Merge topic 'vs2019-redist'

a0b6448c85 IRSL: Update redist directory for VS 2019 update 1

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3233
diff --git a/.clang-tidy b/.clang-tidy
index 520b1a9..bfcb67c 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -11,7 +11,6 @@
 -misc-static-assert,\
 modernize-*,\
 -modernize-deprecated-headers,\
--modernize-raw-string-literal,\
 -modernize-return-braced-init-list,\
 -modernize-use-auto,\
 -modernize-use-noexcept,\
@@ -19,7 +18,6 @@
 -modernize-use-using,\
 performance-*,\
 -performance-inefficient-string-concatenation,\
--performance-inefficient-vector-operation,\
 readability-*,\
 -readability-function-size,\
 -readability-identifier-naming,\
diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake
index 5d67b0b..8c0c5e8 100644
--- a/Auxiliary/bash-completion/cmake
+++ b/Auxiliary/bash-completion/cmake
@@ -96,7 +96,7 @@
             _filedir
             return
             ;;
-        --build|--open)
+        --build|--install|--open)
             _filedir -d
             return
             ;;
diff --git a/Auxiliary/cmake.m4 b/Auxiliary/cmake.m4
index 7beff41..a40c0ae 100644
--- a/Auxiliary/cmake.m4
+++ b/Auxiliary/cmake.m4
@@ -13,7 +13,7 @@
 # $2: language (e.g. C/CXX/Fortran)
 # $3: The compiler ID, defaults to GNU.
 #     Possible values are: GNU, Intel, Clang, SunPro, HP, XL, VisualAge, PGI,
-#     PathScale, Cray, SCO, MIPSpro, MSVC
+#     PathScale, Cray, SCO, MSVC
 # $4: optional extra arguments to cmake, e.g. "-DCMAKE_SIZEOF_VOID_P=8"
 # $5: optional path to cmake binary
 AC_DEFUN([CMAKE_FIND_PACKAGE], [
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 7e029de..7fcdc72 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -353,11 +353,13 @@
             \ XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
             \ XCODE_EXPLICIT_FILE_TYPE
             \ XCODE_FILE_ATTRIBUTES
+            \ XCODE_GENERATE_SCHEME
             \ XCODE_LAST_KNOWN_FILE_TYPE
             \ XCODE_PRODUCT_TYPE
             \ XCODE_SCHEME_ADDRESS_SANITIZER
             \ XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
             \ XCODE_SCHEME_ARGUMENTS
+            \ XCODE_SCHEME_DEBUG_AS_ROOT
             \ XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
             \ XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
             \ XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake
index dc9f0ba..78e22cc 100644
--- a/CMakeCPack.cmake
+++ b/CMakeCPack.cmake
@@ -102,9 +102,6 @@
   if(WIN32 AND NOT CYGWIN)
       list(APPEND _CPACK_IFW_COMPONENTS_ALL cmcldeps)
   endif()
-  if(APPLE)
-    list(APPEND _CPACK_IFW_COMPONENTS_ALL cmakexbuild)
-  endif()
   if(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
     set(_CPACK_IFW_COMPONENT_UNSPECIFIED_NAME
       ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in
index a08c97d..2a4bcc5 100644
--- a/CMakeCPackOptions.cmake.in
+++ b/CMakeCPackOptions.cmake.in
@@ -109,16 +109,6 @@
   set(CPACK_IFW_COMPONENT_CMCLDEPS_VERSION
     "@CMake_IFW_ROOT_COMPONENT_VERSION@")
 
-  set(CPACK_COMPONENT_CMAKEXBUILD_DISPLAY_NAME "cmakexbuild")
-  set(CPACK_COMPONENT_CMAKEXBUILD_DESCRIPTION
-    "The \"cmakexbuild\" executable is a wrapper program for \"xcodebuild\"")
-  set(CPACK_COMPONENT_CMAKEXBUILD_REQUIRED TRUE)
-  set(CPACK_COMPONENT_CMAKEXBUILD_GROUP Tools)
-  set(CPACK_IFW_COMPONENT_CMAKEXBUILD_NAME "CMakeXBuild")
-  set(CPACK_IFW_COMPONENT_CMAKEXBUILD_PRIORITY 85)
-  set(CPACK_IFW_COMPONENT_CMAKEXBUILD_VERSION
-    "@CMake_IFW_ROOT_COMPONENT_VERSION@")
-
   # Dialogs
   set(CPACK_COMPONENT_GROUP_DIALOGS_DISPLAY_NAME "Interactive Dialogs")
   set(CPACK_COMPONENT_GROUP_DIALOGS_DESCRIPTION
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bd130ec..fc033ba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -139,7 +139,7 @@
 
   # Allow the user to enable/disable all system utility library options by
   # defining CMAKE_USE_SYSTEM_LIBRARIES or CMAKE_USE_SYSTEM_LIBRARY_${util}.
-  set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBRHASH LIBUV ZLIB)
+  set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBRHASH LIBUV ZLIB ZSTD)
   foreach(util ${UTILITIES})
     if(NOT DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util}
         AND DEFINED CMAKE_USE_SYSTEM_LIBRARIES)
@@ -173,6 +173,8 @@
     "${CMAKE_USE_SYSTEM_LIBRARY_ZLIB}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE;NOT CMAKE_USE_SYSTEM_CURL" ON)
   CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_BZIP2 "Use system-installed bzip2"
     "${CMAKE_USE_SYSTEM_LIBRARY_BZIP2}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
+  CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_ZSTD "Use system-installed zstd"
+    "${CMAKE_USE_SYSTEM_LIBRARY_ZSTD}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
   CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_LIBLZMA "Use system-installed liblzma"
     "${CMAKE_USE_SYSTEM_LIBRARY_LIBLZMA}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
   option(CMAKE_USE_SYSTEM_FORM "Use system-installed libform" "${CMAKE_USE_SYSTEM_LIBRARY_FORM}")
@@ -445,14 +447,6 @@
   endif()
 
   #---------------------------------------------------------------------
-  # Build Compress library for CTest.
-  set(CMAKE_COMPRESS_INCLUDES
-    "${CMAKE_CURRENT_BINARY_DIR}/Utilities/cmcompress")
-  set(CMAKE_COMPRESS_LIBRARIES "cmcompress")
-  add_subdirectory(Utilities/cmcompress)
-  CMAKE_SET_TARGET_FOLDER(cmcompress "Utilities/3rdParty")
-
-  #---------------------------------------------------------------------
   # Build expat library for CMake, CTest, and libarchive.
   if(CMAKE_USE_SYSTEM_EXPAT)
     find_package(EXPAT)
@@ -484,6 +478,17 @@
   endif()
 
   #---------------------------------------------------------------------
+  # Build or use system zstd for libarchive.
+  if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+    if(NOT CMAKE_USE_SYSTEM_ZSTD)
+      set(ZSTD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmzstd")
+      set(ZSTD_LIBRARY cmzstd)
+      add_subdirectory(Utilities/cmzstd)
+      CMAKE_SET_TARGET_FOLDER(cmzstd "Utilities/3rdParty")
+    endif()
+  endif()
+
+  #---------------------------------------------------------------------
   # Build or use system liblzma for libarchive.
   if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
     if(CMAKE_USE_SYSTEM_LIBLZMA)
@@ -546,6 +551,10 @@
       message(FATAL_ERROR
         "CMAKE_USE_SYSTEM_JSONCPP is ON but a JsonCpp is not found!")
     endif()
+    if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+      set_property(TARGET JsonCpp::JsonCpp APPEND PROPERTY
+        INTERFACE_COMPILE_OPTIONS -Wno-deprecated-declarations)
+    endif()
     set(CMAKE_JSONCPP_LIBRARIES JsonCpp::JsonCpp)
   else()
     set(CMAKE_JSONCPP_LIBRARIES cmjsoncpp)
diff --git a/CompileFlags.cmake b/CompileFlags.cmake
index 5d0e144..c8a039a 100644
--- a/CompileFlags.cmake
+++ b/CompileFlags.cmake
@@ -44,6 +44,15 @@
   endif()
 endif()
 
+# Workaround for TOC Overflow on ppc64
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX" AND
+   CMAKE_SYSTEM_PROCESSOR MATCHES "powerpc")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-bbigtoc")
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
+   CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-multi-toc")
+endif()
+
 if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro AND
     NOT DEFINED CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION)
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
index ec6cb9d..b42fe42 100644
--- a/Help/command/add_library.rst
+++ b/Help/command/add_library.rst
@@ -80,12 +80,17 @@
 within the project.  ``IMPORTED`` libraries are useful for convenient
 reference from commands like :command:`target_link_libraries`.  Details
 about the imported library are specified by setting properties whose names
-begin in ``IMPORTED_`` and ``INTERFACE_``.  The most important such
-property is :prop_tgt:`IMPORTED_LOCATION` (and its per-configuration
-variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the
-location of the main library file on disk.  Or, for object libraries,
-:prop_tgt:`IMPORTED_OBJECTS` (and :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`)
-specifies the locations of object files on disk.
+begin in ``IMPORTED_`` and ``INTERFACE_``.
+
+The most important properties are:
+
+* :prop_tgt:`IMPORTED_LOCATION` (and its per-configuration
+  variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the
+  location of the main library file on disk.
+* :prop_tgt:`IMPORTED_OBJECTS` (and :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`)
+  for object libraries, specifies the locations of object files on disk.
+* :prop_tgt:`PUBLIC_HEADER` files to be installed during :command:`install` invocation
+
 See documentation of the ``IMPORTED_*`` and ``INTERFACE_*`` properties
 for more information.
 
diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst
index a8c257d..46b9b63 100644
--- a/Help/command/add_test.rst
+++ b/Help/command/add_test.rst
@@ -55,7 +55,8 @@
 
   CMake will generate tests only if the :command:`enable_testing`
   command has been invoked.  The :module:`CTest` module invokes the
-  command automatically when the ``BUILD_TESTING`` option is ``ON``.
+  command automatically unless the ``BUILD_TESTING`` option is turned
+  ``OFF``.
 
 ---------------------------------------------------------------------
 
diff --git a/Help/command/aux_source_directory.rst b/Help/command/aux_source_directory.rst
index e0af665..9619f35 100644
--- a/Help/command/aux_source_directory.rst
+++ b/Help/command/aux_source_directory.rst
@@ -11,14 +11,14 @@
 and stores the list in the ``<variable>`` provided.  This command is
 intended to be used by projects that use explicit template
 instantiation.  Template instantiation files can be stored in a
-"Templates" subdirectory and collected automatically using this
+``Templates`` subdirectory and collected automatically using this
 command to avoid manually listing all instantiations.
 
 It is tempting to use this command to avoid writing the list of source
 files for a library or executable target.  While this seems to work,
 there is no way for CMake to generate a build system that knows when a
 new source file has been added.  Normally the generated build system
-knows when it needs to rerun CMake because the CMakeLists.txt file is
+knows when it needs to rerun CMake because the ``CMakeLists.txt`` file is
 modified to add a new source.  When the source is just added to the
 directory without modifying this file, one would have to manually
 rerun CMake to generate a build system incorporating the new file.
diff --git a/Help/command/build_command.rst b/Help/command/build_command.rst
index b83edaf..6659005 100644
--- a/Help/command/build_command.rst
+++ b/Help/command/build_command.rst
@@ -14,7 +14,7 @@
 
 Sets the given ``<variable>`` to a command-line string of the form::
 
- <cmake> --build . [--config <config>] [--target <target>] [-- -i]
+ <cmake> --build . [--config <config>] [--target <target>...] [-- -i]
 
 where ``<cmake>`` is the location of the :manual:`cmake(1)` command-line
 tool, and ``<config>`` and ``<target>`` are the values provided to the
diff --git a/Help/command/cmake_parse_arguments.rst b/Help/command/cmake_parse_arguments.rst
index c8327e2..196d90f 100644
--- a/Help/command/cmake_parse_arguments.rst
+++ b/Help/command/cmake_parse_arguments.rst
@@ -59,6 +59,11 @@
 where recognized. This can be checked afterwards to see
 whether your macro was called with unrecognized parameters.
 
+``<one_value_keywords>`` and ``<multi_value_keywords>`` that where given no
+values at all are collected in a variable ``<prefix>_KEYWORDS_MISSING_VALUES``
+that will be undefined if all keywords received values. This can be checked
+to see if there where keywords without any values given.
+
 As an example here a ``my_install()`` macro, which takes similar arguments
 as the real :command:`install` command:
 
@@ -77,7 +82,7 @@
 
 .. code-block:: cmake
 
-   my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
+   my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
 
 After the ``cmake_parse_arguments`` call the macro will have set or undefined
 the following variables::
@@ -89,6 +94,8 @@
    MY_INSTALL_TARGETS = "foo;bar"
    MY_INSTALL_CONFIGURATIONS <UNDEFINED> # was not used
    MY_INSTALL_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
+   MY_INSTALL_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS"
+            # No value for "CONFIGURATIONS" given
 
 You can then continue and process these variables.
 
@@ -97,5 +104,6 @@
 interpreted as the beginning of the new option.  E.g.
 ``my_install(TARGETS foo DESTINATION OPTIONAL)`` would result in
 ``MY_INSTALL_DESTINATION`` set to ``"OPTIONAL"``, but as ``OPTIONAL``
-is a keyword itself ``MY_INSTALL_DESTINATION`` will be empty and
-``MY_INSTALL_OPTIONAL`` will therefore be set to ``TRUE``.
+is a keyword itself ``MY_INSTALL_DESTINATION`` will be empty (but added
+to ``MY_INSTALL_KEYWORDS_MISSING_VALUES``) and ``MY_INSTALL_OPTIONAL`` will
+therefore be set to ``TRUE``.
diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst
index fba03fd..983fc20 100644
--- a/Help/command/ctest_submit.rst
+++ b/Help/command/ctest_submit.rst
@@ -7,6 +7,7 @@
 
   ctest_submit([PARTS <part>...] [FILES <file>...]
                [SUBMIT_URL <url>]
+               [BUILD_ID <result-var>]
                [HTTPHEADER <header>]
                [RETRY_COUNT <count>]
                [RETRY_DELAY <delay>]
@@ -44,9 +45,21 @@
   The ``http`` or ``https`` URL of the dashboard server to send the submission
   to.  If not given, the :variable:`CTEST_SUBMIT_URL` variable is used.
 
+``BUILD_ID <result-var>``
+  Store in the ``<result-var>`` variable the ID assigned to this build by
+  CDash.
+
 ``HTTPHEADER <HTTP-header>``
   Specify HTTP header to be included in the request to CDash during submission.
-  This suboption can be repeated several times.
+  For example, CDash can be configured to only accept submissions from
+  authenticated clients. In this case, you should provide a bearer token in your
+  header:
+
+  .. code-block:: cmake
+
+    ctest_submit(HTTPHEADER "Authorization: Bearer <auth-token>")
+
+  This suboption can be repeated several times for multiple headers.
 
 ``RETRY_COUNT <count>``
   Specify how many times to retry a timed-out submission.
@@ -86,5 +99,6 @@
 then it is uploaded. Along with the file, a CDash type string is specified
 to tell CDash which handler to use to process the data.
 
-This signature accepts the ``SUBMIT_URL``, ``HTTPHEADER``, ``RETRY_COUNT``,
-``RETRY_DELAY``, ``RETURN_VALUE`` and ``QUIET`` options as described above.
+This signature accepts the ``SUBMIT_URL``, ``BUILD_ID``, ``HTTPHEADER``,
+``RETRY_COUNT``, ``RETRY_DELAY``, ``RETURN_VALUE`` and ``QUIET`` options
+as described above.
diff --git a/Help/command/enable_testing.rst b/Help/command/enable_testing.rst
index e2028d2..3ac1a19 100644
--- a/Help/command/enable_testing.rst
+++ b/Help/command/enable_testing.rst
@@ -7,7 +7,14 @@
 
   enable_testing()
 
-Enables testing for this directory and below.  See also the
-:command:`add_test` command.  Note that ctest expects to find a test file
-in the build directory root.  Therefore, this command should be in the
-source directory root.
+Enables testing for this directory and below.
+
+This command should be in the source directory root
+because ctest expects to find a test file in the build
+directory root.
+
+This command is automatically invoked when the :module:`CTest`
+module is included, except if the ``BUILD_TESTING`` option is
+turned off.
+
+See also the :command:`add_test` command.
diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst
index 3a56dce..2d71352 100644
--- a/Help/command/execute_process.rst
+++ b/Help/command/execute_process.rst
@@ -22,7 +22,9 @@
                   [ERROR_STRIP_TRAILING_WHITESPACE]
                   [ENCODING <name>])
 
-Runs the given sequence of one or more commands in parallel with the standard
+Runs the given sequence of one or more commands.
+
+Commands are executed concurrently as a pipeline, with the standard
 output of each process piped to the standard input of the next.
 A single standard error pipe is used for all processes.
 
@@ -46,8 +48,9 @@
  the child processes.
 
 ``TIMEOUT``
- The child processes will be terminated if they do not finish in the
- specified number of seconds (fractions are allowed).
+ After the specified number of seconds (fractions allowed), all unfinished
+ child processes will be terminated, and the ``RESULT_VARIABLE`` will be
+ set to a string mentioning the "timeout".
 
 ``RESULT_VARIABLE``
  The variable will be set to contain the result of last child process.
@@ -56,9 +59,9 @@
 
 ``RESULTS_VARIABLE <variable>``
  The variable will be set to contain the result of all processes as a
- :ref:`semicolon-separated list <CMake Language Lists>`, in order of the given ``COMMAND``
- arguments.  Each entry will be an integer return code from the
- corresponding child or a string describing an error condition.
+ :ref:`semicolon-separated list <CMake Language Lists>`, in order of the
+ given ``COMMAND`` arguments.  Each entry will be an integer return code
+ from the corresponding child or a string describing an error condition.
 
 ``OUTPUT_VARIABLE``, ``ERROR_VARIABLE``
  The variable named will be set with the contents of the standard output
diff --git a/Help/command/export.rst b/Help/command/export.rst
index b255ee8..2ca7056 100644
--- a/Help/command/export.rst
+++ b/Help/command/export.rst
@@ -54,7 +54,7 @@
   export(PACKAGE <PackageName>)
 
 Store the current build directory in the CMake user package registry
-for package ``<PackageName>``.  The find_package command may consider the
+for package ``<PackageName>``.  The :command:`find_package` command may consider the
 directory while searching for package ``<PackageName>``.  This helps dependent
 projects find and use a package from the current project's build tree
 without help from the user.  Note that the entry in the package
@@ -62,8 +62,13 @@
 package configuration file (``<PackageName>Config.cmake``) that works with the
 build tree. In some cases, for example for packaging and for system
 wide installations, it is not desirable to write the user package
-registry. If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable
-is enabled, the ``export(PACKAGE)`` command will do nothing.
+registry.
+
+By default the ``export(PACKAGE)`` command does nothing (see policy
+:policy:`CMP0090`) because populating the user package registry has effects
+outside the source and build trees.  Set the
+:variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable to add build directories to
+the CMake user package registry.
 
 .. code-block:: cmake
 
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index 54d5f68..eb44eb2 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -180,7 +180,7 @@
 
 These variables are checked by the ``find_package`` command to determine
 whether the configuration file provides an acceptable version.  They
-are not available after the find_package call returns.  If the version
+are not available after the ``find_package`` call returns.  If the version
 is acceptable the following variables are set:
 
 ``<PackageName>_VERSION``
@@ -220,8 +220,8 @@
 CMake constructs a set of possible installation prefixes for the
 package.  Under each prefix several directories are searched for a
 configuration file.  The tables below show the directories searched.
-Each entry is meant for installation trees following Windows (W), UNIX
-(U), or Apple (A) conventions::
+Each entry is meant for installation trees following Windows (``W``), UNIX
+(``U``), or Apple (``A``) conventions::
 
   <prefix>/                                                       (W)
   <prefix>/(cmake|CMake)/                                         (W)
@@ -234,8 +234,8 @@
   <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/               (W/U)
   <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ (W/U)
 
-On systems supporting macOS Frameworks and Application Bundles the
-following directories are searched for frameworks or bundles
+On systems supporting macOS :prop_tgt:`FRAMEWORK` and :prop_tgt:`BUNDLE`, the
+following directories are searched for Frameworks or Application Bundles
 containing a configuration file::
 
   <prefix>/<name>.framework/Resources/                    (A)
@@ -262,16 +262,16 @@
 * The ``lib`` path is always searched.
 
 If ``PATH_SUFFIXES`` is specified, the suffixes are appended to each
-(W) or (U) directory entry one-by-one.
+(``W``) or (``U``) directory entry one-by-one.
 
 This set of directories is intended to work in cooperation with
 projects that provide configuration files in their installation trees.
-Directories above marked with (W) are intended for installations on
+Directories above marked with (``W``) are intended for installations on
 Windows where the prefix may point at the top of an application's
-installation directory.  Those marked with (U) are intended for
+installation directory.  Those marked with (``U``) are intended for
 installations on UNIX platforms where the prefix is shared by multiple
-packages.  This is merely a convention, so all (W) and (U) directories
-are still searched on all platforms.  Directories marked with (A) are
+packages.  This is merely a convention, so all (``W``) and (``U``) directories
+are still searched on all platforms.  Directories marked with (``A``) are
 intended for installations on Apple platforms.  The
 :variable:`CMAKE_FIND_FRAMEWORK` and :variable:`CMAKE_FIND_APPBUNDLE`
 variables determine the order of preference.
diff --git a/Help/command/get_cmake_property.rst b/Help/command/get_cmake_property.rst
index 58bf741..96764a3 100644
--- a/Help/command/get_cmake_property.rst
+++ b/Help/command/get_cmake_property.rst
@@ -9,7 +9,7 @@
 
 Gets a global property from the CMake instance.  The value of
 the ``<property>`` is stored in the variable ``<var>``.
-If the property is not found, ``<var>`` will be set to ``"NOTFOUND"``.
+If the property is not found, ``<var>`` will be set to ``NOTFOUND``.
 See the :manual:`cmake-properties(7)` manual for available properties.
 
 See also the :command:`get_property` command ``GLOBAL`` option.
diff --git a/Help/command/get_target_property.rst b/Help/command/get_target_property.rst
index 4327681..11e07ea 100644
--- a/Help/command/get_target_property.rst
+++ b/Help/command/get_target_property.rst
@@ -11,7 +11,7 @@
 the variable ``VAR``.  If the target property is not found, the behavior
 depends on whether it has been defined to be an ``INHERITED`` property
 or not (see :command:`define_property`).  Non-inherited properties will
-set ``VAR`` to "NOTFOUND", whereas inherited properties will search the
+set ``VAR`` to ``NOTFOUND``, whereas inherited properties will search the
 relevant parent scope as described for the :command:`define_property`
 command and if still unable to find the property, ``VAR`` will be set to
 an empty string.
diff --git a/Help/command/if.rst b/Help/command/if.rst
index a48a0fa..d8e3a45 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -88,7 +88,9 @@
 
 ``if(EXISTS path-to-file-or-directory)``
  True if the named file or directory exists.  Behavior is well-defined
- only for full paths.
+ only for full paths. Resolves symbolic links, i.e. if the named file or
+ directory is a symbolic link, returns true if the target of the
+ symbolic link exists.
 
 ``if(file1 IS_NEWER_THAN file2)``
  True if ``file1`` is newer than ``file2`` or if one of the two files doesn't
@@ -227,7 +229,7 @@
 
   if(var2)
 
-which is true because ``var2`` is defined to "var1" which is not a false
+which is true because ``var2`` is defined to ``var1`` which is not a false
 constant.
 
 Automatic evaluation applies in the other cases whenever the
diff --git a/Help/command/include_external_msproject.rst b/Help/command/include_external_msproject.rst
index 375baf2..88bb2c6 100644
--- a/Help/command/include_external_msproject.rst
+++ b/Help/command/include_external_msproject.rst
@@ -13,7 +13,7 @@
 
 Includes an external Microsoft project in the generated workspace
 file.  Currently does nothing on UNIX.  This will create a target
-named [projectname].  This can be used in the :command:`add_dependencies`
+named ``[projectname]``.  This can be used in the :command:`add_dependencies`
 command to make things depend on the external project.
 
 ``TYPE``, ``GUID`` and ``PLATFORM`` are optional parameters that allow one to
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 6910d6d..7571aae 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -99,6 +99,7 @@
 Installing Targets
 ^^^^^^^^^^^^^^^^^^
 
+.. _`install(TARGETS)`:
 .. _TARGETS:
 
 .. code-block:: cmake
@@ -147,13 +148,13 @@
   property are treated as ``FRAMEWORK`` targets on macOS.
 
 ``BUNDLE``
-  Executables marked with the ``MACOSX_BUNDLE`` property are treated as
+  Executables marked with the :prop_tgt:`MACOSX_BUNDLE` property are treated as
   ``BUNDLE`` targets on macOS.
 
 ``PUBLIC_HEADER``
-  Any ``PUBLIC_HEADER`` files associated with a library are installed in
+  Any :prop_tgt:`PUBLIC_HEADER` files associated with a library are installed in
   the destination specified by the ``PUBLIC_HEADER`` argument on non-Apple
-  platforms. Rules defined by this argument are ignored for ``FRAMEWORK``
+  platforms. Rules defined by this argument are ignored for :prop_tgt:`FRAMEWORK`
   libraries on Apple platforms because the associated files are installed
   into the appropriate locations inside the framework folder. See
   :prop_tgt:`PUBLIC_HEADER` for details.
@@ -288,18 +289,20 @@
   is not recommended to use ``NAMELINK_SKIP`` in conjunction with
   ``NAMELINK_COMPONENT``.
 
-The ``install(TARGETS)`` command can also accept the following options at the
+The `install(TARGETS)`_ command can also accept the following options at the
 top level:
 
 ``EXPORT``
   This option associates the installed target files with an export called
   ``<export-name>``.  It must appear before any target options.  To actually
-  install the export file itself, call ``install(EXPORT)``, documented below.
+  install the export file itself, call `install(EXPORT)`_, documented below.
+  See documentation of the :prop_tgt:`EXPORT_NAME` target property to change
+  the name of the exported target.
 
 ``INCLUDES DESTINATION``
   This option specifies a list of directories which will be added to the
   :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property of the
-  ``<targets>`` when exported by the :command:`install(EXPORT)` command. If a
+  ``<targets>`` when exported by the `install(EXPORT)`_ command. If a
   relative path is specified, it is treated as relative to the
   ``$<INSTALL_PREFIX>``.
 
@@ -333,7 +336,7 @@
 Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property
 set to ``TRUE`` has undefined behavior.
 
-:command:`install(TARGETS)` can install targets that were created in
+`install(TARGETS)`_ can install targets that were created in
 other directories.  When using such cross-directory install rules, running
 ``make install`` (or similar) from a subdirectory will not guarantee that
 targets from other directories are up-to-date.  You can use
@@ -348,6 +351,8 @@
 Installing Files
 ^^^^^^^^^^^^^^^^
 
+.. _`install(FILES)`:
+.. _`install(PROGRAMS)`:
 .. _FILES:
 .. _PROGRAMS:
 
@@ -436,6 +441,7 @@
 Installing Directories
 ^^^^^^^^^^^^^^^^^^^^^^
 
+.. _`install(DIRECTORY)`:
 .. _DIRECTORY:
 
 .. code-block:: cmake
@@ -560,6 +566,8 @@
 Custom Installation Logic
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. _`install(CODE)`:
+.. _`install(SCRIPT)`:
 .. _CODE:
 .. _SCRIPT:
 
@@ -589,6 +597,7 @@
 Installing Exports
 ^^^^^^^^^^^^^^^^^^
 
+.. _`install(EXPORT)`:
 .. _EXPORT:
 
 .. code-block:: cmake
@@ -605,7 +614,7 @@
 The ``EXPORT`` form generates and installs a CMake file containing code to
 import targets from the installation tree into another project.
 Target installations are associated with the export ``<export-name>``
-using the ``EXPORT`` option of the ``install(TARGETS)`` signature
+using the ``EXPORT`` option of the `install(TARGETS)`_ signature
 documented above.  The ``NAMESPACE`` option will prepend ``<namespace>`` to
 the target names as they are written to the import file.  By default
 the generated file will be called ``<export-name>.cmake`` but the ``FILE``
diff --git a/Help/command/install_files.rst b/Help/command/install_files.rst
index f5fb46d..ff074a8 100644
--- a/Help/command/install_files.rst
+++ b/Help/command/install_files.rst
@@ -21,7 +21,7 @@
 file specified already has an extension, that extension will be
 removed first.  This is useful for providing lists of source files
 such as foo.cxx when you want the corresponding foo.h to be installed.
-A typical extension is '.h'.
+A typical extension is ``.h``.
 
 ::
 
diff --git a/Help/command/list.rst b/Help/command/list.rst
index bfcdf34..4444af7 100644
--- a/Help/command/list.rst
+++ b/Help/command/list.rst
@@ -21,6 +21,9 @@
     list(`APPEND`_ <list> [<element>...])
     list(`FILTER`_ <list> {INCLUDE | EXCLUDE} REGEX <regex>)
     list(`INSERT`_ <list> <index> [<element>...])
+    list(`POP_BACK`_ <list> [<out-var>...])
+    list(`POP_FRONT`_ <list> [<out-var>...])
+    list(`PREPEND`_ <list> [<element>...])
     list(`REMOVE_ITEM`_ <list> <value>...)
     list(`REMOVE_AT`_ <list> <index>...)
     list(`REMOVE_DUPLICATES`_ <list>)
@@ -33,8 +36,9 @@
 Introduction
 ^^^^^^^^^^^^
 
-The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``REMOVE_AT``,
-``REMOVE_ITEM``, ``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create
+The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``PREPEND``,
+``POP_BACK``, ``POP_FRONT``, ``REMOVE_AT``, ``REMOVE_ITEM``,
+``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create
 new values for the list within the current CMake variable scope.  Similar to
 the :command:`set` command, the LIST command creates new variable values in
 the current scope, even if the list itself is actually defined in a parent
@@ -142,6 +146,34 @@
 
 Inserts elements to the list to the specified location.
 
+.. _POP_BACK:
+
+.. code-block:: cmake
+
+  list(POP_BACK <list> [<out-var>...])
+
+If no variable name is given, removes exactly one element. Otherwise,
+assign the last element's value to the given variable and removes it,
+up to the last variable name given.
+
+.. _POP_FRONT:
+
+.. code-block:: cmake
+
+  list(POP_FRONT <list> [<out-var>...])
+
+If no variable name is given, removes exactly one element. Otherwise,
+assign the first element's value to the given variable and removes it,
+up to the last variable name given.
+
+.. _PREPEND:
+
+.. code-block:: cmake
+
+  list(PREPEND <list> [<element> ...])
+
+Insert elements to the 0th position in the list.
+
 .. _REMOVE_ITEM:
 
 .. code-block:: cmake
@@ -164,7 +196,8 @@
 
   list(REMOVE_DUPLICATES <list>)
 
-Removes duplicated items in the list.
+Removes duplicated items in the list. The relative order of items is preserved,
+but if duplicates are encountered, only the first instance is preserved.
 
 .. _TRANSFORM:
 
diff --git a/Help/command/math.rst b/Help/command/math.rst
index 4fa55f6..3cbe719 100644
--- a/Help/command/math.rst
+++ b/Help/command/math.rst
@@ -16,7 +16,7 @@
 ``^``, ``~``, ``<<``, ``>>``, and ``(...)``; they have the same meaning
 as in C code.
 
-Hexadecimal numbers are recognized when prefixed with "0x", as in C code.
+Hexadecimal numbers are recognized when prefixed with ``0x``, as in C code.
 
 The result is formatted according to the option ``OUTPUT_FORMAT``,
 where ``<format>`` is one of
diff --git a/Help/command/output_required_files.rst b/Help/command/output_required_files.rst
index 8bc6a73..b3a6e86 100644
--- a/Help/command/output_required_files.rst
+++ b/Help/command/output_required_files.rst
@@ -14,6 +14,6 @@
   output_required_files(srcfile outputfile)
 
 Outputs a list of all the source files that are required by the
-specified srcfile.  This list is written into outputfile.  This is
-similar to writing out the dependencies for srcfile except that it
-jumps from .h files into .cxx, .c and .cpp files if possible.
+specified ``srcfile``.  This list is written into ``outputfile``.  This is
+similar to writing out the dependencies for ``srcfile`` except that it
+jumps from ``.h`` files into ``.cxx``, ``.c`` and ``.cpp`` files if possible.
diff --git a/Help/command/project.rst b/Help/command/project.rst
index 688e56c..7e33ccd 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -31,9 +31,13 @@
 If any of these arguments is not used, then the corresponding variables are
 set to the empty string.
 
-If the variable :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` exists,
-the file pointed to by that variable will be included as the last step of the
-project command.
+If the variable :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` exists, the file
+pointed to by that variable will be included as the first step of the project
+command.
+
+If the variable :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`
+or :variable:`CMAKE_PROJECT_INCLUDE` exists, the file pointed to by that
+variable will be included as the last step of the project command.
 
 Options
 ^^^^^^^
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index c5e4f9f..c2e7e8a 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -57,7 +57,7 @@
   as when a shared library is detected to have no ``SONAME`` field.
   See policy :policy:`CMP0060` for discussion of another case.
 
-  If the library file is in a Mac OSX framework, the ``Headers`` directory
+  If the library file is in a macOS framework, the ``Headers`` directory
   of the framework will also be processed as a
   :ref:`usage requirement <Target Usage Requirements>`.  This has the same
   effect as passing the framework directory as an include directory.
diff --git a/Help/command/use_mangled_mesa.rst b/Help/command/use_mangled_mesa.rst
index 4d9e12b..5b0e2ee 100644
--- a/Help/command/use_mangled_mesa.rst
+++ b/Help/command/use_mangled_mesa.rst
@@ -9,7 +9,7 @@
 
   use_mangled_mesa(PATH_TO_MESA OUTPUT_DIRECTORY)
 
-The path to mesa includes, should contain gl_mangle.h.  The mesa
+The path to mesa includes, should contain ``gl_mangle.h``.  The mesa
 headers are copied to the specified output directory.  This allows
 mangled mesa headers to override other GL headers by being added to
 the include directory path earlier.
diff --git a/Help/command/variable_requires.rst b/Help/command/variable_requires.rst
index b4742a5..322b154 100644
--- a/Help/command/variable_requires.rst
+++ b/Help/command/variable_requires.rst
@@ -18,5 +18,5 @@
 ``TEST_VARIABLE`` is true, then the next argument (``RESULT_VARIABLE``)
 is a variable that is set to true if all the required variables are set.
 The rest of the arguments are variables that must be true or not set
-to NOTFOUND to avoid an error.  If any are not true, an error is
+to ``NOTFOUND`` to avoid an error.  If any are not true, an error is
 reported.
diff --git a/Help/cpack_gen/bundle.rst b/Help/cpack_gen/bundle.rst
index 29727e2..b16dbda 100644
--- a/Help/cpack_gen/bundle.rst
+++ b/Help/cpack_gen/bundle.rst
@@ -12,26 +12,27 @@
 
 .. variable:: CPACK_BUNDLE_NAME
 
- The name of the generated bundle. This appears in the OSX finder as the
+ The name of the generated bundle. This appears in the macOS Finder as the
  bundle name. Required.
 
 .. variable:: CPACK_BUNDLE_PLIST
 
- Path to an OSX plist file that will be used for the generated bundle. This
- assumes that the caller has generated or specified their own Info.plist
+ Path to an macOS Property List (``.plist``) file that will be used
+ for the generated bundle. This
+ assumes that the caller has generated or specified their own ``Info.plist``
  file. Required.
 
 .. variable:: CPACK_BUNDLE_ICON
 
- Path to an OSX icon file that will be used as the icon for the generated
- bundle. This is the icon that appears in the OSX finder for the bundle, and
- in the OSX dock when the bundle is opened. Required.
+ Path to an macOS icon file that will be used as the icon for the generated
+ bundle. This is the icon that appears in the macOS Finder for the bundle, and
+ in the macOS dock when the bundle is opened. Required.
 
 .. variable:: CPACK_BUNDLE_STARTUP_COMMAND
 
  Path to a startup script. This is a path to an executable or script that
  will be run whenever an end-user double-clicks the generated bundle in the
- OSX Finder. Optional.
+ macOS Finder. Optional.
 
 .. variable:: CPACK_BUNDLE_APPLE_CERT_APP
 
@@ -42,8 +43,9 @@
 
 .. variable:: CPACK_BUNDLE_APPLE_ENTITLEMENTS
 
- The name of the ``Plist`` file that contains your apple entitlements for sandboxing
- your application. This file is required for submission to the Mac App Store.
+ The name of the Property List (``.plist``) file that contains your Apple
+ entitlements for sandboxing your application. This file is required
+ for submission to the macOS App Store.
 
 .. variable:: CPACK_BUNDLE_APPLE_CODESIGN_FILES
 
diff --git a/Help/cpack_gen/external.rst b/Help/cpack_gen/external.rst
index e4912a4..406f6be 100644
--- a/Help/cpack_gen/external.rst
+++ b/Help/cpack_gen/external.rst
@@ -13,7 +13,7 @@
 Integration with External Packaging Tools
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-The CPack External generator generates a .json file containing the
+The CPack External generator generates a ``.json`` file containing the
 CPack internal metadata, which gives external software information
 on how to package the software. External packaging software may itself
 invoke CPack, consume the generated metadata,
diff --git a/Help/cpack_gen/nsis.rst b/Help/cpack_gen/nsis.rst
index 9f82a04..cd2aea6 100644
--- a/Help/cpack_gen/nsis.rst
+++ b/Help/cpack_gen/nsis.rst
@@ -1,19 +1,19 @@
 CPack NSIS Generator
 --------------------
 
-CPack NSIS generator specific options
+CPack Nullsoft Scriptable Install System (NSIS) generator specific options
 
 Variables specific to CPack NSIS generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The following variables are specific to the graphical installers built
-on Windows using the Nullsoft Installation System.
+on Windows Nullsoft Scriptable Install System.
 
 .. variable:: CPACK_NSIS_INSTALL_ROOT
 
  The default installation directory presented to the end user by the NSIS
  installer is under this root dir. The full directory presented to the end
- user is: ${CPACK_NSIS_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}
+ user is: ``${CPACK_NSIS_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}``
 
 .. variable:: CPACK_NSIS_MUI_ICON
 
@@ -31,11 +31,11 @@
 
 .. variable:: CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP
 
- The filename of a bitmap to use as the NSIS MUI_WELCOMEFINISHPAGE_BITMAP.
+ The filename of a bitmap to use as the NSIS ``MUI_WELCOMEFINISHPAGE_BITMAP``.
 
 .. variable:: CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP
 
- The filename of a bitmap to use as the NSIS MUI_UNWELCOMEFINISHPAGE_BITMAP.
+ The filename of a bitmap to use as the NSIS ``MUI_UNWELCOMEFINISHPAGE_BITMAP``.
 
 .. variable:: CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS
 
@@ -54,25 +54,25 @@
 
 .. variable:: CPACK_NSIS_COMPRESSOR
 
- The arguments that will be passed to the NSIS SetCompressor command.
+ The arguments that will be passed to the NSIS `SetCompressor` command.
 
 .. variable:: CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL
 
- Ask about uninstalling previous versions first.  If this is set to "ON",
+ Ask about uninstalling previous versions first.  If this is set to ``ON``,
  then an installer will look for previous installed versions and if one is
  found, ask the user whether to uninstall it before proceeding with the
  install.
 
 .. variable:: CPACK_NSIS_MODIFY_PATH
 
- Modify PATH toggle.  If this is set to "ON", then an extra page will appear
+ Modify ``PATH`` toggle.  If this is set to ``ON``, then an extra page will appear
  in the installer that will allow the user to choose whether the program
- directory should be added to the system PATH variable.
+ directory should be added to the system ``PATH`` variable.
 
 .. variable:: CPACK_NSIS_DISPLAY_NAME
 
- The display name string that appears in the Windows Add/Remove Program
- control panel
+ The display name string that appears in the Windows `Apps & features`
+ in `Control Panel`
 
 .. variable:: CPACK_NSIS_PACKAGE_NAME
 
@@ -97,21 +97,21 @@
 
 .. variable:: CPACK_NSIS_<compName>_INSTALL_DIRECTORY
 
- Custom install directory for the specified component <compName> instead
- of $INSTDIR.
+ Custom install directory for the specified component ``<compName>`` instead
+ of ``$INSTDIR``.
 
 .. variable:: CPACK_NSIS_CREATE_ICONS_EXTRA
 
- Additional NSIS commands for creating start menu shortcuts.
+ Additional NSIS commands for creating `Start Menu` shortcuts.
 
 .. variable:: CPACK_NSIS_DELETE_ICONS_EXTRA
 
- Additional NSIS commands to uninstall start menu shortcuts.
+ Additional NSIS commands to uninstall `Start Menu` shortcuts.
 
 .. variable:: CPACK_NSIS_EXECUTABLES_DIRECTORY
 
- Creating NSIS start menu links assumes that they are in 'bin' unless this
- variable is set.  For example, you would set this to 'exec' if your
+ Creating NSIS `Start Menu` links assumes that they are in ``bin`` unless this
+ variable is set.  For example, you would set this to ``exec`` if your
  executables are in an exec directory.
 
 .. variable:: CPACK_NSIS_MUI_FINISHPAGE_RUN
@@ -121,8 +121,8 @@
 
 .. variable:: CPACK_NSIS_MENU_LINKS
 
- Specify links in [application] menu.  This should contain a list of pair
- "link" "link name". The link may be a URL or a path relative to
+ Specify links in ``[application]`` menu.  This should contain a list of pair
+ ``link`` ``link name``. The link may be a URL or a path relative to
  installation prefix.  Like::
 
   set(CPACK_NSIS_MENU_LINKS
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
index 65009db..2693c7b 100644
--- a/Help/cpack_gen/rpm.rst
+++ b/Help/cpack_gen/rpm.rst
@@ -22,19 +22,19 @@
 
 .. note::
 
- `<COMPONENT>` part of variables is preferred to be in upper case (for e.g. if
- component is named `foo` then use `CPACK_RPM_FOO_XXXX` variable name format)
- as is with other `CPACK_<COMPONENT>_XXXX` variables.
+ `<COMPONENT>` part of variables is preferred to be in upper case (e.g. if
+ component is named ``foo`` then use ``CPACK_RPM_FOO_XXXX`` variable name format)
+ as is with other ``CPACK_<COMPONENT>_XXXX`` variables.
  For the purposes of back compatibility (CMake/CPack version 3.5 and lower)
- support for same cased component (e.g. `fOo` would be used as
- `CPACK_RPM_fOo_XXXX`) is still supported for variables defined in older
+ support for same cased component (e.g. ``fOo`` would be used as
+ ``CPACK_RPM_fOo_XXXX``) is still supported for variables defined in older
  versions of CMake/CPack but is not guaranteed for variables that
  will be added in the future. For the sake of back compatibility same cased
  component variables also override upper cased versions where both are
  present.
 
-Here are some CPack RPM generator wiki resources that are here for historic reasons and
-are no longer maintained but may still prove useful:
+Here are some CPack RPM generator wiki resources that are here for historic
+reasons and are no longer maintained but may still prove useful:
 
  - https://gitlab.kitware.com/cmake/community/wikis/doc/cpack/Configuration
  - https://gitlab.kitware.com/cmake/community/wikis/doc/cpack/PackageGenerators#rpm-unix-only
@@ -48,8 +48,8 @@
  * Mandatory : NO
  * Default   : OFF
 
- If enabled (ON) multiple packages are generated. By default a single package
- containing files of all components is generated.
+ If enabled (``ON``) multiple packages are generated. By default
+ a single package containing files of all components is generated.
 
 .. variable:: CPACK_RPM_PACKAGE_SUMMARY
               CPACK_RPM_<component>_PACKAGE_SUMMARY
@@ -76,14 +76,14 @@
  * Default   : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].rpm`` with spaces
                replaced by '-'
 
- This may be set to ``RPM-DEFAULT`` to allow rpmbuild tool to generate package
+ This may be set to ``RPM-DEFAULT`` to allow ``rpmbuild`` tool to generate package
  file name by itself.
  Alternatively provided package file name must end with ``.rpm`` suffix.
 
  .. note::
 
    By using user provided spec file, rpm macro extensions such as for
-   generating debuginfo packages or by simply using multiple components more
+   generating ``debuginfo`` packages or by simply using multiple components more
    than one rpm file may be generated, either from a single spec file or from
    multiple spec files (each component execution produces its own spec file).
    In such cases duplicate file names may occur as a result of this variable
@@ -127,7 +127,7 @@
  * Mandatory : YES
  * Default   : Native architecture output by ``uname -m``
 
- This may be set to ``noarch`` if you know you are building a noarch package.
+ This may be set to ``noarch`` if you know you are building a ``noarch`` package.
 
 .. variable:: CPACK_RPM_PACKAGE_RELEASE
 
@@ -207,7 +207,7 @@
  * Default   : -
 
  May be used to override RPM compression type to be used to build the
- RPM. For example some Linux distribution now default to lzma or xz
+ RPM. For example some Linux distribution now default to ``lzma`` or ``xz``
  compression whereas older cannot use such RPM. Using this one can enforce
  compression type to be used.
 
@@ -226,8 +226,8 @@
  * Mandatory : NO
  * Default   : -
 
- May be used to enable (1, yes) or disable (0, no) automatic shared libraries
- dependency detection. Dependencies are added to requires list.
+ May be used to enable (``1``, ``yes``) or disable (``0``, ``no``) automatic
+ shared libraries dependency detection. Dependencies are added to requires list.
 
  .. note::
 
@@ -241,9 +241,9 @@
  * Mandatory : NO
  * Default   : -
 
- May be used to enable (1, yes) or disable (0, no) automatic listing of shared
- libraries that are provided by the package. Shared libraries are added to
- provides list.
+ May be used to enable (``1``, ``yes``) or disable (``0``, ``no``)
+ automatic listing of shared libraries that are provided by the package.
+ Shared libraries are added to provides list.
 
  .. note::
 
@@ -258,8 +258,8 @@
  * Default   : -
 
  Variable enables/disables autoreq and autoprov at the same time.
- See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and :variable:`CPACK_RPM_PACKAGE_AUTOPROV`
- for more details.
+ See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and
+ :variable:`CPACK_RPM_PACKAGE_AUTOPROV` for more details.
 
  .. note::
 
diff --git a/Help/envvar/ASM_DIALECT.rst b/Help/envvar/ASM_DIALECT.rst
index cabb959..a06e3cb 100644
--- a/Help/envvar/ASM_DIALECT.rst
+++ b/Help/envvar/ASM_DIALECT.rst
@@ -4,8 +4,9 @@
 .. include:: ENV_VAR.txt
 
 Preferred executable for compiling a specific dialect of assembly language
-files. ``ASM<DIALECT>`` can be ``ASM``, ``ASM_NASM``, ``ASM_MASM`` or
-``ASM-ATT``. Will only be used by CMake on the first configuration to determine
+files. ``ASM<DIALECT>`` can be ``ASM``, ``ASM_NASM`` (Netwide Assembler),
+``ASM_MASM`` (Microsoft Assembler) or ``ASM-ATT`` (Assembler AT&T).
+Will only be used by CMake on the first configuration to determine
 ``ASM<DIALECT>`` compiler, after which the value for ``ASM<DIALECT>`` is stored
 in the cache as
 :variable:`CMAKE_ASM<DIALECT>_COMPILER <CMAKE_<LANG>_COMPILER>`. For subsequent
diff --git a/Help/envvar/ASM_DIALECTFLAGS.rst b/Help/envvar/ASM_DIALECTFLAGS.rst
index 90cbbdb..3c3b02a 100644
--- a/Help/envvar/ASM_DIALECTFLAGS.rst
+++ b/Help/envvar/ASM_DIALECTFLAGS.rst
@@ -6,8 +6,8 @@
 Default compilation flags to be used when compiling a specific dialect of an
 assembly language. ``ASM<DIALECT>FLAGS`` can be ``ASMFLAGS``, ``ASM_NASMFLAGS``,
 ``ASM_MASMFLAGS`` or ``ASM-ATTFLAGS``. Will only be used by CMake on the
-first configuration to determine ``ASM<DIALECT>`` default compilation flags, after
-which the value for ``ASM<DIALECT>FLAGS`` is stored in the cache as
-:variable:`CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
-run (including the first), the environment variable will be ignored if the
-:variable:`CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+first configuration to determine ``ASM_<DIALECT>`` default compilation
+flags, after which the value for ``ASM<DIALECT>FLAGS`` is stored in the cache
+as ``CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>``.  For any configuration
+run (including the first), the environment variable will be ignored, if the
+``CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`` variable is defined.
diff --git a/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst b/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
index b769d51..e1991b2 100644
--- a/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
+++ b/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
@@ -4,4 +4,4 @@
 .. include:: ENV_VAR.txt
 
 Environment variable that will exist and be set to ``1`` when a test executed
-by CTest is run in interactive mode.
+by :manual:`ctest(1)` is run in interactive mode.
diff --git a/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst b/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
index bf860cb..d8b4262 100644
--- a/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
+++ b/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
@@ -4,6 +4,6 @@
 .. include:: ENV_VAR.txt
 
 Boolean environment variable that controls if the output should be logged for
-failed tests. Set the value to 1, True, or ON to enable output on failure.
+failed tests. Set the value to ``1``, ``True``, or ``ON`` to enable output on failure.
 See :manual:`ctest(1)` for more information on controlling output of failed
 tests.
diff --git a/Help/envvar/CTEST_PROGRESS_OUTPUT.rst b/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
index de23e11..b36a6b8 100644
--- a/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
+++ b/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
@@ -4,7 +4,7 @@
 .. include:: ENV_VAR.txt
 
 Boolean environment variable that affects how :manual:`ctest <ctest(1)>`
-command output reports overall progress.  When set to 1, TRUE, ON or anything
+command output reports overall progress.  When set to ``1``, ``TRUE``, ``ON`` or anything
 else that evaluates to boolean true, progress is reported by repeatedly
 updating the same line.  This greatly reduces the overall verbosity, but is
 only supported when output is sent directly to a terminal.  If the environment
diff --git a/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst b/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
index 2b303a4..6a52d64 100644
--- a/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
+++ b/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
@@ -3,5 +3,6 @@
 
 .. include:: ENV_VAR.txt
 
-Environment variable that will exist when a test executed by CTest is run
-in non-interactive mode. The value will be equal to :variable:`CMAKE_VERSION`.
+Environment variable that will exist when a test executed by :manual:`ctest(1)`
+is run in non-interactive mode.  The value will be equal to
+:variable:`CMAKE_VERSION`.
diff --git a/Help/envvar/PackageName_ROOT.rst b/Help/envvar/PackageName_ROOT.rst
index ecec63b..82b0a06 100644
--- a/Help/envvar/PackageName_ROOT.rst
+++ b/Help/envvar/PackageName_ROOT.rst
@@ -5,7 +5,7 @@
 
 Calls to :command:`find_package(<PackageName>)` will search in prefixes
 specified by the ``<PackageName>_ROOT`` environment variable, where
-``<PackageName>`` is the name given to the ``find_package`` call
+``<PackageName>`` is the name given to the :command:`find_package` call
 and ``_ROOT`` is literal.  For example, ``find_package(Foo)`` will search
 prefixes specified in the ``Foo_ROOT`` environment variable (if set).
 See policy :policy:`CMP0074`.
diff --git a/Help/generator/CodeBlocks.rst b/Help/generator/CodeBlocks.rst
index 06cc746..d830542 100644
--- a/Help/generator/CodeBlocks.rst
+++ b/Help/generator/CodeBlocks.rst
@@ -4,14 +4,14 @@
 Generates CodeBlocks project files.
 
 Project files for CodeBlocks will be created in the top directory and
-in every subdirectory which features a CMakeLists.txt file containing
-a PROJECT() call.  Additionally a hierarchy of makefiles is generated
+in every subdirectory which features a ``CMakeLists.txt`` file containing
+a :command:`project` call.  Additionally a hierarchy of makefiles is generated
 into the build tree.
 The :variable:`CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES` variable may
 be set to ``ON`` to exclude any files which are located outside of
 the project root directory.
 The appropriate make program can build the
-project through the default make target.  A "make install" target is
+project through the default ``all`` target.  An ``install`` target is
 also provided.
 
 This "extra" generator may be specified as:
diff --git a/Help/generator/CodeLite.rst b/Help/generator/CodeLite.rst
index 3e60aa6..46fa5be 100644
--- a/Help/generator/CodeLite.rst
+++ b/Help/generator/CodeLite.rst
@@ -7,11 +7,11 @@
 in every subdirectory which features a CMakeLists.txt file containing
 a :command:`project` call.
 The :variable:`CMAKE_CODELITE_USE_TARGETS` variable may be set to ``ON``
-to change the default behaviour from projects to targets as the basis
+to change the default behavior from projects to targets as the basis
 for project files.
 The appropriate make program can build the
-project through the default make target.  A "make install" target is
-also provided.
+project through the default ``all`` target.  An ``install`` target
+is also provided.
 
 This "extra" generator may be specified as:
 
diff --git a/Help/generator/Eclipse CDT4.rst b/Help/generator/Eclipse CDT4.rst
index eb68bf0..634e2b6 100644
--- a/Help/generator/Eclipse CDT4.rst
+++ b/Help/generator/Eclipse CDT4.rst
@@ -7,7 +7,7 @@
 out of source builds, a linked resource to the top level source
 directory will be created.  Additionally a hierarchy of makefiles is
 generated into the build tree.  The appropriate make program can build
-the project through the default make target.  A "make install" target
+the project through the default ``all`` target.  An ``install`` target
 is also provided.
 
 This "extra" generator may be specified as:
diff --git a/Help/generator/Green Hills MULTI.rst b/Help/generator/Green Hills MULTI.rst
index e474682..dffc679 100644
--- a/Help/generator/Green Hills MULTI.rst
+++ b/Help/generator/Green Hills MULTI.rst
@@ -9,8 +9,9 @@
 Customizations that are used to pick toolset and target system:
 
 The ``-A <arch>`` can be supplied for setting the target architecture.
-``<arch>`` usually is one of "arm", "ppc", "86", etcetera.  If the target architecture
-is not specified then the default architecture of "arm" will be used.
+``<arch>`` usually is one of ``arm``, ``ppc``, ``86``, etcetera.
+If the target architecture is not specified then
+the default architecture of ``arm`` will be used.
 
 The ``-T <toolset>`` option can be used to set the directory location of the toolset.
 Both absolute and relative paths are valid. Relative paths use ``GHS_TOOLSET_ROOT``
@@ -33,18 +34,19 @@
 * ``GHS_TOOLSET_ROOT``
 
   | Root path for ``toolset`` searches.
-  | Defaults to ``C:/ghs``.
+  | Defaults to ``C:/ghs`` in Windows or ``/usr/ghs`` in Linux.
 
 * ``GHS_OS_ROOT``
 
   | Root path for RTOS searches.
-  | Defaults to ``C:/ghs``.
+  | Defaults to ``C:/ghs`` in Windows or ``/usr/ghs`` in Linux.
 
-* ``GHS_OS_DIR``
+* ``GHS_OS_DIR`` and ``GHS_OS_DIR_OPTION``
 
   | Sets ``-os_dir`` entry in project file.
   | Defaults to latest platform OS installation at ``GHS_OS_ROOT``.  Set this value if
     a specific RTOS is to be used.
+  | ``GHS_OS_DIR_OPTION`` default value is ``-os_dir``.
 
 * ``GHS_BSP_NAME``
 
diff --git a/Help/generator/Kate.rst b/Help/generator/Kate.rst
index 9b61a93..129bf63 100644
--- a/Help/generator/Kate.rst
+++ b/Help/generator/Kate.rst
@@ -5,10 +5,10 @@
 
 A project file for Kate will be created in the top directory in the top level
 build directory.
-To use it in kate, the Project plugin must be enabled.
-The project file is loaded in kate simply by opening the
-ProjectName.kateproject file in the editor.
-If the kate Build-plugin is enabled, all targets generated by CMake are
+To use it in Kate, the Project plugin must be enabled.
+The project file is loaded in Kate by opening the
+``ProjectName.kateproject`` file in the editor.
+If the Kate Build-plugin is enabled, all targets generated by CMake are
 available for building.
 
 This "extra" generator may be specified as:
diff --git a/Help/generator/MSYS Makefiles.rst b/Help/generator/MSYS Makefiles.rst
index f7cfa44..75b9fe5 100644
--- a/Help/generator/MSYS Makefiles.rst
+++ b/Help/generator/MSYS Makefiles.rst
@@ -1,7 +1,8 @@
 MSYS Makefiles
 --------------
 
-Generates makefiles for use with MSYS ``make`` under the MSYS shell.
+Generates makefiles for use with MSYS (Minimal SYStem)
+``make`` under the MSYS shell.
 
 Use this generator in a MSYS shell prompt and using ``make`` as the build
 tool.  The generated makefiles use ``/bin/sh`` as the shell to launch build
diff --git a/Help/generator/MinGW Makefiles.rst b/Help/generator/MinGW Makefiles.rst
index 9fe5fe3..134ea70 100644
--- a/Help/generator/MinGW Makefiles.rst
+++ b/Help/generator/MinGW Makefiles.rst
@@ -4,7 +4,8 @@
 Generates makefiles for use with ``mingw32-make`` under a Windows command
 prompt.
 
-Use this generator under a Windows command prompt with MinGW in the ``PATH``
+Use this generator under a Windows command prompt with
+MinGW (Minimalist GNU for Windows) in the ``PATH``
 and using ``mingw32-make`` as the build tool.  The generated makefiles use
 ``cmd.exe`` as the shell to launch build rules.  They are not compatible with
 MSYS or a unix shell.
diff --git a/Help/generator/Ninja.rst b/Help/generator/Ninja.rst
index 3bbd9dc..51ef49b 100644
--- a/Help/generator/Ninja.rst
+++ b/Help/generator/Ninja.rst
@@ -4,8 +4,8 @@
 Generates build.ninja files.
 
 A build.ninja file is generated into the build tree.  Recent versions
-of the ninja program can build the project through the "all" target.
-An "install" target is also provided.
+of the ninja program can build the project through the ``all`` target.
+An ``install`` target is also provided.
 
 For each subdirectory ``sub/dir`` of the project, additional targets
 are generated:
diff --git a/Help/generator/Sublime Text 2.rst b/Help/generator/Sublime Text 2.rst
index 0597a95..0a07ea9 100644
--- a/Help/generator/Sublime Text 2.rst
+++ b/Help/generator/Sublime Text 2.rst
@@ -4,11 +4,11 @@
 Generates Sublime Text 2 project files.
 
 Project files for Sublime Text 2 will be created in the top directory
-and in every subdirectory which features a CMakeLists.txt file
-containing a PROJECT() call.  Additionally Makefiles (or build.ninja
-files) are generated into the build tree.  The appropriate make
-program can build the project through the default make target.  A
-"make install" target is also provided.
+and in every subdirectory which features a ``CMakeLists.txt`` file
+containing a :command:`project` call.  Additionally ``Makefiles``
+(or ``build.ninja`` files) are generated into the build tree.
+The appropriate make program can build the project through the default ``all``
+target.  An ``install`` target is also provided.
 
 This "extra" generator may be specified as:
 
diff --git a/Help/generator/Unix Makefiles.rst b/Help/generator/Unix Makefiles.rst
index 97d74a8..1e65ee1 100644
--- a/Help/generator/Unix Makefiles.rst
+++ b/Help/generator/Unix Makefiles.rst
@@ -5,4 +5,4 @@
 
 A hierarchy of UNIX makefiles is generated into the build tree.  Any
 standard UNIX-style make program can build the project through the
-default make target.  A "make install" target is also provided.
+default ``all`` target.  An ``install`` target is also provided.
diff --git a/Help/generator/VS_TOOLSET_HOST_ARCH.txt b/Help/generator/VS_TOOLSET_HOST_ARCH.txt
index 4eb900f..0293631 100644
--- a/Help/generator/VS_TOOLSET_HOST_ARCH.txt
+++ b/Help/generator/VS_TOOLSET_HOST_ARCH.txt
@@ -1,6 +1,6 @@
 For each toolset that comes with this version of Visual Studio, there are
-variants that are themselves compiled for 32-bit (x86) and 64-bit (x64) hosts
-(independent of the architecture they target).
+variants that are themselves compiled for 32-bit (``x86``) and
+64-bit (``x64``) hosts (independent of the architecture they target).
 |VS_TOOLSET_HOST_ARCH_DEFAULT|
 One may explicitly request use of either the 32-bit or 64-bit host tools
 by adding either ``host=x86`` or ``host=x64`` to the toolset specification.
diff --git a/Help/generator/Xcode.rst b/Help/generator/Xcode.rst
index 71430c7..d893ac5 100644
--- a/Help/generator/Xcode.rst
+++ b/Help/generator/Xcode.rst
@@ -3,9 +3,7 @@
 
 Generate Xcode project files.
 
-This supports Xcode 3.0 and above.  Support for Xcode versions prior
-to Xcode 5 is deprecated and will be dropped in a future version of
-CMake.
+This supports Xcode 5.0 and above.
 
 Toolset Selection
 ^^^^^^^^^^^^^^^^^
diff --git a/Help/manual/LINKS.txt b/Help/manual/LINKS.txt
index 8e53c0c..60a260c 100644
--- a/Help/manual/LINKS.txt
+++ b/Help/manual/LINKS.txt
@@ -14,7 +14,7 @@
 Mailing List
  https://cmake.org/mailing-lists
 
- For help and discussion about using cmake, a mailing list is
+ For help and discussion about using CMake, a mailing list is
  provided at cmake@cmake.org.  The list is member-post-only but one
  may sign up on the CMake web page.  Please first read the full
  documentation at https://cmake.org before posting questions to
diff --git a/Help/manual/OPTIONS_BUILD.txt b/Help/manual/OPTIONS_BUILD.txt
index baa73d5..64fd816 100644
--- a/Help/manual/OPTIONS_BUILD.txt
+++ b/Help/manual/OPTIONS_BUILD.txt
@@ -9,23 +9,23 @@
 ``-C <initial-cache>``
  Pre-load a script to populate the cache.
 
- When cmake is first run in an empty build tree, it creates a
- CMakeCache.txt file and populates it with customizable settings for
+ When CMake is first run in an empty build tree, it creates a
+ ``CMakeCache.txt`` file and populates it with customizable settings for
  the project.  This option may be used to specify a file from which
  to load cache entries before the first pass through the project's
- cmake listfiles.  The loaded entries take priority over the
+ CMake listfiles.  The loaded entries take priority over the
  project's default values.  The given file should be a CMake script
- containing SET commands that use the CACHE option, not a
+ containing :command:`set` commands that use the ``CACHE`` option, not a
  cache-format file.
 
 ``-D <var>:<type>=<value>, -D <var>=<value>``
- Create or update a cmake cache entry.
+ Create or update a CMake ``CACHE`` entry.
 
- When cmake is first run in an empty build tree, it creates a
- CMakeCache.txt file and populates it with customizable settings for
+ When CMake is first run in an empty build tree, it creates a
+ ``CMakeCache.txt`` file and populates it with customizable settings for
  the project.  This option may be used to specify a setting that
  takes priority over the project's default value.  The option may be
- repeated for as many cache entries as desired.
+ repeated for as many ``CACHE`` entries as desired.
 
  If the ``:<type>`` portion is given it must be one of the types
  specified by the :command:`set` command documentation for its
@@ -39,14 +39,14 @@
  ``-D<var>:<type>=<value>`` or ``-D<var>=<value>``.
 
 ``-U <globbing_expr>``
- Remove matching entries from CMake cache.
+ Remove matching entries from CMake ``CACHE``.
 
  This option may be used to remove one or more variables from the
- CMakeCache.txt file, globbing expressions using * and ? are
- supported.  The option may be repeated for as many cache entries as
+ ``CMakeCache.txt`` file, globbing expressions using ``*`` and ``?`` are
+ supported.  The option may be repeated for as many ``CACHE`` entries as
  desired.
 
- Use with care, you can make your CMakeCache.txt non-working.
+ Use with care, you can make your ``CMakeCache.txt`` non-working.
 
 ``-G <generator-name>``
  Specify a build system generator.
@@ -74,47 +74,47 @@
  Suppress developer warnings.
 
  Suppress warnings that are meant for the author of the
- CMakeLists.txt files. By default this will also turn off
+ ``CMakeLists.txt`` files. By default this will also turn off
  deprecation warnings.
 
 ``-Wdev``
  Enable developer warnings.
 
- Enable warnings that are meant for the author of the CMakeLists.txt
+ Enable warnings that are meant for the author of the ``CMakeLists.txt``
  files. By default this will also turn on deprecation warnings.
 
 ``-Werror=dev``
  Make developer warnings errors.
 
- Make warnings that are meant for the author of the CMakeLists.txt files
+ Make warnings that are meant for the author of the ``CMakeLists.txt`` files
  errors. By default this will also turn on deprecated warnings as errors.
 
 ``-Wno-error=dev``
  Make developer warnings not errors.
 
- Make warnings that are meant for the author of the CMakeLists.txt files not
+ Make warnings that are meant for the author of the ``CMakeLists.txt`` files not
  errors. By default this will also turn off deprecated warnings as errors.
 
 ``-Wdeprecated``
  Enable deprecated functionality warnings.
 
  Enable warnings for usage of deprecated functionality, that are meant
- for the author of the CMakeLists.txt files.
+ for the author of the ``CMakeLists.txt`` files.
 
 ``-Wno-deprecated``
  Suppress deprecated functionality warnings.
 
  Suppress warnings for usage of deprecated functionality, that are meant
- for the author of the CMakeLists.txt files.
+ for the author of the ``CMakeLists.txt`` files.
 
 ``-Werror=deprecated``
  Make deprecated macro and function warnings errors.
 
  Make warnings for usage of deprecated macros and functions, that are meant
- for the author of the CMakeLists.txt files, errors.
+ for the author of the ``CMakeLists.txt`` files, errors.
 
 ``-Wno-error=deprecated``
  Make deprecated macro and function warnings not errors.
 
  Make warnings for usage of deprecated macros and functions, that are meant
- for the author of the CMakeLists.txt files, not errors.
+ for the author of the ``CMakeLists.txt`` files, not errors.
diff --git a/Help/manual/ccmake.1.rst b/Help/manual/ccmake.1.rst
index 9548471..60d45a3 100644
--- a/Help/manual/ccmake.1.rst
+++ b/Help/manual/ccmake.1.rst
@@ -20,7 +20,7 @@
 
 CMake is a cross-platform build system generator.  Projects specify
 their build process with platform-independent CMake listfiles included
-in each directory of a source tree with the name CMakeLists.txt.
+in each directory of a source tree with the name ``CMakeLists.txt``.
 Users build a project by using CMake to generate a build system for a
 native tool on their platform.
 
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
index a1328f2..1ad3453 100644
--- a/Help/manual/cmake-buildsystem.7.rst
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -21,7 +21,7 @@
 
 Executables and libraries are defined using the :command:`add_executable`
 and :command:`add_library` commands.  The resulting binary files have
-appropriate prefixes, suffixes and extensions for the platform targeted.
+appropriate :prop_tgt:`PREFIX`, :prop_tgt:`SUFFIX` and extensions for the platform targeted.
 Dependencies between binary targets are expressed using the
 :command:`target_link_libraries` command:
 
@@ -31,7 +31,7 @@
   add_executable(zipapp zipapp.cpp)
   target_link_libraries(zipapp archive)
 
-``archive`` is defined as a static library -- an archive containing objects
+``archive`` is defined as a ``STATIC`` library -- an archive containing objects
 compiled from ``archive.cpp``, ``zip.cpp``, and ``lzma.cpp``.  ``zipapp``
 is defined as an executable formed by compiling and linking ``zipapp.cpp``.
 When linking the ``zipapp`` executable, the ``archive`` static library is
@@ -59,7 +59,7 @@
 Normal Libraries
 ^^^^^^^^^^^^^^^^
 
-By default, the :command:`add_library` command defines a static library,
+By default, the :command:`add_library` command defines a ``STATIC`` library,
 unless a type is specified.  A type may be specified when using the command:
 
 .. code-block:: cmake
@@ -141,8 +141,8 @@
   target_link_libraries(test_exe archive)
 
 The link (or archiving) step of those other targets will use the object
-files from object libraries that are *directly* linked.  Additionally,
-usage requirements of the object libraries will be honored when compiling
+files from ``OBJECT`` libraries that are *directly* linked.  Additionally,
+usage requirements of the ``OBJECT`` libraries will be honored when compiling
 sources in those other targets.  Furthermore, those usage requirements
 will propagate transitively to dependents of those other targets.
 
@@ -365,8 +365,8 @@
   target_link_libraries(exe2 lib1 lib2)
 
 The ``lib1`` requirement ``INTERFACE_POSITION_INDEPENDENT_CODE`` is not
-"compatible" with the ``POSITION_INDEPENDENT_CODE`` property of the ``exe1``
-target.  The library requires that consumers are built as
+"compatible" with the :prop_tgt:`POSITION_INDEPENDENT_CODE` property of
+the ``exe1`` target.  The library requires that consumers are built as
 position-independent-code, while the executable specifies to not built as
 position-independent-code, so a diagnostic is issued.
 
@@ -547,10 +547,10 @@
     target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
   endif()
 
-may appear to work for ``Makefile`` based and ``Ninja`` generators, but is not
-portable to IDE generators.  Additionally, the :prop_tgt:`IMPORTED`
-configuration-mappings are not accounted for with code like this, so it should
-be avoided.
+may appear to work for :ref:`Makefile Generators` and :generator:`Ninja`
+generators, but is not portable to IDE generators.  Additionally,
+the :prop_tgt:`IMPORTED` configuration-mappings are not accounted for
+with code like this, so it should be avoided.
 
 The unary ``TARGET_PROPERTY`` generator expression and the ``TARGET_POLICY``
 generator expression are evaluated with the consuming target context.  This
@@ -699,7 +699,7 @@
 be controlled by setting the :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` target
 property on the *consumers* of imported targets.
 
-If a binary target is linked transitively to a Mac OX framework, the
+If a binary target is linked transitively to a macOS :prop_tgt:`FRAMEWORK`, the
 ``Headers`` directory of the framework is also treated as a usage requirement.
 This has the same effect as passing the framework directory as an include
 directory.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 7f484a4..e9b3f4c 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -86,7 +86,7 @@
 ``$<EQUAL:value1,value2>``
   ``1`` if ``value1`` and ``value2`` are numerically equal, else ``0``.
 ``$<IN_LIST:string,list>``
-  ``1`` if ``string`` is member of the comma-separated ``list``, else ``0``.
+  ``1`` if ``string`` is member of the semicolon-separated ``list``, else ``0``.
   Uses case-sensitive comparisons.
 ``$<VERSION_LESS:v1,v2>``
   ``1`` if ``v1`` is a version less than ``v2``, else ``0``.
@@ -121,6 +121,9 @@
 ``$<CXX_COMPILER_ID:compiler_id>``
   ``1`` if the CMake-id of the CXX compiler matches ``compiler_id``,
   otherwise ``0``.
+``$<CUDA_COMPILER_ID:compiler_id>``
+  ``1`` if the CMake-id of the CUDA compiler matches ``compiler_id``,
+  otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 ``$<Fortran_COMPILER_ID:compiler_id>``
   ``1`` if the CMake-id of the Fortran compiler matches ``compiler_id``,
@@ -132,6 +135,9 @@
 ``$<CXX_COMPILER_VERSION:version>``
   ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+``$<CUDA_COMPILER_VERSION:version>``
+  ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
 ``$<Fortran_COMPILER_VERSION:version>``
   ``1`` if the version of the Fortran compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
@@ -285,6 +291,10 @@
 
 ``$<JOIN:list,string>``
   Joins the list with the content of ``string``.
+``$<REMOVE_DUPLICATES:list>``
+  Removes duplicated items in the given ``list``.
+``$<FILTER:list,INCLUDE|EXCLUDE,regex>``
+  Includes or removes items from ``list`` that match the regular expression ``regex``.
 ``$<LOWER_CASE:string>``
   Content of ``string`` converted to lower case.
 ``$<UPPER_CASE:string>``
@@ -346,6 +356,9 @@
 ``$<CXX_COMPILER_ID>``
   The CMake-id of the CXX compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+``$<CUDA_COMPILER_ID>``
+  The CMake-id of the CUDA compiler used.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 ``$<Fortran_COMPILER_ID>``
   The CMake-id of the Fortran compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
@@ -355,6 +368,9 @@
 ``$<CXX_COMPILER_VERSION>``
   The version of the CXX compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+``$<CUDA_COMPILER_VERSION>``
+  The version of the CUDA compiler used.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
 ``$<Fortran_COMPILER_VERSION>``
   The version of the Fortran compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
@@ -371,14 +387,45 @@
 ``$<TARGET_NAME_IF_EXISTS:tgt>``
   Expands to the ``tgt`` if the given target exists, an empty string
   otherwise.
+``$<TARGET_OUTPUT_NAME:tgt>``
+  Base name of main file where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_FILE:tgt>``
-  Full path to main file (.exe, .so.1.2, .a) where ``tgt`` is the name of a target.
+  Full path to main file (.exe, .so.1.2, .a) where ``tgt`` is the name of a
+  target.
+``$<TARGET_FILE_PREFIX:tgt>``
+  Prefix of main file where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
+``$<TARGET_FILE_SUFFIX:tgt>``
+  Suffix of main file where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_FILE_NAME:tgt>``
   Name of main file (.exe, .so.1.2, .a).
 ``$<TARGET_FILE_DIR:tgt>``
   Directory of main file (.exe, .so.1.2, .a).
+``$<TARGET_LINKER_OUTPUT_NAME:tgt>``
+  Base name of file used to link where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_LINKER_FILE:tgt>``
   File used to link (.a, .lib, .so) where ``tgt`` is the name of a target.
+``$<TARGET_LINKER_FILE_PREFIX:tgt>``
+  Prefix of file used to link where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
+``$<TARGET_LINKER_FILE_SUFFIX:tgt>``
+  Suffix of file used to link where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_LINKER_FILE_NAME:tgt>``
   Name of file used to link (.a, .lib, .so).
 ``$<TARGET_LINKER_FILE_DIR:tgt>``
@@ -389,6 +436,15 @@
   Name of file with soname (.so.3).
 ``$<TARGET_SONAME_FILE_DIR:tgt>``
   Directory of with soname (.so.3).
+``$<TARGET_PDB_OUTPUT_NAME:tgt>``
+  Base name of the linker generated program database file (.pdb)
+  where ``tgt`` is the name of a target.
+
+  See also the :prop_tgt:`PDB_NAME` target property and its configuration
+  specific variant :prop_tgt:`PDB_NAME_<CONFIG>`.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_PDB_FILE:tgt>``
   Full path to the linker generated program database file (.pdb)
   where ``tgt`` is the name of a target.
@@ -455,6 +511,11 @@
   Content of ``...`` converted to shell path style. For example, slashes are
   converted to backslashes in Windows shells and drive letters are converted
   to posix paths in MSYS shells. The ``...`` must be an absolute path.
+  The ``...`` may be a :ref:`semicolon-separated list <CMake Language Lists>`
+  of paths, in which case each path is converted individually and a result
+  list is generated using the shell path separator (``:`` on POSIX and
+  ``;`` on Windows).  Be sure to enclose the argument containing this genex
+  in double quotes in CMake source code so that ``;`` does not split arguments.
 
 Debugging
 =========
diff --git a/Help/manual/cmake-gui.1.rst b/Help/manual/cmake-gui.1.rst
index 856aa2f..ff8311b 100644
--- a/Help/manual/cmake-gui.1.rst
+++ b/Help/manual/cmake-gui.1.rst
@@ -21,7 +21,7 @@
 
 CMake is a cross-platform build system generator.  Projects specify
 their build process with platform-independent CMake listfiles included
-in each directory of a source tree with the name CMakeLists.txt.
+in each directory of a source tree with the name ``CMakeLists.txt``.
 Users build a project by using CMake to generate a build system for a
 native tool on their platform.
 
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index d9b939f..fc4bfdc 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -125,6 +125,7 @@
    /module/FindDCMTK
    /module/FindDevIL
    /module/FindDoxygen
+   /module/FindEnvModules
    /module/FindEXPAT
    /module/FindFLEX
    /module/FindFLTK2
diff --git a/Help/manual/cmake-packages.7.rst b/Help/manual/cmake-packages.7.rst
index 876ca84..f5aa42d 100644
--- a/Help/manual/cmake-packages.7.rst
+++ b/Help/manual/cmake-packages.7.rst
@@ -12,7 +12,7 @@
 
 Packages provide dependency information to CMake based buildsystems.  Packages
 are found with the :command:`find_package` command.  The result of
-using ``find_package`` is either a set of :prop_tgt:`IMPORTED` targets, or
+using :command:`find_package` is either a set of :prop_tgt:`IMPORTED` targets, or
 a set of variables corresponding to build-relevant information.
 
 Using Packages
@@ -647,12 +647,17 @@
 In some cases using the Package Registries is not desirable. CMake
 allows one to disable them using the following variables:
 
- * :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` disables the
-   :command:`export(PACKAGE)` command.
- * :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` disables the
-   User Package Registry in all the :command:`find_package` calls.
- * :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` disables
-   the System Package Registry in all the :command:`find_package` calls.
+* The :command:`export(PACKAGE)` command does not populate the user
+  package registry when :policy:`CMP0090` is set to ``NEW`` unless the
+  :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable explicitly enables it.
+  When :policy:`CMP0090` is *not* set to ``NEW`` then
+  :command:`export(PACKAGE)` populates the user package registry unless
+  the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable explicitly
+  disables it.
+* :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` disables the
+  User Package Registry in all the :command:`find_package` calls.
+* :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` disables
+  the System Package Registry in all the :command:`find_package` calls.
 
 Package Registry Example
 ------------------------
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 409b5b1..e89ea3da 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -51,6 +51,15 @@
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.15
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0090: export(PACKAGE) does not populate package registry by default. </policy/CMP0090>
+   CMP0089: Compiler id for IBM Clang-based XL compilers is now XLClang. </policy/CMP0089>
+
 Policies Introduced by CMake 3.14
 =================================
 
@@ -65,6 +74,7 @@
    CMP0083: Add PIE options when linking executable. </policy/CMP0083>
    CMP0082: Install rules from add_subdirectory() are interleaved with those in caller. </policy/CMP0082>
 
+
 Policies Introduced by CMake 3.13
 =================================
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index ef86412..4d4b9ff 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -334,6 +334,7 @@
    /prop_tgt/VS_IOT_STARTUP_TASK
    /prop_tgt/VS_KEYWORD
    /prop_tgt/VS_MOBILE_EXTENSIONS_VERSION
+   /prop_tgt/VS_NO_SOLUTION_DEPLOY
    /prop_tgt/VS_SCC_AUXPATH
    /prop_tgt/VS_SCC_LOCALPATH
    /prop_tgt/VS_SCC_PROJECTNAME
@@ -348,10 +349,12 @@
    /prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS
    /prop_tgt/XCODE_ATTRIBUTE_an-attribute
    /prop_tgt/XCODE_EXPLICIT_FILE_TYPE
+   /prop_tgt/XCODE_GENERATE_SCHEME
    /prop_tgt/XCODE_PRODUCT_TYPE
    /prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER
    /prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
    /prop_tgt/XCODE_SCHEME_ARGUMENTS
+   /prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT
    /prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
    /prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
    /prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index ba44b7f..df4531b 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -26,13 +26,13 @@
 :variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` etc are set by
 invoking the :command:`project` command.  If no project command
 is in the top-level CMakeLists file, one will be implicitly generated. By default
-the enabled languages are C and CXX:
+the enabled languages are ``C`` and ``CXX``:
 
 .. code-block:: cmake
 
   project(C_Only C)
 
-A special value of NONE can also be used with the :command:`project` command
+A special value of ``NONE`` can also be used with the :command:`project` command
 to enable no languages:
 
 .. code-block:: cmake
@@ -468,10 +468,10 @@
   The Android ABI detected from the standalone toolchain.
 
 :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX`
-  The absolute path prefix to the binutils in the standalone toolchain.
+  The absolute path prefix to the ``binutils`` in the standalone toolchain.
 
 :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX`
-  The host platform suffix of the binutils in the standalone toolchain.
+  The host platform suffix of the ``binutils`` in the standalone toolchain.
 
 For example, a toolchain file might contain:
 
@@ -533,7 +533,7 @@
 :generator:`Ninja` generators can also be used, but they require the
 project to handle more areas like target CPU selection and code signing.
 
-Any of the three systems can be targetted by setting the
+Any of the three systems can be targeted by setting the
 :variable:`CMAKE_SYSTEM_NAME` variable to a value from the table below.
 By default, the latest Device SDK is chosen.  As for all Apple platforms,
 a different SDK (e.g. a simulator) can be selected by setting the
@@ -609,7 +609,7 @@
 
 Some build artifacts for the embedded Apple platforms require mandatory
 code signing.  If the :generator:`Xcode` generator is being used and
-code signing is required or desired, the developmemt team ID can be
+code signing is required or desired, the development team ID can be
 specified via the ``CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM`` CMake variable.
 This team ID will then be included in the generated Xcode project.
 By default, CMake avoids the need for code signing during the internal
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 6bb30cb..18dd9d7 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -7,7 +7,7 @@
 
    .. contents::
 
-This page  documents variables that are provided by CMake
+This page documents variables that are provided by CMake
 or have meaning to CMake when set by project code.
 
 For general information on variables, see the
@@ -159,6 +159,7 @@
    /variable/CMAKE_ERROR_DEPRECATED
    /variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
    /variable/CMAKE_EXPORT_COMPILE_COMMANDS
+   /variable/CMAKE_EXPORT_PACKAGE_REGISTRY
    /variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY
    /variable/CMAKE_FIND_APPBUNDLE
    /variable/CMAKE_FIND_FRAMEWORK
@@ -194,6 +195,8 @@
    /variable/CMAKE_POLICY_WARNING_CMPNNNN
    /variable/CMAKE_PREFIX_PATH
    /variable/CMAKE_PROGRAM_PATH
+   /variable/CMAKE_PROJECT_INCLUDE
+   /variable/CMAKE_PROJECT_INCLUDE_BEFORE
    /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
    /variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
    /variable/CMAKE_STAGING_PREFIX
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index f3b81ec..5b88694 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -16,6 +16,9 @@
  `Build a Project`_
   cmake --build <dir> [<options>] [-- <build-tool-options>]
 
+ `Install a Project`_
+  cmake --install <dir> [<options>]
+
  `Open a Project`_
   cmake --open <dir>
 
@@ -39,8 +42,8 @@
 the tool can perform as described in sections below.
 
 To build a software project with CMake, `Generate a Project Buildsystem`_.
-Optionally use **cmake** to `Build a Project`_ or just run the
-corresponding build tool (e.g. ``make``) directly.  **cmake** can also
+Optionally use **cmake** to `Build a Project`_, `Install a Project`_ or just
+run the corresponding build tool (e.g. ``make``) directly.  **cmake** can also
 be used to `View Help`_.
 
 The other actions are meant for use by software developers writing
@@ -169,12 +172,12 @@
 ``-L[A][H]``
  List non-advanced cached variables.
 
- List cache variables will run CMake and list all the variables from
- the CMake cache that are not marked as INTERNAL or ADVANCED.  This
- will effectively display current CMake settings, which can then be
- changed with -D option.  Changing some of the variables may result
- in more variables being created.  If A is specified, then it will
- display also advanced variables.  If H is specified, it will also
+ List ``CACHE`` variables will run CMake and list all the variables from
+ the CMake ``CACHE`` that are not marked as ``INTERNAL`` or :prop_cache:`ADVANCED`.
+ This will effectively display current CMake settings, which can then be
+ changed with ``-D`` option.  Changing some of the variables may result
+ in more variables being created.  If ``A`` is specified, then it will
+ display also advanced variables.  If ``H`` is specified, it will also
  display help for each variable.
 
 ``-N``
@@ -198,9 +201,10 @@
  additional information such as the cache, log files etc.
 
 ``--debug-trycompile``
- Do not delete the try_compile build tree. Only useful on one try_compile at a time.
+ Do not delete the :command:`try_compile` build tree.
+ Only useful on one :command:`try_compile` at a time.
 
- Do not delete the files and directories created for try_compile
+ Do not delete the files and directories created for :command:`try_compile`
  calls.  This is useful in debugging failed try_compiles.  It may
  however change the results of the try-compiles as old junk from a
  previous try-compile may cause a different test to either pass or
@@ -211,7 +215,7 @@
  Put cmake in a debug mode.
 
  Print extra information during the cmake run like stack traces with
- message(send_error ) calls.
+ :command:`message(SEND_ERROR)` calls.
 
 ``--trace``
  Put cmake in trace mode.
@@ -248,8 +252,8 @@
  Find problems with variable usage in system files.
 
  Normally, unused and uninitialized variables are searched for only
- in CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR.  This flag tells CMake to
- warn about other files as well.
+ in :variable:`CMAKE_SOURCE_DIR` and :variable:`CMAKE_BINARY_DIR`.
+ This flag tells CMake to warn about other files as well.
 
 .. _`Build Tool Mode`:
 
@@ -269,15 +273,15 @@
 ``--build <dir>``
   Project binary directory to be built.  This is required and must be first.
 
-``-j [<jobs>], --parallel [<jobs>]``
+``--parallel [<jobs>], -j [<jobs>]``
   The maximum number of concurrent processes to use when building.
   If ``<jobs>`` is omitted the native build tool's default number is used.
 
   The :envvar:`CMAKE_BUILD_PARALLEL_LEVEL` environment variable, if set,
   specifies a default parallel level when this option is not given.
 
-``--target <tgt>``
-  Build ``<tgt>`` instead of default targets.  May only be specified once.
+``--target <tgt>..., -t <tgt>...``
+  Build ``<tgt>`` instead of default targets.  May be specified multiple times.
 
 ``--config <cfg>``
   For multi-configuration tools, choose configuration ``<cfg>``.
@@ -289,7 +293,7 @@
 ``--use-stderr``
   Ignored.  Behavior is default in CMake >= 3.0.
 
-``-v, --verbose``
+``--verbose, -v``
   Enable verbose output - if supported - including the build commands to be
   executed.
 
@@ -302,6 +306,41 @@
 
 Run ``cmake --build`` with no options for quick help.
 
+Install a Project
+=================
+
+CMake provides a command-line signature to install an already-generated
+project binary tree:
+
+.. code-block:: shell
+
+  cmake --install <dir> [<options>]
+
+This may be used after building a project to run installation without
+using the generated build system or the native build tool.
+The options are:
+
+``--install <dir>``
+  Project binary directory to install. This is required and must be first.
+
+``--config <cfg>``
+  For multi-configuration tools, choose configuration ``<cfg>``.
+
+``--component <comp>``
+  Component-based install. Only install component ``<comp>``.
+
+``--prefix <prefix>``
+  The installation prefix :variable:`CMAKE_INSTALL_PREFIX`.
+
+``--strip``
+  Strip before installing by setting ``CMAKE_INSTALL_DO_STRIP``.
+
+``-v, --verbose``
+  Enable verbose output.
+
+  This option can be omitted if :envvar:`VERBOSE` environment variable is set.
+
+Run ``cmake --install`` with no options for quick help.
 
 Open a Project
 ==============
@@ -325,8 +364,8 @@
 
 Process the given cmake file as a script written in the CMake
 language.  No configure or generate step is performed and the cache
-is not modified.  If variables are defined using -D, this must be
-done before the -P argument.
+is not modified.  If variables are defined using ``-D``, this must be
+done before the ``-P`` argument.
 
 
 Run a Command-Line Tool
@@ -383,23 +422,27 @@
 
 ``compare_files [--ignore-eol] <file1> <file2>``
   Check if ``<file1>`` is same as ``<file2>``. If files are the same,
-  then returns 0, if not it returns 1.  The ``--ignore-eol`` option
+  then returns ``0``, if not it returns ``1``.  The ``--ignore-eol`` option
   implies line-wise comparison and ignores LF/CRLF differences.
 
 ``copy <file>... <destination>``
   Copy files to ``<destination>`` (either file or directory).
   If multiple files are specified, the ``<destination>`` must be
   directory and it must exist. Wildcards are not supported.
+  ``copy`` does follow symlinks. That means it does not copy symlinks,
+  but the files or directories it point to.
 
 ``copy_directory <dir>... <destination>``
   Copy directories to ``<destination>`` directory.
   If ``<destination>`` directory does not exist it will be created.
+  ``copy_directory`` does follow symlinks.
 
 ``copy_if_different <file>... <destination>``
   Copy files to ``<destination>`` (either file or directory) if
   they have changed.
   If multiple files are specified, the ``<destination>`` must be
   directory and it must exist.
+  ``copy_if_different`` does follow symlinks.
 
 ``echo [<string>...]``
   Displays arguments as text.
@@ -459,13 +502,16 @@
   exist, the command returns a non-zero exit code, but no message
   is logged. The ``-f`` option changes the behavior to return a
   zero exit code (i.e. success) in such situations instead.
+  ``remove`` does not follow symlinks. That means it remove only symlinks
+  and not files it point to.
 
 ``remove_directory <dir>``
   Remove a directory and its contents.  If a directory does
   not exist it will be silently ignored.
 
 ``rename <oldname> <newname>``
-  Rename a file or directory (on one volume).
+  Rename a file or directory (on one volume). If file with the ``<newname>`` name
+  already exists, then it will be silently replaced.
 
 ``server``
   Launch :manual:`cmake-server(7)` mode.
@@ -476,6 +522,21 @@
 ``tar [cxt][vf][zjJ] file.tar [<options>] [--] [<file>...]``
   Create or extract a tar or zip archive.  Options are:
 
+  ``c``
+    Create a new archive containing the specified files.
+    If used, the <file> argument is mandatory.
+  ``x``
+    Extract to disk from the archive.
+  ``t``
+    List archive contents to stdout.
+  ``v``
+    Produce verbose output.
+  ``z``
+    Compress the resulting archive with gzip.
+  ``j``
+    Compress the resulting archive with bzip2.
+  ``J``
+    Compress the resulting archive with XZ.
   ``--``
     Stop interpreting options and treat all remaining arguments
     as file names even if they start in ``-``.
@@ -494,10 +555,11 @@
 ``time <command> [<args>...]``
   Run command and display elapsed time.
 
-``touch <file>``
-  Touch a file.
+``touch <file>...``
+  Creates ``<file>`` if file do not exist.
+  If ``<file>`` exists, it is changing ``<file>`` access and modification times.
 
-``touch_nocreate <file>``
+``touch_nocreate <file>...``
   Touch a file if it exists but do not create it.  If a file does
   not exist it will be silently ignored.
 
diff --git a/Help/manual/cpack.1.rst b/Help/manual/cpack.1.rst
index 679c547..10f617e 100644
--- a/Help/manual/cpack.1.rst
+++ b/Help/manual/cpack.1.rst
@@ -63,7 +63,7 @@
   details.  By default, ``CPackConfig.cmake`` in the current directory will
   be used.
 
-``--verbose,-V``
+``--verbose, -V``
   Run ``cpack`` with verbose output.  This can be used to show more details
   from the package generation tools and is suitable for project developers.
 
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index d1bd69b..5a6b329 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -22,8 +22,8 @@
 
 The **ctest** executable is the CMake test driver program.
 CMake-generated build trees created for projects that use the
-ENABLE_TESTING and ADD_TEST commands have testing support.  This
-program will run the tests and report results.
+:command:`enable_testing` and :command:`add_test` commands have testing support.
+This program will run the tests and report results.
 
 Options
 =======
@@ -33,8 +33,8 @@
 
  Some CMake-generated build trees can have multiple build
  configurations in the same tree.  This option can be used to specify
- which one should be tested.  Example configurations are "Debug" and
- "Release".
+ which one should be tested.  Example configurations are ``Debug`` and
+ ``Release``.
 
 ``--progress``
  Enable short progress output from tests.
@@ -108,7 +108,7 @@
 ``-O <file>, --output-log <file>``
  Output to log file.
 
- This option tells CTest to write all its output to a log file.
+ This option tells CTest to write all its output to a ``<file>`` log file.
 
 ``-N,--show-only[=<format>]``
  Disable actual execution of tests.
@@ -172,9 +172,10 @@
  Execute dashboard test.
 
  This option tells CTest to act as a CDash client and perform a
- dashboard test.  All tests are <Mode><Test>, where Mode can be
- Experimental, Nightly, and Continuous, and Test can be Start,
- Update, Configure, Build, Test, Coverage, and Submit.
+ dashboard test.  All tests are ``<Mode><Test>``, where ``<Mode>`` can be
+ ``Experimental``, ``Nightly``, and ``Continuous``, and ``<Test>`` can be
+ ``Start``, ``Update``, ``Configure``, ``Build``, ``Test``,
+ ``Coverage``, and ``Submit``.
 
  See `Dashboard Client`_.
 
@@ -229,10 +230,10 @@
 ``-I [Start,End,Stride,test#,test#|Test file], --tests-information``
  Run a specific number of tests by number.
 
- This option causes CTest to run tests starting at number Start,
- ending at number End, and incrementing by Stride.  Any additional
- numbers after Stride are considered individual test numbers.  Start,
- End,or stride can be empty.  Optionally a file can be given that
+ This option causes CTest to run tests starting at number ``Start``,
+ ending at number ``End``, and incrementing by ``Stride``.  Any additional
+ numbers after ``Stride`` are considered individual test numbers.  ``Start``,
+ ``End``, or ``Stride`` can be empty.  Optionally a file can be given that
  contains the same syntax as the command line.
 
 ``-U, --union``
@@ -264,12 +265,12 @@
  name which can be very annoying.
 
 ``--interactive-debug-mode [0|1]``
- Set the interactive mode to 0 or 1.
+ Set the interactive mode to ``0`` or ``1``.
 
  This option causes CTest to run tests in either an interactive mode
  or a non-interactive mode.  On Windows this means that in
  non-interactive mode, all system debug pop up windows are blocked.
- In dashboard mode (Experimental, Nightly, Continuous), the default
+ In dashboard mode (``Experimental``, ``Nightly``, ``Continuous``), the default
  is non-interactive.  When just running tests not for a dashboard the
  default is to allow popups and interactive debugging.
 
@@ -350,7 +351,7 @@
 Label and Subproject Summary
 ============================
 
-CTest prints timing summary information for each label and subproject
+CTest prints timing summary information for each ``LABEL`` and subproject
 associated with the tests run. The label time summary will not include labels
 that are mapped to subprojects.
 
@@ -358,8 +359,8 @@
 weighted test timing result in label and subproject summaries. The time is
 reported with `sec*proc` instead of just `sec`.
 
-The weighted time summary reported for each label or subproject j is computed
-as::
+The weighted time summary reported for each label or subproject ``j``
+is computed as::
 
   Weighted Time Summary for Label/Subproject j =
       sum(raw_test_time[j,i] * num_processors[j,i], i=1...num_tests[j])
@@ -368,25 +369,25 @@
 
 where:
 
-* raw_test_time[j,i]: Wall-clock time for the ith test for the jth label or
-  subproject
-* num_processors[j,i]: Value of the CTest PROCESSORS property for the ith test
-  for the jth label or subproject
-* num_tests[j]: Number of tests associated with the jth label or subproject
-* total: Total number of labels or subprojects that have at least one test run
+* ``raw_test_time[j,i]``: Wall-clock time for the ``i`` test
+  for the ``j`` label or subproject
+* ``num_processors[j,i]``: Value of the CTest :prop_test:`PROCESSORS` property
+  for the ``i`` test for the ``j`` label or subproject
+* ``num_tests[j]``: Number of tests associated with the ``j`` label or subproject
+* ``total``: Total number of labels or subprojects that have at least one test run
 
 Therefore, the weighted time summary for each label or subproject represents
 the amount of time that CTest gave to run the tests for each label or
 subproject and gives a good representation of the total expense of the tests
 for each label or subproject when compared to other labels or subprojects.
 
-For example, if "SubprojectA" showed "100 sec*proc" and "SubprojectB" showed
-"10 sec*proc", then CTest allocated approximately  10 times the CPU/core time
-to run the tests for "SubprojectA" than for "SubprojectB" (e.g. so if effort
+For example, if ``SubprojectA`` showed ``100 sec*proc`` and ``SubprojectB`` showed
+``10 sec*proc``, then CTest allocated approximately 10 times the CPU/core time
+to run the tests for ``SubprojectA`` than for ``SubprojectB`` (e.g. so if effort
 is going to be expended to reduce the cost of the test suite for the whole
-project, then reducing the cost of the test suite for "SubprojectA" would
+project, then reducing the cost of the test suite for ``SubprojectA`` would
 likely have a larger impact than effort to reduce the cost of the test suite
-for "SubprojectB").
+for ``SubprojectB``).
 
 .. _`Build and Test Mode`:
 
@@ -449,7 +450,7 @@
 
 ``--build-config-sample``
  A sample executable to use to determine the configuration that
- should be used.  e.g.  Debug/Release/etc.
+ should be used.  e.g.  ``Debug``, ``Release`` etc.
 
 ``--build-options``
  Additional options for configuring the build (i.e. for CMake, not for
@@ -495,7 +496,7 @@
  dashboard.
 
 ``--tomorrow-tag``
- Nightly or experimental starts with next day tag.
+ ``Nightly`` or ``Experimental`` starts with next day tag.
 
  This is useful if the build will not finish in one day.
 
@@ -505,10 +506,10 @@
  This option will submit extra files to the dashboard.
 
 ``--http1.0``
- Submit using HTTP 1.0.
+ Submit using `HTTP 1.0`.
 
- This option will force CTest to use HTTP 1.0 to submit files to the
- dashboard, instead of HTTP 1.1.
+ This option will force CTest to use `HTTP 1.0` to submit files to the
+ dashboard, instead of `HTTP 1.1`.
 
 ``--no-compress-output``
  Do not compress test output when submitting.
@@ -711,7 +712,7 @@
 
   The source tree is updated by ``git fetch`` followed by
   ``git reset --hard`` to the ``FETCH_HEAD``.  The result is the same
-  as ``git pull`` except that any local moficiations are overwritten.
+  as ``git pull`` except that any local modifications are overwritten.
   Use ``GITUpdateCustom`` to specify a different approach.
 
 ``GITInitSubmodules``
diff --git a/Help/module/CPackWIX.rst b/Help/module/CPackWIX.rst
index c88c723..fd378b8 100644
--- a/Help/module/CPackWIX.rst
+++ b/Help/module/CPackWIX.rst
@@ -1,4 +1,5 @@
 CPackWIX
 --------
 
-The documentation for the CPack WIX generator has moved here: :cpack_gen:`CPack WIX Generator`
+The documentation for the CPack WIX generator has moved here:
+:cpack_gen:`CPack WIX Generator`
diff --git a/Help/module/FindEnvModules.rst b/Help/module/FindEnvModules.rst
new file mode 100644
index 0000000..72c120f
--- /dev/null
+++ b/Help/module/FindEnvModules.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindEnvModules.cmake
diff --git a/Help/policy/CMP0000.rst b/Help/policy/CMP0000.rst
index 97ea633..aecfa71 100644
--- a/Help/policy/CMP0000.rst
+++ b/Help/policy/CMP0000.rst
@@ -7,25 +7,27 @@
 they have been written.  This policy has been put in place so users
 trying to build the project may be told when they need to update their
 CMake.  Specifying a version also helps the project build with CMake
-versions newer than that specified.  Use the cmake_minimum_required
-command at the top of your main CMakeLists.txt file:
+versions newer than that specified.  Use the :command:`cmake_minimum_required`
+command at the top of your main ``CMakeLists.txt`` file:
 
 ::
 
   cmake_minimum_required(VERSION <major>.<minor>)
 
-where "<major>.<minor>" is the version of CMake you want to support
-(such as "2.6").  The command will ensure that at least the given
+where ``<major>.<minor>`` is the version of CMake you want to support
+(such as ``3.14``).  The command will ensure that at least the given
 version of CMake is running and help newer versions be compatible with
-the project.  See documentation of cmake_minimum_required for details.
+the project.  See documentation of :command:`cmake_minimum_required` for
+details.
 
-Note that the command invocation must appear in the CMakeLists.txt
+Note that the command invocation must appear in the ``CMakeLists.txt``
 file itself; a call in an included file is not sufficient.  However,
-the cmake_policy command may be called to set policy CMP0000 to OLD or
-NEW behavior explicitly.  The OLD behavior is to silently ignore the
-missing invocation.  The NEW behavior is to issue an error instead of
-a warning.  An included file may set CMP0000 explicitly to affect how
-this policy is enforced for the main CMakeLists.txt file.
+the  :command:`cmake_policy` command may be called to set policy ``CMP0000``
+to ``OLD`` or ``NEW`` behavior explicitly.  The ``OLD`` behavior is to
+silently ignore the missing invocation.  The ``NEW`` behavior is to issue
+an error instead of a warning.  An included file may set ``CMP0000``
+explicitly to affect how this policy is enforced for the main
+``CMakeLists.txt`` file.
 
 This policy was introduced in CMake version 2.6.0.
 
diff --git a/Help/policy/CMP0001.rst b/Help/policy/CMP0001.rst
index 09ad387..6fa64d9 100644
--- a/Help/policy/CMP0001.rst
+++ b/Help/policy/CMP0001.rst
@@ -1,21 +1,21 @@
 CMP0001
 -------
 
-CMAKE_BACKWARDS_COMPATIBILITY should no longer be used.
+``CMAKE_BACKWARDS_COMPATIBILITY`` should no longer be used.
 
-The OLD behavior is to check CMAKE_BACKWARDS_COMPATIBILITY and present
-it to the user.  The NEW behavior is to ignore
+The behavior is to check ``CMAKE_BACKWARDS_COMPATIBILITY`` and present
+it to the user.  The ``NEW`` behavior is to ignore
 CMAKE_BACKWARDS_COMPATIBILITY completely.
 
-In CMake 2.4 and below the variable CMAKE_BACKWARDS_COMPATIBILITY was
+In CMake 2.4 and below the variable ``CMAKE_BACKWARDS_COMPATIBILITY`` was
 used to request compatibility with earlier versions of CMake.  In
 CMake 2.6 and above all compatibility issues are handled by policies
-and the cmake_policy command.  However, CMake must still check
-CMAKE_BACKWARDS_COMPATIBILITY for projects written for CMake 2.4 and
+and the :command:`cmake_policy` command.  However, CMake must still check
+``CMAKE_BACKWARDS_COMPATIBILITY`` for projects written for CMake 2.4 and
 below.
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0002.rst b/Help/policy/CMP0002.rst
index 7cc53ef..dc68d51 100644
--- a/Help/policy/CMP0002.rst
+++ b/Help/policy/CMP0002.rst
@@ -3,8 +3,8 @@
 
 Logical target names must be globally unique.
 
-Targets names created with add_executable, add_library, or
-add_custom_target are logical build target names.  Logical target
+Targets names created with :command:`add_executable`, :command:`add_library`, or
+:command:`add_custom_target` are logical build target names.  Logical target
 names must be globally unique because:
 
 ::
@@ -16,13 +16,13 @@
 
 The logical name of executable and library targets does not have to
 correspond to the physical file names built.  Consider using the
-OUTPUT_NAME target property to create two targets with the same
+:prop_tgt:`OUTPUT_NAME` target property to create two targets with the same
 physical name while keeping logical names distinct.  Custom targets
 must simply have globally unique names (unless one uses the global
-property ALLOW_DUPLICATE_CUSTOM_TARGETS with a Makefiles generator).
+property :prop_gbl:`ALLOW_DUPLICATE_CUSTOM_TARGETS` with a Makefiles generator).
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0003.rst b/Help/policy/CMP0003.rst
index 16b0451..dd90883 100644
--- a/Help/policy/CMP0003.rst
+++ b/Help/policy/CMP0003.rst
@@ -37,7 +37,7 @@
 
   target_link_libraries(myexe /path/to/libA.so B)
 
-where "B" is meant to find "/path/to/libB.so".  This code is wrong
+where ``B`` is meant to find ``/path/to/libB.so``.  This code is wrong
 because the user is asking the linker to find library B but has not
 provided a linker search path (which may be added with the
 link_directories command).  However, with the old linking
@@ -45,9 +45,9 @@
 search path added for library A allowed library B to be found.
 
 In order to support projects depending on linker search paths added by
-linking to libraries with known full paths, the OLD behavior for this
+linking to libraries with known full paths, the ``OLD`` behavior for this
 policy will add the linker search paths even though they are not
-needed for their own libraries.  When this policy is set to OLD, CMake
+needed for their own libraries.  When this policy is set to ``OLD``, CMake
 will produce a link line such as
 
 ::
@@ -98,7 +98,7 @@
 when setting the policy once will probably fix all targets.
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0004.rst b/Help/policy/CMP0004.rst
index 55da4d2..be6d307 100644
--- a/Help/policy/CMP0004.rst
+++ b/Help/policy/CMP0004.rst
@@ -12,14 +12,15 @@
 
 This could lead to subtle errors in user projects.
 
-The OLD behavior for this policy is to silently remove leading and
-trailing whitespace.  The NEW behavior for this policy is to diagnose
+The ``OLD`` behavior for this policy is to silently remove leading and
+trailing whitespace.  The ``NEW`` behavior for this policy is to diagnose
 the existence of such whitespace as an error.  The setting for this
 policy used when checking the library names is that in effect when the
-target is created by an add_executable or add_library command.
+target is created by an :command:`add_executable` or :command:`add_library`
+command.
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0005.rst b/Help/policy/CMP0005.rst
index 66d125f..59567d5 100644
--- a/Help/policy/CMP0005.rst
+++ b/Help/policy/CMP0005.rst
@@ -12,15 +12,15 @@
 cannot assume the user has not added escapes already in an attempt to
 work around limitations in earlier versions.
 
-The OLD behavior for this policy is to place definition values given
+The ``OLD`` behavior for this policy is to place definition values given
 to add_definitions directly in the generated build rules without
-attempting to escape anything.  The NEW behavior for this policy is to
+attempting to escape anything.  The ``NEW`` behavior for this policy is to
 generate correct escapes for all native build tools automatically.
-See documentation of the COMPILE_DEFINITIONS target property for
+See documentation of the ``COMPILE_DEFINITIONS`` target property for
 limitations of the escaping implementation.
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0006.rst b/Help/policy/CMP0006.rst
index d1b9ece..181958b 100644
--- a/Help/policy/CMP0006.rst
+++ b/Help/policy/CMP0006.rst
@@ -1,24 +1,24 @@
 CMP0006
 -------
 
-Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION.
+Installing :prop_tgt:`MACOSX_BUNDLE` targets requires a ``BUNDLE DESTINATION``.
 
-This policy determines whether the install(TARGETS) command must be
-given a BUNDLE DESTINATION when asked to install a target with the
-MACOSX_BUNDLE property set.  CMake 2.4 and below did not distinguish
+This policy determines whether the :command:`install(TARGETS)` command must be
+given a ``BUNDLE DESTINATION`` when asked to install a target with the
+:prop_tgt:`MACOSX_BUNDLE` property set.  CMake 2.4 and below did not distinguish
 application bundles from normal executables when installing targets.
-CMake 2.6 provides a BUNDLE option to the install(TARGETS) command
-that specifies rules specific to application bundles on the Mac.
+CMake 2.6 provides a ``BUNDLE`` option to the :command:`install(TARGETS)`
+command that specifies rules specific to application bundles on the Mac.
 Projects should use this option when installing a target with the
-MACOSX_BUNDLE property set.
+:prop_tgt:`MACOSX_BUNDLE` property set.
 
-The OLD behavior for this policy is to fall back to the RUNTIME
-DESTINATION if a BUNDLE DESTINATION is not given.  The NEW behavior
-for this policy is to produce an error if a bundle target is installed
-without a BUNDLE DESTINATION.
+The ``OLD`` behavior for this policy is to fall back to the
+``RUNTIME DESTINATION`` if a ``BUNDLE DESTINATION`` is not given.  The ``NEW``
+behavior for this policy is to produce an error if a bundle target is installed
+without a ``BUNDLE DESTINATION``.
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0007.rst b/Help/policy/CMP0007.rst
index 3927645..1006ed3 100644
--- a/Help/policy/CMP0007.rst
+++ b/Help/policy/CMP0007.rst
@@ -5,13 +5,13 @@
 
 This policy determines whether the list command will ignore empty
 elements in the list.  CMake 2.4 and below list commands ignored all
-empty elements in the list.  For example, a;b;;c would have length 3
-and not 4.  The OLD behavior for this policy is to ignore empty list
-elements.  The NEW behavior for this policy is to correctly count
+empty elements in the list.  For example, ``a;b;;c`` would have length 3
+and not 4.  The ``OLD`` behavior for this policy is to ignore empty list
+elements.  The ``NEW`` behavior for this policy is to correctly count
 empty elements in a list.
 
 This policy was introduced in CMake version 2.6.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0008.rst b/Help/policy/CMP0008.rst
index f1e2ddd..18ede82 100644
--- a/Help/policy/CMP0008.rst
+++ b/Help/policy/CMP0008.rst
@@ -9,26 +9,27 @@
 
   target_link_libraries(myexe /full/path/to/somelib)
 
-where "somelib" is supposed to be a valid library file name such as
-"libsomelib.a" or "somelib.lib".  For Makefile generators this
+where ``somelib`` is supposed to be a valid library file name such as
+``libsomelib.a`` or ``somelib.lib``.  For Makefile generators this
 produces an error at build time because the dependency on the full
-path cannot be found.  For VS IDE and Xcode generators this used to
+path cannot be found.  For :ref:`Visual Studio Generators` IDE
+and :generator:`Xcode` generators this used to
 work by accident because CMake would always split off the library
 directory and ask the linker to search for the library by name
-(-lsomelib or somelib.lib).  Despite the failure with Makefiles, some
-projects have code like this and build only with VS and/or Xcode.
+(``-lsomelib`` or ``somelib.lib``).  Despite the failure with Makefiles, some
+projects have code like this and build only with Visual Studio and/or Xcode.
 This version of CMake prefers to pass the full path directly to the
 native build tool, which will fail in this case because it does not
 name a valid library file.
 
 This policy determines what to do with full paths that do not appear
-to name a valid library file.  The OLD behavior for this policy is to
+to name a valid library file.  The ``OLD`` behavior for this policy is to
 split the library name from the path and ask the linker to search for
-it.  The NEW behavior for this policy is to trust the given path and
+it.  The ``NEW`` behavior for this policy is to trust the given path and
 pass it directly to the native build tool unchanged.
 
 This policy was introduced in CMake version 2.6.1.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0009.rst b/Help/policy/CMP0009.rst
index 44baeb4..27cfde0 100644
--- a/Help/policy/CMP0009.rst
+++ b/Help/policy/CMP0009.rst
@@ -3,19 +3,19 @@
 
 FILE GLOB_RECURSE calls should not follow symlinks by default.
 
-In CMake 2.6.1 and below, FILE GLOB_RECURSE calls would follow through
-symlinks, sometimes coming up with unexpectedly large result sets
+In CMake 2.6.1 and below, :command:`file(GLOB_RECURSE)` calls would follow
+through symlinks, sometimes coming up with unexpectedly large result sets
 because of symlinks to top level directories that contain hundreds of
 thousands of files.
 
 This policy determines whether or not to follow symlinks encountered
-during a FILE GLOB_RECURSE call.  The OLD behavior for this policy is
-to follow the symlinks.  The NEW behavior for this policy is not to
-follow the symlinks by default, but only if FOLLOW_SYMLINKS is given
-as an additional argument to the FILE command.
+during a :command:`file(GLOB_RECURSE)` call.  The ``OLD`` behavior for this
+policy is to follow the symlinks.  The ``NEW`` behavior for this policy is not
+to follow the symlinks by default, but only if ``FOLLOW_SYMLINKS`` is given
+as an additional argument to the ``FILE`` command.
 
 This policy was introduced in CMake version 2.6.2.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0010.rst b/Help/policy/CMP0010.rst
index 344d704..cfae498 100644
--- a/Help/policy/CMP0010.rst
+++ b/Help/policy/CMP0010.rst
@@ -4,17 +4,17 @@
 Bad variable reference syntax is an error.
 
 In CMake 2.6.2 and below, incorrect variable reference syntax such as
-a missing close-brace ("${FOO") was reported but did not stop
+a missing close-brace (``${FOO``) was reported but did not stop
 processing of CMake code.  This policy determines whether a bad
-variable reference is an error.  The OLD behavior for this policy is
+variable reference is an error.  The ``OLD`` behavior for this policy is
 to warn about the error, leave the string untouched, and continue.
-The NEW behavior for this policy is to report an error.
+The ``NEW`` behavior for this policy is to report an error.
 
 If :policy:`CMP0053` is set to ``NEW``, this policy has no effect
 and is treated as always being ``NEW``.
 
 This policy was introduced in CMake version 2.6.3.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0011.rst b/Help/policy/CMP0011.rst
index d281e0e..257415c 100644
--- a/Help/policy/CMP0011.rst
+++ b/Help/policy/CMP0011.rst
@@ -1,24 +1,25 @@
 CMP0011
 -------
 
-Included scripts do automatic cmake_policy PUSH and POP.
+Included scripts do automatic :command:`cmake_policy` PUSH and POP.
 
 In CMake 2.6.2 and below, CMake Policy settings in scripts loaded by
-the include() and find_package() commands would affect the includer.
-Explicit invocations of cmake_policy(PUSH) and cmake_policy(POP) were
-required to isolate policy changes and protect the includer.  While
-some scripts intend to affect the policies of their includer, most do
-not.  In CMake 2.6.3 and above, include() and find_package() by
-default PUSH and POP an entry on the policy stack around an included
-script, but provide a NO_POLICY_SCOPE option to disable it.  This
-policy determines whether or not to imply NO_POLICY_SCOPE for
-compatibility.  The OLD behavior for this policy is to imply
-NO_POLICY_SCOPE for include() and find_package() commands.  The NEW
-behavior for this policy is to allow the commands to do their default
-cmake_policy PUSH and POP.
+the :command:`include` and :command:`find_package` commands would affect
+the includer.  Explicit invocations of ``cmake_policy(PUSH)`` and
+``cmake_policy(POP)`` were required to isolate policy changes and protect
+the includer.  While some scripts intend to affect the policies of their
+includer, most do not.  In CMake 2.6.3 and above, :command:`include` and
+:command:`find_package` by default ``PUSH`` and ``POP`` an entry on
+the policy stack around an included
+script, but provide a ``NO_POLICY_SCOPE`` option to disable it.  This
+policy determines whether or not to imply ``NO_POLICY_SCOPE`` for
+compatibility.  The ``OLD`` behavior for this policy is to imply
+``NO_POLICY_SCOPE`` for :command:`include` and :command:`find_package` commands.
+The ``NEW`` behavior for this policy is to allow the commands to do
+their default cmake_policy ``PUSH`` and ``POP``.
 
 This policy was introduced in CMake version 2.6.3.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0012.rst b/Help/policy/CMP0012.rst
index 85d64f4..17ec8d3 100644
--- a/Help/policy/CMP0012.rst
+++ b/Help/policy/CMP0012.rst
@@ -1,27 +1,28 @@
 CMP0012
 -------
 
-if() recognizes numbers and boolean constants.
+:command:`if` recognizes numbers and boolean constants.
 
-In CMake versions 2.6.4 and lower the if() command implicitly
+In CMake versions 2.6.4 and lower the :command:`if` command implicitly
 dereferenced arguments corresponding to variables, even those named
-like numbers or boolean constants, except for 0 and 1.  Numbers and
-boolean constants such as true, false, yes, no, on, off, y, n,
-notfound, ignore (all case insensitive) were recognized in some cases
-but not all.  For example, the code "if(TRUE)" might have evaluated as
-false.  Numbers such as 2 were recognized only in boolean expressions
-like "if(NOT 2)" (leading to false) but not as a single-argument like
-"if(2)" (also leading to false).  Later versions of CMake prefer to
+like numbers or boolean constants, except for ``0`` and ``1``.  Numbers and
+boolean constants such as ``true``, ``false``, ``yes``, ``no``, ``on``,
+``off``, ``y``, ``n``, ``notfound``, ``ignore`` (all case insensitive)
+were recognized in some cases but not all.  For example, the code ``if(TRUE)``
+might have evaluated as ``false``.
+Numbers such as 2 were recognized only in boolean expressions
+like ``if(NOT 2)`` (leading to ``false``) but not as a single-argument like
+``if(2)`` (also leading to ``false``).  Later versions of CMake prefer to
 treat numbers and boolean constants literally, so they should not be
 used as variable names.
 
-The OLD behavior for this policy is to implicitly dereference
-variables named like numbers and boolean constants.  The NEW behavior
+The ``OLD`` behavior for this policy is to implicitly dereference
+variables named like numbers and boolean constants.  The ``NEW`` behavior
 for this policy is to recognize numbers and boolean constants without
 dereferencing variables with such names.
 
 This policy was introduced in CMake version 2.8.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0013.rst b/Help/policy/CMP0013.rst
index 2fabb89..dbd67a1 100644
--- a/Help/policy/CMP0013.rst
+++ b/Help/policy/CMP0013.rst
@@ -9,13 +9,13 @@
 tree and could lead to strange behavior.  CMake 2.6.4 and above
 explicitly detect duplicate binary directories.  CMake 2.6.4 always
 considers this case an error.  In CMake 2.8.0 and above this policy
-determines whether or not the case is an error.  The OLD behavior for
+determines whether or not the case is an error.  The ``OLD`` behavior for
 this policy is to allow duplicate binary directories.  The NEW
 behavior for this policy is to disallow duplicate binary directories
 with an error.
 
 This policy was introduced in CMake version 2.8.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0014.rst b/Help/policy/CMP0014.rst
index f1f7b77..331dde5 100644
--- a/Help/policy/CMP0014.rst
+++ b/Help/policy/CMP0014.rst
@@ -1,17 +1,17 @@
 CMP0014
 -------
 
-Input directories must have CMakeLists.txt.
+Input directories must have ``CMakeLists.txt``.
 
-CMake versions before 2.8 silently ignored missing CMakeLists.txt
-files in directories referenced by add_subdirectory() or subdirs(),
+CMake versions before 2.8 silently ignored missing ``CMakeLists.txt``
+files in directories referenced by :command:`add_subdirectory` or  :command:`subdirs`,
 treating them as if present but empty.  In CMake 2.8.0 and above this
-policy determines whether or not the case is an error.  The OLD
-behavior for this policy is to silently ignore the problem.  The NEW
-behavior for this policy is to report an error.
+:command:`cmake_policy` determines whether or not the case is an error.
+The ``OLD`` behavior for this policy is to silently ignore the problem.
+The ``NEW`` behavior for this policy is to report an error.
 
 This policy was introduced in CMake version 2.8.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0015.rst b/Help/policy/CMP0015.rst
index 9a48e3d..90d5203 100644
--- a/Help/policy/CMP0015.rst
+++ b/Help/policy/CMP0015.rst
@@ -1,19 +1,19 @@
 CMP0015
 -------
 
-link_directories() treats paths relative to the source dir.
+ :command:`link_directories` treats paths relative to the source dir.
 
-In CMake 2.8.0 and lower the link_directories() command passed
+In CMake 2.8.0 and lower the :command:`link_directories` command passed
 relative paths unchanged to the linker.  In CMake 2.8.1 and above the
-link_directories() command prefers to interpret relative paths with
-respect to CMAKE_CURRENT_SOURCE_DIR, which is consistent with
-include_directories() and other commands.  The OLD behavior for this
-policy is to use relative paths verbatim in the linker command.  The
-NEW behavior for this policy is to convert relative paths to absolute
-paths by appending the relative path to CMAKE_CURRENT_SOURCE_DIR.
+:command:`link_directories` command prefers to interpret relative paths with
+respect to ``CMAKE_CURRENT_SOURCE_DIR``, which is consistent with
+:command:`include_directories` and other commands.  The ``OLD`` behavior for
+this policy is to use relative paths verbatim in the linker command.  The
+``NEW`` behavior for this policy is to convert relative paths to absolute
+paths by appending the relative path to ``CMAKE_CURRENT_SOURCE_DIR``.
 
 This policy was introduced in CMake version 2.8.1.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0016.rst b/Help/policy/CMP0016.rst
index cc898c8..026d02a 100644
--- a/Help/policy/CMP0016.rst
+++ b/Help/policy/CMP0016.rst
@@ -1,15 +1,16 @@
 CMP0016
 -------
 
-target_link_libraries() reports error if its only argument is not a target.
+:command:`target_link_libraries` reports error if its only argument
+is not a target.
 
-In CMake 2.8.2 and lower the target_link_libraries() command silently
+In CMake 2.8.2 and lower the :command:`target_link_libraries` command silently
 ignored if it was called with only one argument, and this argument
 wasn't a valid target.  In CMake 2.8.3 and above it reports an error
 in this case.
 
 This policy was introduced in CMake version 2.8.3.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0017.rst b/Help/policy/CMP0017.rst
index 9f0f038..ca4664e 100644
--- a/Help/policy/CMP0017.rst
+++ b/Help/policy/CMP0017.rst
@@ -4,18 +4,18 @@
 Prefer files from the CMake module directory when including from there.
 
 Starting with CMake 2.8.4, if a cmake-module shipped with CMake (i.e.
-located in the CMake module directory) calls include() or
-find_package(), the files located in the CMake module directory are
-preferred over the files in CMAKE_MODULE_PATH.  This makes sure that
-the modules belonging to CMake always get those files included which
+located in the CMake module directory) calls :command:`include` or
+:command:`find_package`, the files located in the CMake module directory are
+preferred over the files in :variable:`CMAKE_MODULE_PATH`.  This makes sure
+that the modules belonging to CMake always get those files included which
 they expect, and against which they were developed and tested.  In all
-other cases, the files found in CMAKE_MODULE_PATH still take
-precedence over the ones in the CMake module directory.  The OLD
+other cases, the files found in :variable:`CMAKE_MODULE_PATH` still take
+precedence over the ones in the CMake module directory.  The ``OLD``
 behavior is to always prefer files from CMAKE_MODULE_PATH over files
 from the CMake modules directory.
 
 This policy was introduced in CMake version 2.8.4.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0018.rst b/Help/policy/CMP0018.rst
index a3a7a12..6248406 100644
--- a/Help/policy/CMP0018.rst
+++ b/Help/policy/CMP0018.rst
@@ -1,34 +1,35 @@
 CMP0018
 -------
 
-Ignore CMAKE_SHARED_LIBRARY_<Lang>_FLAGS variable.
+Ignore ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` variable.
 
-CMake 2.8.8 and lower compiled sources in SHARED and MODULE libraries
-using the value of the undocumented CMAKE_SHARED_LIBRARY_<Lang>_FLAGS
+CMake 2.8.8 and lower compiled sources in ``SHARED`` and ``MODULE`` libraries
+using the value of the undocumented ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS``
 platform variable.  The variable contained platform-specific flags
 needed to compile objects for shared libraries.  Typically it included
-a flag such as -fPIC for position independent code but also included
+a flag such as ``-fPIC`` for position independent code but also included
 other flags needed on certain platforms.  CMake 2.8.9 and higher
-prefer instead to use the POSITION_INDEPENDENT_CODE target property to
-determine what targets should be position independent, and new
+prefer instead to use the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
+property to determine what targets should be position independent, and new
 undocumented platform variables to select flags while ignoring
-CMAKE_SHARED_LIBRARY_<Lang>_FLAGS completely.
+``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` completely.
 
 The default for either approach produces identical compilation flags,
-but if a project modifies CMAKE_SHARED_LIBRARY_<Lang>_FLAGS from its
+but if a project modifies ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` from its
 original value this policy determines which approach to use.
 
-The OLD behavior for this policy is to ignore the
-POSITION_INDEPENDENT_CODE property for all targets and use the
-modified value of CMAKE_SHARED_LIBRARY_<Lang>_FLAGS for SHARED and
-MODULE libraries.
+The ``OLD`` behavior for this policy is to ignore the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property for all targets and use the
+modified value of ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` for ``SHARED`` and
+``MODULE`` libraries.
 
-The NEW behavior for this policy is to ignore
-CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and
-honor the POSITION_INDEPENDENT_CODE target property.
+The ``NEW`` behavior for this policy is to ignore
+``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` whether it is modified or not and
+honor the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property.
 
 This policy was introduced in CMake version 2.8.9.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0019.rst b/Help/policy/CMP0019.rst
index 2e3557d..682dcdf 100644
--- a/Help/policy/CMP0019.rst
+++ b/Help/policy/CMP0019.rst
@@ -11,12 +11,12 @@
 evaluated during CMake language processing.  CMake 2.8.11 and higher
 prefer to skip the extra evaluation.
 
-The OLD behavior for this policy is to re-evaluate the values for
-strict compatibility.  The NEW behavior for this policy is to leave
+The ``OLD`` behavior for this policy is to re-evaluate the values for
+strict compatibility.  The ``NEW`` behavior for this policy is to leave
 the values untouched.
 
 This policy was introduced in CMake version 2.8.11.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0020.rst b/Help/policy/CMP0020.rst
index 75ca9de..6d27684 100644
--- a/Help/policy/CMP0020.rst
+++ b/Help/policy/CMP0020.rst
@@ -1,27 +1,27 @@
 CMP0020
 -------
 
-Automatically link Qt executables to qtmain target on Windows.
+Automatically link Qt executables to ``qtmain`` target on Windows.
 
 CMake 2.8.10 and lower required users of Qt to always specify a link
-dependency to the qtmain.lib static library manually on Windows.
+dependency to the ``qtmain.lib`` static library manually on Windows.
 CMake 2.8.11 gained the ability to evaluate generator expressions
-while determining the link dependencies from IMPORTED targets.  This
+while determining the link dependencies from ``IMPORTED`` targets.  This
 allows CMake itself to automatically link executables which link to Qt
-to the qtmain.lib library when using IMPORTED Qt targets.  For
-applications already linking to qtmain.lib, this should have little
+to the ``qtmain.lib`` library when using ``IMPORTED`` Qt targets.  For
+applications already linking to ``qtmain.lib``, this should have little
 impact.  For applications which supply their own alternative WinMain
 implementation and for applications which use the QAxServer library,
 this automatic linking will need to be disabled as per the
 documentation.
 
-The OLD behavior for this policy is not to link executables to
-qtmain.lib automatically when they link to the QtCore IMPORTED target.
-The NEW behavior for this policy is to link executables to qtmain.lib
-automatically when they link to QtCore IMPORTED target.
+The ``OLD`` behavior for this policy is not to link executables to
+``qtmain.lib`` automatically when they link to the QtCore ``IMPORTED`` target.
+The ``NEW`` behavior for this policy is to link executables to ``qtmain.lib``
+automatically when they link to QtCore ``IMPORTED`` target.
 
 This policy was introduced in CMake version 2.8.11.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0021.rst b/Help/policy/CMP0021.rst
index 3a792ca..937b106 100644
--- a/Help/policy/CMP0021.rst
+++ b/Help/policy/CMP0021.rst
@@ -1,20 +1,21 @@
 CMP0021
 -------
 
-Fatal error on relative paths in INCLUDE_DIRECTORIES target property.
+Fatal error on relative paths in :prop_tgt:`INCLUDE_DIRECTORIES` target
+property.
 
-CMake 2.8.10.2 and lower allowed the INCLUDE_DIRECTORIES target
+CMake 2.8.10.2 and lower allowed the :prop_tgt:`INCLUDE_DIRECTORIES` target
 property to contain relative paths.  The base path for such relative
-entries is not well defined.  CMake 2.8.12 issues a FATAL_ERROR if the
-INCLUDE_DIRECTORIES property contains a relative path.
+entries is not well defined.  CMake 2.8.12 issues a ``FATAL_ERROR`` if the
+:prop_tgt:`INCLUDE_DIRECTORIES` property contains a relative path.
 
-The OLD behavior for this policy is not to warn about relative paths
-in the INCLUDE_DIRECTORIES target property.  The NEW behavior for this
-policy is to issue a FATAL_ERROR if INCLUDE_DIRECTORIES contains a
+The ``OLD`` behavior for this policy is not to warn about relative paths
+in the ``INCLUDE_DIRECTORIES`` target property.  The ``NEW`` behavior for this
+policy is to issue a ``FATAL_ERROR`` if ``INCLUDE_DIRECTORIES`` contains a
 relative path.
 
 This policy was introduced in CMake version 2.8.12.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0022.rst b/Help/policy/CMP0022.rst
index 579d09a..be60e37 100644
--- a/Help/policy/CMP0022.rst
+++ b/Help/policy/CMP0022.rst
@@ -1,39 +1,39 @@
 CMP0022
 -------
 
-INTERFACE_LINK_LIBRARIES defines the link interface.
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` defines the link interface.
 
 CMake 2.8.11 constructed the 'link interface' of a target from
 properties matching ``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?``.
 The modern way to specify config-sensitive content is to use generator
 expressions and the ``IMPORTED_`` prefix makes uniform processing of the
 link interface with generator expressions impossible.  The
-INTERFACE_LINK_LIBRARIES target property was introduced as a
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property was introduced as a
 replacement in CMake 2.8.12.  This new property is named consistently
-with the INTERFACE_COMPILE_DEFINITIONS, INTERFACE_INCLUDE_DIRECTORIES
-and INTERFACE_COMPILE_OPTIONS properties.  For in-build targets, CMake
+with the ``INTERFACE_COMPILE_DEFINITIONS``, ``INTERFACE_INCLUDE_DIRECTORIES``
+and ``INTERFACE_COMPILE_OPTIONS`` properties.  For in-build targets, CMake
 will use the INTERFACE_LINK_LIBRARIES property as the source of the
-link interface only if policy CMP0022 is NEW.  When exporting a target
-which has this policy set to NEW, only the INTERFACE_LINK_LIBRARIES
-property will be processed and generated for the IMPORTED target by
-default.  A new option to the install(EXPORT) and export commands
+link interface only if policy ``CMP0022`` is ``NEW``.  When exporting a target
+which has this policy set to ``NEW``, only the :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+property will be processed and generated for the ``IMPORTED`` target by
+default.  A new option to the :command:`install(EXPORT)` and export commands
 allows export of the old-style properties for compatibility with
 downstream users of CMake versions older than 2.8.12.  The
-target_link_libraries command will no longer populate the properties
-matching LINK_INTERFACE_LIBRARIES(_<CONFIG>)? if this policy is NEW.
+:command:`target_link_libraries` command will no longer populate the properties
+matching ``LINK_INTERFACE_LIBRARIES(_<CONFIG>)?`` if this policy is ``NEW``.
 
 Warning-free future-compatible code which works with CMake 2.8.7 onwards
 can be written by using the ``LINK_PRIVATE`` and ``LINK_PUBLIC`` keywords
 of :command:`target_link_libraries`.
 
-The OLD behavior for this policy is to ignore the
-INTERFACE_LINK_LIBRARIES property for in-build targets.  The NEW
-behavior for this policy is to use the INTERFACE_LINK_LIBRARIES
+The ``OLD`` behavior for this policy is to ignore the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property for in-build targets.
+The ``NEW`` behavior for this policy is to use the ``INTERFACE_LINK_LIBRARIES``
 property for in-build targets, and ignore the old properties matching
 ``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?``.
 
 This policy was introduced in CMake version 2.8.12.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0023.rst b/Help/policy/CMP0023.rst
index 76a4900..3c72c81 100644
--- a/Help/policy/CMP0023.rst
+++ b/Help/policy/CMP0023.rst
@@ -1,15 +1,15 @@
 CMP0023
 -------
 
-Plain and keyword target_link_libraries signatures cannot be mixed.
+Plain and keyword :command:`target_link_libraries` signatures cannot be mixed.
 
-CMake 2.8.12 introduced the target_link_libraries signature using the
-PUBLIC, PRIVATE, and INTERFACE keywords to generalize the LINK_PUBLIC
-and LINK_PRIVATE keywords introduced in CMake 2.8.7.  Use of
-signatures with any of these keywords sets the link interface of a
+CMake 2.8.12 introduced the :command:`target_link_libraries` signature using
+the ``PUBLIC``, ``PRIVATE``, and ``INTERFACE`` keywords to generalize the
+``LINK_PUBLIC`` and ``LINK_PRIVATE`` keywords introduced in CMake 2.8.7.
+Use of signatures with any of these keywords sets the link interface of a
 target explicitly, even if empty.  This produces confusing behavior
 when used in combination with the historical behavior of the plain
-target_link_libraries signature.  For example, consider the code:
+:command:`target_link_libraries` signature.  For example, consider the code:
 
 ::
 
@@ -20,16 +20,16 @@
 CMake would use the link implementation, A, as the link interface.
 However, the second line sets the link interface to empty.  In order
 to avoid this subtle behavior CMake now prefers to disallow mixing the
-plain and keyword signatures of target_link_libraries for a single
+plain and keyword signatures of :command:`target_link_libraries` for a single
 target.
 
-The OLD behavior for this policy is to allow keyword and plain
-target_link_libraries signatures to be mixed.  The NEW behavior for
+The ``OLD`` behavior for this policy is to allow keyword and plain
+:command:`target_link_libraries` signatures to be mixed.  The ``NEW`` behavior for
 this policy is to not to allow mixing of the keyword and plain
 signatures.
 
 This policy was introduced in CMake version 2.8.12.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0024.rst b/Help/policy/CMP0024.rst
index 272a56c..6e24b04 100644
--- a/Help/policy/CMP0024.rst
+++ b/Help/policy/CMP0024.rst
@@ -3,22 +3,23 @@
 
 Disallow include export result.
 
-CMake 2.8.12 and lower allowed use of the include() command with the
-result of the export() command.  This relies on the assumption that
-the export() command has an immediate effect at configure-time during
+CMake 2.8.12 and lower allowed use of the :command:`include` command with the
+result of the :command:`export` command.  This relies on the assumption that
+the :command:`export` command has an immediate effect at configure-time during
 a cmake run.  Certain properties of targets are not fully determined
 until later at generate-time, such as the link language and complete
 list of link libraries.  Future refactoring will change the effect of
-the export() command to be executed at generate-time.  Use ALIAS
+the :command:`export` command to be executed at generate-time.  Use ``ALIAS``
 targets instead in cases where the goal is to refer to targets by
 another name.
 
-The OLD behavior for this policy is to allow including the result of
-an export() command.  The NEW behavior for this policy is not to
-allow including the result of an export() command.
+The ``OLD`` behavior for this policy is to allow including the result of
+an :command:`export` command.  The ``NEW`` behavior for this policy is not to
+allow including the result of an :command:`export` command.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0025.rst b/Help/policy/CMP0025.rst
index 62dd509..ba5e1e9 100644
--- a/Help/policy/CMP0025.rst
+++ b/Help/policy/CMP0025.rst
@@ -15,13 +15,13 @@
 :command:`enable_language` command.  The policy must be set prior
 to the invocation of either command.
 
-The OLD behavior for this policy is to use compiler id ``Clang``.  The
-NEW behavior for this policy is to use compiler id ``AppleClang``.
+The ``OLD`` behavior for this policy is to use compiler id ``Clang``.  The
+``NEW`` behavior for this policy is to use compiler id ``AppleClang``.
 
 This policy was introduced in CMake version 3.0.  Use the
-:command:`cmake_policy` command to set this policy to OLD or NEW explicitly.
-Unlike most policies, CMake version |release| does *not* warn
-by default when this policy is not set and simply uses OLD behavior.
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly.  Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
 See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0025 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
diff --git a/Help/policy/CMP0026.rst b/Help/policy/CMP0026.rst
index 3fe1374..3401d4a 100644
--- a/Help/policy/CMP0026.rst
+++ b/Help/policy/CMP0026.rst
@@ -3,26 +3,27 @@
 
 Disallow use of the LOCATION property for build targets.
 
-CMake 2.8.12 and lower allowed reading the LOCATION target
+CMake 2.8.12 and lower allowed reading the :prop_tgt:`LOCATION` target
 property (and configuration-specific variants) to
 determine the eventual location of build targets.  This relies on the
 assumption that all necessary information is available at
 configure-time to determine the final location and filename of the
 target.  However, this property is not fully determined until later at
-generate-time.  At generate time, the $<TARGET_FILE> generator
-expression can be used to determine the eventual LOCATION of a target
+generate-time.  At generate time, the ``$<TARGET_FILE>`` generator
+expression can be used to determine the eventual :prop_tgt:`LOCATION` of a target
 output.
 
-Code which reads the LOCATION target property can be ported to use the
-$<TARGET_FILE> generator expression together with the file(GENERATE)
-subcommand to generate a file containing the target location.
+Code which reads the :prop_tgt:`LOCATION` target property can be ported to
+use the ``$<TARGET_FILE>`` generator expression together with the
+:command:`file(GENERATE)` subcommand to generate a file containing
+the target location.
 
-The OLD behavior for this policy is to allow reading the LOCATION
-properties from build-targets.  The NEW behavior for this policy is to
-not to allow reading the LOCATION properties from build-targets.
+The ``OLD`` behavior for this policy is to allow reading the :prop_tgt:`LOCATION`
+properties from build-targets.  The ``NEW`` behavior for this policy is to
+not to allow reading the :prop_tgt:`LOCATION` properties from build-targets.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0027.rst b/Help/policy/CMP0027.rst
index 28913ce..bf7b6a9 100644
--- a/Help/policy/CMP0027.rst
+++ b/Help/policy/CMP0027.rst
@@ -4,24 +4,24 @@
 Conditionally linked imported targets with missing include directories.
 
 CMake 2.8.11 introduced introduced the concept of
-INTERFACE_INCLUDE_DIRECTORIES, and a check at cmake time that the
-entries in the INTERFACE_INCLUDE_DIRECTORIES of an IMPORTED target
-actually exist.  CMake 2.8.11 also introduced generator expression
-support in the target_link_libraries command.  However, if an imported
-target is linked as a result of a generator expression evaluation, the
-entries in the INTERFACE_INCLUDE_DIRECTORIES of that target were not
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`, and a check at cmake time that the
+entries in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of an ``IMPORTED``
+target actually exist.  CMake 2.8.11 also introduced generator expression
+support in the :command:`target_link_libraries` command.  However, if an
+imported target is linked as a result of a generator expression evaluation, the
+entries in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of that target were not
 checked for existence as they should be.
 
-The OLD behavior of this policy is to report a warning if an entry in
-the INTERFACE_INCLUDE_DIRECTORIES of a generator-expression
-conditionally linked IMPORTED target does not exist.
+The ``OLD`` behavior of this policy is to report a warning if an entry in
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a generator-expression
+conditionally linked ``IMPORTED`` target does not exist.
 
-The NEW behavior of this policy is to report an error if an entry in
-the INTERFACE_INCLUDE_DIRECTORIES of a generator-expression
-conditionally linked IMPORTED target does not exist.
+The ``NEW`` behavior of this policy is to report an error if an entry in
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a generator-expression
+conditionally linked ``IMPORTED`` target does not exist.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0028.rst b/Help/policy/CMP0028.rst
index be57125..ab38229 100644
--- a/Help/policy/CMP0028.rst
+++ b/Help/policy/CMP0028.rst
@@ -1,25 +1,25 @@
 CMP0028
 -------
 
-Double colon in target name means ALIAS or IMPORTED target.
+Double colon in target name means ``ALIAS`` or ``IMPORTED`` target.
 
 CMake 2.8.12 and lower allowed the use of targets and files with double
-colons in target_link_libraries, with some buildsystem generators.
+colons in :command:`target_link_libraries`, with some buildsystem generators.
 
-The use of double-colons is a common pattern used to namespace IMPORTED
-targets and ALIAS targets.  When computing the link dependencies of a target,
-the name of each dependency could either be a target, or a file on disk.
-Previously, if a target was not found with a matching name, the name was
-considered to refer to a file on disk.  This can lead to confusing error
+The use of double-colons is a common pattern used to namespace ``IMPORTED``
+targets and ``ALIAS`` targets.  When computing the link dependencies of
+a target, the name of each dependency could either be a target, or a file
+on disk.  Previously, if a target was not found with a matching name, the name
+was considered to refer to a file on disk.  This can lead to confusing error
 messages if there is a typo in what should be a target name.
 
-The OLD behavior for this policy is to search for targets, then files on disk,
-even if the search term contains double-colons.  The NEW behavior for this
-policy is to issue a FATAL_ERROR if a link dependency contains
-double-colons but is not an IMPORTED target or an ALIAS target.
+The ``OLD`` behavior for this policy is to search for targets, then files on
+disk, even if the search term contains double-colons.  The ``NEW`` behavior
+for this policy is to issue a ``FATAL_ERROR`` if a link dependency contains
+double-colons but is not an ``IMPORTED`` target or an ``ALIAS`` target.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0037.rst b/Help/policy/CMP0037.rst
index d1afeb7..9895fb0 100644
--- a/Help/policy/CMP0037.rst
+++ b/Help/policy/CMP0037.rst
@@ -10,24 +10,25 @@
 diagnostics expect target names to match a restricted pattern.
 
 Target names may contain upper and lower case letters, numbers, the underscore
-character (_), dot(.), plus(+) and minus(-).  As a special case, ALIAS
-targets and IMPORTED targets may contain two consecutive colons.
+character (``_``), dot(``.``), plus(``+``) and minus(``-``).
+As a special case, ``ALIAS`` and ``IMPORTED`` targets may contain
+two consecutive colons.
 
 Target names reserved by one or more CMake generators are not allowed.
-Among others these include "all", "clean", "help", and "install".
+Among others these include ``all``, ``clean``, ``help``, and ``install``.
 
-Target names associated with optional features, such as "test" and "package",
-may also be reserved.  CMake 3.10 and below always reserve them.  CMake 3.11
-and above reserve them only when the corresponding feature is enabled
-(e.g. by including the :module:`CTest` or :module:`CPack` modules).
+Target names associated with optional features, such as ``test`` and
+``package``, may also be reserved.  CMake 3.10 and below always reserve them.
+CMake 3.11 and above reserve them only when the corresponding feature is
+enabled (e.g. by including the :module:`CTest` or :module:`CPack` modules).
 
-The OLD behavior for this policy is to allow creating targets with
+The ``OLD`` behavior for this policy is to allow creating targets with
 reserved names or which do not match the validity pattern.
-The NEW behavior for this policy is to report an error
+The ``NEW`` behavior for this policy is to report an error
 if an add_* command is used with an invalid target name.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0038.rst b/Help/policy/CMP0038.rst
index a306d90..7fb2209 100644
--- a/Help/policy/CMP0038.rst
+++ b/Help/policy/CMP0038.rst
@@ -7,12 +7,12 @@
 a :command:`target_link_libraries` call. This is an indicator of a bug in
 user code.
 
-The OLD behavior for this policy is to ignore targets which list themselves
-in their own link implementation.  The NEW behavior for this policy is to
+The ``OLD`` behavior for this policy is to ignore targets which list themselves
+in their own link implementation.  The ``NEW`` behavior for this policy is to
 report an error if a target attempts to link to itself.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0039.rst b/Help/policy/CMP0039.rst
index 97d78ae..4b14e21 100644
--- a/Help/policy/CMP0039.rst
+++ b/Help/policy/CMP0039.rst
@@ -7,13 +7,13 @@
 position of the :command:`target_link_libraries` command. This is an indicator
 of a bug in user code.
 
-The OLD behavior for this policy is to ignore attempts to set the link
-libraries of utility targets.  The NEW behavior for this policy is to
+The ``OLD`` behavior for this policy is to ignore attempts to set the link
+libraries of utility targets.  The ``NEW`` behavior for this policy is to
 report an error if an attempt is made to set the link libraries of a
 utility target.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0041.rst b/Help/policy/CMP0041.rst
index f027d5d..3b4df36 100644
--- a/Help/policy/CMP0041.rst
+++ b/Help/policy/CMP0041.rst
@@ -15,13 +15,13 @@
 on an :prop_tgt:`IMPORTED` target for the install location should not contain
 paths in the source directory or the build directory.
 
-The OLD behavior for this policy is to ignore relative path entries if they
-contain a generator expression. The NEW behavior for this policy is to report
+The ``OLD`` behavior for this policy is to ignore relative path entries if they
+contain a generator expression. The ``NEW`` behavior for this policy is to report
 an error if a generator expression appears in another location and the path is
 relative.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0042.rst b/Help/policy/CMP0042.rst
index 31314b2..0877564 100644
--- a/Help/policy/CMP0042.rst
+++ b/Help/policy/CMP0042.rst
@@ -15,7 +15,7 @@
 variables.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0043.rst b/Help/policy/CMP0043.rst
index 9e427c3..05210ac 100644
--- a/Help/policy/CMP0043.rst
+++ b/Help/policy/CMP0043.rst
@@ -35,13 +35,13 @@
     COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DIR_DEBUG_MODE>
   )
 
-The OLD behavior for this policy is to consume the content of the suffixed
+The ``OLD`` behavior for this policy is to consume the content of the suffixed
 :prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property when generating the
-compilation command. The NEW behavior for this policy is to ignore the content
+compilation command. The ``NEW`` behavior for this policy is to ignore the content
 of the :prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property .
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0044.rst b/Help/policy/CMP0044.rst
index 02afa9f..6a4d040 100644
--- a/Help/policy/CMP0044.rst
+++ b/Help/policy/CMP0044.rst
@@ -9,13 +9,13 @@
 possible valid values are lowercase, but the comparison with the test value
 was performed case-insensitively.
 
-The OLD behavior for this policy is to perform a case-insensitive comparison
-with the value in the ``<LANG>_COMPILER_ID`` expression. The NEW behavior
+The ``OLD`` behavior for this policy is to perform a case-insensitive comparison
+with the value in the ``<LANG>_COMPILER_ID`` expression. The ``NEW`` behavior
 for this policy is to perform a case-sensitive comparison with the value in
 the ``<LANG>_COMPILER_ID`` expression.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0045.rst b/Help/policy/CMP0045.rst
index c7e1a90f6..80e217b 100644
--- a/Help/policy/CMP0045.rst
+++ b/Help/policy/CMP0045.rst
@@ -7,13 +7,13 @@
 a non-existent target argument without issuing any error or warning.  The
 result variable is set to a ``-NOTFOUND`` value.
 
-The OLD behavior for this policy is to issue no warning and set the result
-variable to a ``-NOTFOUND`` value.  The NEW behavior
+The ``OLD`` behavior for this policy is to issue no warning and set the result
+variable to a ``-NOTFOUND`` value.  The ``NEW`` behavior
 for this policy is to issue a ``FATAL_ERROR`` if the command is called with a
 non-existent target.
 
 This policy was introduced in CMake version 3.0.  CMake version
-|release| warns when the policy is not set and uses OLD behavior.  Use
-the cmake_policy command to set it to OLD or NEW explicitly.
+|release| warns when the policy is not set and uses ``OLD`` behavior.  Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0046.rst b/Help/policy/CMP0046.rst
index 576d1b1..bf78584 100644
--- a/Help/policy/CMP0046.rst
+++ b/Help/policy/CMP0046.rst
@@ -6,14 +6,14 @@
 CMake 2.8.12 and lower silently ignored non-existent dependencies
 listed in the :command:`add_dependencies` command.
 
-The OLD behavior for this policy is to silently ignore non-existent
-dependencies. The NEW behavior for this policy is to report an error
+The ``OLD`` behavior for this policy is to silently ignore non-existent
+dependencies. The ``NEW`` behavior for this policy is to report an error
 if non-existent dependencies are listed in the :command:`add_dependencies`
 command.
 
 This policy was introduced in CMake version 3.0.
 CMake version |release| warns when the policy is not set and uses
-OLD behavior.  Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set it
+to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0047.rst b/Help/policy/CMP0047.rst
index 882dd78..9588edd 100644
--- a/Help/policy/CMP0047.rst
+++ b/Help/policy/CMP0047.rst
@@ -15,14 +15,14 @@
 :command:`enable_language` command.  The policy must be set prior
 to the invocation of either command.
 
-The OLD behavior for this policy is to use the ``GNU`` compiler id
-for the qcc and QCC compiler drivers. The NEW behavior for this policy
+The ``OLD`` behavior for this policy is to use the ``GNU`` compiler id
+for the qcc and QCC compiler drivers. The ``NEW`` behavior for this policy
 is to use the ``QCC`` compiler id for those drivers.
 
 This policy was introduced in CMake version 3.0.  Use the
-:command:`cmake_policy` command to set this policy to OLD or NEW explicitly.
-Unlike most policies, CMake version |release| does *not* warn
-by default when this policy is not set and simply uses OLD behavior.
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly.  Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
 See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0047 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
diff --git a/Help/policy/CMP0048.rst b/Help/policy/CMP0048.rst
index 0e7e606..e63ec01 100644
--- a/Help/policy/CMP0048.rst
+++ b/Help/policy/CMP0048.rst
@@ -1,24 +1,24 @@
 CMP0048
 -------
 
-The :command:`project` command manages VERSION variables.
+The :command:`project` command manages ``VERSION`` variables.
 
 CMake version 3.0 introduced the ``VERSION`` option of the :command:`project`
 command to specify a project version as well as the name.  In order to keep
 :variable:`PROJECT_VERSION` and related variables consistent with variable
-:variable:`PROJECT_NAME` it is necessary to set the VERSION variables
+:variable:`PROJECT_NAME` it is necessary to set the ``VERSION`` variables
 to the empty string when no ``VERSION`` is given to :command:`project`.
-However, this can change behavior for existing projects that set VERSION
+However, this can change behavior for existing projects that set ``VERSION``
 variables themselves since :command:`project` may now clear them.
 This policy controls the behavior for compatibility with such projects.
 
-The OLD behavior for this policy is to leave VERSION variables untouched.
-The NEW behavior for this policy is to set VERSION as documented by the
+The ``OLD`` behavior for this policy is to leave ``VERSION`` variables untouched.
+The ``NEW`` behavior for this policy is to set ``VERSION`` as documented by the
 :command:`project` command.
 
 This policy was introduced in CMake version 3.0.
 CMake version |release| warns when the policy is not set and uses
-OLD behavior.  Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0049.rst b/Help/policy/CMP0049.rst
index 291bf57..49b20be 100644
--- a/Help/policy/CMP0049.rst
+++ b/Help/policy/CMP0049.rst
@@ -13,13 +13,13 @@
 
 This was undocumented behavior.
 
-The OLD behavior for this policy is to expand such variables when processing
-the target sources.  The NEW behavior for this policy is to issue an error
+The ``OLD`` behavior for this policy is to expand such variables when processing
+the target sources.  The ``NEW`` behavior for this policy is to issue an error
 if such variables need to be expanded.
 
 This policy was introduced in CMake version 3.0.
 CMake version |release| warns when the policy is not set and uses
-OLD behavior.  Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0050.rst b/Help/policy/CMP0050.rst
index 39e40b6..27e7b1d 100644
--- a/Help/policy/CMP0050.rst
+++ b/Help/policy/CMP0050.rst
@@ -8,13 +8,13 @@
 Modern use of CMake associates custom commands with their output, rather
 than their input.
 
-The OLD behavior for this policy is to allow the use of
-:command:`add_custom_command` SOURCE signatures.  The NEW behavior for this
+The ``OLD`` behavior for this policy is to allow the use of
+:command:`add_custom_command` SOURCE signatures.  The ``NEW`` behavior for this
 policy is to issue an error if such a signature is used.
 
 This policy was introduced in CMake version 3.0.
 CMake version |release| warns when the policy is not set and uses
-OLD behavior.  Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0052.rst b/Help/policy/CMP0052.rst
index 0ea5ace..ee2e6e8 100644
--- a/Help/policy/CMP0052.rst
+++ b/Help/policy/CMP0052.rst
@@ -1,7 +1,8 @@
 CMP0052
 -------
 
-Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES.
+Reject source and build dirs in installed
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`.
 
 CMake 3.0 and lower allowed subdirectories of the source directory or build
 directory to be in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of
@@ -13,9 +14,9 @@
 See :ref:`Include Directories and Usage Requirements` for more on
 specifying include directories for targets.
 
-The OLD behavior for this policy is to export the content of the
+The ``OLD`` behavior for this policy is to export the content of the
 :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` with the source or binary
-directory.  The NEW behavior for this
+directory.  The ``NEW`` behavior for this
 policy is to issue an error if such a directory is used.
 
 This policy was introduced in CMake version 3.1.
diff --git a/Help/policy/CMP0055.rst b/Help/policy/CMP0055.rst
index b3df758..bc5ad08 100644
--- a/Help/policy/CMP0055.rst
+++ b/Help/policy/CMP0055.rst
@@ -7,13 +7,13 @@
 outside of a loop context and also ignored any given arguments.
 This was undefined behavior.
 
-The OLD behavior for this policy is to allow :command:`break` to be placed
-outside of loop contexts and ignores any arguments.  The NEW behavior for this
+The ``OLD`` behavior for this policy is to allow :command:`break` to be placed
+outside of loop contexts and ignores any arguments.  The ``NEW`` behavior for this
 policy is to issue an error if a misplaced break or any arguments are found.
 
 This policy was introduced in CMake version 3.2.
 CMake version |release| warns when the policy is not set and uses
-OLD behavior.  Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0056.rst b/Help/policy/CMP0056.rst
index 3ba89d5..834da84 100644
--- a/Help/policy/CMP0056.rst
+++ b/Help/policy/CMP0056.rst
@@ -14,9 +14,9 @@
 linker flags are honored as well as compiler flags.  This policy
 provides compatibility with the pre-3.2 behavior.
 
-The OLD behavior for this policy is to not set the value of the
+The ``OLD`` behavior for this policy is to not set the value of the
 :variable:`CMAKE_EXE_LINKER_FLAGS` variable in the generated test
-project.  The NEW behavior for this policy is to set the value of
+project.  The ``NEW`` behavior for this policy is to set the value of
 the :variable:`CMAKE_EXE_LINKER_FLAGS` variable in the test project
 to the same as it is in the calling project.
 
@@ -27,7 +27,7 @@
 
 This policy was introduced in CMake version 3.2.  Unlike most policies,
 CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior.  See documentation of the
+is not set and simply uses ``OLD`` behavior.  See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0056 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
 
diff --git a/Help/policy/CMP0060.rst b/Help/policy/CMP0060.rst
index 8611aff..98ac2cf 100644
--- a/Help/policy/CMP0060.rst
+++ b/Help/policy/CMP0060.rst
@@ -51,14 +51,14 @@
 directories.  Policy ``CMP0060`` provides compatibility for existing
 projects.
 
-The OLD behavior for this policy is to ask the linker to search for
+The ``OLD`` behavior for this policy is to ask the linker to search for
 libraries whose full paths are known to be in implicit link directories.
-The NEW behavior for this policy is to link libraries by full path even
+The ``NEW`` behavior for this policy is to link libraries by full path even
 if they are in implicit link directories.
 
 This policy was introduced in CMake version 3.3.  Unlike most policies,
 CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior.  See documentation of the
+is not set and simply uses ``OLD`` behavior.  See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0060 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
 
diff --git a/Help/policy/CMP0061.rst b/Help/policy/CMP0061.rst
index cb2ac28..57e4161 100644
--- a/Help/policy/CMP0061.rst
+++ b/Help/policy/CMP0061.rst
@@ -21,6 +21,6 @@
 
 This policy was introduced in CMake version 3.3.  Unlike most policies,
 CMake version |release| does *not* warn when this policy is not set and
-simply uses OLD behavior.
+simply uses ``OLD`` behavior.
 
 .. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0062.rst b/Help/policy/CMP0062.rst
index 9047fff..0db7aaf 100644
--- a/Help/policy/CMP0062.rst
+++ b/Help/policy/CMP0062.rst
@@ -1,7 +1,7 @@
 CMP0062
 -------
 
-Disallow install() of export() result.
+Disallow :command:`install` of :command:`export` result.
 
 The :command:`export()` command generates a file containing
 :ref:`Imported Targets`, which is suitable for use from the build
diff --git a/Help/policy/CMP0065.rst b/Help/policy/CMP0065.rst
index 2ed775d..b820aad 100644
--- a/Help/policy/CMP0065.rst
+++ b/Help/policy/CMP0065.rst
@@ -20,7 +20,7 @@
 
 This policy was introduced in CMake version 3.4.  Unlike most policies,
 CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior.  See documentation of the
+is not set and simply uses ``OLD`` behavior.  See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0065 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
 
diff --git a/Help/policy/CMP0066.rst b/Help/policy/CMP0066.rst
index d1dcb0e..e110ae1 100644
--- a/Help/policy/CMP0066.rst
+++ b/Help/policy/CMP0066.rst
@@ -20,7 +20,7 @@
 
 This policy was introduced in CMake version 3.7.  Unlike most policies,
 CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior.  See documentation of the
+is not set and simply uses ``OLD`` behavior.  See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0066 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
 
diff --git a/Help/policy/CMP0067.rst b/Help/policy/CMP0067.rst
index e6dda80..f802787 100644
--- a/Help/policy/CMP0067.rst
+++ b/Help/policy/CMP0067.rst
@@ -30,7 +30,7 @@
 
 This policy was introduced in CMake version 3.8.  Unlike most policies,
 CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior.  See documentation of the
+is not set and simply uses ``OLD`` behavior.  See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0067 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
 
diff --git a/Help/policy/CMP0071.rst b/Help/policy/CMP0071.rst
index ee33aa1..855ecf0 100644
--- a/Help/policy/CMP0071.rst
+++ b/Help/policy/CMP0071.rst
@@ -21,7 +21,7 @@
 
 .. note::
 
-  To silence the CMP0071 warning source files can be excluded from
+  To silence the ``CMP0071`` warning source files can be excluded from
   :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` processing by setting the
   source file properties :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC` or
   :prop_sf:`SKIP_AUTOGEN`.
diff --git a/Help/policy/CMP0082.rst b/Help/policy/CMP0082.rst
index 8256444..d887616 100644
--- a/Help/policy/CMP0082.rst
+++ b/Help/policy/CMP0082.rst
@@ -19,7 +19,7 @@
 
 This policy was introduced in CMake version 3.14.  Unlike most policies,
 CMake version |release| does *not* warn by default when this policy
-is not set and simply uses OLD behavior.  See documentation of the
+is not set and simply uses ``OLD`` behavior.  See documentation of the
 :variable:`CMAKE_POLICY_WARNING_CMP0082 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
 variable to control the warning.
 
diff --git a/Help/policy/CMP0089.rst b/Help/policy/CMP0089.rst
new file mode 100644
index 0000000..029de55
--- /dev/null
+++ b/Help/policy/CMP0089.rst
@@ -0,0 +1,30 @@
+CMP0089
+-------
+
+Compiler id for IBM Clang-based XL compilers is now ``XLClang``.
+
+CMake 3.15 and above recognize that IBM's Clang-based XL compilers
+that define ``__ibmxl__`` are a new front-end distinct from ``xlc``
+with a different command line and set of capabilities.
+CMake now prefers to present this to projects by setting the
+:variable:`CMAKE_<LANG>_COMPILER_ID` variable to ``XLClang`` instead
+of ``XL``.  However, existing projects may assume the compiler id for
+Clang-based XL is just ``XL`` as it was in CMake versions prior to 3.15.
+Therefore this policy determines for Clang-based XL compilers which
+compiler id to report in the :variable:`CMAKE_<LANG>_COMPILER_ID`
+variable after language ``<LANG>`` is enabled by the :command:`project`
+or :command:`enable_language` command.  The policy must be set prior
+to the invocation of either command.
+
+The ``OLD`` behavior for this policy is to use compiler id ``XL``.  The
+``NEW`` behavior for this policy is to use compiler id ``XLClang``.
+
+This policy was introduced in CMake version 3.15.  Use the
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0089 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0090.rst b/Help/policy/CMP0090.rst
new file mode 100644
index 0000000..720c17c
--- /dev/null
+++ b/Help/policy/CMP0090.rst
@@ -0,0 +1,27 @@
+CMP0090
+-------
+
+:command:`export(PACKAGE)` does not populate package registry by default.
+
+In CMake 3.14 and below the :command:`export(PACKAGE)` command populated the
+user package registry by default and users needed to set the
+:variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` to disable it, e.g. in automated
+build and packaging environments.  Since the user package registry is stored
+outside the build tree, this side effect should not be enabled by default.
+Therefore CMake 3.15 and above prefer that :command:`export(PACKAGE)` does
+nothing unless an explicit :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable
+is set to enable it.  This policy provides compatibility with projects that
+have not been updated.
+
+The ``OLD`` behavior for this policy is for :command:`export(PACKAGE)` command
+to populate the user package registry unless
+:variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` is enabled.
+The ``NEW`` behavior is for :command:`export(PACKAGE)` command to do nothing
+unless the :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` is enabled.
+
+This policy was introduced in CMake version 3.15.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/DISALLOWED_COMMAND.txt b/Help/policy/DISALLOWED_COMMAND.txt
index 36280d2..6500bb0 100644
--- a/Help/policy/DISALLOWED_COMMAND.txt
+++ b/Help/policy/DISALLOWED_COMMAND.txt
@@ -1,9 +1,9 @@
 CMake >= |disallowed_version| prefer that this command never be called.
-The OLD behavior for this policy is to allow the command to be called.
-The NEW behavior for this policy is to issue a FATAL_ERROR when the
+The ``OLD`` behavior for this policy is to allow the command to be called.
+The ``NEW`` behavior for this policy is to issue a ``FATAL_ERROR`` when the
 command is called.
 
 This policy was introduced in CMake version |disallowed_version|.
 CMake version |release| warns when the policy is not set and uses
-OLD behavior.  Use the cmake_policy command to set it to OLD or
-NEW explicitly.
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
diff --git a/Help/prop_cache/ADVANCED.rst b/Help/prop_cache/ADVANCED.rst
index a0a4f73..ec4de9d 100644
--- a/Help/prop_cache/ADVANCED.rst
+++ b/Help/prop_cache/ADVANCED.rst
@@ -4,5 +4,5 @@
 True if entry should be hidden by default in GUIs.
 
 This is a boolean value indicating whether the entry is considered
-interesting only for advanced configuration.  The mark_as_advanced()
+interesting only for advanced configuration.  The :command:`mark_as_advanced`
 command modifies this property.
diff --git a/Help/prop_cache/STRINGS.rst b/Help/prop_cache/STRINGS.rst
index 2f8e32e..0e3c326 100644
--- a/Help/prop_cache/STRINGS.rst
+++ b/Help/prop_cache/STRINGS.rst
@@ -1,9 +1,9 @@
 STRINGS
 -------
 
-Enumerate possible STRING entry values for GUI selection.
+Enumerate possible ``STRING`` entry values for GUI selection.
 
-For cache entries with type STRING, this enumerates a set of values.
+For cache entries with type ``STRING``, this enumerates a set of values.
 CMake GUIs may use this to provide a selection widget instead of a
 generic string entry field.  This is for convenience only.  CMake does
 not enforce that the value matches one of those listed.
diff --git a/Help/prop_cache/TYPE.rst b/Help/prop_cache/TYPE.rst
index eb75c2a..7ca859f 100644
--- a/Help/prop_cache/TYPE.rst
+++ b/Help/prop_cache/TYPE.rst
@@ -5,7 +5,7 @@
 
 Cache entry values are always strings, but CMake GUIs present widgets
 to help users set values.  The GUIs use this property as a hint to
-determine the widget type.  Valid TYPE values are:
+determine the widget type.  Valid ``TYPE`` values are:
 
 ::
 
@@ -17,5 +17,5 @@
   STATIC        = Value managed by CMake, do not change.
   UNINITIALIZED = Type not yet specified.
 
-Generally the TYPE of a cache entry should be set by the command which
-creates it (set, option, find_library, etc.).
+Generally the ``TYPE`` of a cache entry should be set by the command which
+creates it ( :command:`set`, :command:`option`, :command:`find_library`, etc.).
diff --git a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
index e32eed3..986ea5b 100644
--- a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
+++ b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
@@ -3,5 +3,5 @@
 
 Additional files to clean during the make clean stage.
 
-A list of files that will be cleaned as a part of the "make clean"
+A list of files that will be cleaned as a part of the ``make clean``
 stage.
diff --git a/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst b/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
index 993f620..f534976 100644
--- a/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
+++ b/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
@@ -1,15 +1,15 @@
 IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
 ----------------------------------
 
-Specify #include line transforms for dependencies in a directory.
+Specify ``#include`` line transforms for dependencies in a directory.
 
-This property specifies rules to transform macro-like #include lines
+This property specifies rules to transform macro-like ``#include`` lines
 during implicit dependency scanning of C and C++ source files.  The
 list of rules must be semicolon-separated with each entry of the form
-"A_MACRO(%)=value-with-%" (the % must be literal).  During dependency
-scanning occurrences of A_MACRO(...) on #include lines will be
+``A_MACRO(%)=value-with-%`` (the ``%`` must be literal).  During dependency
+scanning occurrences of ``A_MACRO(...)`` on ``#include`` lines will be
 replaced by the value given with the macro argument substituted for
-'%'.  For example, the entry
+``%``.  For example, the entry
 
 ::
 
diff --git a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
index 32520865..840a1db 100644
--- a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
+++ b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -3,6 +3,6 @@
 
 Per-configuration interprocedural optimization for a directory.
 
-This is a per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
+This is a per-configuration version of ``INTERPROCEDURAL_OPTIMIZATION``.
 If set, this property overrides the generic property for the named
 configuration.
diff --git a/Help/prop_dir/MACROS.rst b/Help/prop_dir/MACROS.rst
index e4feada..245cc1b 100644
--- a/Help/prop_dir/MACROS.rst
+++ b/Help/prop_dir/MACROS.rst
@@ -4,5 +4,5 @@
 List of macro commands available in the current directory.
 
 This read-only property specifies the list of CMake macros currently
-defined.  It is intended for debugging purposes.  See the macro
+defined.  It is intended for debugging purposes.  See the :command:`macro`
 command.
diff --git a/Help/prop_dir/TESTS.rst b/Help/prop_dir/TESTS.rst
index 56e230e..1c9f6e5 100644
--- a/Help/prop_dir/TESTS.rst
+++ b/Help/prop_dir/TESTS.rst
@@ -3,5 +3,6 @@
 
 List of tests.
 
-This read-only property holds a :ref:`semicolon-separated list <CMake Language Lists>` of tests
+This read-only property holds a
+:ref:`semicolon-separated list <CMake Language Lists>` of tests
 defined so far, in the current directory, by the :command:`add_test` command.
diff --git a/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst b/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
index 814bd5f..b65db99 100644
--- a/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
+++ b/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
@@ -12,20 +12,20 @@
     <contents based on property value>
   EndGlobalSection
 
-The property must be set to a semicolon-separated list of key=value
+The property must be set to a semicolon-separated list of ``key=value``
 pairs.  Each such pair will be transformed into an entry in the
 solution global section.  Whitespace around key and value is ignored.
 List elements which do not contain an equal sign are skipped.
 
 This property only works for Visual Studio 9 and above; it is ignored
 on other generators.  The property only applies when set on a
-directory whose CMakeLists.txt contains a project() command.
+directory whose ``CMakeLists.txt`` contains a :command:`project` command.
 
-Note that CMake generates postSolution sections ExtensibilityGlobals
-and ExtensibilityAddIns by default.  If you set the corresponding
+Note that CMake generates postSolution sections ``ExtensibilityGlobals``
+and ``ExtensibilityAddIns`` by default.  If you set the corresponding
 property, it will override the default section.  For example, setting
-VS_GLOBAL_SECTION_POST_ExtensibilityGlobals will override the default
-contents of the ExtensibilityGlobals section, while keeping
+``VS_GLOBAL_SECTION_POST_ExtensibilityGlobals`` will override the default
+contents of the ``ExtensibilityGlobals`` section, while keeping
 ExtensibilityAddIns on its default.  However, CMake will always
 add a ``SolutionGuid`` to the ``ExtensibilityGlobals`` section
 if it is not specified explicitly.
diff --git a/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst b/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
index f70e9f1..7f8bf61 100644
--- a/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
+++ b/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
@@ -12,11 +12,11 @@
     <contents based on property value>
   EndGlobalSection
 
-The property must be set to a semicolon-separated list of key=value
+The property must be set to a semicolon-separated list of ``key=value``
 pairs.  Each such pair will be transformed into an entry in the
 solution global section.  Whitespace around key and value is ignored.
 List elements which do not contain an equal sign are skipped.
 
 This property only works for Visual Studio 9 and above; it is ignored
 on other generators.  The property only applies when set on a
-directory whose CMakeLists.txt contains a project() command.
+directory whose ``CMakeLists.txt`` contains a :command:`project` command.
diff --git a/Help/prop_dir/VS_STARTUP_PROJECT.rst b/Help/prop_dir/VS_STARTUP_PROJECT.rst
index 04441b6..2680dfa 100644
--- a/Help/prop_dir/VS_STARTUP_PROJECT.rst
+++ b/Help/prop_dir/VS_STARTUP_PROJECT.rst
@@ -7,7 +7,7 @@
 whose ``CMakeLists.txt`` file calls the :command:`project` command.  Set this
 property in the same directory as a :command:`project` command call (e.g. in
 the top-level ``CMakeLists.txt`` file) to specify the default startup project
-for the correpsonding solution file.
+for the corresponding solution file.
 
 The property must be set to the name of an existing target.  This
 will cause that project to be listed first in the generated solution
diff --git a/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst b/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
index 8fab503..19775ff 100644
--- a/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
+++ b/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
@@ -4,16 +4,18 @@
 Allow duplicate custom targets to be created.
 
 Normally CMake requires that all targets built in a project have
-globally unique logical names (see policy CMP0002).  This is necessary
-to generate meaningful project file names in Xcode and VS IDE
+globally unique logical names (see policy :policy:`CMP0002`).
+This is necessary to generate meaningful project file names in
+:generator:`Xcode` and :ref:`Visual Studio Generators` IDE
 generators.  It also allows the target names to be referenced
 unambiguously.
 
-Makefile generators are capable of supporting duplicate custom target
-names.  For projects that care only about Makefile generators and do
-not wish to support Xcode or VS IDE generators, one may set this
-property to true to allow duplicate custom targets.  The property
-allows multiple add_custom_target command calls in different
+Makefile generators are capable of supporting duplicate :command:`add_custom_target`
+names.  For projects that care only about :ref:`Makefile Generators` and do
+not wish to support :generator:`Xcode` or :ref:`Visual Studio Generators` IDE
+generators, one may set this property to ``True``
+to allow duplicate custom targets.  The property
+allows multiple :command:`add_custom_target` command calls in different
 directories to specify the same target name.  However, setting this
 property will cause non-Makefile generators to produce an error and
 refuse to generate the project.
diff --git a/Help/prop_gbl/DISABLED_FEATURES.rst b/Help/prop_gbl/DISABLED_FEATURES.rst
index 111cdf6..882bbfa 100644
--- a/Help/prop_gbl/DISABLED_FEATURES.rst
+++ b/Help/prop_gbl/DISABLED_FEATURES.rst
@@ -5,7 +5,7 @@
 
 List of features which are disabled during the CMake run.  By default
 it contains the names of all packages which were not found.  This is
-determined using the <NAME>_FOUND variables.  Packages which are
-searched QUIET are not listed.  A project can add its own features to
+determined using the ``<NAME>_FOUND`` variables.  Packages which are
+searched ``QUIET`` are not listed.  A project can add its own features to
 this list.  This property is used by the macros in
-FeatureSummary.cmake.
+``FeatureSummary.cmake``.
diff --git a/Help/prop_gbl/ENABLED_FEATURES.rst b/Help/prop_gbl/ENABLED_FEATURES.rst
index b03da5a..acbb3d0 100644
--- a/Help/prop_gbl/ENABLED_FEATURES.rst
+++ b/Help/prop_gbl/ENABLED_FEATURES.rst
@@ -5,7 +5,7 @@
 
 List of features which are enabled during the CMake run.  By default
 it contains the names of all packages which were found.  This is
-determined using the <NAME>_FOUND variables.  Packages which are
-searched QUIET are not listed.  A project can add its own features to
+determined using the ``<NAME>_FOUND`` variables.  Packages which are
+searched ``QUIET`` are not listed.  A project can add its own features to
 this list.  This property is used by the macros in
-FeatureSummary.cmake.
+``FeatureSummary.cmake``.
diff --git a/Help/prop_gbl/USE_FOLDERS.rst b/Help/prop_gbl/USE_FOLDERS.rst
index a1b4ccb..5919723 100644
--- a/Help/prop_gbl/USE_FOLDERS.rst
+++ b/Help/prop_gbl/USE_FOLDERS.rst
@@ -4,7 +4,7 @@
 Use the :prop_tgt:`FOLDER` target property to organize targets into
 folders.
 
-If not set, CMake treats this property as OFF by default.  CMake
+If not set, CMake treats this property as ``OFF`` by default.  CMake
 generators that are capable of organizing into a hierarchy of folders
 use the values of the :prop_tgt:`FOLDER` target property to name those
-folders. See also the documentation for the FOLDER target property.
+folders. See also the documentation for the :prop_tgt:`FOLDER` target property.
diff --git a/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst b/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
index 9a6086e..9500443 100644
--- a/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
+++ b/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
@@ -1,14 +1,15 @@
 XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
 ----------------------------------
 
-Control emission of ``EFFECTIVE_PLATFORM_NAME`` by the Xcode generator.
+Control emission of ``EFFECTIVE_PLATFORM_NAME`` by the :generator:`Xcode`
+generator.
 
 It is required for building the same target with multiple SDKs. A
 common use case is the parallel use of ``iphoneos`` and
 ``iphonesimulator`` SDKs.
 
-Three different states possible that control when the Xcode generator
-emits the ``EFFECTIVE_PLATFORM_NAME`` variable:
+Three different states possible that control when the :generator:`Xcode`
+generator emits the ``EFFECTIVE_PLATFORM_NAME`` variable:
 
 - If set to ``ON`` it will always be emitted
 - If set to ``OFF`` it will never be emitted
diff --git a/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst b/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
index 11f2c03..729ab60 100644
--- a/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
+++ b/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
@@ -1,7 +1,7 @@
 CPACK_DESKTOP_SHORTCUTS
 -----------------------
 
-Species a list of shortcut names that should be created on the Desktop
+Species a list of shortcut names that should be created on the `Desktop`
 for this file.
 
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst b/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
index 11f44d0..4789e25 100644
--- a/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
+++ b/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
@@ -3,4 +3,4 @@
 
 Request that this file not be overwritten on install or reinstall.
 
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_PERMANENT.rst b/Help/prop_inst/CPACK_PERMANENT.rst
index 5e191d0..985de0d 100644
--- a/Help/prop_inst/CPACK_PERMANENT.rst
+++ b/Help/prop_inst/CPACK_PERMANENT.rst
@@ -3,4 +3,4 @@
 
 Request that this file not be removed on uninstall.
 
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst b/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
index 8a16022..d9208b9 100644
--- a/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
+++ b/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
@@ -1,7 +1,7 @@
 CPACK_STARTUP_SHORTCUTS
 -----------------------
 
-Species a list of shortcut names that should be created in the Startup folder
+Species a list of shortcut names that should be created in the `Startup` folder
 for this file.
 
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst b/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
index d30ea39..092334a 100644
--- a/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
+++ b/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
@@ -1,7 +1,7 @@
 CPACK_START_MENU_SHORTCUTS
 --------------------------
 
-Species a list of shortcut names that should be created in the Start Menu
+Species a list of shortcut names that should be created in the `Start Menu`
 for this file.
 
-The property is currently only supported by the WIX generator.
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_WIX_ACL.rst b/Help/prop_inst/CPACK_WIX_ACL.rst
index 4e13ec4..c88f426 100644
--- a/Help/prop_inst/CPACK_WIX_ACL.rst
+++ b/Help/prop_inst/CPACK_WIX_ACL.rst
@@ -17,3 +17,5 @@
 ``<permission>`` is any of the YesNoType attributes listed here::
 
  http://wixtoolset.org/documentation/manual/v3/xsd/wix/permission.html
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS.rst b/Help/prop_sf/COMPILE_DEFINITIONS.rst
index 8d2108c..6317690 100644
--- a/Help/prop_sf/COMPILE_DEFINITIONS.rst
+++ b/Help/prop_sf/COMPILE_DEFINITIONS.rst
@@ -3,14 +3,14 @@
 
 Preprocessor definitions for compiling a source file.
 
-The COMPILE_DEFINITIONS property may be set to a semicolon-separated
-list of preprocessor definitions using the syntax VAR or VAR=value.
+The ``COMPILE_DEFINITIONS`` property may be set to a semicolon-separated
+list of preprocessor definitions using the syntax ``VAR`` or ``VAR=value``.
 Function-style definitions are not supported.  CMake will
 automatically escape the value correctly for the native build system
 (note that CMake language syntax may require escapes to specify some
 values).  This property may be set on a per-configuration basis using
-the name COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case
-name (ex.  "COMPILE_DEFINITIONS_DEBUG").
+the name ``COMPILE_DEFINITIONS_<CONFIG>`` where ``<CONFIG>`` is an upper-case
+name (ex.  ``COMPILE_DEFINITIONS_DEBUG``).
 
 CMake will automatically drop some definitions that are not supported
 by the native build tool.  Xcode does not support per-configuration
@@ -18,7 +18,7 @@
 
 .. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
 
-Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions"
+Contents of ``COMPILE_DEFINITIONS`` may use :manual:`cmake-generator-expressions(7)`
 with the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  However, :generator:`Xcode`
 does not support per-config per-source settings, so expressions
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst b/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
index 8487076..ec867b6 100644
--- a/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
+++ b/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
@@ -5,6 +5,6 @@
 
 Per-configuration preprocessor definitions on a source file.
 
-This is the configuration-specific version of COMPILE_DEFINITIONS.
-Note that Xcode does not support per-configuration source file flags
-so this property will be ignored by the Xcode generator.
+This is the configuration-specific version of :prop_tgt:`COMPILE_DEFINITIONS`.
+Note that :generator:`Xcode` does not support per-configuration source
+file flags so this property will be ignored by the :generator:`Xcode` generator.
diff --git a/Help/prop_sf/EXTERNAL_OBJECT.rst b/Help/prop_sf/EXTERNAL_OBJECT.rst
index efa0e9b..351c04d 100644
--- a/Help/prop_sf/EXTERNAL_OBJECT.rst
+++ b/Help/prop_sf/EXTERNAL_OBJECT.rst
@@ -3,6 +3,6 @@
 
 If set to true then this is an object file.
 
-If this property is set to true then the source file is really an
+If this property is set to ``True`` then the source file is really an
 object file and should not be compiled.  It will still be linked into
 the target though.
diff --git a/Help/prop_sf/Fortran_FORMAT.rst b/Help/prop_sf/Fortran_FORMAT.rst
index 69e34aa..1cbbf48 100644
--- a/Help/prop_sf/Fortran_FORMAT.rst
+++ b/Help/prop_sf/Fortran_FORMAT.rst
@@ -1,9 +1,10 @@
 Fortran_FORMAT
 --------------
 
-Set to FIXED or FREE to indicate the Fortran source layout.
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
 
 This property tells CMake whether a given Fortran source file uses
 fixed-format or free-format.  CMake will pass the corresponding format
-flag to the compiler.  Consider using the target-wide Fortran_FORMAT
-property if all source files in a target share the same format.
+flag to the compiler.  Consider using the target-wide
+:prop_tgt:`Fortran_FORMAT` property if all source files in a target
+share the same format.
diff --git a/Help/prop_sf/KEEP_EXTENSION.rst b/Help/prop_sf/KEEP_EXTENSION.rst
index d6167e5..a32f968 100644
--- a/Help/prop_sf/KEEP_EXTENSION.rst
+++ b/Help/prop_sf/KEEP_EXTENSION.rst
@@ -6,4 +6,4 @@
 If this property is set then the file extension of the output file
 will be the same as that of the source file.  Normally the output file
 extension is computed based on the language of the source file, for
-example .cxx will go to a .o extension.
+example ``.cxx`` will go to a ``.o`` extension.
diff --git a/Help/prop_sf/LABELS.rst b/Help/prop_sf/LABELS.rst
index e1c1069..d0d2a0a 100644
--- a/Help/prop_sf/LABELS.rst
+++ b/Help/prop_sf/LABELS.rst
@@ -4,5 +4,5 @@
 Specify a list of text labels associated with a source file.
 
 This property has meaning only when the source file is listed in a
-target whose LABELS property is also set.  No other semantics are
+target whose ``LABELS`` property is also set.  No other semantics are
 currently specified.
diff --git a/Help/prop_sf/LANGUAGE.rst b/Help/prop_sf/LANGUAGE.rst
index 97bfa20..88d438e 100644
--- a/Help/prop_sf/LANGUAGE.rst
+++ b/Help/prop_sf/LANGUAGE.rst
@@ -5,6 +5,7 @@
 
 A property that can be set to indicate what programming language the
 source file is.  If it is not set the language is determined based on
-the file extension.  Typical values are CXX C etc.  Setting this
+the file extension.  Typical values are ``CXX`` (i.e.  C++), ``C``,
+``CSharp``, ``CUDA``, ``Fortran``, and ``ASM``.  Setting this
 property for a file means this file will be compiled.  Do not set this
 for headers or files that should not be compiled.
diff --git a/Help/prop_sf/OBJECT_OUTPUTS.rst b/Help/prop_sf/OBJECT_OUTPUTS.rst
index 6a28553..e7e880b 100644
--- a/Help/prop_sf/OBJECT_OUTPUTS.rst
+++ b/Help/prop_sf/OBJECT_OUTPUTS.rst
@@ -1,9 +1,9 @@
 OBJECT_OUTPUTS
 --------------
 
-Additional outputs for a Makefile rule.
+Additional outputs for a :generator:`Ninja` or :ref:`Makefile Generators` rule.
 
 Additional outputs created by compilation of this source file.  If any
 of these outputs is missing the object will be recompiled.  This is
-supported only on Makefile generators and will be ignored on other
-generators.
+supported only on the :generator:`Ninja` and :ref:`Makefile Generators`
+and will be ignored on other generators.
diff --git a/Help/prop_sf/SYMBOLIC.rst b/Help/prop_sf/SYMBOLIC.rst
index c7d0b26..8bebe30 100644
--- a/Help/prop_sf/SYMBOLIC.rst
+++ b/Help/prop_sf/SYMBOLIC.rst
@@ -3,6 +3,6 @@
 
 Is this just a name for a rule.
 
-If SYMBOLIC (boolean) is set to true the build system will be informed
+If ``SYMBOLIC`` (boolean) is set to ``True`` the build system will be informed
 that the source file is not actually created on disk but instead used
 as a symbolic name for a build rule.
diff --git a/Help/prop_sf/VS_CSHARP_tagname.rst b/Help/prop_sf/VS_CSHARP_tagname.rst
index d42159f..91c4a06 100644
--- a/Help/prop_sf/VS_CSHARP_tagname.rst
+++ b/Help/prop_sf/VS_CSHARP_tagname.rst
@@ -3,8 +3,9 @@
 
 Visual Studio and CSharp source-file-specific configuration.
 
-Tell the Visual Studio generator to set the source file tag
-``<tagname>`` to a given value in the generated Visual Studio CSharp
+Tell the :manual:`Visual Studio generators <cmake-generators(7)>`
+to set the source file tag ``<tagname>``
+to a given value in the generated Visual Studio CSharp
 project. Ignored on other generators and languages. This property
 can be used to define dependencies between source files or set any
 other Visual Studio specific parameters.
diff --git a/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst b/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
index 9fb3ba3..6a38478 100644
--- a/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
+++ b/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
@@ -2,7 +2,8 @@
 ---------------------
 
 Mark a source file as content for deployment with a Windows Phone or
-Windows Store application when built with a Visual Studio generator.
+Windows Store application when built with a
+:manual:`Visual Studio generators <cmake-generators(7)>`.
 The value must evaluate to either ``1`` or ``0`` and may use
 :manual:`generator expressions <cmake-generator-expressions(7)>`
 to make the choice based on the build configuration.
diff --git a/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst b/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
index 303db95..2ce22fc 100644
--- a/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
+++ b/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
@@ -2,7 +2,8 @@
 ----------------------
 
 Specifies the deployment location for a content source file with a Windows
-Phone or Windows Store application when built with a Visual Studio generator.
+Phone or Windows Store application when built
+with a :manual:`Visual Studio generators <cmake-generators(7)>`.
 This property is only applicable when using :prop_sf:`VS_DEPLOYMENT_CONTENT`.
 The value represent the path relative to the app package and applies to all
 configurations.
diff --git a/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst b/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
index 30f471d..db470ef 100644
--- a/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
+++ b/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
@@ -1,6 +1,6 @@
 VS_INCLUDE_IN_VSIX
 ------------------
 
-Boolean property to specify if the file should be included within a VSIX
-extension package. This is needed for development of Visual Studio
-extensions.
+Boolean property to specify if the file should be included within a
+VSIX (Visual Studio Integration Extension) extension package.
+This is needed for development of Visual Studio extensions.
diff --git a/Help/prop_sf/VS_SHADER_FLAGS.rst b/Help/prop_sf/VS_SHADER_FLAGS.rst
index 0901123..0a53afd 100644
--- a/Help/prop_sf/VS_SHADER_FLAGS.rst
+++ b/Help/prop_sf/VS_SHADER_FLAGS.rst
@@ -1,4 +1,4 @@
 VS_SHADER_FLAGS
 ---------------
 
-Set additional VS shader flags of a ``.hlsl`` source file.
+Set additional Visual Studio shader flags of a ``.hlsl`` source file.
diff --git a/Help/prop_sf/VS_SHADER_TYPE.rst b/Help/prop_sf/VS_SHADER_TYPE.rst
index 6880256..f104837 100644
--- a/Help/prop_sf/VS_SHADER_TYPE.rst
+++ b/Help/prop_sf/VS_SHADER_TYPE.rst
@@ -1,4 +1,4 @@
 VS_SHADER_TYPE
 --------------
 
-Set the VS shader type of a ``.hlsl`` source file.
+Set the Visual Studio shader type of a ``.hlsl`` source file.
diff --git a/Help/prop_sf/VS_XAML_TYPE.rst b/Help/prop_sf/VS_XAML_TYPE.rst
index e92191d..1a274ba 100644
--- a/Help/prop_sf/VS_XAML_TYPE.rst
+++ b/Help/prop_sf/VS_XAML_TYPE.rst
@@ -1,6 +1,7 @@
 VS_XAML_TYPE
 ------------
 
-Mark a XAML source file as a different type than the default ``Page``.
-The most common usage would be to set the default App.xaml file as
-ApplicationDefinition.
+Mark a Extensible Application Markup Language (XAML) source file
+as a different type than the default ``Page``.
+The most common usage would be to set the default ``App.xaml`` file as
+``ApplicationDefinition``.
diff --git a/Help/prop_sf/WRAP_EXCLUDE.rst b/Help/prop_sf/WRAP_EXCLUDE.rst
index 2c79f72..638ff03 100644
--- a/Help/prop_sf/WRAP_EXCLUDE.rst
+++ b/Help/prop_sf/WRAP_EXCLUDE.rst
@@ -4,7 +4,8 @@
 Exclude this source file from any code wrapping techniques.
 
 Some packages can wrap source files into alternate languages to
-provide additional functionality.  For example, C++ code can be
-wrapped into Java or Python etc using SWIG etc.  If WRAP_EXCLUDE is
-set to true (1 etc) that indicates that this source file should not be
-wrapped.
+provide additional functionality.
+
+For example, C++ code can be wrapped into Java or Python, using SWIG.
+If ``WRAP_EXCLUDE`` is set to ``True``, that indicates that this
+source file should not be wrapped.
diff --git a/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst b/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
index 1b24701..b8cf946 100644
--- a/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
+++ b/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
@@ -1,7 +1,7 @@
 XCODE_EXPLICIT_FILE_TYPE
 ------------------------
 
-Set the Xcode ``explicitFileType`` attribute on its reference to a
+Set the :generator:`Xcode` ``explicitFileType`` attribute on its reference to a
 source file.  CMake computes a default based on file extension but
 can be told explicitly with this property.
 
diff --git a/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst b/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
index 39e6966..4c93f44 100644
--- a/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
+++ b/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
@@ -1,9 +1,9 @@
 XCODE_FILE_ATTRIBUTES
 ---------------------
 
-Add values to the Xcode ``ATTRIBUTES`` setting on its reference to a
+Add values to the :generator:`Xcode` ``ATTRIBUTES`` setting on its reference to a
 source file.  Among other things, this can be used to set the role on
-a mig file::
+a ``.mig`` file::
 
   set_source_files_properties(defs.mig
       PROPERTIES
diff --git a/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst b/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
index 42e3757..b21891f 100644
--- a/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
+++ b/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
@@ -1,8 +1,8 @@
 XCODE_LAST_KNOWN_FILE_TYPE
 --------------------------
 
-Set the Xcode ``lastKnownFileType`` attribute on its reference to a
-source file.  CMake computes a default based on file extension but
+Set the :generator:`Xcode` ``lastKnownFileType`` attribute on its reference to
+a source file.  CMake computes a default based on file extension but
 can be told explicitly with this property.
 
 See also :prop_sf:`XCODE_EXPLICIT_FILE_TYPE`, which is preferred
diff --git a/Help/prop_test/COST.rst b/Help/prop_test/COST.rst
index 3236a02..0c0fca7 100644
--- a/Help/prop_test/COST.rst
+++ b/Help/prop_test/COST.rst
@@ -1,7 +1,8 @@
 COST
 ----
 
-Set this to a floating point value. Tests in a test set will be run in descending order of cost.
+Set this to a floating point value. Tests in a test set will be run
+in descending order of cost.
 
 This property describes the cost of a test.  You can explicitly set
-this value; tests with higher COST values will run first.
+this value; tests with higher ``COST`` values will run first.
diff --git a/Help/prop_test/DISABLED.rst b/Help/prop_test/DISABLED.rst
index c18ae7f..1d469e8 100644
--- a/Help/prop_test/DISABLED.rst
+++ b/Help/prop_test/DISABLED.rst
@@ -1,15 +1,15 @@
 DISABLED
 --------
 
-If set to true, the test will be skipped and its status will be 'Not Run'. A
-DISABLED test will not be counted in the total number of tests and its
-completion status will be reported to CDash as 'Disabled'.
+If set to ``True``, the test will be skipped and its status will be 'Not Run'. A
+``DISABLED`` test will not be counted in the total number of tests and its
+completion status will be reported to CDash as ``Disabled``.
 
-A DISABLED test does not participate in test fixture dependency resolution.
-If a DISABLED test has fixture requirements defined in its
+A ``DISABLED`` test does not participate in test fixture dependency resolution.
+If a ``DISABLED`` test has fixture requirements defined in its
 :prop_test:`FIXTURES_REQUIRED` property, it will not cause setup or cleanup
 tests for those fixtures to be added to the test set.
 
-If a test with the :prop_test:`FIXTURES_SETUP` property set is DISABLED, the
-fixture behavior will be as though that setup test was passing and any test
+If a test with the :prop_test:`FIXTURES_SETUP` property set is ``DISABLED``,
+the fixture behavior will be as though that setup test was passing and any test
 case requiring that fixture will still run.
diff --git a/Help/prop_test/ENVIRONMENT.rst b/Help/prop_test/ENVIRONMENT.rst
index df9bc9e..102c792 100644
--- a/Help/prop_test/ENVIRONMENT.rst
+++ b/Help/prop_test/ENVIRONMENT.rst
@@ -4,6 +4,6 @@
 Specify environment variables that should be defined for running a test.
 
 If set to a list of environment variables and values of the form
-MYVAR=value those environment variables will be defined while running
+``MYVAR=value`` those environment variables will be defined while running
 the test.  The environment is restored to its previous state after the
 test is done.
diff --git a/Help/prop_test/MEASUREMENT.rst b/Help/prop_test/MEASUREMENT.rst
index bc4936e..de459ed 100644
--- a/Help/prop_test/MEASUREMENT.rst
+++ b/Help/prop_test/MEASUREMENT.rst
@@ -1,8 +1,8 @@
 MEASUREMENT
 -----------
 
-Specify a CDASH measurement and value to be reported for a test.
+Specify a ``CDASH`` measurement and value to be reported for a test.
 
-If set to a name then that name will be reported to CDASH as a named
-measurement with a value of 1.  You may also specify a value by
-setting MEASUREMENT to "measurement=value".
+If set to a name then that name will be reported to ``CDASH`` as a named
+measurement with a value of ``1``.  You may also specify a value by
+setting ``MEASUREMENT`` to ``measurement=value``.
diff --git a/Help/prop_test/RUN_SERIAL.rst b/Help/prop_test/RUN_SERIAL.rst
index 8f65ae1..ab4c542 100644
--- a/Help/prop_test/RUN_SERIAL.rst
+++ b/Help/prop_test/RUN_SERIAL.rst
@@ -3,6 +3,6 @@
 
 Do not run this test in parallel with any other test.
 
-Use this option in conjunction with the ctest_test PARALLEL_LEVEL
+Use this option in conjunction with the ctest_test ``PARALLEL_LEVEL``
 option to specify that this test should not be run in parallel with
 any other tests.
diff --git a/Help/prop_test/SKIP_RETURN_CODE.rst b/Help/prop_test/SKIP_RETURN_CODE.rst
index c61273c..a05fbf3 100644
--- a/Help/prop_test/SKIP_RETURN_CODE.rst
+++ b/Help/prop_test/SKIP_RETURN_CODE.rst
@@ -6,4 +6,4 @@
 Sometimes only a test itself can determine if all requirements for the
 test are met. If such a situation should not be considered a hard failure
 a return code of the process can be specified that will mark the test as
-"Not Run" if it is encountered.
+``Not Run`` if it is encountered.
diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
index 52ef013..f261756 100644
--- a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -6,7 +6,7 @@
 
 This is a per-configuration version of
 :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY`,
-but multi-configuration generators (VS, Xcode) do NOT append a
+but multi-configuration generators (Visual Studio, Xcode) do NOT append a
 per-configuration subdirectory to the specified directory.  This
 property is initialized by the value of the
 :variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable
diff --git a/Help/prop_tgt/DEBUG_POSTFIX.rst b/Help/prop_tgt/DEBUG_POSTFIX.rst
index 1487656..04e312e 100644
--- a/Help/prop_tgt/DEBUG_POSTFIX.rst
+++ b/Help/prop_tgt/DEBUG_POSTFIX.rst
@@ -1,7 +1,7 @@
 DEBUG_POSTFIX
 -------------
 
-See target property <CONFIG>_POSTFIX.
+See target property ``<CONFIG>_POSTFIX``.
 
-This property is a special case of the more-general <CONFIG>_POSTFIX
-property for the DEBUG configuration.
+This property is a special case of the more-general ``<CONFIG>_POSTFIX``
+property for the ``DEBUG`` configuration.
diff --git a/Help/prop_tgt/DEFINE_SYMBOL.rst b/Help/prop_tgt/DEFINE_SYMBOL.rst
index f47f135..eb7f937 100644
--- a/Help/prop_tgt/DEFINE_SYMBOL.rst
+++ b/Help/prop_tgt/DEFINE_SYMBOL.rst
@@ -3,9 +3,9 @@
 
 Define a symbol when compiling this target's sources.
 
-DEFINE_SYMBOL sets the name of the preprocessor symbol defined when
+``DEFINE_SYMBOL`` sets the name of the preprocessor symbol defined when
 compiling sources in a shared library.  If not set here then it is set
-to target_EXPORTS by default (with some substitutions if the target is
+to ``target_EXPORTS`` by default (with some substitutions if the target is
 not a valid C identifier).  This is useful for headers to know whether
 they are being included from inside their library or outside to
 properly setup dllexport/dllimport decorations.
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
index a2f7d7d..c100326 100644
--- a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -4,7 +4,7 @@
 Specify the .NET target framework version.
 
 Used to specify the .NET target framework version for C++/CLI.  For
-example, "v4.5".
+example: ``v4.5``.
 
 This property is only evaluated for :ref:`Visual Studio Generators`
 VS 2010 and above.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
index a14e48c..664704b 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
@@ -1,8 +1,8 @@
 EXCLUDE_FROM_DEFAULT_BUILD
 --------------------------
 
-Exclude target from "Build Solution".
+Exclude target from ``Build Solution``.
 
 This property is only used by Visual Studio generators.
-When set to TRUE, the target will not be built when you press "Build
-Solution".
+When set to ``TRUE``, the target will not be built when you press
+``Build Solution``.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
index 655a9de..ad1021a 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
@@ -1,9 +1,10 @@
 EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG>
 -----------------------------------
 
-Per-configuration version of target exclusion from "Build Solution".
+Per-configuration version of target exclusion from ``Build Solution``.
 
 This is the configuration-specific version of
-EXCLUDE_FROM_DEFAULT_BUILD.  If the generic EXCLUDE_FROM_DEFAULT_BUILD
-is also set on a target, EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG> takes
+:prop_tgt:`EXCLUDE_FROM_DEFAULT_BUILD`.  If the generic
+:prop_tgt:`EXCLUDE_FROM_DEFAULT_BUILD` is also set on a target,
+``EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG>`` takes
 precedence in configurations for which it has a value.
diff --git a/Help/prop_tgt/EXPORT_NAME.rst b/Help/prop_tgt/EXPORT_NAME.rst
index 1b4247c..0e021d0 100644
--- a/Help/prop_tgt/EXPORT_NAME.rst
+++ b/Help/prop_tgt/EXPORT_NAME.rst
@@ -3,6 +3,6 @@
 
 Exported name for target files.
 
-This sets the name for the IMPORTED target generated when it this
-target is is exported.  If not set, the logical target name is used by
-default.
+This sets the name for the ``IMPORTED`` target generated by the
+:command:`install(EXPORT)` and :command:`export` commands.
+If not set, the logical target name is used by default.
diff --git a/Help/prop_tgt/EchoString.rst b/Help/prop_tgt/EchoString.rst
index 32ae2aa..352d062 100644
--- a/Help/prop_tgt/EchoString.rst
+++ b/Help/prop_tgt/EchoString.rst
@@ -3,5 +3,5 @@
 
 A message to be displayed when the target is built.
 
-A message to display on some generators (such as makefiles) when the
-target is built.
+A message to display on some generators (such as :ref:`Makefile Generators`)
+when the target is built.
diff --git a/Help/prop_tgt/FOLDER.rst b/Help/prop_tgt/FOLDER.rst
index 0121125..f6be9e6 100644
--- a/Help/prop_tgt/FOLDER.rst
+++ b/Help/prop_tgt/FOLDER.rst
@@ -3,10 +3,10 @@
 
 Set the folder name. Use to organize targets in an IDE.
 
-Targets with no FOLDER property will appear as top level entities in
-IDEs like Visual Studio.  Targets with the same FOLDER property value
+Targets with no ``FOLDER`` property will appear as top level entities in
+IDEs like Visual Studio.  Targets with the same ``FOLDER`` property value
 will appear next to each other in a folder of that name.  To nest
-folders, use FOLDER values such as 'GUI/Dialogs' with '/' characters
+folders, use ``FOLDER`` values such as 'GUI/Dialogs' with '/' characters
 separating folder levels.
 
 This property is initialized by the value of the variable
diff --git a/Help/prop_tgt/Fortran_FORMAT.rst b/Help/prop_tgt/Fortran_FORMAT.rst
index 0a11d91..8704e5f 100644
--- a/Help/prop_tgt/Fortran_FORMAT.rst
+++ b/Help/prop_tgt/Fortran_FORMAT.rst
@@ -1,11 +1,11 @@
 Fortran_FORMAT
 --------------
 
-Set to FIXED or FREE to indicate the Fortran source layout.
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
 
 This property tells CMake whether the Fortran source files in a target
 use fixed-format or free-format.  CMake will pass the corresponding
-format flag to the compiler.  Use the source-specific Fortran_FORMAT
+format flag to the compiler.  Use the source-specific ``Fortran_FORMAT``
 property to change the format of a specific source file.  If the
-variable CMAKE_Fortran_FORMAT is set when a target is created its
+variable :variable:`CMAKE_Fortran_FORMAT` is set when a target is created its
 value is used to initialize this property.
diff --git a/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst b/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
index 9c86437..e061863 100644
--- a/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
+++ b/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
@@ -8,10 +8,10 @@
 directory in which the modules will be placed.  When this property is
 not set the modules will be placed in the build directory
 corresponding to the target's source directory.  If the variable
-CMAKE_Fortran_MODULE_DIRECTORY is set when a target is created its
+:variable:`CMAKE_Fortran_MODULE_DIRECTORY` is set when a target is created its
 value is used to initialize this property.
 
 Note that some compilers will automatically search the module output
 directory for modules USEd during compilation but others will not.  If
 your sources USE modules their location must be specified by
-INCLUDE_DIRECTORIES regardless of this property.
+:prop_tgt:`INCLUDE_DIRECTORIES` regardless of this property.
diff --git a/Help/prop_tgt/GENERATOR_FILE_NAME.rst b/Help/prop_tgt/GENERATOR_FILE_NAME.rst
index 032b22a..a486105 100644
--- a/Help/prop_tgt/GENERATOR_FILE_NAME.rst
+++ b/Help/prop_tgt/GENERATOR_FILE_NAME.rst
@@ -6,4 +6,4 @@
 An internal property used by some generators to record the name of the
 project or dsp file associated with this target.  Note that at
 configure time, this property is only set for targets created by
-include_external_msproject().
+:command:`include_external_msproject`.
diff --git a/Help/prop_tgt/GHS_INTEGRITY_APP.rst b/Help/prop_tgt/GHS_INTEGRITY_APP.rst
index 7643038..b669781 100644
--- a/Help/prop_tgt/GHS_INTEGRITY_APP.rst
+++ b/Help/prop_tgt/GHS_INTEGRITY_APP.rst
@@ -4,7 +4,7 @@
 ``ON`` / ``OFF`` boolean to determine if an executable target should
 be treated as an `Integrity Application`.
 
-If no value is set and if a `.int` file is added as a source file to the
+If no value is set and if a ``.int`` file is added as a source file to the
 executable target it will be treated as an `Integrity Application`.
 
 Supported on :generator:`Green Hills MULTI`.
diff --git a/Help/prop_tgt/GNUtoMS.rst b/Help/prop_tgt/GNUtoMS.rst
index cf34da9..a09ebbf 100644
--- a/Help/prop_tgt/GNUtoMS.rst
+++ b/Help/prop_tgt/GNUtoMS.rst
@@ -1,17 +1,17 @@
 GNUtoMS
 -------
 
-Convert GNU import library (.dll.a) to MS format (.lib).
+Convert GNU import library (``.dll.a``) to MS format (``.lib``).
 
 When linking a shared library or executable that exports symbols using
 GNU tools on Windows (MinGW/MSYS) with Visual Studio installed convert
-the import library (.dll.a) from GNU to MS format (.lib).  Both import
-libraries will be installed by install(TARGETS) and exported by
-install(EXPORT) and export() to be linked by applications with either
-GNU- or MS-compatible tools.
+the import library (``.dll.a``) from GNU to MS format (``.lib``).  Both import
+libraries will be installed by :command:`install(TARGETS)` and exported by
+:command:`install(EXPORT)` and  :command:`export` to be linked
+by applications with either GNU- or MS-compatible tools.
 
-If the variable CMAKE_GNUtoMS is set when a target is created its
+If the variable ``CMAKE_GNUtoMS`` is set when a target is created its
 value is used to initialize this property.  The variable must be set
-prior to the first command that enables a language such as project()
-or enable_language().  CMake provides the variable as an option to the
+prior to the first command that enables a language such as :command:`project`
+or :command:`enable_language`.  CMake provides the variable as an option to the
 user automatically when configuring on Windows with GNU tools.
diff --git a/Help/prop_tgt/HAS_CXX.rst b/Help/prop_tgt/HAS_CXX.rst
index 7790932..15199b1 100644
--- a/Help/prop_tgt/HAS_CXX.rst
+++ b/Help/prop_tgt/HAS_CXX.rst
@@ -3,5 +3,5 @@
 
 Link the target using the C++ linker tool (obsolete).
 
-This is equivalent to setting the LINKER_LANGUAGE property to CXX.
-See that property's documentation for details.
+This is equivalent to setting the :prop_tgt:`LINKER_LANGUAGE`
+property to ``CXX``.
diff --git a/Help/prop_tgt/IMPORTED.rst b/Help/prop_tgt/IMPORTED.rst
index 605c1ce..22d28aa 100644
--- a/Help/prop_tgt/IMPORTED.rst
+++ b/Help/prop_tgt/IMPORTED.rst
@@ -1,8 +1,8 @@
 IMPORTED
 --------
 
-Read-only indication of whether a target is IMPORTED.
+Read-only indication of whether a target is ``IMPORTED``.
 
 The boolean value of this property is ``True`` for targets created with
-the IMPORTED option to :command:`add_executable` or :command:`add_library`.
+the ``IMPORTED`` option to :command:`add_executable` or :command:`add_library`.
 It is ``False`` for targets built within the project.
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB.rst b/Help/prop_tgt/IMPORTED_IMPLIB.rst
index acf4b32..77fb552 100644
--- a/Help/prop_tgt/IMPORTED_IMPLIB.rst
+++ b/Help/prop_tgt/IMPORTED_IMPLIB.rst
@@ -1,7 +1,7 @@
 IMPORTED_IMPLIB
 ---------------
 
-Full path to the import library for an IMPORTED target.
+Full path to the import library for an ``IMPORTED`` target.
 
-Set this to the location of the ".lib" part of a windows DLL.  Ignored
+Set this to the location of the ``.lib`` part of a Windows DLL.  Ignored
 for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst b/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
index b4b3f02..5debabc 100644
--- a/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_IMPLIB_<CONFIG>
 ------------------------
 
-<CONFIG>-specific version of IMPORTED_IMPLIB property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_IMPLIB` property.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
index 2db2b0e..f7e2165 100644
--- a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
@@ -8,7 +8,7 @@
 dependent libraries of shared libraries they are including in the
 link.  Set this property to the list of dependent shared libraries of
 an imported library.  The list should be disjoint from the list of
-interface libraries in the INTERFACE_LINK_LIBRARIES property.  On
+interface libraries in the :prop_tgt:`INTERFACE_LINK_LIBRARIES` property.  On
 platforms requiring dependent shared libraries to be found at link
 time CMake uses this list to add appropriate files or paths to the
 link command line.  Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
index ee243c7..5b9c513 100644
--- a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>
 ------------------------------------------
 
-<CONFIG>-specific version of IMPORTED_LINK_DEPENDENT_LIBRARIES.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_DEPENDENT_LIBRARIES`.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.  If set, this property completely
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
index 5ca9c8b..4ed4281 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
@@ -1,14 +1,14 @@
 IMPORTED_LINK_INTERFACE_LANGUAGES
 ---------------------------------
 
-Languages compiled into an IMPORTED static library.
+Languages compiled into an ``IMPORTED`` static library.
 
 Set this to the list of languages of source files compiled to produce
-a STATIC IMPORTED library (such as "C" or "CXX").  CMake accounts for
+a ``STATIC IMPORTED`` library (such as ``C`` or ``CXX``).  CMake accounts for
 these languages when computing how to link a target to the imported
 library.  For example, when a C executable links to an imported C++
 static library CMake chooses the C++ linker to satisfy language
 runtime dependencies of the static library.
 
-This property is ignored for targets that are not STATIC libraries.
+This property is ignored for targets that are not ``STATIC`` libraries.
 This property is ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
index d4a10fb..40fcf7f 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_LINK_INTERFACE_LANGUAGES_<CONFIG>
 ------------------------------------------
 
-<CONFIG>-specific version of IMPORTED_LINK_INTERFACE_LANGUAGES.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_LANGUAGES`.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.  If set, this property completely
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
index 61134a4..527cf2e 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
@@ -1,16 +1,16 @@
 IMPORTED_LINK_INTERFACE_LIBRARIES
 ---------------------------------
 
-Transitive link interface of an IMPORTED target.
+Transitive link interface of an ``IMPORTED`` target.
 
 Set this to the list of libraries whose interface is included when an
-IMPORTED library target is linked to another target.  The libraries
+``IMPORTED`` library target is linked to another target.  The libraries
 will be included on the link line for the target.  Unlike the
-LINK_INTERFACE_LIBRARIES property, this property applies to all
-imported target types, including STATIC libraries.  This property is
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` property, this property applies to all
+imported target types, including ``STATIC`` libraries.  This property is
 ignored for non-imported targets.
 
 This property is ignored if the target also has a non-empty
-INTERFACE_LINK_LIBRARIES property.
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property.
 
-This property is deprecated.  Use INTERFACE_LINK_LIBRARIES instead.
+This property is deprecated.  Use :prop_tgt:`INTERFACE_LINK_LIBRARIES` instead.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
index 13b93ba..050fb1d 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
@@ -1,13 +1,13 @@
 IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>
 ------------------------------------------
 
-<CONFIG>-specific version of IMPORTED_LINK_INTERFACE_LIBRARIES.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_LIBRARIES`.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.  If set, this property completely
 overrides the generic property for the named configuration.
 
 This property is ignored if the target also has a non-empty
-INTERFACE_LINK_LIBRARIES property.
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property.
 
-This property is deprecated.  Use INTERFACE_LINK_LIBRARIES instead.
+This property is deprecated.  Use :prop_tgt:`INTERFACE_LINK_LIBRARIES` instead.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
index 3a86b99..7a92d96 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
@@ -1,6 +1,6 @@
 IMPORTED_LINK_INTERFACE_MULTIPLICITY
 ------------------------------------
 
-Repetition count for cycles of IMPORTED static libraries.
+Repetition count for cycles of ``IMPORTED`` static libraries.
 
-This is LINK_INTERFACE_MULTIPLICITY for IMPORTED targets.
+This is :prop_tgt:`LINK_INTERFACE_MULTIPLICITY` for ``IMPORTED`` targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
index 33b9b84..758237b 100644
--- a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_LINK_INTERFACE_MULTIPLICITY_<CONFIG>
 ---------------------------------------------
 
-<CONFIG>-specific version of IMPORTED_LINK_INTERFACE_MULTIPLICITY.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_MULTIPLICITY`.
 
 If set, this property completely overrides the generic property for
 the named configuration.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION.rst b/Help/prop_tgt/IMPORTED_LOCATION.rst
index 2d07aad..d674f29 100644
--- a/Help/prop_tgt/IMPORTED_LOCATION.rst
+++ b/Help/prop_tgt/IMPORTED_LOCATION.rst
@@ -1,21 +1,21 @@
 IMPORTED_LOCATION
 -----------------
 
-Full path to the main file on disk for an IMPORTED target.
+Full path to the main file on disk for an ``IMPORTED`` target.
 
-Set this to the location of an IMPORTED target file on disk.  For
+Set this to the location of an ``IMPORTED`` target file on disk.  For
 executables this is the location of the executable file.  For bundles
 on macOS this is the location of the executable file inside
-Contents/MacOS under the application bundle folder.  For static
+``Contents/MacOS`` under the application bundle folder.  For ``STATIC``
 libraries and modules this is the location of the library or module.
-For shared libraries on non-DLL platforms this is the location of the
+For ``SHARED`` libraries on non-DLL platforms this is the location of the
 shared library.  For frameworks on macOS this is the location of the
 library file symlink just inside the framework folder.  For DLLs this
-is the location of the ".dll" part of the library.  For UNKNOWN
+is the location of the ``.dll`` part of the library.  For ``UNKNOWN``
 libraries this is the location of the file to be linked.  Ignored for
 non-imported targets.
 
-Projects may skip IMPORTED_LOCATION if the configuration-specific
-property IMPORTED_LOCATION_<CONFIG> is set.  To get the location of an
-imported target read one of the LOCATION or LOCATION_<CONFIG>
-properties.
+Projects may skip ``IMPORTED_LOCATION`` if the configuration-specific
+property :prop_tgt:`IMPORTED_LOCATION_<CONFIG>` is set.  To get the location
+of an imported target read one of the :prop_tgt:`LOCATION` or
+``LOCATION_<CONFIG>`` properties.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst b/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
index f85bb19..c5f5f04 100644
--- a/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_LOCATION_<CONFIG>
 --------------------------
 
-<CONFIG>-specific version of IMPORTED_LOCATION property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LOCATION` property.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_NO_SONAME.rst b/Help/prop_tgt/IMPORTED_NO_SONAME.rst
index 4a1bb44..cbb7642 100644
--- a/Help/prop_tgt/IMPORTED_NO_SONAME.rst
+++ b/Help/prop_tgt/IMPORTED_NO_SONAME.rst
@@ -1,9 +1,9 @@
 IMPORTED_NO_SONAME
 ------------------
 
-Specifies that an IMPORTED shared library target has no "soname".
+Specifies that an ``IMPORTED`` shared library target has no ``soname``.
 
 Set this property to true for an imported shared library file that has
-no "soname" field.  CMake may adjust generated link commands for some
+no ``soname`` field.  CMake may adjust generated link commands for some
 platforms to prevent the linker from using the path to the library in
-place of its missing soname.  Ignored for non-imported targets.
+place of its missing ``soname``.  Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
index 22d6822..76fe471 100644
--- a/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_NO_SONAME_<CONFIG>
 ---------------------------
 
-<CONFIG>-specific version of IMPORTED_NO_SONAME property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_NO_SONAME` property.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_SONAME.rst b/Help/prop_tgt/IMPORTED_SONAME.rst
index d80907e..bf0c3cb 100644
--- a/Help/prop_tgt/IMPORTED_SONAME.rst
+++ b/Help/prop_tgt/IMPORTED_SONAME.rst
@@ -1,8 +1,8 @@
 IMPORTED_SONAME
 ---------------
 
-The "soname" of an IMPORTED target of shared library type.
+The ``soname`` of an ``IMPORTED`` target of shared library type.
 
-Set this to the "soname" embedded in an imported shared library.  This
+Set this to the ``soname`` embedded in an imported shared library.  This
 is meaningful only on platforms supporting the feature.  Ignored for
 non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
index 6ec9af3..59a9d1a 100644
--- a/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
+++ b/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
@@ -1,7 +1,7 @@
 IMPORTED_SONAME_<CONFIG>
 ------------------------
 
-<CONFIG>-specific version of IMPORTED_SONAME property.
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_SONAME` property.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.
diff --git a/Help/prop_tgt/IMPORT_PREFIX.rst b/Help/prop_tgt/IMPORT_PREFIX.rst
index deede97..17e381b 100644
--- a/Help/prop_tgt/IMPORT_PREFIX.rst
+++ b/Help/prop_tgt/IMPORT_PREFIX.rst
@@ -3,7 +3,7 @@
 
 What comes before the import library name.
 
-Similar to the target property PREFIX, but used for import libraries
-(typically corresponding to a DLL) instead of regular libraries.  A
-target property that can be set to override the prefix (such as "lib")
+Similar to the target property :prop_tgt:`PREFIX`, but used for import libraries
+(typically corresponding to a ``DLL``) instead of regular libraries.  A
+target property that can be set to override the prefix (such as ``lib``)
 on an import library name.
diff --git a/Help/prop_tgt/IMPORT_SUFFIX.rst b/Help/prop_tgt/IMPORT_SUFFIX.rst
index bd01250..9307115 100644
--- a/Help/prop_tgt/IMPORT_SUFFIX.rst
+++ b/Help/prop_tgt/IMPORT_SUFFIX.rst
@@ -3,7 +3,7 @@
 
 What comes after the import library name.
 
-Similar to the target property SUFFIX, but used for import libraries
-(typically corresponding to a DLL) instead of regular libraries.  A
-target property that can be set to override the suffix (such as
-".lib") on an import library name.
+Similar to the target property :prop_tgt:`SUFFIX`, but used
+for import libraries (typically corresponding to a ``DLL``) instead of
+regular libraries.  A target property that can be set to override
+the suffix (such as ``.lib``) on an import library name.
diff --git a/Help/prop_tgt/INCLUDE_DIRECTORIES.rst b/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
index 8b40d9c..b381d1d 100644
--- a/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
+++ b/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
@@ -18,7 +18,7 @@
 Relative paths should not be added to this property directly. Use one of
 the commands above instead to handle relative paths.
 
-Contents of ``INCLUDE_DIRECTORIES`` may use "generator expressions" with
+Contents of ``INCLUDE_DIRECTORIES`` may use :manual:`cmake-generator-expressions(7)` with
 the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INSTALL_NAME_DIR.rst b/Help/prop_tgt/INSTALL_NAME_DIR.rst
index 34348bb..2216072 100644
--- a/Help/prop_tgt/INSTALL_NAME_DIR.rst
+++ b/Help/prop_tgt/INSTALL_NAME_DIR.rst
@@ -1,10 +1,10 @@
 INSTALL_NAME_DIR
 ----------------
 
-Mac OSX directory name for installed targets.
+macOS directory name for installed targets.
 
-INSTALL_NAME_DIR is a string specifying the directory portion of the
-"install_name" field of shared libraries on Mac OSX to use in the
+``INSTALL_NAME_DIR`` is a string specifying the directory portion of the
+"install_name" field of shared libraries on macOS to use in the
 installed targets.
 
 This property is initialized by the value of the variable
diff --git a/Help/prop_tgt/INSTALL_RPATH.rst b/Help/prop_tgt/INSTALL_RPATH.rst
index 6206b68..6403f4c 100644
--- a/Help/prop_tgt/INSTALL_RPATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH.rst
@@ -5,5 +5,5 @@
 
 A semicolon-separated list specifying the rpath to use in installed
 targets (for platforms that support it).  This property is initialized
-by the value of the variable CMAKE_INSTALL_RPATH if it is set when a
-target is created.
+by the value of the variable :variable:`CMAKE_INSTALL_RPATH` if it is set when
+a target is created.
diff --git a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
index f0006f8..d8be954 100644
--- a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
@@ -3,8 +3,8 @@
 
 Add paths to linker search and installed rpath.
 
-INSTALL_RPATH_USE_LINK_PATH is a boolean that if set to true will
+``INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True`` will
 append directories in the linker search path and outside the project
-to the INSTALL_RPATH.  This property is initialized by the value of
-the variable CMAKE_INSTALL_RPATH_USE_LINK_PATH if it is set when a
+to the :prop_tgt:`INSTALL_RPATH`.  This property is initialized by the value of
+the variable ``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` if it is set when a
 target is created.
diff --git a/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
index d07f8ea..790554d 100644
--- a/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
@@ -3,9 +3,10 @@
 
 Additional public interface files on which a target binary depends for linking.
 
-This property is supported only by Makefile and Ninja generators.  It is
-intended to specify dependencies on "linker scripts" for custom Makefile link
-rules.
+This property is supported only by :generator:`Ninja` and
+:ref:`Makefile Generators`.
+It is intended to specify dependencies on "linker scripts" for
+custom Makefile link rules.
 
 When target dependencies are specified using :command:`target_link_libraries`,
 CMake will read this property from all target dependencies to determine the
diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
index 782b0f0..79d4604 100644
--- a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -3,7 +3,7 @@
 
 Per-configuration interprocedural optimization for a target.
 
-This is a per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
+This is a per-configuration version of :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION`.
 If set, this property overrides the generic property for the named
 configuration.
 
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
index 28dd404..5cefc38 100644
--- a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
@@ -6,7 +6,8 @@
 
 This is a per-configuration version of the
 :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY` target property, but
-multi-configuration generators (VS, Xcode) do NOT append a
+multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
 per-configuration subdirectory to the specified directory.  This
 property is initialized by the value of the
 :variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` variable if
diff --git a/Help/prop_tgt/LINKER_LANGUAGE.rst b/Help/prop_tgt/LINKER_LANGUAGE.rst
index b1ca867..b0a572b 100644
--- a/Help/prop_tgt/LINKER_LANGUAGE.rst
+++ b/Help/prop_tgt/LINKER_LANGUAGE.rst
@@ -8,7 +8,7 @@
 typical value for an executable is the language of the source file
 providing the program entry point (main).  If not set, the language
 with the highest linker preference value is the default.  See
-documentation of CMAKE_<LANG>_LINKER_PREFERENCE variables.
+documentation of :variable:`CMAKE_<LANG>_LINKER_PREFERENCE` variables.
 
 If this property is not set by the user, it will be calculated at
 generate-time by CMake.
diff --git a/Help/prop_tgt/LINK_DEPENDS.rst b/Help/prop_tgt/LINK_DEPENDS.rst
index 3ab8658..e59d4c0 100644
--- a/Help/prop_tgt/LINK_DEPENDS.rst
+++ b/Help/prop_tgt/LINK_DEPENDS.rst
@@ -7,7 +7,8 @@
 the link rule for this target depends.  The target binary will be
 linked if any of the named files is newer than it.
 
-This property is supported only by Makefile and Ninja generators.  It is
+This property is supported only by :generator:`Ninja` and
+:ref:`Makefile Generators`.  It is
 intended to specify dependencies on "linker scripts" for custom Makefile link
 rules.
 
diff --git a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
index e3918ca..68c3129 100644
--- a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
+++ b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
@@ -1,8 +1,8 @@
 LINK_FLAGS_<CONFIG>
 -------------------
 
-Per-configuration linker flags for a shared library, module or executable
-target.
+Per-configuration linker flags for a ``SHARED`` library, ``MODULE`` or
+``EXECUTABLE`` target.
 
 This is the configuration-specific version of :prop_tgt:`LINK_FLAGS`.
 
diff --git a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
index 4e26388..b798af9 100644
--- a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
+++ b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
@@ -1,9 +1,9 @@
 LINK_INTERFACE_MULTIPLICITY
 ---------------------------
 
-Repetition count for STATIC libraries with cyclic dependencies.
+Repetition count for ``STATIC`` libraries with cyclic dependencies.
 
-When linking to a STATIC library target with cyclic dependencies the
+When linking to a ``STATIC`` library target with cyclic dependencies the
 linker may need to scan more than once through the archives in the
 strongly connected component of the dependency graph.  CMake by
 default constructs the link line so that the linker will scan through
diff --git a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
index 5ea4a45..7c9461f 100644
--- a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
+++ b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
@@ -1,8 +1,8 @@
 LINK_INTERFACE_MULTIPLICITY_<CONFIG>
 ------------------------------------
 
-Per-configuration repetition count for cycles of STATIC libraries.
+Per-configuration repetition count for cycles of ``STATIC`` libraries.
 
 This is the configuration-specific version of
-LINK_INTERFACE_MULTIPLICITY.  If set, this property completely
+:prop_tgt:`LINK_INTERFACE_MULTIPLICITY`.  If set, this property completely
 overrides the generic property for the named configuration.
diff --git a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
index cf9c871..fecbb14 100644
--- a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
+++ b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
@@ -3,16 +3,17 @@
 
 End a link line such that static system libraries are used.
 
-Some linkers support switches such as -Bstatic and -Bdynamic to
-determine whether to use static or shared libraries for -lXXX options.
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
 CMake uses these options to set the link type for libraries whose full
 paths are not known or (in some cases) are in implicit link
 directories for the platform.  By default CMake adds an option at the
 end of the library list (if necessary) to set the linker search type
 back to its starting type.  This property switches the final linker
-search type to -Bstatic regardless of how it started.
+search type to ``-Bstatic`` regardless of how it started.
 
 This property is initialized by the value of the variable
-CMAKE_LINK_SEARCH_END_STATIC if it is set when a target is created.
+:variable:`CMAKE_LINK_SEARCH_END_STATIC` if it is set
+when a target is created.
 
-See also LINK_SEARCH_START_STATIC.
+See also :prop_tgt:`LINK_SEARCH_START_STATIC`.
diff --git a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
index 2e0f9bd..83cf231 100644
--- a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
+++ b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
@@ -3,17 +3,18 @@
 
 Assume the linker looks for static libraries by default.
 
-Some linkers support switches such as -Bstatic and -Bdynamic to
-determine whether to use static or shared libraries for -lXXX options.
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
 CMake uses these options to set the link type for libraries whose full
 paths are not known or (in some cases) are in implicit link
 directories for the platform.  By default the linker search type is
-assumed to be -Bdynamic at the beginning of the library list.  This
-property switches the assumption to -Bstatic.  It is intended for use
-when linking an executable statically (e.g.  with the GNU -static
+assumed to be ``-Bdynamic`` at the beginning of the library list.  This
+property switches the assumption to ``-Bstatic``.  It is intended for use
+when linking an executable statically (e.g. with the GNU ``-static``
 option).
 
 This property is initialized by the value of the variable
-CMAKE_LINK_SEARCH_START_STATIC if it is set when a target is created.
+ :variable:`CMAKE_LINK_SEARCH_START_STATIC` if it is set
+ when a target is created.
 
-See also LINK_SEARCH_END_STATIC.
+See also :prop_tgt:`LINK_SEARCH_END_STATIC`.
diff --git a/Help/prop_tgt/LOCATION.rst b/Help/prop_tgt/LOCATION.rst
index 16d5696..d058064 100644
--- a/Help/prop_tgt/LOCATION.rst
+++ b/Help/prop_tgt/LOCATION.rst
@@ -4,24 +4,25 @@
 Read-only location of a target on disk.
 
 For an imported target, this read-only property returns the value of
-the LOCATION_<CONFIG> property for an unspecified configuration
-<CONFIG> provided by the target.
+the ``LOCATION_<CONFIG>`` property for an unspecified configuration
+``<CONFIG>`` provided by the target.
 
 For a non-imported target, this property is provided for compatibility
 with CMake 2.4 and below.  It was meant to get the location of an
-executable target's output file for use in add_custom_command.  The
+executable target's output file for use in :command:`add_custom_command`.  The
 path may contain a build-system-specific portion that is replaced at
 build time with the configuration getting built (such as
-"$(ConfigurationName)" in VS).  In CMake 2.6 and above
-add_custom_command automatically recognizes a target name in its
-COMMAND and DEPENDS options and computes the target location.  In
-CMake 2.8.4 and above add_custom_command recognizes generator
-expressions to refer to target locations anywhere in the command.
+``$(ConfigurationName)`` in VS).  In CMake 2.6 and above
+:command:`add_custom_command` automatically recognizes a target name in its
+``COMMAND`` and ``DEPENDS`` options and computes the target location.  In
+CMake 2.8.4 and above :command:`add_custom_command` recognizes
+:manual:`generator expressions <cmake-generator-expressions(7)>`
+to refer to target locations anywhere in the command.
 Therefore this property is not needed for creating custom commands.
 
 Do not set properties that affect the location of a target after
 reading this property.  These include properties whose names match
-"(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?",
+``(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?``,
 ``(IMPLIB_)?(PREFIX|SUFFIX)``, or "LINKER_LANGUAGE".  Failure to follow
 this rule is not diagnosed and leaves the location of the target
 undefined.
diff --git a/Help/prop_tgt/LOCATION_CONFIG.rst b/Help/prop_tgt/LOCATION_CONFIG.rst
index ac6bdb7..67de8ed 100644
--- a/Help/prop_tgt/LOCATION_CONFIG.rst
+++ b/Help/prop_tgt/LOCATION_CONFIG.rst
@@ -4,17 +4,17 @@
 Read-only property providing a target location on disk.
 
 A read-only property that indicates where a target's main file is
-located on disk for the configuration <CONFIG>.  The property is
+located on disk for the configuration ``<CONFIG>``.  The property is
 defined only for library and executable targets.  An imported target
 may provide a set of configurations different from that of the
 importing project.  By default CMake looks for an exact-match but
 otherwise uses an arbitrary available configuration.  Use the
-MAP_IMPORTED_CONFIG_<CONFIG> property to map imported configurations
-explicitly.
+:prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` property to map imported
+configurations explicitly.
 
 Do not set properties that affect the location of a target after
 reading this property.  These include properties whose names match
-"(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?",
-``(IMPLIB_)?(PREFIX|SUFFIX)``, or "LINKER_LANGUAGE".  Failure to follow
-this rule is not diagnosed and leaves the location of the target
-undefined.
+``(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?``,
+``(IMPLIB_)?(PREFIX|SUFFIX)``, or  :prop_tgt:`LINKER_LANGUAGE`.
+Failure to follow this rule is not diagnosed and leaves
+the location of the target undefined.
diff --git a/Help/prop_tgt/NO_SONAME.rst b/Help/prop_tgt/NO_SONAME.rst
index ee45ed8..d381a9c 100644
--- a/Help/prop_tgt/NO_SONAME.rst
+++ b/Help/prop_tgt/NO_SONAME.rst
@@ -1,10 +1,10 @@
 NO_SONAME
 ---------
 
-Whether to set "soname" when linking a shared library.
+Whether to set ``soname`` when linking a shared library.
 
-Enable this boolean property if a generated shared library
-should not have "soname" set.  Default is to set "soname" on all
+Enable this boolean property if a generated ``SHARED`` library
+should not have ``soname`` set.  Default is to set ``soname`` on all
 shared libraries as long as the platform supports it.
 Generally, use this property only for leaf private libraries or
 plugins.  If you use it on normal shared libraries which other targets
diff --git a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
index 77fda90..6c55083 100644
--- a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -5,7 +5,8 @@
 generated by the linker for an executable or shared library target.
 
 This is a per-configuration version of :prop_tgt:`PDB_OUTPUT_DIRECTORY`,
-but multi-configuration generators (VS, Xcode) do NOT append a
+but multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
 per-configuration subdirectory to the specified directory.  This
 property is initialized by the value of the
 :variable:`CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable if it is
diff --git a/Help/prop_tgt/POST_INSTALL_SCRIPT.rst b/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
index f1adb40..23935bc 100644
--- a/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
+++ b/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
@@ -3,7 +3,7 @@
 
 Deprecated install support.
 
-The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the old
-way to specify CMake scripts to run before and after installing a
-target.  They are used only when the old INSTALL_TARGETS command is
-used to install the target.  Use the INSTALL command instead.
+The :prop_tgt:`PRE_INSTALL_SCRIPT` and ``POST_INSTALL_SCRIPT`` properties are
+the old way to specify CMake scripts to run before and after installing a
+target.  They are used only when the old ``INSTALL_TARGETS`` command is
+used to install the target.  Use the :command:`install` command instead.
diff --git a/Help/prop_tgt/PREFIX.rst b/Help/prop_tgt/PREFIX.rst
index a165104..a401292 100644
--- a/Help/prop_tgt/PREFIX.rst
+++ b/Help/prop_tgt/PREFIX.rst
@@ -4,4 +4,4 @@
 What comes before the library name.
 
 A target property that can be set to override the prefix (such as
-"lib") on a library name.
+``lib``) on a library name.
diff --git a/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst b/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
index 113d7c5..43432f4 100644
--- a/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
+++ b/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
@@ -3,7 +3,7 @@
 
 Deprecated install support.
 
-The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the old
-way to specify CMake scripts to run before and after installing a
-target.  They are used only when the old INSTALL_TARGETS command is
-used to install the target.  Use the INSTALL command instead.
+The ``PRE_INSTALL_SCRIPT`` and :prop_tgt:`POST_INSTALL_SCRIPT` properties are
+the old way to specify CMake scripts to run before and after installing a
+target.  They are used only when the old ``INSTALL_TARGETS`` command is
+used to install the target.  Use the :command:`install` command instead.
diff --git a/Help/prop_tgt/PRIVATE_HEADER.rst b/Help/prop_tgt/PRIVATE_HEADER.rst
index 2bd4079..23e1f8e 100644
--- a/Help/prop_tgt/PRIVATE_HEADER.rst
+++ b/Help/prop_tgt/PRIVATE_HEADER.rst
@@ -8,4 +8,4 @@
 This property may be set to a list of header files to be placed in the
 PrivateHeaders directory inside the framework folder.  On non-Apple
 platforms these headers may be installed using the ``PRIVATE_HEADER``
-option to the ``install(TARGETS)`` command.
+option to the :command:`install(TARGETS)` command.
diff --git a/Help/prop_tgt/PUBLIC_HEADER.rst b/Help/prop_tgt/PUBLIC_HEADER.rst
index 549ac7c..915e39c 100644
--- a/Help/prop_tgt/PUBLIC_HEADER.rst
+++ b/Help/prop_tgt/PUBLIC_HEADER.rst
@@ -8,4 +8,4 @@
 This property may be set to a list of header files to be placed in the
 ``Headers`` directory inside the framework folder.  On non-Apple platforms
 these headers may be installed using the ``PUBLIC_HEADER`` option to the
-``install(TARGETS)`` command.
+:command:`install(TARGETS)` command.
diff --git a/Help/prop_tgt/RESOURCE.rst b/Help/prop_tgt/RESOURCE.rst
index 55ae774..e5a1cb6 100644
--- a/Help/prop_tgt/RESOURCE.rst
+++ b/Help/prop_tgt/RESOURCE.rst
@@ -9,7 +9,7 @@
 This property may be set to a list of files to be placed in the corresponding
 directory (eg. ``Resources`` directory for macOS) inside the bundle.
 On non-Apple platforms these files may be installed using the ``RESOURCE``
-option to the ``install(TARGETS)`` command.
+option to the :command:`install(TARGETS)` command.
 
 Following example of Application Bundle:
 
@@ -18,21 +18,18 @@
   add_executable(ExecutableTarget
     addDemo.c
     resourcefile.txt
-    appresourcedir/appres.txt
-  )
+    appresourcedir/appres.txt)
 
   target_link_libraries(ExecutableTarget heymath mul)
 
   set(RESOURCE_FILES
     resourcefile.txt
-    appresourcedir/appres.txt
-  )
+    appresourcedir/appres.txt)
 
   set_target_properties(ExecutableTarget PROPERTIES
     MACOSX_BUNDLE TRUE
     MACOSX_FRAMEWORK_IDENTIFIER org.cmake.ExecutableTarget
-    RESOURCE "${RESOURCE_FILES}"
-  )
+    RESOURCE "${RESOURCE_FILES}")
 
 will produce flat structure for iOS systems::
 
@@ -53,7 +50,7 @@
         appres.txt
         resourcefile.txt
 
-For Linux, such cmake script produce following files::
+For Linux, such CMake script produce following files::
 
   ExecutableTarget
   Resources
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
index 94fb277..6727754 100644
--- a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
@@ -6,7 +6,8 @@
 
 This is a per-configuration version of the
 :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target property, but
-multi-configuration generators (VS, Xcode) do NOT append a
+multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
 per-configuration subdirectory to the specified directory.  This
 property is initialized by the value of the
 :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if
diff --git a/Help/prop_tgt/SKIP_BUILD_RPATH.rst b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
index a91fa9c..7086b1b 100644
--- a/Help/prop_tgt/SKIP_BUILD_RPATH.rst
+++ b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
@@ -3,7 +3,7 @@
 
 Should rpaths be used for the build tree.
 
-SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic
+``SKIP_BUILD_RPATH`` is a boolean specifying whether to skip automatic
 generation of an rpath allowing the target to run from the build tree.
 This property is initialized by the value of the variable
-CMAKE_SKIP_BUILD_RPATH if it is set when a target is created.
+:variable:`CMAKE_SKIP_BUILD_RPATH` if it is set when a target is created.
diff --git a/Help/prop_tgt/SUFFIX.rst b/Help/prop_tgt/SUFFIX.rst
index 70844be..32ec429 100644
--- a/Help/prop_tgt/SUFFIX.rst
+++ b/Help/prop_tgt/SUFFIX.rst
@@ -4,4 +4,4 @@
 What comes after the target name.
 
 A target property that can be set to override the suffix (such as
-".so" or ".exe") on the name of a library, module or executable.
+``.so`` or ``.exe``) on the name of a library, module or executable.
diff --git a/Help/prop_tgt/TYPE.rst b/Help/prop_tgt/TYPE.rst
index 1cd9db4..3136d11 100644
--- a/Help/prop_tgt/TYPE.rst
+++ b/Help/prop_tgt/TYPE.rst
@@ -4,6 +4,6 @@
 The type of the target.
 
 This read-only property can be used to test the type of the given
-target.  It will be one of STATIC_LIBRARY, MODULE_LIBRARY,
-SHARED_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY, EXECUTABLE or one
-of the internal target types.
+target.  It will be one of ``STATIC_LIBRARY``, ``MODULE_LIBRARY``,
+``SHARED_LIBRARY``, ``OBJECT_LIBRARY``, ``INTERFACE_LIBRARY``, ``EXECUTABLE``
+or one of the internal target types.
diff --git a/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst b/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst
new file mode 100644
index 0000000..ffcbde5
--- /dev/null
+++ b/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst
@@ -0,0 +1,46 @@
+VS_NO_SOLUTION_DEPLOY
+---------------------
+
+Specify that the target should not be marked for deployment to a Windows CE
+or Windows Phone device in the generated Visual Studio solution.
+
+Be default, all EXE and shared library (DLL) targets are marked to deploy to
+the target device in the generated Visual Studio solution.
+
+Generator expressions are supported.
+
+There are reasons one might want to exclude a target / generated project from
+deployment:
+
+- The library or executable may not be necessary in the primary deploy/debug
+  scenario, and excluding from deployment saves time in the
+  develop/download/debug cycle.
+- There may be insufficient space on the target device to accommodate all of
+  the build products.
+- Visual Studio 2013 requires a target device IP address be entered for each
+  target marked for deployment.  For large numbers of targets, this can be
+  tedious.
+  NOTE: Visual Studio *will* deploy all project dependencies of a project
+  tagged for deployment to the IP address configured for that project even
+  if those dependencies are not tagged for deployment.
+
+
+Example 1
+^^^^^^^^^
+
+This shows setting the variable for the target foo.
+
+.. code-block:: cmake
+
+  add_library(foo SHARED foo.cpp)
+  set_property(TARGET foo PROPERTY VS_NO_SOLUTION_DEPLOY ON)
+
+Example 2
+^^^^^^^^^
+
+This shows setting the variable for the Release configuration only.
+
+.. code-block:: cmake
+
+  add_library(foo SHARED foo.cpp)
+  set_property(TARGET foo PROPERTY VS_NO_SOLUTION_DEPLOY "$<CONFIG:Release>")
diff --git a/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst b/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
index 7e00ac4..71858c5 100644
--- a/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
+++ b/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
@@ -3,8 +3,8 @@
 
 Set Xcode target attributes directly.
 
-Tell the Xcode generator to set '<an-attribute>' to a given value in
-the generated Xcode project.  Ignored on other generators.
+Tell the :generator:`Xcode` generator to set '<an-attribute>' to a given
+value in the generated Xcode project.  Ignored on other generators.
 
 See the :variable:`CMAKE_XCODE_ATTRIBUTE_<an-attribute>` variable
 to set attributes on all targets in a directory tree.
diff --git a/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
new file mode 100644
index 0000000..0adb5db
--- /dev/null
+++ b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
@@ -0,0 +1,39 @@
+XCODE_GENERATE_SCHEME
+---------------------
+
+If enabled, the :generator:`Xcode` generator will generate schema files.  These
+are useful to invoke analyze, archive, build-for-testing and test
+actions from the command line.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_GENERATE_SCHEME` if it is set when a target
+is created.
+
+The following target properties overwrite the default of the
+corresponding settings on the "Diagnostic" tab for each schema file.
+Each of those is initialized by the respective ``CMAKE_`` variable
+at target creation time.
+
+- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
+- :prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
+- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
+- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
+- :prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
+- :prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
+- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
+- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
+- :prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
+
+The following target properties will be applied on the
+"Info" and "Arguments" tab:
+
+- :prop_tgt:`XCODE_SCHEME_ARGUMENTS`
+- :prop_tgt:`XCODE_SCHEME_DEBUG_AS_ROOT`
+- :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
+- :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
diff --git a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
index 694cd77..cc9bac2 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
index 2803da0..37a043a 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
 if it is set when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst b/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
index 2eac4a9..1f228e3 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
@@ -6,5 +6,5 @@
 
 If set to a list of arguments those will be added to the scheme.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst b/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst
new file mode 100644
index 0000000..5407e80
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst
@@ -0,0 +1,7 @@
+XCODE_SCHEME_DEBUG_AS_ROOT
+--------------------------
+
+Whether to debug the target as 'root'.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst b/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
index 75fc326..1a6fcfd 100644
--- a/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
 if it is set when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
index a7fab66..9224022 100644
--- a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
index 162fc45..203c803 100644
--- a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst b/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
index 1dbd6c4..c6d875e 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
@@ -8,5 +8,5 @@
 ``MYVAR=value`` those environment variables will be added to the
 scheme.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst b/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
index d0427e2..104841b 100644
--- a/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
@@ -5,5 +5,5 @@
 Xcode scheme. If not set the schema generator will select the
 current target if it is actually executable.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst b/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
index 64e1990..c4e83da 100644
--- a/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_GUARD_MALLOC` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
index 99c112f..73992c3 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
@@ -9,5 +9,5 @@
 :variable:`CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
index ef3852a..ca761c0 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
index 75baba2..c5ddb95 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
index 984022c..170f33d 100644
--- a/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_MALLOC_STACK` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
index 825ac5b..bb70141 100644
--- a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_THREAD_SANITIZER` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
index 86f894e..5deadb1 100644
--- a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
index 829a62e..0cd823d 100644
--- a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
 if it is set when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
index 5e382ca..d1a9bca 100644
--- a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
@@ -9,5 +9,5 @@
 :variable:`CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
 if it is set when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst b/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
index 80b954a..6e70e8b 100644
--- a/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
@@ -8,5 +8,5 @@
 :variable:`CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS` if it is set
 when a target is created.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/release/3.9.rst b/Help/release/3.9.rst
index ffa95aa..89da627 100644
--- a/Help/release/3.9.rst
+++ b/Help/release/3.9.rst
@@ -150,7 +150,7 @@
 * The :module:`CMakeFindDependencyMacro` module ``find_dependency`` macro
   now forwards all arguments to the underlying :command:`find_package`
   call.  Existing uses will continue to function as before, but callers can
-  now access the full suite of arguments that ``find_package`` accepts.
+  now access the full suite of arguments that :command:`find_package` accepts.
 
 * The :module:`FeatureSummary` module :command:`feature_summary` command now
   accepts the new ``DEFAULT_DESCRIPTION`` option that will print the default
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/FindCups-imported-target.rst b/Help/release/dev/FindCups-imported-target.rst
new file mode 100644
index 0000000..0fd9178
--- /dev/null
+++ b/Help/release/dev/FindCups-imported-target.rst
@@ -0,0 +1,4 @@
+FindCups-imported-target
+------------------------
+
+* The :module:`FindCups` module now provides imported targets.
diff --git a/Help/release/dev/FindGLEW-updates.rst b/Help/release/dev/FindGLEW-updates.rst
new file mode 100644
index 0000000..6487052
--- /dev/null
+++ b/Help/release/dev/FindGLEW-updates.rst
@@ -0,0 +1,5 @@
+FindGLEW-updates
+----------------
+
+* The :module:`FindGLEW` module now provides an interface more consistent
+  with what upstream GLEW provides in its own CMake package files.
diff --git a/Help/release/dev/FindPython-virtual-env.rst b/Help/release/dev/FindPython-virtual-env.rst
new file mode 100644
index 0000000..5489dc2
--- /dev/null
+++ b/Help/release/dev/FindPython-virtual-env.rst
@@ -0,0 +1,5 @@
+FindPython-virtual-env
+----------------------
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+  gain capability to control how virtual environments are handled.
diff --git a/Help/release/dev/add-xlclang.rst b/Help/release/dev/add-xlclang.rst
new file mode 100644
index 0000000..77ff938
--- /dev/null
+++ b/Help/release/dev/add-xlclang.rst
@@ -0,0 +1,5 @@
+add-xlclang
+-----------
+
+* IBM Clang-based XL compilers that define ``__ibmxl__`` now use the
+  compiler id ``XLClang`` instead of ``XL``.  See policy :policy:`CMP0089`.
diff --git a/Help/release/dev/allow-aliasing-unkown-import-targets.rst b/Help/release/dev/allow-aliasing-unkown-import-targets.rst
new file mode 100644
index 0000000..aa5da0c
--- /dev/null
+++ b/Help/release/dev/allow-aliasing-unkown-import-targets.rst
@@ -0,0 +1,5 @@
+allow-aliasing-unkown-import-targets
+------------------------------------
+
+* :command:`add_library` command ``ALIAS`` option learned to support
+  import libraries of the ``UNKNOWN`` type.
diff --git a/Help/release/dev/cmake--install_option.rst b/Help/release/dev/cmake--install_option.rst
new file mode 100644
index 0000000..8e526a0
--- /dev/null
+++ b/Help/release/dev/cmake--install_option.rst
@@ -0,0 +1,6 @@
+cmake--install-option
+---------------------
+
+* A new ``--install`` option was added to :manual:`cmake(1)`.
+  This may be used after building a project to run installation without
+  using the generated build system or the native build tool.
diff --git a/Help/release/dev/cmake-build-multiply-targets.rst b/Help/release/dev/cmake-build-multiply-targets.rst
new file mode 100644
index 0000000..1275ca3
--- /dev/null
+++ b/Help/release/dev/cmake-build-multiply-targets.rst
@@ -0,0 +1,5 @@
+cmake-build-multiply-targets
+----------------------------
+
+* The :manual:`cmake(1)` ``--build`` tool ``--target`` parameter gained support for
+  multiple targets, e.g. ``cmake --build . --target Library1 Library2``.
diff --git a/Help/release/dev/cmake-e-tar-creating-archive.rst b/Help/release/dev/cmake-e-tar-creating-archive.rst
new file mode 100644
index 0000000..717855c
--- /dev/null
+++ b/Help/release/dev/cmake-e-tar-creating-archive.rst
@@ -0,0 +1,6 @@
+cmake-e-tar-creating-archive
+----------------------------
+
+* The :manual:`cmake(1)` ``-E tar`` tool now continues adding files to an
+  archive, even if some of the files aren't readable. This behavior is more
+  consistent with the classic ``tar`` tool.
diff --git a/Help/release/dev/cmake-e-tar-error-handling.rst b/Help/release/dev/cmake-e-tar-error-handling.rst
new file mode 100644
index 0000000..d1f2c72
--- /dev/null
+++ b/Help/release/dev/cmake-e-tar-error-handling.rst
@@ -0,0 +1,8 @@
+cmake-e-tar-error-handling
+--------------------------
+
+* The :manual:`cmake(1)` ``-E tar`` tool now parses all flags, and if an
+  invalid flag was provided, a warning is issued.
+* The :manual:`cmake(1)` ``-E tar`` tool now displays an error if no action
+  flag was specified, along with a list of possible actions: ``t`` (list),
+  ``c`` (create) or ``x`` (extract).
diff --git a/Help/release/dev/cmake-short-target-option.rst b/Help/release/dev/cmake-short-target-option.rst
new file mode 100644
index 0000000..5eac042
--- /dev/null
+++ b/Help/release/dev/cmake-short-target-option.rst
@@ -0,0 +1,6 @@
+cmake-short-target-option
+----------------------------
+
+* The :manual:`cmake(1)` ``--target`` parameter gained shorter
+  version ``-t``, e.g. ``cmake --build . -t Library1 Library2`` is
+  equivalant to ``cmake --build . --target Library1 Library2``.
diff --git a/Help/release/dev/cmake_parse_arguments-keywords_missing_values.rst b/Help/release/dev/cmake_parse_arguments-keywords_missing_values.rst
new file mode 100644
index 0000000..c7fe96b
--- /dev/null
+++ b/Help/release/dev/cmake_parse_arguments-keywords_missing_values.rst
@@ -0,0 +1,6 @@
+cmake_parse_arguments-keywords_missing_values
+---------------------------------------------
+
+* The :command:`cmake_parse_arguments` command gained an additional
+  ``<prefix>_KEYWORDS_MISSING_VALUES`` output variable to report
+  keyword arguments that were given by the caller with no values.
diff --git a/Help/release/dev/ctest_submit_get_buildid.rst b/Help/release/dev/ctest_submit_get_buildid.rst
new file mode 100644
index 0000000..39a0010
--- /dev/null
+++ b/Help/release/dev/ctest_submit_get_buildid.rst
@@ -0,0 +1,6 @@
+ctest_submit_get_buildid
+--------------------------
+
+* The :command:`ctest_submit` command learned a new option: ``BUILD_ID``.
+  This can be used to store the ID assigned to this build by CDash to a
+  variable.
diff --git a/Help/release/dev/cuda-compiler-generator-expressions.rst b/Help/release/dev/cuda-compiler-generator-expressions.rst
new file mode 100644
index 0000000..2610a39
--- /dev/null
+++ b/Help/release/dev/cuda-compiler-generator-expressions.rst
@@ -0,0 +1,5 @@
+cuda-compiler-generator-expressions
+-----------------------------------
+
+* The ``$<CUDA_COMPILER_ID:...>`` and ``$<CUDA_COMPILER_VERSION:...>``
+  :manual:`generator expressions <cmake-generator-expressions(7)>` were added.
diff --git a/Help/release/dev/deprecate-policy-old.rst b/Help/release/dev/deprecate-policy-old.rst
new file mode 100644
index 0000000..b94f4b7
--- /dev/null
+++ b/Help/release/dev/deprecate-policy-old.rst
@@ -0,0 +1,8 @@
+deprecate-policy-old
+--------------------
+
+* An explicit deprecation diagnostic was added for policy ``CMP0066``
+  (``CMP0065`` and below were already deprecated).
+  The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+  of all policies are deprecated and that projects should port to the
+  NEW behaviors.
diff --git a/Help/release/dev/environment-modules.rst b/Help/release/dev/environment-modules.rst
new file mode 100644
index 0000000..eace35d
--- /dev/null
+++ b/Help/release/dev/environment-modules.rst
@@ -0,0 +1,5 @@
+environment-modules
+-------------------
+
+* The :module:`FindEnvModules` module was added to use Lua- and TCL-based
+  environment modules in :ref:`CTest Scripts <CTest Script>`.
diff --git a/Help/release/dev/export-package-default-off.rst b/Help/release/dev/export-package-default-off.rst
new file mode 100644
index 0000000..0868c82
--- /dev/null
+++ b/Help/release/dev/export-package-default-off.rst
@@ -0,0 +1,6 @@
+export-package-default-off
+--------------------------
+
+* The :command:`export(PACKAGE)` command now does nothing unless
+  enabled via :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY`.
+  See policy :policy:`CMP0090`.
diff --git a/Help/release/dev/genex-TARGET_FILE_PREFIX.rst b/Help/release/dev/genex-TARGET_FILE_PREFIX.rst
new file mode 100644
index 0000000..3e480bb
--- /dev/null
+++ b/Help/release/dev/genex-TARGET_FILE_PREFIX.rst
@@ -0,0 +1,7 @@
+genex-TARGET_FILE_PREFIX
+------------------------
+
+* New ``$<TARGET_FILE_PREFIX:...>``, ``$<TARGET_LINKER_FILE_PREFIX:...>``,
+  ``$<TARGET_FILE_SUFFIX:...>`` and ``$<TARGET_LINKER_FILE_SUFFIX:...>``
+  :manual:`generator expressions <cmake-generator-expressions(7)>` have been
+  added to retrieve the prefix and suffix of various artifacts.
diff --git a/Help/release/dev/genex-TARGET_OUTPUT_NAME.rst b/Help/release/dev/genex-TARGET_OUTPUT_NAME.rst
new file mode 100644
index 0000000..e3ffe57
--- /dev/null
+++ b/Help/release/dev/genex-TARGET_OUTPUT_NAME.rst
@@ -0,0 +1,7 @@
+genex-TARGET_OUTPUT_NAME
+------------------------
+
+* New ``$<TARGET_OUTPUT_NAME:...>``, ``$<TARGET_LINKER_OUTPUT_NAME:...>`` and
+  ``$<TARGET_PDB_OUTPUT_NAME:...>``
+  :manual:`generator expressions <cmake-generator-expressions(7)>` have been
+  added to retrieve the base name of various artifacts.
diff --git a/Help/release/dev/genex_filter.rst b/Help/release/dev/genex_filter.rst
new file mode 100644
index 0000000..ad23134
--- /dev/null
+++ b/Help/release/dev/genex_filter.rst
@@ -0,0 +1,6 @@
+genex_filter
+------------
+
+* A new ``$<FILTER:list,INCLUDE|EXCLUDE,regex>``
+  :manual:`generator expression <cmake-generator-expressions(7)>`
+  has been added.
diff --git a/Help/release/dev/ghs-custom-commands.rst b/Help/release/dev/ghs-custom-commands.rst
new file mode 100644
index 0000000..a29ef88
--- /dev/null
+++ b/Help/release/dev/ghs-custom-commands.rst
@@ -0,0 +1,5 @@
+ghs_custom_commands
+-------------------
+
+* The :generator:`Green Hills MULTI` generator now supports
+  :command:`add_custom_command` and :command:`add_custom_target`
diff --git a/Help/release/dev/ghs-linux.rst b/Help/release/dev/ghs-linux.rst
new file mode 100644
index 0000000..6b663c8
--- /dev/null
+++ b/Help/release/dev/ghs-linux.rst
@@ -0,0 +1,4 @@
+ghs-linux
+---------
+
+* The :generator:`Green Hills MULTI` generator is now available on Linux.
diff --git a/Help/release/dev/iface-headers.rst b/Help/release/dev/iface-headers.rst
new file mode 100644
index 0000000..2e1de5e
--- /dev/null
+++ b/Help/release/dev/iface-headers.rst
@@ -0,0 +1,7 @@
+iface-headers
+-------------
+
+* ``INTERFACE`` library can now have :prop_tgt:`PUBLIC_HEADER` and
+  :prop_tgt:`PRIVATE_HEADER` properties set. The headers specified by those
+  properties can be installed using the :command:`install(TARGETS)` command by
+  passing the ``PUBLIC_HEADER`` and ``PRIVATE_HEADER`` arguments respectively.
diff --git a/Help/release/dev/list-prepend-and-pop-subcommands.rst b/Help/release/dev/list-prepend-and-pop-subcommands.rst
new file mode 100644
index 0000000..16b14f1
--- /dev/null
+++ b/Help/release/dev/list-prepend-and-pop-subcommands.rst
@@ -0,0 +1,4 @@
+list-prepend-and-pop-subcommands
+--------------------------------
+
+* :command:`list` learned new sub-commands ``PREPEND``, ``POP_FRONT`` and ``POP_BACK``.
diff --git a/Help/release/dev/pkg-config-linker-flags.rst b/Help/release/dev/pkg-config-linker-flags.rst
new file mode 100644
index 0000000..85c13be
--- /dev/null
+++ b/Help/release/dev/pkg-config-linker-flags.rst
@@ -0,0 +1,5 @@
+pkg-config-linker-flags
+-----------------------
+
+* The :module:`FindPkgConfig` now populates :prop_tgt:`INTERFACE_LINK_OPTIONS`
+  property of imported targets with other (non-library) linker flags.
diff --git a/Help/release/dev/project-include-before.rst b/Help/release/dev/project-include-before.rst
new file mode 100644
index 0000000..3f16cd7
--- /dev/null
+++ b/Help/release/dev/project-include-before.rst
@@ -0,0 +1,5 @@
+cmake_project_include_before
+----------------------------
+
+* A variable :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` was added to allow
+  injection of custom code into the project.
diff --git a/Help/release/dev/project-include.rst b/Help/release/dev/project-include.rst
new file mode 100644
index 0000000..659e933
--- /dev/null
+++ b/Help/release/dev/project-include.rst
@@ -0,0 +1,5 @@
+cmake_project_include
+---------------------
+
+* A variable :variable:`CMAKE_PROJECT_INCLUDE` was added to allow injection
+  of custom code into the project without knowing the project name a priori.
diff --git a/Help/release/dev/remove_duplicates.rst b/Help/release/dev/remove_duplicates.rst
new file mode 100644
index 0000000..f6a7fff
--- /dev/null
+++ b/Help/release/dev/remove_duplicates.rst
@@ -0,0 +1,6 @@
+remove_duplicates
+-----------------
+
+* A new ``$<REMOVE_DUPLICATES:list>``
+  :manual:`generator expression <cmake-generator-expressions(7)>`
+  has been added.
diff --git a/Help/release/dev/require-xcode-5.rst b/Help/release/dev/require-xcode-5.rst
new file mode 100644
index 0000000..6cfe96a
--- /dev/null
+++ b/Help/release/dev/require-xcode-5.rst
@@ -0,0 +1,4 @@
+require-xcode-5
+---------------
+
+* The :generator:`Xcode` generator now requires at least Xcode 5.
diff --git a/Help/release/dev/shell_path.rst b/Help/release/dev/shell_path.rst
new file mode 100644
index 0000000..e8ebfb5
--- /dev/null
+++ b/Help/release/dev/shell_path.rst
@@ -0,0 +1,5 @@
+shell_path
+----------
+
+* The ``$<SHELL_PATH:...>`` :manual:`generator expression
+  <cmake-generator-expressions(7)>` gained support for a list of paths.
diff --git a/Help/release/dev/vs-wince-no-deploy.rst b/Help/release/dev/vs-wince-no-deploy.rst
new file mode 100644
index 0000000..6c18d895
--- /dev/null
+++ b/Help/release/dev/vs-wince-no-deploy.rst
@@ -0,0 +1,6 @@
+vs_wince_no_deploy
+------------------
+
+* A :prop_tgt:`VS_NO_SOLUTION_DEPLOY` target property was added to
+  tell :ref:`Visual Studio Generators` whether to deploy an artifact
+  to the WinCE or Windows Phone target device.
diff --git a/Help/release/dev/xcode-scheme-per-target.rst b/Help/release/dev/xcode-scheme-per-target.rst
new file mode 100644
index 0000000..3febe79
--- /dev/null
+++ b/Help/release/dev/xcode-scheme-per-target.rst
@@ -0,0 +1,6 @@
+xcode-scheme-per-target
+-----------------------
+
+* The :generator:`Xcode` generator now supports per-target schemes.
+  See the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable and
+  :prop_tgt:`XCODE_GENERATE_SCHEME` target property.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 4fcd4ca..2318e03 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_CROSSCOMPILING.rst b/Help/variable/CMAKE_CROSSCOMPILING.rst
index 9e96769..7e6ec33 100644
--- a/Help/variable/CMAKE_CROSSCOMPILING.rst
+++ b/Help/variable/CMAKE_CROSSCOMPILING.rst
@@ -19,8 +19,9 @@
 relying on :variable:`CMAKE_SYSTEM_NAME` to select the target platform, Apple
 device builds use :variable:`CMAKE_OSX_SYSROOT` to select the appropriate SDK,
 which indirectly determines the target platform. Furthermore, when using the
-Xcode generator, developers can switch between device and simulator builds at
-build time rather than having a single choice at configure time, so the concept
+:generator:`Xcode` generator, developers can switch between device and
+simulator builds at build time rather than having a single
+choice at configure time, so the concept
 of whether the build is cross compiling or not is more complex. Therefore, the
 use of ``CMAKE_CROSSCOMPILING`` is not recommended for projects targeting Apple
 devices.
diff --git a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
index 95d2c7f..e7774f2 100644
--- a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
+++ b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
@@ -6,7 +6,7 @@
 for the target system.
 
 The command will be used to run :command:`try_run` generated executables,
-which avoids manual population of the TryRunResults.cmake file.
+which avoids manual population of the ``TryRunResults.cmake`` file.
 
 It is also used as the default value for the
 :prop_tgt:`CROSSCOMPILING_EMULATOR` target property of executables.
diff --git a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
index 72e8e66..eea2c4f 100644
--- a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
+++ b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
@@ -2,6 +2,6 @@
 ------------------------
 
 Executable to use when compiling host code when compiling ``CUDA`` language
-files. Maps to the nvcc -ccbin option.  Will only be used by CMake on the first
+files. Maps to the ``nvcc -ccbin`` option.  Will only be used by CMake on the first
 configuration to determine a valid host compiler for ``CUDA``. After a valid
 host compiler has been found, this value is read-only.
diff --git a/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
index ee109ba..768ed64 100644
--- a/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
+++ b/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
@@ -1,11 +1,16 @@
 CMAKE_EXPORT_NO_PACKAGE_REGISTRY
 --------------------------------
 
-Disable the :command:`export(PACKAGE)` command.
+Disable the :command:`export(PACKAGE)` command when :policy:`CMP0090`
+is not set to ``NEW``.
 
 In some cases, for example for packaging and for system wide
 installations, it is not desirable to write the user package registry.
-If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable is enabled,
+If the ``CMAKE_EXPORT_NO_PACKAGE_REGISTRY`` variable is enabled,
 the :command:`export(PACKAGE)` command will do nothing.
 
+If :policy:`CMP0090` is set to ``NEW`` this variable does nothing, and the
+:variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable controls the behavior
+instead.
+
 See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..3476a19
--- /dev/null
+++ b/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst
@@ -0,0 +1,15 @@
+CMAKE_EXPORT_PACKAGE_REGISTRY
+-----------------------------
+
+Enables the :command:`export(PACKAGE)` command when :policy:`CMP0090`
+is set to ``NEW``.
+
+The :command:`export(PACKAGE)` command does nothing by default.  In some cases
+it is desirable to write to the user package registry, so the
+``CMAKE_EXPORT_PACKAGE_REGISTRY`` variable may be set to enable it.
+
+If :policy:`CMP0090` is *not* set to ``NEW`` this variable does nothing, and
+the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable controls the behavior
+instead.
+
+See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
index 5323880..2bb3979 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_ID.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
@@ -24,7 +24,6 @@
   HP = Hewlett-Packard Compiler (hp.com)
   IAR = IAR Systems (iar.com)
   Intel = Intel Compiler (intel.com)
-  MIPSpro = SGI MIPSpro (sgi.com)
   MSVC = Microsoft Visual Studio (microsoft.com)
   NVIDIA = NVIDIA CUDA Compiler (nvidia.com)
   OpenWatcom = Open Watcom (openwatcom.org)
diff --git a/Help/variable/CMAKE_MAKE_PROGRAM.rst b/Help/variable/CMAKE_MAKE_PROGRAM.rst
index 4f5a50f..a3c8b7c 100644
--- a/Help/variable/CMAKE_MAKE_PROGRAM.rst
+++ b/Help/variable/CMAKE_MAKE_PROGRAM.rst
@@ -19,15 +19,11 @@
   This generator stores ``CMAKE_MAKE_PROGRAM`` in the CMake cache
   so that it may be edited by the user.
 
-* The :generator:`Xcode` generator sets this to ``xcodebuild`` (or possibly an
-  otherwise undocumented ``cmakexbuild`` wrapper implementing some
-  workarounds).
+* The :generator:`Xcode` generator sets this to ``xcodebuild``.
 
   This generator prefers to lookup the build tool at build time
   rather than to store ``CMAKE_MAKE_PROGRAM`` in the CMake cache
-  ahead of time.  This is because ``xcodebuild`` is easy to find,
-  the ``cmakexbuild`` wrapper is needed only for older Xcode versions,
-  and the path to ``cmakexbuild`` may be outdated if CMake itself moves.
+  ahead of time.  This is because ``xcodebuild`` is easy to find.
 
   For compatibility with versions of CMake prior to 3.2, if
   a user or project explicitly adds ``CMAKE_MAKE_PROGRAM`` to
@@ -56,7 +52,8 @@
   possible.
 
 * The :generator:`Green Hills MULTI` generator sets this to the full
-  path to ``gbuild.exe`` based upon the toolset being used.
+  path to ``gbuild.exe(Windows)`` or ``gbuild(Linux)`` based upon
+  the toolset being used.
 
   Once the generator has initialized a particular value for this
   variable, changing the value has undefined behavior.
diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
index d179728..fc52e7b 100644
--- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
+++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
@@ -21,6 +21,8 @@
   policy :policy:`CMP0067`.
 * ``CMAKE_POLICY_WARNING_CMP0082`` controls the warning for
   policy :policy:`CMP0082`.
+* ``CMAKE_POLICY_WARNING_CMP0089`` controls the warning for
+  policy :policy:`CMP0089`.
 
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
new file mode 100644
index 0000000..7de767a
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
@@ -0,0 +1,6 @@
+CMAKE_PROJECT_INCLUDE
+---------------------
+
+A CMake language file or module to be included by the :command:`project`
+command.  This is intended for injecting custom code into project
+builds without modifying their source.
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
new file mode 100644
index 0000000..12a5263
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
@@ -0,0 +1,6 @@
+CMAKE_PROJECT_INCLUDE_BEFORE
+----------------------------
+
+A CMake language file or module to be included before processing the
+:command:`project` command. This is intended for injecting custom code into
+project builds without modifying their source.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
index 44966f3..b77bb68 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
@@ -3,6 +3,6 @@
 
 Whether to disable generation of installation rules.
 
-If ``TRUE``, cmake will neither generate installaton rules nor
+If ``TRUE``, CMake will neither generate installation rules nor
 will it generate ``cmake_install.cmake`` files. This variable is ``FALSE`` by
 default.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
index 416fbe1..d1f1798 100644
--- a/Help/variable/CMAKE_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -7,7 +7,7 @@
 tree.  For an in-source build, this would be the same as
 :variable:`CMAKE_BINARY_DIR`.
 
-When run in -P script mode, CMake sets the variables
+When run in ``-P`` script mode, CMake sets the variables
 :variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
 :variable:`CMAKE_CURRENT_BINARY_DIR` and
 :variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_STAGING_PREFIX.rst b/Help/variable/CMAKE_STAGING_PREFIX.rst
index 1310e94..bdb97fa 100644
--- a/Help/variable/CMAKE_STAGING_PREFIX.rst
+++ b/Help/variable/CMAKE_STAGING_PREFIX.rst
@@ -5,10 +5,10 @@
 be useful if the path in :variable:`CMAKE_SYSROOT` is read-only, or otherwise
 should remain pristine.
 
-The ``CMAKE_STAGING_PREFIX`` location is also used as a search prefix by the
-``find_*`` commands. This can be controlled by setting the
+The :variable:`CMAKE_STAGING_PREFIX` location is also used as a search prefix
+by the ``find_*`` commands. This can be controlled by setting the
 :variable:`CMAKE_FIND_NO_INSTALL_PREFIX` variable.
 
-If any RPATH/RUNPATH entries passed to the linker contain the
-``CMAKE_STAGING_PREFIX``, the matching path fragments are replaced with the
-:variable:`CMAKE_INSTALL_PREFIX`.
+If any ``RPATH``/``RUNPATH`` entries passed to the linker contain the
+:variable:`CMAKE_STAGING_PREFIX`, the matching path fragments are replaced
+with the :variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
index ed47e1a..96184dd 100644
--- a/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
+++ b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
@@ -1,10 +1,10 @@
 CMAKE_SUPPRESS_REGENERATION
 ---------------------------
 
-If CMAKE_SUPPRESS_REGENERATION is ``OFF``, which is default, then CMake adds a
-special target on which all other targets depend that checks the build system
-and optionally re-runs CMake to regenerate the build system when the target
-specification source changes.
+If ``CMAKE_SUPPRESS_REGENERATION`` is ``OFF``, which is default, then CMake
+adds a special target on which all other targets depend that checks the build
+system and optionally re-runs CMake to regenerate the build system when
+the target specification source changes.
 
 If this variable evaluates to ``ON`` at the end of the top-level
 ``CMakeLists.txt`` file, CMake will not add the regeneration target to the
diff --git a/Help/variable/CMAKE_SYSROOT.rst b/Help/variable/CMAKE_SYSROOT.rst
index 64f81bb..35b944f 100644
--- a/Help/variable/CMAKE_SYSROOT.rst
+++ b/Help/variable/CMAKE_SYSROOT.rst
@@ -4,8 +4,8 @@
 Path to pass to the compiler in the ``--sysroot`` flag.
 
 The ``CMAKE_SYSROOT`` content is passed to the compiler in the ``--sysroot``
-flag, if supported.  The path is also stripped from the RPATH/RUNPATH if
-necessary on installation.  The ``CMAKE_SYSROOT`` is also used to prefix
+flag, if supported.  The path is also stripped from the ``RPATH``/``RUNPATH``
+if necessary on installation.  The ``CMAKE_SYSROOT`` is also used to prefix
 paths searched by the ``find_*`` commands.
 
 This variable may only be set in a toolchain file specified by
diff --git a/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst b/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
index 7466784..5b1a003 100644
--- a/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
+++ b/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
@@ -1,34 +1,10 @@
 CMAKE_XCODE_GENERATE_SCHEME
 ---------------------------
 
-If enabled, the Xcode generator will generate schema files.  These
+If enabled, the :generator:`Xcode` generator will generate schema files.  These
 are useful to invoke analyze, archive, build-for-testing and test
 actions from the command line.
 
-The following target properties overwrite the default of the
-corresponding settings on the "Diagnostic" tab for each schema file.
-Each of those is initialized by the respective ``CMAKE_`` variable
-at target creation time.
-
-- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
-- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
-- :prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
-- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
-- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
-- :prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
-- :prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
-- :prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
-- :prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
-- :prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
-- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
-- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
-- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
-- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
-- :prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
-
-The following target properties will be applied on the
-"Info" and "Arguments" tab:
-
-- :prop_tgt:`XCODE_SCHEME_ARGUMENTS`
-- :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
-- :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
+This variable initializes the
+:prop_tgt:`XCODE_GENERATE_SCHEME`
+target property on all targets.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
index 37dc0ce..b972ba5 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
index 05949c3..59eb32d 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst b/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
index 81f4974..71bcf42 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
index 5e133ac..53f55e6 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
index 33162d9..784ceb6 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst b/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
index 03d88c2..9350244 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
index fd6135f..45a2dad 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
@@ -9,5 +9,5 @@
 :prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
index 8fedc20..94d1c61 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
index cddca7c..9bf0eb4 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
index 9c83698..4cc21ee 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
index c937369..6d1b56e 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
index eed796c..de40478 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
index d14ba3f..ec5df66 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
index f8df304..dcec9b0 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
@@ -9,5 +9,5 @@
 :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst b/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
index efc331a..82e9d76 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
@@ -8,5 +8,5 @@
 :prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
 property on all targets.
 
-Please refer to the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
 documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
index 5dad6bd..30ae236 100644
--- a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
+++ b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -5,7 +5,7 @@
 is encountered.
 
 The fatal error is emitted before the installation of the offending
-file takes place.  Some CPack generators, like NSIS, enforce this
+file takes place.  Some CPack generators, like ``NSIS``, enforce this
 internally.  This variable triggers the definition
 of :variable:`CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` when CPack
 runs.
diff --git a/Help/variable/PackageName_ROOT.rst b/Help/variable/PackageName_ROOT.rst
index c5b07ae..1c2fd34 100644
--- a/Help/variable/PackageName_ROOT.rst
+++ b/Help/variable/PackageName_ROOT.rst
@@ -3,7 +3,7 @@
 
 Calls to :command:`find_package(<PackageName>)` will search in prefixes
 specified by the ``<PackageName>_ROOT`` CMake variable, where
-``<PackageName>`` is the name given to the ``find_package`` call
+``<PackageName>`` is the name given to the :command:`find_package` call
 and ``_ROOT`` is literal.  For example, ``find_package(Foo)`` will search
 prefixes specified in the ``Foo_ROOT`` CMake variable (if set).
 See policy :policy:`CMP0074`.
diff --git a/Help/variable/XCODE_VERSION.rst b/Help/variable/XCODE_VERSION.rst
index b85d41e..9caf19a 100644
--- a/Help/variable/XCODE_VERSION.rst
+++ b/Help/variable/XCODE_VERSION.rst
@@ -3,5 +3,5 @@
 
 Version of Xcode (:generator:`Xcode` generator only).
 
-Under the Xcode generator, this is the version of Xcode as specified
-in ``Xcode.app/Contents/version.plist`` (such as ``3.1.2``).
+Under the :generator:`Xcode` generator, this is the version of Xcode
+as specified in ``Xcode.app/Contents/version.plist`` (such as ``3.1.2``).
diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake
index 8c7646e..f94fc5c 100644
--- a/Modules/BundleUtilities.cmake
+++ b/Modules/BundleUtilities.cmake
@@ -7,7 +7,7 @@
 
 Functions to help assemble a standalone bundle application.
 
-A collection of CMake utility functions useful for dealing with .app
+A collection of CMake utility functions useful for dealing with ``.app``
 bundles on the Mac and bundle-like directories on any OS.
 
 The following functions are provided by this module:
@@ -33,7 +33,7 @@
    verify_bundle_symlinks
 
 Requires CMake 2.6 or greater because it uses function, break and
-PARENT_SCOPE.  Also depends on GetPrerequisites.cmake.
+``PARENT_SCOPE``.  Also depends on ``GetPrerequisites.cmake``.
 
 DO NOT USE THESE FUNCTIONS AT CONFIGURE TIME (from ``CMakeLists.txt``)!
 Instead, invoke them from an :command:`install(CODE)` or
@@ -43,55 +43,57 @@
 
   fixup_bundle(<app> <libs> <dirs>)
 
-Fix up a bundle in-place and make it standalone, such that it can be
+Fix up ``<app>`` bundle in-place and make it standalone, such that it can be
 drag-n-drop copied to another machine and run on that machine as long
 as all of the system libraries are compatible.
 
-If you pass plugins to fixup_bundle as the libs parameter, you should
-install them or copy them into the bundle before calling fixup_bundle.
-The "libs" parameter is a list of libraries that must be fixed up, but
-that cannot be determined by otool output analysis.  (i.e., plugins)
+If you pass plugins to ``fixup_bundle`` as the libs parameter, you should
+install them or copy them into the bundle before calling ``fixup_bundle``.
+The ``<libs>`` parameter is a list of libraries that must be fixed up, but
+that cannot be determined by ``otool`` output analysis  (i.e. ``plugins``).
 
 Gather all the keys for all the executables and libraries in a bundle,
 and then, for each key, copy each prerequisite into the bundle.  Then
 fix each one up according to its own list of prerequisites.
 
-Then clear all the keys and call verify_app on the final bundle to
+Then clear all the keys and call ``verify_app`` on the final bundle to
 ensure that it is truly standalone.
 
-As an optional parameter (IGNORE_ITEM) a list of file names can be passed,
-which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe")
+As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+which are then ignored
+(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``).
 
 .. code-block:: cmake
 
   copy_and_fixup_bundle(<src> <dst> <libs> <dirs>)
 
-Makes a copy of the bundle <src> at location <dst> and then fixes up
-the new copied bundle in-place at <dst>...
+Makes a copy of the bundle ``<src>`` at location ``<dst>`` and then fixes up
+the new copied bundle in-place at ``<dst>``.
 
 .. code-block:: cmake
 
   verify_app(<app>)
 
-Verifies that an application <app> appears valid based on running
-analysis tools on it.  Calls "message(FATAL_ERROR" if the application
+Verifies that an application ``<app>`` appears valid based on running
+analysis tools on it.  Calls :command:`message(FATAL_ERROR)` if the application
 is not verified.
 
-As an optional parameter (IGNORE_ITEM) a list of file names can be passed,
-which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe")
+As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+which are then ignored
+(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
 
 .. code-block:: cmake
 
   get_bundle_main_executable(<bundle> <result_var>)
 
 The result will be the full path name of the bundle's main executable
-file or an "error:" prefixed string if it could not be determined.
+file or an ``error:`` prefixed string if it could not be determined.
 
 .. code-block:: cmake
 
   get_dotapp_dir(<exe> <dotapp_dir_var>)
 
-Returns the nearest parent dir whose name ends with ".app" given the
+Returns the nearest parent dir whose name ends with ``.app`` given the
 full path to an executable.  If there is no such parent dir, then
 simply return the dir containing the executable.
 
@@ -101,26 +103,26 @@
 
   get_bundle_and_executable(<app> <bundle_var> <executable_var> <valid_var>)
 
-Takes either a ".app" directory name or the name of an executable
-nested inside a ".app" directory and returns the path to the ".app"
-directory in <bundle_var> and the path to its main executable in
-<executable_var>
+Takes either a ``.app`` directory name or the name of an executable
+nested inside a ``.app`` directory and returns the path to the ``.app``
+directory in ``<bundle_var>`` and the path to its main executable in
+``<executable_var>``.
 
 .. code-block:: cmake
 
   get_bundle_all_executables(<bundle> <exes_var>)
 
-Scans the given bundle recursively for all executable files and
-accumulates them into a variable.
+Scans ``<bundle>`` bundle recursively for all ``<exes_var>`` executable
+files and accumulates them into a variable.
 
 .. code-block:: cmake
 
   get_item_key(<item> <key_var>)
 
-Given a file (item) name, generate a key that should be unique
+Given ``<item>`` file name, generate ``<key_var>`` key that should be unique
 considering the set of libraries that need copying or fixing up to
 make a bundle standalone.  This is essentially the file name including
-extension with "." replaced by "_"
+extension with ``.`` replaced by ``_``
 
 This key is used as a prefix for CMake variables so that we can
 associate a set of variables with a given item based on its key.
@@ -129,10 +131,10 @@
 
   clear_bundle_keys(<keys_var>)
 
-Loop over the list of keys, clearing all the variables associated with
-each key.  After the loop, clear the list of keys itself.
+Loop over the ``<keys_var>`` list of keys, clearing all the variables
+associated with each key.  After the loop, clear the list of keys itself.
 
-Caller of get_bundle_keys should call clear_bundle_keys when done with
+Caller of ``get_bundle_keys`` should call ``clear_bundle_keys`` when done with
 list of keys.
 
 .. code-block:: cmake
@@ -140,86 +142,88 @@
   set_bundle_key_values(<keys_var> <context> <item> <exepath> <dirs>
                         <copyflag> [<rpaths>])
 
-Add a key to the list (if necessary) for the given item.  If added,
-also set all the variables associated with that key.
+Add ``<keys_var>`` key to the list (if necessary) for the given item.
+If added, also set all the variables associated with that key.
 
 .. code-block:: cmake
 
   get_bundle_keys(<app> <libs> <dirs> <keys_var>)
 
-Loop over all the executable and library files within the bundle (and
-given as extra <libs>) and accumulate a list of keys representing
+Loop over all the executable and library files within ``<app>`` bundle (and
+given as extra ``<libs>``) and accumulate a list of keys representing
 them.  Set values associated with each key such that we can loop over
 all of them and copy prerequisite libs into the bundle and then do
-appropriate install_name_tool fixups.
+appropriate ``install_name_tool`` fixups.
 
-As an optional parameter (IGNORE_ITEM) a list of file names can be passed,
-which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe")
+As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+which are then ignored
+(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
 
 .. code-block:: cmake
 
   copy_resolved_item_into_bundle(<resolved_item> <resolved_embedded_item>)
 
-Copy a resolved item into the bundle if necessary.  Copy is not
-necessary if the resolved_item is "the same as" the
-resolved_embedded_item.
+Copy a resolved item into the bundle if necessary.
+Copy is not necessary, if the ``<resolved_item>`` is "the same as" the
+``<resolved_embedded_item>``.
 
 .. code-block:: cmake
 
   copy_resolved_framework_into_bundle(<resolved_item> <resolved_embedded_item>)
 
-Copy a resolved framework into the bundle if necessary.  Copy is not
-necessary if the resolved_item is "the same as" the
-resolved_embedded_item.
+Copy a resolved framework into the bundle if necessary.
+Copy is not necessary, if the ``<resolved_item>`` is "the same as" the
+``<resolved_embedded_item>``.
 
-By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set.  If you want
+By default, ``BU_COPY_FULL_FRAMEWORK_CONTENTS`` is not set.  If you want
 full frameworks embedded in your bundles, set
-BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle.  By
-default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework
-dylib itself plus the framework Resources directory.
+``BU_COPY_FULL_FRAMEWORK_CONTENTS`` to ``ON`` before calling fixup_bundle.  By
+default, ``COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE`` copies the framework
+dylib itself plus the framework ``Resources`` directory.
 
 .. code-block:: cmake
 
   fixup_bundle_item(<resolved_embedded_item> <exepath> <dirs>)
 
-Get the direct/non-system prerequisites of the resolved embedded item.
+Get the direct/non-system prerequisites of the ``<resolved_embedded_item>``.
 For each prerequisite, change the way it is referenced to the value of
-the _EMBEDDED_ITEM keyed variable for that prerequisite.  (Most likely
-changing to an "@executable_path" style reference.)
+the ``_EMBEDDED_ITEM`` keyed variable for that prerequisite.  (Most likely
+changing to an ``@executable_path`` style reference.)
 
-This function requires that the resolved_embedded_item be "inside" the
-bundle already.  In other words, if you pass plugins to fixup_bundle
+This function requires that the ``<resolved_embedded_item>`` be ``inside``
+the bundle already.  In other words, if you pass plugins to ``fixup_bundle``
 as the libs parameter, you should install them or copy them into the
-bundle before calling fixup_bundle.  The "libs" parameter is a list of
+bundle before calling ``fixup_bundle``.  The ``libs`` parameter is a list of
 libraries that must be fixed up, but that cannot be determined by
-otool output analysis.  (i.e., plugins)
+otool output analysis.  (i.e., ``plugins``)
 
 Also, change the id of the item being fixed up to its own
-_EMBEDDED_ITEM value.
+``_EMBEDDED_ITEM`` value.
 
 Accumulate changes in a local variable and make *one* call to
-install_name_tool at the end of the function with all the changes at
+``install_name_tool`` at the end of the function with all the changes at
 once.
 
-If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
-marked writable before install_name_tool tries to change them.
+If the ``BU_CHMOD_BUNDLE_ITEMS`` variable is set then bundle items will be
+marked writable before ``install_name_tool`` tries to change them.
 
 .. code-block:: cmake
 
   verify_bundle_prerequisites(<bundle> <result_var> <info_var>)
 
 Verifies that the sum of all prerequisites of all files inside the
-bundle are contained within the bundle or are "system" libraries,
+bundle are contained within the bundle or are ``system`` libraries,
 presumed to exist everywhere.
 
-As an optional parameter (IGNORE_ITEM) a list of file names can be passed,
-which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe")
+As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+which are then ignored
+(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
 
 .. code-block:: cmake
 
   verify_bundle_symlinks(<bundle> <result_var> <info_var>)
 
-Verifies that any symlinks found in the bundle point to other files
+Verifies that any symlinks found in the ``<bundle>`` bundle point to other files
 that are already also in the bundle...  Anything that points to an
 external file causes this function to fail the verification.
 #]=======================================================================]
diff --git a/Modules/CMakeASM_NASMInformation.cmake b/Modules/CMakeASM_NASMInformation.cmake
index 1e3c608..cb793e7 100644
--- a/Modules/CMakeASM_NASMInformation.cmake
+++ b/Modules/CMakeASM_NASMInformation.cmake
@@ -28,7 +28,9 @@
   endif()
 endif()
 
-set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+if(NOT CMAKE_ASM_NASM_COMPILE_OBJECT)
+  set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+endif()
 
 # Load the generic ASMInformation file:
 set(ASM_DIALECT "_NASM")
diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
index e60ffe0..5b9ed34 100644
--- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
+++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
@@ -30,5 +30,6 @@
      FAIL_REGEX "Incorrect command line option:"            # Borland
      FAIL_REGEX "Warning: illegal option"                   # SunStudio 12
      FAIL_REGEX "[Ww]arning: Invalid suboption"             # Fujitsu
+     FAIL_REGEX "An invalid option .* appears on the command line" # Cray
    )
 endmacro ()
diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake
index 6a22d27..ed288f5 100644
--- a/Modules/CMakeCompilerIdDetection.cmake
+++ b/Modules/CMakeCompilerIdDetection.cmake
@@ -57,6 +57,7 @@
       HP
       Compaq
       zOS
+      XLClang
       XL
       VisualAge
       PGI
@@ -86,8 +87,6 @@
         SDCC
       )
     endif()
-    list(APPEND ordered_compilers
-      MIPSpro)
 
     #Currently the only CUDA compilers are NVIDIA
     if(lang STREQUAL CUDA)
@@ -98,6 +97,8 @@
       foreach(Id ${ordered_compilers})
         string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "# define ${CID_PREFIX}COMPILER_IS_${Id} 0\n")
       endforeach()
+      # Hard-code definitions for compilers that are no longer supported.
+      string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "# define ${CID_PREFIX}COMPILER_IS_MIPSpro 0\n")
     endif()
 
     set(pp_if "#if")
diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake
index b8c8c5d..eabb8b5 100644
--- a/Modules/CMakeDetermineASMCompiler.cmake
+++ b/Modules/CMakeDetermineASMCompiler.cmake
@@ -119,35 +119,40 @@
   CMAKE_DETERMINE_COMPILER_ID_VENDOR(ASM${ASM_DIALECT} "${userflags}")
   if("x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xIAR")
     # primary necessary to detect architecture, so the right archiver and linker can be picked
-    # eg. IAR Assembler V8.10.1.12857/W32 for ARM
+    # eg. "IAR Assembler V8.10.1.12857/W32 for ARM" or "IAR Assembler V4.11.1.4666 for Renesas RX"
     # Cut out identification first, newline handling is a pain
     string(REGEX MATCH "IAR Assembler[^\r\n]*" _compileid "${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT}")
     if("${_compileid}" MATCHES "V([0-9]+\\.[0-9]+\\.[0-9]+)")
       set(CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION ${CMAKE_MATCH_1})
     endif()
-    if("${_compileid}" MATCHES "for[ ]+([A-Za-z0-9]+)")
-      set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID ${CMAKE_MATCH_1})
+    string(REGEX MATCHALL "([A-Za-z0-9]+)" _all_compileid_matches "${_compileid}")
+    if(_all_compileid_matches)
+      list(GET _all_compileid_matches "-1" CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID)
     endif()
   endif()
   unset(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT)
+  unset(_all_compileid_matches)
   unset(_compileid)
 endif()
 
-
 if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
   if(CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION)
     set(_version " ${CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION}")
   else()
     set(_version "")
   endif()
-  message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_version}")
+  if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID)
+    set(_archid " ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}")
+  else()
+    set(_archid "")
+  endif()
+  message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_archid}${_version}")
+  unset(_archid)
   unset(_version)
 else()
   message(STATUS "The ASM${ASM_DIALECT} compiler identification is unknown")
 endif()
 
-
-
 # If we have a gas/as cross compiler, they have usually some prefix, like
 # e.g. powerpc-linux-gas, arm-elf-gas or i586-mingw32msvc-gas , optionally
 # with a 3-component version number at the end
diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake
index d7f6f97..3ec534f 100644
--- a/Modules/CMakeDetermineCCompiler.cmake
+++ b/Modules/CMakeDetermineCCompiler.cmake
@@ -139,8 +139,9 @@
 
   if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|QCC")
     get_filename_component(COMPILER_BASENAME "${CMAKE_C_COMPILER}" NAME)
-    if (COMPILER_BASENAME MATCHES "^(.+-)(clang|g?cc)(-[0-9]+\\.[0-9]+\\.[0-9]+)?(\\.exe)?$")
+    if (COMPILER_BASENAME MATCHES "^(.+-)(clang|g?cc)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
       set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+      set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
     elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
       if(CMAKE_C_COMPILER_TARGET)
         set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_C_COMPILER_TARGET}-)
diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake
index bd878b2..68cb9fe 100644
--- a/Modules/CMakeDetermineCXXCompiler.cmake
+++ b/Modules/CMakeDetermineCXXCompiler.cmake
@@ -136,8 +136,9 @@
 
   if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|QCC")
     get_filename_component(COMPILER_BASENAME "${CMAKE_CXX_COMPILER}" NAME)
-    if (COMPILER_BASENAME MATCHES "^(.+-)(clan)?[gc]\\+\\+(-[0-9]+\\.[0-9]+\\.[0-9]+)?(\\.exe)?$")
+    if (COMPILER_BASENAME MATCHES "^(.+-)(clan)?[gc]\\+\\+(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
       set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+      set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
     elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
       if(CMAKE_CXX_COMPILER_TARGET)
         set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_CXX_COMPILER_TARGET}-)
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index 59dab6d..c1c9982 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -110,8 +110,15 @@
     else()
       set(_version "")
     endif()
+    if(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID)
+      set(_archid " ${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}")
+    else()
+      set(_archid "")
+    endif()
     message(STATUS "The ${lang} compiler identification is "
-      "${CMAKE_${lang}_COMPILER_ID}${_version}")
+      "${CMAKE_${lang}_COMPILER_ID}${_archid}${_version}")
+    unset(_archid)
+    unset(_version)
   else()
     message(STATUS "The ${lang} compiler identification is unknown")
   endif()
@@ -431,10 +438,18 @@
       )
     # Match the compiler location line printed out.
     set(ghs_toolpath "${CMAKE_MAKE_PROGRAM}")
-    string(REPLACE "/gbuild.exe" "/" ghs_toolpath ${ghs_toolpath})
-    string(REPLACE / "\\\\" ghs_toolpath ${ghs_toolpath})
+    if(CMAKE_HOST_UNIX)
+      string(REPLACE "/gbuild" "/" ghs_toolpath ${ghs_toolpath})
+    else()
+      string(REPLACE "/gbuild.exe" "/" ghs_toolpath ${ghs_toolpath})
+      string(REPLACE / "\\\\" ghs_toolpath ${ghs_toolpath})
+    endif()
     if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "(${ghs_toolpath}[^ ]*)")
-      set(_comp "${CMAKE_MATCH_1}.exe")
+      if(CMAKE_HOST_UNIX)
+        set(_comp "${CMAKE_MATCH_1}")
+      else()
+        set(_comp "${CMAKE_MATCH_1}.exe")
+      endif()
       if(EXISTS "${_comp}")
         file(TO_CMAKE_PATH "${_comp}" _comp)
         set(CMAKE_${lang}_COMPILER_ID_TOOL "${_comp}" PARENT_SCOPE)
diff --git a/Modules/CMakeFindDependencyMacro.cmake b/Modules/CMakeFindDependencyMacro.cmake
index de1a332..bcdfbeb 100644
--- a/Modules/CMakeFindDependencyMacro.cmake
+++ b/Modules/CMakeFindDependencyMacro.cmake
@@ -31,36 +31,33 @@
 #]=======================================================================]
 
 macro(find_dependency dep)
-  if (NOT ${dep}_FOUND)
-    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}
-    )
-
-    if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
-      set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
-    endif()
-
-    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)
-      return()
-    endif()
-    set(cmake_fd_required_arg)
-    set(cmake_fd_quiet_arg)
-    set(cmake_fd_exact_arg)
+  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}
+  )
+
+  if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
+    set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
+  endif()
+
+  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)
+    return()
+  endif()
+  set(cmake_fd_required_arg)
+  set(cmake_fd_quiet_arg)
 endmacro()
diff --git a/Modules/CMakeFortranCompilerId.F.in b/Modules/CMakeFortranCompilerId.F.in
index 5995694..30f8d4c 100644
--- a/Modules/CMakeFortranCompilerId.F.in
+++ b/Modules/CMakeFortranCompilerId.F.in
@@ -96,13 +96,6 @@
 # if defined(__FLANG_PATCHLEVEL__)
 #  define COMPILER_VERSION_PATCH DEC(__FLANG_PATCHLEVEL__)
 # endif
-#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION)
-        PRINT *, 'INFO:compiler[MIPSpro]'
-#       if 0
-!       This compiler is either not known or is too old to define an
-!       identification macro.  Try to identify the platform and guess that
-!       it is the native compiler.
-#       endif
 #elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
         PRINT *, 'INFO:compiler[VisualAge]'
 #elif defined(__hpux) || defined(__hpux__)
diff --git a/Modules/CMakeParseImplicitIncludeInfo.cmake b/Modules/CMakeParseImplicitIncludeInfo.cmake
index c8d4c5a..176b3ff 100644
--- a/Modules/CMakeParseImplicitIncludeInfo.cmake
+++ b/Modules/CMakeParseImplicitIncludeInfo.cmake
@@ -92,13 +92,15 @@
   endif()
 
   # XL compiler
-  if("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XL" AND "${line}" MATCHES "^/"
+  if(("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XL"
+      OR "${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XLClang")
+     AND "${line}" MATCHES "^/"
      AND ( ("${lang}" STREQUAL "Fortran" AND
             "${line}" MATCHES "/xl[fF]entry " AND
             "${line}" MATCHES "OSVAR\\([^ ]+\\)")
            OR
             (  ("${lang}" STREQUAL "C" OR "${lang}" STREQUAL "CXX") AND
-            "${line}" MATCHES "/xl[cC]entry " AND
+            "${line}" MATCHES "/xl[cC]2?entry " AND
             "${line}" MATCHES " -qosvar=")
          )  )
     # -qnostdinc cancels other stdinc flags, even if present
@@ -216,6 +218,14 @@
       get_filename_component(dir "${d}" ABSOLUTE)
       list(APPEND implicit_dirs "${dir}")
       string(APPEND log "  collapse include dir [${d}] ==> [${dir}]\n")
+    elseif("${d}" MATCHES [[^\.\.[\/]\.\.[\/](.*)$]])
+      # This relative path is deep enough to get out of the CMakeFiles/CMakeTmp
+      # directory where the ABI check is done.  Assume that the compiler has
+      # computed this path adaptively based on the current working directory
+      # such that the effective result is absolute.
+      get_filename_component(dir "${CMAKE_BINARY_DIR}/${CMAKE_MATCH_1}" ABSOLUTE)
+      list(APPEND implicit_dirs "${dir}")
+      string(APPEND log "  collapse relative include dir [${d}] ==> [${dir}]\n")
     else()
       string(APPEND log "  skipping relative include dir [${d}]\n")
     endif()
diff --git a/Modules/CMakePlatformId.h.in b/Modules/CMakePlatformId.h.in
index 3cb7f24..c88094a 100644
--- a/Modules/CMakePlatformId.h.in
+++ b/Modules/CMakePlatformId.h.in
@@ -156,6 +156,9 @@
 # if defined(__ICCARM__)
 #  define ARCHITECTURE_ID "ARM"
 
+# elif defined(__ICCRX__)
+#  define ARCHITECTURE_ID "RX"
+
 # elif defined(__ICCAVR__)
 #  define ARCHITECTURE_ID "AVR"
 
diff --git a/Modules/CMakeRCInformation.cmake b/Modules/CMakeRCInformation.cmake
index 1227fdf..7bf6567 100644
--- a/Modules/CMakeRCInformation.cmake
+++ b/Modules/CMakeRCInformation.cmake
@@ -32,7 +32,7 @@
 # compile a Resource file into an object file
 if(NOT CMAKE_RC_COMPILE_OBJECT)
   set(CMAKE_RC_COMPILE_OBJECT
-    "<CMAKE_RC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /fo<OBJECT> <SOURCE>")
+    "<CMAKE_RC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /fo <OBJECT> <SOURCE>")
 endif()
 
 # set this variable so we can avoid loading this more than once.
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index d100704..3a111ca 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -118,7 +118,7 @@
       endif()
       string(APPEND SUBMIT_URL "@")
     endif()
-    string(APPEND SUBMIT_URL "${DROP_SITE}${DROP_SITE_LOCATION}")
+    string(APPEND SUBMIT_URL "${DROP_SITE}${DROP_LOCATION}")
   endif()
 
   find_program(CVSCOMMAND cvs )
diff --git a/Modules/CheckTypeSize.c.in b/Modules/CheckTypeSize.c.in
index 2303c4e..82035a3 100644
--- a/Modules/CheckTypeSize.c.in
+++ b/Modules/CheckTypeSize.c.in
@@ -18,7 +18,7 @@
 #endif
 
 #define SIZE (sizeof(@type@))
-char info_size[] =  {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',
+static char info_size[] =  {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',
   ('0' + ((SIZE / 10000)%10)),
   ('0' + ((SIZE / 1000)%10)),
   ('0' + ((SIZE / 100)%10)),
diff --git a/Modules/Compiler/ARMCC-DetermineCompiler.cmake b/Modules/Compiler/ARMCC-DetermineCompiler.cmake
index a3667d7..5f2d0f8 100644
--- a/Modules/Compiler/ARMCC-DetermineCompiler.cmake
+++ b/Modules/Compiler/ARMCC-DetermineCompiler.cmake
@@ -1,5 +1,5 @@
 # ARMCC Toolchain
-set(_compiler_id_pp_test "defined(__ARMCC_VERSION)")
+set(_compiler_id_pp_test "defined(__ARMCC_VERSION) && !defined(__clang__)")
 
 set(_compiler_id_version_compute "
 #if __ARMCC_VERSION >= 1000000
diff --git a/Modules/Compiler/AppleClang-C.cmake b/Modules/Compiler/AppleClang-C.cmake
index a48adec..2794f52 100644
--- a/Modules/Compiler/AppleClang-C.cmake
+++ b/Modules/Compiler/AppleClang-C.cmake
@@ -4,12 +4,15 @@
 if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
 
   set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
   set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
 
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+  set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
 endif()
 
 __compiler_check_default_language_standard(C 4.0 99)
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
index e5fd647..d34d494 100644
--- a/Modules/Compiler/AppleClang-CXX.cmake
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -8,6 +8,7 @@
 if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
 
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
index ad464c7..96537f8 100644
--- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -65,13 +65,28 @@
 macro(cmake_record_c_compile_features)
   set(_result 0)
   if(_result EQUAL 0 AND DEFINED CMAKE_C11_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_c(11)
+    if(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_c(11)
+    else()
+      _record_compiler_features_c(11)
+    endif()
+    unset(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_C99_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_c(99)
+    if(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_c(99)
+    else()
+      _record_compiler_features_c(99)
+    endif()
+    unset(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_C90_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_c(90)
+    if(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_c(90)
+    else()
+      _record_compiler_features_c(90)
+    endif()
+    unset(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT)
   endif()
 endmacro()
 
@@ -79,18 +94,43 @@
 macro(cmake_record_cxx_compile_features)
   set(_result 0)
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_cxx(20)
+    if(CMAKE_CXX20_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cxx(20)
+    else()
+      _record_compiler_features_cxx(20)
+    endif()
+    unset(CMAKE_CXX20_STANDARD__HAS_FULL_SUPPORT)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX17_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_cxx(17)
+    if(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cxx(17)
+    else()
+      _record_compiler_features_cxx(17)
+    endif()
+    unset(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX14_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_cxx(14)
+    if(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cxx(14)
+    else()
+      _record_compiler_features_cxx(14)
+    endif()
+    unset(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX11_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_cxx(11)
+    if(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cxx(11)
+    else()
+      _record_compiler_features_cxx(11)
+    endif()
+    unset(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX98_STANDARD_COMPILE_OPTION)
-    _record_compiler_features_cxx(98)
+    if(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cxx(98)
+    else()
+      _record_compiler_features_cxx(98)
+    endif()
+    unset(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
   endif()
 endmacro()
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
index a07ae40..ff51d30 100644
--- a/Modules/Compiler/Clang-C.cmake
+++ b/Modules/Compiler/Clang-C.cmake
@@ -10,12 +10,15 @@
   if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
     set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
     set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+    set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
 
     set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
     set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+    set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
 
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
   else()
     # clang-cl doesn't have any of these
     set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
index e99011b..34ffd66 100644
--- a/Modules/Compiler/Clang-CXX.cmake
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -19,6 +19,7 @@
   if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.1)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+    set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
@@ -59,6 +60,7 @@
   # support for -std: flags.
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
   set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
diff --git a/Modules/Compiler/Cray-C.cmake b/Modules/Compiler/Cray-C.cmake
index d34154c..9340948 100644
--- a/Modules/Compiler/Cray-C.cmake
+++ b/Modules/Compiler/Cray-C.cmake
@@ -10,11 +10,14 @@
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION  -h noc99,conform)
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION -h noc99,gnu)
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_C99_STANDARD_COMPILE_OPTION  -h c99,conform)
   set(CMAKE_C99_EXTENSION_COMPILE_OPTION -h c99,gnu)
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
   if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.5)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION  -h std=c11,conform)
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION -h std=c11,gnu)
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
   endif ()
 endif ()
 
diff --git a/Modules/Compiler/Cray-CXX.cmake b/Modules/Compiler/Cray-CXX.cmake
index 85a3167..38c8b1e 100644
--- a/Modules/Compiler/Cray-CXX.cmake
+++ b/Modules/Compiler/Cray-CXX.cmake
@@ -10,13 +10,16 @@
 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  -h conform)
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -h gnu)
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.4)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  -h std=c++11)
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -h std=c++11,gnu)
+    set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
   if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.6)
     set(CMAKE_CXX14_STANDARD_COMPILE_OPTION  -h std=c++14)
     set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -h std=c++14,gnu)
+    set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
   endif ()
 endif ()
 
diff --git a/Modules/Compiler/CrayPrgEnv.cmake b/Modules/Compiler/CrayPrgEnv.cmake
index 6c1c770..e55e587 100644
--- a/Modules/Compiler/CrayPrgEnv.cmake
+++ b/Modules/Compiler/CrayPrgEnv.cmake
@@ -1,8 +1,93 @@
 # Guard against multiple inclusions
-if(__craylinux_crayprgenv)
+if(__cmake_craype_crayprgenv)
   return()
 endif()
-set(__craylinux_crayprgenv 1)
+set(__cmake_craype_crayprgenv 1)
+
+# CrayPrgEnv: loaded when compiling through the Cray compiler wrapper.
+# The compiler wrapper can run on a front-end node or a compute node.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW)  # if IN_LIST
+
+# One-time setup of the craype environment.  First, check the wrapper config.
+# The wrapper's selection of a compiler (gcc, clang, intel, etc.) and
+# default include/library paths is selected using the "module" command.
+# The CRAYPE_LINK_TYPE environment variable partly controls if static
+# or dynamic binaries are generated (see __cmake_craype_linktype below).
+# Running cmake and then changing module and/or linktype configuration
+# may cause build problems (since the data in the cmake cache may no
+# longer be correct after the change).  We can look for this and warn
+# the user about it.  Second, use the "module" provided PKG_CONFIG_PATH-like
+# environment variable to add additional prefixes to the system prefix
+# path.
+function(__cmake_craype_setupenv)
+  if(NOT DEFINED __cmake_craype_setupenv_done)  # only done once per run
+    set(__cmake_craype_setupenv_done 1 PARENT_SCOPE)
+    unset(__cmake_check)
+    set(CMAKE_CRAYPE_LINKTYPE "$ENV{CRAYPE_LINK_TYPE}" CACHE STRING
+        "saved value of CRAYPE_LINK_TYPE environment variable")
+    set(CMAKE_CRAYPE_LOADEDMODULES "$ENV{LOADEDMODULES}" CACHE STRING
+        "saved value of LOADEDMODULES environment variable")
+    mark_as_advanced(CMAKE_CRAYPE_LINKTYPE CMAKE_CRAYPE_LOADEDMODULES)
+    if (NOT "${CMAKE_CRAYPE_LINKTYPE}" STREQUAL "$ENV{CRAYPE_LINK_TYPE}")
+      string(APPEND __cmake_check "CRAYPE_LINK_TYPE ")
+    endif()
+    if (NOT "${CMAKE_CRAYPE_LOADEDMODULES}" STREQUAL "$ENV{LOADEDMODULES}")
+      string(APPEND __cmake_check "LOADEDMODULES ")
+    endif()
+    if(DEFINED __cmake_check)
+      message(STATUS "NOTE: ${__cmake_check}changed since initial config!")
+      message(STATUS "NOTE: this may cause unexpected build errors.")
+    endif()
+    # loop over variables of interest
+    foreach(pkgcfgvar PKG_CONFIG_PATH PKG_CONFIG_PATH_DEFAULT
+            PE_PKG_CONFIG_PATH)
+      file(TO_CMAKE_PATH "$ENV{${pkgcfgvar}}" pkgcfg)
+      foreach(path ${pkgcfg})
+        string(REGEX REPLACE "(.*)/lib[^/]*/pkgconfig$" "\\1" path "${path}")
+        if(NOT "${path}" STREQUAL "" AND
+           NOT "${path}" IN_LIST CMAKE_SYSTEM_PREFIX_PATH)
+          list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${path}")
+        endif()
+      endforeach()
+    endforeach()
+    # push it up out of this function into the parent scope
+    set(CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+# The wrapper disables dynamic linking by default.  Dynamic linking is
+# enabled either by setting $ENV{CRAYPE_LINK_TYPE} to "dynamic" or by
+# specifying "-dynamic" to the wrapper when linking.  Specifying "-static"
+# to the wrapper when linking takes priority over $ENV{CRAYPE_LINK_TYPE}.
+# Furthermore, if you specify multiple "-dynamic" and "-static" flags to
+# the wrapper when linking, the last one will win.  In this case, the
+# wrapper will also print a warning like:
+#  Warning: -dynamic was already seen on command line, overriding with -static.
+#
+# note that cmake applies both CMAKE_${lang}_FLAGS and CMAKE_EXE_LINKER_FLAGS
+# (in that order) to the linking command, so -dynamic can appear in either
+# variable.
+function(__cmake_craype_linktype lang rv)
+  # start with ENV, but allow flags to override
+  if("$ENV{CRAYPE_LINK_TYPE}" STREQUAL "dynamic")
+    set(linktype dynamic)
+  else()
+    set(linktype static)
+  endif()
+  # combine flags and convert to a list so we can apply the flags in order
+  set(linkflags "${CMAKE_${lang}_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}")
+  string(REPLACE " " ";" linkflags "${linkflags}")
+  foreach(flag IN LISTS linkflags)
+    if("${flag}" STREQUAL "-dynamic")
+      set(linktype dynamic)
+    elseif("${flag}" STREQUAL "-static")
+      set(linktype static)
+    endif()
+  endforeach()
+  set(${rv} ${linktype} PARENT_SCOPE)
+endfunction()
 
 macro(__CrayPrgEnv_setup lang)
   if(DEFINED ENV{CRAYPE_VERSION})
@@ -13,25 +98,25 @@
     message(STATUS "Cray Programming Environment (unknown version) ${lang}")
   endif()
 
+  # setup the craype environment
+  __cmake_craype_setupenv()
+
   # Flags for the Cray wrappers
   set(CMAKE_STATIC_LIBRARY_LINK_${lang}_FLAGS "-static")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
   set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-dynamic")
 
-  # If the link type is not explicitly specified in the environment then
-  # the Cray wrappers assume that the code will be built statically so
-  # we check the following condition(s) are NOT met
-  #  Compiler flags are explicitly dynamic
-  #  Env var is dynamic and compiler flags are not explicitly static
-  if(NOT (((CMAKE_${lang}_FLAGS MATCHES "(^| )-dynamic($| )") OR
-         (CMAKE_EXE_LINKER_FLAGS MATCHES "(^| )-dynamic($| )"))
-         OR
-         (("$ENV{CRAYPE_LINK_TYPE}" STREQUAL "dynamic") AND
-          NOT ((CMAKE_${lang}_FLAGS MATCHES "(^| )-static($| )") OR
-               (CMAKE_EXE_LINKER_FLAGS MATCHES "(^| )-static($| )")))))
+  # determine linktype from environment and compiler flags
+  __cmake_craype_linktype(${lang} __cmake_craype_${lang}_linktype)
+
+  # switch off shared libs if we get a static linktype
+  if("${__cmake_craype_${lang}_linktype}" STREQUAL "static")
     set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
     set(BUILD_SHARED_LIBS FALSE CACHE BOOL "")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
     set(CMAKE_LINK_SEARCH_START_STATIC TRUE)
   endif()
+
 endmacro()
+
+cmake_policy(POP)
diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake
index f072c54..ca286b3 100644
--- a/Modules/Compiler/GNU-C.cmake
+++ b/Modules/Compiler/GNU-C.cmake
@@ -10,13 +10,16 @@
 endif()
 
 if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
   set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
 endif()
 
 if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+  set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
 elseif (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c1x")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu1x")
diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake
index 0058223..7202607 100644
--- a/Modules/Compiler/GNU-CXX.cmake
+++ b/Modules/Compiler/GNU-CXX.cmake
@@ -19,6 +19,7 @@
 if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
 elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
   # 4.3 supports 0x variants
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
diff --git a/Modules/Compiler/GNU-FindBinUtils.cmake b/Modules/Compiler/GNU-FindBinUtils.cmake
index 16b7bbd..097fbf3 100644
--- a/Modules/Compiler/GNU-FindBinUtils.cmake
+++ b/Modules/Compiler/GNU-FindBinUtils.cmake
@@ -18,7 +18,7 @@
 find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
     "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${__version_x_y}"
     "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${__version_x}"
-    "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar"
+    "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar${_CMAKE_COMPILER_SUFFIX}"
     HINTS ${__gcc_hints}
     DOC "A wrapper around 'ar' adding the appropriate '--plugin' option for the GCC compiler"
 )
@@ -28,7 +28,7 @@
 find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
     "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${__version_x_y}"
     "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${__version_x}"
-    "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib"
+    "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib${_CMAKE_COMPILER_SUFFIX}"
     HINTS ${__gcc_hints}
     DOC "A wrapper around 'ranlib' adding the appropriate '--plugin' option for the GCC compiler"
 )
diff --git a/Modules/Compiler/IAR-ASM.cmake b/Modules/Compiler/IAR-ASM.cmake
index e12bfd1..f9c0ced 100644
--- a/Modules/Compiler/IAR-ASM.cmake
+++ b/Modules/Compiler/IAR-ASM.cmake
@@ -3,21 +3,20 @@
 include(Compiler/IAR)
 
 if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ARM(ASM)
+  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+  __compiler_iar_ilink(ASM)
   set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
 
-  string(APPEND CMAKE_ASM_FLAGS_INIT " ")
-  string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
-  string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
-  string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
-  string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+  __compiler_iar_ilink(ASM)
+  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
 
 elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
   set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_AVR(ASM)
+  __compiler_iar_xlink(ASM)
   set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;asm;msa)
 
 else()
-  message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected as \"AVR\" or \"ARM\".  This should be automatic.")
+  message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
 endif()
diff --git a/Modules/Compiler/IAR-C.cmake b/Modules/Compiler/IAR-C.cmake
index b5e61f0..cb10020 100644
--- a/Modules/Compiler/IAR-C.cmake
+++ b/Modules/Compiler/IAR-C.cmake
@@ -3,44 +3,39 @@
 include(Compiler/IAR)
 include(Compiler/CMakeCommonCompilerMacros)
 
-# The toolchains for ARM and AVR are quite different:
-if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-  if(NOT CMAKE_C_COMPILER_VERSION)
-    message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected.  This should be automatic.")
-  endif()
+# Common
+if(NOT CMAKE_C_COMPILER_VERSION)
+  message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected.  This should be automatic.")
+endif()
 
-  set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
+set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
 
-  set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
-
-  if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.10)
-    set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
-    set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e)
-    set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
-    set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
-  endif()
-  if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.10)
-    set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
-    set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e)
-  endif()
-
-  __compiler_iar_ARM(C)
-  __compiler_check_default_language_standard(C 1.10 90 6.10 99 8.10 11)
-
-elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
-  if(NOT CMAKE_C_COMPILER_VERSION)
-    message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected.  This should be automatic.")
-  endif()
-
-  set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
-
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
-  set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e)
   set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
   set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
+elseif()
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
+endif()
 
-  __compiler_iar_AVR(C)
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
+  set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+# Architecture specific
+if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+  __compiler_iar_ilink(C)
+  __compiler_check_default_language_standard(C 1.10 90 6.10 99 8.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+  __compiler_iar_ilink(C)
+  __compiler_check_default_language_standard(C 1.10 90 2.10 99 4.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
+  __compiler_iar_xlink(C)
   __compiler_check_default_language_standard(C 7.10 99)
   set(CMAKE_C_OUTPUT_EXTENSION ".r90")
 
@@ -48,9 +43,6 @@
     set(CMAKE_C_LINK_FLAGS "-Fmotorola")
   endif()
 
-  set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
-  set(CMAKE_C_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <OBJECTS> ")
-
   # add the target specific include directory:
   get_filename_component(_compilerDir "${CMAKE_C_COMPILER}" PATH)
   get_filename_component(_compilerDir "${_compilerDir}" PATH)
@@ -58,5 +50,5 @@
   include_directories("${_compilerDir}/inc/Atmel" )
 
 else()
-  message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected as \"AVR\" or \"ARM\".  This should be automatic.")
+  message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
 endif()
diff --git a/Modules/Compiler/IAR-CXX.cmake b/Modules/Compiler/IAR-CXX.cmake
index b7076f5..eb27e3c 100644
--- a/Modules/Compiler/IAR-CXX.cmake
+++ b/Modules/Compiler/IAR-CXX.cmake
@@ -3,60 +3,45 @@
 include(Compiler/IAR)
 include(Compiler/CMakeCommonCompilerMacros)
 
-if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-  # "(extended) embedded C++" Mode
-  # old version: --ec++ or --eec++
-  # since 8.10:  --c++ --no_exceptions --no_rtti
-  #
-  # --c++ is full C++ and supported since 6.10
-  if(NOT CMAKE_IAR_CXX_FLAG)
-    if(NOT CMAKE_CXX_COMPILER_VERSION)
-      message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected.  This should be automatic.")
-    endif()
-    if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.10)
-      set(CMAKE_IAR_CXX_FLAG --c++)
-    else()
-      set(CMAKE_IAR_CXX_FLAG --eec++)
-    endif()
+# Common
+if(NOT CMAKE_IAR_CXX_FLAG)
+  if(NOT CMAKE_CXX_COMPILER_VERSION)
+    message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.")
   endif()
+  if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
+    set(CMAKE_IAR_CXX_FLAG --c++)
+  else()
+    set(CMAKE_IAR_CXX_FLAG --eec++)
+  endif()
+endif()
 
-  set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
+set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
 
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -e)
-
-  if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.10)
   set(CMAKE_CXX03_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX03_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -e)
   set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -e)
-  endif()
+endif()
 
-  __compiler_iar_ARM(CXX)
+# Architecture specific
+if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+  __compiler_iar_ilink(CXX)
   __compiler_check_default_language_standard(CXX 6.10 98 8.10 14)
 
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+  __compiler_iar_ilink(CXX)
+  __compiler_check_default_language_standard(CXX 2.10 98 4.10 14)
+
 elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
-  # "embedded C++" --EC++ is probably closest to CXX98 but with no support for:
-  #  Templates, multiple inheritance, virtual inheritance, exceptions, RTTI, C++ style casts,
-  #  Namespaces, the mutable attribute, no STL, any library features related to the above features.
-  #
-  # "(extended) embedded C++" --EEC++ Mode but DOES NOT support any normal C++ standard
-  # probably closest to CXX98 but with no RTTI and no exceptions, and the library
-  # provided is not in the standard namespace
-  if(NOT CMAKE_IAR_CXX_FLAG)
-    if(NOT CMAKE_CXX_COMPILER_VERSION)
-      message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected.  This should be automatic.")
-    endif()
-    set(CMAKE_IAR_CXX_FLAG --eec++)
-  endif()
-
-  set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
-  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -e)
-
-  __compiler_iar_AVR(CXX)
+  __compiler_iar_xlink(CXX)
   __compiler_check_default_language_standard(CXX 7.10 98)
 
   set(CMAKE_CXX_OUTPUT_EXTENSION ".r90")
@@ -64,15 +49,12 @@
     set(CMAKE_CXX_LINK_FLAGS "-Fmotorola")
   endif()
 
-  set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <OBJECTS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
-  set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <OBJECTS> ")
-
   # add the target specific include directory:
   get_filename_component(_compilerDir "${CMAKE_C_COMPILER}" PATH)
   get_filename_component(_compilerDir "${_compilerDir}" PATH)
-  include_directories("${_compilerDir}/inc")
-  include_directories("${_compilerDir}/inc/Atmel")
+  include_directories("${_compilerDir}/inc" )
+  include_directories("${_compilerDir}/inc/Atmel" )
 
 else()
-  message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected as \"AVR\" or \"ARM\".  This should be automatic." )
+  message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected. This should be automatic." )
 endif()
diff --git a/Modules/Compiler/IAR-DetermineCompiler.cmake b/Modules/Compiler/IAR-DetermineCompiler.cmake
index 43477ac..cdfb095 100644
--- a/Modules/Compiler/IAR-DetermineCompiler.cmake
+++ b/Modules/Compiler/IAR-DetermineCompiler.cmake
@@ -31,7 +31,7 @@
 #  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(((__VER__) / 1000) % 1000)
 #  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@((__VER__) % 1000)
 #  define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__IAR_SYSTEMS_ICC__)
-# elif defined(__VER__) && defined(__ICCAVR__)
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__))
 #  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@((__VER__) / 100)
 #  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@((__VER__) - (((__VER__) / 100)*100))
 #  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__SUBVERSION__)
diff --git a/Modules/Compiler/IAR-FindBinUtils.cmake b/Modules/Compiler/IAR-FindBinUtils.cmake
index 5fecb26..e8f5e6b 100644
--- a/Modules/Compiler/IAR-FindBinUtils.cmake
+++ b/Modules/Compiler/IAR-FindBinUtils.cmake
@@ -10,39 +10,39 @@
 
 set(__iar_hints "${__iar_hint_1}" "${__iar_hint_2}")
 
-if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-  # could allow using normal binutils ar, since objects are normal ELF files?
-  find_program(CMAKE_IAR_LINKARM ilinkarm.exe HINTS ${__iar_hints}
-      DOC "The IAR ARM linker")
+if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM" OR
+   "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+   # could allow using normal binutils ar, since objects are normal ELF files?
+  find_program(CMAKE_IAR_LINKER ilink${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}.exe HINTS ${__iar_hints}
+      DOC "The IAR ILINK linker")
   find_program(CMAKE_IAR_ARCHIVE iarchive.exe HINTS ${__iar_hints}
       DOC "The IAR archiver")
 
   # find auxiliary tools
   find_program(CMAKE_IAR_ELFTOOL ielftool.exe HINTS ${__iar_hints}
       DOC "The IAR ELF Tool")
-    find_program(CMAKE_IAR_ELFDUMP ielfdumparm.exe HINTS ${__iar_hints}
+    find_program(CMAKE_IAR_ELFDUMP ielfdump${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}.exe HINTS ${__iar_hints}
       DOC "The IAR ELF Dumper")
   find_program(CMAKE_IAR_OBJMANIP iobjmanip.exe HINTS ${__iar_hints}
       DOC "The IAR ELF Object Tool")
   find_program(CMAKE_IAR_SYMEXPORT isymexport.exe HINTS ${__iar_hints}
       DOC "The IAR Absolute Symbol Exporter")
-  mark_as_advanced(CMAKE_IAR_LINKARM CMAKE_IAR_ARCHIVE CMAKE_IAR_ELFTOOL CMAKE_IAR_ELFDUMP CMAKE_IAR_OBJMANIP CMAKE_IAR_SYMEXPORT)
+  mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_ARCHIVE CMAKE_IAR_ELFTOOL CMAKE_IAR_ELFDUMP CMAKE_IAR_OBJMANIP CMAKE_IAR_SYMEXPORT)
 
   set(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_CUSTOM_CODE
-"set(CMAKE_IAR_LINKARM \"${CMAKE_IAR_LINKARM}\")
+"set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
 set(CMAKE_IAR_ARCHIVE \"${CMAKE_IAR_ARCHIVE}\")
 set(CMAKE_IAR_ELFTOOL \"${CMAKE_IAR_ELFTOOL}\")
 set(CMAKE_IAR_ELFDUMP \"${CMAKE_IAR_ELFDUMP}\")
 set(CMAKE_IAR_OBJMANIP \"${CMAKE_IAR_OBJMANIP}\")
-set(CMAKE_IAR_LINKARM \"${CMAKE_IAR_LINKARM}\")
+set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
 ")
 
-
 elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
 
   # For AVR and AVR32, IAR uses the "xlink" linker and the "xar" archiver:
   find_program(CMAKE_IAR_LINKER xlink.exe HINTS ${__iar_hints}
-      DOC "The IAR AVR linker")
+      DOC "The IAR XLINK linker")
   find_program(CMAKE_IAR_AR xar.exe HINTS ${__iar_hints}
       DOC "The IAR archiver")
   mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_AR)
diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake
index bbcdea2..8e75caa 100644
--- a/Modules/Compiler/IAR.cmake
+++ b/Modules/Compiler/IAR.cmake
@@ -2,11 +2,16 @@
 # Documentation can be downloaded here: http://www.iar.com/website1/1.0.1.0/675/1/
 # The initial feature request is here: https://gitlab.kitware.com/cmake/cmake/issues/10176
 # It also contains additional links and information.
-# See USER GUIDES -> C/C++ Development Guide and ReleaseNotes for:
+# See USER GUIDES -> C/C++ Development Guide and ReleaseNotes for EWARM:
 # version 6.30.8: http://supp.iar.com/FilesPublic/UPDINFO/006607/arm/doc/infocenter/index.ENU.html
 # version 7.60.1: http://supp.iar.com/FilesPublic/UPDINFO/011006/arm/doc/infocenter/index.ENU.html
 # version 8.10.1: http://netstorage.iar.com/SuppDB/Public/UPDINFO/011854/arm/doc/infocenter/index.ENU.html
 
+# The IAR internal compiler platform generations (Predefined symbol __IAR_SYSTEMS_ICC__):
+#  9 and higher means C11 and C++14 as language default (EWARM v8.x, EWRX v4.x and higher)
+#  8 means C99 and C++03 as language default (EWARM v6.x, v7.x. EWRX v2.x, 3.x)
+#  7 and lower means C89 and EC++ as language default. (EWARM v5.x and lower)
+
 # C/C++ Standard versions
 #
 # IAR typically only supports one C and C++ Standard version,
@@ -33,14 +38,46 @@
 # code and data size printouts (that can be inspected with common tools).
 
 # This module is shared by multiple languages; use include blocker.
-if(_IARARM_CMAKE_LOADED)
-  return()
-endif()
-set(_IARARM_CMAKE_LOADED 1)
+include_guard()
 
-macro(__compiler_iar_ARM lang)
+macro(__compiler_iar_ilink lang)
   set(CMAKE_EXECUTABLE_SUFFIX ".elf")
   if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
+    set(CMAKE_${lang}_COMPILE_OBJECT             "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+    set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>")
+    set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
+
+    set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
+    set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEPFILE>")
+
+    string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+    string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r")
+    string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG")
+    string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Oh -DNDEBUG")
+    string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
+  endif()
+
+  if (${lang} STREQUAL "ASM")
+    string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+    string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+    string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+    string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+    string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+  endif()
+
+  set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKER}\" --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
+  set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_CREATE "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_APPEND "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --replace <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_FINISH "")
+
+  set(CMAKE_LINKER "${CMAKE_IAR_LINKER}" CACHE FILEPATH "The IAR linker" FORCE)
+  set(CMAKE_AR "${CMAKE_IAR_ARCHIVE}" CACHE FILEPATH "The IAR archiver" FORCE)
+endmacro()
+
+macro(__compiler_iar_xlink lang)
+  set(CMAKE_EXECUTABLE_SUFFIX ".bin")
+  if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
 
     set(CMAKE_${lang}_COMPILE_OBJECT             "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
     set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>")
@@ -56,32 +93,12 @@
     string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
   endif()
 
-  set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKARM}\" --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
-  set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
-  set(CMAKE_${lang}_ARCHIVE_CREATE "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
-  set(CMAKE_${lang}_ARCHIVE_APPEND "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --replace <LINK_FLAGS> <OBJECTS>")
-  set(CMAKE_${lang}_ARCHIVE_FINISH "")
-
-  set(CMAKE_LINKER "${CMAKE_IAR_LINKARM}" CACHE FILEPATH "The IAR linker" FORCE)
-  set(CMAKE_AR "${CMAKE_IAR_ARCHIVE}" CACHE FILEPATH "The IAR archiver" FORCE)
-endmacro()
-
-macro(__compiler_iar_AVR lang)
-  set(CMAKE_EXECUTABLE_SUFFIX ".bin")
-  if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
-
-    set(CMAKE_${lang}_COMPILE_OBJECT             "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-    set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>")
-    set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
-
-    set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
-    set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEPFILE>")
-
-    string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
-    string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r")
-    string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG")
-    string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Oh -DNDEBUG")
-    string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
+  if (${lang} STREQUAL "ASM")
+    string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+    string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+    string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+    string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+    string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
   endif()
 
   set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKER}\" -S <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
diff --git a/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake b/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
index e5b9741..899e284 100644
--- a/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
+++ b/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
@@ -1,14 +1,6 @@
 
 set(_compiler_id_version_compute "
-# if defined(__ibmxl__)
-#  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
-#  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
-#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
-#  define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
-# else
-   /* __IBMC__ = VRP */
-#  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMC__/100)
-#  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMC__/10 % 10)
-#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMC__    % 10)
-# endif
-")
+  /* __IBMC__ = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMC__/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMC__/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMC__    % 10)")
diff --git a/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake b/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
index 63c3e32..73aa2b4 100644
--- a/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
+++ b/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
@@ -1,14 +1,6 @@
 
 set(_compiler_id_version_compute "
-# if defined(__ibmxl__)
-#  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
-#  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
-#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
-#  define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
-# else
-   /* __IBMCPP__ = VRP */
-#  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMCPP__/100)
-#  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMCPP__/10 % 10)
-#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMCPP__    % 10)
-# endif
-")
+  /* __IBMCPP__ = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMCPP__/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMCPP__/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMCPP__    % 10)")
diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake
index 4e4af29..e9e59a2 100644
--- a/Modules/Compiler/Intel-C.cmake
+++ b/Modules/Compiler/Intel-C.cmake
@@ -12,13 +12,16 @@
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-Qstd=c11")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-Qstd=c11")
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0)
     set(CMAKE_C90_STANDARD_COMPILE_OPTION "-Qstd=c89")
     set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-Qstd=c89")
+    set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
     set(CMAKE_C99_STANDARD_COMPILE_OPTION "-Qstd=c99")
     set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-Qstd=c99")
+    set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
 else()
@@ -26,13 +29,16 @@
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0)
     set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
     set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
+    set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
     set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
     set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+    set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
 endif()
diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake
index c115b6a..471dd4a 100644
--- a/Modules/Compiler/Intel-CXX.cmake
+++ b/Modules/Compiler/Intel-CXX.cmake
@@ -30,6 +30,7 @@
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
     set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
     set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+    set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
 else()
@@ -64,6 +65,7 @@
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
     set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
     set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+    set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
 endif()
diff --git a/Modules/Compiler/MIPSpro-C.cmake b/Modules/Compiler/MIPSpro-C.cmake
deleted file mode 100644
index 675560c..0000000
--- a/Modules/Compiler/MIPSpro-C.cmake
+++ /dev/null
@@ -1 +0,0 @@
-set(CMAKE_C_VERBOSE_FLAG "-v")
diff --git a/Modules/Compiler/MIPSpro-CXX.cmake b/Modules/Compiler/MIPSpro-CXX.cmake
deleted file mode 100644
index 9fb191c..0000000
--- a/Modules/Compiler/MIPSpro-CXX.cmake
+++ /dev/null
@@ -1 +0,0 @@
-set(CMAKE_CXX_VERBOSE_FLAG "-v")
diff --git a/Modules/Compiler/MIPSpro-DetermineCompiler.cmake b/Modules/Compiler/MIPSpro-DetermineCompiler.cmake
deleted file mode 100644
index 9e48553..0000000
--- a/Modules/Compiler/MIPSpro-DetermineCompiler.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-
-set(_compiler_id_pp_test "defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION)")
-
-set(_compiler_id_version_compute "
-# if defined(_SGI_COMPILER_VERSION)
-  /* _SGI_COMPILER_VERSION = VRP */
-#  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_SGI_COMPILER_VERSION/100)
-#  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_SGI_COMPILER_VERSION/10 % 10)
-#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(_SGI_COMPILER_VERSION    % 10)
-# else
-  /* _COMPILER_VERSION = VRP */
-#  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_COMPILER_VERSION/100)
-#  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_COMPILER_VERSION/10 % 10)
-#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(_COMPILER_VERSION    % 10)
-# endif")
diff --git a/Modules/Compiler/MIPSpro-Fortran.cmake b/Modules/Compiler/MIPSpro-Fortran.cmake
deleted file mode 100644
index ffceea8..0000000
--- a/Modules/Compiler/MIPSpro-Fortran.cmake
+++ /dev/null
@@ -1,3 +0,0 @@
-set(CMAKE_Fortran_VERBOSE_FLAG "-v")
-set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixedform")
-set(CMAKE_Fortran_FORMAT_FREE_FLAG "-freeform")
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index be259ff..691926f 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -11,6 +11,7 @@
   # with the default and minimum level being C++14.
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
   set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
diff --git a/Modules/Compiler/PGI-C.cmake b/Modules/Compiler/PGI-C.cmake
index 3b3848a..c39dbe5 100644
--- a/Modules/Compiler/PGI-C.cmake
+++ b/Modules/Compiler/PGI-C.cmake
@@ -6,11 +6,14 @@
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION -c89)
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION -c89)
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_C99_STANDARD_COMPILE_OPTION -c99)
   set(CMAKE_C99_EXTENSION_COMPILE_OPTION -c99)
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
   if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.3)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION -c11)
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION -c11)
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
   endif ()
 endif ()
 
diff --git a/Modules/Compiler/PGI-CXX.cmake b/Modules/Compiler/PGI-CXX.cmake
index 35076bb..c77de36 100644
--- a/Modules/Compiler/PGI-CXX.cmake
+++ b/Modules/Compiler/PGI-CXX.cmake
@@ -6,15 +6,19 @@
 if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  -A)
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION --gnu_extensions)
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.10)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  --c++11 -A)
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION --c++11 --gnu_extensions)
+    set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
     if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.7)
       set(CMAKE_CXX14_STANDARD_COMPILE_OPTION  --c++14 -A)
       set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION --c++14 --gnu_extensions)
+      set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
       if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.1)
         set(CMAKE_CXX17_STANDARD_COMPILE_OPTION  --c++17 -A)
         set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION --c++17 --gnu_extensions)
+        set(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT ON)
       endif()
     endif()
   endif()
diff --git a/Modules/Compiler/SunPro-C.cmake b/Modules/Compiler/SunPro-C.cmake
index c4aba8e..7e962b8 100644
--- a/Modules/Compiler/SunPro-C.cmake
+++ b/Modules/Compiler/SunPro-C.cmake
@@ -39,10 +39,13 @@
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.13)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=c89")
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
   set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=c99")
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=c11")
+  set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
 elseif (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.11)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake
index 5ce58b2..c2f6d1d 100644
--- a/Modules/Compiler/SunPro-CXX.cmake
+++ b/Modules/Compiler/SunPro-CXX.cmake
@@ -48,6 +48,7 @@
 if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++03")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=c++03")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX_LINK_WITH_STANDARD_COMPILE_OPTION 1)
diff --git a/Modules/Compiler/XL-C-DetermineCompiler.cmake b/Modules/Compiler/XL-C-DetermineCompiler.cmake
index 484811e..3f4e05c 100644
--- a/Modules/Compiler/XL-C-DetermineCompiler.cmake
+++ b/Modules/Compiler/XL-C-DetermineCompiler.cmake
@@ -1,4 +1,4 @@
 
-set(_compiler_id_pp_test "defined(__ibmxl__) || (defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800)")
+set(_compiler_id_pp_test "defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800")
 
 include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-C-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/XL-C.cmake b/Modules/Compiler/XL-C.cmake
index 5dc8bc1..2077bda 100644
--- a/Modules/Compiler/XL-C.cmake
+++ b/Modules/Compiler/XL-C.cmake
@@ -6,36 +6,18 @@
 # -qthreaded = Ensures that all optimizations will be thread-safe
 string(APPEND CMAKE_C_FLAGS_INIT " -qthreaded")
 
-# XL v13.1.1 for Linux ppc64 little-endian switched to using a clang based
-# front end and accepts the -std= option while only reserving -qlanglevel= for
-# compatibility.  All other versions (previous versions on Linux ppc64
-# little-endian, all versions on Linux ppc64 big-endian, all versions on AIX
-# and BGQ, etc) are derived from the UNIX compiler and only accept the
-# -qlanglvl option.
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.1)
-  if (CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND
-      CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
-    set(CMAKE_C90_STANDARD_COMPILE_OPTION  "-std=c89")
-    set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
-    set(CMAKE_C99_STANDARD_COMPILE_OPTION  "-std=c99")
-    set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
-    if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
-      set(CMAKE_C11_STANDARD_COMPILE_OPTION  "-std=c11")
-      set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
-    else ()
-      set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
-      set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
-    endif ()
-  else ()
-    set(CMAKE_C90_STANDARD_COMPILE_OPTION "-qlanglvl=stdc89")
-    set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-qlanglvl=extc89")
-    set(CMAKE_C99_STANDARD_COMPILE_OPTION "-qlanglvl=stdc99")
-    set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-qlanglvl=extc99")
-    if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1)
-      set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
-      set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
-    endif ()
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION "-qlanglvl=stdc89")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-qlanglvl=extc89")
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+  set(CMAKE_C99_STANDARD_COMPILE_OPTION "-qlanglvl=stdc99")
+  set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-qlanglvl=extc99")
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+  if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1)
+    set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
+    set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
   endif ()
 endif()
 
-__compiler_check_default_language_standard(C 10.1 90)
+__compiler_check_default_language_standard(C 10.1 90 11.1 99)
diff --git a/Modules/Compiler/XL-CXX-DetermineCompiler.cmake b/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
index 2bf1ec6..dffa4bc 100644
--- a/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
+++ b/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
@@ -1,4 +1,4 @@
 
-set(_compiler_id_pp_test "defined(__ibmxl__) || (defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800)")
+set(_compiler_id_pp_test "defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800")
 
 include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-CXX-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/XL-CXX.cmake b/Modules/Compiler/XL-CXX.cmake
index b87e923..ec3f1f8 100644
--- a/Modules/Compiler/XL-CXX.cmake
+++ b/Modules/Compiler/XL-CXX.cmake
@@ -6,41 +6,18 @@
 # -qthreaded = Ensures that all optimizations will be thread-safe
 string(APPEND CMAKE_CXX_FLAGS_INIT " -qthreaded")
 
-# XL v13.1.1 for Linux ppc64 little-endian switched to using a clang based
-# front end and accepts the -std= option while only reserving -qlanglevel= for
-# compatibility.  All other versions (previous versions on Linux ppc64
-# little-endian, all versions on Linux ppc64 big-endian, all versions on AIX
-# and BGQ, etc) are derived from the UNIX compiler and only accept the
-# -qlanglvl option.
 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.1)
-  if (CMAKE_SYSTEM MATCHES "Linux.*ppc64")
-    if (CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND
-        CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
-      set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
-      set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
-      if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
-        set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
-        set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
-        set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
-        set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-qlanglvl=extended1y")
-      else ()
-        set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
-        set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
-      endif ()
-    else ()
-      # The non-clang based Linux ppc64 compiler, both big-endian and
-      # little-endian lacks, the non-extension language level flags
-      set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-qlanglvl=extended")
-      set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-qlanglvl=extended")
-      set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
-      set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
-    endif ()
-  else ()
+  if(CMAKE_SYSTEM MATCHES "Linux")
+    set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+    set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+  else()
     set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-qlanglvl=strict98")
     set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-qlanglvl=extended")
-    set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
-    set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
-  endif ()
+  endif()
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+  set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
 endif ()
 
 __compiler_check_default_language_standard(CXX 10.1 98)
diff --git a/Modules/Compiler/XL.cmake b/Modules/Compiler/XL.cmake
index 68dc28a..a9cec11 100644
--- a/Modules/Compiler/XL.cmake
+++ b/Modules/Compiler/XL.cmake
@@ -10,12 +10,6 @@
 
 include(Compiler/CMakeCommonCompilerMacros)
 
-# Find the CreateExportList program that comes with this toolchain.
-find_program(CMAKE_XL_CreateExportList
-  NAMES CreateExportList
-  DOC "IBM XL CreateExportList tool"
-  )
-
 macro(__compiler_xl lang)
   # Feature flags.
   set(CMAKE_${lang}_VERBOSE_FLAG "-V")
@@ -35,20 +29,4 @@
   set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 
   set(CMAKE_DEPFILE_FLAGS_${lang} "-MF <DEPFILE> -qmakedep=gcc")
-
-  # CMAKE_XL_CreateExportList is part of the AIX XL compilers but not the linux ones.
-  # If we found the tool, we'll use it to create exports, otherwise stick with the regular
-  # create shared library compile line.
-  if (CMAKE_XL_CreateExportList)
-    # The compiler front-end passes all object files, archive files, and shared
-    # library files named on the command line to CreateExportList to create a
-    # list of all symbols to be exported from the shared library.  This causes
-    # all archive members to be copied into the shared library whether they are
-    # needed or not.  Instead we run the tool ourselves to pass only the object
-    # files so that we export only the symbols actually provided by the sources.
-    set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-      "${CMAKE_XL_CreateExportList} <OBJECT_DIR>/objects.exp <OBJECTS>"
-      "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
-      )
-  endif()
 endmacro()
diff --git a/Modules/Compiler/XLClang-C-DetermineCompiler.cmake b/Modules/Compiler/XLClang-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..4d89921
--- /dev/null
+++ b/Modules/Compiler/XLClang-C-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+set(_compiler_id_pp_test "defined(__ibmxl__) && defined(__clang__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
+")
diff --git a/Modules/Compiler/XLClang-C.cmake b/Modules/Compiler/XLClang-C.cmake
new file mode 100644
index 0000000..54c18a6
--- /dev/null
+++ b/Modules/Compiler/XLClang-C.cmake
@@ -0,0 +1,20 @@
+include(Compiler/XLClang)
+__compiler_xlclang(C)
+
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION  "-std=c89")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+  set(CMAKE_C99_STANDARD_COMPILE_OPTION  "-std=c99")
+  set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+  set(CMAKE_C11_STANDARD_COMPILE_OPTION  "-qlanglvl=extc1x")
+  set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
+  if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
+    set(CMAKE_C11_STANDARD_COMPILE_OPTION  "-std=c11")
+    set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+  endif ()
+endif()
+
+__compiler_check_default_language_standard(C 13.1.1 99)
diff --git a/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake b/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..4d89921
--- /dev/null
+++ b/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+set(_compiler_id_pp_test "defined(__ibmxl__) && defined(__clang__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
+")
diff --git a/Modules/Compiler/XLClang-CXX.cmake b/Modules/Compiler/XLClang-CXX.cmake
new file mode 100644
index 0000000..03c7c7b
--- /dev/null
+++ b/Modules/Compiler/XLClang-CXX.cmake
@@ -0,0 +1,23 @@
+include(Compiler/XLClang)
+__compiler_xlclang(CXX)
+
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
+  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  "")
+  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  "-qlanglvl=extended0x")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
+  set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+  if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
+    set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  "-std=c++11")
+    set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+    set(CMAKE_CXX14_STANDARD_COMPILE_OPTION  "-std=c++1y")
+    set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+    set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+  endif ()
+endif()
+
+__compiler_check_default_language_standard(CXX 13.1.1 98)
+
+set(CMAKE_CXX_COMPILE_OBJECT
+  "<CMAKE_CXX_COMPILER> -x c++ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
diff --git a/Modules/Compiler/XLClang.cmake b/Modules/Compiler/XLClang.cmake
new file mode 100644
index 0000000..cdf0fdc
--- /dev/null
+++ b/Modules/Compiler/XLClang.cmake
@@ -0,0 +1,22 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_XLCLANG)
+  return()
+endif()
+set(__COMPILER_XLCLANG 1)
+
+include(Compiler/XL)
+
+macro(__compiler_xlclang lang)
+  __compiler_xl(${lang})
+
+  # Feature flags.
+  set(CMAKE_${lang}_VERBOSE_FLAG "-V")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIC")
+  set(CMAKE_${lang}_RESPONSE_FILE_FLAG "@")
+  set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "@")
+endmacro()
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 22e0523..20b37d2 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -202,23 +202,24 @@
         :command:`file(DOWNLOAD)`)
 
       ``NETRC <level>``
-        Specify whether the .netrc file is to be used for operation. If this
-        option is not specified, the value of the ``CMAKE_NETRC`` variable
-        will be used instead (see :command:`file(DOWNLOAD)`)
+        Specify whether the ``.netrc`` file is to be used for operation.
+        If this option is not specified, the value of the ``CMAKE_NETRC``
+        variable will be used instead (see :command:`file(DOWNLOAD)`)
         Valid levels are:
 
         ``IGNORED``
-          The .netrc file is ignored.
+          The ``.netrc`` file is ignored.
           This is the default.
         ``OPTIONAL``
-          The .netrc file is optional, and information in the URL is preferred.
-          The file will be scanned to find which ever information is not specified
-          in the URL.
+          The ``.netrc`` file is optional, and information in the URL
+          is preferred.  The file will be scanned to find which ever
+          information is not specified in the URL.
         ``REQUIRED``
-          The .netrc file is required, and information in the URL is ignored.
+          The ``.netrc`` file is required, and information in the URL
+          is ignored.
 
       ``NETRC_FILE <file>``
-        Specify an alternative .netrc file to the one in your home directory
+        Specify an alternative ``.netrc`` file to the one in your home directory
         if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
         is not specified, the value of the ``CMAKE_NETRC_FILE`` variable will
         be used instead (see :command:`file(DOWNLOAD)`)
@@ -251,6 +252,9 @@
           The lack of such deterministic behavior makes the main project lose
           traceability and repeatability.
 
+        If ``GIT_SHALLOW`` is enabled then ``GIT_TAG`` works only with
+        branch names and tags.  A commit hash is not allowed.
+
       ``GIT_REMOTE_NAME <name>``
         The optional name of the remote. If this option is not specified, it
         defaults to ``origin``.
@@ -418,6 +422,10 @@
       different behavior depending on whether the build starts from a fresh
       build directory or re-uses previous build contents.
 
+      If the CMake generator is the ``Green Hills MULTI`` and not overridden then
+      the orginal projects settings for the GHS toolset and target system
+      customization cache variables are propagated into the external project.
+
     ``SOURCE_SUBDIR <dir>``
       When no ``CONFIGURE_COMMAND`` option is specified, the configure step
       assumes the external project has a ``CMakeLists.txt`` file at the top of
@@ -1053,11 +1061,6 @@
   )
 
 function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
-  if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
-    set(git_clone_shallow_options "--depth 1 --no-single-branch")
-  else()
-    set(git_clone_shallow_options "--depth 1")
-  endif()
   if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
     # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
     set(git_checkout_explicit-- "--")
@@ -1067,18 +1070,41 @@
     # because that will not search for remote branch names, a common use case.
     set(git_checkout_explicit-- "")
   endif()
+  if("${git_tag}" STREQUAL "")
+    message(FATAL_ERROR "Tag for git checkout should not be empty.")
+  endif()
+
+  set(git_clone_options)
+  if(git_shallow)
+    if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
+      list(APPEND git_clone_options "--depth 1 --no-single-branch")
+    else()
+      list(APPEND git_clone_options "--depth 1")
+    endif()
+  endif()
+  if(git_progress)
+    list(APPEND git_clone_options --progress)
+  endif()
+  foreach(config IN LISTS git_config)
+    list(APPEND git_clone_options --config ${config})
+  endforeach()
+  if(NOT ${git_remote_name} STREQUAL "origin")
+    list(APPEND git_clone_options --origin \"${git_remote_name}\")
+  endif()
+
+  string (REPLACE ";" " " git_clone_options "${git_clone_options}")
+
+  set(git_options)
+  # disable cert checking if explicitly told not to do it
+  if(NOT "x${tls_verify}" STREQUAL "x" AND NOT tls_verify)
+    set(git_options
+      -c http.sslVerify=false)
+  endif()
+  string (REPLACE ";" " " git_options "${git_options}")
+
   file(WRITE ${script_filename}
-"if(\"${git_tag}\" STREQUAL \"\")
-  message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
-endif()
-
-set(run 0)
-
-if(\"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
-  set(run 1)
-endif()
-
-if(NOT run)
+"
+if(NOT \"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
   message(STATUS \"Avoiding repeated git clone, stamp file is up to date: '${gitclone_stampfile}'\")
   return()
 endif()
@@ -1091,38 +1117,12 @@
   message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
 endif()
 
-set(git_options)
-
-# disable cert checking if explicitly told not to do it
-set(tls_verify \"${tls_verify}\")
-if(NOT \"x${tls_verify}\" STREQUAL \"x\" AND NOT tls_verify)
-  list(APPEND git_options
-    -c http.sslVerify=false)
-endif()
-
-set(git_clone_options)
-
-set(git_shallow \"${git_shallow}\")
-if(git_shallow)
-  list(APPEND git_clone_options ${git_clone_shallow_options})
-endif()
-
-set(git_progress \"${git_progress}\")
-if(git_progress)
-  list(APPEND git_clone_options --progress)
-endif()
-
-set(git_config \"${git_config}\")
-foreach(config IN LISTS git_config)
-  list(APPEND git_clone_options --config \${config})
-endforeach()
-
 # try the clone 3 times in case there is an odd git clone issue
 set(error_code 1)
 set(number_of_tries 0)
 while(error_code AND number_of_tries LESS 3)
   execute_process(
-    COMMAND \"${git_EXECUTABLE}\" \${git_options} clone \${git_clone_options} --origin \"${git_remote_name}\" \"${git_repository}\" \"${src_name}\"
+    COMMAND \"${git_EXECUTABLE}\" ${git_options} clone ${git_clone_options} \"${git_repository}\" \"${src_name}\"
     WORKING_DIRECTORY \"${work_dir}\"
     RESULT_VARIABLE error_code
     )
@@ -1137,7 +1137,7 @@
 endif()
 
 execute_process(
-  COMMAND \"${git_EXECUTABLE}\" \${git_options} checkout ${git_tag} ${git_checkout_explicit--}
+  COMMAND \"${git_EXECUTABLE}\" ${git_options} checkout ${git_tag} ${git_checkout_explicit--}
   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
   RESULT_VARIABLE error_code
   )
@@ -1146,16 +1146,7 @@
 endif()
 
 execute_process(
-  COMMAND \"${git_EXECUTABLE}\" \${git_options} submodule init ${git_submodules}
-  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
-  RESULT_VARIABLE error_code
-  )
-if(error_code)
-  message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\")
-endif()
-
-execute_process(
-  COMMAND \"${git_EXECUTABLE}\" \${git_options} submodule update --recursive --init ${git_submodules}
+  COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update --recursive --init ${git_submodules}
   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
   RESULT_VARIABLE error_code
   )
@@ -1169,7 +1160,6 @@
   COMMAND \${CMAKE_COMMAND} -E copy
     \"${gitclone_infofile}\"
     \"${gitclone_stampfile}\"
-  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
   RESULT_VARIABLE error_code
   )
 if(error_code)
@@ -1182,18 +1172,12 @@
 endfunction()
 
 function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile)
+  if("${hg_tag}" STREQUAL "")
+    message(FATAL_ERROR "Tag for hg checkout should not be empty.")
+  endif()
   file(WRITE ${script_filename}
-"if(\"${hg_tag}\" STREQUAL \"\")
-  message(FATAL_ERROR \"Tag for hg checkout should not be empty.\")
-endif()
-
-set(run 0)
-
-if(\"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
-  set(run 1)
-endif()
-
-if(NOT run)
+"
+if(NOT \"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
   message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\")
   return()
 endif()
@@ -1230,7 +1214,6 @@
   COMMAND \${CMAKE_COMMAND} -E copy
     \"${hgclone_infofile}\"
     \"${hgclone_stampfile}\"
-  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
   RESULT_VARIABLE error_code
   )
 if(error_code)
@@ -1244,16 +1227,16 @@
 
 
 function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name git_submodules git_repository work_dir)
+  if("${git_tag}" STREQUAL "")
+    message(FATAL_ERROR "Tag for git checkout should not be empty.")
+  endif()
   if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.6)
     set(git_stash_save_options --all --quiet)
   else()
     set(git_stash_save_options --quiet)
   endif()
   file(WRITE ${script_filename}
-"if(\"${git_tag}\" STREQUAL \"\")
-  message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
-endif()
-
+"
 execute_process(
   COMMAND \"${git_EXECUTABLE}\" rev-list --max-count=1 HEAD
   WORKING_DIRECTORY \"${work_dir}\"
@@ -2460,7 +2443,7 @@
     #
     set(repository ${git_repository})
     set(module)
-    set(tag)
+    set(tag ${git_remote_name})
     configure_file(
       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
       "${stamp_dir}/${name}-gitinfo.txt"
@@ -2871,18 +2854,6 @@
       set(has_cmake_cache_default_args 1)
     endif()
 
-    if(has_cmake_cache_args OR has_cmake_cache_default_args)
-      set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
-      if(has_cmake_cache_args)
-        _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
-      endif()
-      if(has_cmake_cache_default_args)
-        _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
-      endif()
-      _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
-      list(APPEND cmd "-C${_ep_cache_args_script}")
-    endif()
-
     get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
     get_target_property(cmake_generator_instance ${name} _EP_CMAKE_GENERATOR_INSTANCE)
     get_target_property(cmake_generator_platform ${name} _EP_CMAKE_GENERATOR_PLATFORM)
@@ -2903,6 +2874,16 @@
         list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
       else()
         list(APPEND cmd "-G${CMAKE_GENERATOR}")
+        if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+          set(has_cmake_cache_default_args 1)
+          set(cmake_cache_default_args ${cmake_cache_default_args}
+            "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
+            "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
+            "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
+            "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
+            "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
+            "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}")
+        endif()
       endif()
       if(cmake_generator_platform)
         message(FATAL_ERROR "Option CMAKE_GENERATOR_PLATFORM not allowed without CMAKE_GENERATOR.")
@@ -2924,6 +2905,18 @@
       endif()
     endif()
 
+    if(has_cmake_cache_args OR has_cmake_cache_default_args)
+      set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
+      if(has_cmake_cache_args)
+        _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
+      endif()
+      if(has_cmake_cache_default_args)
+        _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
+      endif()
+      _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
+      list(APPEND cmd "-C${_ep_cache_args_script}")
+    endif()
+
     list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
   endif()
 
diff --git a/Modules/FindBISON.cmake b/Modules/FindBISON.cmake
index 06ac2d9..b0e25dc 100644
--- a/Modules/FindBISON.cmake
+++ b/Modules/FindBISON.cmake
@@ -19,7 +19,7 @@
   true if the program was found
 
 The minimum required version of ``bison`` can be specified using the
-standard CMake syntax, e.g.  ``find_package(BISON 2.1.3)``.
+standard CMake syntax, e.g.  :command:`find_package(BISON 2.1.3)`.
 
 If ``bison`` is found, the module defines the macro::
 
@@ -55,7 +55,7 @@
 The macro defines the following variables:
 
 ``BISON_<Name>_DEFINED``
-  true is the macro ran successfully
+  ``True`` is the macro ran successfully
 
 ``BISON_<Name>_INPUT``
   The input source file, an alias for <YaccInput>
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index 0aa4f50..77e689f 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -5,12 +5,12 @@
 FindBLAS
 --------
 
-Find BLAS library
+Find Basic Linear Algebra Subprograms (BLAS) library
 
-This module finds an installed fortran library that implements the
+This module finds an installed Fortran library that implements the
 BLAS linear-algebra interface (see http://www.netlib.org/blas/).  The
-list of libraries searched for is taken from the autoconf macro file,
-acx_blas.m4 (distributed at
+list of libraries searched for is taken from the ``autoconf`` macro file,
+``acx_blas.m4`` (distributed at
 http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
 
 Input Variables
@@ -52,7 +52,7 @@
   if ``ON`` tries to find the BLAS95 interfaces
 
 ``BLA_PREFER_PKGCONFIG``
-  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
 
 Result Variables
@@ -63,7 +63,7 @@
 ``BLAS_FOUND``
   library implementing the BLAS interface is found
 ``BLAS_LINKER_FLAGS``
-  uncached list of required linker flags (excluding -l and -L).
+  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)
@@ -75,7 +75,7 @@
 
 .. note::
 
-  C or CXX must be enabled to use Intel MKL
+  C or CXX must be enabled to use Intel Math Kernel Library (MKL)
 
   For example, to use Intel MKL libraries and/or Intel compiler:
 
@@ -83,6 +83,13 @@
 
     set(BLA_VENDOR Intel10_64lp)
     find_package(BLAS)
+
+Hints
+^^^^^
+
+Set ``MKLROOT`` environment variable to a directory that contains an MKL
+installation.
+
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
@@ -394,6 +401,24 @@
         endif ()
       endif ()
 
+      if (DEFINED ENV{MKLROOT})
+        set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}")
+      endif ()
+      if (_BLAS_MKLROOT_LIB_DIR)
+        if( SIZEOF_INTEGER EQUAL 8 )
+          set( _BLAS_MKL_PATH_PREFIX "intel64" )
+        else()
+          set( _BLAS_MKL_PATH_PREFIX "ia32" )
+        endif()
+        if (WIN32)
+          string(APPEND _BLAS_MKLROOT_LIB_DIR "/lib/${_BLAS_MKL_PATH_PREFIX}_win")
+        elseif (APPLE)
+          string(APPEND _BLAS_MKLROOT_LIB_DIR "/lib/${_BLAS_MKL_PATH_PREFIX}_mac")
+        else ()
+          string(APPEND _BLAS_MKLROOT_LIB_DIR "/lib/${_BLAS_MKL_PATH_PREFIX}_lin")
+        endif ()
+      endif ()
+
       foreach (IT ${BLAS_SEARCH_LIBS})
         string(REPLACE " " ";" SEARCH_LIBS ${IT})
         if (NOT ${_LIBRARIES})
@@ -404,6 +429,7 @@
             ""
             "${SEARCH_LIBS}"
             "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
+            "${_BLAS_MKLROOT_LIB_DIR}"
             )
         endif ()
       endforeach ()
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 7882c4b..7325eca 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -85,33 +85,33 @@
   Boost::dynamic_linking        - interface target to enable dynamic linking
                                   linking with MSVC (adds BOOST_ALL_DYN_LINK)
 
-Implicit dependencies such as Boost::filesystem requiring
-Boost::system will be automatically detected and satisfied, even
-if system is not specified when using find_package and if
-Boost::system is not added to target_link_libraries.  If using
-Boost::thread, then Threads::Threads will also be added automatically.
+Implicit dependencies such as ``Boost::filesystem`` requiring
+``Boost::system`` will be automatically detected and satisfied, even
+if system is not specified when using :command:`find_package` and if
+``Boost::system`` is not added to :command:`target_link_libraries`.  If using
+``Boost::thread``, then ``Threads::Threads`` will also be added automatically.
 
 It is important to note that the imported targets behave differently
 than variables created by this module: multiple calls to
-find_package(Boost) in the same directory or sub-directories with
+:command:`find_package(Boost)` in the same directory or sub-directories with
 different options (e.g. static or shared) will not override the
 values of the targets created by the first call.
 
-Users may set these hints or results as cache entries.  Projects
+Users may set these hints or results as ``CACHE`` entries.  Projects
 should not read these entries directly but instead use the above
 result variables.  Note that some hint names start in upper-case
 "BOOST".  One may specify these as environment variables if they are
 not specified as CMake variables or cache entries.
 
-This module first searches for the Boost header files using the above
-hint variables (excluding BOOST_LIBRARYDIR) and saves the result in
-Boost_INCLUDE_DIR.  Then it searches for requested component libraries
-using the above hints (excluding BOOST_INCLUDEDIR and
-Boost_ADDITIONAL_VERSIONS), "lib" directories near Boost_INCLUDE_DIR,
+This module first searches for the ``Boost`` header files using the above
+hint variables (excluding ``BOOST_LIBRARYDIR``) and saves the result in
+``Boost_INCLUDE_DIR``.  Then it searches for requested component libraries
+using the above hints (excluding ``BOOST_INCLUDEDIR`` and
+``Boost_ADDITIONAL_VERSIONS``), "lib" directories near ``Boost_INCLUDE_DIR``,
 and the library name configuration settings below.  It saves the
-library directories in Boost_LIBRARY_DIR_DEBUG and
-Boost_LIBRARY_DIR_RELEASE and individual library
-locations in Boost_<C>_LIBRARY_DEBUG and Boost_<C>_LIBRARY_RELEASE.
+library directories in ``Boost_LIBRARY_DIR_DEBUG`` and
+``Boost_LIBRARY_DIR_RELEASE`` and individual library
+locations in ``Boost_<C>_LIBRARY_DEBUG`` and ``Boost_<C>_LIBRARY_RELEASE``.
 When one changes settings used by previous searches in the same build
 tree (excluding environment variables) this module discards previous
 search results affected by the changes and searches again.
@@ -179,9 +179,9 @@
 On Visual Studio and Borland compilers Boost headers request automatic
 linking to corresponding libraries.  This requires matching libraries
 to be linked explicitly or available in the link library search path.
-In this case setting Boost_USE_STATIC_LIBS to OFF may not achieve
+In this case setting ``Boost_USE_STATIC_LIBS`` to ``OFF`` may not achieve
 dynamic linking.  Boost automatic linking typically requests static
-libraries with a few exceptions (such as Boost.Python).  Use::
+libraries with a few exceptions (such as ``Boost.Python``).  Use::
 
   add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
 
@@ -230,12 +230,12 @@
 If Boost was built using the boost-cmake project it provides a package
 configuration file for use with find_package's Config mode.  This
 module looks for the package configuration file called
-BoostConfig.cmake or boost-config.cmake and stores the result in cache
-entry "Boost_DIR".  If found, the package configuration file is loaded
+``BoostConfig.cmake`` or ``boost-config.cmake`` and stores the result in
+``CACHE`` entry "Boost_DIR".  If found, the package configuration file is loaded
 and this module returns with no further action.  See documentation of
 the Boost CMake package configuration for details on what it provides.
 
-Set Boost_NO_BOOST_CMAKE to ON to disable the search for boost-cmake.
+Set ``Boost_NO_BOOST_CMAKE`` to ``ON``, to disable the search for boost-cmake.
 #]=======================================================================]
 
 # Save project's policies
@@ -465,9 +465,18 @@
     endif()
   elseif (GHSMULTI)
     set(_boost_COMPILER "-ghs")
-  elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
-    if(MSVC_TOOLSET_VERSION GREATER_EQUAL 141)
-      set(_boost_COMPILER "-vc141;-vc140")
+  elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+    if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150)
+      # Not yet known.
+      set(_boost_COMPILER "")
+    elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140)
+      # MSVC toolset 14.x versions are forward compatible.
+      set(_boost_COMPILER "")
+      foreach(v 9 8 7 6 5 4 3 2 1 0)
+        if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v})
+          list(APPEND _boost_COMPILER "-vc14${v}")
+        endif()
+      endforeach()
     elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80)
       set(_boost_COMPILER "-vc${MSVC_TOOLSET_VERSION}")
     elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10)
@@ -477,6 +486,12 @@
     else() # VS 6.0 Good luck!
       set(_boost_COMPILER "-vc6") # yes, this is correct
     endif()
+
+    if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
+      string(REPLACE "." ";" VERSION_LIST "${CMAKE_CXX_COMPILER_VERSION}")
+      list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR)
+      set(_boost_COMPILER "-clangw${CLANG_VERSION_MAJOR};${_boost_COMPILER}")
+    endif()
   elseif (BORLAND)
     set(_boost_COMPILER "-bcb")
   elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
@@ -1077,9 +1092,15 @@
     else()
       set(_arch_suffix 32)
     endif()
-    if(MSVC_TOOLSET_VERSION GREATER_EQUAL 141)
-      list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.1)
-      list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.0)
+    if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150)
+      # Not yet known.
+    elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140)
+      # MSVC toolset 14.x versions are forward compatible.
+      foreach(v 9 8 7 6 5 4 3 2 1 0)
+        if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v})
+          list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.${v})
+        endif()
+      endforeach()
     elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80)
       math(EXPR _toolset_major_version "${MSVC_TOOLSET_VERSION} / 10")
       list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-${_toolset_major_version}.0)
@@ -1201,6 +1222,8 @@
   add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
   add_library(Boost::disable_autolinking INTERFACE IMPORTED)
   add_library(Boost::dynamic_linking INTERFACE IMPORTED)
+  set_target_properties(Boost::dynamic_linking PROPERTIES
+    INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
 endif()
 if(WIN32)
   # In windows, automatic linking is performed, so you do not have
@@ -1225,8 +1248,6 @@
     INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC")
   set_target_properties(Boost::disable_autolinking PROPERTIES
     INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
-  set_target_properties(Boost::dynamic_linking PROPERTIES
-    INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
 endif()
 
 _Boost_CHECK_SPELLING(Boost_ROOT)
@@ -1756,7 +1777,7 @@
     list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
     list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
     # Gentoo
-    list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
+    list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}.${COMPONENT_PYTHON_VERSION_MINOR}")
     # RPMs
     list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
   endif()
diff --git a/Modules/FindCups.cmake b/Modules/FindCups.cmake
index 10ce229..2c79911 100644
--- a/Modules/FindCups.cmake
+++ b/Modules/FindCups.cmake
@@ -5,18 +5,38 @@
 FindCups
 --------
 
-Try to find the Cups printing system
+Find the CUPS printing system.
 
-Once done this will define
+Set ``CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE`` to ``TRUE`` if you need a version which
+features this function (i.e. at least ``1.1.19``)
 
-::
+Imported targets
+^^^^^^^^^^^^^^^^
 
-  CUPS_FOUND - system has Cups
-  CUPS_INCLUDE_DIR - the Cups include directory
-  CUPS_LIBRARIES - Libraries needed to use Cups
-  CUPS_VERSION_STRING - version of Cups found (since CMake 2.8.8)
-  Set CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE to TRUE if you need a version which
-  features this function (i.e. at least 1.1.19)
+This module defines :prop_tgt:`IMPORTED` target ``Cups::Cups``, if Cups has
+been found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``CUPS_FOUND``
+  true if CUPS headers and libraries were found
+``CUPS_INCLUDE_DIRS``
+  the directory containing the Cups headers
+``CUPS_LIBRARIES``
+  the libraries to link against to use CUPS.
+``CUPS_VERSION_STRING``
+  the version of CUPS found (since CMake 2.8.8)
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``CUPS_INCLUDE_DIR``
+  the directory containing the Cups headers
 #]=======================================================================]
 
 find_path(CUPS_INCLUDE_DIR cups/cups.h )
@@ -66,3 +86,13 @@
 endif ()
 
 mark_as_advanced(CUPS_INCLUDE_DIR CUPS_LIBRARIES)
+
+if (CUPS_FOUND)
+    set(CUPS_INCLUDE_DIRS "${CUPS_INCLUDE_DIR}")
+    if (NOT TARGET Cups::Cups)
+        add_library(Cups::Cups INTERFACE IMPORTED)
+        set_target_properties(Cups::Cups PROPERTIES
+            INTERFACE_LINK_LIBRARIES      "${CUPS_LIBRARIES}"
+            INTERFACE_INCLUDE_DIRECTORIES "${CUPS_INCLUDE_DIR}")
+    endif ()
+endif ()
diff --git a/Modules/FindEnvModules.cmake b/Modules/FindEnvModules.cmake
new file mode 100644
index 0000000..5d3452d
--- /dev/null
+++ b/Modules/FindEnvModules.cmake
@@ -0,0 +1,333 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindEnvModules
+--------------
+
+Locate an environment module implementation and make commands available to
+CMake scripts to use them.  This is compatible with both Lua-based Lmod
+and TCL-based EnvironmentModules.
+
+This module is intended for the use case of setting up the compiler and library
+environment within a :ref:`CTest Script <CTest Script>` (``ctest -S``).  It can
+also be used in a :ref:`CMake Script <Script Processing Mode>` (``cmake -P``).
+
+.. note::
+
+  The loaded environment will not survive past the end of the calling process.
+  Do not use this module in project code (``CMakeLists.txt`` files) to load
+  a compiler environment; it will not be available during the build.  Instead
+  load the environment manually before running CMake or using the generated
+  build system.
+
+Example Usage
+^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+  set(CTEST_BUILD_NAME "CrayLinux-CrayPE-Cray-dynamic")
+  set(CTEST_BUILD_CONFIGURATION Release)
+  set(CTEST_BUILD_FLAGS "-k -j8")
+  set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
+
+  ...
+
+  find_package(EnvModules REQUIRED)
+
+  env_module(purge)
+  env_module(load modules)
+  env_module(load craype)
+  env_module(load PrgEnv-cray)
+  env_module(load craype-knl)
+  env_module(load cray-mpich)
+  env_module(load cray-libsci)
+
+  set(ENV{CRAYPE_LINK_TYPE} dynamic)
+
+  ...
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``EnvModules_FOUND``
+  Found the a compatible environment modules framework
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variable will be set:
+
+``EnvModules_COMMAND``
+  The low level module command to use.  Currently supported are
+  implementations are the Lua based Lmod and TCL based EnvironmentModules.
+
+Environment Variables
+^^^^^^^^^^^^^^^^^^^^^
+
+``ENV{MODULESHOME}``
+  Usually set by the module environment implementation, used as a hint to
+  locate the module command to execute.
+
+Provided Functions
+^^^^^^^^^^^^^^^^^^
+
+This defines the following cmake functions for interacting with environment
+modules:
+
+.. command:: env_module
+
+  Execute an aribitrary module command:
+
+  .. code-block:: cmake
+
+    env_module(cmd arg1 ... argN)
+    env_module(
+      COMMAND cmd arg1 ... argN
+      [OUTPUT_VARIABLE <out-var>]
+      [RESULT_VARIABLE <ret-var>]
+    )
+
+  The options are:
+
+  ``cmd arg1 ... argN``
+    The module sub-command and arguments to execute as if they were
+    passed directly to the module command in your shell environment.
+
+  ``OUTPUT_VARIABLE <out-var>``
+    The standard output from executing the module command.
+
+  ``RESULT_VARIABLE <ret-var>``
+    The return code from executing the module command.
+
+.. command:: env_module_swap
+
+  Swap one module for another:
+
+  .. code-block:: cmake
+
+    env_module_swap(out_mod in_mod
+      [OUTPUT_VARIABLE <out-var>]
+      [RESULT_VARIABLE <ret-var>]
+    )
+
+  This is functionally equivalent to the ``module swap out_mod in_mod`` shell
+  command.  The options are:
+
+  ``OUTPUT_VARIABLE <out-var>``
+    The standard output from executing the module command.
+
+  ``RESULT_VARIABLE <ret-var>``
+    The return code from executing the module command.
+
+.. command:: env_module_list
+
+  Retrieve the list of currently loaded modules:
+
+  .. code-block:: cmake
+
+    env_module_list(<out-var>)
+
+  This is functionally equivalent to the ``module list`` shell command.
+  The result is stored in ``<out-var>`` as a properly formatted CMake
+  :ref:`semicolon-separated list <CMake Language Lists>` variable.
+
+.. command:: env_module_avail
+
+  Retrieve the list of available modules:
+
+  .. code-block:: cmake
+
+    env_module_avail([<mod-prefix>] <out-var>)
+
+  This is functionally equivalent to the ``module avail <mod-prefix>`` shell
+  command.  The result is stored in ``<out-var>`` as a properly formatted
+  CMake :ref:`semicolon-separated list <CMake Language Lists>` variable.
+
+#]=======================================================================]
+
+function(env_module)
+  if(NOT EnvModules_COMMAND)
+    message(FATAL_ERROR "Failed to process module command.  EnvModules_COMMAND not found")
+    return()
+  endif()
+
+  set(options)
+  set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
+  set(multiValueArgs COMMAND)
+  cmake_parse_arguments(MOD_ARGS
+    "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
+  )
+  if(NOT MOD_ARGS_COMMAND)
+    # If no explicit command argument was given, then treat the calling syntax
+    # as: module(cmd args...)
+    set(exec_cmd ${ARGV})
+  else()
+    set(exec_cmd ${MOD_ARGS_COMMAND})
+  endif()
+
+  if(MOD_ARGS_OUTPUT_VARIABLE)
+    set(err_var_args ERROR_VARIABLE err_var)
+   endif()
+
+  execute_process(
+    COMMAND mktemp -t module.cmake.XXXXXXXXXXXX
+    OUTPUT_VARIABLE tempfile_name
+  )
+  string(STRIP "${tempfile_name}" tempfile_name)
+
+  # If the $MODULESHOME/init/cmake file exists then assume that the CMake
+  # "shell" functionality exits
+  if(EXISTS "$ENV{MODULESHOME}/init/cmake")
+    execute_process(
+      COMMAND ${EnvModules_COMMAND} cmake ${exec_cmd}
+      OUTPUT_FILE ${tempfile_name}
+      ${err_var_args}
+      RESULT_VARIABLE ret_var
+    )
+
+  else() # fallback to the sh shell and manually convert to CMake
+    execute_process(
+      COMMAND ${EnvModules_COMMAND} sh ${exec_cmd}
+      OUTPUT_VARIABLE out_var
+      ${err_var_args}
+      RESULT_VARIABLE ret_var
+    )
+  endif()
+
+  # If we executed successfully then process and cleanup the temp file
+  if(ret_var EQUAL 0)
+    # No CMake shell so we need to process the sh output into CMake code
+    if(NOT EXISTS "$ENV{MODULESHOME}/init/cmake")
+      file(WRITE ${tempfile_name} "")
+      string(REPLACE "\n" ";" out_var "${out_var}")
+      foreach(sh_cmd IN LISTS out_var)
+        if(sh_cmd MATCHES "^ *unset *([^ ]*)")
+          set(cmake_cmd "unset(ENV{${CMAKE_MATCH_1}})")
+        elseif(sh_cmd MATCHES "^ *export *([^ ]*)")
+          set(cmake_cmd "set(ENV{${CMAKE_MATCH_1}} \"\${${CMAKE_MATCH_1}}\")")
+        elseif(sh_cmd MATCHES " *([^ =]*) *= *(.*)")
+          set(var_name "${CMAKE_MATCH_1}")
+          set(var_value "${CMAKE_MATCH_2}")
+          if(var_value MATCHES "^\"(.*[^\\])\"")
+            # If it's in quotes, take the value as is
+            set(var_value "${CMAKE_MATCH_1}")
+          else()
+            # Otherwise, strip trailing spaces
+            string(REGEX REPLACE "([^\\])? +$" "\\1" var_value "${var_value}")
+          endif()
+          string(REPLACE "\\ " " " var_value "${var_value}")
+          set(cmake_cmd "set(${var_name} \"${var_value}\")")
+        else()
+          continue()
+        endif()
+        file(APPEND ${tempfile_name} "${cmake_cmd}\n")
+      endforeach()
+    endif()
+
+    # Process the change in environment variables
+    include(${tempfile_name})
+    file(REMOVE ${tempfile_name})
+  endif()
+
+  # Push the output back out to the calling scope
+  if(MOD_ARGS_OUTPUT_VARIABLE)
+    set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
+  endif()
+  if(MOD_ARGS_RESULT_VARIABLE)
+    set(${MOD_ARGS_RESULT_VARIABLE} ${ret_var} PARENT_SCOPE)
+  endif()
+endfunction(env_module)
+
+#------------------------------------------------------------------------------
+function(env_module_swap out_mod in_mod)
+  set(options)
+  set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
+  set(multiValueArgs)
+
+  cmake_parse_arguments(MOD_ARGS
+    "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
+  )
+
+  env_module(COMMAND -t swap ${out_mod} ${in_mod}
+    OUTPUT_VARIABLE tmp_out
+    RETURN_VARIABLE tmp_ret
+  )
+
+  if(MOD_ARGS_OUTPUT_VARIABLE)
+    set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
+  endif()
+  if(MOD_ARGS_RESULT_VARIABLE)
+    set(${MOD_ARGS_RESULT_VARIABLE} ${tmp_ret} PARENT_SCOPE)
+  endif()
+endfunction()
+
+#------------------------------------------------------------------------------
+function(env_module_list out_var)
+  cmake_policy(SET CMP0007 NEW)
+  env_module(COMMAND -t list OUTPUT_VARIABLE tmp_out)
+
+  # Convert output into a CMake list
+  string(REPLACE "\n" ";" ${out_var} "${tmp_out}")
+
+  # Remove title headers and empty entries
+  list(REMOVE_ITEM ${out_var} "No modules loaded")
+  if(${out_var})
+    list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
+  endif()
+  list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
+
+  set(${out_var} ${${out_var}} PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------
+function(env_module_avail)
+  cmake_policy(SET CMP0007 NEW)
+
+  if(ARGC EQUAL 1)
+    set(mod_prefix)
+    set(out_var ${ARGV0})
+  elseif(ARGC EQUAL 2)
+    set(mod_prefix ${ARGV0})
+    set(out_var ${ARGV1})
+  else()
+    message(FATAL_ERROR "Usage: env_module_avail([mod_prefix] out_var)")
+  endif()
+  env_module(COMMAND -t avail ${mod_prefix} OUTPUT_VARIABLE tmp_out)
+
+  # Convert output into a CMake list
+  string(REPLACE "\n" ";" tmp_out "${tmp_out}")
+
+  set(${out_var})
+  foreach(MOD IN LISTS tmp_out)
+    # Remove directory entries and empty values
+    if(MOD MATCHES "^(.*:)?$")
+      continue()
+    endif()
+
+    # Convert default modules
+    if(MOD MATCHES "^(.*)/$" ) # "foo/"
+      list(APPEND ${out_var} ${CMAKE_MATCH_1})
+    elseif(MOD MATCHES "^((.*)/.*)\\(default\\)$") # "foo/1.2.3(default)"
+      list(APPEND ${out_var} ${CMAKE_MATCH_2})
+      list(APPEND ${out_var} ${CMAKE_MATCH_1})
+    else()
+      list(APPEND ${out_var} ${MOD})
+    endif()
+  endforeach()
+
+  set(${out_var} ${${out_var}} PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------
+# Make sure we know where the underlying module command is
+find_program(EnvModules_COMMAND
+  NAMES lmod modulecmd
+  HINTS ENV MODULESHOME
+  PATH_SUFFIXES libexec
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(EnvModules DEFAULT_MSG EnvModules_COMMAND)
diff --git a/Modules/FindFLEX.cmake b/Modules/FindFLEX.cmake
index edebe75..68eb9c8 100644
--- a/Modules/FindFLEX.cmake
+++ b/Modules/FindFLEX.cmake
@@ -13,7 +13,7 @@
 
 ::
 
-  FLEX_FOUND - true is flex executable is found
+  FLEX_FOUND - True is flex executable is found
   FLEX_EXECUTABLE - the path to the flex executable
   FLEX_VERSION - the version of flex
   FLEX_LIBRARIES - The flex libraries
@@ -35,10 +35,10 @@
               [DEFINES_FILE <string>]
               )
 
-which creates a custom command to generate the <FlexOutput> file from
-the <FlexInput> file.  If COMPILE_FLAGS option is specified, the next
+which creates a custom command to generate the ``FlexOutput`` file from
+the ``FlexInput`` file.  If ``COMPILE_FLAGS`` option is specified, the next
 parameter is added to the flex command line. If flex is configured to
-output a header file, the DEFINES_FILE option may be used to specify its
+output a header file, the ``DEFINES_FILE`` option may be used to specify its
 name. Name is an alias used to get details of this custom command.
 Indeed the macro defines the following variables:
 
@@ -61,8 +61,8 @@
   ADD_FLEX_BISON_DEPENDENCY(FlexTarget BisonTarget)
 
 which adds the required dependency between a scanner and a parser
-where <FlexTarget> and <BisonTarget> are the first parameters of
-respectively FLEX_TARGET and BISON_TARGET macros.
+where ``FlexTarget`` and ``BisonTarget`` are the first parameters of
+respectively ``FLEX_TARGET`` and ``BISON_TARGET`` macros.
 
 ::
 
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index ad8a810..2e9a052 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -7,64 +7,305 @@
 
 Find the OpenGL Extension Wrangler Library (GLEW)
 
-IMPORTED Targets
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module’s behavior:
+
+``GLEW_USE_STATIC_LIBS``
+  to find and create :prop_tgt:`IMPORTED` target for static linkage.
+
+``GLEW_VERBOSE``
+  to output a detailed log of this module.
+
+Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the :prop_tgt:`IMPORTED` target ``GLEW::GLEW``,
-if GLEW has been found.
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+
+``GLEW::glew``
+  The GLEW shared library.
+``GLEW::glew_s``
+  The GLEW static library, if ``GLEW_USE_STATIC_LIBS`` is set to ``TRUE``.
+``GLEW::GLEW``
+  Duplicates either ``GLEW::glew`` or ``GLEW::glew_s`` based on availability.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
 This module defines the following variables:
 
-::
+``GLEW_INCLUDE_DIRS``
+  include directories for GLEW
+``GLEW_LIBRARIES``
+  libraries to link against GLEW
+``GLEW_SHARED_LIBRARIES``
+  libraries to link against shared GLEW
+``GLEW_STATIC_LIBRARIES``
+  libraries to link against static GLEW
+``GLEW_FOUND``
+  true if GLEW has been found and can be used
+``GLEW_VERSION``
+  GLEW version
+``GLEW_VERSION_MAJOR``
+  GLEW major version
+``GLEW_VERSION_MINOR``
+  GLEW minor version
+``GLEW_VERSION_MICRO``
+  GLEW micro version
 
-  GLEW_INCLUDE_DIRS - include directories for GLEW
-  GLEW_LIBRARIES - libraries to link against GLEW
-  GLEW_FOUND - true if GLEW has been found and can be used
 #]=======================================================================]
 
-find_path(GLEW_INCLUDE_DIR GL/glew.h)
-
-if(NOT GLEW_LIBRARY)
-  find_library(GLEW_LIBRARY_RELEASE NAMES GLEW glew32 glew glew32s PATH_SUFFIXES lib64 libx32)
-  find_library(GLEW_LIBRARY_DEBUG NAMES GLEWd glew32d glewd PATH_SUFFIXES lib64)
-
-  include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
-  select_library_configurations(GLEW)
-endif ()
-
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
-find_package_handle_standard_args(GLEW
-                                  REQUIRED_VARS GLEW_INCLUDE_DIR GLEW_LIBRARY)
+
+find_package(GLEW CONFIG QUIET)
 
 if(GLEW_FOUND)
-  set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR})
+  find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_CONFIG)
+  return()
+endif()
 
-  if(NOT GLEW_LIBRARIES)
-    set(GLEW_LIBRARIES ${GLEW_LIBRARY})
+if(GLEW_VERBOSE)
+  message(STATUS "FindGLEW: did not find GLEW CMake config file. Searching for libraries.")
+endif()
+
+
+function(__glew_set_find_library_suffix shared_or_static)
+  if(UNIX AND "${shared_or_static}" MATCHES "SHARED")
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE)
+  elseif(UNIX AND "${shared_or_static}" MATCHES "STATIC")
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+  elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED")
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE)
+  elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC")
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+  elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED")
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE)
+  elseif(WIN32 AND "${shared_or_static}" MATCHES "STATIC")
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a" PARENT_SCOPE)
   endif()
 
-  if (NOT TARGET GLEW::GLEW)
-    add_library(GLEW::GLEW UNKNOWN IMPORTED)
-    set_target_properties(GLEW::GLEW PROPERTIES
-      INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+  if(GLEW_VERBOSE)
+    message(STATUS "FindGLEW: CMAKE_FIND_LIBRARY_SUFFIXES for ${shared_or_static}: ${CMAKE_FIND_LIBRARY_SUFFIXES}")
+  endif()
+endfunction()
 
-    if(GLEW_LIBRARY_RELEASE)
-      set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
-      set_target_properties(GLEW::GLEW PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_LIBRARY_RELEASE}")
-    endif()
 
-    if(GLEW_LIBRARY_DEBUG)
-      set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
-      set_target_properties(GLEW::GLEW PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_LIBRARY_DEBUG}")
-    endif()
-
-    if(NOT GLEW_LIBRARY_RELEASE AND NOT GLEW_LIBRARY_DEBUG)
-      set_property(TARGET GLEW::GLEW APPEND PROPERTY IMPORTED_LOCATION "${GLEW_LIBRARY}")
-    endif()
+if(GLEW_VERBOSE)
+  if(DEFINED GLEW_USE_STATIC_LIBS)
+    message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS: ${GLEW_USE_STATIC_LIBS}.")
+  else()
+    message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS is undefined. Treated as FALSE.")
   endif()
 endif()
 
+find_path(GLEW_INCLUDE_DIR GL/glew.h)
 mark_as_advanced(GLEW_INCLUDE_DIR)
+
+set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR})
+
+if(GLEW_VERBOSE)
+  message(STATUS "FindGLEW: GLEW_INCLUDE_DIR: ${GLEW_INCLUDE_DIR}")
+  message(STATUS "FindGLEW: GLEW_INCLUDE_DIRS: ${GLEW_INCLUDE_DIRS}")
+endif()
+
+if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64" OR "${CMAKE_GENERATOR}" MATCHES "Win64")
+  set(_arch "x64")
+else()
+  set(_arch "Win32")
+endif()
+
+
+set(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
+__glew_set_find_library_suffix(SHARED)
+
+find_library(GLEW_SHARED_LIBRARY_RELEASE
+             NAMES GLEW glew glew32
+             PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
+             PATHS ENV GLEW_ROOT)
+
+find_library(GLEW_SHARED_LIBRARY_DEBUG
+             NAMES GLEWd glewd glew32d
+             PATH_SUFFIXES lib lib64
+             PATHS ENV GLEW_ROOT)
+
+
+__glew_set_find_library_suffix(STATIC)
+
+find_library(GLEW_STATIC_LIBRARY_RELEASE
+             NAMES GLEW glew glew32s
+             PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
+             PATHS ENV GLEW_ROOT)
+
+find_library(GLEW_STATIC_LIBRARY_DEBUG
+             NAMES GLEWds glewds glew32ds
+             PATH_SUFFIXES lib lib64
+             PATHS ENV GLEW_ROOT)
+
+set(CMAKE_FIND_LIBRARY_SUFFIXES ${__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES})
+unset(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES)
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+select_library_configurations(GLEW_SHARED)
+select_library_configurations(GLEW_STATIC)
+
+if(NOT GLEW_USE_STATIC_LIBS)
+  set(GLEW_LIBRARIES ${GLEW_SHARED_LIBRARY})
+else()
+  set(GLEW_LIBRARIES ${GLEW_STATIC_LIBRARY})
+endif()
+
+
+if(GLEW_VERBOSE)
+  message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_RELEASE: ${GLEW_SHARED_LIBRARY_RELEASE}")
+  message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_RELEASE: ${GLEW_STATIC_LIBRARY_RELEASE}")
+  message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_DEBUG: ${GLEW_SHARED_LIBRARY_DEBUG}")
+  message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_DEBUG: ${GLEW_STATIC_LIBRARY_DEBUG}")
+  message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY: ${GLEW_SHARED_LIBRARY}")
+  message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY: ${GLEW_STATIC_LIBRARY}")
+  message(STATUS "FindGLEW: GLEW_LIBRARIES: ${GLEW_LIBRARIES}")
+endif()
+
+
+# Read version from GL/glew.h file
+if(EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h")
+  file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" _contents REGEX "^VERSION_.+ [0-9]+")
+  if(_contents)
+    string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MAJOR "${_contents}")
+    string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MINOR "${_contents}")
+    string(REGEX REPLACE ".*VERSION_MICRO[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MICRO "${_contents}")
+    set(GLEW_VERSION "${GLEW_VERSION_MAJOR}.${GLEW_VERSION_MINOR}.${GLEW_VERSION_MICRO}")
+  endif()
+endif()
+
+if(GLEW_VERBOSE)
+  message(STATUS "FindGLEW: GLEW_VERSION_MAJOR: ${GLEW_VERSION_MAJOR}")
+  message(STATUS "FindGLEW: GLEW_VERSION_MINOR: ${GLEW_VERSION_MINOR}")
+  message(STATUS "FindGLEW: GLEW_VERSION_MICRO: ${GLEW_VERSION_MICRO}")
+  message(STATUS "FindGLEW: GLEW_VERSION: ${GLEW_VERSION}")
+endif()
+
+find_package_handle_standard_args(GLEW
+                                  REQUIRED_VARS GLEW_INCLUDE_DIRS GLEW_LIBRARIES
+                                  VERSION_VAR GLEW_VERSION)
+
+if(NOT GLEW_FOUND)
+  if(GLEW_VERBOSE)
+    message(STATUS "FindGLEW: could not found GLEW library.")
+  endif()
+  return()
+endif()
+
+
+if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS)
+  if(GLEW_VERBOSE)
+    message(STATUS "FindGLEW: Creating GLEW::glew imported target.")
+  endif()
+
+  add_library(GLEW::glew UNKNOWN IMPORTED)
+
+  set_target_properties(GLEW::glew
+                        PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+  if(GLEW_SHARED_LIBRARY_RELEASE)
+    set_property(TARGET GLEW::glew
+                 APPEND
+                 PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+    set_target_properties(GLEW::glew
+                          PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
+  endif()
+
+  if(GLEW_SHARED_LIBRARY_DEBUG)
+    set_property(TARGET GLEW::glew
+                 APPEND
+                 PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+    set_target_properties(GLEW::glew
+                          PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
+  endif()
+
+elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS)
+  if(GLEW_VERBOSE)
+    message(STATUS "FindGLEW: Creating GLEW::glew_s imported target.")
+  endif()
+
+  add_library(GLEW::glew_s UNKNOWN IMPORTED)
+
+  set_target_properties(GLEW::glew_s
+                        PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+  if(GLEW_STATIC_LIBRARY_RELEASE)
+    set_property(TARGET GLEW::glew_s
+                 APPEND
+                 PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+    set_target_properties(GLEW::glew_s
+                          PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
+  endif()
+
+  if(GLEW_STATIC_LIBRARY_DEBUG)
+    set_property(TARGET GLEW::glew_s
+                 APPEND
+                 PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+    set_target_properties(GLEW::glew_s
+                          PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
+  endif()
+endif()
+
+if(NOT TARGET GLEW::GLEW)
+  if(GLEW_VERBOSE)
+    message(STATUS "FindGLEW: Creating GLEW::GLEW imported target.")
+  endif()
+
+  add_library(GLEW::GLEW UNKNOWN IMPORTED)
+
+  set_target_properties(GLEW::GLEW
+                        PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+  if(TARGET GLEW::glew)
+    if(GLEW_SHARED_LIBRARY_RELEASE)
+      set_property(TARGET GLEW::GLEW
+                   APPEND
+                   PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+      set_target_properties(GLEW::GLEW
+                            PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
+    endif()
+
+    if(GLEW_SHARED_LIBRARY_DEBUG)
+      set_property(TARGET GLEW::GLEW
+                   APPEND
+                   PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+      set_target_properties(GLEW::GLEW
+                            PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
+    endif()
+
+  elseif(TARGET GLEW::glew_s)
+    if(GLEW_STATIC_LIBRARY_RELEASE)
+      set_property(TARGET GLEW::GLEW
+                   APPEND
+                   PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+      set_target_properties(GLEW::GLEW
+                            PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
+    endif()
+
+    if(GLEW_STATIC_LIBRARY_DEBUG AND GLEW_USE_STATIC_LIBS)
+      set_property(TARGET GLEW::GLEW
+                   APPEND
+                   PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+      set_target_properties(GLEW::GLEW
+                            PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
+    endif()
+
+  elseif(GLEW_VERBOSE)
+    message(WARNING "FindGLEW: no `GLEW::glew` or `GLEW::glew_s` target was created. Something went wrong in FindGLEW target creation.")
+  endif()
+endif()
diff --git a/Modules/FindGTK2.cmake b/Modules/FindGTK2.cmake
index 6c1897c..3bd61a9 100644
--- a/Modules/FindGTK2.cmake
+++ b/Modules/FindGTK2.cmake
@@ -303,9 +303,7 @@
             /opt/gnome/lib
             /opt/openwin/include
             /usr/openwin/lib
-            /sw/include
             /sw/lib
-            /opt/local/include
             /opt/local/lib
             /usr/pkg/lib
             /usr/pkg/include/glib
@@ -415,7 +413,6 @@
         PATHS
             /opt/gnome/lib
             /usr/openwin/lib
-            /sw/lib
             $ENV{GTKMM_BASEPATH}/lib
             [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]/lib
             [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]/lib
diff --git a/Modules/FindLua50.cmake b/Modules/FindLua50.cmake
index aafc056..52a54e7 100644
--- a/Modules/FindLua50.cmake
+++ b/Modules/FindLua50.cmake
@@ -40,9 +40,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw # Fink
-  /opt/local # DarwinPorts
-  /opt/csw # Blastwave
   /opt
 )
 
@@ -54,9 +51,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw
-  /opt/local
-  /opt/csw
   /opt
 )
 
@@ -72,9 +66,6 @@
       ENV LUA_DIR
     PATH_SUFFIXES lib
     PATHS
-    /sw
-    /opt/local
-    /opt/csw
     /opt
   )
   if(LUA_LIBRARY_lualib AND LUA_LIBRARY_lua)
diff --git a/Modules/FindLua51.cmake b/Modules/FindLua51.cmake
index 31eaf87..1c9029b 100644
--- a/Modules/FindLua51.cmake
+++ b/Modules/FindLua51.cmake
@@ -41,9 +41,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw # Fink
-  /opt/local # DarwinPorts
-  /opt/csw # Blastwave
   /opt
 )
 
@@ -55,9 +52,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw
-  /opt/local
-  /opt/csw
   /opt
 )
 
diff --git a/Modules/FindOpenAL.cmake b/Modules/FindOpenAL.cmake
index dbd7961..18f3ff6 100644
--- a/Modules/FindOpenAL.cmake
+++ b/Modules/FindOpenAL.cmake
@@ -63,9 +63,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw # Fink
-  /opt/local # DarwinPorts
-  /opt/csw # Blastwave
   /opt
   [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
 )
@@ -84,9 +81,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw
-  /opt/local
-  /opt/csw
   /opt
   [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
 )
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 7e37212..5a34b9e 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -96,7 +96,6 @@
     else()
       set(OMP_FLAG_Intel "-qopenmp")
     endif()
-    set(OMP_FLAG_MIPSpro "-mp")
     set(OMP_FLAG_MSVC "-openmp")
     set(OMP_FLAG_PathScale "-openmp")
     set(OMP_FLAG_NAG "-openmp")
diff --git a/Modules/FindPhysFS.cmake b/Modules/FindPhysFS.cmake
index 0366f77..a32f83a 100644
--- a/Modules/FindPhysFS.cmake
+++ b/Modules/FindPhysFS.cmake
@@ -24,9 +24,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw # Fink
-  /opt/local # DarwinPorts
-  /opt/csw # Blastwave
   /opt
 )
 
@@ -38,9 +35,6 @@
   PATHS
   ~/Library/Frameworks
   /Library/Frameworks
-  /sw
-  /opt/local
-  /opt/csw
   /opt
 )
 
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index e192426..e05d5c8 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -84,26 +84,8 @@
   endif()
 endmacro()
 
-#[========================================[.rst:
-.. command:: pkg_get_variable
-
-  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>)
-
-  If ``pkg-config`` returns multiple values for the specified variable,
-  ``resultVar`` will contain a :ref:`;-list <CMake Language Lists>`.
-
-  For example:
-
-  .. code-block:: cmake
-
-    pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
-#]========================================]
-function (pkg_get_variable result pkg variable)
+# Internal version of pkg_get_variable; expects PKG_CONFIG_PATH to already be set
+function (_pkg_get_variable result pkg variable)
   _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}")
   set("${result}"
     "${prefix_result}"
@@ -242,7 +224,7 @@
 function(_pkg_create_imp_target _prefix _imp_target_global)
   # only create the target if it is linkable, i.e. no executables
   if (NOT TARGET PkgConfig::${_prefix}
-      AND ( ${_prefix}_INCLUDE_DIRS OR ${_prefix}_LINK_LIBRARIES OR ${_prefix}_CFLAGS_OTHER ))
+      AND ( ${_prefix}_INCLUDE_DIRS OR ${_prefix}_LINK_LIBRARIES OR ${_prefix}_LDFLAGS_OTHER OR ${_prefix}_CFLAGS_OTHER ))
     if(${_imp_target_global})
       set(_global_opt "GLOBAL")
     else()
@@ -258,6 +240,10 @@
       set_property(TARGET PkgConfig::${_prefix} PROPERTY
                    INTERFACE_LINK_LIBRARIES "${${_prefix}_LINK_LIBRARIES}")
     endif()
+    if(${_prefix}_LDFLAGS_OTHER)
+      set_property(TARGET PkgConfig::${_prefix} PROPERTY
+                   INTERFACE_LINK_OPTIONS "${${_prefix}_LDFLAGS_OTHER}")
+    endif()
     if(${_prefix}_CFLAGS_OTHER)
       set_property(TARGET PkgConfig::${_prefix} PROPERTY
                    INTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}")
@@ -275,6 +261,102 @@
 endmacro()
 
 ###
+macro(_pkg_set_path_internal)
+  set(_extra_paths)
+
+  if(NOT _no_cmake_path)
+    _pkgconfig_add_extra_path(_extra_paths CMAKE_PREFIX_PATH)
+    _pkgconfig_add_extra_path(_extra_paths CMAKE_FRAMEWORK_PATH)
+    _pkgconfig_add_extra_path(_extra_paths CMAKE_APPBUNDLE_PATH)
+  endif()
+
+  if(NOT _no_cmake_environment_path)
+    _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_PREFIX_PATH)
+    _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_FRAMEWORK_PATH)
+    _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_APPBUNDLE_PATH)
+  endif()
+
+  if(NOT _extra_paths STREQUAL "")
+    # Save the PKG_CONFIG_PATH environment variable, and add paths
+    # from the CMAKE_PREFIX_PATH variables
+    set(_pkgconfig_path_old "$ENV{PKG_CONFIG_PATH}")
+    set(_pkgconfig_path "${_pkgconfig_path_old}")
+    if(NOT _pkgconfig_path STREQUAL "")
+      file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+    endif()
+
+    # Create a list of the possible pkgconfig subfolder (depending on
+    # the system
+    set(_lib_dirs)
+    if(NOT DEFINED CMAKE_SYSTEM_NAME
+        OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+            AND NOT CMAKE_CROSSCOMPILING))
+      if(EXISTS "/etc/debian_version") # is this a debian system ?
+        if(CMAKE_LIBRARY_ARCHITECTURE)
+          list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
+        endif()
+      else()
+        # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties
+        get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS)
+        if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
+          list(APPEND _lib_dirs "lib32/pkgconfig")
+        endif()
+        get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+        if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+          list(APPEND _lib_dirs "lib64/pkgconfig")
+        endif()
+        get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS)
+        if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32")
+          list(APPEND _lib_dirs "libx32/pkgconfig")
+        endif()
+      endif()
+    endif()
+    if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING)
+      list(APPEND _lib_dirs "libdata/pkgconfig")
+    endif()
+    list(APPEND _lib_dirs "lib/pkgconfig")
+    list(APPEND _lib_dirs "share/pkgconfig")
+
+    # Check if directories exist and eventually append them to the
+    # pkgconfig path list
+    foreach(_prefix_dir ${_extra_paths})
+      foreach(_lib_dir ${_lib_dirs})
+        if(EXISTS "${_prefix_dir}/${_lib_dir}")
+          list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}")
+          list(REMOVE_DUPLICATES _pkgconfig_path)
+        endif()
+      endforeach()
+    endforeach()
+
+    # Prepare and set the environment variable
+    if(NOT _pkgconfig_path STREQUAL "")
+      # remove empty values from the list
+      list(REMOVE_ITEM _pkgconfig_path "")
+      file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+      if(UNIX)
+        string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
+        string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
+      endif()
+      set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path}")
+    endif()
+
+    # Unset variables
+    unset(_lib_dirs)
+    unset(_pkgconfig_path)
+  endif()
+endmacro()
+
+macro(_pkg_restore_path_internal)
+  if(NOT _extra_paths STREQUAL "")
+    # Restore the environment variable
+    set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
+  endif()
+
+  unset(_extra_paths)
+  unset(_pkgconfig_path_old)
+endmacro()
+
+###
 macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global _prefix)
   _pkgconfig_unset(${_prefix}_FOUND)
   _pkgconfig_unset(${_prefix}_VERSION)
@@ -314,88 +396,7 @@
     set(_pkg_check_modules_packages)
     set(_pkg_check_modules_failed)
 
-    set(_extra_paths)
-
-    if(NOT _no_cmake_path)
-      _pkgconfig_add_extra_path(_extra_paths CMAKE_PREFIX_PATH)
-      _pkgconfig_add_extra_path(_extra_paths CMAKE_FRAMEWORK_PATH)
-      _pkgconfig_add_extra_path(_extra_paths CMAKE_APPBUNDLE_PATH)
-    endif()
-
-    if(NOT _no_cmake_environment_path)
-      _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_PREFIX_PATH)
-      _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_FRAMEWORK_PATH)
-      _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_APPBUNDLE_PATH)
-    endif()
-
-    if(NOT "${_extra_paths}" STREQUAL "")
-      # Save the PKG_CONFIG_PATH environment variable, and add paths
-      # from the CMAKE_PREFIX_PATH variables
-      set(_pkgconfig_path_old "$ENV{PKG_CONFIG_PATH}")
-      set(_pkgconfig_path "${_pkgconfig_path_old}")
-      if(NOT "${_pkgconfig_path}" STREQUAL "")
-        file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path)
-      endif()
-
-      # Create a list of the possible pkgconfig subfolder (depending on
-      # the system
-      set(_lib_dirs)
-      if(NOT DEFINED CMAKE_SYSTEM_NAME
-          OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
-              AND NOT CMAKE_CROSSCOMPILING))
-        if(EXISTS "/etc/debian_version") # is this a debian system ?
-          if(CMAKE_LIBRARY_ARCHITECTURE)
-            list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
-          endif()
-        else()
-          # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties
-          get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS)
-          if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
-            list(APPEND _lib_dirs "lib32/pkgconfig")
-          endif()
-          get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
-          if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
-            list(APPEND _lib_dirs "lib64/pkgconfig")
-          endif()
-          get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS)
-          if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32")
-            list(APPEND _lib_dirs "libx32/pkgconfig")
-          endif()
-        endif()
-      endif()
-      if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING)
-        list(APPEND _lib_dirs "libdata/pkgconfig")
-      endif()
-      list(APPEND _lib_dirs "lib/pkgconfig")
-      list(APPEND _lib_dirs "share/pkgconfig")
-
-      # Check if directories exist and eventually append them to the
-      # pkgconfig path list
-      foreach(_prefix_dir ${_extra_paths})
-        foreach(_lib_dir ${_lib_dirs})
-          if(EXISTS "${_prefix_dir}/${_lib_dir}")
-            list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}")
-            list(REMOVE_DUPLICATES _pkgconfig_path)
-          endif()
-        endforeach()
-      endforeach()
-
-      # Prepare and set the environment variable
-      if(NOT "${_pkgconfig_path}" STREQUAL "")
-        # remove empty values from the list
-        list(REMOVE_ITEM _pkgconfig_path "")
-        file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
-        if(UNIX)
-          string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
-          string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
-        endif()
-        set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path}")
-      endif()
-
-      # Unset variables
-      unset(_lib_dirs)
-      unset(_pkgconfig_path)
-    endif()
+    _pkg_set_path_internal()
 
     # iterate through module list and check whether they exist and match the required version
     foreach (_pkg_check_modules_pkg ${_pkg_check_modules_list})
@@ -498,13 +499,7 @@
       _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global})
     endif()
 
-    if(NOT "${_extra_paths}" STREQUAL "")
-      # Restore the environment variable
-      set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
-    endif()
-
-    unset(_extra_paths)
-    unset(_pkgconfig_path_old)
+    _pkg_restore_path_internal()
   else()
     if (${_is_required})
       message(SEND_ERROR "pkg-config tool not found")
@@ -708,6 +703,34 @@
   endif()
 endmacro()
 
+#[========================================[.rst:
+.. command:: pkg_get_variable
+
+  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>)
+
+  If ``pkg-config`` returns multiple values for the specified variable,
+  ``resultVar`` will contain a :ref:`;-list <CMake Language Lists>`.
+
+  For example:
+
+  .. code-block:: cmake
+
+    pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
+#]========================================]
+function (pkg_get_variable result pkg variable)
+  _pkg_set_path_internal()
+  _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}")
+  set("${result}"
+    "${prefix_result}"
+    PARENT_SCOPE)
+  _pkg_restore_path_internal()
+endfunction ()
+
 
 #[========================================[.rst:
 Variables Affecting Behavior
diff --git a/Modules/FindProducer.cmake b/Modules/FindProducer.cmake
index fba0494..65495b5 100644
--- a/Modules/FindProducer.cmake
+++ b/Modules/FindProducer.cmake
@@ -45,12 +45,9 @@
   PATHS
     ~/Library/Frameworks
     /Library/Frameworks
-    /sw/include # Fink
-    /opt/local/include # DarwinPorts
-    /opt/csw/include # Blastwave
-    /opt/include
-    [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]/include
-    [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
+    /opt
+    [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]
+    [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]
 )
 
 find_library(PRODUCER_LIBRARY
@@ -61,9 +58,6 @@
     ENV OSGDIR
   PATH_SUFFIXES lib
   PATHS
-  /sw
-  /opt/local
-  /opt/csw
   /opt
 )
 
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 1c134e2..c5074e8 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -145,18 +145,30 @@
   * ``NEVER``: Never try to use registry.
 
 ``CMAKE_FIND_FRAMEWORK``
-  On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+  On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
   preference between Apple-style and unix-style package components.
 
   .. note::
 
     Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
 
-.. note::
+``Python_FIND_VIRTUALENV``
+  This variable defines the handling of virtual environments. It is meaningfull
+  only when a virtual environment is active (i.e. the ``activate`` script has
+  been evaluated). In this case, it takes precedence over
+  ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+  The ``Python_FIND_VIRTUALENV`` variable can be set to empty or one of the
+  following:
 
-  If a Python virtual environment is configured, set variable
-  ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
-  value ``LAST`` or ``NEVER`` to select it preferably.
+  * ``FIRST``: The virtual environment is used before any other standard
+    paths to look-up for the interpreter. This is the default.
+  * ``ONLY``: Only the virtual environment is used to look-up for the
+    interpreter.
+  * ``STANDARD``: The virtual environment is not used to look-up for the
+    interpreter. In this case, variable ``Python_FIND_REGISTRY`` (Windows)
+    or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+    ``NEVER`` to select preferably the interpreter from the virtual
+    environment.
 
 Commands
 ^^^^^^^^
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 1236bf8..0868989 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -298,6 +298,22 @@
   set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
 endif()
 
+# virtual environments handling
+if (DEFINED ENV{VIRTUAL_ENV})
+  if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV)
+    if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
+      message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'IGNORE' expected.")
+      set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV "FIRST")
+    else()
+      set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV})
+    endif()
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST)
+  endif()
+else()
+  set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD)
+endif()
+
 
 unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
 unset (_${_PYTHON_PREFIX}_CACHED_VARS)
@@ -318,6 +334,30 @@
 
     _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
 
+    # Virtual environments handling
+    if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+      find_program (${_PYTHON_PREFIX}_EXECUTABLE
+                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
+                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
+                          python
+                    NAMES_PER_DIR
+                    HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                    PATHS ENV VIRTUAL_ENV
+                    PATH_SUFFIXES bin Scripts
+                    NO_CMAKE_PATH
+                    NO_CMAKE_ENVIRONMENT_PATH
+                    NO_SYSTEM_ENVIRONMENT_PATH
+                    NO_CMAKE_SYSTEM_PATH)
+
+      _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION})
+      if (${_PYTHON_PREFIX}_EXECUTABLE)
+        break()
+      endif()
+      if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+        continue()
+      endif()
+    endif()
+
     # Apple frameworks handling
     if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
       find_program (${_PYTHON_PREFIX}_EXECUTABLE
@@ -423,7 +463,8 @@
     endif()
   endforeach()
 
-  if (NOT ${_PYTHON_PREFIX}_EXECUTABLE)
+  if (NOT ${_PYTHON_PREFIX}_EXECUTABLE AND
+      NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
     # No specific version found. Retry with generic names
     # try using HINTS
     find_program (${_PYTHON_PREFIX}_EXECUTABLE
@@ -685,18 +726,32 @@
   # if python interpreter is found, use its location and version to ensure consistency
   # between interpreter and development environment
   unset (_${_PYTHON_PREFIX}_PREFIX)
+  unset (_${_PYTHON_PREFIX}_EXEC_PREFIX)
+  unset (_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX)
   if (${_PYTHON_PREFIX}_Interpreter_FOUND)
     execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                             "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.PREFIX)"
+                             "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.EXEC_PREFIX)"
                      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX
+                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_EXEC_PREFIX
                      ERROR_QUIET
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (_${_PYTHON_PREFIX}_RESULT)
-      unset (_${_PYTHON_PREFIX}_PREFIX)
+      unset (_${_PYTHON_PREFIX}_EXEC_PREFIX)
+    endif()
+
+    if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "STANDARD")
+      execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                               "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.BASE_EXEC_PREFIX)"
+                       RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                       OUTPUT_VARIABLE _${_PYTHON_PREFIX}_BASE_EXEC_PREFIX
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_${_PYTHON_PREFIX}_RESULT)
+        unset (_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX)
+      endif()
     endif()
   endif()
-  set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+  set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_EXEC_PREFIX}" "${_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
 
   foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
     string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index b9c0b6b..a2be84f 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -153,11 +153,23 @@
 
     Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
 
-.. note::
+``Python2_FIND_VIRTUALENV``
+  This variable defines the handling of virtual environments. It is meaningfull
+  only when a virtual environment is active (i.e. the ``activate`` script has
+  been evaluated). In this case, it takes precedence over
+  ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+  The ``Python2_FIND_VIRTUALENV`` variable can be set to empty or one of the
+  following:
 
-  If a Python virtual environment is configured, set variable
-  ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
-  value ``LAST`` or ``NEVER`` to select it preferably.
+  * ``FIRST``: The virtual environment is used before any other standard
+    paths to look-up for the interpreter. This is the default.
+  * ``ONLY``: Only the virtual environment is used to look-up for the
+    interpreter.
+  * ``STANDARD``: The virtual environment is not used to look-up for the
+    interpreter. In this case, variable ``Python2_FIND_REGISTRY`` (Windows)
+    or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+    ``NEVER`` to select preferably the interpreter from the virtual
+    environment.
 
 Commands
 ^^^^^^^^
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index c2f3384..3409554 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -137,7 +137,7 @@
 ``Python3_FIND_REGISTRY``
   On Windows the ``Python3_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
-  the ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the
+  The ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the
   following:
 
   * ``FIRST``: Try to use registry before environment variables.
@@ -146,18 +146,30 @@
   * ``NEVER``: Never try to use registry.
 
 ``CMAKE_FIND_FRAMEWORK``
-  On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+  On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
   preference between Apple-style and unix-style package components.
 
   .. note::
 
     Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
 
-.. note::
+``Python3_FIND_VIRTUALENV``
+  This variable defines the handling of virtual environments. It is meaningfull
+  only when a virtual environment is active (i.e. the ``activate`` script has
+  been evaluated). In this case, it takes precedence over
+  ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+  The ``Python3_FIND_VIRTUALENV`` variable can be set to empty or one of the
+  following:
 
-  If a Python virtual environment is configured, set variable
-  ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
-  value ``LAST`` or ``NEVER`` to select it preferably.
+  * ``FIRST``: The virtual environment is used before any other standard
+    paths to look-up for the interpreter. This is the default.
+  * ``ONLY``: Only the virtual environment is used to look-up for the
+    interpreter.
+  * ``STANDARD``: The virtual environment is not used to look-up for the
+    interpreter. In this case, variable ``Python3_FIND_REGISTRY`` (Windows)
+    or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+    ``NEVER`` to select preferably the interpreter from the virtual
+    environment.
 
 Commands
 ^^^^^^^^
diff --git a/Modules/FindSDL.cmake b/Modules/FindSDL.cmake
index 2813831..8d793a9 100644
--- a/Modules/FindSDL.cmake
+++ b/Modules/FindSDL.cmake
@@ -112,9 +112,6 @@
         ENV SDLDIR
       PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
       PATHS
-      /sw
-      /opt/local
-      /opt/csw
       /opt
     )
   endif()
diff --git a/Modules/FindSDL_sound.cmake b/Modules/FindSDL_sound.cmake
index e217981..c986574 100644
--- a/Modules/FindSDL_sound.cmake
+++ b/Modules/FindSDL_sound.cmake
@@ -208,9 +208,6 @@
            ENV MIKMODDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -228,9 +225,6 @@
            ENV MODPLUGDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -250,9 +244,6 @@
            ENV OGGDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -268,9 +259,6 @@
            ENV VORBISDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -289,9 +277,6 @@
            ENV SMPEGDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -310,9 +295,6 @@
            ENV FLACDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -334,9 +316,6 @@
            ENV SPEEXDIR
            ENV SDLSOUNDDIR
            ENV SDLDIR
-           /sw
-           /opt/local
-           /opt/csw
            /opt
          PATH_SUFFIXES
            lib
@@ -356,9 +335,6 @@
              ENV SPEEXDIR
              ENV SDLSOUNDDIR
              ENV SDLDIR
-             /sw
-             /opt/local
-             /opt/csw
              /opt
            PATH_SUFFIXES lib
            )
diff --git a/Modules/FindSWIG.cmake b/Modules/FindSWIG.cmake
index fc0ed00..49f303e 100644
--- a/Modules/FindSWIG.cmake
+++ b/Modules/FindSWIG.cmake
@@ -19,11 +19,11 @@
 
 
 The minimum required version of SWIG can be specified using the
-standard syntax, e.g.  find_package(SWIG 1.1)
+standard syntax, e.g.   :command:`find_package(SWIG 1.1)`
 
-All information is collected from the SWIG_EXECUTABLE so the version
+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
+``SWIG_EXECUTABLE``
 #]=======================================================================]
 
 find_program(SWIG_EXECUTABLE NAMES swig3.0 swig2.0 swig)
@@ -64,4 +64,4 @@
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWIG  REQUIRED_VARS SWIG_EXECUTABLE SWIG_DIR
                                         VERSION_VAR SWIG_VERSION )
 
-mark_as_advanced(SWIG_DIR SWIG_VERSION)
+mark_as_advanced(SWIG_DIR SWIG_VERSION SWIG_EXECUTABLE)
diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake
index 63ca936..00a3a41 100644
--- a/Modules/FindTIFF.cmake
+++ b/Modules/FindTIFF.cmake
@@ -5,7 +5,7 @@
 FindTIFF
 --------
 
-Find the TIFF library (libtiff).
+Find the TIFF library (``libtiff``).
 
 Imported targets
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake
index 919392a..d317b71 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -38,19 +38,42 @@
 #]=======================================================================]
 
 include (CheckLibraryExists)
-include (CheckSymbolExists)
 set(Threads_FOUND FALSE)
 set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
 set(CMAKE_REQUIRED_QUIET ${Threads_FIND_QUIETLY})
 
 if(CMAKE_C_COMPILER_LOADED)
   include (CheckIncludeFile)
+  include (CheckCSourceCompiles)
 elseif(CMAKE_CXX_COMPILER_LOADED)
   include (CheckIncludeFileCXX)
+  include (CheckCXXSourceCompiles)
 else()
   message(FATAL_ERROR "FindThreads only works if either C or CXX language is enabled")
 endif()
 
+# simple pthread test code
+set(PTHREAD_C_CXX_TEST_SOURCE [====[
+#include <pthread.h>
+
+void* test_func(void* data)
+{
+  return data;
+}
+
+int main(void)
+{
+  pthread_t thread;
+  pthread_create(&thread, NULL, test_func, NULL);
+  pthread_detach(thread);
+  pthread_join(thread, NULL);
+  pthread_atfork(NULL, NULL, NULL);
+  pthread_exit(NULL);
+
+  return 0;
+}
+]====])
+
 # Internal helper macro.
 # Do NOT even think about using it outside of this file!
 macro(_check_threads_lib LIBNAME FUNCNAME VARNAME)
@@ -109,8 +132,8 @@
 else()
   CHECK_INCLUDE_FILE_CXX("pthread.h" CMAKE_HAVE_PTHREAD_H)
 endif()
-if(CMAKE_HAVE_PTHREAD_H)
 
+if(CMAKE_HAVE_PTHREAD_H)
   #
   # We have pthread.h
   # Let's check for the library now.
@@ -118,13 +141,19 @@
   set(CMAKE_HAVE_THREADS_LIBRARY)
   if(NOT THREADS_HAVE_PTHREAD_ARG)
     # Check if pthread functions are in normal C library.
-    CHECK_SYMBOL_EXISTS(pthread_create pthread.h CMAKE_HAVE_LIBC_CREATE)
-    if(CMAKE_HAVE_LIBC_CREATE)
+    # We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code.
+    # If the pthread functions already exist in C library, we could just use
+    # them instead of linking to the additional pthread library.
+    if(CMAKE_C_COMPILER_LOADED)
+      CHECK_C_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
+    elseif(CMAKE_CXX_COMPILER_LOADED)
+      CHECK_CXX_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
+    endif()
+    if(CMAKE_HAVE_LIBC_PTHREAD)
       set(CMAKE_THREAD_LIBS_INIT "")
       set(CMAKE_HAVE_THREADS_LIBRARY 1)
       set(Threads_FOUND TRUE)
     else()
-
       # Check for -pthread first if enabled. This is the recommended
       # way, but not backwards compatible as one must also pass -pthread
       # as compiler flag then.
@@ -132,6 +161,9 @@
          _check_pthreads_flag()
       endif ()
 
+      if(CMAKE_SYSTEM MATCHES "GHS-MULTI")
+        _check_threads_lib(posix pthread_create CMAKE_HAVE_PTHREADS_CREATE)
+      endif()
       _check_threads_lib(pthreads pthread_create CMAKE_HAVE_PTHREADS_CREATE)
       _check_threads_lib(pthread  pthread_create CMAKE_HAVE_PTHREAD_CREATE)
       if(CMAKE_SYSTEM_NAME MATCHES "SunOS")
@@ -144,7 +176,7 @@
   _check_pthreads_flag()
 endif()
 
-if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_CREATE)
+if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_PTHREAD)
   set(CMAKE_USE_PTHREADS_INIT 1)
   set(Threads_FOUND TRUE)
 endif()
diff --git a/Modules/FindUnixCommands.cmake b/Modules/FindUnixCommands.cmake
index 3a735f7..2513f5c 100644
--- a/Modules/FindUnixCommands.cmake
+++ b/Modules/FindUnixCommands.cmake
@@ -7,8 +7,9 @@
 
 Find Unix commands, including the ones from Cygwin
 
-This module looks for the Unix commands bash, cp, gzip, mv, rm, and tar
-and stores the result in the variables BASH, CP, GZIP, MV, RM, and TAR.
+This module looks for the Unix commands ``bash``, ``cp``, ``gzip``,
+``mv``, ``rm``, and ``tar`` and stores the result in the variables
+``BASH``, ``CP``, ``GZIP``, ``MV``, ``RM``, and ``TAR``.
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
diff --git a/Modules/FortranCInterface/CMakeLists.txt b/Modules/FortranCInterface/CMakeLists.txt
index e3b81d7..381080b 100644
--- a/Modules/FortranCInterface/CMakeLists.txt
+++ b/Modules/FortranCInterface/CMakeLists.txt
@@ -15,11 +15,11 @@
 # List manglings of global symbol names to try.
 set(global_symbols
   my_sub    # VisualAge
-  my_sub_   # GNU, Intel, HP, SunPro, MIPSpro, PGI
+  my_sub_   # GNU, Intel, HP, SunPro, PGI
   my_sub__  # GNU g77
   MY_SUB    # Intel on Windows
   mysub     # VisualAge
-  mysub_    # GNU, Intel, HP, SunPro, MIPSpro, PGI
+  mysub_    # GNU, Intel, HP, SunPro, PGI
   MYSUB     # Intel on Windows
   ${FortranCInterface_GLOBAL_SYMBOLS}
   )
@@ -48,7 +48,6 @@
 list(REMOVE_DUPLICATES module_symbols)
 
 # Note that some compiler manglings cannot be invoked from C:
-#   MIPSpro uses "MY_SUB.in.MY_MODULE"
 #   SunPro uses "my_module.my_sub_"
 #   PathScale uses "MY_SUB.in.MY_MODULE"
 
diff --git a/Modules/GenerateExportHeader.cmake b/Modules/GenerateExportHeader.cmake
index f2e4527..e4481f6 100644
--- a/Modules/GenerateExportHeader.cmake
+++ b/Modules/GenerateExportHeader.cmake
@@ -7,7 +7,7 @@
 
 Function for generation of export macros for libraries
 
-This module provides the function GENERATE_EXPORT_HEADER().
+This module provides the function ``GENERATE_EXPORT_HEADER()``.
 
 The ``GENERATE_EXPORT_HEADER`` function can be used to generate a file
 suitable for preprocessor inclusion which contains EXPORT macros to be
diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake
index 2de71ee..26b2517 100644
--- a/Modules/Internal/CPack/CPackRPM.cmake
+++ b/Modules/Internal/CPack/CPackRPM.cmake
@@ -63,6 +63,11 @@
   set(${RETURN_VAR} "${OWNER_PERMISSIONS}${GROUP_PERMISSIONS}${WORLD_PERMISSIONS}" PARENT_SCOPE)
 endfunction()
 
+function(cpack_rpm_exact_regex regex_var string)
+  string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${string}")
+  set("${regex_var}" "${regex}" PARENT_SCOPE)
+endfunction()
+
 function(cpack_rpm_prepare_relocation_paths)
   # set appropriate prefix, remove possible trailing slash and convert backslashes to slashes
   if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX)
@@ -482,7 +487,9 @@
         # recalculate path length after conversion to canonical form
         string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)
 
-        if(SYMLINK_POINT_ MATCHES "${WDIR}/.*")
+        cpack_rpm_exact_regex(IN_SYMLINK_POINT_REGEX "${WDIR}")
+        string(APPEND IN_SYMLINK_POINT_REGEX "/.*")
+        if(SYMLINK_POINT_ MATCHES "${IN_SYMLINK_POINT_REGEX}")
           # only symlinks that are pointing inside the packaging structure should be checked for relocation
           string(SUBSTRING "${SYMLINK_POINT_}" ${WDR_LEN_} -1 SYMLINK_POINT_WD_)
           cpack_rpm_symlink_get_relocation_prefixes("${F}" "${PACKAGE_PREFIXES}" "SYMLINK_RELOCATIONS")
diff --git a/Modules/Internal/FeatureTesting.cmake b/Modules/Internal/FeatureTesting.cmake
index de336e7..75be473 100644
--- a/Modules/Internal/FeatureTesting.cmake
+++ b/Modules/Internal/FeatureTesting.cmake
@@ -71,10 +71,35 @@
 
 macro(_record_compiler_features_c std)
   list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
-  _record_compiler_features(C "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+
+  get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_C${std}_KNOWN_FEATURES)
+  if(lang_level_has_features)
+    _record_compiler_features(C "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+  endif()
+  unset(lang_level_has_features)
 endmacro()
 
 macro(_record_compiler_features_cxx std)
   list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
-  _record_compiler_features(CXX "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
+
+  get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_CXX${std}_KNOWN_FEATURES)
+  if(lang_level_has_features)
+    _record_compiler_features(CXX "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
+  endif()
+  unset(lang_level_has_features)
+endmacro()
+
+macro(_has_compiler_features lang level compile_flags feature_list)
+  # presume all known features are supported
+  get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+  list(APPEND ${feature_list} ${known_features})
+endmacro()
+
+macro(_has_compiler_features_c std)
+  list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
+  _has_compiler_features(C ${std} "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+endmacro()
+macro(_has_compiler_features_cxx std)
+  list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
+  _has_compiler_features(CXX ${std} "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
 endmacro()
diff --git a/Modules/Platform/AIX-XL.cmake b/Modules/Platform/AIX-XL.cmake
index b3078ff..06a806b 100644
--- a/Modules/Platform/AIX-XL.cmake
+++ b/Modules/Platform/AIX-XL.cmake
@@ -25,4 +25,26 @@
   set(CMAKE_SHARED_MODULE_${lang}_FLAGS  " ")
 
   set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
+
+  # Find the CreateExportList program that comes with this toolchain.
+  find_program(CMAKE_XL_CreateExportList
+    NAMES CreateExportList
+    DOC "IBM XL CreateExportList tool"
+    )
+
+  # CMAKE_XL_CreateExportList is part of the AIX XL compilers but not the linux ones.
+  # If we found the tool, we'll use it to create exports, otherwise stick with the regular
+  # create shared library compile line.
+  if (CMAKE_XL_CreateExportList)
+    # The compiler front-end passes all object files, archive files, and shared
+    # library files named on the command line to CreateExportList to create a
+    # list of all symbols to be exported from the shared library.  This causes
+    # all archive members to be copied into the shared library whether they are
+    # needed or not.  Instead we run the tool ourselves to pass only the object
+    # files so that we export only the symbols actually provided by the sources.
+    set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+      "${CMAKE_XL_CreateExportList} <OBJECT_DIR>/objects.exp <OBJECTS>"
+      "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
+      )
+  endif()
 endmacro()
diff --git a/Modules/Platform/AIX-XLClang-C.cmake b/Modules/Platform/AIX-XLClang-C.cmake
new file mode 100644
index 0000000..f0bedc5
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XLClang)
+__aix_compiler_xlclang(C)
diff --git a/Modules/Platform/AIX-XLClang-CXX.cmake b/Modules/Platform/AIX-XLClang-CXX.cmake
new file mode 100644
index 0000000..cceb576
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XLClang)
+__aix_compiler_xlclang(CXX)
diff --git a/Modules/Platform/AIX-XLClang.cmake b/Modules/Platform/AIX-XLClang.cmake
new file mode 100644
index 0000000..c932095
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang.cmake
@@ -0,0 +1,15 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__AIX_COMPILER_XLCLANG)
+  return()
+endif()
+set(__AIX_COMPILER_XLCLANG 1)
+
+include(Platform/AIX-XL)
+
+macro(__aix_compiler_xlclang lang)
+  __aix_compiler_xl(${lang})
+endmacro()
diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake
index 3d69733..f08f841 100644
--- a/Modules/Platform/Android.cmake
+++ b/Modules/Platform/Android.cmake
@@ -2,9 +2,11 @@
 
 set(ANDROID 1)
 
-# Android has soname, but binary names must end in ".so" so we cannot append
-# a version number.  Also we cannot portably represent symlinks on the host.
-set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1)
+# Conventionally Android does not use versioned soname
+# But in modern versions it is acceptable
+if(NOT DEFINED CMAKE_PLATFORM_NO_VERSIONED_SONAME)
+  set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1)
+endif()
 
 # Android reportedly ignores RPATH, and we cannot predict the install
 # location anyway.
diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake
index a1a3d3f..f2aaf3f 100644
--- a/Modules/Platform/CrayLinuxEnvironment.cmake
+++ b/Modules/Platform/CrayLinuxEnvironment.cmake
@@ -1,6 +1,5 @@
-# Compute Node Linux doesn't quite work the same as native Linux so all of this
-# needs to be custom.  We use the variables defined through Cray's environment
-# modules to set up the right paths for things.
+# CrayLinuxEnvironment: loaded by users cross-compiling on a Cray front-end
+# node by specifying "-DCMAKE_SYSTEM_NAME=CrayLinuxEnvironment" to cmake
 
 set(UNIX 1)
 
@@ -30,13 +29,6 @@
 # Note: this may need to change in the future with 64-bit ARM
 set(CMAKE_SYSTEM_PROCESSOR "x86_64")
 
-set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
-set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
-set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
-set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
-
-set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
-
 # Don't override shared lib support if it's already been set and possibly
 # overridden elsewhere by the CrayPrgEnv module
 if(NOT CMAKE_FIND_LIBRARY_SUFFIXES)
@@ -44,12 +36,9 @@
   set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
 endif()
 
-set(CMAKE_DL_LIBS dl)
+# The rest of this file is based on UnixPaths.cmake, adjusted for Cray
 
-# Note: Much of this is pulled from UnixPaths.cmake but adjusted to the Cray
-# environment accordingly
-
-# Get the install directory of the running cmake to the search directories
+# add the install directory of the running cmake to the search directories
 # CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up
 get_filename_component(__cmake_install_dir "${CMAKE_ROOT}" PATH)
 get_filename_component(__cmake_install_dir "${__cmake_install_dir}" PATH)
@@ -81,7 +70,6 @@
 endif()
 
 list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
-  $ENV{SYSROOT_DIR}/usr/include
   $ENV{SYSROOT_DIR}/usr/include/X11
 )
 list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
@@ -95,57 +83,5 @@
   $ENV{SYSROOT_DIR}/lib64
 )
 
-# Compute the intersection of several lists
-function(__cray_list_intersect OUTPUT INPUT0)
-  if(ARGC EQUAL 2)
-    list(APPEND ${OUTPUT} ${${INPUT0}})
-  else()
-    foreach(I IN LISTS ${INPUT0})
-      set(__is_common 1)
-      foreach(L IN LISTS ARGN)
-        list(FIND ${L} "${I}" __idx)
-        if(__idx EQUAL -1)
-          set(__is_common 0)
-          break()
-        endif()
-      endforeach()
-      if(__is_common)
-        list(APPEND ${OUTPUT}  "${I}")
-      endif()
-    endforeach()
-  endif()
-  set(${OUTPUT} ${${OUTPUT}} PARENT_SCOPE)
-endfunction()
-
-macro(__list_clean_dupes var)
-  if(${var})
-    list(REMOVE_DUPLICATES ${var})
-  endif()
-endmacro()
-
-get_property(__langs GLOBAL PROPERTY ENABLED_LANGUAGES)
-set(__cray_inc_path_vars)
-set(__cray_lib_path_vars)
-foreach(__lang IN LISTS __langs)
-  list(APPEND __cray_inc_path_vars CMAKE_${__lang}_IMPLICIT_INCLUDE_DIRECTORIES)
-  list(APPEND __cray_lib_path_vars CMAKE_${__lang}_IMPLICIT_LINK_DIRECTORIES)
-endforeach()
-if(__cray_inc_path_vars)
-  __cray_list_intersect(__cray_implicit_include_dirs ${__cray_inc_path_vars})
-  if(__cray_implicit_include_dirs)
-    list(INSERT CMAKE_SYSTEM_INCLUDE_PATH 0 ${__cray_implicit_include_dirs})
-  endif()
-endif()
-if(__cray_lib_path_vars)
-  __cray_list_intersect(__cray_implicit_library_dirs ${__cray_lib_path_vars})
-  if(__cray_implicit_library_dirs)
-    list(INSERT CMAKE_SYSTEM_LIBRARY_PATH 0 ${__cray_implicit_library_dirs})
-  endif()
-endif()
-__list_clean_dupes(CMAKE_SYSTEM_PREFIX_PATH)
-__list_clean_dupes(CMAKE_SYSTEM_INCLUDE_PATH)
-__list_clean_dupes(CMAKE_SYSTEM_LIBRARY_PATH)
-__list_clean_dupes(CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES)
-
 # Enable use of lib64 search path variants by default.
 set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
diff --git a/Modules/Platform/GHS-MULTI-Initialize.cmake b/Modules/Platform/GHS-MULTI-Determine.cmake
similarity index 73%
rename from Modules/Platform/GHS-MULTI-Initialize.cmake
rename to Modules/Platform/GHS-MULTI-Determine.cmake
index 25004c6..349d906 100644
--- a/Modules/Platform/GHS-MULTI-Initialize.cmake
+++ b/Modules/Platform/GHS-MULTI-Determine.cmake
@@ -3,45 +3,50 @@
 
 #Setup Green Hills MULTI specific compilation information
 
-set(GHS_OS_ROOT "C:/ghs" CACHE PATH "GHS platform OS search root directory")
+if(CMAKE_HOST_UNIX)
+  set(GHS_OS_ROOT "/usr/ghs" CACHE PATH "GHS platform OS search root directory")
+else()
+  set(GHS_OS_ROOT "C:/ghs" CACHE PATH "GHS platform OS search root directory")
+endif()
 mark_as_advanced(GHS_OS_ROOT)
 
 set(GHS_OS_DIR "NOTFOUND" CACHE PATH "GHS platform OS directory")
 mark_as_advanced(GHS_OS_DIR)
 
-set(GHS_OS_DIR_OPTION "-os_dir " CACHE STRING "GHS compiler os option")
-mark_as_advanced(GHS_OS_DIR)
+set(GHS_OS_DIR_OPTION "-os_dir " CACHE STRING "GHS compiler OS option")
+mark_as_advanced(GHS_OS_DIR_OPTION)
 
 #set GHS_OS_DIR if not set by user
-if ( NOT GHS_OS_DIR )
-  if (EXISTS ${GHS_OS_ROOT})
+if(NOT GHS_OS_DIR)
+  if(EXISTS ${GHS_OS_ROOT})
 
     #get all directories in root directory
     FILE(GLOB GHS_CANDIDATE_OS_DIRS
       LIST_DIRECTORIES true RELATIVE ${GHS_OS_ROOT} ${GHS_OS_ROOT}/*)
     FILE(GLOB GHS_CANDIDATE_OS_FILES
       LIST_DIRECTORIES false RELATIVE ${GHS_OS_ROOT} ${GHS_OS_ROOT}/*)
-    if ( GHS_CANDIDATE_OS_FILES )
+    if(GHS_CANDIDATE_OS_FILES)
       list(REMOVE_ITEM GHS_CANDIDATE_OS_DIRS ${GHS_CANDIDATE_OS_FILES})
     endif ()
 
     #filter based on platform name
-    if (GHS_TARGET_PLATFORM MATCHES "integrity")
-      list(FILTER GHS_CANDIDATE_OS_DIRS INCLUDE REGEX "int[0-9][0-9][0-9][0-9a-z].*")
+    if(GHS_TARGET_PLATFORM MATCHES "integrity")
+      list(FILTER GHS_CANDIDATE_OS_DIRS INCLUDE REGEX "int[0-9][0-9][0-9][0-9a-z]")
     else() #fall-back for standalone
       unset(GHS_CANDIDATE_OS_DIRS)
       set(GHS_OS_DIR "IGNORE")
-    endif ()
+    endif()
 
-    if (GHS_CANDIDATE_OS_DIRS)
+    if(GHS_CANDIDATE_OS_DIRS)
       list(SORT GHS_CANDIDATE_OS_DIRS)
       list(GET GHS_CANDIDATE_OS_DIRS -1 GHS_OS_DIR)
       string(CONCAT GHS_OS_DIR ${GHS_OS_ROOT} "/" ${GHS_OS_DIR})
     endif()
 
+    #update cache with new value
     set(GHS_OS_DIR "${GHS_OS_DIR}" CACHE PATH "GHS platform OS directory" FORCE)
-  endif ()
-endif ()
+  endif()
+endif()
 
 set(GHS_BSP_NAME "IGNORE" CACHE STRING "BSP name")
 
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index a6448a0..df3bd1e 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -377,10 +377,12 @@
     set(CMAKE_RC_COMPILER_INIT rc)
   endif()
   if(NOT CMAKE_RC_FLAGS_INIT)
-    string(APPEND CMAKE_RC_FLAGS_INIT " ${flags}")
+    # llvm-rc fails when flags are specified with /D and no space after
+    string(REPLACE " /D" " -D" fixed_flags " ${flags}")
+    string(APPEND CMAKE_RC_FLAGS_INIT " ${fixed_flags}")
   endif()
   if(NOT CMAKE_RC_FLAGS_DEBUG_INIT)
-    string(APPEND CMAKE_RC_FLAGS_DEBUG_INIT " /D_DEBUG")
+    string(APPEND CMAKE_RC_FLAGS_DEBUG_INIT " -D_DEBUG")
   endif()
 
   enable_language(RC)
diff --git a/Modules/ProcessorCount.cmake b/Modules/ProcessorCount.cmake
index e4b4e53..8c25256 100644
--- a/Modules/ProcessorCount.cmake
+++ b/Modules/ProcessorCount.cmake
@@ -70,6 +70,20 @@
   endif()
 
   if(NOT count)
+    # Linux (systems with nproc):
+    # Prefer nproc to getconf if available as getconf may return the host CPU count in Linux containers
+    find_program(ProcessorCount_cmd_nproc nproc)
+    mark_as_advanced(ProcessorCount_cmd_nproc)
+    if(ProcessorCount_cmd_nproc)
+      execute_process(COMMAND ${ProcessorCount_cmd_nproc}
+        ERROR_QUIET
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        OUTPUT_VARIABLE count)
+      #message("ProcessorCount: trying nproc '${ProcessorCount_cmd_nproc}'")
+    endif()
+  endif()
+
+  if(NOT count)
     # Linux (systems with getconf):
     find_program(ProcessorCount_cmd_getconf getconf)
     mark_as_advanced(ProcessorCount_cmd_getconf)
diff --git a/Modules/UseQt4.cmake b/Modules/UseQt4.cmake
index dc2348e..8fec717 100644
--- a/Modules/UseQt4.cmake
+++ b/Modules/UseQt4.cmake
@@ -7,8 +7,8 @@
 
 Use Module for QT4
 
-Sets up C and C++ to use Qt 4.  It is assumed that FindQt.cmake has
-already been loaded.  See FindQt.cmake for information on how to load
+Sets up C and C++ to use Qt 4.  It is assumed that :module:`FindQt` has
+already been loaded.  See :module:`FindQt` for information on how to load
 Qt 4 into your CMake project.
 #]=======================================================================]
 
@@ -105,4 +105,3 @@
   endif ()
 
 endforeach()
-
diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake
index 21ccd7c..23d81b5 100644
--- a/Modules/WriteCompilerDetectionHeader.cmake
+++ b/Modules/WriteCompilerDetectionHeader.cmake
@@ -5,7 +5,7 @@
 WriteCompilerDetectionHeader
 ----------------------------
 
-This module provides the function write_compiler_detection_header().
+This module provides the function ``write_compiler_detection_header()``.
 
 This function can be used to generate a file suitable for preprocessor
 inclusion which contains macros to be used in source code::
diff --git a/README.rst b/README.rst
index 775463e..76783ec 100644
--- a/README.rst
+++ b/README.rst
@@ -57,21 +57,39 @@
 Run the ``bootstrap`` script you find in the source directory of CMake.
 You can use the ``--help`` option to see the supported options.
 You may use the ``--prefix=<install_prefix>`` option to specify a custom
-installation directory for CMake. You can run the ``bootstrap`` script from
-within the CMake source directory or any other build directory of your
-choice. Once this has finished successfully, run ``make`` and
-``make install``.  In summary::
+installation directory for CMake.  Once this has finished successfully,
+run ``make`` and ``make install``.
 
- $ ./bootstrap && make && sudo make install
+For example, if you simply want to build and install CMake from source,
+you can build directly in the source tree::
+
+  $ ./bootstrap && make && sudo make install
+
+Or, if you plan to develop CMake or otherwise run the test suite, create
+a separate build tree::
+
+  $ mkdir cmake-build && cd cmake-build
+  $ ../cmake-source/bootstrap && make
 
 Windows
 ^^^^^^^
 
-You need to download and install a binary release of CMake in order to build
-CMake.  You can get these releases from the `CMake Download Page`_.  Then
-proceed with the instructions below.
+There are two ways for building CMake under Windows:
+
+1. Compile with MSVC from VS 2015 or later.
+   You need to download and install a binary release of CMake.  You can get
+   these releases from the `CMake Download Page`_.  Then proceed with the
+   instructions below for `Building CMake with CMake`_.
+
+2. Bootstrap with MinGW under MSYS2.
+   Download and install `MSYS2`_.  Then install the required build tools::
+
+     $ pacman -S --needed git base-devel mingw-w64-x86_64-gcc
+
+   and bootstrap as above.
 
 .. _`CMake Download Page`: https://cmake.org/cmake/resources/software.html
+.. _`MSYS2`: https://www.msys2.org/
 
 Building CMake with CMake
 -------------------------
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1c06052..924d997 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -92,7 +92,6 @@
   ${CMAKE_ZLIB_INCLUDES}
   ${CMAKE_EXPAT_INCLUDES}
   ${CMAKE_TAR_INCLUDES}
-  ${CMAKE_COMPRESS_INCLUDES}
   ${CMake_HAIKU_INCLUDE_DIRS}
   )
 
@@ -144,6 +143,8 @@
   cmAffinity.cxx
   cmAffinity.h
   cmArchiveWrite.cxx
+  cmArgumentParser.cxx
+  cmArgumentParser.h
   cmBase32.cxx
   cmCacheManager.cxx
   cmCacheManager.h
@@ -225,6 +226,10 @@
   cmFileAPICodemodel.h
   cmFileAPICMakeFiles.cxx
   cmFileAPICMakeFiles.h
+  cmFileCopier.cxx
+  cmFileCopier.h
+  cmFileInstaller.cxx
+  cmFileInstaller.h
   cmFileLock.cxx
   cmFileLock.h
   cmFileLockPool.cxx
@@ -233,8 +238,10 @@
   cmFileLockResult.h
   cmFilePathChecksum.cxx
   cmFilePathChecksum.h
-  cmFileTimeComparison.cxx
-  cmFileTimeComparison.h
+  cmFileTime.cxx
+  cmFileTime.h
+  cmFileTimeCache.cxx
+  cmFileTimeCache.h
   cmFortranParserImpl.cxx
   cmFSPermissions.cxx
   cmFSPermissions.h
@@ -345,8 +352,8 @@
   cmQtAutoGenInitializer.h
   cmQtAutoGeneratorMocUic.cxx
   cmQtAutoGeneratorMocUic.h
-  cmQtAutoGeneratorRcc.cxx
-  cmQtAutoGeneratorRcc.h
+  cmQtAutoRcc.cxx
+  cmQtAutoRcc.h
   cmRST.cxx
   cmRST.h
   cmScriptGenerator.h
@@ -438,8 +445,6 @@
   cmCMakeMinimumRequired.h
   cmCMakePolicyCommand.cxx
   cmCMakePolicyCommand.h
-  cmCommandArgumentsHelper.cxx
-  cmCommandArgumentsHelper.h
   cmConditionEvaluator.cxx
   cmConditionEvaluator.h
   cmConfigureFileCommand.cxx
@@ -724,14 +729,6 @@
       cmVisualStudioSlnParser.cxx
       cmVisualStudioWCEPlatformParser.h
       cmVisualStudioWCEPlatformParser.cxx
-      cmGlobalGhsMultiGenerator.cxx
-      cmGlobalGhsMultiGenerator.h
-      cmLocalGhsMultiGenerator.cxx
-      cmLocalGhsMultiGenerator.h
-      cmGhsMultiTargetGenerator.cxx
-      cmGhsMultiTargetGenerator.h
-      cmGhsMultiGpj.cxx
-      cmGhsMultiGpj.h
       cmVSSetupHelper.cxx
       cmVSSetupHelper.h
       )
@@ -751,6 +748,22 @@
     )
 endif()
 
+# GHS support
+# Works only for windows and linux
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  set(SRCS ${SRCS}
+      cmGlobalGhsMultiGenerator.cxx
+      cmGlobalGhsMultiGenerator.h
+      cmLocalGhsMultiGenerator.cxx
+      cmLocalGhsMultiGenerator.h
+      cmGhsMultiTargetGenerator.cxx
+      cmGhsMultiTargetGenerator.h
+      cmGhsMultiGpj.cxx
+      cmGhsMultiGpj.h
+    )
+endif()
+
+
 # Ninja support
 set(SRCS ${SRCS}
   cmGlobalNinjaGenerator.cxx
@@ -793,7 +806,7 @@
   else()
     set(CMake_${check} 0)
   endif()
-  set_property(SOURCE cmFileTimeComparison.cxx APPEND PROPERTY
+  set_property(SOURCE cmFileTime.cxx APPEND PROPERTY
     COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}})
 endforeach()
 
@@ -801,7 +814,7 @@
 add_library(CMakeLib ${SRCS})
 target_link_libraries(CMakeLib cmsys
   ${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
-  ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
+  ${CMAKE_TAR_LIBRARIES}
   ${CMAKE_CURL_LIBRARIES}
   ${CMAKE_JSONCPP_LIBRARIES}
   ${CMAKE_LIBUV_LIBRARIES}
@@ -1060,9 +1073,6 @@
 endif()
 
 if(APPLE)
-  add_executable(cmakexbuild cmakexbuild.cxx)
-  list(APPEND _tools cmakexbuild)
-  target_link_libraries(cmakexbuild CMakeLib)
   add_executable(OSXScriptLauncher
     CPack/OSXScriptLauncher.cxx)
   target_link_libraries(OSXScriptLauncher cmsys)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 0a264b9..636d332 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 14)
-set(CMake_VERSION_PATCH 1)
-#set(CMake_VERSION_RC 0)
+set(CMake_VERSION_PATCH 20190416)
+#set(CMake_VERSION_RC 1)
diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in
index 22b4a36..762d9bb 100644
--- a/Source/CMakeVersion.rc.in
+++ b/Source/CMakeVersion.rc.in
@@ -1,25 +1,16 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
 
-#define VER_FILEVERSION             @CMake_RCVERSION@
-#define VER_FILEVERSION_STR         "@CMake_RCVERSION_STR@\0"
-
-#define VER_PRODUCTVERSION          @CMake_RCVERSION@
-#define VER_PRODUCTVERSION_STR      "@CMake_RCVERSION_STR@\0"
-
-/* Version-information resource identifier.  */
-#define VS_VERSION_INFO 1
-
-VS_VERSION_INFO VERSIONINFO
-FILEVERSION    	VER_FILEVERSION
-PRODUCTVERSION 	VER_PRODUCTVERSION
+1               VERSIONINFO
+FILEVERSION     @CMake_RCVERSION@
+PRODUCTVERSION  @CMake_RCVERSION@
 BEGIN
     BLOCK "StringFileInfo"
     BEGIN
         BLOCK "040904E4"
         BEGIN
-            VALUE "FileVersion",      VER_FILEVERSION_STR
-            VALUE "ProductVersion",   VER_PRODUCTVERSION_STR
+            VALUE "FileVersion",      "@CMake_RCVERSION_STR@\0"
+            VALUE "ProductVersion",   "@CMake_RCVERSION_STR@\0"
         END
     END
 
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index 9102e3e..c1b6eea 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -85,8 +85,8 @@
     int retVal = 1;
     cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl);
     bool res = cmSystemTools::RunSingleCommand(
-      ifwCmd.c_str(), &output, &output, &retVal, nullptr,
-      this->GeneratorVerbose, cmDuration::zero());
+      ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+      cmDuration::zero());
     if (!res || retVal) {
       cmGeneratedFileStream ofs(ifwTmpFile);
       ofs << "# Run command: " << ifwCmd << std::endl
@@ -198,8 +198,8 @@
     int retVal = 1;
     cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl);
     bool res = cmSystemTools::RunSingleCommand(
-      ifwCmd.c_str(), &output, &output, &retVal, nullptr,
-      this->GeneratorVerbose, cmDuration::zero());
+      ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+      cmDuration::zero());
     if (!res || retVal) {
       cmGeneratedFileStream ofs(ifwTmpFile);
       ofs << "# Run command: " << ifwCmd << std::endl
diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx
index 4966d09..00d272c 100644
--- a/Source/CPack/OSXScriptLauncher.cxx
+++ b/Source/CPack/OSXScriptLauncher.cxx
@@ -73,7 +73,7 @@
   args.push_back(nullptr);
 
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*args.begin());
+  cmsysProcess_SetCommand(cp, args.data());
   cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str());
   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
   cmsysProcess_SetTimeout(cp, 0);
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index 398ebd3..045d93d 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -61,9 +61,8 @@
   std::string output;
 
   int returnValue = 0;
-  bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output,
-                                                &output, &returnValue, 0,
-                                                cmSystemTools::OUTPUT_NONE);
+  bool status = cmSystemTools::RunSingleCommand(
+    command, &output, &output, &returnValue, 0, cmSystemTools::OUTPUT_NONE);
 
   cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
   logFile << command << std::endl;
@@ -619,7 +618,7 @@
 
   std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
 
-  if (!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath.c_str())) {
+  if (!ConfigureFile(wixTemplate, mainSourceFilePath)) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Failed creating '" << mainSourceFilePath
                                       << "'' from template." << std::endl);
diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt
deleted file mode 100644
index 1aaf9af..0000000
--- a/Source/CPack/bills-comments.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-cpack.cxx
-
-cmCPackGenerators  -- creates cmCPackGenericGenerator's via NewGenerator
-  - a cmCPackGenericGenerator factory
-
-
-cmCPackGenericGenerator::Initialize
-   this->InitializeInternal
-     CPACK_INCLUDE_TOPLEVEL_DIRECTORY = 0 turns off
-
-
-// binary package run
-cmCPackGenericGenerator::ProcessGenerator   // DoPackage
-  cmCPackGenericGenerator::PrepareNames  -- sets a bunch of CPACK_vars
-  cmCPackGenericGenerator::InstallProject
-     run preinstall  (make preinstall/fast)
-     call ReadListFile(cmake_install.cmake)
-  glob recurse in install directory to get list of files
-     this->CompressFiles with the list of files
-
-
-// source package run
-cmCPackGenericGenerator::ProcessGenerator   // DoPackage
-  cmCPackGenericGenerator::PrepareNames  -- sets a bunch of CPACK_vars
-  cmCPackGenericGenerator::InstallProject  -->
-     if set CPACK_INSTALLED_DIRECTORIES
-        glob the files in that directory
-        copy those files to the tmp install directory _CPack something
-  glob recurse in install directory to get list of files
-     this->CompressFiles with the list of files
-
-
-cmCPackGenericGenerator::InstallProject is used for both source and binary
-packages.  It is controlled based on values set in CPACK_ variables.
-
-
-InstallProject
-   1. CPACK_INSTALL_COMMANDS       - a list of commands used to install the package
-
-   2. CPACK_INSTALLED_DIRECTORIES  - copy this directory to CPACK_TEMPORARY_DIRECTORY
-
-   3. CPACK_INSTALL_CMAKE_PROJECTS - a cmake install script
-         - run make preinstall
-         - run cmake_install.cmake
-             - set CMAKE_INSTALL_PREFIX to the temp directory
-             - CPACK_BUILD_CONFIG check this and set the BUILD_TYPE to it
-              - ReadListFile on the install script  cmake_install.cmake
-         - run strip on the executables and libraries if CPACK_STRIP_FILES is TRUE
-
-Recommendations:
-
-rename cmCPackGenerators  to cmCPackGeneratorFactory
-
-rename cmCPackGenericGenerator  -->  cmCPackGenerator
-
-rename cmCPackGenericGenerator::ProcessGenerator  -> cmCPackGenerator::DoPackage
-
-
-break up cmCPackGenerator::InstallProject so it calls the following:
-
-// run user provided install commands
-  cmCPackGenerator::RunInstallCommands();
-// copy entire directories that need no processing like source trees
-  cmCPackGenerator::CopyPreInstalledDirectories();
-// run the cmake install scripts if provided
-  cmCPackGenerator::RunCMakeInstallScripts()
-
--
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
index 2119f78..49a9f15 100644
--- a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
@@ -44,10 +44,9 @@
   // to create the file before the super class is called
   {
     cmGeneratedFileStream ofs(manifestFile.c_str());
-    for (std::vector<std::string>::const_iterator i = files.begin();
-         i != files.end(); ++i) {
+    for (std::string const& file : files) {
       // remove the temp dir and replace with /usr
-      ofs << (*i).substr(tempdir.size()) << "\n";
+      ofs << file.substr(tempdir.size()) << "\n";
     }
     ofs << manifest << "\n";
   }
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 635de49..cfb5efd 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -195,7 +195,7 @@
       // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
       // should not add XXX/application
       orderedFiles.insert(currentPath);
-      currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
+      currentPath = cmSystemTools::CollapseFullPath("..", currentPath);
     }
   }
 
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 013ad81..7a3742b 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -244,8 +244,8 @@
   int exit_code = 1;
 
   bool result = cmSystemTools::RunSingleCommand(
-    command.str().c_str(), output, output, &exit_code, nullptr,
-    this->GeneratorVerbose, cmDuration::zero());
+    command.str(), output, output, &exit_code, nullptr, this->GeneratorVerbose,
+    cmDuration::zero());
 
   if (!result || exit_code) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index fcf8af1..9fdafa4 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -181,7 +181,7 @@
   {
     s << "{\n";
     for (std::string const& elem : value) {
-      s << "  \"" << elem << "\": {\"origin\": \"" << elem << "\"},\n";
+      s << "  \"" << elem << R"(": {"origin": ")" << elem << "\"},\n";
     }
     s << '}';
   }
@@ -325,8 +325,7 @@
                              ONE_PACKAGE_PER_COMPONENT);
   }
 
-  std::string output_dir =
-    cmSystemTools::CollapseCombinedPath(toplevel, "../");
+  std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
   pkg_create_from_manifest(output_dir.c_str(), ::TXZ, toplevel.c_str(),
                            manifestname.c_str(), nullptr);
 
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 57c0545..127bcf9 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -43,7 +43,8 @@
   this->MakefileMap = nullptr;
 }
 
-void cmCPackGenerator::DisplayVerboseOutput(const char* msg, float progress)
+void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg,
+                                            float progress)
 {
   (void)progress;
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
@@ -278,7 +279,7 @@
       std::string output;
       int retVal = 1;
       bool resB = cmSystemTools::RunSingleCommand(
-        ic.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+        ic, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
         cmDuration::zero());
       if (!resB || retVal) {
         std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
@@ -387,8 +388,7 @@
         }
         /* If it is not a symlink then do a plain copy */
         else if (!(cmSystemTools::CopyFileIfDifferent(inFile, filePath) &&
-                   cmSystemTools::CopyFileTime(inFile.c_str(),
-                                               filePath.c_str()))) {
+                   cmSystemTools::CopyFileTime(inFile, filePath))) {
           cmCPackLogger(cmCPackLog::LOG_ERROR,
                         "Problem copying file: " << inFile << " -> "
                                                  << filePath << std::endl);
@@ -647,8 +647,8 @@
     std::string output;
     int retVal = 1;
     bool resB = cmSystemTools::RunSingleCommand(
-      buildCommand.c_str(), &output, &output, &retVal,
-      installDirectory.c_str(), this->GeneratorVerbose, cmDuration::zero());
+      buildCommand, &output, &output, &retVal, installDirectory.c_str(),
+      this->GeneratorVerbose, cmDuration::zero());
     if (!resB || retVal) {
       std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
       tmpFile += "/PreinstallOutput.log";
@@ -689,7 +689,7 @@
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cm.AddCMakePaths();
-  cm.SetProgressCallback([this](const char* msg, float prog) {
+  cm.SetProgressCallback([this](const std::string& msg, float prog) {
     this->DisplayVerboseOutput(msg, prog);
   });
   cm.SetTrace(this->Trace);
@@ -1245,7 +1245,8 @@
   return true;
 }
 
-bool cmCPackGenerator::ConfigureFile(const char* inName, const char* outName,
+bool cmCPackGenerator::ConfigureFile(const std::string& inName,
+                                     const std::string& outName,
                                      bool copyOnly /* = false */)
 {
   return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
@@ -1254,9 +1255,8 @@
 
 int cmCPackGenerator::CleanTemporaryDirectory()
 {
-  std::string tempInstallDirectoryWithPostfix =
+  std::string tempInstallDirectory =
     this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
-  const char* tempInstallDirectory = tempInstallDirectoryWithPostfix.c_str();
   if (cmsys::SystemTools::FileExists(tempInstallDirectory)) {
     cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                   "- Clean temporary : " << tempInstallDirectory << std::endl);
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 4755f94..3c06d41 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -96,7 +96,7 @@
   void SetLogger(cmCPackLog* log) { this->Logger = log; }
 
   //! Display verbose information via logger
-  void DisplayVerboseOutput(const char* msg, float progress);
+  void DisplayVerboseOutput(const std::string& msg, float progress);
 
   bool ReadListFile(const char* moduleName);
 
@@ -169,7 +169,8 @@
   virtual const char* GetPackagingInstallPrefix();
 
   virtual std::string FindTemplate(const char* name);
-  virtual bool ConfigureFile(const char* inName, const char* outName,
+  virtual bool ConfigureFile(const std::string& inName,
+                             const std::string& outName,
                              bool copyOnly = false);
   virtual bool ConfigureString(const std::string& input, std::string& output);
   virtual int InitializeInternal();
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
index 7f633e4..972f0f7 100644
--- a/Source/CPack/cmCPackGeneratorFactory.h
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -22,6 +22,9 @@
   cmCPackGeneratorFactory();
   ~cmCPackGeneratorFactory();
 
+  cmCPackGeneratorFactory(const cmCPackGeneratorFactory&) = delete;
+  cmCPackGeneratorFactory& operator=(const cmCPackGeneratorFactory&) = delete;
+
   //! Get the generator
   cmCPackGenerator* NewGenerator(const std::string& name);
   void DeleteGenerator(cmCPackGenerator* gen);
diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h
index 8e99221..65281e3 100644
--- a/Source/CPack/cmCPackLog.h
+++ b/Source/CPack/cmCPackLog.h
@@ -26,6 +26,9 @@
   cmCPackLog();
   ~cmCPackLog();
 
+  cmCPackLog(const cmCPackLog&) = delete;
+  cmCPackLog& operator=(const cmCPackLog&) = delete;
+
   enum __log_tags
   {
     NOTAG = 0,
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 37ea66e..e2020c5 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -182,7 +182,7 @@
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC", "");
     this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS", "");
     this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL",
-                            "File /r \"${INST_DIR}\\*.*\"");
+                            R"(File /r "${INST_DIR}\*.*")");
     this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", "");
     this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", "");
     this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS", "");
@@ -242,7 +242,7 @@
       }
 
       // Add this component to the various section lists.
-      sectionList += "  !insertmacro \"${MacroName}\" \"";
+      sectionList += R"(  !insertmacro "${MacroName}" ")";
       sectionList += comp.first;
       sectionList += "\"\n";
       selectedVarsList += "Var " + comp.first + "_selected\n";
@@ -292,9 +292,8 @@
     this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
   }
 
-  this->ConfigureFile(nsisInInstallOptions.c_str(),
-                      nsisInstallOptions.c_str());
-  this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
+  this->ConfigureFile(nsisInInstallOptions, nsisInstallOptions);
+  this->ConfigureFile(nsisInFileName, nsisFileName);
   std::string nsisCmd = "\"";
   nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
   nsisCmd += "\" \"" + nsisFileName + "\"";
@@ -302,8 +301,8 @@
   std::string output;
   int retVal = 1;
   bool res = cmSystemTools::RunSingleCommand(
-    nsisCmd.c_str(), &output, &output, &retVal, nullptr,
-    this->GeneratorVerbose, cmDuration::zero());
+    nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+    cmDuration::zero());
   if (!res || retVal) {
     cmGeneratedFileStream ofs(tmpFile);
     ofs << "# Run command: " << nsisCmd << std::endl
@@ -407,8 +406,8 @@
   std::string output;
   int retVal = 1;
   bool resS = cmSystemTools::RunSingleCommand(
-    nsisCmd.c_str(), &output, &output, &retVal, nullptr,
-    this->GeneratorVerbose, cmDuration::zero());
+    nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+    cmDuration::zero());
   cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
   cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
   if (!resS || retVal ||
@@ -495,10 +494,10 @@
       std::string execName = *it;
       ++it;
       std::string linkName = *it;
-      str << "  CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
-          << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+      str << R"(  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+          << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
           << execName << ".exe\"" << std::endl;
-      deleteStr << "  Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+      deleteStr << R"(  Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
                 << ".lnk\"" << std::endl;
       // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
       // if so add a desktop link
@@ -508,7 +507,7 @@
                     execName) != cpackPackageDesktopLinksVector.end()) {
         str << "  StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
         str << "    CreateShortCut \"$DESKTOP\\" << linkName
-            << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+            << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
             << execName << ".exe\"" << std::endl;
         deleteStr << "  StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
         deleteStr << "    Delete \"$DESKTOP\\" << linkName << ".lnk\""
@@ -564,15 +563,15 @@
     ++it;
     std::string linkName = *it;
     if (!url) {
-      str << "  CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
-          << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
-      deleteStr << "  Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+      str << R"(  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+          << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
+      deleteStr << R"(  Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
                 << ".lnk\"" << std::endl;
     } else {
-      str << "  WriteINIStr \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
-          << ".url\" \"InternetShortcut\" \"URL\" \"" << sourceName << "\""
+      str << R"(  WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+          << R"(.url" "InternetShortcut" "URL" ")" << sourceName << "\""
           << std::endl;
-      deleteStr << "  Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+      deleteStr << R"(  Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
                 << ".url\"" << std::endl;
     }
     // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
@@ -582,7 +581,7 @@
     if (this->IsSet(desktop)) {
       str << "  StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
       str << "    CreateShortCut \"$DESKTOP\\" << linkName
-          << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+          << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
       deleteStr << "  StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
       deleteStr << "    Delete \"$DESKTOP\\" << linkName << ".lnk\""
                 << std::endl;
@@ -749,7 +748,7 @@
     std::string output;
     int retVal = -1;
     int res = cmSystemTools::RunSingleCommand(
-      cmd.c_str(), &output, &output, &retVal, dirName.c_str(),
+      cmd, &output, &output, &retVal, dirName.c_str(),
       cmSystemTools::OUTPUT_NONE, cmDuration::zero());
     if (!res || retVal) {
       std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
index 486633c..90e0afe 100644
--- a/Source/CPack/cmCPackOSXX11Generator.cxx
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -83,7 +83,7 @@
       return 0;
     }
     std::string destFileName = resourcesDirectory + "/" + iconFileName;
-    this->ConfigureFile(iconFile, destFileName.c_str(), true);
+    this->ConfigureFile(iconFile, destFileName, true);
     this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
   }
 
@@ -155,8 +155,8 @@
   bool res = false;
   while (numTries > 0) {
     res = cmSystemTools::RunSingleCommand(
-      dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
-      this->GeneratorVerbose, cmDuration::zero());
+      dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+      cmDuration::zero());
     if (res && !retVal) {
       numTries = -1;
       break;
@@ -236,7 +236,7 @@
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
                 << (inFileName ? inFileName : "(NULL)")
                 << " to " << destFileName << std::endl);
-  this->ConfigureFile(inFileName, destFileName.c_str());
+  this->ConfigureFile(inFileName, destFileName);
   return true;
 }
 */
@@ -266,7 +266,7 @@
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "Configure file: " << inFileName << " to " << destFileName
                                    << std::endl);
-  this->ConfigureFile(inFileName.c_str(), destFileName.c_str(), copyOnly);
+  this->ConfigureFile(inFileName, destFileName, copyOnly);
   return true;
 }
 
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
index ae227aa..8c22c65 100644
--- a/Source/CPack/cmCPackPKGGenerator.cxx
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -66,21 +66,17 @@
   xout.StartElement("choices-outline");
 
   // Emit the outline for the groups
-  std::map<std::string, cmCPackComponentGroup>::iterator groupIt;
-  for (groupIt = this->ComponentGroups.begin();
-       groupIt != this->ComponentGroups.end(); ++groupIt) {
-    if (groupIt->second.ParentGroup == nullptr) {
-      CreateChoiceOutline(groupIt->second, xout);
+  for (auto const& group : this->ComponentGroups) {
+    if (group.second.ParentGroup == nullptr) {
+      CreateChoiceOutline(group.second, xout);
     }
   }
 
   // Emit the outline for the non-grouped components
-  std::map<std::string, cmCPackComponent>::iterator compIt;
-  for (compIt = this->Components.begin(); compIt != this->Components.end();
-       ++compIt) {
-    if (!compIt->second.Group) {
+  for (auto const& comp : this->Components) {
+    if (!comp.second.Group) {
       xout.StartElement("line");
-      xout.Attribute("choice", compIt->first + "Choice");
+      xout.Attribute("choice", comp.first + "Choice");
       xout.Content(""); // Avoid self-closing tag.
       xout.EndElement();
     }
@@ -94,13 +90,11 @@
   xout.EndElement(); // choices-outline>
 
   // Create the actual choices
-  for (groupIt = this->ComponentGroups.begin();
-       groupIt != this->ComponentGroups.end(); ++groupIt) {
-    CreateChoice(groupIt->second, xout);
+  for (auto const& group : this->ComponentGroups) {
+    CreateChoice(group.second, xout);
   }
-  for (compIt = this->Components.begin(); compIt != this->Components.end();
-       ++compIt) {
-    CreateChoice(compIt->second, xout);
+  for (auto const& comp : this->Components) {
+    CreateChoice(comp.second, xout);
   }
 
   if (!this->PostFlightComponent.Name.empty()) {
@@ -111,7 +105,7 @@
 
   // Create the distribution.dist file in the metapackage to turn it
   // into a distribution package.
-  this->ConfigureFile(distributionTemplate.c_str(), distributionFile.c_str());
+  this->ConfigureFile(distributionTemplate, distributionFile);
 }
 
 void cmCPackPKGGenerator::CreateChoiceOutline(
@@ -119,17 +113,13 @@
 {
   xout.StartElement("line");
   xout.Attribute("choice", group.Name + "Choice");
-  std::vector<cmCPackComponentGroup*>::const_iterator groupIt;
-  for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();
-       ++groupIt) {
-    CreateChoiceOutline(**groupIt, xout);
+  for (cmCPackComponentGroup* subgroup : group.Subgroups) {
+    CreateChoiceOutline(*subgroup, xout);
   }
 
-  std::vector<cmCPackComponent*>::const_iterator compIt;
-  for (compIt = group.Components.begin(); compIt != group.Components.end();
-       ++compIt) {
+  for (cmCPackComponent* comp : group.Components) {
     xout.StartElement("line");
-    xout.Attribute("choice", (*compIt)->Name + "Choice");
+    xout.Attribute("choice", comp->Name + "Choice");
     xout.Content(""); // Avoid self-closing tag.
     xout.EndElement();
   }
@@ -238,11 +228,9 @@
   }
   visited.insert(&component);
 
-  std::vector<cmCPackComponent*>::const_iterator dependIt;
-  for (dependIt = component.Dependencies.begin();
-       dependIt != component.Dependencies.end(); ++dependIt) {
-    out << " && choices['" << (*dependIt)->Name << "Choice'].selected";
-    AddDependencyAttributes(**dependIt, visited, out);
+  for (cmCPackComponent* depend : component.Dependencies) {
+    out << " && choices['" << depend->Name << "Choice'].selected";
+    AddDependencyAttributes(*depend, visited, out);
   }
 }
 
@@ -255,11 +243,9 @@
   }
   visited.insert(&component);
 
-  std::vector<cmCPackComponent*>::const_iterator dependIt;
-  for (dependIt = component.ReverseDependencies.begin();
-       dependIt != component.ReverseDependencies.end(); ++dependIt) {
-    out << " || choices['" << (*dependIt)->Name << "Choice'].selected";
-    AddReverseDependencyAttributes(**dependIt, visited, out);
+  for (cmCPackComponent* depend : component.ReverseDependencies) {
+    out << " || choices['" << depend->Name << "Choice'].selected";
+    AddReverseDependencyAttributes(*depend, visited, out);
   }
 }
 
@@ -308,7 +294,7 @@
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "Configure file: " << (inFileName ? inFileName : "(NULL)")
                                    << " to " << destFileName << std::endl);
-  this->ConfigureFile(inFileName, destFileName.c_str());
+  this->ConfigureFile(inFileName, destFileName);
   return true;
 }
 
@@ -336,7 +322,7 @@
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "Configure file: " << inFileName << " to " << destFileName
                                    << std::endl);
-  this->ConfigureFile(inFileName.c_str(), destFileName.c_str());
+  this->ConfigureFile(inFileName, destFileName);
   return true;
 }
 
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
index 246178d..3d93c48 100644
--- a/Source/CPack/cmCPackPackageMakerGenerator.cxx
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -295,8 +295,8 @@
   bool res = false;
   while (numTries > 0) {
     res = cmSystemTools::RunSingleCommand(
-      dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
-      this->GeneratorVerbose, cmDuration::zero());
+      dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+      cmDuration::zero());
     if (res && !retVal) {
       numTries = -1;
       break;
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
index a556e0c..94b5b5f 100644
--- a/Source/CPack/cmCPackProductBuildGenerator.cxx
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -145,8 +145,8 @@
   std::string output;
   int retVal = 1;
   bool res = cmSystemTools::RunSingleCommand(
-    command.c_str(), &output, &output, &retVal, nullptr,
-    this->GeneratorVerbose, cmDuration::zero());
+    command, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+    cmDuration::zero());
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
   if (!res || retVal) {
     cmGeneratedFileStream ofs(tmpFile);
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 0413422..3ceb824 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -82,7 +82,7 @@
     return 0;
   }
   std::string key = value.substr(0, pos);
-  value = value.c_str() + pos + 1;
+  value = value.substr(pos + 1);
   def->Map[key] = value;
   cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
               "Set CPack variable: " << key << " to \"" << value << "\""
@@ -90,7 +90,7 @@
   return 1;
 }
 
-static void cpackProgressCallback(const char* message, float /*unused*/)
+static void cpackProgressCallback(const std::string& message, float /*unused*/)
 {
   std::cout << "-- " << message << std::endl;
 }
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index b154caf..83aeb64 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -365,7 +365,7 @@
   if (opts.empty()) {
     opts = this->CTest->GetCTestConfiguration("BZRUpdateOptions");
   }
-  std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 
   // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
 
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 2fd4c7a..9ad9669 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -118,7 +118,7 @@
     : CM(cm)
   {
     cmSystemTools::SetMessageCallback(
-      [&s](const char* msg, const char* /*unused*/) {
+      [&s](const std::string& msg, const char* /*unused*/) {
         s += msg;
         s += "\n";
       });
@@ -126,9 +126,11 @@
     cmSystemTools::SetStdoutCallback([&s](std::string const& m) { s += m; });
     cmSystemTools::SetStderrCallback([&s](std::string const& m) { s += m; });
 
-    this->CM.SetProgressCallback([&s](const char* msg, float /*unused*/) {
-      s += msg;
-      s += "\n";
+    this->CM.SetProgressCallback([&s](const std::string& msg, float prog) {
+      if (prog < 0) {
+        s += msg;
+        s += "\n";
+      }
     });
   }
 
@@ -139,6 +141,11 @@
     cmSystemTools::SetStdoutCallback(nullptr);
     cmSystemTools::SetMessageCallback(nullptr);
   }
+
+  cmCTestBuildAndTestCaptureRAII(const cmCTestBuildAndTestCaptureRAII&) =
+    delete;
+  cmCTestBuildAndTestCaptureRAII& operator=(
+    const cmCTestBuildAndTestCaptureRAII&) = delete;
 };
 
 int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
@@ -250,7 +257,7 @@
     }
     int retVal = cm.GetGlobalGenerator()->Build(
       cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
-      this->BuildProject, tar, output, this->BuildMakeProgram, config,
+      this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
       !this->BuildNoClean, false, false, remainingTime);
     out << output;
     // if the build failed then return
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
index 5e6d0aa..2d47b15 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.h
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -44,7 +44,7 @@
   void Initialize() override;
 
 protected:
-  ///! Run CMake and build a test and then run it as a single test.
+  //! Run CMake and build a test and then run it as a single test.
   int RunCMakeAndTest(std::string* output);
   int RunCMake(std::string* outstring, std::ostringstream& out,
                std::string& cmakeOutString, cmake* cm);
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 32f7496..2eacaf1 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -4,7 +4,6 @@
 
 #include "cmCTest.h"
 #include "cmCTestBuildHandler.h"
-#include "cmCTestGenericHandler.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -39,12 +38,10 @@
 
 cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
 {
-  cmCTestGenericHandler* handler = this->CTest->GetInitializedHandler("build");
-  if (!handler) {
-    this->SetError("internal CTest error. Cannot instantiate build handler");
-    return nullptr;
-  }
-  this->Handler = static_cast<cmCTestBuildHandler*>(handler);
+  cmCTestBuildHandler* handler = this->CTest->GetBuildHandler();
+  handler->Initialize();
+
+  this->Handler = handler;
 
   const char* ctestBuildCommand =
     this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index d934c00..1e17e1c 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -5,7 +5,7 @@
 #include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmDuration.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
 #include "cmGeneratedFileStream.h"
 #include "cmMakefile.h"
 #include "cmProcessOutput.h"
@@ -32,13 +32,13 @@
   "^Error: ",
   "^Error ",
   "[0-9] ERROR: ",
-  "^\"[^\"]+\", line [0-9]+: [^Ww]",
+  R"(^"[^"]+", line [0-9]+: [^Ww])",
   "^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
   "^ld([^:])*:([ \\t])*ERROR([^:])*:",
-  "^ild:([ \\t])*\\(undefined symbol\\)",
+  R"(^ild:([ \t])*\(undefined symbol\))",
   "([^ :]+) : (error|fatal error|catastrophic error)",
   "([^:]+): (Error:|error|undefined reference|multiply defined)",
-  "([^:]+)\\(([^\\)]+)\\) ?: (error|fatal error|catastrophic error)",
+  R"(([^:]+)\(([^\)]+)\) ?: (error|fatal error|catastrophic error))",
   "^fatal error C[0-9]+:",
   ": syntax error ",
   "^collect2: ld returned 1 exit status",
@@ -50,14 +50,14 @@
   "^CMake Error.*:",
   ":[ \\t]cannot find",
   ":[ \\t]can't find",
-  ": \\*\\*\\* No rule to make target [`'].*\\'.  Stop",
-  ": \\*\\*\\* No targets specified and no makefile found",
+  R"(: \*\*\* No rule to make target [`'].*\'.  Stop)",
+  R"(: \*\*\* No targets specified and no makefile found)",
   ": Invalid loader fixup for symbol",
   ": Invalid fixups exist",
   ": Can't find library for",
   ": internal link edit command failed",
   ": Unrecognized option [`'].*\\'",
-  "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([^WI]\\)",
+  R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([^WI]\))",
   "ld: 0706-006 Cannot find or open library file: -l ",
   "ild: \\(argument error\\) can't find library argument ::",
   "^could not be found and will not be loaded.",
@@ -66,11 +66,11 @@
   "ld: 0711-993 Error occurred while writing to the output file:",
   "ld: fatal: ",
   "final link failed:",
-  "make: \\*\\*\\*.*Error",
-  "make\\[.*\\]: \\*\\*\\*.*Error",
-  "\\*\\*\\* Error code",
+  R"(make: \*\*\*.*Error)",
+  R"(make\[.*\]: \*\*\*.*Error)",
+  R"(\*\*\* Error code)",
   "nternal error:",
-  "Makefile:[0-9]+: \\*\\*\\* .*  Stop\\.",
+  R"(Makefile:[0-9]+: \*\*\* .*  Stop\.)",
   ": No such file or directory",
   ": Invalid argument",
   "^The project cannot be built\\.",
@@ -101,19 +101,19 @@
   "^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
   "^ld([^:])*:([ \\t])*WARNING([^:])*:",
   "([^:]+): warning ([0-9]+):",
-  "^\"[^\"]+\", line [0-9]+: [Ww](arning|arnung)",
+  R"(^"[^"]+", line [0-9]+: [Ww](arning|arnung))",
   "([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
   "^(Warning|Warnung) ([0-9]+):",
   "^(Warning|Warnung)[ :]",
   "WARNING: ",
   "([^ :]+) : warning",
   "([^:]+): warning",
-  "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([WI]\\)",
+  R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([WI]\))",
   "^cxx: Warning:",
   ".*file: .* has no symbols",
   "([^ :]+):([0-9]+): (Warning|Warnung)",
   "\\([0-9]*\\): remark #[0-9]*",
-  "\".*\", line [0-9]+: remark\\([0-9]*\\):",
+  R"(".*", line [0-9]+: remark\([0-9]*\):)",
   "cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
   "^CMake Warning.*:",
   "^\\[WARNING\\]",
@@ -121,9 +121,9 @@
 };
 
 static const char* cmCTestWarningExceptions[] = {
-  "/usr/.*/X11/Xlib\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
-  "/usr/.*/X11/Xutil\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
-  "/usr/.*/X11/XResource\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
+  R"(/usr/.*/X11/Xlib\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+  R"(/usr/.*/X11/Xutil\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+  R"(/usr/.*/X11/XResource\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
   "WARNING 84 :",
   "WARNING 47 :",
   "makefile:",
@@ -150,8 +150,8 @@
 static cmCTestBuildCompileErrorWarningRex cmCTestWarningErrorFileLine[] = {
   { "^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):", 1, 2 },
   { "^([a-zA-Z./0-9_+ ~-]+):([0-9]+):", 1, 2 },
-  { "^([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
-  { "^[0-9]+>([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+  { R"(^([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
+  { R"(^[0-9]+>([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
   { "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
   { "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 },
   { "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 },
@@ -387,7 +387,7 @@
     std::string srcdirrep;
     for (cc = srcdir.size() - 2; cc > 0; cc--) {
       if (srcdir[cc] == '/') {
-        srcdirrep = srcdir.c_str() + cc;
+        srcdirrep = srcdir.substr(cc);
         srcdirrep = "/..." + srcdirrep;
         srcdir = srcdir.substr(0, cc + 1);
         break;
@@ -401,7 +401,7 @@
     std::string bindirrep;
     for (cc = bindir.size() - 2; cc > 0; cc--) {
       if (bindir[cc] == '/') {
-        bindirrep = bindir.c_str() + cc;
+        bindirrep = bindir.substr(cc);
         bindirrep = "/..." + bindirrep;
         bindir = bindir.substr(0, cc + 1);
         break;
@@ -418,8 +418,8 @@
   int retVal = 0;
   int res = cmsysProcess_State_Exited;
   if (!this->CTest->GetShowOnly()) {
-    res = this->RunMakeCommand(makeCommand.c_str(), &retVal,
-                               buildDirectory.c_str(), 0, ofs);
+    res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
+                               ofs);
   } else {
     cmCTestOptionalLog(this->CTest, DEBUG,
                        "Build with command: " << makeCommand << std::endl,
@@ -503,7 +503,7 @@
 class cmCTestBuildHandler::FragmentCompare
 {
 public:
-  FragmentCompare(cmFileTimeComparison* ftc)
+  FragmentCompare(cmFileTimeCache* ftc)
     : FTC(ftc)
   {
   }
@@ -513,14 +513,14 @@
     // Order files by modification time.  Use lexicographic order
     // among files with the same time.
     int result;
-    if (this->FTC->FileTimeCompare(l, r, &result) && result != 0) {
+    if (this->FTC->Compare(l, r, &result) && result != 0) {
       return result < 0;
     }
     return l < r;
   }
 
 private:
-  cmFileTimeComparison* FTC = nullptr;
+  cmFileTimeCache* FTC = nullptr;
 };
 
 void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
@@ -530,7 +530,7 @@
   }
 
   // Sort XML fragments in chronological order.
-  cmFileTimeComparison ftc;
+  cmFileTimeCache ftc;
   FragmentCompare fragmentCompare(&ftc);
   typedef std::set<std::string, FragmentCompare> Fragments;
   Fragments fragments(fragmentCompare);
@@ -680,6 +680,8 @@
 public:
   LaunchHelper(cmCTestBuildHandler* handler);
   ~LaunchHelper();
+  LaunchHelper(const LaunchHelper&) = delete;
+  LaunchHelper& operator=(const LaunchHelper&) = delete;
 
 private:
   cmCTestBuildHandler* Handler;
@@ -764,9 +766,10 @@
   }
 }
 
-int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
-                                        const char* dir, int timeout,
-                                        std::ostream& ofs, Encoding encoding)
+int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
+                                        int* retVal, const char* dir,
+                                        int timeout, std::ostream& ofs,
+                                        Encoding encoding)
 {
   // First generate the command and arguments
   std::vector<std::string> args = cmSystemTools::ParseArguments(command);
@@ -800,7 +803,7 @@
 
   // Now create process object
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
+  cmsysProcess_SetCommand(cp, argv.data());
   cmsysProcess_SetWorkingDirectory(cp, dir);
   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
   cmsysProcess_SetTimeout(cp, timeout);
@@ -978,7 +981,7 @@
       this->CurrentProcessingLine.insert(this->CurrentProcessingLine.end(),
                                          queue->begin(), it);
       this->CurrentProcessingLine.push_back(0);
-      const char* line = &*this->CurrentProcessingLine.begin();
+      const char* line = this->CurrentProcessingLine.data();
 
       // Process the line
       int lineType = this->ProcessSingleLine(line);
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index a9b121b..722c590 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -52,7 +52,7 @@
 
   //! Run command specialized for make and configure. Returns process status
   // and retVal is return value or exception.
-  int RunMakeCommand(const char* command, int* retVal, const char* dir,
+  int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
                      int timeout, std::ostream& ofs,
                      Encoding encoding = cmProcessOutput::Auto);
 
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 6e8f73f..9c03839 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -78,7 +78,7 @@
       opts = "-dP";
     }
   }
-  std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 
   // Specify the start time for nightly testing.
   if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index 7b5c3bc..74a932a 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -3,7 +3,7 @@
 #include "cmCTestConfigureCommand.h"
 
 #include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
+#include "cmCTestConfigureHandler.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
@@ -142,13 +142,8 @@
                                        labelsForSubprojects, this->Quiet);
   }
 
-  cmCTestGenericHandler* handler =
-    this->CTest->GetInitializedHandler("configure");
-  if (!handler) {
-    this->SetError(
-      "internal CTest error. Cannot instantiate configure handler");
-    return nullptr;
-  }
+  cmCTestConfigureHandler* handler = this->CTest->GetConfigureHandler();
+  handler->Initialize();
   handler->SetQuiet(this->Quiet);
   return handler;
 }
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index 6b7601b..7e93189 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -61,7 +61,7 @@
     cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                        "Configure with command: " << cCommand << std::endl,
                        this->Quiet);
-    res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal,
+    res = this->CTest->RunMakeCommand(cCommand, output, &retVal,
                                       buildDirectory.c_str(),
                                       cmDuration::zero(), ofs);
 
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index d2003ba..07aae76 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -19,12 +19,8 @@
   this->CTest->SetCTestConfigurationFromCMakeVariable(
     this->Makefile, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS",
     this->Quiet);
-  cmCTestCoverageHandler* handler = static_cast<cmCTestCoverageHandler*>(
-    this->CTest->GetInitializedHandler("coverage"));
-  if (!handler) {
-    this->SetError("internal CTest error. Cannot instantiate test handler");
-    return nullptr;
-  }
+  cmCTestCoverageHandler* handler = this->CTest->GetCoverageHandler();
+  handler->Initialize();
 
   // If a LABELS option was given, select only files with the labels.
   if (this->LabelsMentioned) {
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 225383c..d76bd2a 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -52,6 +52,8 @@
     }
     cmsysProcess_Delete(this->Process);
   }
+  cmCTestRunProcess(const cmCTestRunProcess&) = delete;
+  cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete;
   void SetCommand(const char* command)
   {
     this->CommandLineStrings.clear();
@@ -72,7 +74,7 @@
       args.push_back(cl.c_str());
     }
     args.push_back(nullptr); // null terminate
-    cmsysProcess_SetCommand(this->Process, &*args.begin());
+    cmsysProcess_SetCommand(this->Process, args.data());
     if (!this->WorkingDirectory.empty()) {
       cmsysProcess_SetWorkingDirectory(this->Process,
                                        this->WorkingDirectory.c_str());
@@ -223,7 +225,7 @@
     checkDir = fBinDir;
   }
   std::string ndc = cmSystemTools::FileExistsInParentDirectories(
-    ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+    ".NoDartCoverage", fFile, checkDir);
   if (!ndc.empty()) {
     cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                        "Found: " << ndc << " so skip coverage of " << file
@@ -254,8 +256,8 @@
     return true;
   }
 
-  ndc = cmSystemTools::FileExistsInParentDirectories(
-    ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+  ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage", fFile,
+                                                     checkDir);
   if (!ndc.empty()) {
     cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                        "Found: " << ndc << " so skip coverage of: " << file
@@ -786,6 +788,9 @@
       cmSystemTools::UnsetEnv("LC_ALL");
     }
   }
+  cmCTestCoverageHandlerLocale(const cmCTestCoverageHandlerLocale&) = delete;
+  cmCTestCoverageHandlerLocale& operator=(
+    const cmCTestCoverageHandlerLocale&) = delete;
   std::string lc_all;
 };
 
@@ -999,7 +1004,7 @@
   static_cast<void>(locale_C);
 
   std::vector<std::string> basecovargs =
-    cmSystemTools::ParseArguments(gcovExtraFlags.c_str());
+    cmSystemTools::ParseArguments(gcovExtraFlags);
   basecovargs.insert(basecovargs.begin(), gcovCommand);
   basecovargs.emplace_back("-o");
 
@@ -1058,8 +1063,7 @@
       this->Quiet);
 
     std::vector<std::string> lines;
-
-    cmSystemTools::Split(output.c_str(), lines);
+    cmsys::SystemTools::Split(output, lines);
 
     for (std::string const& line : lines) {
       std::string sourceFile;
@@ -1373,7 +1377,7 @@
   static_cast<void>(locale_C);
 
   std::vector<std::string> covargs =
-    cmSystemTools::ParseArguments(lcovExtraFlags.c_str());
+    cmSystemTools::ParseArguments(lcovExtraFlags);
   covargs.insert(covargs.begin(), lcovCommand);
   const std::string command = joinCommandLine(covargs);
 
@@ -1435,8 +1439,7 @@
       this->Quiet);
 
     std::vector<std::string> lines;
-
-    cmSystemTools::Split(output.c_str(), lines);
+    cmsys::SystemTools::Split(output, lines);
 
     for (std::string const& line : lines) {
       std::string sourceFile;
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
index 86d9489..6186af8 100644
--- a/Source/CTest/cmCTestCurl.h
+++ b/Source/CTest/cmCTestCurl.h
@@ -16,6 +16,8 @@
 public:
   cmCTestCurl(cmCTest*);
   ~cmCTestCurl();
+  cmCTestCurl(const cmCTestCurl&) = delete;
+  cmCTestCurl& operator=(const cmCTestCurl&) = delete;
   bool UploadFile(std::string const& local_file, std::string const& url,
                   std::string const& fields, std::string& response);
   bool HttpRequest(std::string const& url, std::string const& fields,
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 210abe5..9d9761c 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -162,7 +162,7 @@
   if (opts.empty()) {
     opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
   }
-  std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
   for (std::string const& arg : args) {
     git_fetch.push_back(arg.c_str());
   }
@@ -547,7 +547,7 @@
   {
     // Look for header fields that we need.
     if (cmHasLiteralPrefix(this->Line, "commit ")) {
-      this->Rev.Rev = this->Line.c_str() + 7;
+      this->Rev.Rev = this->Line.substr(7);
     } else if (cmHasLiteralPrefix(this->Line, "author ")) {
       Person author;
       this->ParsePerson(this->Line.c_str() + 7, author);
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 6fb99d8..727c59c 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -144,7 +144,7 @@
   if (opts.empty()) {
     opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
   }
-  std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
   for (std::string const& arg : args) {
     hg_update.push_back(arg.c_str());
   }
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 57a14ef..adf9553 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -76,6 +76,8 @@
       }
     }
   }
+  SaveRestoreErrorState(const SaveRestoreErrorState&) = delete;
+  SaveRestoreErrorState& operator=(const SaveRestoreErrorState&) = delete;
 
 private:
   bool InitialErrorState;
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 5e66e05..a96513e 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -308,7 +308,7 @@
     if (line[0] == ' ') {
       // Label lines appear indented by one space.
       if (inTarget || inSource) {
-        this->Labels.insert(line.c_str() + 1);
+        this->Labels.insert(line.substr(1));
       }
     } else if (!this->OptionSource.empty() && !inSource) {
       // Non-indented lines specify a source file name.  The first one
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index debbe59..107fd61 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -28,6 +28,9 @@
   cmCTestLaunch(int argc, const char* const* argv);
   ~cmCTestLaunch();
 
+  cmCTestLaunch(const cmCTestLaunch&) = delete;
+  cmCTestLaunch& operator=(const cmCTestLaunch&) = delete;
+
   // Run the real command.
   int Run();
   void RunChild();
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index a5d5995..7dad1ce 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -7,7 +7,6 @@
 #include <vector>
 
 #include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
 #include "cmCTestMemCheckHandler.h"
 #include "cmMakefile.h"
 
@@ -20,8 +19,8 @@
 
 cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
 {
-  cmCTestGenericHandler* handler =
-    this->CTest->GetInitializedHandler("memcheck");
+  cmCTestMemCheckHandler* handler = this->CTest->GetMemCheckHandler();
+  handler->Initialize();
 
   this->CTest->SetCTestConfigurationFromCMakeVariable(
     this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 8ba59d3..b09e7bb 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -520,7 +520,7 @@
       this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
   }
   this->MemoryTesterOptions =
-    cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
+    cmSystemTools::ParseArguments(memoryTesterOptions);
 
   this->MemoryTesterOutputFile =
     this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.??.log";
@@ -725,7 +725,7 @@
   cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
   int defects = 0;
   std::vector<std::string> lines;
-  cmSystemTools::Split(str.c_str(), lines);
+  cmsys::SystemTools::Split(str, lines);
   std::ostringstream ostr;
   log.clear();
   for (std::string const& l : lines) {
@@ -755,7 +755,7 @@
   const std::string& str, std::string& log, std::vector<int>& results)
 {
   std::vector<std::string> lines;
-  cmSystemTools::Split(str.c_str(), lines);
+  cmsys::SystemTools::Split(str, lines);
   std::ostringstream ostr;
   log.clear();
 
@@ -798,7 +798,7 @@
   const std::string& str, std::string& log, std::vector<int>& results)
 {
   std::vector<std::string> lines;
-  cmSystemTools::Split(str.c_str(), lines);
+  cmsys::SystemTools::Split(str, lines);
   bool unlimitedOutput = false;
   if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
       this->CustomMaximumFailedTestOutputSize == 0) {
@@ -815,9 +815,9 @@
   cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
 
   cmsys::RegularExpression vgFIM(
-    "== .*Invalid free\\(\\) / delete / delete\\[\\]");
+    R"(== .*Invalid free\(\) / delete / delete\[\])");
   cmsys::RegularExpression vgFMM(
-    "== .*Mismatched free\\(\\) / delete / delete \\[\\]");
+    R"(== .*Mismatched free\(\) / delete / delete \[\])");
   cmsys::RegularExpression vgMLK1(
     "== .*[0-9,]+ bytes in [0-9,]+ blocks are definitely lost"
     " in loss record [0-9,]+ of [0-9,]+");
@@ -937,7 +937,7 @@
   log.clear();
   auto sttime = std::chrono::steady_clock::now();
   std::vector<std::string> lines;
-  cmSystemTools::Split(str.c_str(), lines);
+  cmsys::SystemTools::Split(str, lines);
   cmCTestOptionalLog(this->CTest, DEBUG,
                      "Start test: " << lines.size() << std::endl, this->Quiet);
   std::vector<std::string>::size_type cc;
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index 8880dac..746d72c 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -114,7 +114,7 @@
   // this type of checker
   void InitializeResultsVectors();
 
-  ///! Initialize memory checking subsystem.
+  //! Initialize memory checking subsystem.
   bool InitializeMemoryChecking();
 
   /**
@@ -143,11 +143,11 @@
   void PostProcessTest(cmCTestTestResult& res, int test);
   void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
 
-  ///! append MemoryTesterOutputFile to the test log
+  //! append MemoryTesterOutputFile to the test log
   void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
                              std::string const& filename);
 
-  ///! generate the output filename for the given test index
+  //! generate the output filename for the given test index
   void TestOutputFileNames(int test, std::vector<std::string>& files);
 };
 
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 756ac6c..477161a 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -8,6 +8,7 @@
 #include "cmCTestTestHandler.h"
 #include "cmDuration.h"
 #include "cmListFileCache.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
@@ -108,8 +109,8 @@
                             fake_load_value)) {
     if (!cmSystemTools::StringToULong(fake_load_value.c_str(),
                                       &this->FakeLoadForTesting)) {
-      cmSystemTools::Error("Failed to parse fake load value: ",
-                           fake_load_value.c_str());
+      cmSystemTools::Error("Failed to parse fake load value: " +
+                           fake_load_value);
     }
   }
 }
@@ -651,9 +652,7 @@
 
   // Reverse iterate over the different dependency levels (deepest first).
   // Sort tests within each level by COST and append them to the cost list.
-  for (std::list<TestSet>::reverse_iterator i = priorityStack.rbegin();
-       i != priorityStack.rend(); ++i) {
-    TestSet const& currentSet = *i;
+  for (TestSet const& currentSet : cmReverseRange(priorityStack)) {
     TestComparator comp(this);
 
     TestList sortedCopy;
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 435be97..aa42810 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -5,6 +5,7 @@
 #include "cmCTest.h"
 #include "cmCTestVC.h"
 #include "cmProcessTools.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 
 #include "cmsys/RegularExpression.hxx"
@@ -193,7 +194,7 @@
   {
     this->SetLog(&P4->Log, prefix);
     this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
-    this->RegexDiff.compile("^\\.\\.\\. (.*)#[0-9]+ ([^ ]+)$");
+    this->RegexDiff.compile(R"(^\.\.\. (.*)#[0-9]+ ([^ ]+)$)");
   }
 
 private:
@@ -323,8 +324,7 @@
     // The CTEST_P4_OPTIONS variable adds additional Perforce command line
     // options before the main command
     std::string opts = this->CTest->GetCTestConfiguration("P4Options");
-    std::vector<std::string> args =
-      cmSystemTools::ParseArguments(opts.c_str());
+    std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 
     P4Options.insert(P4Options.end(), args.begin(), args.end());
   }
@@ -425,12 +425,11 @@
 
   // p4 describe -s ...@1111111,2222222
   std::vector<char const*> p4_describe;
-  for (std::vector<std::string>::reverse_iterator i = ChangeLists.rbegin();
-       i != ChangeLists.rend(); ++i) {
+  for (std::string const& i : cmReverseRange(ChangeLists)) {
     SetP4Options(p4_describe);
     p4_describe.push_back("describe");
     p4_describe.push_back("-s");
-    p4_describe.push_back(i->c_str());
+    p4_describe.push_back(i.c_str());
     p4_describe.push_back(nullptr);
 
     DescribeParser outDescribe(this, "p4_describe-out> ");
@@ -501,7 +500,7 @@
   if (opts.empty()) {
     opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
   }
-  std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
   for (std::string const& arg : args) {
     p4_sync.push_back(arg.c_str());
   }
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 7f081ef..31976b9 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -9,11 +9,10 @@
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
-#include "cm_zlib.h"
-#include "cmsys/Base64.h"
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
 #include <cmAlgorithms.h>
+#include <cstdint>
 #include <cstring>
 #include <iomanip>
 #include <ratio>
@@ -31,9 +30,6 @@
   this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
   this->TestResult.TestCount = 0;
   this->TestResult.Properties = nullptr;
-  this->ProcessOutput.clear();
-  this->CompressedOutput.clear();
-  this->CompressionRatio = 2;
   this->NumberOfRunsLeft = 1; // default to 1 run of the test
   this->RunUntilFail = false; // default to run the test once
   this->RunAgain = false;     // default to not having to run again
@@ -68,73 +64,8 @@
   }
 }
 
-// Streamed compression of test output.  The compressed data
-// is appended to this->CompressedOutput
-void cmCTestRunTest::CompressOutput()
-{
-  int ret;
-  z_stream strm;
-
-  unsigned char* in = reinterpret_cast<unsigned char*>(
-    const_cast<char*>(this->ProcessOutput.c_str()));
-  // zlib makes the guarantee that this is the maximum output size
-  int outSize = static_cast<int>(
-    static_cast<double>(this->ProcessOutput.size()) * 1.001 + 13.0);
-  unsigned char* out = new unsigned char[outSize];
-
-  strm.zalloc = Z_NULL;
-  strm.zfree = Z_NULL;
-  strm.opaque = Z_NULL;
-  ret = deflateInit(&strm, -1); // default compression level
-  if (ret != Z_OK) {
-    delete[] out;
-    return;
-  }
-
-  strm.avail_in = static_cast<uInt>(this->ProcessOutput.size());
-  strm.next_in = in;
-  strm.avail_out = outSize;
-  strm.next_out = out;
-  ret = deflate(&strm, Z_FINISH);
-
-  if (ret != Z_STREAM_END) {
-    cmCTestLog(this->CTest, ERROR_MESSAGE,
-               "Error during output compression. Sending uncompressed output."
-                 << std::endl);
-    delete[] out;
-    return;
-  }
-
-  (void)deflateEnd(&strm);
-
-  unsigned char* encoded_buffer =
-    new unsigned char[static_cast<int>(outSize * 1.5)];
-
-  size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1);
-
-  this->CompressedOutput.clear();
-  for (size_t i = 0; i < rlen; i++) {
-    this->CompressedOutput += encoded_buffer[i];
-  }
-
-  if (strm.total_in) {
-    this->CompressionRatio =
-      static_cast<double>(strm.total_out) / static_cast<double>(strm.total_in);
-  }
-
-  delete[] encoded_buffer;
-  delete[] out;
-}
-
 bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
 {
-  if ((!this->TestHandler->MemCheck &&
-       this->CTest->ShouldCompressTestOutput()) ||
-      (this->TestHandler->MemCheck &&
-       this->CTest->ShouldCompressTestOutput())) {
-    this->CompressOutput();
-  }
-
   this->WriteLogOutputTop(completed, total);
   std::string reason;
   bool passed = true;
@@ -143,7 +74,7 @@
   if (res != cmProcess::State::Expired) {
     this->TimeoutIsForStopTime = false;
   }
-  int retVal = this->TestProcess->GetExitValue();
+  std::int64_t retVal = this->TestProcess->GetExitValue();
   bool forceFail = false;
   bool skipped = false;
   bool outputTestErrorsToConsole = false;
@@ -201,14 +132,17 @@
     } else {
       this->TestResult.Status = cmCTestTestHandler::FAILED;
       outputStream << "***Failed  " << reason;
-      outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+      outputTestErrorsToConsole =
+        this->CTest->GetOutputTestOutputOnTestFailure();
     }
   } else if (res == cmProcess::State::Expired) {
     outputStream << "***Timeout ";
     this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
-    outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+    outputTestErrorsToConsole =
+      this->CTest->GetOutputTestOutputOnTestFailure();
   } else if (res == cmProcess::State::Exception) {
-    outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+    outputTestErrorsToConsole =
+      this->CTest->GetOutputTestOutputOnTestFailure();
     outputStream << "***Exception: ";
     this->TestResult.ExceptionStatus =
       this->TestProcess->GetExitExceptionString();
@@ -335,10 +269,18 @@
   // if the test actually started and ran
   // record the results in TestResult
   if (started) {
-    bool compress = !this->TestHandler->MemCheck &&
-      this->CompressionRatio < 1 && this->CTest->ShouldCompressTestOutput();
+    std::string compressedOutput;
+    if (!this->TestHandler->MemCheck &&
+        this->CTest->ShouldCompressTestOutput()) {
+      std::string str = this->ProcessOutput;
+      if (this->CTest->CompressString(str)) {
+        compressedOutput = std::move(str);
+      }
+    }
+    bool compress = !compressedOutput.empty() &&
+      compressedOutput.length() < this->ProcessOutput.length();
     this->TestResult.Output =
-      compress ? this->CompressedOutput : this->ProcessOutput;
+      compress ? compressedOutput : this->ProcessOutput;
     this->TestResult.CompressOutput = compress;
     this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
     if (!skipped) {
@@ -493,32 +435,26 @@
 
   this->ProcessOutput.clear();
 
+  this->TestResult.Properties = this->TestProperties;
+  this->TestResult.ExecutionTime = cmDuration::zero();
+  this->TestResult.CompressOutput = false;
+  this->TestResult.ReturnValue = -1;
+  this->TestResult.TestCount = this->TestProperties->Index;
+  this->TestResult.Name = this->TestProperties->Name;
+  this->TestResult.Path = this->TestProperties->Directory;
+
   // Return immediately if test is disabled
   if (this->TestProperties->Disabled) {
-    this->TestResult.Properties = this->TestProperties;
-    this->TestResult.ExecutionTime = cmDuration::zero();
-    this->TestResult.CompressOutput = false;
-    this->TestResult.ReturnValue = -1;
     this->TestResult.CompletionStatus = "Disabled";
     this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
-    this->TestResult.TestCount = this->TestProperties->Index;
-    this->TestResult.Name = this->TestProperties->Name;
-    this->TestResult.Path = this->TestProperties->Directory;
     this->TestProcess = cm::make_unique<cmProcess>(*this);
     this->TestResult.Output = "Disabled";
     this->TestResult.FullCommandLine.clear();
     return false;
   }
 
-  this->TestResult.Properties = this->TestProperties;
-  this->TestResult.ExecutionTime = cmDuration::zero();
-  this->TestResult.CompressOutput = false;
-  this->TestResult.ReturnValue = -1;
   this->TestResult.CompletionStatus = "Failed to start";
   this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND;
-  this->TestResult.TestCount = this->TestProperties->Index;
-  this->TestResult.Name = this->TestProperties->Name;
-  this->TestResult.Path = this->TestProperties->Directory;
 
   // Check for failed fixture dependencies before we even look at the command
   // arguments because if we are not going to run the test, the command and
@@ -696,9 +632,8 @@
 {
   this->TestProcess = cm::make_unique<cmProcess>(*this);
   this->TestProcess->SetId(this->Index);
-  this->TestProcess->SetWorkingDirectory(
-    this->TestProperties->Directory.c_str());
-  this->TestProcess->SetCommand(this->ActualCommand.c_str());
+  this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
+  this->TestProcess->SetCommand(this->ActualCommand);
   this->TestProcess->SetCommandArguments(this->Arguments);
 
   // determine how much time we have
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 918d5fa..38cc417 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -58,9 +58,6 @@
   // Read and store output.  Returns true if it must be called again.
   void CheckOutput(std::string const& line);
 
-  // Compresses the output, writing to CompressedOutput
-  void CompressOutput();
-
   // launch the test process, return whether it started correctly
   bool StartTest(size_t completed, size_t total);
   // capture and report the test results
@@ -105,8 +102,6 @@
   cmCTest* CTest;
   std::unique_ptr<cmProcess> TestProcess;
   std::string ProcessOutput;
-  std::string CompressedOutput;
-  double CompressionRatio;
   // The test results
   cmCTestTestHandler::cmCTestTestResult TestResult;
   cmCTestMultiProcessHandler& MultiTestHandler;
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 3bf66ca..04749b7 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -242,7 +242,7 @@
   if (opts.empty()) {
     opts = this->CTest->GetCTestConfiguration("SVNUpdateOptions");
   }
-  std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 
   // Specify the start time for nightly testing.
   if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
@@ -277,7 +277,7 @@
   std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
 
   std::vector<std::string> parsedUserOptions =
-    cmSystemTools::ParseArguments(userOptions.c_str());
+    cmSystemTools::ParseArguments(userOptions);
   for (std::string const& opt : parsedUserOptions) {
     args.push_back(opt.c_str());
   }
@@ -515,7 +515,7 @@
     if (path.size() > this->SVN->SourceDirectory.size() &&
         strncmp(path.c_str(), this->SVN->SourceDirectory.c_str(),
                 this->SVN->SourceDirectory.size()) == 0) {
-      local_path = path.c_str() + this->SVN->SourceDirectory.size() + 1;
+      local_path = path.substr(this->SVN->SourceDirectory.size() + 1);
     } else {
       local_path = path;
     }
@@ -554,7 +554,7 @@
   // Add path with base prefix removed
   if (path.size() > this->Base.size() &&
       strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0) {
-    local_path += (path.c_str() + this->Base.size());
+    local_path += path.substr(this->Base.size());
   } else {
     local_path += path;
   }
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 33b8b4a..43cfe16 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -199,7 +199,7 @@
 
   // Now create process object
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
+  cmsysProcess_SetCommand(cp, argv.data());
   // cmsysProcess_SetWorkingDirectory(cp, dir);
   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
   // cmsysProcess_SetTimeout(cp, timeout);
@@ -288,11 +288,12 @@
       this->ParentMakefile->GetRecursionDepth());
   }
 
-  this->CMake->SetProgressCallback([this](const char* m, float /*unused*/) {
-    if (m && *m) {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
-    }
-  });
+  this->CMake->SetProgressCallback(
+    [this](const std::string& m, float /*unused*/) {
+      if (!m.empty()) {
+        cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
+      }
+    });
 
   this->AddCTestCommand("ctest_build", new cmCTestBuildCommand);
   this->AddCTestCommand("ctest_configure", new cmCTestConfigureCommand);
@@ -330,7 +331,7 @@
   }
   // make sure the file exists
   if (!cmSystemTools::FileExists(script)) {
-    cmSystemTools::Error("Cannot find file: ", script.c_str());
+    cmSystemTools::Error("Cannot find file: " + script);
     return 1;
   }
 
@@ -470,8 +471,8 @@
     msg += "\nCTEST_COMMAND = ";
     msg += (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)";
     cmSystemTools::Error(
-      "Some required settings in the configuration file were missing:\n",
-      msg.c_str());
+      "Some required settings in the configuration file were missing:\n" +
+      msg);
     return 4;
   }
 
@@ -607,12 +608,10 @@
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                "Run cvs: " << this->CVSCheckOut << std::endl);
     res = cmSystemTools::RunSingleCommand(
-      this->CVSCheckOut.c_str(), &output, &output, &retVal,
-      this->CTestRoot.c_str(), this->HandlerVerbose,
-      cmDuration::zero() /*this->TimeOut*/);
+      this->CVSCheckOut, &output, &output, &retVal, this->CTestRoot.c_str(),
+      this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
     if (!res || retVal != 0) {
-      cmSystemTools::Error("Unable to perform cvs checkout:\n",
-                           output.c_str());
+      cmSystemTools::Error("Unable to perform cvs checkout:\n" + output);
       return 6;
     }
   }
@@ -675,11 +674,11 @@
       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                  "Run Update: " << fullCommand << std::endl);
       res = cmSystemTools::RunSingleCommand(
-        fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(),
+        fullCommand, &output, &output, &retVal, cvsArgs[0].c_str(),
         this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
       if (!res || retVal != 0) {
-        cmSystemTools::Error("Unable to perform extra updates:\n", eu.c_str(),
-                             "\nWith output:\n", output.c_str());
+        cmSystemTools::Error("Unable to perform extra updates:\n" + eu +
+                             "\nWith output:\n" + output);
         return 0;
       }
     }
@@ -721,8 +720,8 @@
   if (!cmSystemTools::FileExists(this->BinaryDir) &&
       this->SourceDir != this->BinaryDir) {
     if (!cmSystemTools::MakeDirectory(this->BinaryDir)) {
-      cmSystemTools::Error("Unable to create the binary directory:\n",
-                           this->BinaryDir.c_str());
+      cmSystemTools::Error("Unable to create the binary directory:\n" +
+                           this->BinaryDir);
       this->RestoreBackupDirectories();
       return 7;
     }
@@ -779,7 +778,7 @@
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                "Run cmake command: " << command << std::endl);
     res = cmSystemTools::RunSingleCommand(
-      command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+      command, &output, &output, &retVal, this->BinaryDir.c_str(),
       this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
 
     if (!this->CMOutFile.empty()) {
@@ -818,7 +817,7 @@
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                "Run ctest command: " << command << std::endl);
     res = cmSystemTools::RunSingleCommand(
-      command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+      command, &output, &output, &retVal, this->BinaryDir.c_str(),
       this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
 
     // did something critical fail in ctest
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 00c0610..afc3e67 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -3,7 +3,6 @@
 #include "cmCTestSubmitCommand.h"
 
 #include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
 #include "cmCTestSubmitHandler.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -13,6 +12,29 @@
 
 class cmExecutionStatus;
 
+cmCTestSubmitCommand::cmCTestSubmitCommand()
+{
+  this->PartsMentioned = false;
+  this->FilesMentioned = false;
+  this->InternalTest = false;
+  this->RetryCount = "";
+  this->RetryDelay = "";
+  this->CDashUpload = false;
+  this->Arguments[cts_BUILD_ID] = "BUILD_ID";
+  this->Last = cts_LAST;
+}
+
+/**
+ * This is a virtual constructor for the command.
+ */
+cmCommand* cmCTestSubmitCommand::Clone()
+{
+  cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
+  ni->CTest = this->CTest;
+  ni->CTestScriptHandler = this->CTestScriptHandler;
+  return ni;
+}
+
 cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
 {
   const char* submitURL = !this->SubmitURL.empty()
@@ -42,33 +64,23 @@
     this->Makefile->GetDefinition("CTEST_NOTES_FILES");
   if (notesFilesVariable) {
     std::vector<std::string> notesFiles;
-    cmCTest::VectorOfStrings newNotesFiles;
     cmSystemTools::ExpandListArgument(notesFilesVariable, notesFiles);
-    newNotesFiles.insert(newNotesFiles.end(), notesFiles.begin(),
-                         notesFiles.end());
-    this->CTest->GenerateNotesFile(newNotesFiles);
+    this->CTest->GenerateNotesFile(notesFiles);
   }
 
   const char* extraFilesVariable =
     this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
   if (extraFilesVariable) {
     std::vector<std::string> extraFiles;
-    cmCTest::VectorOfStrings newExtraFiles;
     cmSystemTools::ExpandListArgument(extraFilesVariable, extraFiles);
-    newExtraFiles.insert(newExtraFiles.end(), extraFiles.begin(),
-                         extraFiles.end());
-    if (!this->CTest->SubmitExtraFiles(newExtraFiles)) {
+    if (!this->CTest->SubmitExtraFiles(extraFiles)) {
       this->SetError("problem submitting extra files.");
       return nullptr;
     }
   }
 
-  cmCTestGenericHandler* handler =
-    this->CTest->GetInitializedHandler("submit");
-  if (!handler) {
-    this->SetError("internal CTest error. Cannot instantiate submit handler");
-    return nullptr;
-  }
+  cmCTestSubmitHandler* handler = this->CTest->GetSubmitHandler();
+  handler->Initialize();
 
   // If no FILES or PARTS given, *all* PARTS are submitted by default.
   //
@@ -90,38 +102,30 @@
     // But FILES with no PARTS mentioned should just submit the FILES
     // without any of the default parts.
     //
-    std::set<cmCTest::Part> noParts;
-    static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(noParts);
-
-    static_cast<cmCTestSubmitHandler*>(handler)->SelectFiles(this->Files);
+    handler->SelectParts(std::set<cmCTest::Part>());
+    handler->SelectFiles(this->Files);
   }
 
   // If a PARTS option was given, select only the named parts for submission.
   //
   if (this->PartsMentioned) {
-    static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(this->Parts);
+    handler->SelectParts(this->Parts);
   }
 
   // Pass along any HTTPHEADER to the handler if this option was given.
   if (!this->HttpHeaders.empty()) {
-    static_cast<cmCTestSubmitHandler*>(handler)->SetHttpHeaders(
-      this->HttpHeaders);
+    handler->SetHttpHeaders(this->HttpHeaders);
   }
 
-  static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
-    "RetryDelay", this->RetryDelay.c_str());
-  static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
-    "RetryCount", this->RetryCount.c_str());
-  static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
-    "InternalTest", this->InternalTest ? "ON" : "OFF");
+  handler->SetOption("RetryDelay", this->RetryDelay.c_str());
+  handler->SetOption("RetryCount", this->RetryCount.c_str());
+  handler->SetOption("InternalTest", this->InternalTest ? "ON" : "OFF");
 
   handler->SetQuiet(this->Quiet);
 
   if (this->CDashUpload) {
-    static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
-      "CDashUploadFile", this->CDashUploadFile.c_str());
-    static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
-      "CDashUploadType", this->CDashUploadType.c_str());
+    handler->SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
+    handler->SetOption("CDashUploadType", this->CDashUploadType.c_str());
   }
   return handler;
 }
@@ -130,7 +134,15 @@
                                        cmExecutionStatus& status)
 {
   this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
-  return this->cmCTestHandlerCommand::InitialPass(args, status);
+
+  bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
+
+  if (this->Values[cts_BUILD_ID] && *this->Values[cts_BUILD_ID]) {
+    this->Makefile->AddDefinition(this->Values[cts_BUILD_ID],
+                                  this->CTest->GetBuildID().c_str());
+  }
+
+  return ret;
 }
 
 bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 0caccd6..1e27046 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -25,26 +25,8 @@
 class cmCTestSubmitCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestSubmitCommand()
-  {
-    this->PartsMentioned = false;
-    this->FilesMentioned = false;
-    this->InternalTest = false;
-    this->RetryCount = "";
-    this->RetryDelay = "";
-    this->CDashUpload = false;
-  }
-
-  /**
-   * This is a virtual constructor for the command.
-   */
-  cmCommand* Clone() override
-  {
-    cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
-    ni->CTest = this->CTest;
-    ni->CTestScriptHandler = this->CTestScriptHandler;
-    return ni;
-  }
+  cmCTestSubmitCommand();
+  cmCommand* Clone() override;
 
   bool InitialPass(std::vector<std::string> const& args,
                    cmExecutionStatus& status) override;
@@ -75,11 +57,17 @@
     ArgumentDoingLast2
   };
 
+  enum
+  {
+    cts_BUILD_ID = ct_LAST,
+    cts_LAST
+  };
+
   bool PartsMentioned;
   std::set<cmCTest::Part> Parts;
   bool FilesMentioned;
   bool InternalTest;
-  cmCTest::SetOfStrings Files;
+  std::set<std::string> Files;
   std::string RetryCount;
   std::string RetryDelay;
   bool CDashUpload;
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 87112da..2b54365 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -259,8 +259,7 @@
         upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag());
         upload_as += "-";
         upload_as += ctest_curl.Escape(this->CTest->GetTestModelString());
-        cmCTestScriptHandler* ch = static_cast<cmCTestScriptHandler*>(
-          this->CTest->GetHandler("script"));
+        cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
         cmake* cm = ch->GetCMake();
         if (cm) {
           const char* subproject =
@@ -343,7 +342,7 @@
       if (!chunk.empty()) {
         cmCTestOptionalLog(this->CTest, DEBUG,
                            "CURL output: ["
-                             << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+                             << cmCTestLogWrite(chunk.data(), chunk.size())
                              << "]" << std::endl,
                            this->Quiet);
         this->ParseResponse(chunk);
@@ -352,7 +351,7 @@
         cmCTestOptionalLog(
           this->CTest, DEBUG,
           "CURL debug output: ["
-            << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+            << cmCTestLogWrite(chunkDebug.data(), chunkDebug.size()) << "]"
             << std::endl,
           this->Quiet);
       }
@@ -404,12 +403,11 @@
           res = ::curl_easy_perform(curl);
 
           if (!chunk.empty()) {
-            cmCTestOptionalLog(
-              this->CTest, DEBUG,
-              "CURL output: ["
-                << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
-                << std::endl,
-              this->Quiet);
+            cmCTestOptionalLog(this->CTest, DEBUG,
+                               "CURL output: ["
+                                 << cmCTestLogWrite(chunk.data(), chunk.size())
+                                 << "]" << std::endl,
+                               this->Quiet);
             this->ParseResponse(chunk);
           }
 
@@ -433,11 +431,11 @@
         // avoid deref of begin for zero size array
         if (!chunk.empty()) {
           *this->LogFile << "   Curl output was: "
-                         << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+                         << cmCTestLogWrite(chunk.data(), chunk.size())
                          << std::endl;
           cmCTestLog(this->CTest, ERROR_MESSAGE,
                      "CURL output: ["
-                       << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+                       << cmCTestLogWrite(chunk.data(), chunk.size()) << "]"
                        << std::endl);
         }
         ::curl_easy_cleanup(curl);
@@ -486,7 +484,7 @@
   if (this->HasWarnings || this->HasErrors) {
     cmCTestLog(this->CTest, HANDLER_OUTPUT,
                "   Server Response:\n"
-                 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
+                 << cmCTestLogWrite(chunk.data(), chunk.size()) << "\n");
   }
 }
 
@@ -559,8 +557,7 @@
   //    has already been uploaded
   // TODO I added support for subproject. You would need to add
   // a "&subproject=subprojectname" to the first POST.
-  cmCTestScriptHandler* ch =
-    static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script"));
+  cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
   cmake* cm = ch->GetCMake();
   const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
   // TODO: Encode values for a URL instead of trusting caller.
@@ -903,7 +900,7 @@
   }
 }
 
-void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
+void cmCTestSubmitHandler::SelectFiles(std::set<std::string> const& files)
 {
   this->Files.insert(files.begin(), files.end());
 }
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index 58f4f97..e0fed10 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -38,7 +38,7 @@
   void SelectParts(std::set<cmCTest::Part> const& parts);
 
   /** Specify a set of files to submit.  */
-  void SelectFiles(cmCTest::SetOfStrings const& files);
+  void SelectFiles(std::set<std::string> const& files);
 
   // handle the cdash file upload protocol
   int HandleCDashUploadFile(std::string const& file, std::string const& type);
@@ -74,7 +74,7 @@
   bool SubmitPart[cmCTest::PartCount];
   bool HasWarnings;
   bool HasErrors;
-  cmCTest::SetOfStrings Files;
+  std::set<std::string> Files;
   std::vector<std::string> HttpHeaders;
 };
 
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 895ca12..cfd5e3d 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -4,6 +4,7 @@
 
 #include "cmCTest.h"
 #include "cmCTestGenericHandler.h"
+#include "cmCTestTestHandler.h"
 #include "cmDuration.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
@@ -140,5 +141,7 @@
 
 cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
 {
-  return this->CTest->GetInitializedHandler("test");
+  cmCTestTestHandler* handler = this->CTest->GetTestHandler();
+  handler->Initialize();
+  return handler;
 }
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index cf2652a..0ed56c8 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1486,7 +1486,7 @@
     int retVal = 0;
     cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                        "Run command: " << it << std::endl, this->Quiet);
-    if (!cmSystemTools::RunSingleCommand(it.c_str(), nullptr, nullptr, &retVal,
+    if (!cmSystemTools::RunSingleCommand(it, nullptr, nullptr, &retVal,
                                          nullptr, cmSystemTools::OUTPUT_MERGE
                                          /*this->Verbose*/) ||
         retVal != 0) {
@@ -2265,8 +2265,8 @@
             size_t pos = val.find_first_of('=');
             if (pos != std::string::npos) {
               std::string mKey = val.substr(0, pos);
-              const char* mVal = val.c_str() + pos + 1;
-              rt.Measurements[mKey] = mVal;
+              std::string mVal = val.substr(pos + 1);
+              rt.Measurements[mKey] = std::move(mVal);
             } else {
               rt.Measurements[val] = "1";
             }
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 0b557db..7f3f5e4 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -11,6 +11,7 @@
 
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
+#include <cstdint>
 #include <iosfwd>
 #include <map>
 #include <set>
@@ -58,7 +59,7 @@
    */
   void PopulateCustomVectors(cmMakefile* mf) override;
 
-  ///! Control the use of the regular expresisons, call these methods to turn
+  //! Control the use of the regular expresisons, call these methods to turn
   /// them on
   void UseIncludeRegExp();
   void UseExcludeRegExp();
@@ -77,7 +78,7 @@
     this->CustomMaximumFailedTestOutputSize = n;
   }
 
-  ///! pass the -I argument down
+  //! pass the -I argument down
   void SetTestsToRunInformation(const char*);
 
   cmCTestTestHandler();
@@ -153,7 +154,7 @@
     std::string Reason;
     std::string FullCommandLine;
     cmDuration ExecutionTime;
-    int ReturnValue;
+    std::int64_t ReturnValue;
     int Status;
     std::string ExceptionStatus;
     bool CompressOutput;
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
index 3d800f8..a2f1462 100644
--- a/Source/CTest/cmCTestUpdateCommand.cxx
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -3,7 +3,7 @@
 #include "cmCTestUpdateCommand.h"
 
 #include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
+#include "cmCTestUpdateHandler.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
 
@@ -74,12 +74,8 @@
   this->CTest->SetCTestConfigurationFromCMakeVariable(
     this->Makefile, "P4Options", "CTEST_P4_OPTIONS", this->Quiet);
 
-  cmCTestGenericHandler* handler =
-    this->CTest->GetInitializedHandler("update");
-  if (!handler) {
-    this->SetError("internal CTest error. Cannot instantiate update handler");
-    return nullptr;
-  }
+  cmCTestUpdateHandler* handler = this->CTest->GetUpdateHandler();
+  handler->Initialize();
   handler->SetCommand(this);
   if (source_dir.empty()) {
     this->SetError("source directory not specified. Please use SOURCE tag");
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index 2fe2cd3..59fbf37 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -6,7 +6,6 @@
 #include <vector>
 
 #include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
 #include "cmCTestUploadHandler.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -14,14 +13,9 @@
 
 cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
 {
-  cmCTestGenericHandler* handler =
-    this->CTest->GetInitializedHandler("upload");
-  if (!handler) {
-    this->SetError("internal CTest error. Cannot instantiate upload handler");
-    return nullptr;
-  }
-  static_cast<cmCTestUploadHandler*>(handler)->SetFiles(this->Files);
-
+  cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
+  handler->Initialize();
+  handler->SetFiles(this->Files);
   handler->SetQuiet(this->Quiet);
   return handler;
 }
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index 61bf1cc..0d3b06e 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -5,9 +5,9 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include "cmCTest.h"
 #include "cmCTestHandlerCommand.h"
 
+#include <set>
 #include <string>
 
 class cmCTestGenericHandler;
@@ -22,8 +22,6 @@
 class cmCTestUploadCommand : public cmCTestHandlerCommand
 {
 public:
-  cmCTestUploadCommand() {}
-
   /**
    * This is a virtual constructor for the command.
    */
@@ -55,7 +53,7 @@
     ArgumentDoingLast2
   };
 
-  cmCTest::SetOfStrings Files;
+  std::set<std::string> Files;
 };
 
 #endif
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
index 261ecab..ee9ee91 100644
--- a/Source/CTest/cmCTestUploadHandler.cxx
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestUploadHandler.h"
 
+#include "cmCTest.h"
 #include "cmGeneratedFileStream.h"
 #include "cmVersion.h"
 #include "cmXMLWriter.h"
@@ -20,7 +21,7 @@
   this->Files.clear();
 }
 
-void cmCTestUploadHandler::SetFiles(const cmCTest::SetOfStrings& files)
+void cmCTestUploadHandler::SetFiles(std::set<std::string> const& files)
 {
   this->Files = files;
 }
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
index ff50574..4d8fab4 100644
--- a/Source/CTest/cmCTestUploadHandler.h
+++ b/Source/CTest/cmCTestUploadHandler.h
@@ -5,9 +5,11 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include "cmCTest.h"
 #include "cmCTestGenericHandler.h"
 
+#include <set>
+#include <string>
+
 /** \class cmCTestUploadHandler
  * \brief Helper class for CTest
  *
@@ -20,7 +22,6 @@
   typedef cmCTestGenericHandler Superclass;
 
   cmCTestUploadHandler();
-  ~cmCTestUploadHandler() override {}
 
   /*
    * The main entry point for this class
@@ -30,10 +31,10 @@
   void Initialize() override;
 
   /** Specify a set of files to submit.  */
-  void SetFiles(cmCTest::SetOfStrings const& files);
+  void SetFiles(std::set<std::string> const& files);
 
 private:
-  cmCTest::SetOfStrings Files;
+  std::set<std::string> Files;
 };
 
 #endif
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 70ef8df..bfe8d70 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -11,7 +11,9 @@
 #include <iostream>
 #include <signal.h>
 #include <string>
-#if !defined(_WIN32)
+#if defined(_WIN32)
+#  include "cm_kwiml.h"
+#else
 #  include <unistd.h>
 #endif
 #include <utility>
@@ -71,7 +73,7 @@
 
 cmProcess::~cmProcess() = default;
 
-void cmProcess::SetCommand(const char* command)
+void cmProcess::SetCommand(std::string const& command)
 {
   this->Command = command;
 }
@@ -81,6 +83,11 @@
   this->Arguments = args;
 }
 
+void cmProcess::SetWorkingDirectory(std::string const& dir)
+{
+  this->WorkingDirectory = dir;
+}
+
 bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
 {
   this->ProcessState = cmProcess::State::Error;
@@ -199,7 +206,7 @@
   for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
     if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
       // Extract the range first..last as a line.
-      const char* text = &*this->begin() + this->First;
+      const char* text = this->data() + this->First;
       size_type length = this->Last - this->First;
       while (length && text[length - 1] == '\r') {
         length--;
@@ -229,7 +236,7 @@
 {
   // Return the partial last line, if any.
   if (!this->empty()) {
-    line.assign(&*this->begin(), this->size());
+    line.assign(this->data(), this->size());
     this->First = this->Last = 0;
     this->clear();
     return true;
@@ -353,7 +360,7 @@
   }
 
   // Record exit information.
-  this->ExitValue = static_cast<int>(exit_status);
+  this->ExitValue = exit_status;
   this->Signal = term_signal;
   this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
   // Because of a processor clock scew the runtime may become slightly
@@ -539,7 +546,8 @@
     case STATUS_NO_MEMORY:
     default:
       char buf[1024];
-      _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue);
+      const char* fmt = "Exit code 0x%" KWIML_INT_PRIx64 "\n";
+      _snprintf(buf, 1024, fmt, this->ExitValue);
       exception_str.assign(buf);
   }
 #else
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index b2d87fa..a0a4b6b 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -28,10 +28,9 @@
 public:
   explicit cmProcess(cmCTestRunTest& runner);
   ~cmProcess();
-  const char* GetCommand() { return this->Command.c_str(); }
-  void SetCommand(const char* command);
+  void SetCommand(std::string const& command);
   void SetCommandArguments(std::vector<std::string> const& arg);
-  void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+  void SetWorkingDirectory(std::string const& dir);
   void SetTimeout(cmDuration t) { this->Timeout = t; }
   void ChangeTimeout(cmDuration t);
   void ResetStartTime();
@@ -53,7 +52,7 @@
   State GetProcessStatus();
   int GetId() { return this->Id; }
   void SetId(int id) { this->Id = id; }
-  int GetExitValue() { return this->ExitValue; }
+  int64_t GetExitValue() { return this->ExitValue; }
   cmDuration GetTotalTime() { return this->TotalTime; }
 
   enum class Exception
@@ -122,7 +121,7 @@
   std::vector<std::string> Arguments;
   std::vector<const char*> ProcessArgs;
   int Id;
-  int ExitValue;
+  int64_t ExitValue;
 };
 
 #endif
diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp
index 9ea52c4..593d9b2 100644
--- a/Source/Checks/cm_cxx17_check.cpp
+++ b/Source/Checks/cm_cxx17_check.cpp
@@ -3,6 +3,10 @@
 #include <memory>
 #include <unordered_map>
 
+#ifdef _MSC_VER
+#  include <comdef.h>
+#endif
+
 int main()
 {
   int a[] = { 0, 1, 2 };
@@ -14,5 +18,14 @@
   auto ci = std::size(a);
 
   std::unique_ptr<int> u(new int(0));
+
+#ifdef _MSC_VER
+  // clang-cl has problems instantiating this constructor in C++17 mode
+  //  error: indirection requires pointer operand ('const _GUID' invalid)
+  //      return *_IID;
+  IUnknownPtr ptr{};
+  IDispatchPtr disp(ptr);
+#endif
+
   return *u + *ai + *(bi - 1) + (3 - static_cast<int>(ci));
 }
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index f2982a6..745c6bb 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -150,7 +150,7 @@
   }
 
   cmSystemTools::SetMessageCallback(
-    [myform](const char* message, const char* title) {
+    [myform](const std::string& message, const char* title) {
       myform->AddError(message, title);
     });
 
diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h
index ddb67de..7842905 100644
--- a/Source/CursesDialog/cmCursesForm.h
+++ b/Source/CursesDialog/cmCursesForm.h
@@ -9,6 +9,8 @@
 
 #include "cmsys/FStream.hxx"
 
+#include <string>
+
 class cmCursesForm
 {
 public:
@@ -34,7 +36,7 @@
   // Description:
   // During a CMake run, an error handle should add errors
   // to be displayed afterwards.
-  virtual void AddError(const char*, const char*) {}
+  virtual void AddError(const std::string&, const char*) {}
 
   // Description:
   // Turn debugging on. This will create ccmakelog.txt.
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index a41d051..4e887d6 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -19,9 +19,8 @@
   std::vector<std::string> const& messages, const char* title)
 {
   // Append all messages into on big string
-  std::vector<std::string>::const_iterator it;
-  for (it = messages.begin(); it != messages.end(); it++) {
-    this->Messages += (*it);
+  for (std::string const& message : messages) {
+    this->Messages += message;
     // Add one blank line after each message
     this->Messages += "\n\n";
   }
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 8ca7802..028e852 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -79,18 +79,11 @@
 // See if a cache entry is in the list of entries in the ui.
 bool cmCursesMainForm::LookForCacheEntry(const std::string& key)
 {
-  if (!this->Entries) {
-    return false;
-  }
-
-  std::vector<cmCursesCacheEntryComposite*>::iterator it;
-  for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
-    if (key == (*it)->Key) {
-      return true;
-    }
-  }
-
-  return false;
+  return this->Entries &&
+    std::any_of(this->Entries->begin(), this->Entries->end(),
+                [&key](cmCursesCacheEntryComposite* entry) {
+                  return key == entry->Key;
+                });
 }
 
 // Create new cmCursesCacheEntryComposite entries from the cache
@@ -107,10 +100,9 @@
   // Count non-internal and non-static entries
   int count = 0;
 
-  for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
-       it != cacheKeys.end(); ++it) {
+  for (std::string const& key : cacheKeys) {
     cmStateEnums::CacheEntryType t =
-      this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+      this->CMakeInstance->GetState()->GetCacheEntryType(key);
     if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
         t != cmStateEnums::UNINITIALIZED) {
       ++count;
@@ -130,11 +122,9 @@
     // Create the composites.
 
     // First add entries which are new
-    for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
-         it != cacheKeys.end(); ++it) {
-      std::string key = *it;
+    for (std::string const& key : cacheKeys) {
       cmStateEnums::CacheEntryType t =
-        this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+        this->CMakeInstance->GetState()->GetCacheEntryType(key);
       if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
           t == cmStateEnums::UNINITIALIZED) {
         continue;
@@ -148,11 +138,9 @@
     }
 
     // then add entries which are old
-    for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
-         it != cacheKeys.end(); ++it) {
-      std::string key = *it;
+    for (std::string const& key : cacheKeys) {
       cmStateEnums::CacheEntryType t =
-        this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+        this->CMakeInstance->GetState()->GetCacheEntryType(key);
       if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
           t == cmStateEnums::UNINITIALIZED) {
         continue;
@@ -190,13 +178,12 @@
   } else {
     // If normal mode, count only non-advanced entries
     this->NumberOfVisibleEntries = 0;
-    std::vector<cmCursesCacheEntryComposite*>::iterator it;
-    for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+    for (cmCursesCacheEntryComposite* entry : *this->Entries) {
       const char* existingValue =
-        this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+        this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-          (*it)->GetValue(), "ADVANCED");
+          entry->GetValue(), "ADVANCED");
       if (!existingValue || (!this->AdvancedMode && advanced)) {
         continue;
       }
@@ -217,27 +204,26 @@
 
   // Assign fields
   int j = 0;
-  std::vector<cmCursesCacheEntryComposite*>::iterator it;
-  for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+  for (cmCursesCacheEntryComposite* entry : *this->Entries) {
     const char* existingValue =
-      this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+      this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
     bool advanced =
       this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-        (*it)->GetValue(), "ADVANCED");
+        entry->GetValue(), "ADVANCED");
     if (!existingValue || (!this->AdvancedMode && advanced)) {
       continue;
     }
-    this->Fields[3 * j] = (*it)->Label->Field;
-    this->Fields[3 * j + 1] = (*it)->IsNewLabel->Field;
-    this->Fields[3 * j + 2] = (*it)->Entry->Field;
+    this->Fields[3 * j] = entry->Label->Field;
+    this->Fields[3 * j + 1] = entry->IsNewLabel->Field;
+    this->Fields[3 * j + 2] = entry->Entry->Field;
     j++;
   }
   // if no cache entries there should still be one dummy field
   if (j == 0) {
-    it = this->Entries->begin();
-    this->Fields[0] = (*it)->Label->Field;
-    this->Fields[1] = (*it)->IsNewLabel->Field;
-    this->Fields[2] = (*it)->Entry->Field;
+    const auto& front = *this->Entries->front();
+    this->Fields[0] = front.Label->Field;
+    this->Fields[1] = front.IsNewLabel->Field;
+    this->Fields[2] = front.Entry->Field;
     this->NumberOfVisibleEntries = 1;
   }
   // Has to be null terminated.
@@ -278,13 +264,12 @@
   } else {
     // If normal, display only non-advanced entries
     this->NumberOfVisibleEntries = 0;
-    std::vector<cmCursesCacheEntryComposite*>::iterator it;
-    for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+    for (cmCursesCacheEntryComposite* entry : *this->Entries) {
       const char* existingValue =
-        this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+        this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-          (*it)->GetValue(), "ADVANCED");
+          entry->GetValue(), "ADVANCED");
       if (!existingValue || (!this->AdvancedMode && advanced)) {
         continue;
       }
@@ -297,13 +282,12 @@
   if (height > 0) {
     bool isNewPage;
     int i = 0;
-    std::vector<cmCursesCacheEntryComposite*>::iterator it;
-    for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+    for (cmCursesCacheEntryComposite* entry : *this->Entries) {
       const char* existingValue =
-        this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+        this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-          (*it)->GetValue(), "ADVANCED");
+          entry->GetValue(), "ADVANCED");
       if (!existingValue || (!this->AdvancedMode && advanced)) {
         continue;
       }
@@ -314,10 +298,10 @@
       if (isNewPage) {
         this->NumberOfPages++;
       }
-      (*it)->Label->Move(left, top + row - 1, isNewPage);
-      (*it)->IsNewLabel->Move(left + 32, top + row - 1, false);
-      (*it)->Entry->Move(left + 33, top + row - 1, false);
-      (*it)->Entry->SetPage(this->NumberOfPages);
+      entry->Label->Move(left, top + row - 1, isNewPage);
+      entry->IsNewLabel->Move(left + 32, top + row - 1, false);
+      entry->Entry->Move(left + 33, top + row - 1, false);
+      entry->Entry->SetPage(this->NumberOfPages);
       i++;
     }
   }
@@ -506,14 +490,14 @@
   pos_form_cursor(this->Form);
 }
 
-void cmCursesMainForm::UpdateProgress(const char* msg, float prog)
+void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
 {
   char tmp[1024];
   const char* cmsg = tmp;
   if (prog >= 0) {
-    sprintf(tmp, "%s %i%%", msg, static_cast<int>(100 * prog));
+    sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog));
   } else {
-    cmsg = msg;
+    cmsg = msg.c_str();
   }
   this->UpdateStatusBar(cmsg);
   this->PrintKeys(1);
@@ -533,7 +517,9 @@
   touchwin(stdscr);
   refresh();
   this->CMakeInstance->SetProgressCallback(
-    [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+    [this](const std::string& msg, float prog) {
+      this->UpdateProgress(msg, prog);
+    });
 
   // always save the current gui values to disk
   this->FillCacheManagerFromUI();
@@ -603,7 +589,9 @@
   touchwin(stdscr);
   refresh();
   this->CMakeInstance->SetProgressCallback(
-    [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+    [this](const std::string& msg, float prog) {
+      this->UpdateProgress(msg, prog);
+    });
 
   // Get rid of previous errors
   this->Errors = std::vector<std::string>();
@@ -647,7 +635,8 @@
   return 0;
 }
 
-void cmCursesMainForm::AddError(const char* message, const char* /*unused*/)
+void cmCursesMainForm::AddError(const std::string& message,
+                                const char* /*unused*/)
 {
   this->Errors.emplace_back(message);
 }
@@ -658,28 +647,29 @@
     return;
   }
 
-  std::vector<cmCursesCacheEntryComposite*>::iterator it;
-  for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
-    const char* val = (*it)->GetValue();
-    if (val && !strcmp(value, val)) {
-      this->CMakeInstance->UnwatchUnusedCli(value);
-      this->Entries->erase(it);
-      break;
-    }
+  auto removeIt =
+    std::find_if(this->Entries->begin(), this->Entries->end(),
+                 [value](cmCursesCacheEntryComposite* entry) -> bool {
+                   const char* val = entry->GetValue();
+                   return val != nullptr && !strcmp(value, val);
+                 });
+
+  if (removeIt != this->Entries->end()) {
+    this->CMakeInstance->UnwatchUnusedCli(value);
+    this->Entries->erase(removeIt);
   }
 }
 
 // copy from the list box to the cache manager
 void cmCursesMainForm::FillCacheManagerFromUI()
 {
-  size_t size = this->Entries->size();
-  for (size_t i = 0; i < size; i++) {
-    std::string cacheKey = (*this->Entries)[i]->Key;
+  for (cmCursesCacheEntryComposite* entry : *this->Entries) {
+    const std::string& cacheKey = entry->Key;
     const char* existingValue =
       this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
     if (existingValue) {
       std::string oldValue = existingValue;
-      std::string newValue = (*this->Entries)[i]->Entry->GetValue();
+      std::string newValue = entry->Entry->GetValue();
       std::string fixedOldValue;
       std::string fixedNewValue;
       cmStateEnums::CacheEntryType t =
@@ -975,17 +965,14 @@
 
           if (nextCur) {
             // make the next or prev. current field after deletion
-            nextCur = nullptr;
-            std::vector<cmCursesCacheEntryComposite*>::iterator it;
-            for (it = this->Entries->begin(); it != this->Entries->end();
-                 ++it) {
-              if (nextVal == (*it)->Key) {
-                nextCur = (*it)->Entry->Field;
-              }
-            }
+            auto nextEntryIt =
+              std::find_if(this->Entries->begin(), this->Entries->end(),
+                           [&nextVal](cmCursesCacheEntryComposite* entry) {
+                             return nextVal == entry->Key;
+                           });
 
-            if (nextCur) {
-              set_current_field(this->Form, nextCur);
+            if (nextEntryIt != this->Entries->end()) {
+              set_current_field(this->Form, (*nextEntryIt)->Entry->Field);
             }
           }
         }
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index cc6482f..d379975 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -81,7 +81,7 @@
    * During a CMake run, an error handle should add errors
    * to be displayed afterwards.
    */
-  void AddError(const char* message, const char* title) override;
+  void AddError(const std::string& message, const char* title) override;
 
   /**
    * Used to do a configure. If argument is specified, it does only the check
@@ -102,7 +102,7 @@
   /**
    * Progress callback
    */
-  void UpdateProgress(const char* msg, float prog);
+  void UpdateProgress(const std::string& msg, float prog);
 
 protected:
   // Copy the cache values from the user interface to the actual
diff --git a/Source/LexerParser/cmCommandArgumentParser.cxx b/Source/LexerParser/cmCommandArgumentParser.cxx
index 68b9e6c..b965b32 100644
--- a/Source/LexerParser/cmCommandArgumentParser.cxx
+++ b/Source/LexerParser/cmCommandArgumentParser.cxx
@@ -513,7 +513,7 @@
 static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "cal_ENVCURLY", "cal_NCURLY",
-  "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", "\"\\\\\"",
+  "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", R"("\\")",
   "cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept", "Start",
   "GoalWithOptionalBackSlash", "Goal", "String", "OuterText", "Variable",
   "EnvVarName", "MultipleIds", "ID", YY_NULLPTR
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 9ce0323..cb89d19 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -2,9 +2,6 @@
 # file Copyright.txt or https://cmake.org/licensing for details.
 
 project(QtDialog)
-if(POLICY CMP0020)
-  cmake_policy(SET CMP0020 NEW) # Drop when CMake >= 2.8.11 required
-endif()
 CMake_OPTIONAL_COMPONENT(cmake-gui)
 find_package(Qt5Widgets QUIET)
 if (Qt5Widgets_FOUND)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index cd30ad5..8d9a50c 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -48,6 +48,9 @@
 
 #if defined(USE_QWindowsIntegrationPlugin)
 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
+#  if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
+#  endif
 #endif
 
 int main(int argc, char** argv)
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index 72cce9f..5f6ccca 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -303,7 +303,6 @@
 #ifdef QT_WINEXTRAS
   this->TaskbarButton = new QWinTaskbarButton(this);
   this->TaskbarButton->setWindow(this->windowHandle());
-  this->TaskbarButton->setOverlayIcon(QIcon(":/loading.png"));
 #endif
 }
 
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index f28e1a8..364a378 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -95,33 +95,32 @@
 
   QStringList generator_list;
 
-  std::vector<cmake::GeneratorInfo>::const_iterator it;
-  for (it = gens.begin(); it != gens.end(); ++it) {
-    generator_list.append(QString::fromLocal8Bit(it->name.c_str()));
+  for (cmake::GeneratorInfo const& gen : gens) {
+    generator_list.append(QString::fromLocal8Bit(gen.name.c_str()));
 
-    if (it->supportsPlatform) {
+    if (gen.supportsPlatform) {
       this->GeneratorsSupportingPlatform.append(
-        QString::fromLocal8Bit(it->name.c_str()));
+        QString::fromLocal8Bit(gen.name.c_str()));
 
       this
-        ->GeneratorDefaultPlatform[QString::fromLocal8Bit(it->name.c_str())] =
-        QString::fromLocal8Bit(it->defaultPlatform.c_str());
+        ->GeneratorDefaultPlatform[QString::fromLocal8Bit(gen.name.c_str())] =
+        QString::fromLocal8Bit(gen.defaultPlatform.c_str());
 
       std::vector<std::string>::const_iterator platformIt =
-        it->supportedPlatforms.cbegin();
-      while (platformIt != it->supportedPlatforms.cend()) {
+        gen.supportedPlatforms.cbegin();
+      while (platformIt != gen.supportedPlatforms.cend()) {
 
         this->GeneratorSupportedPlatforms.insert(
-          QString::fromLocal8Bit(it->name.c_str()),
+          QString::fromLocal8Bit(gen.name.c_str()),
           QString::fromLocal8Bit((*platformIt).c_str()));
 
         platformIt++;
       }
     }
 
-    if (it->supportsToolset) {
+    if (gen.supportsToolset) {
       this->GeneratorsSupportingToolset.append(
-        QString::fromLocal8Bit(it->name.c_str()));
+        QString::fromLocal8Bit(gen.name.c_str()));
     }
   }
 
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index a073c30..f357f90 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -25,7 +25,7 @@
   cmSystemTools::SetRunCommandHideConsole(true);
 
   cmSystemTools::SetMessageCallback(
-    [this](const char* msg, const char* title) {
+    [this](std::string const& msg, const char* title) {
       this->messageCallback(msg, title);
     });
   cmSystemTools::SetStdoutCallback(
@@ -37,7 +37,7 @@
   this->CMakeInstance->SetCMakeEditCommand(
     cmSystemTools::GetCMakeGUICommand());
   this->CMakeInstance->SetProgressCallback(
-    [this](const char* msg, float percent) {
+    [this](const std::string& msg, float percent) {
       this->progressCallback(msg, percent);
     });
 
@@ -48,9 +48,8 @@
   this->CMakeInstance->GetRegisteredGenerators(
     generators, /*includeNamesWithPlatform=*/false);
 
-  std::vector<cmake::GeneratorInfo>::const_iterator it;
-  for (it = generators.begin(); it != generators.end(); ++it) {
-    this->AvailableGenerators.push_back(*it);
+  for (cmake::GeneratorInfo const& gen : generators) {
+    this->AvailableGenerators.push_back(gen);
   }
 }
 
@@ -234,24 +233,23 @@
   // set the value of properties
   cmState* state = this->CMakeInstance->GetState();
   std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
-  for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
-       it != cacheKeys.end(); ++it) {
-    cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*it);
+  for (std::string const& key : cacheKeys) {
+    cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
     if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC) {
       continue;
     }
 
     QCMakeProperty prop;
-    prop.Key = QString::fromLocal8Bit(it->c_str());
+    prop.Key = QString::fromLocal8Bit(key.c_str());
     int idx = props.indexOf(prop);
     if (idx == -1) {
-      toremove.append(QString::fromLocal8Bit(it->c_str()));
+      toremove.append(QString::fromLocal8Bit(key.c_str()));
     } else {
       prop = props[idx];
       if (prop.Value.type() == QVariant::Bool) {
-        state->SetCacheEntryValue(*it, prop.Value.toBool() ? "ON" : "OFF");
+        state->SetCacheEntryValue(key, prop.Value.toBool() ? "ON" : "OFF");
       } else {
-        state->SetCacheEntryValue(*it,
+        state->SetCacheEntryValue(key,
                                   prop.Value.toString().toLocal8Bit().data());
       }
       props.removeAt(idx);
@@ -297,22 +295,21 @@
 
   cmState* state = this->CMakeInstance->GetState();
   std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
-  for (std::vector<std::string>::const_iterator i = cacheKeys.begin();
-       i != cacheKeys.end(); ++i) {
-    cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*i);
+  for (std::string const& key : cacheKeys) {
+    cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
     if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
         t == cmStateEnums::UNINITIALIZED) {
       continue;
     }
 
-    const char* cachedValue = state->GetCacheEntryValue(*i);
+    const char* cachedValue = state->GetCacheEntryValue(key);
 
     QCMakeProperty prop;
-    prop.Key = QString::fromLocal8Bit(i->c_str());
+    prop.Key = QString::fromLocal8Bit(key.c_str());
     prop.Help =
-      QString::fromLocal8Bit(state->GetCacheEntryProperty(*i, "HELPSTRING"));
+      QString::fromLocal8Bit(state->GetCacheEntryProperty(key, "HELPSTRING"));
     prop.Value = QString::fromLocal8Bit(cachedValue);
-    prop.Advanced = state->GetCacheEntryPropertyAsBool(*i, "ADVANCED");
+    prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED");
     if (t == cmStateEnums::BOOL) {
       prop.Type = QCMakeProperty::BOOL;
       prop.Value = cmSystemTools::IsOn(cachedValue);
@@ -323,7 +320,7 @@
     } else if (t == cmStateEnums::STRING) {
       prop.Type = QCMakeProperty::STRING;
       const char* stringsProperty =
-        state->GetCacheEntryProperty(*i, "STRINGS");
+        state->GetCacheEntryProperty(key, "STRINGS");
       if (stringsProperty) {
         prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
       }
@@ -349,19 +346,19 @@
 #endif
 }
 
-void QCMake::progressCallback(const char* msg, float percent)
+void QCMake::progressCallback(const std::string& msg, float percent)
 {
   if (percent >= 0) {
-    emit this->progressChanged(QString::fromLocal8Bit(msg), percent);
+    emit this->progressChanged(QString::fromStdString(msg), percent);
   } else {
-    emit this->outputMessage(QString::fromLocal8Bit(msg));
+    emit this->outputMessage(QString::fromStdString(msg));
   }
   QCoreApplication::processEvents();
 }
 
-void QCMake::messageCallback(const char* msg, const char* /*title*/)
+void QCMake::messageCallback(std::string const& msg, const char* /*title*/)
 {
-  emit this->errorMessage(QString::fromLocal8Bit(msg));
+  emit this->errorMessage(QString::fromStdString(msg));
   QCoreApplication::processEvents();
 }
 
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index ef4d2a1..f2fd6d9 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -168,8 +168,8 @@
   cmake* CMakeInstance;
 
   bool interruptCallback();
-  void progressCallback(const char* msg, float percent);
-  void messageCallback(const char* msg, const char* title);
+  void progressCallback(std::string const& msg, float percent);
+  void messageCallback(std::string const& msg, const char* title);
   void stdoutCallback(std::string const& msg);
   void stderrCallback(std::string const& msg);
 
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
index 021bd29..4956a47 100644
--- a/Source/cmAddDependenciesCommand.cxx
+++ b/Source/cmAddDependenciesCommand.cxx
@@ -6,6 +6,7 @@
 
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmTarget.h"
 
 class cmExecutionStatus;
@@ -27,10 +28,10 @@
     this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
   }
   if (cmTarget* target = this->Makefile->FindTargetToUse(target_name)) {
-    std::vector<std::string>::const_iterator s = args.begin();
-    ++s; // skip over target_name
-    for (; s != args.end(); ++s) {
-      target->AddUtility(*s, this->Makefile);
+
+    // skip over target_name
+    for (std::string const& arg : cmMakeRange(args).advance(1)) {
+      target->AddUtility(arg, this->Makefile);
     }
   } else {
     std::ostringstream e;
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
index 5149333..adf4464 100644
--- a/Source/cmAddLibraryCommand.cxx
+++ b/Source/cmAddLibraryCommand.cxx
@@ -222,7 +222,9 @@
         aliasedType != cmStateEnums::STATIC_LIBRARY &&
         aliasedType != cmStateEnums::MODULE_LIBRARY &&
         aliasedType != cmStateEnums::OBJECT_LIBRARY &&
-        aliasedType != cmStateEnums::INTERFACE_LIBRARY) {
+        aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
+        !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
+          aliasedTarget->IsImported())) {
       std::ostringstream e;
       e << "cannot create ALIAS target \"" << libName << "\" because target \""
         << aliasedName << "\" is not a library.";
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
index 75e5aa4..7947188 100644
--- a/Source/cmAddSubDirectoryCommand.cxx
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -6,6 +6,7 @@
 #include <string.h>
 
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 
 class cmExecutionStatus;
@@ -26,15 +27,13 @@
   bool excludeFromAll = false;
 
   // process the rest of the arguments looking for optional args
-  std::vector<std::string>::const_iterator i = args.begin();
-  ++i;
-  for (; i != args.end(); ++i) {
-    if (*i == "EXCLUDE_FROM_ALL") {
+  for (std::string const& arg : cmMakeRange(args).advance(1)) {
+    if (arg == "EXCLUDE_FROM_ALL") {
       excludeFromAll = true;
       continue;
     }
     if (binArg.empty()) {
-      binArg = *i;
+      binArg = arg;
     } else {
       this->SetError("called with incorrect number of arguments");
       return false;
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index d38b0d1..0980416 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -5,6 +5,8 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include "cmRange.h"
+
 #include "cm_kwiml.h"
 #include <algorithm>
 #include <functional>
@@ -156,57 +158,12 @@
 };
 }
 
-template <typename const_iterator_>
-struct cmRange
-{
-  typedef const_iterator_ const_iterator;
-  typedef typename std::iterator_traits<const_iterator>::value_type value_type;
-  typedef typename std::iterator_traits<const_iterator>::difference_type
-    difference_type;
-  cmRange(const_iterator begin_, const_iterator end_)
-    : Begin(begin_)
-    , End(end_)
-  {
-  }
-  const_iterator begin() const { return Begin; }
-  const_iterator end() const { return End; }
-  bool empty() const { return std::distance(Begin, End) == 0; }
-  difference_type size() const { return std::distance(Begin, End); }
-  cmRange& advance(KWIML_INT_intptr_t amount)
-  {
-    std::advance(Begin, amount);
-    return *this;
-  }
-
-  cmRange& retreat(KWIML_INT_intptr_t amount)
-  {
-    std::advance(End, -amount);
-    return *this;
-  }
-
-private:
-  const_iterator Begin;
-  const_iterator End;
-};
-
 typedef cmRange<std::vector<std::string>::const_iterator> cmStringRange;
 
 class cmListFileBacktrace;
 typedef cmRange<std::vector<cmListFileBacktrace>::const_iterator>
   cmBacktraceRange;
 
-template <typename Iter1, typename Iter2>
-cmRange<Iter1> cmMakeRange(Iter1 begin, Iter2 end)
-{
-  return cmRange<Iter1>(begin, end);
-}
-
-template <typename Range>
-cmRange<typename Range::const_iterator> cmMakeRange(Range const& range)
-{
-  return cmRange<typename Range::const_iterator>(range.begin(), range.end());
-}
-
 template <typename Range>
 void cmDeleteAll(Range const& r)
 {
@@ -276,27 +233,45 @@
                         ContainerAlgorithms::BinarySearcher<MatchRange>(m));
 }
 
+template <typename ForwardIterator>
+ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
+{
+  using Value = typename std::iterator_traits<ForwardIterator>::value_type;
+  using Hash = struct
+  {
+    std::size_t operator()(ForwardIterator it) const
+    {
+      return std::hash<Value>{}(*it);
+    }
+  };
+
+  using Equal = struct
+  {
+    bool operator()(ForwardIterator it1, ForwardIterator it2) const
+    {
+      return *it1 == *it2;
+    }
+  };
+  std::unordered_set<ForwardIterator, Hash, Equal> uniq;
+
+  ForwardIterator result = first;
+  while (first != last) {
+    if (uniq.find(first) == uniq.end()) {
+      if (result != first) {
+        *result = std::move(*first);
+      }
+      uniq.insert(result);
+      ++result;
+    }
+    ++first;
+  }
+  return result;
+}
+
 template <typename Range>
 typename Range::const_iterator cmRemoveDuplicates(Range& r)
 {
-  typedef typename Range::value_type T;
-  std::unordered_set<T> unique;
-  std::vector<size_t> indices;
-  size_t count = 0;
-  const typename Range::const_iterator end = r.end();
-  for (typename Range::const_iterator it = r.begin(); it != end;
-       ++it, ++count) {
-    const typename std::unordered_set<T>::iterator occur = unique.find(*it);
-    if (occur == unique.end()) {
-      unique.insert(*it);
-    } else {
-      indices.push_back(count);
-    }
-  }
-  if (indices.empty()) {
-    return end;
-  }
-  return cmRemoveIndices(r, indices);
+  return cmRemoveDuplicates(r.begin(), r.end());
 }
 
 template <typename Range>
@@ -322,14 +297,6 @@
   return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; });
 }
 
-template <typename Range>
-cmRange<typename Range::const_reverse_iterator> cmReverseRange(
-  Range const& range)
-{
-  return cmRange<typename Range::const_reverse_iterator>(range.rbegin(),
-                                                         range.rend());
-}
-
 template <class Iter>
 std::reverse_iterator<Iter> cmMakeReverseIterator(Iter it)
 {
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index 6e5109a..177ba02 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -54,6 +54,8 @@
   {
   }
   ~Entry() { archive_entry_free(this->Object); }
+  Entry(const Entry&) = delete;
+  Entry& operator=(const Entry&) = delete;
   operator struct archive_entry*() { return this->Object; }
 };
 
@@ -177,12 +179,10 @@
 bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix,
                          bool recursive)
 {
-  if (this->Okay()) {
-    if (!path.empty() && path.back() == '/') {
-      path.erase(path.size() - 1);
-    }
-    this->AddPath(path.c_str(), skip, prefix, recursive);
+  if (!path.empty() && path.back() == '/') {
+    path.erase(path.size() - 1);
   }
+  this->AddPath(path.c_str(), skip, prefix, recursive);
   return this->Okay();
 }
 
@@ -218,6 +218,7 @@
 
 bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
 {
+  this->Error = "";
   // Skip the file if we have no name for it.  This may happen on a
   // top-level directory, which does not need to be included anyway.
   if (skip >= strlen(file)) {
@@ -239,7 +240,7 @@
   cm_archive_entry_copy_pathname(e, dest);
   if (archive_read_disk_entry_from_file(this->Disk, e, -1, nullptr) !=
       ARCHIVE_OK) {
-    this->Error = "archive_read_disk_entry_from_file '";
+    this->Error = "Unable to read from file '";
     this->Error += file;
     this->Error += "': ";
     this->Error += cm_archive_error_string(this->Disk);
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
index 6ecdd63..1f23dae 100644
--- a/Source/cmArchiveWrite.h
+++ b/Source/cmArchiveWrite.h
@@ -58,6 +58,9 @@
 
   ~cmArchiveWrite();
 
+  cmArchiveWrite(const cmArchiveWrite&) = delete;
+  cmArchiveWrite& operator=(const cmArchiveWrite&) = delete;
+
   /**
    * Add a path (file or directory) to the archive.  Directories are
    * added recursively.  The "path" must be readable on disk, either
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
new file mode 100644
index 0000000..751d117
--- /dev/null
+++ b/Source/cmArgumentParser.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmArgumentParser.h"
+
+#include <algorithm>
+#include <type_traits>
+
+namespace ArgumentParser {
+
+auto ActionMap::Emplace(cm::string_view name, Action 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;
+                     });
+  return (it != this->end() && it->first == name)
+    ? std::make_pair(it, false)
+    : std::make_pair(this->emplace(it, name, std::move(action)), true);
+}
+
+auto ActionMap::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;
+                     });
+  return (it != this->end() && it->first == name) ? it : this->end();
+}
+
+void Instance::Bind(bool& val)
+{
+  val = true;
+  this->CurrentString = nullptr;
+  this->CurrentList = nullptr;
+  this->ExpectValue = false;
+}
+
+void Instance::Bind(std::string& val)
+{
+  this->CurrentString = &val;
+  this->CurrentList = nullptr;
+  this->ExpectValue = true;
+}
+
+void Instance::Bind(StringList& val)
+{
+  this->CurrentString = nullptr;
+  this->CurrentList = &val;
+  this->ExpectValue = true;
+}
+
+void Instance::Bind(MultiStringList& val)
+{
+  this->CurrentString = nullptr;
+  this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back());
+  this->ExpectValue = false;
+}
+
+void Instance::Consume(cm::string_view arg, void* result,
+                       std::vector<std::string>* unparsedArguments,
+                       std::vector<std::string>* keywordsMissingValue)
+{
+  auto const it = this->Bindings.Find(arg);
+  if (it != this->Bindings.end()) {
+    it->second(*this, result);
+    if (this->ExpectValue && keywordsMissingValue != nullptr) {
+      keywordsMissingValue->emplace_back(arg);
+    }
+    return;
+  }
+
+  if (this->CurrentString != nullptr) {
+    this->CurrentString->assign(std::string(arg));
+    this->CurrentString = nullptr;
+    this->CurrentList = nullptr;
+  } else if (this->CurrentList != nullptr) {
+    this->CurrentList->emplace_back(arg);
+  } else if (unparsedArguments != nullptr) {
+    unparsedArguments->emplace_back(arg);
+  }
+
+  if (this->ExpectValue) {
+    if (keywordsMissingValue != nullptr) {
+      keywordsMissingValue->pop_back();
+    }
+    this->ExpectValue = false;
+  }
+}
+
+} // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
new file mode 100644
index 0000000..6cfe946
--- /dev/null
+++ b/Source/cmArgumentParser.h
@@ -0,0 +1,143 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmArgumentParser_h
+#define cmArgumentParser_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
+
+#include <cassert>
+#include <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace ArgumentParser {
+
+using StringList = std::vector<std::string>;
+using MultiStringList = std::vector<StringList>;
+
+class Instance;
+using Action = std::function<void(Instance&, void*)>;
+
+// using ActionMap = cm::flat_map<cm::string_view, Action>;
+class ActionMap : public std::vector<std::pair<cm::string_view, Action>>
+{
+public:
+  std::pair<iterator, bool> Emplace(cm::string_view name, Action action);
+  const_iterator Find(cm::string_view name) const;
+};
+
+class Instance
+{
+public:
+  Instance(ActionMap const& bindings)
+    : Bindings(bindings)
+  {
+  }
+
+  void Bind(bool& val);
+  void Bind(std::string& val);
+  void Bind(StringList& val);
+  void Bind(MultiStringList& val);
+
+  void Consume(cm::string_view arg, void* result,
+               std::vector<std::string>* unparsedArguments,
+               std::vector<std::string>* keywordsMissingValue);
+
+private:
+  ActionMap const& Bindings;
+  std::string* CurrentString = nullptr;
+  StringList* CurrentList = nullptr;
+  bool ExpectValue = false;
+};
+
+} // namespace ArgumentParser
+
+template <typename Result>
+class cmArgumentParser
+{
+public:
+  // 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>
+  cmArgumentParser& Bind(cm::static_string_view name, T Result::*member)
+  {
+    bool const inserted =
+      this->Bindings
+        .Emplace(name,
+                 [member](ArgumentParser::Instance& instance, void* result) {
+                   instance.Bind(static_cast<Result*>(result)->*member);
+                 })
+        .second;
+    assert(inserted), (void)inserted;
+    return *this;
+  }
+
+  template <typename Range>
+  void Parse(Result& result, Range const& args,
+             std::vector<std::string>* unparsedArguments = nullptr,
+             std::vector<std::string>* keywordsMissingValue = nullptr) const
+  {
+    ArgumentParser::Instance instance(this->Bindings);
+    for (cm::string_view arg : args) {
+      instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue);
+    }
+  }
+
+  template <typename Range>
+  Result Parse(Range const& args,
+               std::vector<std::string>* unparsedArguments = nullptr,
+               std::vector<std::string>* keywordsMissingValue = nullptr) const
+  {
+    Result result;
+    this->Parse(result, args, unparsedArguments, keywordsMissingValue);
+    return result;
+  }
+
+private:
+  ArgumentParser::ActionMap Bindings;
+};
+
+template <>
+class cmArgumentParser<void>
+{
+public:
+  template <typename T>
+  cmArgumentParser& Bind(cm::static_string_view name, T& ref)
+  {
+    bool const inserted = this->Bind(cm::string_view(name), ref);
+    assert(inserted), (void)inserted;
+    return *this;
+  }
+
+  template <typename Range>
+  void Parse(Range const& args,
+             std::vector<std::string>* unparsedArguments = nullptr,
+             std::vector<std::string>* keywordsMissingValue = nullptr) const
+  {
+    ArgumentParser::Instance instance(this->Bindings);
+    for (cm::string_view arg : args) {
+      instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue);
+    }
+  }
+
+protected:
+  template <typename T>
+  bool Bind(cm::string_view name, T& ref)
+  {
+    return this->Bindings
+      .Emplace(name,
+               [&ref](ArgumentParser::Instance& instance, void*) {
+                 instance.Bind(ref);
+               })
+      .second;
+  }
+
+private:
+  ArgumentParser::ActionMap Bindings;
+};
+
+#endif
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
index 4218d81..4b4bca2 100644
--- a/Source/cmCMakeMinimumRequired.cxx
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -55,7 +55,7 @@
       (version_min.empty() || version_max.empty())) {
     std::ostringstream e;
     e << "VERSION \"" << version_string
-      << "\" does not have a version on both sides of \"...\".";
+      << R"(" does not have a version on both sides of "...".)";
     this->SetError(e.str());
     return false;
   }
diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx
index ac30e1a..8da5ef7 100644
--- a/Source/cmCMakePolicyCommand.cxx
+++ b/Source/cmCMakePolicyCommand.cxx
@@ -176,7 +176,7 @@
       (version_min.empty() || version_max.empty())) {
     std::ostringstream e;
     e << "VERSION \"" << version_string
-      << "\" does not have a version on both sides of \"...\".";
+      << R"(" does not have a version on both sides of "...".)";
     this->SetError(e.str());
     return false;
   }
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index c0088ac..5efc784 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -491,12 +491,16 @@
   typedef std::map<cmSourceFile*, cmCPluginAPISourceFile*> derived;
   typedef derived::iterator iterator;
   typedef derived::value_type value_type;
+  cmCPluginAPISourceFileMap() = default;
   ~cmCPluginAPISourceFileMap()
   {
     for (auto const& i : *this) {
       delete i.second;
     }
   }
+  cmCPluginAPISourceFileMap(const cmCPluginAPISourceFileMap&) = delete;
+  cmCPluginAPISourceFileMap& operator=(const cmCPluginAPISourceFileMap&) =
+    delete;
 };
 cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
 
@@ -683,26 +687,24 @@
   }
 
   // Next, try the various source extensions
-  for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
-       ext != sourceExts.end(); ++ext) {
+  for (std::string const& ext : sourceExts) {
     hname = pathname;
     hname += ".";
-    hname += *ext;
+    hname += ext;
     if (cmSystemTools::FileExists(hname)) {
-      sf->SourceExtension = *ext;
+      sf->SourceExtension = ext;
       sf->FullPath = hname;
       return;
     }
   }
 
   // Finally, try the various header extensions
-  for (std::vector<std::string>::const_iterator ext = headerExts.begin();
-       ext != headerExts.end(); ++ext) {
+  for (std::string const& ext : headerExts) {
     hname = pathname;
     hname += ".";
-    hname += *ext;
+    hname += ext;
     if (cmSystemTools::FileExists(hname)) {
-      sf->SourceExtension = *ext;
+      sf->SourceExtension = ext;
       sf->FullPath = hname;
       return;
     }
@@ -711,13 +713,11 @@
   std::ostringstream e;
   e << "Cannot find source file \"" << pathname << "\"";
   e << "\n\nTried extensions";
-  for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
-       ext != sourceExts.end(); ++ext) {
-    e << " ." << *ext;
+  for (std::string const& ext : sourceExts) {
+    e << " ." << ext;
   }
-  for (std::vector<std::string>::const_iterator ext = headerExts.begin();
-       ext != headerExts.end(); ++ext) {
-    e << " ." << *ext;
+  for (std::string const& ext : headerExts) {
+    e << " ." << ext;
   }
   cmSystemTools::Error(e.str());
 }
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 989c7ee..709feac 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -43,7 +43,6 @@
 #include "cmCTestTestHandler.h"
 #include "cmCTestUpdateHandler.h"
 #include "cmCTestUploadHandler.h"
-#include "cmCurl.h"
 #include "cmDynamicLoader.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
@@ -62,12 +61,149 @@
 #  include <be/kernel/OS.h> /* disable_debugger() API. */
 #endif
 
-#define DEBUGOUT                                                              \
-  std::cout << __LINE__ << " ";                                               \
-  std::cout
-#define DEBUGERR                                                              \
-  std::cerr << __LINE__ << " ";                                               \
-  std::cerr
+struct cmCTest::Private
+{
+  /** Representation of one part.  */
+  struct PartInfo
+  {
+    void SetName(const std::string& name) { this->Name = name; }
+    const std::string& GetName() const { return this->Name; }
+
+    void Enable() { this->Enabled = true; }
+    explicit operator bool() const { return this->Enabled; }
+
+    std::vector<std::string> SubmitFiles;
+
+  private:
+    bool Enabled = false;
+    std::string Name;
+  };
+
+  int RepeatTests = 1; // default to run each test once
+  bool RepeatUntilFail = false;
+  std::string ConfigType;
+  std::string ScheduleType;
+  std::chrono::system_clock::time_point StopTime;
+  bool TestProgressOutput = false;
+  bool Verbose = false;
+  bool ExtraVerbose = false;
+  bool ProduceXML = false;
+  bool LabelSummary = true;
+  bool SubprojectSummary = true;
+  bool UseHTTP10 = false;
+  bool PrintLabels = false;
+  bool Failover = false;
+
+  bool FlushTestProgressLine = false;
+
+  bool ForceNewCTestProcess = false;
+
+  bool RunConfigurationScript = false;
+
+  // these are helper classes
+  cmCTestBuildHandler BuildHandler;
+  cmCTestBuildAndTestHandler BuildAndTestHandler;
+  cmCTestCoverageHandler CoverageHandler;
+  cmCTestScriptHandler ScriptHandler;
+  cmCTestTestHandler TestHandler;
+  cmCTestUpdateHandler UpdateHandler;
+  cmCTestConfigureHandler ConfigureHandler;
+  cmCTestMemCheckHandler MemCheckHandler;
+  cmCTestSubmitHandler SubmitHandler;
+  cmCTestUploadHandler UploadHandler;
+
+  std::vector<cmCTestGenericHandler*> GetTestingHandlers()
+  {
+    return { &this->BuildHandler,     &this->BuildAndTestHandler,
+             &this->CoverageHandler,  &this->ScriptHandler,
+             &this->TestHandler,      &this->UpdateHandler,
+             &this->ConfigureHandler, &this->MemCheckHandler,
+             &this->SubmitHandler,    &this->UploadHandler };
+  }
+
+  std::map<std::string, cmCTestGenericHandler*> GetNamedTestingHandlers()
+  {
+    return { { "build", &this->BuildHandler },
+             { "buildtest", &this->BuildAndTestHandler },
+             { "coverage", &this->CoverageHandler },
+             { "script", &this->ScriptHandler },
+             { "test", &this->TestHandler },
+             { "update", &this->UpdateHandler },
+             { "configure", &this->ConfigureHandler },
+             { "memcheck", &this->MemCheckHandler },
+             { "submit", &this->SubmitHandler },
+             { "upload", &this->UploadHandler } };
+  }
+
+  bool ShowOnly = false;
+  bool OutputAsJson = false;
+  int OutputAsJsonVersion = 1;
+
+  // TODO: The ctest configuration should be a hierarchy of
+  // configuration option sources: command-line, script, ini file.
+  // Then the ini file can get re-loaded whenever it changes without
+  // affecting any higher-precedence settings.
+  std::map<std::string, std::string> CTestConfiguration;
+  std::map<std::string, std::string> CTestConfigurationOverwrites;
+
+  PartInfo Parts[PartCount];
+  std::map<std::string, Part> PartMap;
+
+  std::string CurrentTag;
+  bool TomorrowTag = false;
+
+  int TestModel = cmCTest::EXPERIMENTAL;
+  std::string SpecificTrack;
+
+  cmDuration TimeOut = cmDuration::zero();
+
+  cmDuration GlobalTimeout = cmDuration::zero();
+
+  int MaxTestNameWidth = 30;
+
+  int ParallelLevel = 1;
+  bool ParallelLevelSetInCli = false;
+
+  unsigned long TestLoad = 0;
+
+  int CompatibilityMode;
+
+  // information for the --build-and-test options
+  std::string BinaryDir;
+
+  std::string NotesFiles;
+
+  bool InteractiveDebugMode = true;
+
+  bool ShortDateFormat = true;
+
+  bool CompressXMLFiles = false;
+  bool CompressTestOutput = true;
+
+  // By default we write output to the process output streams.
+  std::ostream* StreamOut = &std::cout;
+  std::ostream* StreamErr = &std::cerr;
+
+  bool SuppressUpdatingCTestConfiguration = false;
+
+  bool Debug = false;
+  bool ShowLineNumbers = false;
+  bool Quiet = false;
+
+  std::string BuildID;
+
+  std::vector<std::string> InitialCommandLineArguments;
+
+  int SubmitIndex = 0;
+
+  cmGeneratedFileStream* OutputLogFile = nullptr;
+  int OutputLogFileLastTag = -1;
+
+  bool OutputTestOutputOnTestFailure = false;
+  bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
+
+  std::map<std::string, std::string> Definitions;
+};
 
 struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
 {
@@ -123,6 +259,11 @@
   return lctime;
 }
 
+bool cmCTest::GetTomorrowTag() const
+{
+  return this->Impl->TomorrowTag;
+}
+
 std::string cmCTest::CleanString(const std::string& str)
 {
   std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
@@ -142,7 +283,7 @@
   struct tm* t = localtime(&currenttime);
   // return ::CleanString(ctime(&currenttime));
   char current_time[1024];
-  if (this->ShortDateFormat) {
+  if (this->Impl->ShortDateFormat) {
     strftime(current_time, 1000, "%b %d %H:%M %Z", t);
   } else {
     strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
@@ -160,88 +301,6 @@
   return fname;
 }
 
-#ifdef CMAKE_BUILD_WITH_CMAKE
-static size_t HTTPResponseCallback(void* ptr, size_t size, size_t nmemb,
-                                   void* data)
-{
-  int realsize = static_cast<int>(size * nmemb);
-
-  std::string* response = static_cast<std::string*>(data);
-  const char* chPtr = static_cast<char*>(ptr);
-  *response += chPtr;
-
-  return realsize;
-}
-
-int cmCTest::HTTPRequest(std::string url, HTTPMethod method,
-                         std::string& response, std::string const& fields,
-                         std::string const& putFile, int timeout)
-{
-  CURL* curl;
-  FILE* file;
-  ::curl_global_init(CURL_GLOBAL_ALL);
-  curl = ::curl_easy_init();
-  cmCurlSetCAInfo(curl);
-
-  // set request options based on method
-  switch (method) {
-    case cmCTest::HTTP_POST:
-      ::curl_easy_setopt(curl, CURLOPT_POST, 1);
-      ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.c_str());
-      break;
-    case cmCTest::HTTP_PUT:
-      if (!cmSystemTools::FileExists(putFile)) {
-        response = "Error: File ";
-        response += putFile + " does not exist.\n";
-        return -1;
-      }
-      ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
-      file = cmsys::SystemTools::Fopen(putFile, "rb");
-      ::curl_easy_setopt(curl, CURLOPT_INFILE, file);
-      // fall through to append GET fields
-      CM_FALLTHROUGH;
-    case cmCTest::HTTP_GET:
-      if (!fields.empty()) {
-        url += "?" + fields;
-      }
-      break;
-  }
-
-  ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
-  ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
-  ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-
-  // set response options
-  ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HTTPResponseCallback);
-  ::curl_easy_setopt(curl, CURLOPT_FILE, &response);
-  ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
-
-  CURLcode res = ::curl_easy_perform(curl);
-
-  ::curl_easy_cleanup(curl);
-  ::curl_global_cleanup();
-
-  return static_cast<int>(res);
-}
-#endif
-
-std::string cmCTest::MakeURLSafe(const std::string& str)
-{
-  std::ostringstream ost;
-  char buffer[10];
-  for (unsigned char ch : str) {
-    if ((ch > 126 || ch < 32 || ch == '&' || ch == '%' || ch == '+' ||
-         ch == '=' || ch == '@') &&
-        ch != 9) {
-      sprintf(buffer, "%02x;", static_cast<unsigned int>(ch));
-      ost << buffer;
-    } else {
-      ost << ch;
-    }
-  }
-  return ost.str();
-}
-
 std::string cmCTest::DecodeURL(const std::string& in)
 {
   std::string out;
@@ -258,92 +317,39 @@
 }
 
 cmCTest::cmCTest()
+  : Impl(new Private)
 {
-  this->LabelSummary = true;
-  this->SubprojectSummary = true;
-  this->ParallelLevel = 1;
-  this->ParallelLevelSetInCli = false;
-  this->TestLoad = 0;
-  this->SubmitIndex = 0;
-  this->Failover = false;
-  this->ForceNewCTestProcess = false;
-  this->TomorrowTag = false;
-  this->TestProgressOutput = false;
-  this->FlushTestProgressLine = false;
-  this->Verbose = false;
-
-  this->Debug = false;
-  this->ShowLineNumbers = false;
-  this->Quiet = false;
-  this->ExtraVerbose = false;
-  this->ProduceXML = false;
-  this->ShowOnly = false;
-  this->OutputAsJson = false;
-  this->OutputAsJsonVersion = 1;
-  this->RunConfigurationScript = false;
-  this->UseHTTP10 = false;
-  this->PrintLabels = false;
-  this->CompressTestOutput = true;
-  this->TestModel = cmCTest::EXPERIMENTAL;
-  this->MaxTestNameWidth = 30;
-  this->InteractiveDebugMode = true;
-  this->TimeOut = cmDuration::zero();
-  this->GlobalTimeout = cmDuration::zero();
-  this->CompressXMLFiles = false;
-  this->ScheduleType.clear();
-  this->OutputLogFile = nullptr;
-  this->OutputLogFileLastTag = -1;
-  this->SuppressUpdatingCTestConfiguration = false;
-  this->BuildID = "";
-  this->OutputTestOutputOnTestFailure = false;
-  this->OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
-  this->RepeatTests = 1; // default to run each test once
-  this->RepeatUntilFail = false;
-
   std::string envValue;
   if (cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE", envValue)) {
-    this->OutputTestOutputOnTestFailure = !cmSystemTools::IsOff(envValue);
+    this->Impl->OutputTestOutputOnTestFailure =
+      !cmSystemTools::IsOff(envValue);
   }
   envValue.clear();
   if (cmSystemTools::GetEnv("CTEST_PROGRESS_OUTPUT", envValue)) {
-    this->TestProgressOutput = !cmSystemTools::IsOff(envValue);
+    this->Impl->TestProgressOutput = !cmSystemTools::IsOff(envValue);
   }
 
-  this->InitStreams();
-
-  this->Parts[PartStart].SetName("Start");
-  this->Parts[PartUpdate].SetName("Update");
-  this->Parts[PartConfigure].SetName("Configure");
-  this->Parts[PartBuild].SetName("Build");
-  this->Parts[PartTest].SetName("Test");
-  this->Parts[PartCoverage].SetName("Coverage");
-  this->Parts[PartMemCheck].SetName("MemCheck");
-  this->Parts[PartSubmit].SetName("Submit");
-  this->Parts[PartNotes].SetName("Notes");
-  this->Parts[PartExtraFiles].SetName("ExtraFiles");
-  this->Parts[PartUpload].SetName("Upload");
-  this->Parts[PartDone].SetName("Done");
+  this->Impl->Parts[PartStart].SetName("Start");
+  this->Impl->Parts[PartUpdate].SetName("Update");
+  this->Impl->Parts[PartConfigure].SetName("Configure");
+  this->Impl->Parts[PartBuild].SetName("Build");
+  this->Impl->Parts[PartTest].SetName("Test");
+  this->Impl->Parts[PartCoverage].SetName("Coverage");
+  this->Impl->Parts[PartMemCheck].SetName("MemCheck");
+  this->Impl->Parts[PartSubmit].SetName("Submit");
+  this->Impl->Parts[PartNotes].SetName("Notes");
+  this->Impl->Parts[PartExtraFiles].SetName("ExtraFiles");
+  this->Impl->Parts[PartUpload].SetName("Upload");
+  this->Impl->Parts[PartDone].SetName("Done");
 
   // Fill the part name-to-id map.
   for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
-    this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
+    this->Impl
+      ->PartMap[cmSystemTools::LowerCase(this->Impl->Parts[p].GetName())] = p;
   }
 
-  this->ShortDateFormat = true;
-
-  this->TestingHandlers["build"] = new cmCTestBuildHandler;
-  this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
-  this->TestingHandlers["coverage"] = new cmCTestCoverageHandler;
-  this->TestingHandlers["script"] = new cmCTestScriptHandler;
-  this->TestingHandlers["test"] = new cmCTestTestHandler;
-  this->TestingHandlers["update"] = new cmCTestUpdateHandler;
-  this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
-  this->TestingHandlers["memcheck"] = new cmCTestMemCheckHandler;
-  this->TestingHandlers["submit"] = new cmCTestSubmitHandler;
-  this->TestingHandlers["upload"] = new cmCTestUploadHandler;
-
-  for (auto& handler : this->TestingHandlers) {
-    handler.second->SetCTestInstance(this);
+  for (auto& handler : this->Impl->GetTestingHandlers()) {
+    handler->SetCTestInstance(this);
   }
 
   // Make sure we can capture the build tool output.
@@ -352,31 +358,40 @@
 
 cmCTest::~cmCTest()
 {
-  cmDeleteAll(this->TestingHandlers);
-  this->SetOutputLogFileName(nullptr);
+  delete this->Impl->OutputLogFile;
+}
+
+int cmCTest::GetParallelLevel() const
+{
+  return this->Impl->ParallelLevel;
 }
 
 void cmCTest::SetParallelLevel(int level)
 {
-  this->ParallelLevel = level < 1 ? 1 : level;
+  this->Impl->ParallelLevel = level < 1 ? 1 : level;
+}
+
+unsigned long cmCTest::GetTestLoad() const
+{
+  return this->Impl->TestLoad;
 }
 
 void cmCTest::SetTestLoad(unsigned long load)
 {
-  this->TestLoad = load;
+  this->Impl->TestLoad = load;
 }
 
 bool cmCTest::ShouldCompressTestOutput()
 {
-  return this->CompressTestOutput;
+  return this->Impl->CompressTestOutput;
 }
 
 cmCTest::Part cmCTest::GetPartFromName(const char* name)
 {
   // Look up by lower-case to make names case-insensitive.
   std::string lower_name = cmSystemTools::LowerCase(name);
-  PartMapType::const_iterator i = this->PartMap.find(lower_name);
-  if (i != this->PartMap.end()) {
+  auto const i = this->Impl->PartMap.find(lower_name);
+  if (i != this->Impl->PartMap.end()) {
     return i->second;
   }
 
@@ -392,19 +407,19 @@
   }
 
   cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
-  if (!this->InteractiveDebugMode) {
+  if (!this->Impl->InteractiveDebugMode) {
     this->BlockTestErrorDiagnostics();
   } else {
     cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
   }
 
-  this->BinaryDir = binary_dir;
-  cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
+  this->Impl->BinaryDir = binary_dir;
+  cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
 
   this->UpdateCTestConfiguration();
 
   cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
-  if (this->ProduceXML) {
+  if (this->Impl->ProduceXML) {
     cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
     cmCTestOptionalLog(this, OUTPUT,
                        "   Site: "
@@ -415,7 +430,7 @@
                          << std::endl,
                        quiet);
     cmCTestOptionalLog(this, DEBUG, "Produce XML is on" << std::endl, quiet);
-    if (this->TestModel == cmCTest::NIGHTLY &&
+    if (this->Impl->TestModel == cmCTest::NIGHTLY &&
         this->GetCTestConfiguration("NightlyStartTime").empty()) {
       cmCTestOptionalLog(
         this, WARNING,
@@ -435,17 +450,18 @@
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator gg(&cm);
   cmMakefile mf(&gg, cm.GetCurrentSnapshot());
-  if (!this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), &mf)) {
+  if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir.c_str(),
+                                             &mf)) {
     cmCTestOptionalLog(
       this, DEBUG, "Cannot find custom configuration file tree" << std::endl,
       quiet);
     return 0;
   }
 
-  if (this->ProduceXML) {
+  if (this->Impl->ProduceXML) {
     // Verify "Testing" directory exists:
     //
-    std::string testingDir = this->BinaryDir + "/Testing";
+    std::string testingDir = this->Impl->BinaryDir + "/Testing";
     if (cmSystemTools::FileExists(testingDir)) {
       if (!cmSystemTools::FileIsDirectory(testingDir)) {
         cmCTestLog(this, ERROR_MESSAGE,
@@ -475,7 +491,7 @@
 
     if (createNewTag) {
       time_t tctime = time(nullptr);
-      if (this->TomorrowTag) {
+      if (this->Impl->TomorrowTag) {
         tctime += (24 * 60 * 60);
       }
       struct tm* lctime = gmtime(&tctime);
@@ -493,26 +509,28 @@
         }
         std::string track;
         if (cmSystemTools::GetLineFromStream(tfin, track) &&
-            !this->Parts[PartStart] && !command) {
-          this->SpecificTrack = track;
+            !this->Impl->Parts[PartStart] && !command) {
+          this->Impl->SpecificTrack = track;
         }
         std::string model;
         if (cmSystemTools::GetLineFromStream(tfin, model) &&
-            !this->Parts[PartStart] && !command) {
-          this->TestModel = GetTestModelFromString(model.c_str());
+            !this->Impl->Parts[PartStart] && !command) {
+          this->Impl->TestModel = GetTestModelFromString(model.c_str());
         }
         tfin.close();
       }
-      if (tag.empty() || (nullptr != command) || this->Parts[PartStart]) {
+      if (tag.empty() || (nullptr != command) ||
+          this->Impl->Parts[PartStart]) {
         cmCTestOptionalLog(
           this, DEBUG,
           "TestModel: " << this->GetTestModelString() << std::endl, quiet);
-        cmCTestOptionalLog(
-          this, DEBUG, "TestModel: " << this->TestModel << std::endl, quiet);
-        if (this->TestModel == cmCTest::NIGHTLY) {
+        cmCTestOptionalLog(this, DEBUG,
+                           "TestModel: " << this->Impl->TestModel << std::endl,
+                           quiet);
+        if (this->Impl->TestModel == cmCTest::NIGHTLY) {
           lctime = this->GetNightlyTime(
             this->GetCTestConfiguration("NightlyStartTime"),
-            this->TomorrowTag);
+            this->Impl->TomorrowTag);
         }
         char datestring[100];
         sprintf(datestring, "%04d%02d%02d-%02d%02d", lctime->tm_year + 1900,
@@ -523,7 +541,7 @@
         if (ofs) {
           ofs << tag << std::endl;
           ofs << this->GetTestModelString() << std::endl;
-          switch (this->TestModel) {
+          switch (this->Impl->TestModel) {
             case cmCTest::EXPERIMENTAL:
               ofs << "Experimental" << std::endl;
               break;
@@ -565,7 +583,7 @@
         return 0;
       }
 
-      if (this->TestModel == cmCTest::UNKNOWN) {
+      if (this->Impl->TestModel == cmCTest::UNKNOWN) {
         if (model == cmCTest::UNKNOWN) {
           cmCTestLog(this, ERROR_MESSAGE,
                      "TAG file does not contain model and "
@@ -577,8 +595,8 @@
         this->SetTestModel(model);
       }
 
-      if (model != this->TestModel && model != cmCTest::UNKNOWN &&
-          this->TestModel != cmCTest::UNKNOWN) {
+      if (model != this->Impl->TestModel && model != cmCTest::UNKNOWN &&
+          this->Impl->TestModel != cmCTest::UNKNOWN) {
         cmCTestOptionalLog(this, WARNING,
                            "Model given in TAG does not match "
                            "model given in ctest_start()"
@@ -586,14 +604,15 @@
                            quiet);
       }
 
-      if (!this->SpecificTrack.empty() && track != this->SpecificTrack) {
+      if (!this->Impl->SpecificTrack.empty() &&
+          track != this->Impl->SpecificTrack) {
         cmCTestOptionalLog(this, WARNING,
                            "Track given in TAG does not match "
                            "track given in ctest_start()"
                              << std::endl,
                            quiet);
       } else {
-        this->SpecificTrack = track;
+        this->Impl->SpecificTrack = track;
       }
 
       cmCTestOptionalLog(this, OUTPUT,
@@ -603,7 +622,7 @@
                          quiet);
     }
 
-    this->CurrentTag = tag;
+    this->Impl->CurrentTag = tag;
   }
 
   return 1;
@@ -613,9 +632,9 @@
 {
   std::string src_dir = this->GetCTestConfiguration("SourceDirectory");
   std::string bld_dir = this->GetCTestConfiguration("BuildDirectory");
-  this->BuildID = "";
+  this->Impl->BuildID = "";
   for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
-    this->Parts[p].SubmitFiles.clear();
+    this->Impl->Parts[p].SubmitFiles.clear();
   }
 
   cmMakefile* mf = command->GetMakefile();
@@ -669,18 +688,18 @@
 
 bool cmCTest::UpdateCTestConfiguration()
 {
-  if (this->SuppressUpdatingCTestConfiguration) {
+  if (this->Impl->SuppressUpdatingCTestConfiguration) {
     return true;
   }
-  std::string fileName = this->BinaryDir + "/CTestConfiguration.ini";
+  std::string fileName = this->Impl->BinaryDir + "/CTestConfiguration.ini";
   if (!cmSystemTools::FileExists(fileName)) {
-    fileName = this->BinaryDir + "/DartConfiguration.tcl";
+    fileName = this->Impl->BinaryDir + "/DartConfiguration.tcl";
   }
   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
              "UpdateCTestConfiguration  from :" << fileName << "\n");
   if (!cmSystemTools::FileExists(fileName)) {
     // No need to exit if we are not producing XML
-    if (this->ProduceXML) {
+    if (this->Impl->ProduceXML) {
       cmCTestLog(this, ERROR_MESSAGE,
                  "Cannot find file: " << fileName << std::endl);
       return false;
@@ -720,15 +739,15 @@
       }
       std::string key = line.substr(0, cpos);
       std::string value = cmCTest::CleanString(line.substr(cpos + 1));
-      this->CTestConfiguration[key] = value;
+      this->Impl->CTestConfiguration[key] = value;
     }
     fin.close();
   }
   if (!this->GetCTestConfiguration("BuildDirectory").empty()) {
-    this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
-    cmSystemTools::ChangeDirectory(this->BinaryDir);
+    this->Impl->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
+    cmSystemTools::ChangeDirectory(this->Impl->BinaryDir);
   }
-  this->TimeOut =
+  this->Impl->TimeOut =
     std::chrono::seconds(atoi(this->GetCTestConfiguration("TimeOut").c_str()));
   std::string const& testLoad = this->GetCTestConfiguration("TestLoad");
   if (!testLoad.empty()) {
@@ -740,8 +759,8 @@
                  "Invalid value for 'Test Load' : " << testLoad << std::endl);
     }
   }
-  if (this->ProduceXML) {
-    this->CompressXMLFiles =
+  if (this->Impl->ProduceXML) {
+    this->Impl->CompressXMLFiles =
       cmSystemTools::IsOn(this->GetCTestConfiguration("CompressSubmission"));
   }
   return true;
@@ -760,21 +779,26 @@
 
 void cmCTest::SetTestModel(int mode)
 {
-  this->InteractiveDebugMode = false;
-  this->TestModel = mode;
+  this->Impl->InteractiveDebugMode = false;
+  this->Impl->TestModel = mode;
+}
+
+int cmCTest::GetTestModel() const
+{
+  return this->Impl->TestModel;
 }
 
 bool cmCTest::SetTest(const char* ttype, bool report)
 {
   if (cmSystemTools::LowerCase(ttype) == "all") {
     for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
-      this->Parts[p].Enable();
+      this->Impl->Parts[p].Enable();
     }
     return true;
   }
   Part p = this->GetPartFromName(ttype);
   if (p != PartCount) {
-    this->Parts[p].Enable();
+    this->Impl->Parts[p].Enable();
     return true;
   }
   if (report) {
@@ -792,7 +816,7 @@
 bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
                              cmGeneratedFileStream& stream, bool compress)
 {
-  std::string testingDir = this->BinaryDir + "/Testing";
+  std::string testingDir = this->Impl->BinaryDir + "/Testing";
   if (!path.empty()) {
     testingDir += "/" + path;
   }
@@ -819,7 +843,7 @@
     return false;
   }
   if (compress) {
-    if (this->CompressXMLFiles) {
+    if (this->Impl->CompressXMLFiles) {
       stream.SetCompression(true);
     }
   }
@@ -844,40 +868,59 @@
 
 bool cmCTest::CTestFileExists(const std::string& filename)
 {
-  std::string testingDir =
-    this->BinaryDir + "/Testing/" + this->CurrentTag + "/" + filename;
+  std::string testingDir = this->Impl->BinaryDir + "/Testing/" +
+    this->Impl->CurrentTag + "/" + filename;
   return cmSystemTools::FileExists(testingDir);
 }
 
-cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
+cmCTestBuildHandler* cmCTest::GetBuildHandler()
 {
-  cmCTest::t_TestingHandlers::iterator it =
-    this->TestingHandlers.find(handler);
-  if (it == this->TestingHandlers.end()) {
-    return nullptr;
-  }
-  it->second->Initialize();
-  return it->second;
+  return &this->Impl->BuildHandler;
 }
 
-cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
+cmCTestBuildAndTestHandler* cmCTest::GetBuildAndTestHandler()
 {
-  cmCTest::t_TestingHandlers::iterator it =
-    this->TestingHandlers.find(handler);
-  if (it == this->TestingHandlers.end()) {
-    return nullptr;
-  }
-  return it->second;
+  return &this->Impl->BuildAndTestHandler;
 }
 
-int cmCTest::ExecuteHandler(const char* shandler)
+cmCTestCoverageHandler* cmCTest::GetCoverageHandler()
 {
-  cmCTestGenericHandler* handler = this->GetHandler(shandler);
-  if (!handler) {
-    return -1;
-  }
-  handler->Initialize();
-  return handler->ProcessHandler();
+  return &this->Impl->CoverageHandler;
+}
+
+cmCTestScriptHandler* cmCTest::GetScriptHandler()
+{
+  return &this->Impl->ScriptHandler;
+}
+
+cmCTestTestHandler* cmCTest::GetTestHandler()
+{
+  return &this->Impl->TestHandler;
+}
+
+cmCTestUpdateHandler* cmCTest::GetUpdateHandler()
+{
+  return &this->Impl->UpdateHandler;
+}
+
+cmCTestConfigureHandler* cmCTest::GetConfigureHandler()
+{
+  return &this->Impl->ConfigureHandler;
+}
+
+cmCTestMemCheckHandler* cmCTest::GetMemCheckHandler()
+{
+  return &this->Impl->MemCheckHandler;
+}
+
+cmCTestSubmitHandler* cmCTest::GetSubmitHandler()
+{
+  return &this->Impl->SubmitHandler;
+}
+
+cmCTestUploadHandler* cmCTest::GetUploadHandler()
+{
+  return &this->Impl->UploadHandler;
 }
 
 int cmCTest::ProcessSteps()
@@ -887,11 +930,11 @@
   int update_count = 0;
 
   for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) {
-    notest = !this->Parts[p];
+    notest = !this->Impl->Parts[p];
   }
-  if (this->Parts[PartUpdate] &&
+  if (this->Impl->Parts[PartUpdate] &&
       (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
-    cmCTestGenericHandler* uphandler = this->GetHandler("update");
+    cmCTestUpdateHandler* uphandler = this->GetUpdateHandler();
     uphandler->SetPersistentOption(
       "SourceDirectory",
       this->GetCTestConfiguration("SourceDirectory").c_str());
@@ -900,45 +943,45 @@
       res |= cmCTest::UPDATE_ERRORS;
     }
   }
-  if (this->TestModel == cmCTest::CONTINUOUS && !update_count) {
+  if (this->Impl->TestModel == cmCTest::CONTINUOUS && !update_count) {
     return 0;
   }
-  if (this->Parts[PartConfigure] &&
+  if (this->Impl->Parts[PartConfigure] &&
       (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
-    if (this->GetHandler("configure")->ProcessHandler() < 0) {
+    if (this->GetConfigureHandler()->ProcessHandler() < 0) {
       res |= cmCTest::CONFIGURE_ERRORS;
     }
   }
-  if (this->Parts[PartBuild] &&
+  if (this->Impl->Parts[PartBuild] &&
       (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
     this->UpdateCTestConfiguration();
-    if (this->GetHandler("build")->ProcessHandler() < 0) {
+    if (this->GetBuildHandler()->ProcessHandler() < 0) {
       res |= cmCTest::BUILD_ERRORS;
     }
   }
-  if ((this->Parts[PartTest] || notest) &&
+  if ((this->Impl->Parts[PartTest] || notest) &&
       (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
     this->UpdateCTestConfiguration();
-    if (this->GetHandler("test")->ProcessHandler() < 0) {
+    if (this->GetTestHandler()->ProcessHandler() < 0) {
       res |= cmCTest::TEST_ERRORS;
     }
   }
-  if (this->Parts[PartCoverage] &&
+  if (this->Impl->Parts[PartCoverage] &&
       (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
     this->UpdateCTestConfiguration();
-    if (this->GetHandler("coverage")->ProcessHandler() < 0) {
+    if (this->GetCoverageHandler()->ProcessHandler() < 0) {
       res |= cmCTest::COVERAGE_ERRORS;
     }
   }
-  if (this->Parts[PartMemCheck] &&
+  if (this->Impl->Parts[PartMemCheck] &&
       (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
     this->UpdateCTestConfiguration();
-    if (this->GetHandler("memcheck")->ProcessHandler() < 0) {
+    if (this->GetMemCheckHandler()->ProcessHandler() < 0) {
       res |= cmCTest::MEMORY_ERRORS;
     }
   }
   if (!notest) {
-    std::string notes_dir = this->BinaryDir + "/Testing/Notes";
+    std::string notes_dir = this->Impl->BinaryDir + "/Testing/Notes";
     if (cmSystemTools::FileIsDirectory(notes_dir)) {
       cmsys::Directory d;
       d.Load(notes_dir);
@@ -948,24 +991,24 @@
         std::string fullname = notes_dir + "/" + file;
         if (cmSystemTools::FileExists(fullname) &&
             !cmSystemTools::FileIsDirectory(fullname)) {
-          if (!this->NotesFiles.empty()) {
-            this->NotesFiles += ";";
+          if (!this->Impl->NotesFiles.empty()) {
+            this->Impl->NotesFiles += ";";
           }
-          this->NotesFiles += fullname;
-          this->Parts[PartNotes].Enable();
+          this->Impl->NotesFiles += fullname;
+          this->Impl->Parts[PartNotes].Enable();
         }
       }
     }
   }
-  if (this->Parts[PartNotes]) {
+  if (this->Impl->Parts[PartNotes]) {
     this->UpdateCTestConfiguration();
-    if (!this->NotesFiles.empty()) {
-      this->GenerateNotesFile(this->NotesFiles.c_str());
+    if (!this->Impl->NotesFiles.empty()) {
+      this->GenerateNotesFile(this->Impl->NotesFiles.c_str());
     }
   }
-  if (this->Parts[PartSubmit]) {
+  if (this->Impl->Parts[PartSubmit]) {
     this->UpdateCTestConfiguration();
-    if (this->GetHandler("submit")->ProcessHandler() < 0) {
+    if (this->GetSubmitHandler()->ProcessHandler() < 0) {
       res |= cmCTest::SUBMIT_ERRORS;
     }
   }
@@ -977,10 +1020,10 @@
 
 std::string cmCTest::GetTestModelString()
 {
-  if (!this->SpecificTrack.empty()) {
-    return this->SpecificTrack;
+  if (!this->Impl->SpecificTrack.empty()) {
+    return this->Impl->SpecificTrack;
   }
-  switch (this->TestModel) {
+  switch (this->Impl->TestModel) {
     case cmCTest::NIGHTLY:
       return "Nightly";
     case cmCTest::CONTINUOUS:
@@ -1009,7 +1052,7 @@
 //######################################################################
 //######################################################################
 
-int cmCTest::RunMakeCommand(const char* command, std::string& output,
+int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
                             int* retVal, const char* dir, cmDuration timeout,
                             std::ostream& ofs, Encoding encoding)
 {
@@ -1039,7 +1082,7 @@
 
   // Now create process object
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
+  cmsysProcess_SetCommand(cp, argv.data());
   cmsysProcess_SetWorkingDirectory(cp, dir);
   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
   cmsysProcess_SetTimeout(cp, timeout.count());
@@ -1139,8 +1182,9 @@
   if (timeout != cmCTest::MaxDuration()) {
     timeout -= std::chrono::minutes(2);
   }
-  if (this->TimeOut > cmDuration::zero() && this->TimeOut < timeout) {
-    timeout = this->TimeOut;
+  if (this->Impl->TimeOut > cmDuration::zero() &&
+      this->Impl->TimeOut < timeout) {
+    timeout = this->Impl->TimeOut;
   }
   if (testTimeOut > cmDuration::zero() &&
       testTimeOut < this->GetRemainingTimeAllowed()) {
@@ -1158,10 +1202,10 @@
                      : std::to_string(cmDurationTo<unsigned int>(timeout)))
                << "\n");
   if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
-      !this->ForceNewCTestProcess) {
+      !this->Impl->ForceNewCTestProcess) {
     cmCTest inst;
-    inst.ConfigType = this->ConfigType;
-    inst.TimeOut = timeout;
+    inst.Impl->ConfigType = this->Impl->ConfigType;
+    inst.Impl->TimeOut = timeout;
 
     // Capture output of the child ctest.
     std::ostringstream oss;
@@ -1222,7 +1266,7 @@
   }
 
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
+  cmsysProcess_SetCommand(cp, argv.data());
   cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
   if (cmSystemTools::GetRunCommandHideConsole()) {
     cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -1258,7 +1302,7 @@
   cmsysProcess_WaitForExit(cp, nullptr);
   processOutput.DecodeText(tempOutput, tempOutput);
   if (output && tempOutput.begin() != tempOutput.end()) {
-    output->append(&*tempOutput.begin(), tempOutput.size());
+    output->append(tempOutput.data(), tempOutput.size());
   }
   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
              "-- Process completed" << std::endl);
@@ -1267,11 +1311,11 @@
 
   if (result == cmsysProcess_State_Exited) {
     *retVal = cmsysProcess_GetExitValue(cp);
-    if (*retVal != 0 && this->OutputTestOutputOnTestFailure) {
+    if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
       OutputTestErrors(tempOutput);
     }
   } else if (result == cmsysProcess_State_Exception) {
-    if (this->OutputTestOutputOnTestFailure) {
+    if (this->Impl->OutputTestOutputOnTestFailure) {
       OutputTestErrors(tempOutput);
     }
     *retVal = cmsysProcess_GetExitException(cp);
@@ -1330,7 +1374,7 @@
 
 void cmCTest::StartXML(cmXMLWriter& xml, bool append)
 {
-  if (this->CurrentTag.empty()) {
+  if (this->Impl->CurrentTag.empty()) {
     cmCTestLog(this, ERROR_MESSAGE,
                "Current Tag empty, this may mean"
                " NightlStartTime was not set correctly."
@@ -1346,7 +1390,7 @@
 
   std::string buildname =
     cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
-  std::string stamp = cmCTest::SafeBuildIdField(this->CurrentTag + "-" +
+  std::string stamp = cmCTest::SafeBuildIdField(this->Impl->CurrentTag + "-" +
                                                 this->GetTestModelString());
   std::string site =
     cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
@@ -1394,8 +1438,7 @@
 
 void cmCTest::AddSiteProperties(cmXMLWriter& xml)
 {
-  cmCTestScriptHandler* ch =
-    static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+  cmCTestScriptHandler* ch = this->GetScriptHandler();
   cmake* cm = ch->GetCMake();
   // if no CMake then this is the old style script and props like
   // this will not work anyway.
@@ -1465,7 +1508,7 @@
 }
 
 int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
-                                      const cmCTest::VectorOfStrings& files)
+                                      std::vector<std::string> const& files)
 {
   std::string buildname =
     cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
@@ -1477,7 +1520,7 @@
   xml.StartElement("Site");
   xml.Attribute("BuildName", buildname);
   xml.Attribute("BuildStamp",
-                this->CurrentTag + "-" + this->GetTestModelString());
+                this->Impl->CurrentTag + "-" + this->GetTestModelString());
   xml.Attribute("Name", this->GetCTestConfiguration("Site"));
   xml.Attribute("Generator",
                 std::string("ctest") + cmVersion::GetCMakeVersion());
@@ -1515,10 +1558,10 @@
   return 1;
 }
 
-int cmCTest::GenerateNotesFile(const VectorOfStrings& files)
+int cmCTest::GenerateNotesFile(std::vector<std::string> const& files)
 {
   cmGeneratedFileStream ofs;
-  if (!this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs)) {
+  if (!this->OpenOutputFile(this->Impl->CurrentTag, "Notes.xml", ofs)) {
     cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
     return 1;
   }
@@ -1533,11 +1576,10 @@
     return 1;
   }
 
-  VectorOfStrings files;
-
   cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
 
-  files = cmSystemTools::SplitString(cfiles, ';');
+  std::vector<std::string> const files =
+    cmSystemTools::SplitString(cfiles, ';');
   if (files.empty()) {
     return 1;
   }
@@ -1548,14 +1590,14 @@
 int cmCTest::GenerateDoneFile()
 {
   cmGeneratedFileStream ofs;
-  if (!this->OpenOutputFile(this->CurrentTag, "Done.xml", ofs)) {
+  if (!this->OpenOutputFile(this->Impl->CurrentTag, "Done.xml", ofs)) {
     cmCTestLog(this, ERROR_MESSAGE, "Cannot open done file" << std::endl);
     return 1;
   }
   cmXMLWriter xml(ofs);
   xml.StartDocument();
   xml.StartElement("Done");
-  xml.Element("buildId", this->BuildID);
+  xml.Element("buildId", this->Impl->BuildID);
   xml.Element("time", std::chrono::system_clock::now());
   xml.EndElement(); // Done
   xml.EndDocument();
@@ -1604,7 +1646,7 @@
   return std::string(&encoded_buffer[0], rlen);
 }
 
-bool cmCTest::SubmitExtraFiles(const VectorOfStrings& files)
+bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files)
 {
   for (std::string const& file : files) {
     if (!cmSystemTools::FileExists(file)) {
@@ -1624,11 +1666,10 @@
     return true;
   }
 
-  VectorOfStrings files;
-
   cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
 
-  files = cmSystemTools::SplitString(cfiles, ';');
+  std::vector<std::string> const files =
+    cmSystemTools::SplitString(cfiles, ';');
   if (files.empty()) {
     return true;
   }
@@ -1796,17 +1837,17 @@
 {
   std::string arg = args[i];
   if (this->CheckArgument(arg, "-F")) {
-    this->Failover = true;
+    this->Impl->Failover = true;
   }
   if (this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) {
     i++;
     int plevel = atoi(args[i].c_str());
     this->SetParallelLevel(plevel);
-    this->ParallelLevelSetInCli = true;
+    this->Impl->ParallelLevelSetInCli = true;
   } else if (arg.find("-j") == 0) {
     int plevel = atoi(arg.substr(2).c_str());
     this->SetParallelLevel(plevel);
-    this->ParallelLevelSetInCli = true;
+    this->Impl->ParallelLevelSetInCli = true;
   }
   if (this->CheckArgument(arg, "--repeat-until-fail")) {
     if (i >= args.size() - 1) {
@@ -1820,9 +1861,9 @@
         "'--repeat-until-fail' given non-integer value '" + args[i] + "'";
       return false;
     }
-    this->RepeatTests = static_cast<int>(repeat);
+    this->Impl->RepeatTests = static_cast<int>(repeat);
     if (repeat > 1) {
-      this->RepeatUntilFail = true;
+      this->Impl->RepeatUntilFail = true;
     }
   }
 
@@ -1838,21 +1879,21 @@
   }
 
   if (this->CheckArgument(arg, "--no-compress-output")) {
-    this->CompressTestOutput = false;
+    this->Impl->CompressTestOutput = false;
   }
 
   if (this->CheckArgument(arg, "--print-labels")) {
-    this->PrintLabels = true;
+    this->Impl->PrintLabels = true;
   }
 
   if (this->CheckArgument(arg, "--http1.0")) {
-    this->UseHTTP10 = true;
+    this->Impl->UseHTTP10 = true;
   }
 
   if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
     i++;
     auto timeout = cmDuration(atof(args[i].c_str()));
-    this->GlobalTimeout = timeout;
+    this->Impl->GlobalTimeout = timeout;
   }
 
   if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) {
@@ -1867,47 +1908,44 @@
   }
 
   if (this->CheckArgument(arg, "--debug")) {
-    this->Debug = true;
-    this->ShowLineNumbers = true;
+    this->Impl->Debug = true;
+    this->Impl->ShowLineNumbers = true;
   }
   if (this->CheckArgument(arg, "--track") && i < args.size() - 1) {
     i++;
-    this->SpecificTrack = args[i];
+    this->Impl->SpecificTrack = args[i];
   }
   if (this->CheckArgument(arg, "--show-line-numbers")) {
-    this->ShowLineNumbers = true;
+    this->Impl->ShowLineNumbers = true;
   }
   if (this->CheckArgument(arg, "--no-label-summary")) {
-    this->LabelSummary = false;
+    this->Impl->LabelSummary = false;
   }
   if (this->CheckArgument(arg, "--no-subproject-summary")) {
-    this->SubprojectSummary = false;
+    this->Impl->SubprojectSummary = false;
   }
   if (this->CheckArgument(arg, "-Q", "--quiet")) {
-    this->Quiet = true;
+    this->Impl->Quiet = true;
   }
   if (this->CheckArgument(arg, "--progress")) {
-    this->TestProgressOutput = true;
+    this->Impl->TestProgressOutput = true;
   }
   if (this->CheckArgument(arg, "-V", "--verbose")) {
-    this->Verbose = true;
+    this->Impl->Verbose = true;
   }
   if (this->CheckArgument(arg, "-VV", "--extra-verbose")) {
-    this->ExtraVerbose = true;
-    this->Verbose = true;
+    this->Impl->ExtraVerbose = true;
+    this->Impl->Verbose = true;
   }
   if (this->CheckArgument(arg, "--output-on-failure")) {
-    this->OutputTestOutputOnTestFailure = true;
+    this->Impl->OutputTestOutputOnTestFailure = true;
   }
   if (this->CheckArgument(arg, "--test-output-size-passed") &&
       i < args.size() - 1) {
     i++;
     long outputSize;
     if (cmSystemTools::StringToLong(args[i].c_str(), &outputSize)) {
-      if (cmCTestTestHandler* pCTestTestHandler =
-            static_cast<cmCTestTestHandler*>(this->TestingHandlers["test"])) {
-        pCTestTestHandler->SetTestOutputSizePassed(int(outputSize));
-      }
+      this->Impl->TestHandler.SetTestOutputSizePassed(int(outputSize));
     } else {
       cmCTestLog(this, WARNING,
                  "Invalid value for '--test-output-size-passed': " << args[i]
@@ -1919,10 +1957,7 @@
     i++;
     long outputSize;
     if (cmSystemTools::StringToLong(args[i].c_str(), &outputSize)) {
-      if (cmCTestTestHandler* pCTestTestHandler =
-            static_cast<cmCTestTestHandler*>(this->TestingHandlers["test"])) {
-        pCTestTestHandler->SetTestOutputSizeFailed(int(outputSize));
-      }
+      this->Impl->TestHandler.SetTestOutputSizeFailed(int(outputSize));
     } else {
       cmCTestLog(this, WARNING,
                  "Invalid value for '--test-output-size-failed': " << args[i]
@@ -1930,10 +1965,10 @@
     }
   }
   if (this->CheckArgument(arg, "-N", "--show-only")) {
-    this->ShowOnly = true;
+    this->Impl->ShowOnly = true;
   }
   if (cmSystemTools::StringStartsWith(arg.c_str(), "--show-only=")) {
-    this->ShowOnly = true;
+    this->Impl->ShowOnly = true;
 
     // Check if a specific format is requested. Defaults to human readable
     // text.
@@ -1941,9 +1976,9 @@
     std::string format = arg.substr(argWithFormat.length());
     if (format == "json-v1") {
       // Force quiet mode so the only output is the json object model.
-      this->Quiet = true;
-      this->OutputAsJson = true;
-      this->OutputAsJsonVersion = 1;
+      this->Impl->Quiet = true;
+      this->Impl->OutputAsJson = true;
+      this->Impl->OutputAsJsonVersion = 1;
     } else if (format != "human") {
       errormsg = "'--show-only=' given unknown value '" + format + "'";
       return false;
@@ -1956,25 +1991,25 @@
   }
 
   if (this->CheckArgument(arg, "--tomorrow-tag")) {
-    this->TomorrowTag = true;
+    this->Impl->TomorrowTag = true;
   }
   if (this->CheckArgument(arg, "--force-new-ctest-process")) {
-    this->ForceNewCTestProcess = true;
+    this->Impl->ForceNewCTestProcess = true;
   }
   if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) {
     i++;
-    this->MaxTestNameWidth = atoi(args[i].c_str());
+    this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
   }
   if (this->CheckArgument(arg, "--interactive-debug-mode") &&
       i < args.size() - 1) {
     i++;
-    this->InteractiveDebugMode = cmSystemTools::IsOn(args[i]);
+    this->Impl->InteractiveDebugMode = cmSystemTools::IsOn(args[i]);
   }
   if (this->CheckArgument(arg, "--submit-index") && i < args.size() - 1) {
     i++;
-    this->SubmitIndex = atoi(args[i].c_str());
-    if (this->SubmitIndex < 0) {
-      this->SubmitIndex = 0;
+    this->Impl->SubmitIndex = atoi(args[i].c_str());
+    if (this->Impl->SubmitIndex < 0) {
+      this->Impl->SubmitIndex = 0;
     }
   }
 
@@ -1983,7 +2018,7 @@
     this->AddCTestConfigurationOverwrite(args[i]);
   }
   if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) {
-    this->ProduceXML = true;
+    this->Impl->ProduceXML = true;
     this->SetTest("Notes");
     i++;
     this->SetNotesFiles(args[i].c_str());
@@ -1993,78 +2028,75 @@
   if (this->CheckArgument(arg, "-I", "--tests-information") &&
       i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
-                                                  args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("TestsToRunInformation", args[i].c_str());
+    this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
+                                                args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
+                                                    args[i].c_str());
   }
   if (this->CheckArgument(arg, "-U", "--union")) {
-    this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
-    this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
+    this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
+    this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
   }
   if (this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption("IncludeRegularExpression",
-                                                  args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("IncludeRegularExpression", args[i].c_str());
+    this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
+                                                args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
+                                                    args[i].c_str());
   }
   if (this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption("LabelRegularExpression",
-                                                  args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("LabelRegularExpression", args[i].c_str());
+    this->GetTestHandler()->SetPersistentOption("LabelRegularExpression",
+                                                args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression",
+                                                    args[i].c_str());
   }
   if (this->CheckArgument(arg, "-LE", "--label-exclude") &&
       i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption(
+    this->GetTestHandler()->SetPersistentOption(
       "ExcludeLabelRegularExpression", args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption(
+      "ExcludeLabelRegularExpression", args[i].c_str());
   }
 
   if (this->CheckArgument(arg, "-E", "--exclude-regex") &&
       i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption("ExcludeRegularExpression",
-                                                  args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
+    this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
+                                                args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression",
+                                                    args[i].c_str());
   }
 
   if (this->CheckArgument(arg, "-FA", "--fixture-exclude-any") &&
       i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption(
+    this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureRegularExpression", args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("ExcludeFixtureRegularExpression",
-                            args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption(
+      "ExcludeFixtureRegularExpression", args[i].c_str());
   }
   if (this->CheckArgument(arg, "-FS", "--fixture-exclude-setup") &&
       i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption(
+    this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureSetupRegularExpression", args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("ExcludeFixtureSetupRegularExpression",
-                            args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption(
+      "ExcludeFixtureSetupRegularExpression", args[i].c_str());
   }
   if (this->CheckArgument(arg, "-FC", "--fixture-exclude-cleanup") &&
       i < args.size() - 1) {
     i++;
-    this->GetHandler("test")->SetPersistentOption(
+    this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
-    this->GetHandler("memcheck")
-      ->SetPersistentOption("ExcludeFixtureCleanupRegularExpression",
-                            args[i].c_str());
+    this->GetMemCheckHandler()->SetPersistentOption(
+      "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
   }
 
   if (this->CheckArgument(arg, "--rerun-failed")) {
-    this->GetHandler("test")->SetPersistentOption("RerunFailed", "true");
-    this->GetHandler("memcheck")->SetPersistentOption("RerunFailed", "true");
+    this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
+    this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
   }
   return true;
 }
@@ -2111,10 +2143,9 @@
   std::string arg = args[i];
   if (this->CheckArgument(arg, "-SP", "--script-new-process") &&
       i < args.size() - 1) {
-    this->RunConfigurationScript = true;
+    this->Impl->RunConfigurationScript = true;
     i++;
-    cmCTestScriptHandler* ch =
-      static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+    cmCTestScriptHandler* ch = this->GetScriptHandler();
     // -SR is an internal argument, -SP should be ignored when it is passed
     if (!SRArgumentSpecified) {
       ch->AddConfigurationScript(args[i].c_str(), false);
@@ -2123,18 +2154,16 @@
 
   if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) {
     SRArgumentSpecified = true;
-    this->RunConfigurationScript = true;
+    this->Impl->RunConfigurationScript = true;
     i++;
-    cmCTestScriptHandler* ch =
-      static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+    cmCTestScriptHandler* ch = this->GetScriptHandler();
     ch->AddConfigurationScript(args[i].c_str(), true);
   }
 
   if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) {
-    this->RunConfigurationScript = true;
+    this->Impl->RunConfigurationScript = true;
     i++;
-    cmCTestScriptHandler* ch =
-      static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+    cmCTestScriptHandler* ch = this->GetScriptHandler();
     // -SR is an internal argument, -S should be ignored when it is passed
     if (!SRArgumentSpecified) {
       ch->AddConfigurationScript(args[i].c_str(), true);
@@ -2149,7 +2178,7 @@
   cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
 
   if (cmake::ParseCacheEntry(arg, name, value, type)) {
-    this->Definitions[name] = value;
+    this->Impl->Definitions[name] = value;
     return true;
   }
 
@@ -2165,8 +2194,8 @@
   bool SRArgumentSpecified = false;
 
   // copy the command line
-  this->InitialCommandLineArguments.insert(
-    this->InitialCommandLineArguments.end(), args.begin(), args.end());
+  this->Impl->InitialCommandLineArguments.insert(
+    this->Impl->InitialCommandLineArguments.end(), args.begin(), args.end());
 
   // process the command line arguments
   for (size_t i = 1; i < args.size(); ++i) {
@@ -2183,7 +2212,7 @@
     // --dashboard: handle a request for a dashboard
     std::string arg = args[i];
     if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) {
-      this->ProduceXML = true;
+      this->Impl->ProduceXML = true;
       i++;
       std::string targ = args[i];
       // AddTestsForDashboard parses the dashboard type and converts it
@@ -2219,7 +2248,7 @@
 
     // --extra-submit
     if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) {
-      this->ProduceXML = true;
+      this->Impl->ProduceXML = true;
       this->SetTest("Submit");
       i++;
       if (!this->SubmitExtraFiles(args[i].c_str())) {
@@ -2234,14 +2263,14 @@
 
     // --schedule-random
     if (this->CheckArgument(arg, "--schedule-random")) {
-      this->ScheduleType = "Random";
+      this->Impl->ScheduleType = "Random";
     }
 
     // pass the argument to all the handlers as well, but i may no longer be
     // set to what it was originally so I'm not sure this is working as
     // intended
-    for (auto& handler : this->TestingHandlers) {
-      if (!handler.second->ProcessCommandLineArguments(arg, i, args)) {
+    for (auto& handler : this->Impl->GetTestingHandlers()) {
+      if (!handler->ProcessCommandLineArguments(arg, i, args)) {
         cmCTestLog(this, ERROR_MESSAGE,
                    "Problem parsing command line arguments within a handler");
         return 0;
@@ -2250,7 +2279,7 @@
   } // the close of the for argument loop
 
   // handle CTEST_PARALLEL_LEVEL environment variable
-  if (!this->ParallelLevelSetInCli) {
+  if (!this->Impl->ParallelLevelSetInCli) {
     std::string parallel;
     if (cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL", parallel)) {
       int plevel = atoi(parallel.c_str());
@@ -2260,10 +2289,10 @@
 
   // TestProgressOutput only supported if console supports it and not logging
   // to a file
-  this->TestProgressOutput = this->TestProgressOutput &&
-    !this->OutputLogFile && this->ProgressOutputSupportedByConsole();
+  this->Impl->TestProgressOutput = this->Impl->TestProgressOutput &&
+    !this->Impl->OutputLogFile && this->ProgressOutputSupportedByConsole();
 #ifdef _WIN32
-  if (this->TestProgressOutput) {
+  if (this->Impl->TestProgressOutput) {
     // Disable output line buffering so we can print content without
     // a newline.
     std::setvbuf(stdout, nullptr, _IONBF, 0);
@@ -2290,7 +2319,7 @@
   std::string arg = args[i];
   if (this->CheckArgument(arg, "-T", "--test-action") &&
       (i < args.size() - 1)) {
-    this->ProduceXML = true;
+    this->Impl->ProduceXML = true;
     i++;
     if (!this->SetTest(args[i].c_str(), false)) {
       success = false;
@@ -2350,16 +2379,16 @@
 {
   int res;
   // call process directory
-  if (this->RunConfigurationScript) {
-    if (this->ExtraVerbose) {
+  if (this->Impl->RunConfigurationScript) {
+    if (this->Impl->ExtraVerbose) {
       cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
     }
-    for (auto& handler : this->TestingHandlers) {
-      handler.second->SetVerbose(this->ExtraVerbose);
-      handler.second->SetSubmitIndex(this->SubmitIndex);
+    for (auto& handler : this->Impl->GetTestingHandlers()) {
+      handler->SetVerbose(this->Impl->ExtraVerbose);
+      handler->SetSubmitIndex(this->Impl->SubmitIndex);
     }
-    this->GetHandler("script")->SetVerbose(this->Verbose);
-    res = this->GetHandler("script")->ProcessHandler();
+    this->GetScriptHandler()->SetVerbose(this->Impl->Verbose);
+    res = this->GetScriptHandler()->ProcessHandler();
     if (res != 0) {
       cmCTestLog(this, DEBUG,
                  "running script failing returning: " << res << std::endl);
@@ -2368,11 +2397,11 @@
   } else {
     // What is this?  -V seems to be the same as -VV,
     // and Verbose is always on in this case
-    this->ExtraVerbose = this->Verbose;
-    this->Verbose = true;
-    for (auto& handler : this->TestingHandlers) {
-      handler.second->SetVerbose(this->Verbose);
-      handler.second->SetSubmitIndex(this->SubmitIndex);
+    this->Impl->ExtraVerbose = this->Impl->Verbose;
+    this->Impl->Verbose = true;
+    for (auto& handler : this->Impl->GetTestingHandlers()) {
+      handler->SetVerbose(this->Impl->Verbose);
+      handler->SetSubmitIndex(this->Impl->SubmitIndex);
     }
     std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
     if (!this->Initialize(cwd.c_str(), nullptr)) {
@@ -2393,9 +2422,8 @@
 
 int cmCTest::RunCMakeAndTest(std::string* output)
 {
-  this->Verbose = true;
-  cmCTestBuildAndTestHandler* handler =
-    static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
+  this->Impl->Verbose = true;
+  cmCTestBuildAndTestHandler* handler = this->GetBuildAndTestHandler();
   int retv = handler->ProcessHandler();
   *output = handler->GetOutput();
 #ifdef CMAKE_BUILD_WITH_CMAKE
@@ -2413,7 +2441,12 @@
   if (!notes) {
     return;
   }
-  this->NotesFiles = notes;
+  this->Impl->NotesFiles = notes;
+}
+
+std::chrono::system_clock::time_point cmCTest::GetStopTime() const
+{
+  return this->Impl->StopTime;
 }
 
 void cmCTest::SetStopTime(std::string const& time_str)
@@ -2443,21 +2476,29 @@
 
   time_t stop_time = curl_getdate(buf, &current_time);
   if (stop_time == -1) {
-    this->StopTime = std::chrono::system_clock::time_point();
+    this->Impl->StopTime = std::chrono::system_clock::time_point();
     return;
   }
-  this->StopTime = std::chrono::system_clock::from_time_t(stop_time);
+  this->Impl->StopTime = std::chrono::system_clock::from_time_t(stop_time);
 
   if (stop_time < current_time) {
-    this->StopTime += std::chrono::hours(24);
+    this->Impl->StopTime += std::chrono::hours(24);
   }
 }
 
+std::string cmCTest::GetScheduleType() const
+{
+  return this->Impl->ScheduleType;
+}
+
+void cmCTest::SetScheduleType(std::string const& type)
+{
+  this->Impl->ScheduleType = type;
+}
+
 int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
 {
   bool found = false;
-  VectorOfStrings dirs;
-  VectorOfStrings ndirs;
   cmCTestLog(this, DEBUG,
              "* Read custom CTest configuration directory: " << dir
                                                              << std::endl);
@@ -2505,7 +2546,7 @@
   }
 
   if (found) {
-    for (auto& handler : this->TestingHandlers) {
+    for (auto& handler : this->Impl->GetNamedTestingHandlers()) {
       cmCTestLog(this, DEBUG,
                  "* Read custom CTest configuration vectors for handler: "
                    << handler.first << " (" << handler.second << ")"
@@ -2596,16 +2637,16 @@
 
 std::string cmCTest::GetCTestConfiguration(const std::string& name)
 {
-  if (this->CTestConfigurationOverwrites.find(name) !=
-      this->CTestConfigurationOverwrites.end()) {
-    return this->CTestConfigurationOverwrites[name];
+  if (this->Impl->CTestConfigurationOverwrites.find(name) !=
+      this->Impl->CTestConfigurationOverwrites.end()) {
+    return this->Impl->CTestConfigurationOverwrites[name];
   }
-  return this->CTestConfiguration[name];
+  return this->Impl->CTestConfiguration[name];
 }
 
 void cmCTest::EmptyCTestConfiguration()
 {
-  this->CTestConfiguration.clear();
+  this->Impl->CTestConfiguration.clear();
 }
 
 void cmCTest::SetCTestConfiguration(const char* name, const char* value,
@@ -2620,10 +2661,10 @@
     return;
   }
   if (!value) {
-    this->CTestConfiguration.erase(name);
+    this->Impl->CTestConfiguration.erase(name);
     return;
   }
-  this->CTestConfiguration[name] = value;
+  this->Impl->CTestConfiguration[name] = value;
 }
 
 std::string cmCTest::GetSubmitURL()
@@ -2654,69 +2695,190 @@
 
 std::string cmCTest::GetCurrentTag()
 {
-  return this->CurrentTag;
+  return this->Impl->CurrentTag;
 }
 
 std::string cmCTest::GetBinaryDir()
 {
-  return this->BinaryDir;
+  return this->Impl->BinaryDir;
 }
 
 std::string const& cmCTest::GetConfigType()
 {
-  return this->ConfigType;
+  return this->Impl->ConfigType;
+}
+
+cmDuration cmCTest::GetTimeOut() const
+{
+  return this->Impl->TimeOut;
+}
+
+void cmCTest::SetTimeOut(cmDuration t)
+{
+  this->Impl->TimeOut = t;
+}
+
+cmDuration cmCTest::GetGlobalTimeout() const
+{
+  return this->Impl->GlobalTimeout;
 }
 
 bool cmCTest::GetShowOnly()
 {
-  return this->ShowOnly;
+  return this->Impl->ShowOnly;
 }
 
 bool cmCTest::GetOutputAsJson()
 {
-  return this->OutputAsJson;
+  return this->Impl->OutputAsJson;
 }
 
 int cmCTest::GetOutputAsJsonVersion()
 {
-  return this->OutputAsJsonVersion;
+  return this->Impl->OutputAsJsonVersion;
+}
+
+bool cmCTest::ShouldUseHTTP10() const
+{
+  return this->Impl->UseHTTP10;
+}
+
+bool cmCTest::ShouldPrintLabels() const
+{
+  return this->Impl->PrintLabels;
 }
 
 int cmCTest::GetMaxTestNameWidth() const
 {
-  return this->MaxTestNameWidth;
+  return this->Impl->MaxTestNameWidth;
+}
+
+void cmCTest::SetMaxTestNameWidth(int w)
+{
+  this->Impl->MaxTestNameWidth = w;
 }
 
 void cmCTest::SetProduceXML(bool v)
 {
-  this->ProduceXML = v;
+  this->Impl->ProduceXML = v;
 }
 
 bool cmCTest::GetProduceXML()
 {
-  return this->ProduceXML;
+  return this->Impl->ProduceXML;
+}
+
+std::vector<std::string>& cmCTest::GetInitialCommandLineArguments()
+{
+  return this->Impl->InitialCommandLineArguments;
 }
 
 const char* cmCTest::GetSpecificTrack()
 {
-  if (this->SpecificTrack.empty()) {
+  if (this->Impl->SpecificTrack.empty()) {
     return nullptr;
   }
-  return this->SpecificTrack.c_str();
+  return this->Impl->SpecificTrack.c_str();
 }
 
 void cmCTest::SetSpecificTrack(const char* track)
 {
   if (!track) {
-    this->SpecificTrack.clear();
+    this->Impl->SpecificTrack.clear();
     return;
   }
-  this->SpecificTrack = track;
+  this->Impl->SpecificTrack = track;
+}
+
+void cmCTest::SetFailover(bool failover)
+{
+  this->Impl->Failover = failover;
+}
+
+bool cmCTest::GetFailover() const
+{
+  return this->Impl->Failover;
+}
+
+bool cmCTest::GetTestProgressOutput() const
+{
+  return this->Impl->TestProgressOutput;
+}
+
+bool cmCTest::GetVerbose() const
+{
+  return this->Impl->Verbose;
+}
+
+bool cmCTest::GetExtraVerbose() const
+{
+  return this->Impl->ExtraVerbose;
+}
+
+void cmCTest::SetStreams(std::ostream* out, std::ostream* err)
+{
+  this->Impl->StreamOut = out;
+  this->Impl->StreamErr = err;
+}
+
+bool cmCTest::GetLabelSummary() const
+{
+  return this->Impl->LabelSummary;
+}
+
+bool cmCTest::GetSubprojectSummary() const
+{
+  return this->Impl->SubprojectSummary;
+}
+
+bool cmCTest::GetOutputTestOutputOnTestFailure() const
+{
+  return this->Impl->OutputTestOutputOnTestFailure;
+}
+
+const std::map<std::string, std::string>& cmCTest::GetDefinitions() const
+{
+  return this->Impl->Definitions;
+}
+
+int cmCTest::GetTestRepeat() const
+{
+  return this->Impl->RepeatTests;
+}
+
+bool cmCTest::GetRepeatUntilFail() const
+{
+  return this->Impl->RepeatUntilFail;
+}
+
+void cmCTest::SetBuildID(const std::string& id)
+{
+  this->Impl->BuildID = id;
+}
+
+std::string cmCTest::GetBuildID() const
+{
+  return this->Impl->BuildID;
 }
 
 void cmCTest::AddSubmitFile(Part part, const char* name)
 {
-  this->Parts[part].SubmitFiles.emplace_back(name);
+  this->Impl->Parts[part].SubmitFiles.emplace_back(name);
+}
+
+std::vector<std::string> const& cmCTest::GetSubmitFiles(Part part) const
+{
+  return this->Impl->Parts[part].SubmitFiles;
+}
+
+void cmCTest::ClearSubmitFiles(Part part)
+{
+  this->Impl->Parts[part].SubmitFiles.clear();
+}
+
+void cmCTest::SetSuppressUpdatingCTestConfiguration(bool val)
+{
+  this->Impl->SuppressUpdatingCTestConfiguration = val;
 }
 
 void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
@@ -2732,14 +2894,14 @@
   }
   std::string key = overStr.substr(0, epos);
   std::string value = overStr.substr(epos + 1);
-  this->CTestConfigurationOverwrites[key] = value;
+  this->Impl->CTestConfigurationOverwrites[key] = value;
 }
 
 void cmCTest::SetConfigType(const char* ct)
 {
-  this->ConfigType = ct ? ct : "";
-  cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
-  std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
+  this->Impl->ConfigType = ct ? ct : "";
+  cmSystemTools::ReplaceString(this->Impl->ConfigType, ".\\", "");
+  std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->Impl->ConfigType;
   cmSystemTools::PutEnv(confTypeEnv);
 }
 
@@ -2776,7 +2938,7 @@
   stdErr->clear();
 
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
+  cmsysProcess_SetCommand(cp, argv.data());
   cmsysProcess_SetWorkingDirectory(cp, dir);
   if (cmSystemTools::GetRunCommandHideConsole()) {
     cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -2805,12 +2967,12 @@
         done = true;
     }
     if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
-        this->ExtraVerbose) {
+        this->Impl->ExtraVerbose) {
       processOutput.DecodeText(data, length, strdata);
       cmSystemTools::Stdout(strdata);
     }
   }
-  if (this->ExtraVerbose) {
+  if (this->Impl->ExtraVerbose) {
     processOutput.DecodeText(std::string(), strdata);
     if (!strdata.empty()) {
       cmSystemTools::Stdout(strdata);
@@ -2820,11 +2982,11 @@
   cmsysProcess_WaitForExit(cp, nullptr);
   if (!tempOutput.empty()) {
     processOutput.DecodeText(tempOutput, tempOutput);
-    stdOut->append(&*tempOutput.begin(), tempOutput.size());
+    stdOut->append(tempOutput.data(), tempOutput.size());
   }
   if (!tempError.empty()) {
     processOutput.DecodeText(tempError, tempError);
-    stdErr->append(&*tempError.begin(), tempError.size());
+    stdErr->append(tempError.data(), tempError.size());
   }
 
   bool result = true;
@@ -2859,12 +3021,12 @@
 
 void cmCTest::SetOutputLogFileName(const char* name)
 {
-  if (this->OutputLogFile) {
-    delete this->OutputLogFile;
-    this->OutputLogFile = nullptr;
+  if (this->Impl->OutputLogFile) {
+    delete this->Impl->OutputLogFile;
+    this->Impl->OutputLogFile = nullptr;
   }
   if (name) {
-    this->OutputLogFile = new cmGeneratedFileStream(name);
+    this->Impl->OutputLogFile = new cmGeneratedFileStream(name);
   }
 }
 
@@ -2880,18 +3042,11 @@
 
 #define cmCTestLogOutputFileLine(stream)                                      \
   do {                                                                        \
-    if (this->ShowLineNumbers) {                                              \
+    if (this->Impl->ShowLineNumbers) {                                        \
       (stream) << std::endl << file << ":" << line << " ";                    \
     }                                                                         \
   } while (false)
 
-void cmCTest::InitStreams()
-{
-  // By default we write output to the process output streams.
-  this->StreamOut = &std::cout;
-  this->StreamErr = &std::cerr;
-}
-
 void cmCTest::Log(int logType, const char* file, int line, const char* msg,
                   bool suppress)
 {
@@ -2902,53 +3057,53 @@
     return;
   }
   if (logType == cmCTest::HANDLER_PROGRESS_OUTPUT &&
-      (this->Debug || this->ExtraVerbose)) {
+      (this->Impl->Debug || this->Impl->ExtraVerbose)) {
     return;
   }
-  if (this->OutputLogFile) {
+  if (this->Impl->OutputLogFile) {
     bool display = true;
-    if (logType == cmCTest::DEBUG && !this->Debug) {
+    if (logType == cmCTest::DEBUG && !this->Impl->Debug) {
       display = false;
     }
-    if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
-        !this->ExtraVerbose) {
+    if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Impl->Debug &&
+        !this->Impl->ExtraVerbose) {
       display = false;
     }
     if (display) {
-      cmCTestLogOutputFileLine(*this->OutputLogFile);
-      if (logType != this->OutputLogFileLastTag) {
-        *this->OutputLogFile << "[";
+      cmCTestLogOutputFileLine(*this->Impl->OutputLogFile);
+      if (logType != this->Impl->OutputLogFileLastTag) {
+        *this->Impl->OutputLogFile << "[";
         if (logType >= OTHER || logType < 0) {
-          *this->OutputLogFile << "OTHER";
+          *this->Impl->OutputLogFile << "OTHER";
         } else {
-          *this->OutputLogFile << cmCTestStringLogType[logType];
+          *this->Impl->OutputLogFile << cmCTestStringLogType[logType];
         }
-        *this->OutputLogFile << "] " << std::endl << std::flush;
+        *this->Impl->OutputLogFile << "] " << std::endl << std::flush;
       }
-      *this->OutputLogFile << msg << std::flush;
-      if (logType != this->OutputLogFileLastTag) {
-        *this->OutputLogFile << std::endl << std::flush;
-        this->OutputLogFileLastTag = logType;
+      *this->Impl->OutputLogFile << msg << std::flush;
+      if (logType != this->Impl->OutputLogFileLastTag) {
+        *this->Impl->OutputLogFile << std::endl << std::flush;
+        this->Impl->OutputLogFileLastTag = logType;
       }
     }
   }
-  if (!this->Quiet) {
-    std::ostream& out = *this->StreamOut;
-    std::ostream& err = *this->StreamErr;
+  if (!this->Impl->Quiet) {
+    std::ostream& out = *this->Impl->StreamOut;
+    std::ostream& err = *this->Impl->StreamErr;
 
     if (logType == HANDLER_TEST_PROGRESS_OUTPUT) {
-      if (this->TestProgressOutput) {
+      if (this->Impl->TestProgressOutput) {
         cmCTestLogOutputFileLine(out);
-        if (this->FlushTestProgressLine) {
+        if (this->Impl->FlushTestProgressLine) {
           printf("\r");
-          this->FlushTestProgressLine = false;
+          this->Impl->FlushTestProgressLine = false;
           out.flush();
         }
 
         std::string msg_str{ msg };
         auto const lineBreakIt = msg_str.find('\n');
         if (lineBreakIt != std::string::npos) {
-          this->FlushTestProgressLine = true;
+          this->Impl->FlushTestProgressLine = true;
           msg_str.erase(std::remove(msg_str.begin(), msg_str.end(), '\n'),
                         msg_str.end());
         }
@@ -2965,7 +3120,7 @@
 
     switch (logType) {
       case DEBUG:
-        if (this->Debug) {
+        if (this->Impl->Debug) {
           cmCTestLogOutputFileLine(out);
           out << msg;
           out.flush();
@@ -2973,14 +3128,14 @@
         break;
       case OUTPUT:
       case HANDLER_OUTPUT:
-        if (this->Debug || this->Verbose) {
+        if (this->Impl->Debug || this->Impl->Verbose) {
           cmCTestLogOutputFileLine(out);
           out << msg;
           out.flush();
         }
         break;
       case HANDLER_VERBOSE_OUTPUT:
-        if (this->Debug || this->ExtraVerbose) {
+        if (this->Impl->Debug || this->Impl->ExtraVerbose) {
           cmCTestLogOutputFileLine(out);
           out << msg;
           out.flush();
@@ -3007,7 +3162,7 @@
 
 std::string cmCTest::GetColorCode(Color color) const
 {
-  if (this->OutputColorCode) {
+  if (this->Impl->OutputColorCode) {
 #if defined(_WIN32)
     // Not supported on Windows
     static_cast<void>(color);
@@ -3021,14 +3176,7 @@
 
 cmDuration cmCTest::GetRemainingTimeAllowed()
 {
-  if (!this->GetHandler("script")) {
-    return cmCTest::MaxDuration();
-  }
-
-  cmCTestScriptHandler* ch =
-    static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-
-  return ch->GetRemainingTimeAllowed();
+  return this->GetScriptHandler()->GetRemainingTimeAllowed();
 }
 
 cmDuration cmCTest::MaxDuration()
@@ -3038,17 +3186,14 @@
 
 void cmCTest::SetRunCurrentScript(bool value)
 {
-  cmCTestScriptHandler* ch =
-    static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-
-  ch->SetRunCurrentScript(value);
+  this->GetScriptHandler()->SetRunCurrentScript(value);
 }
 
 void cmCTest::OutputTestErrors(std::vector<char> const& process_output)
 {
   std::string test_outputs("\n*** Test Failed:\n");
   if (!process_output.empty()) {
-    test_outputs.append(&*process_output.begin(), process_output.size());
+    test_outputs.append(process_output.data(), process_output.size());
   }
   cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
 }
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 92a02c3..d300c33 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -10,13 +10,22 @@
 
 #include <chrono>
 #include <map>
-#include <set>
+#include <memory> // IWYU pragma: keep
 #include <sstream>
 #include <string>
 #include <time.h>
 #include <vector>
 
-class cmCTestGenericHandler;
+class cmCTestBuildHandler;
+class cmCTestBuildAndTestHandler;
+class cmCTestCoverageHandler;
+class cmCTestScriptHandler;
+class cmCTestTestHandler;
+class cmCTestUpdateHandler;
+class cmCTestConfigureHandler;
+class cmCTestMemCheckHandler;
+class cmCTestSubmitHandler;
+class cmCTestUploadHandler;
 class cmCTestStartCommand;
 class cmGeneratedFileStream;
 class cmMakefile;
@@ -31,9 +40,6 @@
  */
 class cmCTest
 {
-  friend class cmCTestRunTest;
-  friend class cmCTestMultiProcessHandler;
-
 public:
   typedef cmProcessOutput::Encoding Encoding;
   /** Enumerate parts of the testing and submission process.  */
@@ -54,44 +60,10 @@
     PartCount // Update names in constructor when adding a part
   };
 
-  /** Representation of one part.  */
-  struct PartInfo
-  {
-    void SetName(const std::string& name) { this->Name = name; }
-    const std::string& GetName() const { return this->Name; }
-
-    void Enable() { this->Enabled = true; }
-    explicit operator bool() const { return this->Enabled; }
-
-    std::vector<std::string> SubmitFiles;
-
-  private:
-    bool Enabled = false;
-    std::string Name;
-  };
-#ifdef CMAKE_BUILD_WITH_CMAKE
-  enum HTTPMethod
-  {
-    HTTP_GET,
-    HTTP_POST,
-    HTTP_PUT
-  };
-
-  /**
-   * Perform an HTTP request.
-   */
-  static int HTTPRequest(std::string url, HTTPMethod method,
-                         std::string& response, std::string const& fields = "",
-                         std::string const& putFile = "", int timeout = 0);
-#endif
-
   /** Get a testing part id from its string name.  Returns PartCount
       if the string does not name a valid part.  */
   Part GetPartFromName(const char* name);
 
-  typedef std::vector<std::string> VectorOfStrings;
-  typedef std::set<std::string> SetOfStrings;
-
   /** Process Command line arguments */
   int Run(std::vector<std::string>&, std::string* output = nullptr);
 
@@ -128,7 +100,7 @@
   /**
    * Is the tomorrow tag set?
    */
-  bool GetTomorrowTag() { return this->TomorrowTag; }
+  bool GetTomorrowTag() const;
 
   /**
    * Try to run tests of the project
@@ -137,16 +109,16 @@
 
   /** what is the configuration type, e.g. Debug, Release etc. */
   std::string const& GetConfigType();
-  cmDuration GetTimeOut() { return this->TimeOut; }
-  void SetTimeOut(cmDuration t) { this->TimeOut = t; }
+  cmDuration GetTimeOut() const;
+  void SetTimeOut(cmDuration t);
 
-  cmDuration GetGlobalTimeout() { return this->GlobalTimeout; }
+  cmDuration GetGlobalTimeout() const;
 
   /** how many test to run at the same time */
-  int GetParallelLevel() { return this->ParallelLevel; }
+  int GetParallelLevel() const;
   void SetParallelLevel(int);
 
-  unsigned long GetTestLoad() { return this->TestLoad; }
+  unsigned long GetTestLoad() const;
   void SetTestLoad(unsigned long);
 
   /**
@@ -164,7 +136,7 @@
    * Set the cmake test mode (experimental, nightly, continuous).
    */
   void SetTestModel(int mode);
-  int GetTestModel() { return this->TestModel; }
+  int GetTestModel() const;
 
   std::string GetTestModelString();
   static int GetTestModelFromString(const char* str);
@@ -182,6 +154,9 @@
   cmCTest();
   ~cmCTest();
 
+  cmCTest(const cmCTest&) = delete;
+  cmCTest& operator=(const cmCTest&) = delete;
+
   /** Set the notes files to be created. */
   void SetNotesFiles(const char* notes);
 
@@ -219,26 +194,23 @@
 
   int GetOutputAsJsonVersion();
 
-  bool ShouldUseHTTP10() { return this->UseHTTP10; }
+  bool ShouldUseHTTP10() const;
 
-  bool ShouldPrintLabels() { return this->PrintLabels; }
+  bool ShouldPrintLabels() const;
 
   bool ShouldCompressTestOutput();
   bool CompressString(std::string& str);
 
-  std::chrono::system_clock::time_point GetStopTime()
-  {
-    return this->StopTime;
-  }
+  std::chrono::system_clock::time_point GetStopTime() const;
   void SetStopTime(std::string const& time);
 
   /** Used for parallel ctest job scheduling */
-  std::string GetScheduleType() { return this->ScheduleType; }
-  void SetScheduleType(std::string const& type) { this->ScheduleType = type; }
+  std::string GetScheduleType() const;
+  void SetScheduleType(std::string const& type);
 
   /** The max output width */
   int GetMaxTestNameWidth() const;
-  void SetMaxTestNameWidth(int w) { this->MaxTestNameWidth = w; }
+  void SetMaxTestNameWidth(int w);
 
   /**
    * Run a single executable command and put the stdout and stderr
@@ -277,8 +249,9 @@
    * Run command specialized for make and configure. Returns process status
    * and retVal is return value or exception.
    */
-  int RunMakeCommand(const char* command, std::string& output, int* retVal,
-                     const char* dir, cmDuration timeout, std::ostream& ofs,
+  int RunMakeCommand(const std::string& command, std::string& output,
+                     int* retVal, const char* dir, cmDuration timeout,
+                     std::ostream& ofs,
                      Encoding encoding = cmProcessOutput::Auto);
 
   /** Return the current tag */
@@ -331,16 +304,18 @@
               Encoding encoding = cmProcessOutput::Auto);
 
   /**
-   * Execute handler and return its result. If the handler fails, it returns
-   * negative value.
-   */
-  int ExecuteHandler(const char* handler);
-
-  /**
    * Get the handler object
    */
-  cmCTestGenericHandler* GetHandler(const char* handler);
-  cmCTestGenericHandler* GetInitializedHandler(const char* handler);
+  cmCTestBuildHandler* GetBuildHandler();
+  cmCTestBuildAndTestHandler* GetBuildAndTestHandler();
+  cmCTestCoverageHandler* GetCoverageHandler();
+  cmCTestScriptHandler* GetScriptHandler();
+  cmCTestTestHandler* GetTestHandler();
+  cmCTestUpdateHandler* GetUpdateHandler();
+  cmCTestConfigureHandler* GetConfigureHandler();
+  cmCTestMemCheckHandler* GetMemCheckHandler();
+  cmCTestSubmitHandler* GetSubmitHandler();
+  cmCTestUploadHandler* GetUploadHandler();
 
   /**
    * Set the CTest variable from CMake variable
@@ -350,9 +325,6 @@
                                               const std::string& cmake_var,
                                               bool suppress = false);
 
-  /** Make string safe to be sent as a URL */
-  static std::string MakeURLSafe(const std::string&);
-
   /** Decode a URL to the original string.  */
   static std::string DecodeURL(const std::string&);
 
@@ -360,10 +332,7 @@
    * Should ctect configuration be updated. When using new style ctest
    * script, this should be true.
    */
-  void SetSuppressUpdatingCTestConfiguration(bool val)
-  {
-    this->SuppressUpdatingCTestConfiguration = val;
-  }
+  void SetSuppressUpdatingCTestConfiguration(bool val);
 
   /**
    * Add overwrite to ctest configuration.
@@ -373,14 +342,14 @@
   void AddCTestConfigurationOverwrite(const std::string& encstr);
 
   /** Create XML file that contains all the notes specified */
-  int GenerateNotesFile(const VectorOfStrings& files);
+  int GenerateNotesFile(std::vector<std::string> const& files);
 
   /** Create XML file to indicate that build is complete */
   int GenerateDoneFile();
 
   /** Submit extra files to the server */
   bool SubmitExtraFiles(const char* files);
-  bool SubmitExtraFiles(const VectorOfStrings& files);
+  bool SubmitExtraFiles(std::vector<std::string> const& files);
 
   /** Set the output log file name */
   void SetOutputLogFileName(const char* name);
@@ -420,62 +389,52 @@
   std::string GetColorCode(Color color) const;
 
   /** The Build ID is assigned by CDash */
-  void SetBuildID(const std::string& id) { this->BuildID = id; }
-  std::string GetBuildID() { return this->BuildID; }
+  void SetBuildID(const std::string& id);
+  std::string GetBuildID() const;
 
   /** Add file to be submitted */
   void AddSubmitFile(Part part, const char* name);
-  std::vector<std::string> const& GetSubmitFiles(Part part)
-  {
-    return this->Parts[part].SubmitFiles;
-  }
-  void ClearSubmitFiles(Part part) { this->Parts[part].SubmitFiles.clear(); }
+  std::vector<std::string> const& GetSubmitFiles(Part part) const;
+  void ClearSubmitFiles(Part part);
 
   /**
    * Read the custom configuration files and apply them to the current ctest
    */
   int ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf);
 
-  std::vector<std::string>& GetInitialCommandLineArguments()
-  {
-    return this->InitialCommandLineArguments;
-  }
+  std::vector<std::string>& GetInitialCommandLineArguments();
 
   /** Set the track to submit to */
   void SetSpecificTrack(const char* track);
   const char* GetSpecificTrack();
 
-  void SetFailover(bool failover) { this->Failover = failover; }
-  bool GetFailover() { return this->Failover; }
+  void SetFailover(bool failover);
+  bool GetFailover() const;
 
-  bool GetTestProgressOutput() const { return this->TestProgressOutput; }
+  bool GetTestProgressOutput() const;
 
-  bool GetVerbose() { return this->Verbose; }
-  bool GetExtraVerbose() { return this->ExtraVerbose; }
+  bool GetVerbose() const;
+  bool GetExtraVerbose() const;
 
   /** Direct process output to given streams.  */
-  void SetStreams(std::ostream* out, std::ostream* err)
-  {
-    this->StreamOut = out;
-    this->StreamErr = err;
-  }
+  void SetStreams(std::ostream* out, std::ostream* err);
+
   void AddSiteProperties(cmXMLWriter& xml);
 
-  bool GetLabelSummary() { return this->LabelSummary; }
-  bool GetSubprojectSummary() { return this->SubprojectSummary; }
+  bool GetLabelSummary() const;
+  bool GetSubprojectSummary() const;
 
   std::string GetCostDataFile();
 
-  const std::map<std::string, std::string>& GetDefinitions()
-  {
-    return this->Definitions;
-  }
+  bool GetOutputTestOutputOnTestFailure() const;
+
+  const std::map<std::string, std::string>& GetDefinitions() const;
 
   /** Return the number of times a test should be run */
-  int GetTestRepeat() { return this->RepeatTests; }
+  int GetTestRepeat() const;
 
   /** Return true if test should run until fail */
-  bool GetRepeatUntilFail() { return this->RepeatUntilFail; }
+  bool GetRepeatUntilFail() const;
 
   void GenerateSubprojectsOutput(cmXMLWriter& xml);
   std::vector<std::string> GetLabelsForSubprojects();
@@ -483,85 +442,8 @@
   void SetRunCurrentScript(bool value);
 
 private:
-  int RepeatTests;
-  bool RepeatUntilFail;
-  std::string ConfigType;
-  std::string ScheduleType;
-  std::chrono::system_clock::time_point StopTime;
-  bool TestProgressOutput;
-  bool Verbose;
-  bool ExtraVerbose;
-  bool ProduceXML;
-  bool LabelSummary;
-  bool SubprojectSummary;
-  bool UseHTTP10;
-  bool PrintLabels;
-  bool Failover;
-
-  bool FlushTestProgressLine;
-
-  bool ForceNewCTestProcess;
-
-  bool RunConfigurationScript;
-
   int GenerateNotesFile(const char* files);
 
-  // these are helper classes
-  typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers;
-  t_TestingHandlers TestingHandlers;
-
-  bool ShowOnly;
-  bool OutputAsJson;
-  int OutputAsJsonVersion;
-
-  /** Map of configuration properties */
-  typedef std::map<std::string, std::string> CTestConfigurationMap;
-
-  // TODO: The ctest configuration should be a hierarchy of
-  // configuration option sources: command-line, script, ini file.
-  // Then the ini file can get re-loaded whenever it changes without
-  // affecting any higher-precedence settings.
-  CTestConfigurationMap CTestConfiguration;
-  CTestConfigurationMap CTestConfigurationOverwrites;
-  PartInfo Parts[PartCount];
-  typedef std::map<std::string, Part> PartMapType;
-  PartMapType PartMap;
-
-  std::string CurrentTag;
-  bool TomorrowTag;
-
-  int TestModel;
-  std::string SpecificTrack;
-
-  cmDuration TimeOut;
-
-  cmDuration GlobalTimeout;
-
-  int MaxTestNameWidth;
-
-  int ParallelLevel;
-  bool ParallelLevelSetInCli;
-
-  unsigned long TestLoad;
-
-  int CompatibilityMode;
-
-  // information for the --build-and-test options
-  std::string BinaryDir;
-
-  std::string NotesFiles;
-
-  bool InteractiveDebugMode;
-
-  bool ShortDateFormat;
-
-  bool CompressXMLFiles;
-  bool CompressTestOutput;
-
-  void InitStreams();
-  std::ostream* StreamOut;
-  std::ostream* StreamErr;
-
   void BlockTestErrorDiagnostics();
 
   /**
@@ -606,7 +488,8 @@
   bool UpdateCTestConfiguration();
 
   /** Create note from files. */
-  int GenerateCTestNotesOutput(cmXMLWriter& xml, const VectorOfStrings& files);
+  int GenerateCTestNotesOutput(cmXMLWriter& xml,
+                               std::vector<std::string> const& files);
 
   /** Check if the argument is the one specified */
   bool CheckArgument(const std::string& arg, const char* varg1,
@@ -626,25 +509,8 @@
   int RunCMakeAndTest(std::string* output);
   int ExecuteTests();
 
-  bool SuppressUpdatingCTestConfiguration;
-
-  bool Debug;
-  bool ShowLineNumbers;
-  bool Quiet;
-
-  std::string BuildID;
-
-  std::vector<std::string> InitialCommandLineArguments;
-
-  int SubmitIndex;
-
-  cmGeneratedFileStream* OutputLogFile;
-  int OutputLogFileLastTag;
-
-  bool OutputTestOutputOnTestFailure;
-  bool OutputColorCode;
-
-  std::map<std::string, std::string> Definitions;
+  struct Private;
+  std::unique_ptr<Private> Impl;
 };
 
 class cmCTestLogWrite
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index 2728f0f..6116de0 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -239,8 +239,7 @@
   cmGeneratedFileStream fout(cacheFile);
   fout.SetCopyIfDifferent(true);
   if (!fout) {
-    cmSystemTools::Error("Unable to open cache file for save. ",
-                         cacheFile.c_str());
+    cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
     cmSystemTools::ReportLastSystemError("");
     return false;
   }
@@ -364,8 +363,8 @@
   checkCacheFile += "/cmake.check_cache";
   cmsys::ofstream checkCache(checkCacheFile.c_str());
   if (!checkCache) {
-    cmSystemTools::Error("Unable to open check cache file for write. ",
-                         checkCacheFile.c_str());
+    cmSystemTools::Error("Unable to open check cache file for write. " +
+                         checkCacheFile);
     return false;
   }
   checkCache << "# This file is generated by cmake for dependency checking "
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
index 0c70ed2..65f22f7 100644
--- a/Source/cmCacheManager.h
+++ b/Source/cmCacheManager.h
@@ -93,33 +93,33 @@
     CacheEntry& GetEntry() { return this->Position->second; }
   };
 
-  ///! return an iterator to iterate through the cache map
+  //! return an iterator to iterate through the cache map
   cmCacheManager::CacheIterator NewIterator() { return CacheIterator(*this); }
 
-  ///! Load a cache for given makefile.  Loads from path/CMakeCache.txt.
+  //! Load a cache for given makefile.  Loads from path/CMakeCache.txt.
   bool LoadCache(const std::string& path, bool internal,
                  std::set<std::string>& excludes,
                  std::set<std::string>& includes);
 
-  ///! Save cache for given makefile.  Saves to output path/CMakeCache.txt
+  //! Save cache for given makefile.  Saves to output path/CMakeCache.txt
   bool SaveCache(const std::string& path, cmMessenger* messenger);
 
-  ///! Delete the cache given
+  //! Delete the cache given
   bool DeleteCache(const std::string& path);
 
-  ///! Print the cache to a stream
+  //! Print the cache to a stream
   void PrintCache(std::ostream&) const;
 
-  ///! Get the iterator for an entry with a given key.
+  //! Get the iterator for an entry with a given key.
   cmCacheManager::CacheIterator GetCacheIterator(const char* key = nullptr);
 
-  ///! Remove an entry from the cache
+  //! Remove an entry from the cache
   void RemoveCacheEntry(const std::string& key);
 
-  ///! Get the number of entries in the cache
+  //! Get the number of entries in the cache
   int GetSize() { return static_cast<int>(this->Cache.size()); }
 
-  ///! Get a value from the cache given a key
+  //! Get a value from the cache given a key
   const std::string* GetInitializedCacheValue(const std::string& key) const;
 
   const char* GetCacheEntryValue(const std::string& key)
@@ -197,14 +197,14 @@
   unsigned int GetCacheMinorVersion() const { return this->CacheMinorVersion; }
 
 protected:
-  ///! Add an entry into the cache
+  //! Add an entry into the cache
   void AddCacheEntry(const std::string& key, const char* value,
                      const char* helpString,
                      cmStateEnums::CacheEntryType type);
 
-  ///! Get a cache entry object for a key
+  //! Get a cache entry object for a key
   CacheEntry* GetCacheEntry(const std::string& key);
-  ///! Clean out the CMakeFiles directory if no CMakeCache.txt
+  //! Clean out the CMakeFiles directory if no CMakeCache.txt
   void CleanCMakeFiles(const std::string& path);
 
   // Cache version info
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
index ee5feee..2f6cf64 100644
--- a/Source/cmCallVisualStudioMacro.cxx
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -35,8 +35,8 @@
 #    endif
 #  endif
 
-///! Use ReportHRESULT to make a cmSystemTools::Message after calling
-///! a COM method that may have failed.
+//! Use ReportHRESULT to make a cmSystemTools::Message after calling
+//! a COM method that may have failed.
 #  define ReportHRESULT(hr, context)                                          \
     if (FAILED(hr)) {                                                         \
       if (LogErrorsAsMessages) {                                              \
@@ -50,7 +50,7 @@
       }                                                                       \
     }
 
-///! Using the given instance of Visual Studio, call the named macro
+//! Using the given instance of Visual Studio, call the named macro
 HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
                           const std::string& args)
 {
@@ -133,7 +133,7 @@
   return hr;
 }
 
-///! Get the Solution object from the IDE object
+//! Get the Solution object from the IDE object
 HRESULT GetSolutionObject(IDispatch* vsIDE, IDispatchPtr& vsSolution)
 {
   HRESULT hr = E_POINTER;
@@ -176,7 +176,7 @@
   return hr;
 }
 
-///! Get the FullName property from the Solution object
+//! Get the FullName property from the Solution object
 HRESULT GetSolutionFullName(IDispatch* vsSolution, std::string& fullName)
 {
   HRESULT hr = E_POINTER;
@@ -220,7 +220,7 @@
   return hr;
 }
 
-///! Get the FullName property from the Solution object, given the IDE object
+//! Get the FullName property from the Solution object, given the IDE object
 HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
 {
   IDispatchPtr vsSolution;
@@ -235,8 +235,8 @@
   return hr;
 }
 
-///! Get all running objects from the Windows running object table.
-///! Save them in a map by their display names.
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
 HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
 {
   // mrot == Map of the Running Object Table
@@ -292,8 +292,8 @@
   return hr;
 }
 
-///! Do the two file names refer to the same Visual Studio solution? Or are
-///! we perhaps looking for any and all solutions?
+//! Do the two file names refer to the same Visual Studio solution? Or are
+//! we perhaps looking for any and all solutions?
 bool FilesSameSolution(const std::string& slnFile, const std::string& slnName)
 {
   if (slnFile == "ALL" || slnName == "ALL") {
@@ -310,9 +310,9 @@
   return s1 == s2;
 }
 
-///! Find instances of Visual Studio with the given solution file
-///! open. Pass "ALL" for slnFile to gather all running instances
-///! of Visual Studio.
+//! Find instances of Visual Studio with the given solution file
+//! open. Pass "ALL" for slnFile to gather all running instances
+//! of Visual Studio.
 HRESULT FindVisualStudioInstances(const std::string& slnFile,
                                   std::vector<IDispatchPtr>& instances)
 {
@@ -384,8 +384,8 @@
   return count;
 }
 
-///! Get all running objects from the Windows running object table.
-///! Save them in a map by their display names.
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
 int cmCallVisualStudioMacro::CallMacro(const std::string& slnFile,
                                        const std::string& macro,
                                        const std::string& args,
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
index fdc9e66..9b5b3a8 100644
--- a/Source/cmCallVisualStudioMacro.h
+++ b/Source/cmCallVisualStudioMacro.h
@@ -16,16 +16,16 @@
 class cmCallVisualStudioMacro
 {
 public:
-  ///! Call the named macro in instances of Visual Studio with the
-  ///! given solution file open. Pass "ALL" for slnFile to call the
-  ///! macro in each Visual Studio instance.
+  //! Call the named macro in instances of Visual Studio with the
+  //! given solution file open. Pass "ALL" for slnFile to call the
+  //! macro in each Visual Studio instance.
   static int CallMacro(const std::string& slnFile, const std::string& macro,
                        const std::string& args,
                        const bool logErrorsAsMessages);
 
-  ///! Count the number of running instances of Visual Studio with the
-  ///! given solution file open. Pass "ALL" for slnFile to count all
-  ///! running Visual Studio instances.
+  //! Count the number of running instances of Visual Studio with the
+  //! given solution file open. Pass "ALL" for slnFile to count all
+  //! running Visual Studio instances.
   static int GetNumberOfRunningVisualStudioInstances(
     const std::string& slnFile);
 
diff --git a/Source/cmCommandArgumentsHelper.cxx b/Source/cmCommandArgumentsHelper.cxx
deleted file mode 100644
index 968b17c..0000000
--- a/Source/cmCommandArgumentsHelper.cxx
+++ /dev/null
@@ -1,233 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmCommandArgumentsHelper.h"
-
-cmCommandArgument::cmCommandArgument(cmCommandArgumentsHelper* args,
-                                     const char* key,
-                                     cmCommandArgumentGroup* group)
-  : Key(key)
-  , Group(group)
-  , WasActive(false)
-  , ArgumentsBeforeEmpty(true)
-  , CurrentIndex(0)
-{
-  if (args != nullptr) {
-    args->AddArgument(this);
-  }
-
-  if (this->Group != nullptr) {
-    this->Group->ContainedArguments.push_back(this);
-  }
-}
-
-void cmCommandArgument::Reset()
-{
-  this->WasActive = false;
-  this->CurrentIndex = 0;
-  this->DoReset();
-}
-
-void cmCommandArgument::Follows(const cmCommandArgument* arg)
-{
-  this->ArgumentsBeforeEmpty = false;
-  this->ArgumentsBefore.insert(arg);
-}
-
-void cmCommandArgument::FollowsGroup(const cmCommandArgumentGroup* group)
-{
-  if (group != nullptr) {
-    this->ArgumentsBeforeEmpty = false;
-    this->ArgumentsBefore.insert(group->ContainedArguments.begin(),
-                                 group->ContainedArguments.end());
-  }
-}
-
-bool cmCommandArgument::MayFollow(const cmCommandArgument* current) const
-{
-  if (this->ArgumentsBeforeEmpty) {
-    return true;
-  }
-  return this->ArgumentsBefore.find(current) != this->ArgumentsBefore.end();
-}
-
-bool cmCommandArgument::KeyMatches(const std::string& key) const
-{
-  if ((this->Key == nullptr) || (this->Key[0] == '\0')) {
-    return true;
-  }
-  return (key == this->Key);
-}
-
-void cmCommandArgument::ApplyOwnGroup()
-{
-  if (this->Group != nullptr) {
-    for (cmCommandArgument* cargs : this->Group->ContainedArguments) {
-      if (cargs != this) {
-        this->ArgumentsBefore.insert(cargs);
-      }
-    }
-  }
-}
-
-void cmCommandArgument::Activate()
-{
-  this->WasActive = true;
-  this->CurrentIndex = 0;
-}
-
-bool cmCommandArgument::Consume(const std::string& arg)
-{
-  bool res = this->DoConsume(arg, this->CurrentIndex);
-  this->CurrentIndex++;
-  return res;
-}
-
-cmCAStringVector::cmCAStringVector(cmCommandArgumentsHelper* args,
-                                   const char* key,
-                                   cmCommandArgumentGroup* group)
-  : cmCommandArgument(args, key, group)
-  , Ignore(nullptr)
-{
-  if ((key == nullptr) || (*key == 0)) {
-    this->DataStart = 0;
-  } else {
-    this->DataStart = 1;
-  }
-}
-
-bool cmCAStringVector::DoConsume(const std::string& arg, unsigned int index)
-{
-  if (index >= this->DataStart) {
-    if ((this->Ignore == nullptr) || (arg != this->Ignore)) {
-      this->Vector.push_back(arg);
-    }
-  }
-
-  return false;
-}
-
-void cmCAStringVector::DoReset()
-{
-  this->Vector.clear();
-}
-
-cmCAString::cmCAString(cmCommandArgumentsHelper* args, const char* key,
-                       cmCommandArgumentGroup* group)
-  : cmCommandArgument(args, key, group)
-{
-  if ((key == nullptr) || (*key == 0)) {
-    this->DataStart = 0;
-  } else {
-    this->DataStart = 1;
-  }
-}
-
-bool cmCAString::DoConsume(const std::string& arg, unsigned int index)
-{
-  if (index == this->DataStart) {
-    this->String = arg;
-  }
-
-  return index >= this->DataStart;
-}
-
-void cmCAString::DoReset()
-{
-  this->String.clear();
-}
-
-cmCAEnabler::cmCAEnabler(cmCommandArgumentsHelper* args, const char* key,
-                         cmCommandArgumentGroup* group)
-  : cmCommandArgument(args, key, group)
-  , Enabled(false)
-{
-}
-
-bool cmCAEnabler::DoConsume(const std::string&, unsigned int index)
-{
-  if (index == 0) {
-    this->Enabled = true;
-  }
-  return true;
-}
-
-void cmCAEnabler::DoReset()
-{
-  this->Enabled = false;
-}
-
-cmCADisabler::cmCADisabler(cmCommandArgumentsHelper* args, const char* key,
-                           cmCommandArgumentGroup* group)
-  : cmCommandArgument(args, key, group)
-  , Enabled(true)
-{
-}
-
-bool cmCADisabler::DoConsume(const std::string&, unsigned int index)
-{
-  if (index == 0) {
-    this->Enabled = false;
-  }
-  return true;
-}
-
-void cmCADisabler::DoReset()
-{
-  this->Enabled = true;
-}
-
-void cmCommandArgumentGroup::Follows(const cmCommandArgument* arg)
-{
-  for (cmCommandArgument* ca : this->ContainedArguments) {
-    ca->Follows(arg);
-  }
-}
-
-void cmCommandArgumentGroup::FollowsGroup(const cmCommandArgumentGroup* group)
-{
-  for (cmCommandArgument* ca : this->ContainedArguments) {
-    ca->FollowsGroup(group);
-  }
-}
-
-void cmCommandArgumentsHelper::Parse(const std::vector<std::string>* args,
-                                     std::vector<std::string>* unconsumedArgs)
-{
-  if (args == nullptr) {
-    return;
-  }
-
-  for (cmCommandArgument* ca : this->Arguments) {
-    ca->ApplyOwnGroup();
-    ca->Reset();
-  }
-
-  cmCommandArgument* activeArgument = nullptr;
-  const cmCommandArgument* previousArgument = nullptr;
-  for (std::string const& it : *args) {
-    for (cmCommandArgument* ca : this->Arguments) {
-      if (ca->KeyMatches(it) && (ca->MayFollow(previousArgument))) {
-        activeArgument = ca;
-        activeArgument->Activate();
-        break;
-      }
-    }
-
-    if (activeArgument) {
-      bool argDone = activeArgument->Consume(it);
-      previousArgument = activeArgument;
-      if (argDone) {
-        activeArgument = nullptr;
-      }
-    } else {
-      if (unconsumedArgs != nullptr) {
-        unconsumedArgs->push_back(it);
-      }
-    }
-  }
-}
-
-void cmCommandArgumentsHelper::AddArgument(cmCommandArgument* arg)
-{
-  this->Arguments.push_back(arg);
-}
diff --git a/Source/cmCommandArgumentsHelper.h b/Source/cmCommandArgumentsHelper.h
deleted file mode 100644
index dc934be..0000000
--- a/Source/cmCommandArgumentsHelper.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#ifndef cmCommandArgumentsHelper_h
-#define cmCommandArgumentsHelper_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <set>
-#include <string>
-#include <vector>
-
-class cmCommandArgumentGroup;
-class cmCommandArgumentsHelper;
-
-/* cmCommandArgumentsHelper, cmCommandArgumentGroup and cmCommandArgument (i.e.
-its derived classes cmCAXXX can be used to simplify the processing of
-arguments to cmake commands. Maybe they can also be used to generate
-documentation.
-
-For every argument supported by a command one cmCommandArgument is created
-and added to cmCommandArgumentsHelper. cmCommand has a cmCommandArgumentsHelper
-as member variable so this should be used.
-
-The order of the arguments is defined using the Follows(arg) method. It says
-that this argument follows immediateley the given argument. It can be used
-with multiple arguments if the argument can follow after different arguments.
-
-Arguments can be arranged in groups using cmCommandArgumentGroup. Every
-member of a group can follow any other member of the group. These groups
-can also be used to define the order.
-
-Once all arguments and groups are set up, cmCommandArgumentsHelper::Parse()
-is called and afterwards the values of the arguments can be evaluated.
-
-For an example see cmExportCommand.cxx.
-*/
-class cmCommandArgument
-{
-public:
-  cmCommandArgument(cmCommandArgumentsHelper* args, const char* key,
-                    cmCommandArgumentGroup* group = nullptr);
-  virtual ~cmCommandArgument() = default;
-
-  /// this argument may follow after arg. 0 means it comes first.
-  void Follows(const cmCommandArgument* arg);
-
-  /// this argument may follow after any of the arguments in the given group
-  void FollowsGroup(const cmCommandArgumentGroup* group);
-
-  /// Returns true if the argument was found in the argument list
-  bool WasFound() const { return this->WasActive; }
-
-  // The following methods are only called from
-  // cmCommandArgumentsHelper::Parse(), but making this a friend would
-  // give it access to everything
-
-  /// Make the current argument the currently active argument
-  void Activate();
-  /// Consume the current string
-  bool Consume(const std::string& arg);
-
-  /// Return true if this argument may follow after the given argument.
-  bool MayFollow(const cmCommandArgument* current) const;
-
-  /** Returns true if the given key matches the key for this argument.
-  If this argument has an empty key everything matches. */
-  bool KeyMatches(const std::string& key) const;
-
-  /// Make this argument follow all members of the own group
-  void ApplyOwnGroup();
-
-  /// Reset argument, so it's back to its initial state
-  void Reset();
-
-private:
-  const char* Key;
-  std::set<const cmCommandArgument*> ArgumentsBefore;
-  cmCommandArgumentGroup* Group;
-  bool WasActive;
-  bool ArgumentsBeforeEmpty;
-  unsigned int CurrentIndex;
-
-  virtual bool DoConsume(const std::string& arg, unsigned int index) = 0;
-  virtual void DoReset() = 0;
-};
-
-/** cmCAStringVector is to be used for arguments which can consist of more
-than one string, e.g. the FILES argument in INSTALL(FILES f1 f2 f3 ...). */
-class cmCAStringVector : public cmCommandArgument
-{
-public:
-  cmCAStringVector(cmCommandArgumentsHelper* args, const char* key,
-                   cmCommandArgumentGroup* group = nullptr);
-
-  /// Return the vector of strings
-  const std::vector<std::string>& GetVector() const { return this->Vector; }
-
-  /** Is there a keyword which should be skipped in
-  the arguments (e.g. ARGS for ADD_CUSTOM_COMMAND) ? */
-  void SetIgnore(const char* ignore) { this->Ignore = ignore; }
-
-private:
-  std::vector<std::string> Vector;
-  unsigned int DataStart;
-  const char* Ignore;
-  bool DoConsume(const std::string& arg, unsigned int index) override;
-  void DoReset() override;
-};
-
-/** cmCAString is to be used for arguments which consist of one value,
-e.g. the executable name in ADD_EXECUTABLE(). */
-class cmCAString : public cmCommandArgument
-{
-public:
-  cmCAString(cmCommandArgumentsHelper* args, const char* key,
-             cmCommandArgumentGroup* group = nullptr);
-
-  /// Return the string
-  const std::string& GetString() const { return this->String; }
-  const char* GetCString() const { return this->String.c_str(); }
-
-private:
-  std::string String;
-  unsigned int DataStart;
-  bool DoConsume(const std::string& arg, unsigned int index) override;
-  void DoReset() override;
-};
-
-/** cmCAEnabler is to be used for options which are off by default and can be
-enabled using a special argument, e.g. EXCLUDE_FROM_ALL in ADD_EXECUTABLE(). */
-class cmCAEnabler : public cmCommandArgument
-{
-public:
-  cmCAEnabler(cmCommandArgumentsHelper* args, const char* key,
-              cmCommandArgumentGroup* group = nullptr);
-
-  /// Has it been enabled ?
-  bool IsEnabled() const { return this->Enabled; }
-
-private:
-  bool Enabled;
-  bool DoConsume(const std::string& arg, unsigned int index) override;
-  void DoReset() override;
-};
-
-/** cmCADisable is to be used for options which are on by default and can be
-disabled using a special argument.*/
-class cmCADisabler : public cmCommandArgument
-{
-public:
-  cmCADisabler(cmCommandArgumentsHelper* args, const char* key,
-               cmCommandArgumentGroup* group = nullptr);
-
-  /// Is it still enabled ?
-  bool IsEnabled() const { return this->Enabled; }
-
-private:
-  bool Enabled;
-  bool DoConsume(const std::string& arg, unsigned int index) override;
-  void DoReset() override;
-};
-
-/** Group of arguments, needed for ordering. E.g. WIN32, EXCLUDE_FROM_ALL and
-MACSOX_BUNDLE from ADD_EXECUTABLE() are a group.
-*/
-class cmCommandArgumentGroup
-{
-  friend class cmCommandArgument;
-
-public:
-  /// All members of this group may follow the given argument
-  void Follows(const cmCommandArgument* arg);
-
-  /// All members of this group may follow all members of the given group
-  void FollowsGroup(const cmCommandArgumentGroup* group);
-
-private:
-  std::vector<cmCommandArgument*> ContainedArguments;
-};
-
-class cmCommandArgumentsHelper
-{
-public:
-  /// Parse the argument list
-  void Parse(const std::vector<std::string>* args,
-             std::vector<std::string>* unconsumedArgs);
-  /// Add an argument.
-  void AddArgument(cmCommandArgument* arg);
-
-private:
-  std::vector<cmCommandArgument*> Arguments;
-};
-
-#endif
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 4717cf6..186deb6 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -9,6 +9,7 @@
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -256,11 +257,7 @@
   // Iterate in reverse order so we can keep only the last occurrence
   // of a shared library.
   std::set<int> emmitted;
-  for (std::vector<int>::const_reverse_iterator
-         li = this->FinalLinkOrder.rbegin(),
-         le = this->FinalLinkOrder.rend();
-       li != le; ++li) {
-    int i = *li;
+  for (int i : cmReverseRange(this->FinalLinkOrder)) {
     LinkEntry const& e = this->EntryList[i];
     cmGeneratorTarget const* t = e.Target;
     // Entries that we know the linker will re-use do not need to be repeated.
@@ -586,11 +583,10 @@
     }
 
     // Intersect the sets for this item.
-    DependSetList::const_iterator i = sets->begin();
-    DependSet common = *i;
-    for (++i; i != sets->end(); ++i) {
+    DependSet common = sets->front();
+    for (DependSet const& i : cmMakeRange(*sets).advance(1)) {
       DependSet intersection;
-      std::set_intersection(common.begin(), common.end(), i->begin(), i->end(),
+      std::set_intersection(common.begin(), common.end(), i.begin(), i.end(),
                             std::inserter(intersection, intersection.begin()));
       common = intersection;
     }
@@ -708,9 +704,8 @@
   // Run in reverse order so the topological order will preserve the
   // original order where there are no constraints.
   EdgeList const& nl = this->CCG->GetComponentGraphEdges(c);
-  for (EdgeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
-       ++ni) {
-    this->VisitComponent(*ni);
+  for (cmGraphEdge const& edge : cmReverseRange(nl)) {
+    this->VisitComponent(edge);
   }
 
   // Assign an ordering id to this component.
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 252f874..dfaaf8b 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -31,6 +31,9 @@
                        const std::string& config);
   ~cmComputeLinkDepends();
 
+  cmComputeLinkDepends(const cmComputeLinkDepends&) = delete;
+  cmComputeLinkDepends& operator=(const cmComputeLinkDepends&) = delete;
+
   // Basic information about each link item.
   struct LinkEntry
   {
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 3d61665..44d8615 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -457,8 +457,8 @@
   // We require a link language for the target.
   if (this->LinkLanguage.empty()) {
     cmSystemTools::Error(
-      "CMake can not determine linker language for target: ",
-      this->Target->GetName().c_str());
+      "CMake can not determine linker language for target: " +
+      this->Target->GetName());
     return false;
   }
 
@@ -1266,7 +1266,7 @@
 void cmComputeLinkInformation::AddDirectoryItem(std::string const& item)
 {
   if (this->Makefile->IsOn("APPLE") &&
-      cmSystemTools::IsPathToFramework(item.c_str())) {
+      cmSystemTools::IsPathToFramework(item)) {
     this->AddFrameworkItem(item);
   } else {
     this->DropDirectoryItem(item);
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 9b7b02f..01d4c07 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -11,6 +11,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -549,10 +550,9 @@
     int head = -1;
     std::set<int> emitted;
     NodeList const& nl = components[c];
-    for (NodeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
-         ++ni) {
+    for (int ni : cmReverseRange(nl)) {
       std::set<int> visited;
-      if (!this->IntraComponent(cmap, c, *ni, &head, emitted, visited)) {
+      if (!this->IntraComponent(cmap, c, ni, &head, emitted, visited)) {
         // Cycle in add_dependencies within component!
         this->ComplainAboutBadComponent(ccg, c, true);
         return false;
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 94ea529..303b147 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -130,8 +130,8 @@
     return false;
   }
 
-  return this->GetBooleanValueWithAutoDereference(*(newArgs.begin()),
-                                                  errorString, status, true);
+  return this->GetBooleanValueWithAutoDereference(newArgs.front(), errorString,
+                                                  status, true);
 }
 
 //=========================================================================
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
index 8224a0f..0917d11 100644
--- a/Source/cmConfigureFileCommand.cxx
+++ b/Source/cmConfigureFileCommand.cxx
@@ -102,7 +102,7 @@
 
 int cmConfigureFileCommand::ConfigureFile()
 {
-  return this->Makefile->ConfigureFile(
-    this->InputFile.c_str(), this->OutputFile.c_str(), this->CopyOnly,
-    this->AtOnly, this->EscapeQuotes, this->NewLineStyle);
+  return this->Makefile->ConfigureFile(this->InputFile, this->OutputFile,
+                                       this->CopyOnly, this->AtOnly,
+                                       this->EscapeQuotes, this->NewLineStyle);
 }
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 3892011..dcb1ff5 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -60,7 +60,8 @@
 /* GHS Multi platform variables */
 static std::set<std::string> ghs_platform_vars{
   "GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT",
-  "GHS_OS_ROOT",         "GHS_OS_DIR",         "GHS_BSP_NAME"
+  "GHS_OS_ROOT",         "GHS_OS_DIR",         "GHS_BSP_NAME",
+  "GHS_OS_DIR_OPTION"
 };
 
 static void writeProperty(FILE* fout, std::string const& targetName,
@@ -896,7 +897,7 @@
     // Forward the GHS variables to the inner project cache.
     for (std::string const& var : ghs_platform_vars) {
       if (const char* val = this->Makefile->GetDefinition(var)) {
-        std::string flag = "-D" + var + "=" + val;
+        std::string flag = "-D" + var + "=" + "'" + val + "'";
         cmakeFlags.push_back(std::move(flag));
       }
     }
@@ -965,8 +966,8 @@
   if (binDir.find("CMakeTmp") == std::string::npos) {
     cmSystemTools::Error(
       "TRY_COMPILE attempt to remove -rf directory that does not contain "
-      "CMakeTmp:",
-      binDir.c_str());
+      "CMakeTmp:" +
+      binDir);
     return;
   }
 
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 69532e6..b78493f 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -136,8 +136,7 @@
   this->Makefile->AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES",
                                 functionMapCode.c_str());
   bool res = true;
-  if (!this->Makefile->ConfigureFile(configFile.c_str(), driver.c_str(), false,
-                                     true, false)) {
+  if (!this->Makefile->ConfigureFile(configFile, driver, false, true, false)) {
     res = false;
   }
 
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 9684cff..7fd60c0 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -32,6 +32,9 @@
   cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
                            cmLocalGenerator* lg);
   ~cmCustomCommandGenerator();
+  cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
+  cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
+    delete;
   cmCustomCommand const& GetCC() const { return this->CC; }
   unsigned int GetNumberOfCommands() const;
   std::string GetCommand(unsigned int c) const;
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
index 7d1d316..ed76dbf 100644
--- a/Source/cmDepends.cxx
+++ b/Source/cmDepends.cxx
@@ -2,7 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmDepends.h"
 
-#include "cmFileTimeComparison.h"
+#include "cmFileTime.h"
+#include "cmFileTimeCache.h"
 #include "cmGeneratedFileStream.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -10,46 +11,39 @@
 
 #include "cmsys/FStream.hxx"
 #include <sstream>
-#include <string.h>
 #include <utility>
 
 cmDepends::cmDepends(cmLocalGenerator* lg, std::string targetDir)
   : LocalGenerator(lg)
   , TargetDirectory(std::move(targetDir))
-  , Dependee(new char[MaxPath])
-  , Depender(new char[MaxPath])
 {
 }
 
-cmDepends::~cmDepends()
-{
-  delete[] this->Dependee;
-  delete[] this->Depender;
-}
+cmDepends::~cmDepends() = default;
 
 bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
 {
-  // Lookup the set of sources to scan.
-  std::string srcLang = "CMAKE_DEPENDS_CHECK_";
-  srcLang += this->Language;
-  cmMakefile* mf = this->LocalGenerator->GetMakefile();
-  std::string const& srcStr = mf->GetSafeDefinition(srcLang);
-  std::vector<std::string> pairs;
-  cmSystemTools::ExpandListArgument(srcStr, pairs);
-
   std::map<std::string, std::set<std::string>> dependencies;
-  for (std::vector<std::string>::iterator si = pairs.begin();
-       si != pairs.end();) {
-    // Get the source and object file.
-    std::string const& src = *si++;
-    if (si == pairs.end()) {
-      break;
+  {
+    // Lookup the set of sources to scan.
+    std::vector<std::string> pairs;
+    {
+      std::string const srcLang = "CMAKE_DEPENDS_CHECK_" + this->Language;
+      cmMakefile* mf = this->LocalGenerator->GetMakefile();
+      cmSystemTools::ExpandListArgument(mf->GetSafeDefinition(srcLang), pairs);
     }
-    std::string const& obj = *si++;
-    dependencies[obj].insert(src);
+    for (std::vector<std::string>::iterator si = pairs.begin();
+         si != pairs.end();) {
+      // Get the source and object file.
+      std::string const& src = *si++;
+      if (si == pairs.end()) {
+        break;
+      }
+      std::string const& obj = *si++;
+      dependencies[obj].insert(src);
+    }
   }
   for (auto const& d : dependencies) {
-
     // Write the dependencies for this pair.
     if (!this->WriteDependencies(d.second, d.first, makeDepends,
                                  internalDepends)) {
@@ -67,7 +61,7 @@
 
 bool cmDepends::Check(const std::string& makeFile,
                       const std::string& internalFile,
-                      std::map<std::string, DependencyVector>& validDeps)
+                      DependencyMap& validDeps)
 {
   // Check whether dependencies must be regenerated.
   bool okay = true;
@@ -76,9 +70,9 @@
     // Clear all dependencies so they will be regenerated.
     this->Clear(makeFile);
     cmSystemTools::RemoveFile(internalFile);
+    this->FileTimeCache->Remove(internalFile);
     okay = false;
   }
-
   return okay;
 }
 
@@ -107,48 +101,62 @@
   return false;
 }
 
-bool cmDepends::CheckDependencies(
-  std::istream& internalDepends, const std::string& internalDependsFileName,
-  std::map<std::string, DependencyVector>& validDeps)
+bool cmDepends::CheckDependencies(std::istream& internalDepends,
+                                  const std::string& internalDependsFileName,
+                                  DependencyMap& validDeps)
 {
+  // Read internal depends file time
+  cmFileTime internalDependsTime;
+  if (!this->FileTimeCache->Load(internalDependsFileName,
+                                 internalDependsTime)) {
+    return false;
+  }
+
   // Parse dependencies from the stream.  If any dependee is missing
   // or newer than the depender then dependencies should be
   // regenerated.
   bool okay = true;
   bool dependerExists = false;
-  DependencyVector* currentDependencies = nullptr;
 
-  while (internalDepends.getline(this->Dependee, this->MaxPath)) {
-    if (this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
-        this->Dependee[0] == '\r') {
+  std::string line;
+  line.reserve(1024);
+  std::string depender;
+  std::string dependee;
+  cmFileTime dependerTime;
+  cmFileTime dependeeTime;
+  std::vector<std::string>* currentDependencies = nullptr;
+
+  while (std::getline(internalDepends, line)) {
+    // Check if this an empty or a comment line
+    if (line.empty() || line.front() == '#') {
       continue;
     }
-    size_t len = internalDepends.gcount() - 1;
-    if (this->Dependee[len - 1] == '\r') {
-      len--;
-      this->Dependee[len] = 0;
+    // Drop carriage return character at the end
+    if (line.back() == '\r') {
+      line.pop_back();
+      if (line.empty()) {
+        continue;
+      }
     }
-    if (this->Dependee[0] != ' ') {
-      memcpy(this->Depender, this->Dependee, len + 1);
-      // Calling FileExists() for the depender here saves in many cases 50%
-      // of the calls to FileExists() further down in the loop. E.g. for
-      // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
-      // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
-      dependerExists = cmSystemTools::FileExists(this->Depender);
+    // Check if this a depender line
+    if (line.front() != ' ') {
+      depender = line;
+      dependerExists = this->FileTimeCache->Load(depender, dependerTime);
       // If we erase validDeps[this->Depender] by overwriting it with an empty
       // vector, we lose dependencies for dependers that have multiple
       // entries. No need to initialize the entry, std::map will do so on first
       // access.
-      currentDependencies = &validDeps[this->Depender];
+      currentDependencies = &validDeps[depender];
       continue;
     }
-    /*
-    // Parse the dependency line.
-    if(!this->ParseDependency(line.c_str()))
-      {
-      continue;
-      }
-      */
+
+    // This is a dependee line
+    dependee = line.substr(1);
+
+    // Add dependee to depender's list
+    if (currentDependencies != nullptr) {
+      currentDependencies->push_back(dependee);
+    }
 
     // Dependencies must be regenerated
     // * if the dependee does not exist
@@ -156,13 +164,8 @@
     // * if the depender does not exist, but the dependee is newer than the
     //   depends file
     bool regenerate = false;
-    const std::string dependee(this->Dependee + 1);
-    const std::string depender(this->Depender);
-    if (currentDependencies != nullptr) {
-      currentDependencies->push_back(dependee);
-    }
-
-    if (!cmSystemTools::FileExists(dependee)) {
+    bool dependeeExists = this->FileTimeCache->Load(dependee, dependeeTime);
+    if (!dependeeExists) {
       // The dependee does not exist.
       regenerate = true;
 
@@ -173,45 +176,38 @@
             << depender << "\"." << std::endl;
         cmSystemTools::Stdout(msg.str());
       }
-    } else {
-      if (dependerExists) {
-        // The dependee and depender both exist.  Compare file times.
-        int result = 0;
-        if ((!this->FileComparison->FileTimeCompare(depender, dependee,
-                                                    &result) ||
-             result < 0)) {
-          // The depender is older than the dependee.
-          regenerate = true;
+    } else if (dependerExists) {
+      // The dependee and depender both exist.  Compare file times.
+      if (dependerTime.Older(dependeeTime)) {
+        // The depender is older than the dependee.
+        regenerate = true;
 
-          // Print verbose output.
-          if (this->Verbose) {
-            std::ostringstream msg;
-            msg << "Dependee \"" << dependee << "\" is newer than depender \""
-                << depender << "\"." << std::endl;
-            cmSystemTools::Stdout(msg.str());
-          }
+        // Print verbose output.
+        if (this->Verbose) {
+          std::ostringstream msg;
+          msg << "Dependee \"" << dependee << "\" is newer than depender \""
+              << depender << "\"." << std::endl;
+          cmSystemTools::Stdout(msg.str());
         }
-      } else {
-        // The dependee exists, but the depender doesn't. Regenerate if the
-        // internalDepends file is older than the dependee.
-        int result = 0;
-        if ((!this->FileComparison->FileTimeCompare(internalDependsFileName,
-                                                    dependee, &result) ||
-             result < 0)) {
-          // The depends-file is older than the dependee.
-          regenerate = true;
+      }
+    } else {
+      // The dependee exists, but the depender doesn't. Regenerate if the
+      // internalDepends file is older than the dependee.
+      if (internalDependsTime.Older(dependeeTime)) {
+        // The depends-file is older than the dependee.
+        regenerate = true;
 
-          // Print verbose output.
-          if (this->Verbose) {
-            std::ostringstream msg;
-            msg << "Dependee \"" << dependee
-                << "\" is newer than depends file \""
-                << internalDependsFileName << "\"." << std::endl;
-            cmSystemTools::Stdout(msg.str());
-          }
+        // Print verbose output.
+        if (this->Verbose) {
+          std::ostringstream msg;
+          msg << "Dependee \"" << dependee
+              << "\" is newer than depends file \"" << internalDependsFileName
+              << "\"." << std::endl;
+          cmSystemTools::Stdout(msg.str());
         }
       }
     }
+
     if (regenerate) {
       // Dependencies must be regenerated.
       okay = false;
@@ -219,13 +215,14 @@
       // Remove the information of this depender from the map, it needs
       // to be rescanned
       if (currentDependencies != nullptr) {
-        validDeps.erase(this->Depender);
+        validDeps.erase(depender);
         currentDependencies = nullptr;
       }
 
       // Remove the depender to be sure it is rebuilt.
       if (dependerExists) {
         cmSystemTools::RemoveFile(depender);
+        this->FileTimeCache->Remove(depender);
         dependerExists = false;
       }
     }
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
index 20c91ca..b7475f0 100644
--- a/Source/cmDepends.h
+++ b/Source/cmDepends.h
@@ -8,11 +8,10 @@
 #include <iosfwd>
 #include <map>
 #include <set>
-#include <stddef.h>
 #include <string>
 #include <vector>
 
-class cmFileTimeComparison;
+class cmFileTimeCache;
 class cmLocalGenerator;
 
 /** \class cmDepends
@@ -25,6 +24,9 @@
 class cmDepends
 {
 public:
+  typedef std::map<std::string, std::vector<std::string>> DependencyMap;
+
+public:
   /** Instances need to know the build directory name and the relative
       path from the build directory to the target file.  */
   cmDepends(cmLocalGenerator* lg = nullptr, std::string targetDir = "");
@@ -56,26 +58,19 @@
   /** Write dependencies for the target file.  */
   bool Write(std::ostream& makeDepends, std::ostream& internalDepends);
 
-  class DependencyVector : public std::vector<std::string>
-  {
-  };
-
   /** Check dependencies for the target file.  Returns true if
       dependencies are okay and false if they must be generated.  If
       they must be generated Clear has already been called to wipe out
       the old dependencies.
       Dependencies which are still valid will be stored in validDeps. */
   bool Check(const std::string& makeFile, const std::string& internalFile,
-             std::map<std::string, DependencyVector>& validDeps);
+             DependencyMap& validDeps);
 
   /** Clear dependencies for the target file so they will be regenerated.  */
   void Clear(const std::string& file);
 
   /** Set the file comparison object */
-  void SetFileComparison(cmFileTimeComparison* fc)
-  {
-    this->FileComparison = fc;
-  }
+  void SetFileTimeCache(cmFileTimeCache* fc) { this->FileTimeCache = fc; }
 
 protected:
   // Write dependencies for the target file to the given stream.
@@ -88,9 +83,9 @@
   // Check dependencies for the target file in the given stream.
   // Return false if dependencies must be regenerated and true
   // otherwise.
-  virtual bool CheckDependencies(
-    std::istream& internalDepends, const std::string& internalDependsFileName,
-    std::map<std::string, DependencyVector>& validDeps);
+  virtual bool CheckDependencies(std::istream& internalDepends,
+                                 const std::string& internalDependsFileName,
+                                 DependencyMap& validDeps);
 
   // Finalize the dependency information for the target.
   virtual bool Finalize(std::ostream& makeDepends,
@@ -101,17 +96,13 @@
 
   // Flag for verbose output.
   bool Verbose = false;
-  cmFileTimeComparison* FileComparison = nullptr;
+  cmFileTimeCache* FileTimeCache = nullptr;
 
   std::string Language;
 
   // The full path to the target's build directory.
   std::string TargetDirectory;
 
-  size_t MaxPath = 16384;
-  char* Dependee;
-  char* Depender;
-
   // The include file search path.
   std::vector<std::string> IncludePath;
 
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
index b1630f9..dc49c18 100644
--- a/Source/cmDependsC.cxx
+++ b/Source/cmDependsC.cxx
@@ -6,7 +6,7 @@
 #include <utility>
 
 #include "cmAlgorithms.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTime.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
@@ -21,9 +21,8 @@
 
 cmDependsC::cmDependsC() = default;
 
-cmDependsC::cmDependsC(
-  cmLocalGenerator* lg, const std::string& targetDir, const std::string& lang,
-  const std::map<std::string, DependencyVector>* validDeps)
+cmDependsC::cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
+                       const std::string& lang, const DependencyMap* validDeps)
   : cmDepends(lg, targetDir)
   , ValidDeps(validDeps)
 {
@@ -102,8 +101,7 @@
     this->LocalGenerator->MaybeConvertToRelativePath(binDir, obj);
 
   if (this->ValidDeps != nullptr) {
-    std::map<std::string, DependencyVector>::const_iterator tmpIt =
-      this->ValidDeps->find(obj_i);
+    auto const tmpIt = this->ValidDeps->find(obj_i);
     if (tmpIt != this->ValidDeps->end()) {
       dependencies.insert(tmpIt->second.begin(), tmpIt->second.end());
       haveDeps = true;
@@ -123,12 +121,6 @@
     }
 
     std::set<std::string> scanned;
-
-    // Use reserve to allocate enough memory for tempPathStr
-    // so that during the loops no memory is allocated or freed
-    std::string tempPathStr;
-    tempPathStr.reserve(4 * 1024);
-
     while (!this->Unscanned.empty()) {
       // Get the next file to scan.
       UnscannedEntry current = this->Unscanned.front();
@@ -147,22 +139,21 @@
         // the source containing the include statement.
         fullName = current.QuotedLocation;
       } else {
-        std::map<std::string, std::string>::iterator headerLocationIt =
+        auto headerLocationIt =
           this->HeaderLocationCache.find(current.FileName);
         if (headerLocationIt != this->HeaderLocationCache.end()) {
           fullName = headerLocationIt->second;
         } else {
-          for (std::string const& i : this->IncludePath) {
+          for (std::string const& iPath : this->IncludePath) {
             // Construct the name of the file as if it were in the current
             // include directory.  Avoid using a leading "./".
-
-            tempPathStr =
-              cmSystemTools::CollapseCombinedPath(i, current.FileName);
+            std::string tmpPath =
+              cmSystemTools::CollapseFullPath(current.FileName, iPath);
 
             // Look for the file in this location.
-            if (cmSystemTools::FileExists(tempPathStr, true)) {
-              fullName = tempPathStr;
-              HeaderLocationCache[current.FileName] = fullName;
+            if (cmSystemTools::FileExists(tmpPath, true)) {
+              fullName = tmpPath;
+              this->HeaderLocationCache[current.FileName] = std::move(tmpPath);
               break;
             }
           }
@@ -173,8 +164,7 @@
       // regex.
       if (fullName.empty() &&
           this->IncludeRegexComplain.find(current.FileName)) {
-        cmSystemTools::Error("Cannot find file \"", current.FileName.c_str(),
-                             "\".");
+        cmSystemTools::Error("Cannot find file \"" + current.FileName + "\".");
         return false;
       }
 
@@ -184,8 +174,7 @@
         scanned.insert(fullName);
 
         // Check whether this file is already in the cache
-        std::map<std::string, cmIncludeLines*>::iterator fileIt =
-          this->FileCache.find(fullName);
+        auto fileIt = this->FileCache.find(fullName);
         if (fileIt != this->FileCache.end()) {
           fileIt->second->Used = true;
           dependencies.insert(fullName);
@@ -257,6 +246,8 @@
   cmIncludeLines* cacheEntry = nullptr;
   bool haveFileName = false;
 
+  cmFileTime cacheFileTime;
+  bool const cacheFileTimeGood = cacheFileTime.Load(this->CacheFileName);
   while (cmSystemTools::GetLineFromStream(fin, line)) {
     if (line.empty()) {
       cacheEntry = nullptr;
@@ -266,11 +257,12 @@
     // the first line after an empty line is the name of the parsed file
     if (!haveFileName) {
       haveFileName = true;
-      int newer = 0;
-      cmFileTimeComparison comp;
-      bool res = comp.FileTimeCompare(this->CacheFileName, line, &newer);
 
-      if (res && newer == 1) // cache is newer than the parsed file
+      cmFileTime fileTime;
+      bool const res = cacheFileTimeGood && fileTime.Load(line);
+      bool const newer = res && cacheFileTime.Newer(fileTime);
+
+      if (res && newer) // cache is newer than the parsed file
       {
         cacheEntry = new cmIncludeLines;
         this->FileCache[line] = cacheEntry;
@@ -368,7 +360,7 @@
         // must check for the file in the directory containing the
         // file we are scanning.
         entry.QuotedLocation =
-          cmSystemTools::CollapseCombinedPath(directory, entry.FileName);
+          cmSystemTools::CollapseFullPath(entry.FileName, directory);
       }
 
       // Queue the file if it has not yet been encountered and it
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
index eee5ae1..3fc839e 100644
--- a/Source/cmDependsC.h
+++ b/Source/cmDependsC.h
@@ -27,8 +27,7 @@
       relative path from the build directory to the target file.  */
   cmDependsC();
   cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
-             const std::string& lang,
-             const std::map<std::string, DependencyVector>* validDeps);
+             const std::string& lang, const DependencyMap* validDeps);
 
   /** Virtual destructor to cleanup subclasses properly.  */
   ~cmDependsC() override;
@@ -81,7 +80,7 @@
   };
 
 protected:
-  const std::map<std::string, DependencyVector>* ValidDeps = nullptr;
+  const DependencyMap* ValidDeps = nullptr;
   std::set<std::string> Encountered;
   std::queue<UnscannedEntry> Unscanned;
 
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index 3f036a9..178e18b 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -295,7 +295,7 @@
           // They do not include the ".mod" extension.
           mod += ".mod";
         }
-        this->ConsiderModule(mod.c_str() + 1, stampDir);
+        this->ConsiderModule(mod.substr(1), stampDir);
       }
     } else if (line == "provides") {
       doing_provides = true;
diff --git a/Source/cmDependsJava.cxx b/Source/cmDependsJava.cxx
index 2485e15..b17b2ba 100644
--- a/Source/cmDependsJava.cxx
+++ b/Source/cmDependsJava.cxx
@@ -24,8 +24,7 @@
 
 bool cmDependsJava::CheckDependencies(
   std::istream& /*internalDepends*/,
-  const std::string& /*internalDependsFileName*/,
-  std::map<std::string, DependencyVector>& /*validDeps*/)
+  const std::string& /*internalDependsFileName*/, DependencyMap& /*validDeps*/)
 {
   return true;
 }
diff --git a/Source/cmDependsJava.h b/Source/cmDependsJava.h
index 109ef13..dd671a1 100644
--- a/Source/cmDependsJava.h
+++ b/Source/cmDependsJava.h
@@ -8,7 +8,6 @@
 #include "cmDepends.h"
 
 #include <iosfwd>
-#include <map>
 #include <set>
 #include <string>
 
@@ -33,9 +32,9 @@
   bool WriteDependencies(const std::set<std::string>& sources,
                          const std::string& file, std::ostream& makeDepends,
                          std::ostream& internalDepends) override;
-  bool CheckDependencies(
-    std::istream& internalDepends, const std::string& internalDependsFileName,
-    std::map<std::string, DependencyVector>& validDeps) override;
+  bool CheckDependencies(std::istream& internalDepends,
+                         const std::string& internalDependsFileName,
+                         DependencyMap& validDeps) override;
 };
 
 #endif
diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx
index 792db48..12d875d 100644
--- a/Source/cmDependsJavaParserHelper.cxx
+++ b/Source/cmDependsJavaParserHelper.cxx
@@ -5,6 +5,7 @@
 #include "cmDependsJavaLexer.h"
 #include "cmSystemTools.h"
 
+#include "cm_string_view.hxx"
 #include "cmsys/FStream.hxx"
 #include <iostream>
 #include <stdio.h>
@@ -298,14 +299,10 @@
   unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
   fprintf(stderr, "JPError: %s (%lu / Line: %d)\n", str, pos,
           this->CurrentLine);
-  int cc;
-  std::cerr << "String: [";
-  for (cc = 0;
-       cc < 30 && *(this->InputBuffer.c_str() + this->InputBufferPos + cc);
-       cc++) {
-    std::cerr << *(this->InputBuffer.c_str() + this->InputBufferPos + cc);
-  }
-  std::cerr << "]" << std::endl;
+  std::cerr << "String: ["
+            << cm::string_view{ this->InputBuffer }.substr(
+                 this->InputBufferPos, 30)
+            << "]" << std::endl;
 }
 
 void cmDependsJavaParserHelper::UpdateCombine(const char* str1,
diff --git a/Source/cmDependsJavaParserHelper.h b/Source/cmDependsJavaParserHelper.h
index 0b445d9..a673b5b 100644
--- a/Source/cmDependsJavaParserHelper.h
+++ b/Source/cmDependsJavaParserHelper.h
@@ -24,6 +24,10 @@
   cmDependsJavaParserHelper();
   ~cmDependsJavaParserHelper();
 
+  cmDependsJavaParserHelper(const cmDependsJavaParserHelper&) = delete;
+  cmDependsJavaParserHelper& operator=(const cmDependsJavaParserHelper&) =
+    delete;
+
   int ParseString(const char* str, int verb);
   int ParseFile(const char* file);
 
diff --git a/Source/cmELF.h b/Source/cmELF.h
index c8a91e4..987f0c3 100644
--- a/Source/cmELF.h
+++ b/Source/cmELF.h
@@ -28,6 +28,9 @@
   /** Destruct.   */
   ~cmELF();
 
+  cmELF(const cmELF&) = delete;
+  cmELF& operator=(const cmELF&) = delete;
+
   /** Get the error message if any.  */
   std::string const& GetErrorMessage() const { return this->ErrorMessage; }
 
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
index 75a7786..36651af 100644
--- a/Source/cmExecProgramCommand.cxx
+++ b/Source/cmExecProgramCommand.cxx
@@ -67,7 +67,7 @@
 
   std::string command;
   if (!arguments.empty()) {
-    command = cmSystemTools::ConvertToRunCommandPath(args[0].c_str());
+    command = cmSystemTools::ConvertToRunCommandPath(args[0]);
     command += " ";
     command += arguments;
   } else {
@@ -152,7 +152,7 @@
         if (!cmSystemTools::FileExists(cmd)) {
           shortCmd = cmd;
         } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) {
-          cmSystemTools::Error("GetShortPath failed for ", cmd.c_str());
+          cmSystemTools::Error("GetShortPath failed for " + cmd);
           return false;
         }
         shortCmd += " ";
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 8c67cdb..ff6340f 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -2,12 +2,14 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExecuteProcessCommand.h"
 
+#include "cm_static_string_view.hxx"
 #include "cmsys/Process.h"
+#include <algorithm>
 #include <ctype.h> /* isspace */
-#include <sstream>
 #include <stdio.h>
 
 #include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
 #include "cmMakefile.h"
 #include "cmProcessOutput.h"
 #include "cmSystemTools.h"
@@ -32,157 +34,85 @@
     this->SetError("called with incorrect number of arguments");
     return false;
   }
-  std::vector<std::vector<const char*>> cmds;
-  std::string arguments;
-  bool doing_command = false;
-  size_t command_index = 0;
-  bool output_quiet = false;
-  bool error_quiet = false;
-  bool output_strip_trailing_whitespace = false;
-  bool error_strip_trailing_whitespace = false;
-  std::string timeout_string;
-  std::string input_file;
-  std::string output_file;
-  std::string error_file;
-  std::string output_variable;
-  std::string error_variable;
-  std::string result_variable;
-  std::string results_variable;
-  std::string working_directory;
-  cmProcessOutput::Encoding encoding = cmProcessOutput::None;
-  for (size_t i = 0; i < args.size(); ++i) {
-    if (args[i] == "COMMAND") {
-      doing_command = true;
-      command_index = cmds.size();
-      cmds.emplace_back();
-    } else if (args[i] == "OUTPUT_VARIABLE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        output_variable = args[i];
-      } else {
-        this->SetError(" called with no value for OUTPUT_VARIABLE.");
-        return false;
-      }
-    } else if (args[i] == "ERROR_VARIABLE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        error_variable = args[i];
-      } else {
-        this->SetError(" called with no value for ERROR_VARIABLE.");
-        return false;
-      }
-    } else if (args[i] == "RESULT_VARIABLE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        result_variable = args[i];
-      } else {
-        this->SetError(" called with no value for RESULT_VARIABLE.");
-        return false;
-      }
-    } else if (args[i] == "RESULTS_VARIABLE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        results_variable = args[i];
-      } else {
-        this->SetError(" called with no value for RESULTS_VARIABLE.");
-        return false;
-      }
-    } else if (args[i] == "WORKING_DIRECTORY") {
-      doing_command = false;
-      if (++i < args.size()) {
-        working_directory = args[i];
-      } else {
-        this->SetError(" called with no value for WORKING_DIRECTORY.");
-        return false;
-      }
-    } else if (args[i] == "INPUT_FILE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        input_file = args[i];
-      } else {
-        this->SetError(" called with no value for INPUT_FILE.");
-        return false;
-      }
-    } else if (args[i] == "OUTPUT_FILE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        output_file = args[i];
-      } else {
-        this->SetError(" called with no value for OUTPUT_FILE.");
-        return false;
-      }
-    } else if (args[i] == "ERROR_FILE") {
-      doing_command = false;
-      if (++i < args.size()) {
-        error_file = args[i];
-      } else {
-        this->SetError(" called with no value for ERROR_FILE.");
-        return false;
-      }
-    } else if (args[i] == "TIMEOUT") {
-      doing_command = false;
-      if (++i < args.size()) {
-        timeout_string = args[i];
-      } else {
-        this->SetError(" called with no value for TIMEOUT.");
-        return false;
-      }
-    } else if (args[i] == "OUTPUT_QUIET") {
-      doing_command = false;
-      output_quiet = true;
-    } else if (args[i] == "ERROR_QUIET") {
-      doing_command = false;
-      error_quiet = true;
-    } else if (args[i] == "OUTPUT_STRIP_TRAILING_WHITESPACE") {
-      doing_command = false;
-      output_strip_trailing_whitespace = true;
-    } else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") {
-      doing_command = false;
-      error_strip_trailing_whitespace = true;
-    } else if (args[i] == "ENCODING") {
-      doing_command = false;
-      if (++i < args.size()) {
-        encoding = cmProcessOutput::FindEncoding(args[i]);
-      } else {
-        this->SetError(" called with no value for ENCODING.");
-        return false;
-      }
-    } else if (doing_command) {
-      cmds[command_index].push_back(args[i].c_str());
-    } else {
-      std::ostringstream e;
-      e << " given unknown argument \"" << args[i] << "\".";
-      this->SetError(e.str());
-      return false;
-    }
+
+  struct Arguments
+  {
+    std::vector<std::vector<std::string>> Commands;
+    std::string OutputVariable;
+    std::string ErrorVariable;
+    std::string ResultVariable;
+    std::string ResultsVariable;
+    std::string WorkingDirectory;
+    std::string InputFile;
+    std::string OutputFile;
+    std::string ErrorFile;
+    std::string Timeout;
+    bool OutputQuiet = false;
+    bool ErrorQuiet = false;
+    bool OutputStripTrailingWhitespace = false;
+    bool ErrorStripTrailingWhitespace = false;
+    std::string Encoding;
+  };
+
+  static auto const parser =
+    cmArgumentParser<Arguments>{}
+      .Bind("COMMAND"_s, &Arguments::Commands)
+      .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
+      .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable)
+      .Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable)
+      .Bind("RESULTS_VARIABLE"_s, &Arguments::ResultsVariable)
+      .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory)
+      .Bind("INPUT_FILE"_s, &Arguments::InputFile)
+      .Bind("OUTPUT_FILE"_s, &Arguments::OutputFile)
+      .Bind("ERROR_FILE"_s, &Arguments::ErrorFile)
+      .Bind("TIMEOUT"_s, &Arguments::Timeout)
+      .Bind("OUTPUT_QUIET"_s, &Arguments::OutputQuiet)
+      .Bind("ERROR_QUIET"_s, &Arguments::ErrorQuiet)
+      .Bind("OUTPUT_STRIP_TRAILING_WHITESPACE"_s,
+            &Arguments::OutputStripTrailingWhitespace)
+      .Bind("ERROR_STRIP_TRAILING_WHITESPACE"_s,
+            &Arguments::ErrorStripTrailingWhitespace)
+      .Bind("ENCODING"_s, &Arguments::Encoding);
+
+  std::vector<std::string> unparsedArguments;
+  std::vector<std::string> keywordsMissingValue;
+  Arguments const arguments =
+    parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+  if (!keywordsMissingValue.empty()) {
+    this->SetError(" called with no value for " +
+                   keywordsMissingValue.front() + ".");
+    return false;
+  }
+  if (!unparsedArguments.empty()) {
+    this->SetError(" given unknown argument \"" + unparsedArguments.front() +
+                   "\".");
+    return false;
   }
 
-  if (!this->Makefile->CanIWriteThisFile(output_file)) {
-    std::string e = "attempted to output into a file: " + output_file +
-      " into a source directory.";
-    this->SetError(e);
+  if (!this->Makefile->CanIWriteThisFile(arguments.OutputFile)) {
+    this->SetError("attempted to output into a file: " + arguments.OutputFile +
+                   " into a source directory.");
     cmSystemTools::SetFatalErrorOccured();
     return false;
   }
 
   // Check for commands given.
-  if (cmds.empty()) {
+  if (arguments.Commands.empty()) {
     this->SetError(" called with no COMMAND argument.");
     return false;
   }
-  for (auto& cmd : cmds) {
+  for (std::vector<std::string> const& cmd : arguments.Commands) {
     if (cmd.empty()) {
       this->SetError(" given COMMAND argument with no value.");
       return false;
     }
-    // Add the null terminating pointer to the command argument list.
-    cmd.push_back(nullptr);
   }
 
   // Parse the timeout string.
   double timeout = -1;
-  if (!timeout_string.empty()) {
-    if (sscanf(timeout_string.c_str(), "%lg", &timeout) != 1) {
+  if (!arguments.Timeout.empty()) {
+    if (sscanf(arguments.Timeout.c_str(), "%lg", &timeout) != 1) {
       this->SetError(" called with TIMEOUT value that could not be parsed.");
       return false;
     }
@@ -192,13 +122,17 @@
   cmsysProcess* cp = cmsysProcess_New();
 
   // Set the command sequence.
-  for (auto const& cmd : cmds) {
-    cmsysProcess_AddCommand(cp, &*cmd.begin());
+  for (std::vector<std::string> const& cmd : arguments.Commands) {
+    std::vector<const char*> argv(cmd.size() + 1);
+    std::transform(cmd.begin(), cmd.end(), argv.begin(),
+                   [](std::string const& s) { return s.c_str(); });
+    argv.back() = nullptr;
+    cmsysProcess_AddCommand(cp, argv.data());
   }
 
   // Set the process working directory.
-  if (!working_directory.empty()) {
-    cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
+  if (!arguments.WorkingDirectory.empty()) {
+    cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
   }
 
   // Always hide the process window.
@@ -206,22 +140,24 @@
 
   // Check the output variables.
   bool merge_output = false;
-  if (!input_file.empty()) {
-    cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
+  if (!arguments.InputFile.empty()) {
+    cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
+                             arguments.InputFile.c_str());
   }
-  if (!output_file.empty()) {
+  if (!arguments.OutputFile.empty()) {
     cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
-                             output_file.c_str());
+                             arguments.OutputFile.c_str());
   }
-  if (!error_file.empty()) {
-    if (error_file == output_file) {
+  if (!arguments.ErrorFile.empty()) {
+    if (arguments.ErrorFile == arguments.OutputFile) {
       merge_output = true;
     } else {
       cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
-                               error_file.c_str());
+                               arguments.ErrorFile.c_str());
     }
   }
-  if (!output_variable.empty() && output_variable == error_variable) {
+  if (!arguments.OutputVariable.empty() &&
+      arguments.OutputVariable == arguments.ErrorVariable) {
     merge_output = true;
   }
   if (merge_output) {
@@ -242,19 +178,20 @@
   int length;
   char* data;
   int p;
-  cmProcessOutput processOutput(encoding);
+  cmProcessOutput processOutput(
+    cmProcessOutput::FindEncoding(arguments.Encoding));
   std::string strdata;
   while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
     // Put the output in the right place.
-    if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) {
-      if (output_variable.empty()) {
+    if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) {
+      if (arguments.OutputVariable.empty()) {
         processOutput.DecodeText(data, length, strdata, 1);
         cmSystemTools::Stdout(strdata);
       } else {
         cmExecuteProcessCommandAppend(tempOutput, data, length);
       }
-    } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) {
-      if (error_variable.empty()) {
+    } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) {
+      if (arguments.ErrorVariable.empty()) {
         processOutput.DecodeText(data, length, strdata, 2);
         cmSystemTools::Stderr(strdata);
       } else {
@@ -262,13 +199,13 @@
       }
     }
   }
-  if (!output_quiet && output_variable.empty()) {
+  if (!arguments.OutputQuiet && arguments.OutputVariable.empty()) {
     processOutput.DecodeText(std::string(), strdata, 1);
     if (!strdata.empty()) {
       cmSystemTools::Stdout(strdata);
     }
   }
-  if (!error_quiet && error_variable.empty()) {
+  if (!arguments.ErrorQuiet && arguments.ErrorVariable.empty()) {
     processOutput.DecodeText(std::string(), strdata, 2);
     if (!strdata.empty()) {
       cmSystemTools::Stderr(strdata);
@@ -281,46 +218,49 @@
   processOutput.DecodeText(tempError, tempError);
 
   // Fix the text in the output strings.
-  cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace);
-  cmExecuteProcessCommandFixText(tempError, error_strip_trailing_whitespace);
+  cmExecuteProcessCommandFixText(tempOutput,
+                                 arguments.OutputStripTrailingWhitespace);
+  cmExecuteProcessCommandFixText(tempError,
+                                 arguments.ErrorStripTrailingWhitespace);
 
   // Store the output obtained.
-  if (!output_variable.empty() && !tempOutput.empty()) {
-    this->Makefile->AddDefinition(output_variable, &*tempOutput.begin());
+  if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
+    this->Makefile->AddDefinition(arguments.OutputVariable, tempOutput.data());
   }
-  if (!merge_output && !error_variable.empty() && !tempError.empty()) {
-    this->Makefile->AddDefinition(error_variable, &*tempError.begin());
+  if (!merge_output && !arguments.ErrorVariable.empty() &&
+      !tempError.empty()) {
+    this->Makefile->AddDefinition(arguments.ErrorVariable, tempError.data());
   }
 
   // Store the result of running the process.
-  if (!result_variable.empty()) {
+  if (!arguments.ResultVariable.empty()) {
     switch (cmsysProcess_GetState(cp)) {
       case cmsysProcess_State_Exited: {
         int v = cmsysProcess_GetExitValue(cp);
         char buf[16];
         sprintf(buf, "%d", v);
-        this->Makefile->AddDefinition(result_variable, buf);
+        this->Makefile->AddDefinition(arguments.ResultVariable, buf);
       } break;
       case cmsysProcess_State_Exception:
-        this->Makefile->AddDefinition(result_variable,
+        this->Makefile->AddDefinition(arguments.ResultVariable,
                                       cmsysProcess_GetExceptionString(cp));
         break;
       case cmsysProcess_State_Error:
-        this->Makefile->AddDefinition(result_variable,
+        this->Makefile->AddDefinition(arguments.ResultVariable,
                                       cmsysProcess_GetErrorString(cp));
         break;
       case cmsysProcess_State_Expired:
-        this->Makefile->AddDefinition(result_variable,
+        this->Makefile->AddDefinition(arguments.ResultVariable,
                                       "Process terminated due to timeout");
         break;
     }
   }
   // Store the result of running the processes.
-  if (!results_variable.empty()) {
+  if (!arguments.ResultsVariable.empty()) {
     switch (cmsysProcess_GetState(cp)) {
       case cmsysProcess_State_Exited: {
         std::vector<std::string> res;
-        for (size_t i = 0; i < cmds.size(); ++i) {
+        for (size_t i = 0; i < arguments.Commands.size(); ++i) {
           switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) {
             case kwsysProcess_StateByIndex_Exited: {
               int exitCode =
@@ -339,19 +279,19 @@
               break;
           }
         }
-        this->Makefile->AddDefinition(results_variable,
+        this->Makefile->AddDefinition(arguments.ResultsVariable,
                                       cmJoin(res, ";").c_str());
       } break;
       case cmsysProcess_State_Exception:
-        this->Makefile->AddDefinition(results_variable,
+        this->Makefile->AddDefinition(arguments.ResultsVariable,
                                       cmsysProcess_GetExceptionString(cp));
         break;
       case cmsysProcess_State_Error:
-        this->Makefile->AddDefinition(results_variable,
+        this->Makefile->AddDefinition(arguments.ResultsVariable,
                                       cmsysProcess_GetErrorString(cp));
         break;
       case cmsysProcess_State_Expired:
-        this->Makefile->AddDefinition(results_variable,
+        this->Makefile->AddDefinition(arguments.ResultsVariable,
                                       "Process terminated due to timeout");
         break;
     }
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 722831a..5b611c0 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -2,10 +2,13 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportCommand.h"
 
+#include "cm_static_string_view.hxx"
 #include "cmsys/RegularExpression.hxx"
 #include <map>
 #include <sstream>
+#include <utility>
 
+#include "cmArgumentParser.h"
 #include "cmExportBuildAndroidMKGenerator.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExportSetMap.h"
@@ -13,10 +16,12 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
+class cmExportSet;
 class cmExecutionStatus;
 
 #if defined(__HAIKU__)
@@ -24,19 +29,6 @@
 #  include <StorageDefs.h>
 #endif
 
-cmExportCommand::cmExportCommand()
-  : Targets(&Helper, "TARGETS")
-  , Append(&Helper, "APPEND", &ArgumentGroup)
-  , ExportSetName(&Helper, "EXPORT", &ArgumentGroup)
-  , Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
-  , Filename(&Helper, "FILE", &ArgumentGroup)
-  , ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup)
-  , AndroidMKFile(&Helper, "ANDROID_MK")
-{
-  this->ExportSet = nullptr;
-}
-
-// cmExportCommand
 bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
                                   cmExecutionStatus&)
 {
@@ -48,45 +40,62 @@
   if (args[0] == "PACKAGE") {
     return this->HandlePackage(args);
   }
+
+  struct Arguments
+  {
+    std::string ExportSetName;
+    std::vector<std::string> Targets;
+    std::string Namespace;
+    std::string Filename;
+    std::string AndroidMKFile;
+    bool Append = false;
+    bool ExportOld = false;
+  };
+
+  auto parser = cmArgumentParser<Arguments>{}
+                  .Bind("NAMESPACE"_s, &Arguments::Namespace)
+                  .Bind("FILE"_s, &Arguments::Filename);
+
   if (args[0] == "EXPORT") {
-    this->ExportSetName.Follows(nullptr);
-    this->ArgumentGroup.Follows(&this->ExportSetName);
+    parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
   } else {
-    this->Targets.Follows(nullptr);
-    this->ArgumentGroup.Follows(&this->Targets);
+    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);
   }
 
   std::vector<std::string> unknownArgs;
-  this->Helper.Parse(&args, &unknownArgs);
+  Arguments const arguments = parser.Parse(args, &unknownArgs);
 
   if (!unknownArgs.empty()) {
-    this->SetError("Unknown arguments.");
+    this->SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
     return false;
   }
 
   std::string fname;
   bool android = false;
-  if (this->AndroidMKFile.WasFound()) {
-    fname = this->AndroidMKFile.GetString();
+  if (!arguments.AndroidMKFile.empty()) {
+    fname = arguments.AndroidMKFile;
     android = true;
   }
-  if (!this->Filename.WasFound() && fname.empty()) {
+  if (arguments.Filename.empty() && fname.empty()) {
     if (args[0] != "EXPORT") {
       this->SetError("FILE <filename> option missing.");
       return false;
     }
-    fname = this->ExportSetName.GetString() + ".cmake";
+    fname = arguments.ExportSetName + ".cmake";
   } else if (fname.empty()) {
     // Make sure the file has a .cmake extension.
-    if (cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString()) !=
+    if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
         ".cmake") {
       std::ostringstream e;
-      e << "FILE option given filename \"" << this->Filename.GetString()
+      e << "FILE option given filename \"" << arguments.Filename
         << "\" which does not have an extension of \".cmake\".\n";
       this->SetError(e.str());
       return false;
     }
-    fname = this->Filename.GetString();
+    fname = arguments.Filename;
   }
 
   // Get the file to write.
@@ -108,33 +117,19 @@
 
   cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
 
+  cmExportSet* ExportSet = nullptr;
   if (args[0] == "EXPORT") {
-    if (this->Append.IsEnabled()) {
-      std::ostringstream e;
-      e << "EXPORT signature does not recognise the APPEND option.";
-      this->SetError(e.str());
-      return false;
-    }
-
-    if (this->ExportOld.IsEnabled()) {
-      std::ostringstream e;
-      e << "EXPORT signature does not recognise the "
-           "EXPORT_LINK_INTERFACE_LIBRARIES option.";
-      this->SetError(e.str());
-      return false;
-    }
-
     cmExportSetMap& setMap = gg->GetExportSets();
-    std::string setName = this->ExportSetName.GetString();
-    if (setMap.find(setName) == setMap.end()) {
+    auto const it = setMap.find(arguments.ExportSetName);
+    if (it == setMap.end()) {
       std::ostringstream e;
-      e << "Export set \"" << setName << "\" not found.";
+      e << "Export set \"" << arguments.ExportSetName << "\" not found.";
       this->SetError(e.str());
       return false;
     }
-    this->ExportSet = setMap[setName];
-  } else if (this->Targets.WasFound()) {
-    for (std::string const& currentTarget : this->Targets.GetVector()) {
+    ExportSet = it->second;
+  } else if (!arguments.Targets.empty()) {
+    for (std::string const& currentTarget : arguments.Targets) {
       if (this->Makefile->IsAlias(currentTarget)) {
         std::ostringstream e;
         e << "given ALIAS target \"" << currentTarget
@@ -158,7 +153,7 @@
       }
       targets.push_back(currentTarget);
     }
-    if (this->Append.IsEnabled()) {
+    if (arguments.Append) {
       if (cmExportBuildFileGenerator* ebfg =
             gg->GetExportedTargetsFile(fname)) {
         ebfg->AppendTargets(targets);
@@ -178,15 +173,15 @@
     ebfg = new cmExportBuildFileGenerator;
   }
   ebfg->SetExportFile(fname.c_str());
-  ebfg->SetNamespace(this->Namespace.GetCString());
-  ebfg->SetAppendMode(this->Append.IsEnabled());
-  if (this->ExportSet) {
-    ebfg->SetExportSet(this->ExportSet);
+  ebfg->SetNamespace(arguments.Namespace);
+  ebfg->SetAppendMode(arguments.Append);
+  if (ExportSet != nullptr) {
+    ebfg->SetExportSet(ExportSet);
   } else {
     ebfg->SetTargets(targets);
   }
   this->Makefile->AddExportBuildFileGenerator(ebfg);
-  ebfg->SetExportOld(this->ExportOld.IsEnabled());
+  ebfg->SetExportOld(arguments.ExportOld);
 
   // Compute the set of configurations exported.
   std::vector<std::string> configurationTypes;
@@ -197,7 +192,7 @@
   for (std::string const& ct : configurationTypes) {
     ebfg->AddConfiguration(ct);
   }
-  if (this->ExportSet) {
+  if (ExportSet != nullptr) {
     gg->AddBuildExportExportSet(ebfg);
   } else {
     gg->AddBuildExportSet(ebfg);
@@ -243,10 +238,23 @@
     return false;
   }
 
-  // If the CMAKE_EXPORT_NO_PACKAGE_REGISTRY variable is set the command
-  // export(PACKAGE) does nothing.
-  if (this->Makefile->IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
-    return true;
+  // CMP0090 decides both the default and what variable changes it.
+  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0090)) {
+    case cmPolicies::WARN:
+    case cmPolicies::OLD:
+      // Default is to export, but can be disabled.
+      if (this->Makefile->IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
+        return true;
+      }
+      break;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      // Default is to not export, but can be enabled.
+      if (!this->Makefile->IsOn("CMAKE_EXPORT_PACKAGE_REGISTRY")) {
+        return true;
+      }
+      break;
   }
 
   // We store the current build directory in the registry as a value
diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h
index a5c6751..99f9932 100644
--- a/Source/cmExportCommand.h
+++ b/Source/cmExportCommand.h
@@ -9,21 +9,12 @@
 #include <vector>
 
 #include "cmCommand.h"
-#include "cmCommandArgumentsHelper.h"
 
 class cmExecutionStatus;
-class cmExportSet;
 
-/** \class cmExportLibraryDependenciesCommand
- * \brief Add a test to the lists of tests to run.
- *
- * cmExportLibraryDependenciesCommand adds a test to the list of tests to run
- *
- */
 class cmExportCommand : public cmCommand
 {
 public:
-  cmExportCommand();
   /**
    * This is a virtual constructor for the command.
    */
@@ -37,21 +28,6 @@
                    cmExecutionStatus& status) override;
 
 private:
-  cmCommandArgumentsHelper Helper;
-  cmCommandArgumentGroup ArgumentGroup;
-  cmCAStringVector Targets;
-  cmCAEnabler Append;
-  cmCAString ExportSetName;
-  cmCAString Namespace;
-  cmCAString Filename;
-  cmCAEnabler ExportOld;
-  cmCAString AndroidMKFile;
-
-  cmExportSet* ExportSet;
-
-  friend class cmExportBuildFileGenerator;
-  std::string ErrorMessage;
-
   bool HandlePackage(std::vector<std::string> const& args);
   void StorePackageRegistryWin(std::string const& package, const char* content,
                                const char* hash);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index c8f743a..a12e0c4 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -70,8 +70,9 @@
   std::unique_ptr<cmsys::ofstream> foutPtr;
   if (this->AppendMode) {
     // Open for append.
+    auto openmodeApp = std::ios::app;
     foutPtr = cm::make_unique<cmsys::ofstream>(this->MainImportFile.c_str(),
-                                               std::ios::app);
+                                               openmodeApp);
   } else {
     // Generate atomically and with copy-if-different.
     std::unique_ptr<cmGeneratedFileStream> ap(
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
index b4b2962..0a0646c 100644
--- a/Source/cmExportLibraryDependenciesCommand.cxx
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -50,8 +50,9 @@
   // Use copy-if-different if not appending.
   std::unique_ptr<cmsys::ofstream> foutPtr;
   if (this->Append) {
+    const auto openmodeApp = std::ios::app;
     foutPtr =
-      cm::make_unique<cmsys::ofstream>(this->Filename.c_str(), std::ios::app);
+      cm::make_unique<cmsys::ofstream>(this->Filename.c_str(), openmodeApp);
   } else {
     std::unique_ptr<cmGeneratedFileStream> ap(
       new cmGeneratedFileStream(this->Filename, true));
@@ -61,7 +62,7 @@
   std::ostream& fout = *foutPtr;
 
   if (!fout) {
-    cmSystemTools::Error("Error Writing ", this->Filename.c_str());
+    cmSystemTools::Error("Error Writing " + this->Filename);
     cmSystemTools::ReportLastSystemError("");
     return;
   }
diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h
index 0ef306f..d654c12 100644
--- a/Source/cmExportSet.h
+++ b/Source/cmExportSet.h
@@ -25,6 +25,9 @@
   /// Destructor
   ~cmExportSet();
 
+  cmExportSet(const cmExportSet&) = delete;
+  cmExportSet& operator=(const cmExportSet&) = delete;
+
   void Compute(cmLocalGenerator* lg);
 
   void AddTargetExport(cmTargetExport* tgt);
diff --git a/Source/cmExportSetMap.cxx b/Source/cmExportSetMap.cxx
index 0740828..293e80c 100644
--- a/Source/cmExportSetMap.cxx
+++ b/Source/cmExportSetMap.cxx
@@ -23,6 +23,8 @@
   this->derived::clear();
 }
 
+cmExportSetMap::cmExportSetMap() = default;
+
 cmExportSetMap::~cmExportSetMap()
 {
   this->clear();
diff --git a/Source/cmExportSetMap.h b/Source/cmExportSetMap.h
index 0f71c79..3853732 100644
--- a/Source/cmExportSetMap.h
+++ b/Source/cmExportSetMap.h
@@ -25,8 +25,13 @@
 
   void clear();
 
+  cmExportSetMap();
+
   /// Overloaded destructor deletes all member export sets.
   ~cmExportSetMap();
+
+  cmExportSetMap(const cmExportSetMap&) = delete;
+  cmExportSetMap& operator=(const cmExportSetMap&) = delete;
 };
 
 #endif
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
index 4438f28..a472a06 100644
--- a/Source/cmExternalMakefileProjectGenerator.h
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -31,13 +31,13 @@
   virtual void EnableLanguage(std::vector<std::string> const& languages,
                               cmMakefile*, bool optional);
 
-  ///! set the global generator which will generate the makefiles
+  //! set the global generator which will generate the makefiles
   virtual void SetGlobalGenerator(cmGlobalGenerator* generator)
   {
     this->GlobalGenerator = generator;
   }
 
-  ///! Return the list of global generators supported by this extra generator
+  //! Return the list of global generators supported by this extra generator
   const std::vector<std::string>& GetSupportedGlobalGenerators() const
   {
     return this->SupportedGlobalGenerators;
@@ -49,7 +49,7 @@
   static std::string CreateFullGeneratorName(
     const std::string& globalGenerator, const std::string& extraGenerator);
 
-  ///! Generate the project files, the Makefiles have already been generated
+  //! Generate the project files, the Makefiles have already been generated
   virtual void Generate() = 0;
 
   void SetName(const std::string& n) { Name = n; }
@@ -59,9 +59,9 @@
                     bool dryRun);
 
 protected:
-  ///! Contains the names of the global generators support by this generator.
+  //! Contains the names of the global generators support by this generator.
   std::vector<std::string> SupportedGlobalGenerators;
-  ///! the global generator which creates the makefiles
+  //! the global generator which creates the makefiles
   const cmGlobalGenerator* GlobalGenerator = nullptr;
 
   std::string Name;
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index e408de3..93ff8f4 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -13,6 +13,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
@@ -247,8 +248,8 @@
 
   // figure out the compiler
   std::string compiler = this->GetCBCompilerId(mf);
-  std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
-  const std::string makeArgs =
+  const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& makeArgs =
     mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
 
   cmXMLWriter xml(fout);
@@ -589,10 +590,9 @@
     std::vector<std::string>::const_iterator end =
       cmRemoveDuplicates(allIncludeDirs);
 
-    for (std::vector<std::string>::const_iterator i = allIncludeDirs.begin();
-         i != end; ++i) {
+    for (std::string const& str : cmMakeRange(allIncludeDirs.cbegin(), end)) {
       xml.StartElement("Add");
-      xml.Attribute("directory", *i);
+      xml.Attribute("directory", str);
       xml.EndElement();
     }
 
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index 0773edc..6fe8c14 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -628,8 +628,8 @@
 std::string cmExtraCodeLiteGenerator::GetBuildCommand(
   const cmMakefile* mf, const std::string& targetName) const
 {
-  std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
-  std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+  const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
   std::string buildCommand = make; // Default
   std::ostringstream ss;
   if (generator == "NMake Makefiles" || generator == "Ninja") {
@@ -669,8 +669,8 @@
   const cmMakefile* mf) const
 {
   std::string buildCommand;
-  std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
-  std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+  const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
   if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") {
     std::ostringstream ss;
 #if defined(_WIN32)
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index e05f74b..aece3bc 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -881,8 +881,8 @@
   xml.Attribute("moduleId", "org.eclipse.cdt.make.core.buildtargets");
   xml.StartElement("buildTargets");
   emmited.clear();
-  const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
-  const std::string makeArgs =
+  const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& makeArgs =
     mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS");
 
   cmGlobalGenerator* generator =
@@ -1079,7 +1079,8 @@
   cmXMLWriter& xml, const cmMakefile& makefile)
 {
   // we need the "make" and the C (or C++) compiler which are used, Alex
-  std::string make = makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& make =
+    makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
   std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
   std::string arg1 = makefile.GetSafeDefinition("CMAKE_C_COMPILER_ARG1");
   if (compiler.empty()) {
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index 23ba6b7..877f109 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -75,8 +75,8 @@
                                         cmGeneratedFileStream& fout) const
 {
   cmMakefile const* mf = lg->GetMakefile();
-  const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
-  const std::string makeArgs =
+  const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& makeArgs =
     mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
   std::string const& homeOutputDir = lg->GetBinaryDirectory();
 
@@ -196,7 +196,7 @@
 {
   static char JsonSep = ' ';
 
-  fout << "\t\t\t" << JsonSep << "{\"name\":\"" << target
+  fout << "\t\t\t" << JsonSep << R"({"name":")" << target
        << "\", "
           "\"build_cmd\":\""
        << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path)
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 739a177..71c8fcd 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -168,7 +168,7 @@
   const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
   cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
 {
-  std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
   std::string compiler;
   if (!lgs.empty()) {
     this->AppendTarget(fout, "all", lgs[0], nullptr, make.c_str(), mf,
@@ -263,7 +263,7 @@
       // Regular expression to extract compiler flags from a string
       // https://gist.github.com/3944250
       const char* regexString =
-        "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
+        R"((^|[ ])-[DIOUWfgs][^= ]+(=\"[^"]+\"|=[^"][^ ]+)?)";
       flagRegex.compile(regexString);
       std::string workString =
         flagsString + " " + definesString + " " + includesString;
@@ -315,12 +315,12 @@
   std::string generator = this->GlobalGenerator->GetName();
   if (generator == "NMake Makefiles") {
     std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
-    command += ", \"/NOLOGO\", \"/f\", \"";
+    command += R"(, "/NOLOGO", "/f", ")";
     command += makefileName + "\"";
     command += ", \"" + target + "\"";
   } else if (generator == "Ninja") {
     std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
-    command += ", \"-f\", \"";
+    command += R"(, "-f", ")";
     command += makefileName + "\"";
     command += ", \"" + target + "\"";
   } else {
@@ -332,7 +332,7 @@
     } else {
       makefileName = cmSystemTools::ConvertToOutputPath(makefile);
     }
-    command += ", \"-f\", \"";
+    command += R"(, "-f", ")";
     command += makefileName + "\"";
     command += ", \"" + target + "\"";
   }
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index 4b14d26..89629c7 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -6,6 +6,7 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
 
@@ -40,18 +41,17 @@
     this->Makefile->AddIncludeDirectories(outputDirectories);
   }
 
-  for (std::vector<std::string>::const_iterator i = (args.begin() + 1);
-       i != args.end(); i++) {
-    cmSourceFile* curr = this->Makefile->GetSource(*i);
+  for (std::string const& arg : cmMakeRange(args).advance(1)) {
+    cmSourceFile* curr = this->Makefile->GetSource(arg);
     // if we should use the source GUI
     // to generate .cxx and .h files
     if (!curr || !curr->GetPropertyAsBool("WRAP_EXCLUDE")) {
       std::string outName = outputDirectory;
       outName += "/";
-      outName += cmSystemTools::GetFilenameWithoutExtension(*i);
+      outName += cmSystemTools::GetFilenameWithoutExtension(arg);
       std::string hname = outName;
       hname += ".h";
-      std::string origname = cdir + "/" + *i;
+      std::string origname = cdir + "/" + arg;
       // add starting depends
       std::vector<std::string> depends;
       depends.push_back(origname);
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 0f911c1..f5ec9fe 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3,7 +3,7 @@
 #include "cmFileCommand.h"
 
 #include "cm_kwiml.h"
-#include "cmsys/Directory.hxx"
+#include "cm_static_string_view.hxx"
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
@@ -16,24 +16,23 @@
 #include <sstream>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <utility>
 #include <vector>
 
 #include "cmAlgorithms.h"
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
 #include "cmCryptoHash.h"
-#include "cmFSPermissions.h"
+#include "cmFileCopier.h"
+#include "cmFileInstaller.h"
 #include "cmFileLockPool.h"
-#include "cmFileTimeComparison.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
 #include "cmHexFileConverter.h"
-#include "cmInstallType.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
 #include "cm_sys_stat.h"
@@ -55,8 +54,6 @@
 
 class cmSystemToolsFileTime;
 
-using namespace cmFSPermissions;
-
 #if defined(_WIN32)
 // libcurl doesn't support file:// urls for unicode filenames on Windows.
 // Convert string from UTF-8 to ACP if this is a file:// URL.
@@ -223,7 +220,7 @@
   bool writable = false;
 
   // Set permissions to writable
-  if (cmSystemTools::GetPermissions(fileName.c_str(), mode)) {
+  if (cmSystemTools::GetPermissions(fileName, mode)) {
 #if defined(_MSC_VER) || defined(__MINGW32__)
     writable = (mode & S_IWRITE) != 0;
     mode_t newMode = mode | S_IWRITE;
@@ -232,7 +229,7 @@
     mode_t newMode = mode | S_IWUSR | S_IWGRP;
 #endif
     if (!writable) {
-      cmSystemTools::SetPermissions(fileName.c_str(), newMode);
+      cmSystemTools::SetPermissions(fileName, newMode);
     }
   }
   // If GetPermissions fails, pretend like it is ok. File open will fail if
@@ -259,7 +256,7 @@
   }
   file.close();
   if (mode && !writable) {
-    cmSystemTools::SetPermissions(fileName.c_str(), mode);
+    cmSystemTools::SetPermissions(fileName, mode);
   }
   return true;
 }
@@ -272,36 +269,34 @@
     return false;
   }
 
-  cmCommandArgumentsHelper argHelper;
-  cmCommandArgumentGroup group;
+  std::string const& fileNameArg = args[1];
+  std::string const& variable = args[2];
 
-  cmCAString readArg(&argHelper, "READ");
-  cmCAString fileNameArg(&argHelper, nullptr);
-  cmCAString resultArg(&argHelper, nullptr);
+  struct Arguments
+  {
+    std::string Offset;
+    std::string Limit;
+    bool Hex = false;
+  };
 
-  cmCAString offsetArg(&argHelper, "OFFSET", &group);
-  cmCAString limitArg(&argHelper, "LIMIT", &group);
-  cmCAEnabler hexOutputArg(&argHelper, "HEX", &group);
-  readArg.Follows(nullptr);
-  fileNameArg.Follows(&readArg);
-  resultArg.Follows(&fileNameArg);
-  group.Follows(&resultArg);
-  argHelper.Parse(&args, nullptr);
+  static auto const parser = cmArgumentParser<Arguments>{}
+                               .Bind("OFFSET"_s, &Arguments::Offset)
+                               .Bind("LIMIT"_s, &Arguments::Limit)
+                               .Bind("HEX"_s, &Arguments::Hex);
 
-  std::string fileName = fileNameArg.GetString();
+  Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
+
+  std::string fileName = fileNameArg;
   if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
     fileName = this->Makefile->GetCurrentSourceDirectory();
-    fileName += "/" + fileNameArg.GetString();
+    fileName += "/" + fileNameArg;
   }
 
-  std::string variable = resultArg.GetString();
-
 // Open the specified file.
 #if defined(_WIN32) || defined(__CYGWIN__)
-  cmsys::ifstream file(
-    fileName.c_str(),
-    std::ios::in |
-      (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
+  cmsys::ifstream file(fileName.c_str(),
+                       arguments.Hex ? (std::ios::binary | std::ios::in)
+                                     : std::ios::in);
 #else
   cmsys::ifstream file(fileName.c_str());
 #endif
@@ -317,21 +312,21 @@
 
   // is there a limit?
   long sizeLimit = -1;
-  if (!limitArg.GetString().empty()) {
-    sizeLimit = atoi(limitArg.GetCString());
+  if (!arguments.Limit.empty()) {
+    sizeLimit = atoi(arguments.Limit.c_str());
   }
 
   // is there an offset?
   long offset = 0;
-  if (!offsetArg.GetString().empty()) {
-    offset = atoi(offsetArg.GetCString());
+  if (!arguments.Offset.empty()) {
+    offset = atoi(arguments.Offset.c_str());
   }
 
   file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
 
   std::string output;
 
-  if (hexOutputArg.IsEnabled()) {
+  if (arguments.Hex) {
     // Convert part of the file into hex code
     char c;
     while ((sizeLimit != 0) && (file.get(c))) {
@@ -393,7 +388,7 @@
 #else
   std::ostringstream e;
   e << args[0] << " not available during bootstrap";
-  this->SetError(e.str().c_str());
+  this->SetError(e.str());
   return false;
 #endif
 }
@@ -523,7 +518,7 @@
       maxlen = len;
       arg_mode = arg_none;
     } else if (arg_mode == arg_regex) {
-      if (!regex.compile(args[i].c_str())) {
+      if (!regex.compile(args[i])) {
         std::ostringstream e;
         e << "STRINGS option REGEX value \"" << args[i]
           << "\" could not be compiled.";
@@ -947,16 +942,14 @@
   // File command has at least one argument
   assert(args.size() > 1);
 
-  std::vector<std::string>::const_iterator i = args.begin();
-
-  i++; // Get rid of subcommand
-
   std::string expr;
-  for (; i != args.end(); ++i) {
-    const std::string* cdir = &(*i);
-    if (!cmsys::SystemTools::FileIsFullPath(*i)) {
+  for (std::string const& arg :
+       cmMakeRange(args).advance(1)) // Get rid of subcommand
+  {
+    const std::string* cdir = &arg;
+    if (!cmsys::SystemTools::FileIsFullPath(arg)) {
       expr = this->Makefile->GetCurrentSourceDirectory();
-      expr += "/" + *i;
+      expr += "/" + arg;
       cdir = &expr;
     }
     if (!this->Makefile->CanIWriteThisFile(*cdir)) {
@@ -981,15 +974,13 @@
   // File command has at least one argument
   assert(args.size() > 1);
 
-  std::vector<std::string>::const_iterator i = args.begin();
-
-  i++; // Get rid of subcommand
-
-  for (; i != args.end(); ++i) {
-    std::string tfile = *i;
+  for (std::string const& arg :
+       cmMakeRange(args).advance(1)) // Get rid of subcommand
+  {
+    std::string tfile = arg;
     if (!cmsys::SystemTools::FileIsFullPath(tfile)) {
       tfile = this->Makefile->GetCurrentSourceDirectory();
-      tfile += "/" + *i;
+      tfile += "/" + arg;
     }
     if (!this->Makefile->CanIWriteThisFile(tfile)) {
       std::string e =
@@ -1061,1088 +1052,17 @@
   return true;
 }
 
-// File installation helper class.
-struct cmFileCopier
-{
-  cmFileCopier(cmFileCommand* command, const char* name = "COPY")
-    : FileCommand(command)
-    , Makefile(command->GetMakefile())
-    , Name(name)
-    , Always(false)
-    , MatchlessFiles(true)
-    , FilePermissions(0)
-    , DirPermissions(0)
-    , CurrentMatchRule(nullptr)
-    , UseGivenPermissionsFile(false)
-    , UseGivenPermissionsDir(false)
-    , UseSourcePermissions(true)
-    , Doing(DoingNone)
-  {
-  }
-  virtual ~cmFileCopier() = default;
-
-  bool Run(std::vector<std::string> const& args);
-
-protected:
-  cmFileCommand* FileCommand;
-  cmMakefile* Makefile;
-  const char* Name;
-  bool Always;
-  cmFileTimeComparison FileTimes;
-
-  // Whether to install a file not matching any expression.
-  bool MatchlessFiles;
-
-  // Permissions for files and directories installed by this object.
-  mode_t FilePermissions;
-  mode_t DirPermissions;
-
-  // Properties set by pattern and regex match rules.
-  struct MatchProperties
-  {
-    bool Exclude = false;
-    mode_t Permissions = 0;
-  };
-  struct MatchRule
-  {
-    cmsys::RegularExpression Regex;
-    MatchProperties Properties;
-    std::string RegexString;
-    MatchRule(std::string const& regex)
-      : Regex(regex.c_str())
-      , RegexString(regex)
-    {
-    }
-  };
-  std::vector<MatchRule> MatchRules;
-
-  // Get the properties from rules matching this input file.
-  MatchProperties CollectMatchProperties(const char* file)
-  {
-// Match rules are case-insensitive on some platforms.
-#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
-    std::string lower = cmSystemTools::LowerCase(file);
-    const char* file_to_match = lower.c_str();
-#else
-    const char* file_to_match = file;
-#endif
-
-    // Collect properties from all matching rules.
-    bool matched = false;
-    MatchProperties result;
-    for (MatchRule& mr : this->MatchRules) {
-      if (mr.Regex.find(file_to_match)) {
-        matched = true;
-        result.Exclude |= mr.Properties.Exclude;
-        result.Permissions |= mr.Properties.Permissions;
-      }
-    }
-    if (!matched && !this->MatchlessFiles) {
-      result.Exclude = !cmSystemTools::FileIsDirectory(file);
-    }
-    return result;
-  }
-
-  bool SetPermissions(const char* toFile, mode_t permissions)
-  {
-    if (permissions) {
-#ifdef WIN32
-      if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
-        // Store the mode in an NTFS alternate stream.
-        std::string mode_t_adt_filename =
-          std::string(toFile) + ":cmake_mode_t";
-
-        // Writing to an NTFS alternate stream changes the modification
-        // time, so we need to save and restore its original value.
-        cmSystemToolsFileTime* file_time_orig = cmSystemTools::FileTimeNew();
-        cmSystemTools::FileTimeGet(toFile, file_time_orig);
-
-        cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
-
-        if (permissionStream) {
-          permissionStream << std::oct << permissions << std::endl;
-        }
-
-        permissionStream.close();
-
-        cmSystemTools::FileTimeSet(toFile, file_time_orig);
-
-        cmSystemTools::FileTimeDelete(file_time_orig);
-      }
-#endif
-
-      if (!cmSystemTools::SetPermissions(toFile, permissions)) {
-        std::ostringstream e;
-        e << this->Name << " cannot set permissions on \"" << toFile << "\"";
-        this->FileCommand->SetError(e.str());
-        return false;
-      }
-    }
-    return true;
-  }
-
-  // Translate an argument to a permissions bit.
-  bool CheckPermissions(std::string const& arg, mode_t& permissions)
-  {
-    if (!cmFSPermissions::stringToModeT(arg, permissions)) {
-      std::ostringstream e;
-      e << this->Name << " given invalid permission \"" << arg << "\".";
-      this->FileCommand->SetError(e.str());
-      return false;
-    }
-    return true;
-  }
-
-  bool InstallSymlink(const char* fromFile, const char* toFile);
-  bool InstallFile(const char* fromFile, const char* toFile,
-                   MatchProperties match_properties);
-  bool InstallDirectory(const char* source, const char* destination,
-                        MatchProperties match_properties);
-  virtual bool Install(const char* fromFile, const char* toFile);
-  virtual std::string const& ToName(std::string const& fromName)
-  {
-    return fromName;
-  }
-
-  enum Type
-  {
-    TypeFile,
-    TypeDir,
-    TypeLink
-  };
-  virtual void ReportCopy(const char*, Type, bool) {}
-  virtual bool ReportMissing(const char* fromFile)
-  {
-    // The input file does not exist and installation is not optional.
-    std::ostringstream e;
-    e << this->Name << " cannot find \"" << fromFile << "\".";
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-
-  MatchRule* CurrentMatchRule;
-  bool UseGivenPermissionsFile;
-  bool UseGivenPermissionsDir;
-  bool UseSourcePermissions;
-  std::string Destination;
-  std::string FilesFromDir;
-  std::vector<std::string> Files;
-  int Doing;
-
-  virtual bool Parse(std::vector<std::string> const& args);
-  enum
-  {
-    DoingNone,
-    DoingError,
-    DoingDestination,
-    DoingFilesFromDir,
-    DoingFiles,
-    DoingPattern,
-    DoingRegex,
-    DoingPermissionsFile,
-    DoingPermissionsDir,
-    DoingPermissionsMatch,
-    DoingLast1
-  };
-  virtual bool CheckKeyword(std::string const& arg);
-  virtual bool CheckValue(std::string const& arg);
-
-  void NotBeforeMatch(std::string const& arg)
-  {
-    std::ostringstream e;
-    e << "option " << arg << " may not appear before PATTERN or REGEX.";
-    this->FileCommand->SetError(e.str());
-    this->Doing = DoingError;
-  }
-  void NotAfterMatch(std::string const& arg)
-  {
-    std::ostringstream e;
-    e << "option " << arg << " may not appear after PATTERN or REGEX.";
-    this->FileCommand->SetError(e.str());
-    this->Doing = DoingError;
-  }
-  virtual void DefaultFilePermissions()
-  {
-    // Use read/write permissions.
-    this->FilePermissions = 0;
-    this->FilePermissions |= mode_owner_read;
-    this->FilePermissions |= mode_owner_write;
-    this->FilePermissions |= mode_group_read;
-    this->FilePermissions |= mode_world_read;
-  }
-  virtual void DefaultDirectoryPermissions()
-  {
-    // Use read/write/executable permissions.
-    this->DirPermissions = 0;
-    this->DirPermissions |= mode_owner_read;
-    this->DirPermissions |= mode_owner_write;
-    this->DirPermissions |= mode_owner_execute;
-    this->DirPermissions |= mode_group_read;
-    this->DirPermissions |= mode_group_execute;
-    this->DirPermissions |= mode_world_read;
-    this->DirPermissions |= mode_world_execute;
-  }
-
-  bool GetDefaultDirectoryPermissions(mode_t** mode)
-  {
-    // check if default dir creation permissions were set
-    const char* default_dir_install_permissions =
-      this->Makefile->GetDefinition(
-        "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
-    if (default_dir_install_permissions && *default_dir_install_permissions) {
-      std::vector<std::string> items;
-      cmSystemTools::ExpandListArgument(default_dir_install_permissions,
-                                        items);
-      for (const auto& arg : items) {
-        if (!this->CheckPermissions(arg, **mode)) {
-          std::ostringstream e;
-          e << this->FileCommand->GetError()
-            << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
-               "variable.";
-          this->FileCommand->SetError(e.str());
-          return false;
-        }
-      }
-    } else {
-      *mode = nullptr;
-    }
-
-    return true;
-  }
-};
-
-bool cmFileCopier::Parse(std::vector<std::string> const& args)
-{
-  this->Doing = DoingFiles;
-  for (unsigned int i = 1; i < args.size(); ++i) {
-    // Check this argument.
-    if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
-      std::ostringstream e;
-      e << "called with unknown argument \"" << args[i] << "\".";
-      this->FileCommand->SetError(e.str());
-      return false;
-    }
-
-    // Quit if an argument is invalid.
-    if (this->Doing == DoingError) {
-      return false;
-    }
-  }
-
-  // Require a destination.
-  if (this->Destination.empty()) {
-    std::ostringstream e;
-    e << this->Name << " given no DESTINATION";
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-
-  // If file permissions were not specified set default permissions.
-  if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
-    this->DefaultFilePermissions();
-  }
-
-  // If directory permissions were not specified set default permissions.
-  if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
-    this->DefaultDirectoryPermissions();
-  }
-
-  return true;
-}
-
-bool cmFileCopier::CheckKeyword(std::string const& arg)
-{
-  if (arg == "DESTINATION") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingDestination;
-    }
-  } else if (arg == "FILES_FROM_DIR") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingFilesFromDir;
-    }
-  } else if (arg == "PATTERN") {
-    this->Doing = DoingPattern;
-  } else if (arg == "REGEX") {
-    this->Doing = DoingRegex;
-  } else if (arg == "EXCLUDE") {
-    // Add this property to the current match rule.
-    if (this->CurrentMatchRule) {
-      this->CurrentMatchRule->Properties.Exclude = true;
-      this->Doing = DoingNone;
-    } else {
-      this->NotBeforeMatch(arg);
-    }
-  } else if (arg == "PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->Doing = DoingPermissionsMatch;
-    } else {
-      this->NotBeforeMatch(arg);
-    }
-  } else if (arg == "FILE_PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingPermissionsFile;
-      this->UseGivenPermissionsFile = true;
-    }
-  } else if (arg == "DIRECTORY_PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingPermissionsDir;
-      this->UseGivenPermissionsDir = true;
-    }
-  } else if (arg == "USE_SOURCE_PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->UseSourcePermissions = true;
-    }
-  } else if (arg == "NO_SOURCE_PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->UseSourcePermissions = false;
-    }
-  } else if (arg == "FILES_MATCHING") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->MatchlessFiles = false;
-    }
-  } else {
-    return false;
-  }
-  return true;
-}
-
-bool cmFileCopier::CheckValue(std::string const& arg)
-{
-  switch (this->Doing) {
-    case DoingFiles:
-      this->Files.push_back(arg);
-      break;
-    case DoingDestination:
-      if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
-        this->Destination = arg;
-      } else {
-        this->Destination = this->Makefile->GetCurrentBinaryDirectory();
-        this->Destination += "/" + arg;
-      }
-      this->Doing = DoingNone;
-      break;
-    case DoingFilesFromDir:
-      if (cmSystemTools::FileIsFullPath(arg)) {
-        this->FilesFromDir = arg;
-      } else {
-        this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
-        this->FilesFromDir += "/" + arg;
-      }
-      cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
-      this->Doing = DoingNone;
-      break;
-    case DoingPattern: {
-      // Convert the pattern to a regular expression.  Require a
-      // leading slash and trailing end-of-string in the matched
-      // string to make sure the pattern matches only whole file
-      // names.
-      std::string regex = "/";
-      regex += cmsys::Glob::PatternToRegex(arg, false);
-      regex += "$";
-      this->MatchRules.emplace_back(regex);
-      this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
-      if (this->CurrentMatchRule->Regex.is_valid()) {
-        this->Doing = DoingNone;
-      } else {
-        std::ostringstream e;
-        e << "could not compile PATTERN \"" << arg << "\".";
-        this->FileCommand->SetError(e.str());
-        this->Doing = DoingError;
-      }
-    } break;
-    case DoingRegex:
-      this->MatchRules.emplace_back(arg);
-      this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
-      if (this->CurrentMatchRule->Regex.is_valid()) {
-        this->Doing = DoingNone;
-      } else {
-        std::ostringstream e;
-        e << "could not compile REGEX \"" << arg << "\".";
-        this->FileCommand->SetError(e.str());
-        this->Doing = DoingError;
-      }
-      break;
-    case DoingPermissionsFile:
-      if (!this->CheckPermissions(arg, this->FilePermissions)) {
-        this->Doing = DoingError;
-      }
-      break;
-    case DoingPermissionsDir:
-      if (!this->CheckPermissions(arg, this->DirPermissions)) {
-        this->Doing = DoingError;
-      }
-      break;
-    case DoingPermissionsMatch:
-      if (!this->CheckPermissions(
-            arg, this->CurrentMatchRule->Properties.Permissions)) {
-        this->Doing = DoingError;
-      }
-      break;
-    default:
-      return false;
-  }
-  return true;
-}
-
-bool cmFileCopier::Run(std::vector<std::string> const& args)
-{
-  if (!this->Parse(args)) {
-    return false;
-  }
-
-  for (std::string const& f : this->Files) {
-    std::string file;
-    if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
-      if (!this->FilesFromDir.empty()) {
-        file = this->FilesFromDir;
-      } else {
-        file = this->Makefile->GetCurrentSourceDirectory();
-      }
-      file += "/";
-      file += f;
-    } else if (!this->FilesFromDir.empty()) {
-      this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
-                                  "to be specified as relative paths.");
-      return false;
-    } else {
-      file = f;
-    }
-
-    // Split the input file into its directory and name components.
-    std::vector<std::string> fromPathComponents;
-    cmSystemTools::SplitPath(file, fromPathComponents);
-    std::string fromName = *(fromPathComponents.end() - 1);
-    std::string fromDir = cmSystemTools::JoinPath(
-      fromPathComponents.begin(), fromPathComponents.end() - 1);
-
-    // Compute the full path to the destination file.
-    std::string toFile = this->Destination;
-    if (!this->FilesFromDir.empty()) {
-      std::string dir = cmSystemTools::GetFilenamePath(f);
-      if (!dir.empty()) {
-        toFile += "/";
-        toFile += dir;
-      }
-    }
-    std::string const& toName = this->ToName(fromName);
-    if (!toName.empty()) {
-      toFile += "/";
-      toFile += toName;
-    }
-
-    // Construct the full path to the source file.  The file name may
-    // have been changed above.
-    std::string fromFile = fromDir;
-    if (!fromName.empty()) {
-      fromFile += "/";
-      fromFile += fromName;
-    }
-
-    if (!this->Install(fromFile.c_str(), toFile.c_str())) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool cmFileCopier::Install(const char* fromFile, const char* toFile)
-{
-  if (!*fromFile) {
-    std::ostringstream e;
-    e << "INSTALL encountered an empty string input file name.";
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-
-  // Collect any properties matching this file name.
-  MatchProperties match_properties = this->CollectMatchProperties(fromFile);
-
-  // Skip the file if it is excluded.
-  if (match_properties.Exclude) {
-    return true;
-  }
-
-  if (cmSystemTools::SameFile(fromFile, toFile)) {
-    return true;
-  }
-  if (cmSystemTools::FileIsSymlink(fromFile)) {
-    return this->InstallSymlink(fromFile, toFile);
-  }
-  if (cmSystemTools::FileIsDirectory(fromFile)) {
-    return this->InstallDirectory(fromFile, toFile, match_properties);
-  }
-  if (cmSystemTools::FileExists(fromFile)) {
-    return this->InstallFile(fromFile, toFile, match_properties);
-  }
-  return this->ReportMissing(fromFile);
-}
-
-bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
-{
-  // Read the original symlink.
-  std::string symlinkTarget;
-  if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
-    std::ostringstream e;
-    e << this->Name << " cannot read symlink \"" << fromFile
-      << "\" to duplicate at \"" << toFile << "\".";
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-
-  // Compare the symlink value to that at the destination if not
-  // always installing.
-  bool copy = true;
-  if (!this->Always) {
-    std::string oldSymlinkTarget;
-    if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
-      if (symlinkTarget == oldSymlinkTarget) {
-        copy = false;
-      }
-    }
-  }
-
-  // Inform the user about this file installation.
-  this->ReportCopy(toFile, TypeLink, copy);
-
-  if (copy) {
-    // Remove the destination file so we can always create the symlink.
-    cmSystemTools::RemoveFile(toFile);
-
-    // Create destination directory if it doesn't exist
-    cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
-
-    // Create the symlink.
-    if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
-      std::ostringstream e;
-      e << this->Name << " cannot duplicate symlink \"" << fromFile
-        << "\" at \"" << toFile << "\".";
-      this->FileCommand->SetError(e.str());
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
-                               MatchProperties match_properties)
-{
-  // Determine whether we will copy the file.
-  bool copy = true;
-  if (!this->Always) {
-    // If both files exist with the same time do not copy.
-    if (!this->FileTimes.FileTimesDiffer(fromFile, toFile)) {
-      copy = false;
-    }
-  }
-
-  // Inform the user about this file installation.
-  this->ReportCopy(toFile, TypeFile, copy);
-
-  // Copy the file.
-  if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
-    std::ostringstream e;
-    e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
-      << toFile << "\".";
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-
-  // Set the file modification time of the destination file.
-  if (copy && !this->Always) {
-    // Add write permission so we can set the file time.
-    // Permissions are set unconditionally below anyway.
-    mode_t perm = 0;
-    if (cmSystemTools::GetPermissions(toFile, perm)) {
-      cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
-    }
-    if (!cmSystemTools::CopyFileTime(fromFile, toFile)) {
-      std::ostringstream e;
-      e << this->Name << " cannot set modification time on \"" << toFile
-        << "\"";
-      this->FileCommand->SetError(e.str());
-      return false;
-    }
-  }
-
-  // Set permissions of the destination file.
-  mode_t permissions =
-    (match_properties.Permissions ? match_properties.Permissions
-                                  : this->FilePermissions);
-  if (!permissions) {
-    // No permissions were explicitly provided but the user requested
-    // that the source file permissions be used.
-    cmSystemTools::GetPermissions(fromFile, permissions);
-  }
-  return this->SetPermissions(toFile, permissions);
-}
-
-bool cmFileCopier::InstallDirectory(const char* source,
-                                    const char* destination,
-                                    MatchProperties match_properties)
-{
-  // Inform the user about this directory installation.
-  this->ReportCopy(destination, TypeDir,
-                   !cmSystemTools::FileIsDirectory(destination));
-
-  // check if default dir creation permissions were set
-  mode_t default_dir_mode_v = 0;
-  mode_t* default_dir_mode = &default_dir_mode_v;
-  if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
-    return false;
-  }
-
-  // Make sure the destination directory exists.
-  if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
-    std::ostringstream e;
-    e << this->Name << " cannot make directory \"" << destination
-      << "\": " << cmSystemTools::GetLastSystemError();
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-
-  // Compute the requested permissions for the destination directory.
-  mode_t permissions =
-    (match_properties.Permissions ? match_properties.Permissions
-                                  : this->DirPermissions);
-  if (!permissions) {
-    // No permissions were explicitly provided but the user requested
-    // that the source directory permissions be used.
-    cmSystemTools::GetPermissions(source, permissions);
-  }
-
-  // Compute the set of permissions required on this directory to
-  // recursively install files and subdirectories safely.
-  mode_t required_permissions =
-    mode_owner_read | mode_owner_write | mode_owner_execute;
-
-  // If the required permissions are specified it is safe to set the
-  // final permissions now.  Otherwise we must add the required
-  // permissions temporarily during file installation.
-  mode_t permissions_before = 0;
-  mode_t permissions_after = 0;
-  if ((permissions & required_permissions) == required_permissions) {
-    permissions_before = permissions;
-  } else {
-    permissions_before = permissions | required_permissions;
-    permissions_after = permissions;
-  }
-
-  // Set the required permissions of the destination directory.
-  if (!this->SetPermissions(destination, permissions_before)) {
-    return false;
-  }
-
-  // Load the directory contents to traverse it recursively.
-  cmsys::Directory dir;
-  if (source && *source) {
-    dir.Load(source);
-  }
-  unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
-  for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
-    if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
-          strcmp(dir.GetFile(fileNum), "..") == 0)) {
-      std::string fromPath = source;
-      fromPath += "/";
-      fromPath += dir.GetFile(fileNum);
-      std::string toPath = destination;
-      toPath += "/";
-      toPath += dir.GetFile(fileNum);
-      if (!this->Install(fromPath.c_str(), toPath.c_str())) {
-        return false;
-      }
-    }
-  }
-
-  // Set the requested permissions of the destination directory.
-  return this->SetPermissions(destination, permissions_after);
-}
-
 bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
 {
   cmFileCopier copier(this);
   return copier.Run(args);
 }
 
-struct cmFileInstaller : public cmFileCopier
-{
-  cmFileInstaller(cmFileCommand* command)
-    : cmFileCopier(command, "INSTALL")
-    , InstallType(cmInstallType_FILES)
-    , Optional(false)
-    , MessageAlways(false)
-    , MessageLazy(false)
-    , MessageNever(false)
-    , DestDirLength(0)
-  {
-    // Installation does not use source permissions by default.
-    this->UseSourcePermissions = false;
-    // Check whether to copy files always or only if they have changed.
-    std::string install_always;
-    if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
-      this->Always = cmSystemTools::IsOn(install_always);
-    }
-    // Get the current manifest.
-    this->Manifest =
-      this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
-  }
-  ~cmFileInstaller() override
-  {
-    // Save the updated install manifest.
-    this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
-                                  this->Manifest.c_str());
-  }
-
-protected:
-  cmInstallType InstallType;
-  bool Optional;
-  bool MessageAlways;
-  bool MessageLazy;
-  bool MessageNever;
-  int DestDirLength;
-  std::string Rename;
-
-  std::string Manifest;
-  void ManifestAppend(std::string const& file)
-  {
-    if (!this->Manifest.empty()) {
-      this->Manifest += ";";
-    }
-    this->Manifest += file.substr(this->DestDirLength);
-  }
-
-  std::string const& ToName(std::string const& fromName) override
-  {
-    return this->Rename.empty() ? fromName : this->Rename;
-  }
-
-  void ReportCopy(const char* toFile, Type type, bool copy) override
-  {
-    if (!this->MessageNever && (copy || !this->MessageLazy)) {
-      std::string message = (copy ? "Installing: " : "Up-to-date: ");
-      message += toFile;
-      this->Makefile->DisplayStatus(message.c_str(), -1);
-    }
-    if (type != TypeDir) {
-      // Add the file to the manifest.
-      this->ManifestAppend(toFile);
-    }
-  }
-  bool ReportMissing(const char* fromFile) override
-  {
-    return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
-  }
-  bool Install(const char* fromFile, const char* toFile) override
-  {
-    // Support installing from empty source to make a directory.
-    if (this->InstallType == cmInstallType_DIRECTORY && !*fromFile) {
-      return this->InstallDirectory(fromFile, toFile, MatchProperties());
-    }
-    return this->cmFileCopier::Install(fromFile, toFile);
-  }
-
-  bool Parse(std::vector<std::string> const& args) override;
-  enum
-  {
-    DoingType = DoingLast1,
-    DoingRename,
-    DoingLast2
-  };
-  bool CheckKeyword(std::string const& arg) override;
-  bool CheckValue(std::string const& arg) override;
-  void DefaultFilePermissions() override
-  {
-    this->cmFileCopier::DefaultFilePermissions();
-    // Add execute permissions based on the target type.
-    switch (this->InstallType) {
-      case cmInstallType_SHARED_LIBRARY:
-      case cmInstallType_MODULE_LIBRARY:
-        if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
-          break;
-        }
-        CM_FALLTHROUGH;
-      case cmInstallType_EXECUTABLE:
-      case cmInstallType_PROGRAMS:
-        this->FilePermissions |= mode_owner_execute;
-        this->FilePermissions |= mode_group_execute;
-        this->FilePermissions |= mode_world_execute;
-        break;
-      default:
-        break;
-    }
-  }
-  bool GetTargetTypeFromString(const std::string& stype);
-  bool HandleInstallDestination();
-};
-
-bool cmFileInstaller::Parse(std::vector<std::string> const& args)
-{
-  if (!this->cmFileCopier::Parse(args)) {
-    return false;
-  }
-
-  if (!this->Rename.empty()) {
-    if (!this->FilesFromDir.empty()) {
-      this->FileCommand->SetError("INSTALL option RENAME may not be "
-                                  "combined with FILES_FROM_DIR.");
-      return false;
-    }
-    if (this->InstallType != cmInstallType_FILES &&
-        this->InstallType != cmInstallType_PROGRAMS) {
-      this->FileCommand->SetError("INSTALL option RENAME may be used "
-                                  "only with FILES or PROGRAMS.");
-      return false;
-    }
-    if (this->Files.size() > 1) {
-      this->FileCommand->SetError("INSTALL option RENAME may be used "
-                                  "only with one file.");
-      return false;
-    }
-  }
-
-  if (!this->HandleInstallDestination()) {
-    return false;
-  }
-
-  if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
-       (this->MessageNever ? 1 : 0)) > 1) {
-    this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
-                                "MESSAGE_LAZY, and MESSAGE_NEVER "
-                                "are mutually exclusive.");
-    return false;
-  }
-
-  return true;
-}
-
-bool cmFileInstaller::CheckKeyword(std::string const& arg)
-{
-  if (arg == "TYPE") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingType;
-    }
-  } else if (arg == "FILES") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingFiles;
-    }
-  } else if (arg == "RENAME") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingRename;
-    }
-  } else if (arg == "OPTIONAL") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->Optional = true;
-    }
-  } else if (arg == "MESSAGE_ALWAYS") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->MessageAlways = true;
-    }
-  } else if (arg == "MESSAGE_LAZY") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->MessageLazy = true;
-    }
-  } else if (arg == "MESSAGE_NEVER") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      this->Doing = DoingNone;
-      this->MessageNever = true;
-    }
-  } else if (arg == "PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->Doing = DoingPermissionsMatch;
-    } else {
-      // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
-      this->Doing = DoingPermissionsFile;
-      this->UseGivenPermissionsFile = true;
-    }
-  } else if (arg == "DIR_PERMISSIONS") {
-    if (this->CurrentMatchRule) {
-      this->NotAfterMatch(arg);
-    } else {
-      // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
-      this->Doing = DoingPermissionsDir;
-      this->UseGivenPermissionsDir = true;
-    }
-  } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
-             arg == "PROPERTIES") {
-    std::ostringstream e;
-    e << "INSTALL called with old-style " << arg << " argument.  "
-      << "This script was generated with an older version of CMake.  "
-      << "Re-run this cmake version on your build tree.";
-    this->FileCommand->SetError(e.str());
-    this->Doing = DoingError;
-  } else {
-    return this->cmFileCopier::CheckKeyword(arg);
-  }
-  return true;
-}
-
-bool cmFileInstaller::CheckValue(std::string const& arg)
-{
-  switch (this->Doing) {
-    case DoingType:
-      if (!this->GetTargetTypeFromString(arg)) {
-        this->Doing = DoingError;
-      }
-      break;
-    case DoingRename:
-      this->Rename = arg;
-      break;
-    default:
-      return this->cmFileCopier::CheckValue(arg);
-  }
-  return true;
-}
-
-bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
-{
-  if (stype == "EXECUTABLE") {
-    this->InstallType = cmInstallType_EXECUTABLE;
-  } else if (stype == "FILE") {
-    this->InstallType = cmInstallType_FILES;
-  } else if (stype == "PROGRAM") {
-    this->InstallType = cmInstallType_PROGRAMS;
-  } else if (stype == "STATIC_LIBRARY") {
-    this->InstallType = cmInstallType_STATIC_LIBRARY;
-  } else if (stype == "SHARED_LIBRARY") {
-    this->InstallType = cmInstallType_SHARED_LIBRARY;
-  } else if (stype == "MODULE") {
-    this->InstallType = cmInstallType_MODULE_LIBRARY;
-  } else if (stype == "DIRECTORY") {
-    this->InstallType = cmInstallType_DIRECTORY;
-  } else {
-    std::ostringstream e;
-    e << "Option TYPE given unknown value \"" << stype << "\".";
-    this->FileCommand->SetError(e.str());
-    return false;
-  }
-  return true;
-}
-
-bool cmFileInstaller::HandleInstallDestination()
-{
-  std::string& destination = this->Destination;
-
-  // allow for / to be a valid destination
-  if (destination.size() < 2 && destination != "/") {
-    this->FileCommand->SetError("called with inappropriate arguments. "
-                                "No DESTINATION provided or .");
-    return false;
-  }
-
-  std::string sdestdir;
-  if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
-    cmSystemTools::ConvertToUnixSlashes(sdestdir);
-    char ch1 = destination[0];
-    char ch2 = destination[1];
-    char ch3 = 0;
-    if (destination.size() > 2) {
-      ch3 = destination[2];
-    }
-    int skip = 0;
-    if (ch1 != '/') {
-      int relative = 0;
-      if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
-          ch2 == ':') {
-        // Assume windows
-        // let's do some destdir magic:
-        skip = 2;
-        if (ch3 != '/') {
-          relative = 1;
-        }
-      } else {
-        relative = 1;
-      }
-      if (relative) {
-        // This is relative path on unix or windows. Since we are doing
-        // destdir, this case does not make sense.
-        this->FileCommand->SetError(
-          "called with relative DESTINATION. This "
-          "does not make sense when using DESTDIR. Specify "
-          "absolute path or remove DESTDIR environment variable.");
-        return false;
-      }
-    } else {
-      if (ch2 == '/') {
-        // looks like a network path.
-        std::string message =
-          "called with network path DESTINATION. This "
-          "does not make sense when using DESTDIR. Specify local "
-          "absolute path or remove DESTDIR environment variable."
-          "\nDESTINATION=\n";
-        message += destination;
-        this->FileCommand->SetError(message);
-        return false;
-      }
-    }
-    destination = sdestdir + (destination.c_str() + skip);
-    this->DestDirLength = int(sdestdir.size());
-  }
-
-  // check if default dir creation permissions were set
-  mode_t default_dir_mode_v = 0;
-  mode_t* default_dir_mode = &default_dir_mode_v;
-  if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
-    return false;
-  }
-
-  if (this->InstallType != cmInstallType_DIRECTORY) {
-    if (!cmSystemTools::FileExists(destination)) {
-      if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
-        std::string errstring = "cannot create directory: " + destination +
-          ". Maybe need administrative privileges.";
-        this->FileCommand->SetError(errstring);
-        return false;
-      }
-    }
-    if (!cmSystemTools::FileIsDirectory(destination)) {
-      std::string errstring =
-        "INSTALL destination: " + destination + " is not a directory.";
-      this->FileCommand->SetError(errstring);
-      return false;
-    }
-  }
-  return true;
-}
-
 bool cmFileCommand::HandleRPathChangeCommand(
   std::vector<std::string> const& args)
 {
   // Evaluate arguments.
-  const char* file = nullptr;
+  std::string file;
   const char* oldRPath = nullptr;
   const char* newRPath = nullptr;
   enum Doing
@@ -2161,7 +1081,7 @@
     } else if (args[i] == "FILE") {
       doing = DoingFile;
     } else if (doing == DoingFile) {
-      file = args[i].c_str();
+      file = args[i];
       doing = DoingNone;
     } else if (doing == DoingOld) {
       oldRPath = args[i].c_str();
@@ -2176,7 +1096,7 @@
       return false;
     }
   }
-  if (!file) {
+  if (file.empty()) {
     this->SetError("RPATH_CHANGE not given FILE option.");
     return false;
   }
@@ -2218,7 +1138,7 @@
       message += "\" to \"";
       message += newRPath;
       message += "\"";
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     }
     if (have_ft) {
       cmSystemTools::FileTimeSet(file, ft);
@@ -2232,7 +1152,7 @@
   std::vector<std::string> const& args)
 {
   // Evaluate arguments.
-  const char* file = nullptr;
+  std::string file;
   enum Doing
   {
     DoingNone,
@@ -2243,7 +1163,7 @@
     if (args[i] == "FILE") {
       doing = DoingFile;
     } else if (doing == DoingFile) {
-      file = args[i].c_str();
+      file = args[i];
       doing = DoingNone;
     } else {
       std::ostringstream e;
@@ -2252,7 +1172,7 @@
       return false;
     }
   }
-  if (!file) {
+  if (file.empty()) {
     this->SetError("RPATH_REMOVE not given FILE option.");
     return false;
   }
@@ -2282,7 +1202,7 @@
       std::string message = "Removed runtime path from \"";
       message += file;
       message += "\"";
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     }
     if (have_ft) {
       cmSystemTools::FileTimeSet(file, ft);
@@ -2296,7 +1216,7 @@
   std::vector<std::string> const& args)
 {
   // Evaluate arguments.
-  const char* file = nullptr;
+  std::string file;
   const char* rpath = nullptr;
   enum Doing
   {
@@ -2311,7 +1231,7 @@
     } else if (args[i] == "FILE") {
       doing = DoingFile;
     } else if (doing == DoingFile) {
-      file = args[i].c_str();
+      file = args[i];
       doing = DoingNone;
     } else if (doing == DoingRPath) {
       rpath = args[i].c_str();
@@ -2323,7 +1243,7 @@
       return false;
     }
   }
-  if (!file) {
+  if (file.empty()) {
     this->SetError("RPATH_CHECK not given FILE option.");
     return false;
   }
@@ -2351,55 +1271,54 @@
     return false;
   }
 
-  cmCommandArgumentsHelper argHelper;
-  cmCommandArgumentGroup group;
+  std::string const& fileNameArg = args[1];
 
-  cmCAString readArg(&argHelper, "READ_ELF");
-  cmCAString fileNameArg(&argHelper, nullptr);
+  struct Arguments
+  {
+    std::string RPath;
+    std::string RunPath;
+    std::string Error;
+  };
 
-  cmCAString rpathArg(&argHelper, "RPATH", &group);
-  cmCAString runpathArg(&argHelper, "RUNPATH", &group);
-  cmCAString errorArg(&argHelper, "CAPTURE_ERROR", &group);
+  static auto const parser = cmArgumentParser<Arguments>{}
+                               .Bind("RPATH"_s, &Arguments::RPath)
+                               .Bind("RUNPATH"_s, &Arguments::RunPath)
+                               .Bind("CAPTURE_ERROR"_s, &Arguments::Error);
+  Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2));
 
-  readArg.Follows(nullptr);
-  fileNameArg.Follows(&readArg);
-  group.Follows(&fileNameArg);
-  argHelper.Parse(&args, nullptr);
-
-  if (!cmSystemTools::FileExists(fileNameArg.GetString(), true)) {
+  if (!cmSystemTools::FileExists(fileNameArg, true)) {
     std::ostringstream e;
-    e << "READ_ELF given FILE \"" << fileNameArg.GetString()
-      << "\" that does not exist.";
+    e << "READ_ELF given FILE \"" << fileNameArg << "\" that does not exist.";
     this->SetError(e.str());
     return false;
   }
 
 #if defined(CMAKE_USE_ELF_PARSER)
-  cmELF elf(fileNameArg.GetCString());
+  cmELF elf(fileNameArg.c_str());
 
-  if (!rpathArg.GetString().empty()) {
+  if (!arguments.RPath.empty()) {
     if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
       std::string rpath(se_rpath->Value);
       std::replace(rpath.begin(), rpath.end(), ':', ';');
-      this->Makefile->AddDefinition(rpathArg.GetString(), rpath.c_str());
+      this->Makefile->AddDefinition(arguments.RPath, rpath.c_str());
     }
   }
-  if (!runpathArg.GetString().empty()) {
+  if (!arguments.RunPath.empty()) {
     if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
       std::string runpath(se_runpath->Value);
       std::replace(runpath.begin(), runpath.end(), ':', ';');
-      this->Makefile->AddDefinition(runpathArg.GetString(), runpath.c_str());
+      this->Makefile->AddDefinition(arguments.RunPath, runpath.c_str());
     }
   }
 
   return true;
 #else
   std::string error = "ELF parser not available on this platform.";
-  if (errorArg.GetString().empty()) {
+  if (arguments.Error.empty()) {
     this->SetError(error);
     return false;
   }
-  this->Makefile->AddDefinition(errorArg.GetString(), error.c_str());
+  this->Makefile->AddDefinition(arguments.Error, error.c_str());
   return true;
 #endif
 }
@@ -2481,14 +1400,14 @@
 {
 
   std::string message;
-  std::vector<std::string>::const_iterator i = args.begin();
 
-  i++; // Get rid of subcommand
-  for (; i != args.end(); ++i) {
-    std::string fileName = *i;
+  for (std::string const& arg :
+       cmMakeRange(args).advance(1)) // Get rid of subcommand
+  {
+    std::string fileName = arg;
     if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
       fileName = this->Makefile->GetCurrentSourceDirectory();
-      fileName += "/" + *i;
+      fileName += "/" + arg;
     }
 
     if (cmSystemTools::FileIsDirectory(fileName) &&
@@ -2501,44 +1420,43 @@
   return true;
 }
 
+namespace {
+std::string ToNativePath(const std::string& path)
+{
+  const auto& outPath = cmSystemTools::ConvertToOutputPath(path);
+  if (outPath.size() > 1 && outPath.front() == '\"' &&
+      outPath.back() == '\"') {
+    return outPath.substr(1, outPath.size() - 2);
+  }
+  return outPath;
+}
+
+std::string ToCMakePath(const std::string& path)
+{
+  auto temp = path;
+  cmSystemTools::ConvertToUnixSlashes(temp);
+  return temp;
+}
+}
+
 bool cmFileCommand::HandleCMakePathCommand(
   std::vector<std::string> const& args, bool nativePath)
 {
-  std::vector<std::string>::const_iterator i = args.begin();
   if (args.size() != 3) {
     this->SetError("FILE([TO_CMAKE_PATH|TO_NATIVE_PATH] path result) must be "
                    "called with exactly three arguments.");
     return false;
   }
-  i++; // Get rid of subcommand
 #if defined(_WIN32) && !defined(__CYGWIN__)
   char pathSep = ';';
 #else
   char pathSep = ':';
 #endif
-  std::vector<std::string> path = cmSystemTools::SplitString(*i, pathSep);
-  i++;
-  const char* var = i->c_str();
-  std::string value;
-  for (std::vector<std::string>::iterator j = path.begin(); j != path.end();
-       ++j) {
-    if (j != path.begin()) {
-      value += ";";
-    }
-    if (!nativePath) {
-      cmSystemTools::ConvertToUnixSlashes(*j);
-    } else {
-      *j = cmSystemTools::ConvertToOutputPath(*j);
-      // remove double quotes in the path
-      std::string& s = *j;
+  std::vector<std::string> path = cmSystemTools::SplitString(args[1], pathSep);
 
-      if (s.size() > 1 && s.front() == '\"' && s.back() == '\"') {
-        s = s.substr(1, s.size() - 2);
-      }
-    }
-    value += *j;
-  }
-  this->Makefile->AddDefinition(var, value.c_str());
+  std::string value = cmJoin(
+    cmMakeRange(path).transform(nativePath ? ToNativePath : ToCMakePath), ";");
+  this->Makefile->AddDefinition(args[2], value.c_str());
   return true;
 }
 
@@ -2651,7 +1569,7 @@
   if (helper->UpdatePercentage(dlnow, dltotal, status)) {
     cmFileCommand* fc = helper->GetFileCommand();
     cmMakefile* mf = fc->GetMakefile();
-    mf->DisplayStatus(status.c_str(), -1);
+    mf->DisplayStatus(status, -1);
   }
 
   return 0;
@@ -2669,7 +1587,7 @@
   if (helper->UpdatePercentage(ulnow, ultotal, status)) {
     cmFileCommand* fc = helper->GetFileCommand();
     cmMakefile* mf = fc->GetMakefile();
-    mf->DisplayStatus(status.c_str(), -1);
+    mf->DisplayStatus(status, -1);
   }
 
   return 0;
@@ -2693,6 +1611,9 @@
     }
   }
 
+  cURLEasyGuard(const cURLEasyGuard&) = delete;
+  cURLEasyGuard& operator=(const cURLEasyGuard&) = delete;
+
   void release() { this->Easy = nullptr; }
 
 private:
@@ -3067,7 +1988,7 @@
 
   if (!logVar.empty()) {
     chunkDebug.push_back(0);
-    this->Makefile->AddDefinition(logVar, &*chunkDebug.begin());
+    this->Makefile->AddDefinition(logVar, chunkDebug.data());
   }
 
   return true;
@@ -3326,14 +2247,14 @@
     if (!chunkResponse.empty()) {
       chunkResponse.push_back(0);
       log += "Response:\n";
-      log += &*chunkResponse.begin();
+      log += chunkResponse.data();
       log += "\n";
     }
 
     if (!chunkDebug.empty()) {
       chunkDebug.push_back(0);
       log += "Debug:\n";
-      log += &*chunkDebug.begin();
+      log += chunkDebug.data();
       log += "\n";
     }
 
@@ -3674,44 +2595,39 @@
     return false;
   }
 
-  cmCommandArgumentsHelper argHelper;
-  cmCommandArgumentGroup group;
+  std::string const& fileName = args[1];
+  std::string const& newFileName = args[2];
 
-  cmCAString linkArg(&argHelper, "CREATE_LINK");
-  cmCAString fileArg(&argHelper, nullptr);
-  cmCAString newFileArg(&argHelper, nullptr);
+  struct Arguments
+  {
+    std::string Result;
+    bool CopyOnError = false;
+    bool Symbolic = false;
+  };
 
-  cmCAString resultArg(&argHelper, "RESULT", &group);
-  cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group);
-  cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group);
-
-  linkArg.Follows(nullptr);
-  fileArg.Follows(&linkArg);
-  newFileArg.Follows(&fileArg);
-  group.Follows(&newFileArg);
+  static auto const parser =
+    cmArgumentParser<Arguments>{}
+      .Bind("RESULT"_s, &Arguments::Result)
+      .Bind("COPY_ON_ERROR"_s, &Arguments::CopyOnError)
+      .Bind("SYMBOLIC"_s, &Arguments::Symbolic);
 
   std::vector<std::string> unconsumedArgs;
-  argHelper.Parse(&args, &unconsumedArgs);
+  Arguments const arguments =
+    parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
 
   if (!unconsumedArgs.empty()) {
     this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"');
     return false;
   }
 
-  std::string fileName = fileArg.GetString();
-  std::string newFileName = newFileArg.GetString();
-
-  // Output variable for storing the result.
-  const std::string& resultVar = resultArg.GetString();
-
   // The system error message generated in the operation.
   std::string result;
 
   // Check if the paths are distinct.
   if (fileName == newFileName) {
     result = "CREATE_LINK cannot use same file and newfile";
-    if (!resultVar.empty()) {
-      this->Makefile->AddDefinition(resultVar, result.c_str());
+    if (!arguments.Result.empty()) {
+      this->Makefile->AddDefinition(arguments.Result, result.c_str());
       return true;
     }
     this->SetError(result);
@@ -3719,10 +2635,10 @@
   }
 
   // Hard link requires original file to exist.
-  if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) {
+  if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
     result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
-    if (!resultVar.empty()) {
-      this->Makefile->AddDefinition(resultVar, result.c_str());
+    if (!arguments.Result.empty()) {
+      this->Makefile->AddDefinition(arguments.Result, result.c_str());
       return true;
     }
     this->SetError(result);
@@ -3738,8 +2654,8 @@
       << "' because existing path cannot be removed: "
       << cmSystemTools::GetLastSystemError() << "\n";
 
-    if (!resultVar.empty()) {
-      this->Makefile->AddDefinition(resultVar, e.str().c_str());
+    if (!arguments.Result.empty()) {
+      this->Makefile->AddDefinition(arguments.Result, e.str().c_str());
       return true;
     }
     this->SetError(e.str());
@@ -3750,15 +2666,15 @@
   bool completed = false;
 
   // Check if the command requires a symbolic link.
-  if (symbolicArg.IsEnabled()) {
+  if (arguments.Symbolic) {
     completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result);
   } else {
     completed = cmSystemTools::CreateLink(fileName, newFileName, &result);
   }
 
   // Check if copy-on-error is enabled in the arguments.
-  if (!completed && copyOnErrorArg.IsEnabled()) {
-    completed = cmSystemTools::cmCopyFile(fileName, newFileName);
+  if (!completed && arguments.CopyOnError) {
+    completed = cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
     if (!completed) {
       result = "Copy failed: " + cmSystemTools::GetLastSystemError();
     }
@@ -3767,14 +2683,14 @@
   // Check if the operation was successful.
   if (completed) {
     result = "0";
-  } else if (resultVar.empty()) {
+  } else if (arguments.Result.empty()) {
     // The operation failed and the result is not reported in a variable.
     this->SetError(result);
     return false;
   }
 
-  if (!resultVar.empty()) {
-    this->Makefile->AddDefinition(resultVar, result.c_str());
+  if (!arguments.Result.empty()) {
+    this->Makefile->AddDefinition(arguments.Result, result.c_str());
   }
 
   return true;
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
new file mode 100644
index 0000000..8913e6d
--- /dev/null
+++ b/Source/cmFileCopier.cxx
@@ -0,0 +1,660 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmFileCopier.h"
+
+#include "cmFSPermissions.h"
+#include "cmFileCommand.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmsys/Directory.hxx"
+#include "cmsys/Glob.hxx"
+
+#ifdef _WIN32
+#  include "cmsys/FStream.hxx"
+#endif
+
+#include <sstream>
+#include <string.h>
+
+using namespace cmFSPermissions;
+
+cmFileCopier::cmFileCopier(cmFileCommand* command, const char* name)
+  : FileCommand(command)
+  , Makefile(command->GetMakefile())
+  , Name(name)
+  , Always(false)
+  , MatchlessFiles(true)
+  , FilePermissions(0)
+  , DirPermissions(0)
+  , CurrentMatchRule(nullptr)
+  , UseGivenPermissionsFile(false)
+  , UseGivenPermissionsDir(false)
+  , UseSourcePermissions(true)
+  , Doing(DoingNone)
+{
+}
+
+cmFileCopier::~cmFileCopier() = default;
+
+cmFileCopier::MatchProperties cmFileCopier::CollectMatchProperties(
+  const std::string& file)
+{
+  // Match rules are case-insensitive on some platforms.
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+  const std::string file_to_match = cmSystemTools::LowerCase(file);
+#else
+  const std::string& file_to_match = file;
+#endif
+
+  // Collect properties from all matching rules.
+  bool matched = false;
+  MatchProperties result;
+  for (MatchRule& mr : this->MatchRules) {
+    if (mr.Regex.find(file_to_match)) {
+      matched = true;
+      result.Exclude |= mr.Properties.Exclude;
+      result.Permissions |= mr.Properties.Permissions;
+    }
+  }
+  if (!matched && !this->MatchlessFiles) {
+    result.Exclude = !cmSystemTools::FileIsDirectory(file);
+  }
+  return result;
+}
+
+bool cmFileCopier::SetPermissions(const std::string& toFile,
+                                  mode_t permissions)
+{
+  if (permissions) {
+#ifdef WIN32
+    if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+      // Store the mode in an NTFS alternate stream.
+      std::string mode_t_adt_filename = toFile + ":cmake_mode_t";
+
+      // Writing to an NTFS alternate stream changes the modification
+      // time, so we need to save and restore its original value.
+      cmSystemToolsFileTime* file_time_orig = cmSystemTools::FileTimeNew();
+      cmSystemTools::FileTimeGet(toFile, file_time_orig);
+
+      cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
+
+      if (permissionStream) {
+        permissionStream << std::oct << permissions << std::endl;
+      }
+
+      permissionStream.close();
+
+      cmSystemTools::FileTimeSet(toFile, file_time_orig);
+
+      cmSystemTools::FileTimeDelete(file_time_orig);
+    }
+#endif
+
+    if (!cmSystemTools::SetPermissions(toFile, permissions)) {
+      std::ostringstream e;
+      e << this->Name << " cannot set permissions on \"" << toFile << "\"";
+      this->FileCommand->SetError(e.str());
+      return false;
+    }
+  }
+  return true;
+}
+
+// Translate an argument to a permissions bit.
+bool cmFileCopier::CheckPermissions(std::string const& arg,
+                                    mode_t& permissions)
+{
+  if (!cmFSPermissions::stringToModeT(arg, permissions)) {
+    std::ostringstream e;
+    e << this->Name << " given invalid permission \"" << arg << "\".";
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+  return true;
+}
+
+std::string const& cmFileCopier::ToName(std::string const& fromName)
+{
+  return fromName;
+}
+
+bool cmFileCopier::ReportMissing(const std::string& fromFile)
+{
+  // The input file does not exist and installation is not optional.
+  std::ostringstream e;
+  e << this->Name << " cannot find \"" << fromFile << "\".";
+  this->FileCommand->SetError(e.str());
+  return false;
+}
+
+void cmFileCopier::NotBeforeMatch(std::string const& arg)
+{
+  std::ostringstream e;
+  e << "option " << arg << " may not appear before PATTERN or REGEX.";
+  this->FileCommand->SetError(e.str());
+  this->Doing = DoingError;
+}
+
+void cmFileCopier::NotAfterMatch(std::string const& arg)
+{
+  std::ostringstream e;
+  e << "option " << arg << " may not appear after PATTERN or REGEX.";
+  this->FileCommand->SetError(e.str());
+  this->Doing = DoingError;
+}
+
+void cmFileCopier::DefaultFilePermissions()
+{
+  // Use read/write permissions.
+  this->FilePermissions = 0;
+  this->FilePermissions |= mode_owner_read;
+  this->FilePermissions |= mode_owner_write;
+  this->FilePermissions |= mode_group_read;
+  this->FilePermissions |= mode_world_read;
+}
+
+void cmFileCopier::DefaultDirectoryPermissions()
+{
+  // Use read/write/executable permissions.
+  this->DirPermissions = 0;
+  this->DirPermissions |= mode_owner_read;
+  this->DirPermissions |= mode_owner_write;
+  this->DirPermissions |= mode_owner_execute;
+  this->DirPermissions |= mode_group_read;
+  this->DirPermissions |= mode_group_execute;
+  this->DirPermissions |= mode_world_read;
+  this->DirPermissions |= mode_world_execute;
+}
+
+bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode)
+{
+  // check if default dir creation permissions were set
+  const char* default_dir_install_permissions = this->Makefile->GetDefinition(
+    "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+  if (default_dir_install_permissions && *default_dir_install_permissions) {
+    std::vector<std::string> items;
+    cmSystemTools::ExpandListArgument(default_dir_install_permissions, items);
+    for (const auto& arg : items) {
+      if (!this->CheckPermissions(arg, **mode)) {
+        std::ostringstream e;
+        e << this->FileCommand->GetError()
+          << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
+             "variable.";
+        this->FileCommand->SetError(e.str());
+        return false;
+      }
+    }
+  } else {
+    *mode = nullptr;
+  }
+
+  return true;
+}
+
+bool cmFileCopier::Parse(std::vector<std::string> const& args)
+{
+  this->Doing = DoingFiles;
+  for (unsigned int i = 1; i < args.size(); ++i) {
+    // Check this argument.
+    if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
+      std::ostringstream e;
+      e << "called with unknown argument \"" << args[i] << "\".";
+      this->FileCommand->SetError(e.str());
+      return false;
+    }
+
+    // Quit if an argument is invalid.
+    if (this->Doing == DoingError) {
+      return false;
+    }
+  }
+
+  // Require a destination.
+  if (this->Destination.empty()) {
+    std::ostringstream e;
+    e << this->Name << " given no DESTINATION";
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+
+  // If file permissions were not specified set default permissions.
+  if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
+    this->DefaultFilePermissions();
+  }
+
+  // If directory permissions were not specified set default permissions.
+  if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
+    this->DefaultDirectoryPermissions();
+  }
+
+  return true;
+}
+
+bool cmFileCopier::CheckKeyword(std::string const& arg)
+{
+  if (arg == "DESTINATION") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingDestination;
+    }
+  } else if (arg == "FILES_FROM_DIR") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingFilesFromDir;
+    }
+  } else if (arg == "PATTERN") {
+    this->Doing = DoingPattern;
+  } else if (arg == "REGEX") {
+    this->Doing = DoingRegex;
+  } else if (arg == "EXCLUDE") {
+    // Add this property to the current match rule.
+    if (this->CurrentMatchRule) {
+      this->CurrentMatchRule->Properties.Exclude = true;
+      this->Doing = DoingNone;
+    } else {
+      this->NotBeforeMatch(arg);
+    }
+  } else if (arg == "PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->Doing = DoingPermissionsMatch;
+    } else {
+      this->NotBeforeMatch(arg);
+    }
+  } else if (arg == "FILE_PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingPermissionsFile;
+      this->UseGivenPermissionsFile = true;
+    }
+  } else if (arg == "DIRECTORY_PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingPermissionsDir;
+      this->UseGivenPermissionsDir = true;
+    }
+  } else if (arg == "USE_SOURCE_PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->UseSourcePermissions = true;
+    }
+  } else if (arg == "NO_SOURCE_PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->UseSourcePermissions = false;
+    }
+  } else if (arg == "FILES_MATCHING") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->MatchlessFiles = false;
+    }
+  } else {
+    return false;
+  }
+  return true;
+}
+
+bool cmFileCopier::CheckValue(std::string const& arg)
+{
+  switch (this->Doing) {
+    case DoingFiles:
+      this->Files.push_back(arg);
+      break;
+    case DoingDestination:
+      if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
+        this->Destination = arg;
+      } else {
+        this->Destination = this->Makefile->GetCurrentBinaryDirectory();
+        this->Destination += "/" + arg;
+      }
+      this->Doing = DoingNone;
+      break;
+    case DoingFilesFromDir:
+      if (cmSystemTools::FileIsFullPath(arg)) {
+        this->FilesFromDir = arg;
+      } else {
+        this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
+        this->FilesFromDir += "/" + arg;
+      }
+      cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
+      this->Doing = DoingNone;
+      break;
+    case DoingPattern: {
+      // Convert the pattern to a regular expression.  Require a
+      // leading slash and trailing end-of-string in the matched
+      // string to make sure the pattern matches only whole file
+      // names.
+      std::string regex = "/";
+      regex += cmsys::Glob::PatternToRegex(arg, false);
+      regex += "$";
+      this->MatchRules.emplace_back(regex);
+      this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+      if (this->CurrentMatchRule->Regex.is_valid()) {
+        this->Doing = DoingNone;
+      } else {
+        std::ostringstream e;
+        e << "could not compile PATTERN \"" << arg << "\".";
+        this->FileCommand->SetError(e.str());
+        this->Doing = DoingError;
+      }
+    } break;
+    case DoingRegex:
+      this->MatchRules.emplace_back(arg);
+      this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+      if (this->CurrentMatchRule->Regex.is_valid()) {
+        this->Doing = DoingNone;
+      } else {
+        std::ostringstream e;
+        e << "could not compile REGEX \"" << arg << "\".";
+        this->FileCommand->SetError(e.str());
+        this->Doing = DoingError;
+      }
+      break;
+    case DoingPermissionsFile:
+      if (!this->CheckPermissions(arg, this->FilePermissions)) {
+        this->Doing = DoingError;
+      }
+      break;
+    case DoingPermissionsDir:
+      if (!this->CheckPermissions(arg, this->DirPermissions)) {
+        this->Doing = DoingError;
+      }
+      break;
+    case DoingPermissionsMatch:
+      if (!this->CheckPermissions(
+            arg, this->CurrentMatchRule->Properties.Permissions)) {
+        this->Doing = DoingError;
+      }
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+bool cmFileCopier::Run(std::vector<std::string> const& args)
+{
+  if (!this->Parse(args)) {
+    return false;
+  }
+
+  for (std::string const& f : this->Files) {
+    std::string file;
+    if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
+      if (!this->FilesFromDir.empty()) {
+        file = this->FilesFromDir;
+      } else {
+        file = this->Makefile->GetCurrentSourceDirectory();
+      }
+      file += "/";
+      file += f;
+    } else if (!this->FilesFromDir.empty()) {
+      this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
+                                  "to be specified as relative paths.");
+      return false;
+    } else {
+      file = f;
+    }
+
+    // Split the input file into its directory and name components.
+    std::vector<std::string> fromPathComponents;
+    cmSystemTools::SplitPath(file, fromPathComponents);
+    std::string fromName = *(fromPathComponents.end() - 1);
+    std::string fromDir = cmSystemTools::JoinPath(
+      fromPathComponents.begin(), fromPathComponents.end() - 1);
+
+    // Compute the full path to the destination file.
+    std::string toFile = this->Destination;
+    if (!this->FilesFromDir.empty()) {
+      std::string dir = cmSystemTools::GetFilenamePath(f);
+      if (!dir.empty()) {
+        toFile += "/";
+        toFile += dir;
+      }
+    }
+    std::string const& toName = this->ToName(fromName);
+    if (!toName.empty()) {
+      toFile += "/";
+      toFile += toName;
+    }
+
+    // Construct the full path to the source file.  The file name may
+    // have been changed above.
+    std::string fromFile = fromDir;
+    if (!fromName.empty()) {
+      fromFile += "/";
+      fromFile += fromName;
+    }
+
+    if (!this->Install(fromFile, toFile)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool cmFileCopier::Install(const std::string& fromFile,
+                           const std::string& toFile)
+{
+  if (fromFile.empty()) {
+    std::ostringstream e;
+    e << "INSTALL encountered an empty string input file name.";
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+
+  // Collect any properties matching this file name.
+  MatchProperties match_properties = this->CollectMatchProperties(fromFile);
+
+  // Skip the file if it is excluded.
+  if (match_properties.Exclude) {
+    return true;
+  }
+
+  if (cmSystemTools::SameFile(fromFile, toFile)) {
+    return true;
+  }
+  if (cmSystemTools::FileIsSymlink(fromFile)) {
+    return this->InstallSymlink(fromFile, toFile);
+  }
+  if (cmSystemTools::FileIsDirectory(fromFile)) {
+    return this->InstallDirectory(fromFile, toFile, match_properties);
+  }
+  if (cmSystemTools::FileExists(fromFile)) {
+    return this->InstallFile(fromFile, toFile, match_properties);
+  }
+  return this->ReportMissing(fromFile);
+}
+
+bool cmFileCopier::InstallSymlink(const std::string& fromFile,
+                                  const std::string& toFile)
+{
+  // Read the original symlink.
+  std::string symlinkTarget;
+  if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
+    std::ostringstream e;
+    e << this->Name << " cannot read symlink \"" << fromFile
+      << "\" to duplicate at \"" << toFile << "\".";
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+
+  // Compare the symlink value to that at the destination if not
+  // always installing.
+  bool copy = true;
+  if (!this->Always) {
+    std::string oldSymlinkTarget;
+    if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+      if (symlinkTarget == oldSymlinkTarget) {
+        copy = false;
+      }
+    }
+  }
+
+  // Inform the user about this file installation.
+  this->ReportCopy(toFile, TypeLink, copy);
+
+  if (copy) {
+    // Remove the destination file so we can always create the symlink.
+    cmSystemTools::RemoveFile(toFile);
+
+    // Create destination directory if it doesn't exist
+    cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
+
+    // Create the symlink.
+    if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+      std::ostringstream e;
+      e << this->Name << " cannot duplicate symlink \"" << fromFile
+        << "\" at \"" << toFile << "\".";
+      this->FileCommand->SetError(e.str());
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool cmFileCopier::InstallFile(const std::string& fromFile,
+                               const std::string& toFile,
+                               MatchProperties match_properties)
+{
+  // Determine whether we will copy the file.
+  bool copy = true;
+  if (!this->Always) {
+    // If both files exist with the same time do not copy.
+    if (!this->FileTimes.DifferS(fromFile, toFile)) {
+      copy = false;
+    }
+  }
+
+  // Inform the user about this file installation.
+  this->ReportCopy(toFile, TypeFile, copy);
+
+  // Copy the file.
+  if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
+    std::ostringstream e;
+    e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
+      << toFile << "\".";
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+
+  // Set the file modification time of the destination file.
+  if (copy && !this->Always) {
+    // Add write permission so we can set the file time.
+    // Permissions are set unconditionally below anyway.
+    mode_t perm = 0;
+    if (cmSystemTools::GetPermissions(toFile, perm)) {
+      cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
+    }
+    if (!cmSystemTools::CopyFileTime(fromFile, toFile)) {
+      std::ostringstream e;
+      e << this->Name << " cannot set modification time on \"" << toFile
+        << "\"";
+      this->FileCommand->SetError(e.str());
+      return false;
+    }
+  }
+
+  // Set permissions of the destination file.
+  mode_t permissions =
+    (match_properties.Permissions ? match_properties.Permissions
+                                  : this->FilePermissions);
+  if (!permissions) {
+    // No permissions were explicitly provided but the user requested
+    // that the source file permissions be used.
+    cmSystemTools::GetPermissions(fromFile, permissions);
+  }
+  return this->SetPermissions(toFile, permissions);
+}
+
+bool cmFileCopier::InstallDirectory(const std::string& source,
+                                    const std::string& destination,
+                                    MatchProperties match_properties)
+{
+  // Inform the user about this directory installation.
+  this->ReportCopy(destination, TypeDir,
+                   !cmSystemTools::FileIsDirectory(destination));
+
+  // check if default dir creation permissions were set
+  mode_t default_dir_mode_v = 0;
+  mode_t* default_dir_mode = &default_dir_mode_v;
+  if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+    return false;
+  }
+
+  // Make sure the destination directory exists.
+  if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+    std::ostringstream e;
+    e << this->Name << " cannot make directory \"" << destination
+      << "\": " << cmSystemTools::GetLastSystemError();
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+
+  // Compute the requested permissions for the destination directory.
+  mode_t permissions =
+    (match_properties.Permissions ? match_properties.Permissions
+                                  : this->DirPermissions);
+  if (!permissions) {
+    // No permissions were explicitly provided but the user requested
+    // that the source directory permissions be used.
+    cmSystemTools::GetPermissions(source, permissions);
+  }
+
+  // Compute the set of permissions required on this directory to
+  // recursively install files and subdirectories safely.
+  mode_t required_permissions =
+    mode_owner_read | mode_owner_write | mode_owner_execute;
+
+  // If the required permissions are specified it is safe to set the
+  // final permissions now.  Otherwise we must add the required
+  // permissions temporarily during file installation.
+  mode_t permissions_before = 0;
+  mode_t permissions_after = 0;
+  if ((permissions & required_permissions) == required_permissions) {
+    permissions_before = permissions;
+  } else {
+    permissions_before = permissions | required_permissions;
+    permissions_after = permissions;
+  }
+
+  // Set the required permissions of the destination directory.
+  if (!this->SetPermissions(destination, permissions_before)) {
+    return false;
+  }
+
+  // Load the directory contents to traverse it recursively.
+  cmsys::Directory dir;
+  if (!source.empty()) {
+    dir.Load(source);
+  }
+  unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
+  for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
+    if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
+          strcmp(dir.GetFile(fileNum), "..") == 0)) {
+      std::string fromPath = source;
+      fromPath += "/";
+      fromPath += dir.GetFile(fileNum);
+      std::string toPath = destination;
+      toPath += "/";
+      toPath += dir.GetFile(fileNum);
+      if (!this->Install(fromPath, toPath)) {
+        return false;
+      }
+    }
+  }
+
+  // Set the requested permissions of the destination directory.
+  return this->SetPermissions(destination, permissions_after);
+}
diff --git a/Source/cmFileCopier.h b/Source/cmFileCopier.h
new file mode 100644
index 0000000..003b8f6
--- /dev/null
+++ b/Source/cmFileCopier.h
@@ -0,0 +1,120 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFileCopier_h
+#define cmFileCopier_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTimeCache.h"
+#include "cm_sys_stat.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include <string>
+#include <vector>
+
+class cmFileCommand;
+class cmMakefile;
+
+// File installation helper class.
+struct cmFileCopier
+{
+  cmFileCopier(cmFileCommand* command, const char* name = "COPY");
+  virtual ~cmFileCopier();
+
+  bool Run(std::vector<std::string> const& args);
+
+protected:
+  cmFileCommand* FileCommand;
+  cmMakefile* Makefile;
+  const char* Name;
+  bool Always;
+  cmFileTimeCache FileTimes;
+
+  // Whether to install a file not matching any expression.
+  bool MatchlessFiles;
+
+  // Permissions for files and directories installed by this object.
+  mode_t FilePermissions;
+  mode_t DirPermissions;
+
+  // Properties set by pattern and regex match rules.
+  struct MatchProperties
+  {
+    bool Exclude = false;
+    mode_t Permissions = 0;
+  };
+  struct MatchRule
+  {
+    cmsys::RegularExpression Regex;
+    MatchProperties Properties;
+    std::string RegexString;
+    MatchRule(std::string const& regex)
+      : Regex(regex)
+      , RegexString(regex)
+    {
+    }
+  };
+  std::vector<MatchRule> MatchRules;
+
+  // Get the properties from rules matching this input file.
+  MatchProperties CollectMatchProperties(const std::string& file);
+
+  bool SetPermissions(const std::string& toFile, mode_t permissions);
+
+  // Translate an argument to a permissions bit.
+  bool CheckPermissions(std::string const& arg, mode_t& permissions);
+
+  bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
+  bool InstallFile(const std::string& fromFile, const std::string& toFile,
+                   MatchProperties match_properties);
+  bool InstallDirectory(const std::string& source,
+                        const std::string& destination,
+                        MatchProperties match_properties);
+  virtual bool Install(const std::string& fromFile, const std::string& toFile);
+  virtual std::string const& ToName(std::string const& fromName);
+
+  enum Type
+  {
+    TypeFile,
+    TypeDir,
+    TypeLink
+  };
+  virtual void ReportCopy(const std::string&, Type, bool) {}
+  virtual bool ReportMissing(const std::string& fromFile);
+
+  MatchRule* CurrentMatchRule;
+  bool UseGivenPermissionsFile;
+  bool UseGivenPermissionsDir;
+  bool UseSourcePermissions;
+  std::string Destination;
+  std::string FilesFromDir;
+  std::vector<std::string> Files;
+  int Doing;
+
+  virtual bool Parse(std::vector<std::string> const& args);
+  enum
+  {
+    DoingNone,
+    DoingError,
+    DoingDestination,
+    DoingFilesFromDir,
+    DoingFiles,
+    DoingPattern,
+    DoingRegex,
+    DoingPermissionsFile,
+    DoingPermissionsDir,
+    DoingPermissionsMatch,
+    DoingLast1
+  };
+  virtual bool CheckKeyword(std::string const& arg);
+  virtual bool CheckValue(std::string const& arg);
+
+  void NotBeforeMatch(std::string const& arg);
+  void NotAfterMatch(std::string const& arg);
+  virtual void DefaultFilePermissions();
+  virtual void DefaultDirectoryPermissions();
+
+  bool GetDefaultDirectoryPermissions(mode_t** mode);
+};
+
+#endif
diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx
new file mode 100644
index 0000000..d4f76fd
--- /dev/null
+++ b/Source/cmFileInstaller.cxx
@@ -0,0 +1,350 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmFileInstaller.h"
+
+#include "cmFSPermissions.h"
+#include "cmFileCommand.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include "cm_sys_stat.h"
+
+#include <sstream>
+
+using namespace cmFSPermissions;
+
+cmFileInstaller::cmFileInstaller(cmFileCommand* command)
+  : cmFileCopier(command, "INSTALL")
+  , InstallType(cmInstallType_FILES)
+  , Optional(false)
+  , MessageAlways(false)
+  , MessageLazy(false)
+  , MessageNever(false)
+  , DestDirLength(0)
+{
+  // Installation does not use source permissions by default.
+  this->UseSourcePermissions = false;
+  // Check whether to copy files always or only if they have changed.
+  std::string install_always;
+  if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
+    this->Always = cmSystemTools::IsOn(install_always);
+  }
+  // Get the current manifest.
+  this->Manifest =
+    this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
+}
+cmFileInstaller::~cmFileInstaller()
+{
+  // Save the updated install manifest.
+  this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
+                                this->Manifest.c_str());
+}
+
+void cmFileInstaller::ManifestAppend(std::string const& file)
+{
+  if (!this->Manifest.empty()) {
+    this->Manifest += ";";
+  }
+  this->Manifest += file.substr(this->DestDirLength);
+}
+
+std::string const& cmFileInstaller::ToName(std::string const& fromName)
+{
+  return this->Rename.empty() ? fromName : this->Rename;
+}
+
+void cmFileInstaller::ReportCopy(const std::string& toFile, Type type,
+                                 bool copy)
+{
+  if (!this->MessageNever && (copy || !this->MessageLazy)) {
+    std::string message = (copy ? "Installing: " : "Up-to-date: ");
+    message += toFile;
+    this->Makefile->DisplayStatus(message, -1);
+  }
+  if (type != TypeDir) {
+    // Add the file to the manifest.
+    this->ManifestAppend(toFile);
+  }
+}
+bool cmFileInstaller::ReportMissing(const std::string& fromFile)
+{
+  return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
+}
+bool cmFileInstaller::Install(const std::string& fromFile,
+                              const std::string& toFile)
+{
+  // Support installing from empty source to make a directory.
+  if (this->InstallType == cmInstallType_DIRECTORY && fromFile.empty()) {
+    return this->InstallDirectory(fromFile, toFile, MatchProperties());
+  }
+  return this->cmFileCopier::Install(fromFile, toFile);
+}
+
+void cmFileInstaller::DefaultFilePermissions()
+{
+  this->cmFileCopier::DefaultFilePermissions();
+  // Add execute permissions based on the target type.
+  switch (this->InstallType) {
+    case cmInstallType_SHARED_LIBRARY:
+    case cmInstallType_MODULE_LIBRARY:
+      if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
+        break;
+      }
+      CM_FALLTHROUGH;
+    case cmInstallType_EXECUTABLE:
+    case cmInstallType_PROGRAMS:
+      this->FilePermissions |= mode_owner_execute;
+      this->FilePermissions |= mode_group_execute;
+      this->FilePermissions |= mode_world_execute;
+      break;
+    default:
+      break;
+  }
+}
+
+bool cmFileInstaller::Parse(std::vector<std::string> const& args)
+{
+  if (!this->cmFileCopier::Parse(args)) {
+    return false;
+  }
+
+  if (!this->Rename.empty()) {
+    if (!this->FilesFromDir.empty()) {
+      this->FileCommand->SetError("INSTALL option RENAME may not be "
+                                  "combined with FILES_FROM_DIR.");
+      return false;
+    }
+    if (this->InstallType != cmInstallType_FILES &&
+        this->InstallType != cmInstallType_PROGRAMS) {
+      this->FileCommand->SetError("INSTALL option RENAME may be used "
+                                  "only with FILES or PROGRAMS.");
+      return false;
+    }
+    if (this->Files.size() > 1) {
+      this->FileCommand->SetError("INSTALL option RENAME may be used "
+                                  "only with one file.");
+      return false;
+    }
+  }
+
+  if (!this->HandleInstallDestination()) {
+    return false;
+  }
+
+  if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
+       (this->MessageNever ? 1 : 0)) > 1) {
+    this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
+                                "MESSAGE_LAZY, and MESSAGE_NEVER "
+                                "are mutually exclusive.");
+    return false;
+  }
+
+  return true;
+}
+
+bool cmFileInstaller::CheckKeyword(std::string const& arg)
+{
+  if (arg == "TYPE") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingType;
+    }
+  } else if (arg == "FILES") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingFiles;
+    }
+  } else if (arg == "RENAME") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingRename;
+    }
+  } else if (arg == "OPTIONAL") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->Optional = true;
+    }
+  } else if (arg == "MESSAGE_ALWAYS") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->MessageAlways = true;
+    }
+  } else if (arg == "MESSAGE_LAZY") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->MessageLazy = true;
+    }
+  } else if (arg == "MESSAGE_NEVER") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      this->Doing = DoingNone;
+      this->MessageNever = true;
+    }
+  } else if (arg == "PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->Doing = DoingPermissionsMatch;
+    } else {
+      // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
+      this->Doing = DoingPermissionsFile;
+      this->UseGivenPermissionsFile = true;
+    }
+  } else if (arg == "DIR_PERMISSIONS") {
+    if (this->CurrentMatchRule) {
+      this->NotAfterMatch(arg);
+    } else {
+      // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
+      this->Doing = DoingPermissionsDir;
+      this->UseGivenPermissionsDir = true;
+    }
+  } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
+             arg == "PROPERTIES") {
+    std::ostringstream e;
+    e << "INSTALL called with old-style " << arg << " argument.  "
+      << "This script was generated with an older version of CMake.  "
+      << "Re-run this cmake version on your build tree.";
+    this->FileCommand->SetError(e.str());
+    this->Doing = DoingError;
+  } else {
+    return this->cmFileCopier::CheckKeyword(arg);
+  }
+  return true;
+}
+
+bool cmFileInstaller::CheckValue(std::string const& arg)
+{
+  switch (this->Doing) {
+    case DoingType:
+      if (!this->GetTargetTypeFromString(arg)) {
+        this->Doing = DoingError;
+      }
+      break;
+    case DoingRename:
+      this->Rename = arg;
+      break;
+    default:
+      return this->cmFileCopier::CheckValue(arg);
+  }
+  return true;
+}
+
+bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
+{
+  if (stype == "EXECUTABLE") {
+    this->InstallType = cmInstallType_EXECUTABLE;
+  } else if (stype == "FILE") {
+    this->InstallType = cmInstallType_FILES;
+  } else if (stype == "PROGRAM") {
+    this->InstallType = cmInstallType_PROGRAMS;
+  } else if (stype == "STATIC_LIBRARY") {
+    this->InstallType = cmInstallType_STATIC_LIBRARY;
+  } else if (stype == "SHARED_LIBRARY") {
+    this->InstallType = cmInstallType_SHARED_LIBRARY;
+  } else if (stype == "MODULE") {
+    this->InstallType = cmInstallType_MODULE_LIBRARY;
+  } else if (stype == "DIRECTORY") {
+    this->InstallType = cmInstallType_DIRECTORY;
+  } else {
+    std::ostringstream e;
+    e << "Option TYPE given unknown value \"" << stype << "\".";
+    this->FileCommand->SetError(e.str());
+    return false;
+  }
+  return true;
+}
+
+bool cmFileInstaller::HandleInstallDestination()
+{
+  std::string& destination = this->Destination;
+
+  // allow for / to be a valid destination
+  if (destination.size() < 2 && destination != "/") {
+    this->FileCommand->SetError("called with inappropriate arguments. "
+                                "No DESTINATION provided or .");
+    return false;
+  }
+
+  std::string sdestdir;
+  if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
+    cmSystemTools::ConvertToUnixSlashes(sdestdir);
+    char ch1 = destination[0];
+    char ch2 = destination[1];
+    char ch3 = 0;
+    if (destination.size() > 2) {
+      ch3 = destination[2];
+    }
+    int skip = 0;
+    if (ch1 != '/') {
+      int relative = 0;
+      if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
+          ch2 == ':') {
+        // Assume windows
+        // let's do some destdir magic:
+        skip = 2;
+        if (ch3 != '/') {
+          relative = 1;
+        }
+      } else {
+        relative = 1;
+      }
+      if (relative) {
+        // This is relative path on unix or windows. Since we are doing
+        // destdir, this case does not make sense.
+        this->FileCommand->SetError(
+          "called with relative DESTINATION. This "
+          "does not make sense when using DESTDIR. Specify "
+          "absolute path or remove DESTDIR environment variable.");
+        return false;
+      }
+    } else {
+      if (ch2 == '/') {
+        // looks like a network path.
+        std::string message =
+          "called with network path DESTINATION. This "
+          "does not make sense when using DESTDIR. Specify local "
+          "absolute path or remove DESTDIR environment variable."
+          "\nDESTINATION=\n";
+        message += destination;
+        this->FileCommand->SetError(message);
+        return false;
+      }
+    }
+    destination = sdestdir + destination.substr(skip);
+    this->DestDirLength = int(sdestdir.size());
+  }
+
+  // check if default dir creation permissions were set
+  mode_t default_dir_mode_v = 0;
+  mode_t* default_dir_mode = &default_dir_mode_v;
+  if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+    return false;
+  }
+
+  if (this->InstallType != cmInstallType_DIRECTORY) {
+    if (!cmSystemTools::FileExists(destination)) {
+      if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+        std::string errstring = "cannot create directory: " + destination +
+          ". Maybe need administrative privileges.";
+        this->FileCommand->SetError(errstring);
+        return false;
+      }
+    }
+    if (!cmSystemTools::FileIsDirectory(destination)) {
+      std::string errstring =
+        "INSTALL destination: " + destination + " is not a directory.";
+      this->FileCommand->SetError(errstring);
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/Source/cmFileInstaller.h b/Source/cmFileInstaller.h
new file mode 100644
index 0000000..312529a
--- /dev/null
+++ b/Source/cmFileInstaller.h
@@ -0,0 +1,55 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFileInstaller_h
+#define cmFileInstaller_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileCopier.h"
+
+#include "cmInstallType.h"
+
+#include <string>
+#include <vector>
+
+class cmFileCommand;
+
+struct cmFileInstaller : public cmFileCopier
+{
+  cmFileInstaller(cmFileCommand* command);
+  ~cmFileInstaller() override;
+
+protected:
+  cmInstallType InstallType;
+  bool Optional;
+  bool MessageAlways;
+  bool MessageLazy;
+  bool MessageNever;
+  int DestDirLength;
+  std::string Rename;
+
+  std::string Manifest;
+  void ManifestAppend(std::string const& file);
+
+  std::string const& ToName(std::string const& fromName) override;
+
+  void ReportCopy(const std::string& toFile, Type type, bool copy) override;
+  bool ReportMissing(const std::string& fromFile) override;
+  bool Install(const std::string& fromFile,
+               const std::string& toFile) override;
+
+  bool Parse(std::vector<std::string> const& args) override;
+  enum
+  {
+    DoingType = DoingLast1,
+    DoingRename,
+    DoingLast2
+  };
+  bool CheckKeyword(std::string const& arg) override;
+  bool CheckValue(std::string const& arg) override;
+  void DefaultFilePermissions() override;
+  bool GetTargetTypeFromString(const std::string& stype);
+  bool HandleInstallDestination();
+};
+
+#endif
diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx
index 2cffa7c..47a223a 100644
--- a/Source/cmFilePathChecksum.cxx
+++ b/Source/cmFilePathChecksum.cxx
@@ -74,7 +74,7 @@
     cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath);
 
   // Convert binary checksum to string
-  return cmBase32Encoder().encodeString(&hashBytes.front(), hashBytes.size(),
+  return cmBase32Encoder().encodeString(hashBytes.data(), hashBytes.size(),
                                         false);
 }
 
diff --git a/Source/cmFileTime.cxx b/Source/cmFileTime.cxx
new file mode 100644
index 0000000..253457f
--- /dev/null
+++ b/Source/cmFileTime.cxx
@@ -0,0 +1,49 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFileTime.h"
+
+#include <string>
+#include <time.h>
+
+// Use a platform-specific API to get file times efficiently.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+#  include "cm_sys_stat.h"
+#else
+#  include "cmsys/Encoding.hxx"
+#  include <windows.h>
+#endif
+
+bool cmFileTime::Load(std::string const& fileName)
+{
+#if !defined(_WIN32) || defined(__CYGWIN__)
+  // POSIX version.  Use the stat function.
+  struct stat fst;
+  if (::stat(fileName.c_str(), &fst) != 0) {
+    return false;
+  }
+#  if CMake_STAT_HAS_ST_MTIM
+  // Nanosecond resolution
+  this->NS = fst.st_mtim.tv_sec * NsPerS + fst.st_mtim.tv_nsec;
+#  elif CMake_STAT_HAS_ST_MTIMESPEC
+  // Nanosecond resolution
+  this->NS = fst.st_mtimespec.tv_sec * NsPerS + fst.st_mtimespec.tv_nsec;
+#  else
+  // Second resolution
+  this->NS = fst.st_mtime * NsPerS;
+#  endif
+#else
+  // Windows version.  Get the modification time from extended file attributes.
+  WIN32_FILE_ATTRIBUTE_DATA fdata;
+  if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fileName).c_str(),
+                            GetFileExInfoStandard, &fdata)) {
+    return false;
+  }
+
+  // Copy the file time to the output location.
+  this->NS = (static_cast<NSC>(fdata.ftLastWriteTime.dwHighDateTime) << 32) |
+    static_cast<NSC>(fdata.ftLastWriteTime.dwLowDateTime);
+  // The file time resolution is 100 ns.
+  this->NS *= 100;
+#endif
+  return true;
+}
diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h
new file mode 100644
index 0000000..d4de4e0
--- /dev/null
+++ b/Source/cmFileTime.h
@@ -0,0 +1,130 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFileTime_h
+#define cmFileTime_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+/** \class cmFileTime
+ * \brief Abstract file modification time with support for comparison with
+ *        other file modification times.
+ */
+class cmFileTime
+{
+public:
+  typedef long long NSC;
+  static constexpr NSC NsPerS = 1000000000;
+
+  cmFileTime() = default;
+  ~cmFileTime() = default;
+
+  /**
+   * @brief Loads the file time of fileName from the file system
+   * @return true on success
+   */
+  bool Load(std::string const& fileName);
+
+  /**
+   * @brief Return true if this is older than ftm
+   */
+  bool Older(cmFileTime const& ftm) const { return (this->NS - ftm.NS) < 0; }
+
+  /**
+   * @brief Return true if this is newer than ftm
+   */
+  bool Newer(cmFileTime const& ftm) const { return (ftm.NS - this->NS) < 0; }
+
+  /**
+   * @brief Return true if this is the same as ftm
+   */
+  bool Equal(cmFileTime const& ftm) const { return this->NS == ftm.NS; }
+
+  /**
+   * @brief Return true if this is not the same as ftm
+   */
+  bool Differ(cmFileTime const& ftm) const { return this->NS != ftm.NS; }
+
+  /**
+   * @brief Compare file modification times.
+   * @return -1, 0, +1 for this older, same, or newer than ftm.
+   */
+  int Compare(cmFileTime const& ftm) const
+  {
+    NSC const diff = this->NS - ftm.NS;
+    if (diff == 0) {
+      return 0;
+    }
+    return (diff < 0) ? -1 : 1;
+  }
+
+  // -- Comparison in second resolution
+
+  /**
+   * @brief Return true if this is at least a second older than ftm
+   */
+  bool OlderS(cmFileTime const& ftm) const
+  {
+    return (ftm.NS - this->NS) >= cmFileTime::NsPerS;
+  }
+
+  /**
+   * @brief Return true if this is at least a second newer than ftm
+   */
+  bool NewerS(cmFileTime const& ftm) const
+  {
+    return (this->NS - ftm.NS) >= cmFileTime::NsPerS;
+  }
+
+  /**
+   * @brief Return true if this is within the same second as ftm
+   */
+  bool EqualS(cmFileTime const& ftm) const
+  {
+    NSC diff = this->NS - ftm.NS;
+    if (diff < 0) {
+      diff = -diff;
+    }
+    return (diff < cmFileTime::NsPerS);
+  }
+
+  /**
+   * @brief Return true if this is older or newer than ftm by at least a second
+   */
+  bool DifferS(cmFileTime const& ftm) const
+  {
+    NSC diff = this->NS - ftm.NS;
+    if (diff < 0) {
+      diff = -diff;
+    }
+    return (diff >= cmFileTime::NsPerS);
+  }
+
+  /**
+   * @brief Compare file modification times.
+   * @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
+  {
+    NSC const diff = this->NS - ftm.NS;
+    if (diff <= -cmFileTime::NsPerS) {
+      return -1;
+    }
+    if (diff >= cmFileTime::NsPerS) {
+      return 1;
+    }
+    return 0;
+  }
+
+  /**
+   * @brief The file modification time in nanoseconds
+   */
+  NSC GetNS() const { return this->NS; }
+
+private:
+  NSC NS = 0;
+};
+
+#endif
diff --git a/Source/cmFileTimeCache.cxx b/Source/cmFileTimeCache.cxx
new file mode 100644
index 0000000..24d6bf6
--- /dev/null
+++ b/Source/cmFileTimeCache.cxx
@@ -0,0 +1,62 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFileTimeCache.h"
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+cmFileTimeCache::cmFileTimeCache() = default;
+
+cmFileTimeCache::~cmFileTimeCache() = default;
+
+bool cmFileTimeCache::Load(std::string const& fileName, cmFileTime& fileTime)
+{
+  // Use the stored time if available.
+  {
+    auto fit = this->Cache.find(fileName);
+    if (fit != this->Cache.end()) {
+      fileTime = fit->second;
+      return true;
+    }
+  }
+  // Read file time from OS
+  if (!fileTime.Load(fileName)) {
+    return false;
+  }
+  // Store file time in cache
+  this->Cache[fileName] = fileTime;
+  return true;
+}
+
+bool cmFileTimeCache::Remove(std::string const& fileName)
+{
+  return (this->Cache.erase(fileName) != 0);
+}
+
+bool cmFileTimeCache::Compare(std::string const& f1, std::string const& f2,
+                              int* result)
+{
+  // Get the modification time for each file.
+  cmFileTime ft1, ft2;
+  if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+    // Compare the two modification times.
+    *result = ft1.Compare(ft2);
+    return true;
+  }
+  // No comparison available.  Default to the same time.
+  *result = 0;
+  return false;
+}
+
+bool cmFileTimeCache::DifferS(std::string const& f1, std::string const& f2)
+{
+  // Get the modification time for each file.
+  cmFileTime ft1, ft2;
+  if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+    // Compare the two modification times.
+    return ft1.DifferS(ft2);
+  }
+  // No comparison available.  Default to different times.
+  return true;
+}
diff --git a/Source/cmFileTimeCache.h b/Source/cmFileTimeCache.h
new file mode 100644
index 0000000..4f1a3a2
--- /dev/null
+++ b/Source/cmFileTimeCache.h
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFileTimeCache_h
+#define cmFileTimeCache_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTime.h" // IWYU pragma: keep
+#include <string>
+#include <unordered_map>
+
+/** \class cmFileTimeCache
+ * \brief Caches file modification times in an internal map for fast lookups.
+ */
+class cmFileTimeCache
+{
+public:
+  cmFileTimeCache();
+  ~cmFileTimeCache();
+
+  cmFileTimeCache(const cmFileTimeCache&) = delete;
+  cmFileTimeCache& operator=(const cmFileTimeCache&) = delete;
+
+  /**
+   * @brief Loads the file time from the cache or the file system.
+   * @return true on success
+   */
+  bool Load(std::string const& fileName, cmFileTime& fileTime);
+
+  /**
+   * @brief Removes a file time from the cache
+   * @return true if the file was found in the cache and removed
+   */
+  bool Remove(std::string const& fileName);
+
+  /**
+   * @brief Compare file modification times.
+   * @return true for successful comparison and false for error.
+   *
+   * When true is returned, result has -1, 0, +1 for
+   * f1 older, same, or newer than f2.
+   */
+  bool Compare(std::string const& f1, std::string const& f2, int* result);
+
+  /**
+   * @brief Compare file modification times.
+   * @return true unless both files exist and have modification times less
+   *         than 1 second apart.
+   */
+  bool DifferS(std::string const& f1, std::string const& f2);
+
+private:
+  std::unordered_map<std::string, cmFileTime> Cache;
+};
+
+#endif
diff --git a/Source/cmFileTimeComparison.cxx b/Source/cmFileTimeComparison.cxx
deleted file mode 100644
index 8b3911e..0000000
--- a/Source/cmFileTimeComparison.cxx
+++ /dev/null
@@ -1,233 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmFileTimeComparison.h"
-
-#include <string>
-#include <time.h>
-#include <unordered_map>
-#include <utility>
-
-// Use a platform-specific API to get file times efficiently.
-#if !defined(_WIN32) || defined(__CYGWIN__)
-#  include "cm_sys_stat.h"
-#  define cmFileTimeComparison_Type struct stat
-#else
-#  include "cmsys/Encoding.hxx"
-#  include <windows.h>
-#  define cmFileTimeComparison_Type FILETIME
-#endif
-
-class cmFileTimeComparisonInternal
-{
-public:
-  // Internal comparison method.
-  inline bool FileTimeCompare(const std::string& f1, const std::string& f2,
-                              int* result);
-
-  bool FileTimesDiffer(const std::string& f1, const std::string& f2);
-
-private:
-  typedef std::unordered_map<std::string, cmFileTimeComparison_Type>
-    FileStatsMap;
-  FileStatsMap Files;
-
-  // Internal methods to lookup and compare modification times.
-  inline bool Stat(const std::string& fname, cmFileTimeComparison_Type* st);
-  inline int Compare(cmFileTimeComparison_Type* st1,
-                     cmFileTimeComparison_Type* st2);
-  inline bool TimesDiffer(cmFileTimeComparison_Type* st1,
-                          cmFileTimeComparison_Type* st2);
-};
-
-bool cmFileTimeComparisonInternal::Stat(const std::string& fname,
-                                        cmFileTimeComparison_Type* st)
-{
-  // Use the stored time if available.
-  cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
-    this->Files.find(fname);
-  if (fit != this->Files.end()) {
-    *st = fit->second;
-    return true;
-  }
-
-#if !defined(_WIN32) || defined(__CYGWIN__)
-  // POSIX version.  Use the stat function.
-  int res = ::stat(fname.c_str(), st);
-  if (res != 0) {
-    return false;
-  }
-#else
-  // Windows version.  Get the modification time from extended file
-  // attributes.
-  WIN32_FILE_ATTRIBUTE_DATA fdata;
-  if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fname).c_str(),
-                            GetFileExInfoStandard, &fdata)) {
-    return false;
-  }
-
-  // Copy the file time to the output location.
-  *st = fdata.ftLastWriteTime;
-#endif
-
-  // Store the time for future use.
-  this->Files[fname] = *st;
-  return true;
-}
-
-cmFileTimeComparison::cmFileTimeComparison()
-{
-  this->Internals = new cmFileTimeComparisonInternal;
-}
-
-cmFileTimeComparison::~cmFileTimeComparison()
-{
-  delete this->Internals;
-}
-
-bool cmFileTimeComparison::FileTimeCompare(const std::string& f1,
-                                           const std::string& f2, int* result)
-{
-  return this->Internals->FileTimeCompare(f1, f2, result);
-}
-
-bool cmFileTimeComparison::FileTimesDiffer(const std::string& f1,
-                                           const std::string& f2)
-{
-  return this->Internals->FileTimesDiffer(f1, f2);
-}
-
-int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1,
-                                          cmFileTimeComparison_Type* s2)
-{
-#if !defined(_WIN32) || defined(__CYGWIN__)
-#  if CMake_STAT_HAS_ST_MTIM
-  // Compare using nanosecond resolution.
-  if (s1->st_mtim.tv_sec < s2->st_mtim.tv_sec) {
-    return -1;
-  }
-  if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) {
-    return 1;
-  }
-  if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) {
-    return -1;
-  }
-  if (s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec) {
-    return 1;
-  }
-#  elif CMake_STAT_HAS_ST_MTIMESPEC
-  // Compare using nanosecond resolution.
-  if (s1->st_mtimespec.tv_sec < s2->st_mtimespec.tv_sec) {
-    return -1;
-  }
-  if (s1->st_mtimespec.tv_sec > s2->st_mtimespec.tv_sec) {
-    return 1;
-  }
-  if (s1->st_mtimespec.tv_nsec < s2->st_mtimespec.tv_nsec) {
-    return -1;
-  }
-  if (s1->st_mtimespec.tv_nsec > s2->st_mtimespec.tv_nsec) {
-    return 1;
-  }
-#  else
-  // Compare using 1 second resolution.
-  if (s1->st_mtime < s2->st_mtime) {
-    return -1;
-  }
-  if (s1->st_mtime > s2->st_mtime) {
-    return 1;
-  }
-#  endif
-  // Files have the same time.
-  return 0;
-#else
-  // Compare using system-provided function.
-  return (int)CompareFileTime(s1, s2);
-#endif
-}
-
-bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type* s1,
-                                               cmFileTimeComparison_Type* s2)
-{
-#if !defined(_WIN32) || defined(__CYGWIN__)
-#  if CMake_STAT_HAS_ST_MTIM
-  // Times are integers in units of 1ns.
-  long long bil = 1000000000;
-  long long t1 = s1->st_mtim.tv_sec * bil + s1->st_mtim.tv_nsec;
-  long long t2 = s2->st_mtim.tv_sec * bil + s2->st_mtim.tv_nsec;
-  if (t1 < t2) {
-    return (t2 - t1) >= bil;
-  }
-  if (t2 < t1) {
-    return (t1 - t2) >= bil;
-  }
-  return false;
-#  elif CMake_STAT_HAS_ST_MTIMESPEC
-  // Times are integers in units of 1ns.
-  long long bil = 1000000000;
-  long long t1 = s1->st_mtimespec.tv_sec * bil + s1->st_mtimespec.tv_nsec;
-  long long t2 = s2->st_mtimespec.tv_sec * bil + s2->st_mtimespec.tv_nsec;
-  if (t1 < t2) {
-    return (t2 - t1) >= bil;
-  }
-  if (t2 < t1) {
-    return (t1 - t2) >= bil;
-  }
-  return false;
-#  else
-  // Times are integers in units of 1s.
-  if (s1->st_mtime < s2->st_mtime) {
-    return (s2->st_mtime - s1->st_mtime) >= 1;
-  }
-  if (s1->st_mtime > s2->st_mtime) {
-    return (s1->st_mtime - s2->st_mtime) >= 1;
-  }
-  return false;
-#  endif
-#else
-  // Times are integers in units of 100ns.
-  LARGE_INTEGER t1;
-  LARGE_INTEGER t2;
-  t1.LowPart = s1->dwLowDateTime;
-  t1.HighPart = s1->dwHighDateTime;
-  t2.LowPart = s2->dwLowDateTime;
-  t2.HighPart = s2->dwHighDateTime;
-  if (t1.QuadPart < t2.QuadPart) {
-    return (t2.QuadPart - t1.QuadPart) >= static_cast<LONGLONG>(10000000);
-  } else if (t2.QuadPart < t1.QuadPart) {
-    return (t1.QuadPart - t2.QuadPart) >= static_cast<LONGLONG>(10000000);
-  } else {
-    return false;
-  }
-#endif
-}
-
-bool cmFileTimeComparisonInternal::FileTimeCompare(const std::string& f1,
-                                                   const std::string& f2,
-                                                   int* result)
-{
-  // Get the modification time for each file.
-  cmFileTimeComparison_Type s1;
-  cmFileTimeComparison_Type s2;
-  if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) {
-    // Compare the two modification times.
-    *result = this->Compare(&s1, &s2);
-    return true;
-  }
-  // No comparison available.  Default to the same time.
-  *result = 0;
-  return false;
-}
-
-bool cmFileTimeComparisonInternal::FileTimesDiffer(const std::string& f1,
-                                                   const std::string& f2)
-{
-  // Get the modification time for each file.
-  cmFileTimeComparison_Type s1;
-  cmFileTimeComparison_Type s2;
-  if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) {
-    // Compare the two modification times.
-    return this->TimesDiffer(&s1, &s2);
-  }
-  // No comparison available.  Default to different times.
-  return true;
-}
diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h
deleted file mode 100644
index 5f74e34..0000000
--- a/Source/cmFileTimeComparison.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#ifndef cmFileTimeComparison_h
-#define cmFileTimeComparison_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-
-class cmFileTimeComparisonInternal;
-
-/** \class cmFileTimeComparison
- * \brief Helper class for comparing file modification times.
- *
- * Compare file modification times or test if file modification times differ.
- */
-class cmFileTimeComparison
-{
-public:
-  cmFileTimeComparison();
-  ~cmFileTimeComparison();
-
-  /**
-   *  Compare file modification times.
-   *  Return true for successful comparison and false for error.
-   *  When true is returned, result has -1, 0, +1 for
-   *  f1 older, same, or newer than f2.
-   */
-  bool FileTimeCompare(const std::string& f1, const std::string& f2,
-                       int* result);
-
-  /**
-   *  Compare file modification times.  Return true unless both files
-   *  exist and have modification times less than 1 second apart.
-   */
-  bool FileTimesDiffer(const std::string& f1, const std::string& f2);
-
-protected:
-  cmFileTimeComparisonInternal* Internals;
-};
-
-#endif
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 425546a..2e5e29c 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -4,12 +4,12 @@
 
 #include <deque>
 #include <iostream>
-#include <iterator>
 #include <map>
 #include <stddef.h>
 
 #include "cmAlgorithms.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSearchPath.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -205,11 +205,9 @@
   cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
 
   // Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
-  for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths =
-         this->Makefile->FindPackageRootPathStack.rbegin();
-       pkgPaths != this->Makefile->FindPackageRootPathStack.rend();
-       ++pkgPaths) {
-    paths.AddPrefixPaths(*pkgPaths);
+  for (std::vector<std::string> const& pkgPaths :
+       cmReverseRange(this->Makefile->FindPackageRootPathStack)) {
+    paths.AddPrefixPaths(pkgPaths);
   }
 
   paths.AddSuffixes(this->SearchPathSuffixes);
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
index 78be64e..9aaa000 100644
--- a/Source/cmFindCommon.cxx
+++ b/Source/cmFindCommon.cxx
@@ -310,7 +310,7 @@
 
 void AddTrailingSlash(std::string& s)
 {
-  if (!s.empty() && *s.rbegin() != '/') {
+  if (!s.empty() && s.back() != '/') {
     s += '/';
   }
 }
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index c2e0712..7ebd211 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -23,6 +23,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmSearchPath.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -466,7 +467,7 @@
     // Allocate a PACKAGE_ROOT_PATH for the current find_package call.
     this->Makefile->FindPackageRootPathStack.emplace_back();
     std::vector<std::string>& rootPaths =
-      *this->Makefile->FindPackageRootPathStack.rbegin();
+      this->Makefile->FindPackageRootPathStack.back();
 
     // Add root paths from <PackageName>_ROOT CMake and environment variables,
     // subject to CMP0074.
@@ -827,10 +828,10 @@
           << " requested version \"" << this->Version << "\".\n"
           << "The following configuration files were considered but not "
              "accepted:\n";
-        for (std::vector<ConfigFileInfo>::const_iterator i =
-               this->ConsideredConfigs.begin();
-             i != duplicate_end; ++i) {
-          e << "  " << i->filename << ", version: " << i->version << "\n";
+
+        for (ConfigFileInfo const& info :
+             cmMakeRange(this->ConsideredConfigs.cbegin(), duplicate_end)) {
+          e << "  " << info.filename << ", version: " << info.version << "\n";
         }
       } else {
         std::string requestedVersionString;
@@ -911,7 +912,7 @@
       std::ostringstream aw;
       aw << "Could NOT find " << this->Name << " (missing: " << this->Name
          << "_DIR)";
-      this->Makefile->DisplayStatus(aw.str().c_str(), -1);
+      this->Makefile->DisplayStatus(aw.str(), -1);
     }
   }
 
@@ -1372,6 +1373,9 @@
       cmSystemTools::RemoveFile(this->File);
     }
   }
+  cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
+  cmFindPackageCommandHoldFile& operator=(
+    const cmFindPackageCommandHoldFile&) = delete;
   void Release() { this->File = nullptr; }
 };
 
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index e359def..08003eb 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -11,6 +11,7 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 
 cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf)
@@ -48,12 +49,10 @@
       if (mf.GetDefinition(this->Args[0])) {
         oldDef = mf.GetDefinition(this->Args[0]);
       }
-      std::vector<std::string>::const_iterator j = this->Args.begin();
-      ++j;
 
-      for (; j != this->Args.end(); ++j) {
+      for (std::string const& arg : cmMakeRange(this->Args).advance(1)) {
         // set the variable to the loop value
-        mf.AddDefinition(this->Args[0], j->c_str());
+        mf.AddDefinition(this->Args[0], arg.c_str());
         // Invoke all the functions that were collected in the block.
         cmExecutionStatus status;
         for (cmListFileFunction const& func : this->Functions) {
diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h
index 0762340..6a33be5 100644
--- a/Source/cmFortranParser.h
+++ b/Source/cmFortranParser.h
@@ -141,6 +141,9 @@
                     std::set<std::string> defines, cmFortranSourceInfo& info);
   ~cmFortranParser_s();
 
+  cmFortranParser_s(const cmFortranParser_s&) = delete;
+  cmFortranParser_s& operator=(const cmFortranParser_s&) = delete;
+
   bool FindIncludeFile(const char* dir, const char* includeName,
                        std::string& fileName);
 
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index 264a338..9d75b72 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -8,6 +8,7 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmState.h"
 
 // define the class for function commands
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index 4fe1587..2f47788 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -29,8 +29,7 @@
 {
   // Check if the file opened.
   if (!*this && !quiet) {
-    cmSystemTools::Error("Cannot open file for write: ",
-                         this->TempName.c_str());
+    cmSystemTools::Error("Cannot open file for write: " + this->TempName);
     cmSystemTools::ReportLastSystemError("");
   }
 #ifdef CMAKE_BUILD_WITH_CMAKE
@@ -68,8 +67,7 @@
 
   // Check if the file opened.
   if (!*this && !quiet) {
-    cmSystemTools::Error("Cannot open file for write: ",
-                         this->TempName.c_str());
+    cmSystemTools::Error("Cannot open file for write: " + this->TempName);
     cmSystemTools::ReportLastSystemError("");
   }
   return *this;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index f9a6d64..268de6f 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -34,20 +34,16 @@
     std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator pend =
     this->ParamChildren.end();
   for (; pit != pend; ++pit) {
-    std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
-      pit->begin();
-    const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
-      pit->end();
-    for (; it != end; ++it) {
+    for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
       if (node->RequiresLiteralInput()) {
-        if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) {
+        if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
           reportError(context, this->GetOriginalExpression(),
                       "$<" + identifier +
                         "> expression requires literal input.");
           return std::string();
         }
       }
-      result += (*it)->Evaluate(context, dagChecker);
+      result += pExprEval->Evaluate(context, dagChecker);
       if (context->HadError) {
         return std::string();
       }
@@ -70,12 +66,9 @@
 {
   std::string identifier;
   {
-    std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
-      this->IdentifierChildren.begin();
-    const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
-      this->IdentifierChildren.end();
-    for (; it != end; ++it) {
-      identifier += (*it)->Evaluate(context, dagChecker);
+    for (cmGeneratorExpressionEvaluator* pExprEval :
+         this->IdentifierChildren) {
+      identifier += pExprEval->Evaluate(context, dagChecker);
       if (context->HadError) {
         return std::string();
       }
@@ -138,12 +131,8 @@
         return std::string();
       }
       std::string parameter;
-      std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
-        pit->begin();
-      const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
-        pit->end();
-      for (; it != end; ++it) {
-        parameter += (*it)->Evaluate(context, dagChecker);
+      for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
+        parameter += pExprEval->Evaluate(context, dagChecker);
         if (context->HadError) {
           return std::string();
         }
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 70c80c9..af409e4 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -15,6 +15,9 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -25,6 +28,7 @@
 #include <algorithm>
 #include <assert.h>
 #include <errno.h>
+#include <iterator>
 #include <map>
 #include <memory> // IWYU pragma: keep
 #include <set>
@@ -103,13 +107,11 @@
                          const GeneratorExpressionContent* content,           \
                          cmGeneratorExpressionDAGChecker*) const              \
     {                                                                         \
-      std::vector<std::string>::const_iterator it = parameters.begin();       \
-      const std::vector<std::string>::const_iterator end = parameters.end();  \
-      for (; it != end; ++it) {                                               \
-        if (*it == #FAILURE_VALUE) {                                          \
+      for (std::string const& param : parameters) {                           \
+        if (param == #FAILURE_VALUE) {                                        \
           return #FAILURE_VALUE;                                              \
         }                                                                     \
-        if (*it != #SUCCESS_VALUE) {                                          \
+        if (param != #SUCCESS_VALUE) {                                        \
           reportError(context, content->GetOriginalExpression(),              \
                       "Parameters to $<" #OP                                  \
                       "> must resolve to either '0' or '1'.");                \
@@ -135,13 +137,13 @@
     const GeneratorExpressionContent* content,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    if (*parameters.begin() != "0" && *parameters.begin() != "1") {
+    if (parameters.front() != "0" && parameters.front() != "1") {
       reportError(
         context, content->GetOriginalExpression(),
         "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
       return std::string();
     }
-    return *parameters.begin() == "0" ? "1" : "0";
+    return parameters.front() == "0" ? "1" : "0";
   }
 } notNode;
 
@@ -157,7 +159,7 @@
     const GeneratorExpressionContent* /*content*/,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    return !cmSystemTools::IsOff(*parameters.begin()) ? "1" : "0";
+    return !cmSystemTools::IsOff(parameters.front()) ? "1" : "0";
   }
 } boolNode;
 
@@ -194,7 +196,7 @@
     const GeneratorExpressionContent* /*content*/,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    return *parameters.begin() == parameters[1] ? "1" : "0";
+    return parameters.front() == parameters[1] ? "1" : "0";
   }
 } strEqualNode;
 
@@ -326,6 +328,79 @@
   }
 } inListNode;
 
+static const struct FilterNode : public cmGeneratorExpressionNode
+{
+  FilterNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 3; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    if (parameters.size() != 3) {
+      reportError(context, content->GetOriginalExpression(),
+                  "$<FILTER:...> expression requires three parameters");
+      return {};
+    }
+
+    if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
+      reportError(
+        context, content->GetOriginalExpression(),
+        "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
+      return {};
+    }
+
+    const bool exclude = parameters[1] == "EXCLUDE";
+
+    cmsys::RegularExpression re;
+    if (!re.compile(parameters[2])) {
+      reportError(context, content->GetOriginalExpression(),
+                  "$<FILTER:...> failed to compile regex");
+      return {};
+    }
+
+    std::vector<std::string> values, result;
+    cmSystemTools::ExpandListArgument(parameters.front(), values, true);
+
+    std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result),
+                 [&re, exclude](std::string const& input) {
+                   return exclude ^ re.find(input);
+                 });
+    return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";");
+  }
+} filterNode;
+
+static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
+{
+  RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 1; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    if (parameters.size() != 1) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        "$<REMOVE_DUPLICATES:...> expression requires one parameter");
+    }
+
+    std::vector<std::string> values;
+    cmSystemTools::ExpandListArgument(parameters.front(), values, true);
+
+    auto valuesEnd = cmRemoveDuplicates(values);
+    auto valuesBegin = values.cbegin();
+    return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";");
+  }
+
+} removeDuplicatesNode;
+
 static const struct TargetExistsNode : public cmGeneratorExpressionNode
 {
   TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
@@ -613,7 +688,7 @@
       return compilerId;
     }
     static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
-    if (!compilerIdValidator.find(*parameters.begin())) {
+    if (!compilerIdValidator.find(parameters.front())) {
       reportError(context, content->GetOriginalExpression(),
                   "Expression syntax not recognized.");
       return std::string();
@@ -622,11 +697,11 @@
       return parameters.front().empty() ? "1" : "0";
     }
 
-    if (strcmp(parameters.begin()->c_str(), compilerId.c_str()) == 0) {
+    if (strcmp(parameters.front().c_str(), compilerId.c_str()) == 0) {
       return "1";
     }
 
-    if (cmsysString_strcasecmp(parameters.begin()->c_str(),
+    if (cmsysString_strcasecmp(parameters.front().c_str(),
                                compilerId.c_str()) == 0) {
       switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
         case cmPolicies::WARN: {
@@ -692,6 +767,28 @@
   }
 } cxxCompilerIdNode;
 
+static const struct CUDACompilerIdNode : public CompilerIdNode
+{
+  CUDACompilerIdNode() {} // NOLINT(modernize-use-equals-default)
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        "$<CUDA_COMPILER_ID> may only be used with binary targets.  It may "
+        "not be used with add_custom_command or add_custom_target.");
+      return std::string();
+    }
+    return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+                                      "CUDA");
+  }
+} cudaCompilerIdNode;
+
 static const struct FortranCompilerIdNode : public CompilerIdNode
 {
   FortranCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
@@ -734,7 +831,7 @@
     }
 
     static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
-    if (!compilerIdValidator.find(*parameters.begin())) {
+    if (!compilerIdValidator.find(parameters.front())) {
       reportError(context, content->GetOriginalExpression(),
                   "Expression syntax not recognized.");
       return std::string();
@@ -744,7 +841,7 @@
     }
 
     return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
-                                         parameters.begin()->c_str(),
+                                         parameters.front().c_str(),
                                          compilerVersion.c_str())
       ? "1"
       : "0";
@@ -773,9 +870,9 @@
   }
 } cCompilerVersionNode;
 
-static const struct CxxCompilerVersionNode : public CompilerVersionNode
+static const struct CXXCompilerVersionNode : public CompilerVersionNode
 {
-  CxxCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
+  CXXCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
 
   std::string Evaluate(
     const std::vector<std::string>& parameters,
@@ -795,6 +892,28 @@
   }
 } cxxCompilerVersionNode;
 
+static const struct CUDACompilerVersionNode : public CompilerVersionNode
+{
+  CUDACompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        "$<CUDA_COMPILER_VERSION> may only be used with binary targets.  It "
+        "may not be used with add_custom_command or add_custom_target.");
+      return std::string();
+    }
+    return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+                                      "CUDA");
+  }
+} cudaCompilerVersionNode;
+
 static const struct FortranCompilerVersionNode : public CompilerVersionNode
 {
   FortranCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
@@ -839,7 +958,7 @@
       return parameters.front().empty() ? "1" : "0";
     }
 
-    if (*parameters.begin() == platformId) {
+    if (parameters.front() == platformId) {
       return "1";
     }
     return "0";
@@ -1001,7 +1120,7 @@
       return configurationNode.Evaluate(parameters, context, content, nullptr);
     }
     static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
-    if (!configValidator.find(*parameters.begin())) {
+    if (!configValidator.find(parameters.front())) {
       reportError(context, content->GetOriginalExpression(),
                   "Expression syntax not recognized.");
       return std::string();
@@ -1011,7 +1130,7 @@
       return parameters.front().empty() ? "1" : "0";
     }
 
-    if (cmsysString_strcasecmp(parameters.begin()->c_str(),
+    if (cmsysString_strcasecmp(parameters.front().c_str(),
                                context->Config.c_str()) == 0) {
       return "1";
     }
@@ -1166,7 +1285,7 @@
     static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
 
     cmGeneratorTarget const* target = context->HeadTarget;
-    std::string propertyName = *parameters.begin();
+    std::string propertyName = parameters.front();
 
     if (parameters.size() == 1) {
       context->HadHeadSensitiveCondition = true;
@@ -1182,14 +1301,14 @@
     }
 
     if (parameters.size() == 2) {
-      if (parameters.begin()->empty() && parameters[1].empty()) {
+      if (parameters.front().empty() && parameters[1].empty()) {
         reportError(
           context, content->GetOriginalExpression(),
           "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
           "target name and property name.");
         return std::string();
       }
-      if (parameters.begin()->empty()) {
+      if (parameters.front().empty()) {
         reportError(
           context, content->GetOriginalExpression(),
           "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
@@ -1950,8 +2069,54 @@
   static std::string Get(const std::string& result) { return result; }
 };
 
+struct TargetArtifactBase : public cmGeneratorExpressionNode
+{
+  TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
+
+protected:
+  cmGeneratorTarget* GetTarget(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const
+  {
+    // Lookup the referenced target.
+    std::string name = parameters.front();
+
+    if (!cmGeneratorExpression::IsValidTargetName(name)) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "Expression syntax not recognized.");
+      return nullptr;
+    }
+    cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
+    if (!target) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "No target \"" + name + "\"");
+      return nullptr;
+    }
+    if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
+        target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "Target \"" + name +
+                      "\" is not an executable or library.");
+      return nullptr;
+    }
+    if (dagChecker &&
+        (dagChecker->EvaluatingLinkLibraries(target) ||
+         (dagChecker->EvaluatingSources() &&
+          target == dagChecker->TopTarget()))) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "Expressions which require the linker language may not "
+                    "be used while evaluating link libraries");
+      return nullptr;
+    }
+
+    return target;
+  }
+};
+
 template <typename ArtifactT, typename ComponentT>
-struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
+struct TargetFilesystemArtifact : public TargetArtifactBase
 {
   TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
 
@@ -1963,34 +2128,9 @@
     const GeneratorExpressionContent* content,
     cmGeneratorExpressionDAGChecker* dagChecker) const override
   {
-    // Lookup the referenced target.
-    std::string name = *parameters.begin();
-
-    if (!cmGeneratorExpression::IsValidTargetName(name)) {
-      ::reportError(context, content->GetOriginalExpression(),
-                    "Expression syntax not recognized.");
-      return std::string();
-    }
-    cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
+    cmGeneratorTarget* target =
+      this->GetTarget(parameters, context, content, dagChecker);
     if (!target) {
-      ::reportError(context, content->GetOriginalExpression(),
-                    "No target \"" + name + "\"");
-      return std::string();
-    }
-    if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
-        target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
-      ::reportError(context, content->GetOriginalExpression(),
-                    "Target \"" + name +
-                      "\" is not an executable or library.");
-      return std::string();
-    }
-    if (dagChecker &&
-        (dagChecker->EvaluatingLinkLibraries(target) ||
-         (dagChecker->EvaluatingSources() &&
-          target == dagChecker->TopTarget()))) {
-      ::reportError(context, content->GetOriginalExpression(),
-                    "Expressions which require the linker language may not "
-                    "be used while evaluating link libraries");
       return std::string();
     }
     context->DependTargets.insert(target);
@@ -2037,6 +2177,239 @@
                                       ArtifactPathTag>
   targetBundleContentDirNode;
 
+//
+// To retrieve base name for various artifacts
+//
+template <typename ArtifactT>
+struct TargetOutputNameArtifactResultGetter
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* /*unused*/)
+  {
+    return target->GetOutputName(context->Config,
+                                 cmStateEnums::RuntimeBinaryArtifact);
+  }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content)
+  {
+    // The file used to link to the target (.so, .lib, .a).
+    if (!target->IsLinkable()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_LINKER_OUTPUT_NAME is allowed only for libraries "
+                    "and executables with ENABLE_EXPORTS.");
+      return std::string();
+    }
+    cmStateEnums::ArtifactType artifact =
+      target->HasImportLibrary(context->Config)
+      ? cmStateEnums::ImportLibraryArtifact
+      : cmStateEnums::RuntimeBinaryArtifact;
+    return target->GetOutputName(context->Config, artifact);
+  }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content)
+  {
+    if (target->IsImported()) {
+      ::reportError(
+        context, content->GetOriginalExpression(),
+        "TARGET_PDB_OUTPUT_NAME not allowed for IMPORTED targets.");
+      return std::string();
+    }
+
+    std::string language = target->GetLinkerLanguage(context->Config);
+
+    std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+
+    if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+      ::reportError(
+        context, content->GetOriginalExpression(),
+        "TARGET_PDB_OUTPUT_NAME is not supported by the target linker.");
+      return std::string();
+    }
+
+    cmStateEnums::TargetType targetType = target->GetType();
+
+    if (targetType != cmStateEnums::SHARED_LIBRARY &&
+        targetType != cmStateEnums::MODULE_LIBRARY &&
+        targetType != cmStateEnums::EXECUTABLE) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_PDB_OUTPUT_NAME is allowed only for "
+                    "targets with linker created artifacts.");
+      return std::string();
+    }
+
+    return target->GetPDBOutputName(context->Config);
+  }
+};
+
+template <typename ArtifactT>
+struct TargetOutputNameArtifact : public TargetArtifactBase
+{
+  TargetOutputNameArtifact() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 1; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    cmGeneratorTarget* target =
+      this->GetTarget(parameters, context, content, dagChecker);
+    if (!target) {
+      return std::string();
+    }
+
+    std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
+      target, context, content);
+    if (context->HadError) {
+      return std::string();
+    }
+    return result;
+  }
+};
+
+static const TargetOutputNameArtifact<ArtifactNameTag> targetOutputNameNode;
+
+static const TargetOutputNameArtifact<ArtifactLinkerTag>
+  targetLinkerOutputNameNode;
+
+static const TargetOutputNameArtifact<ArtifactPdbTag> targetPdbOutputNameNode;
+
+class ArtifactFilePrefixTag;
+class ArtifactLinkerFilePrefixTag;
+class ArtifactFileSuffixTag;
+class ArtifactLinkerFileSuffixTag;
+
+template <typename ArtifactT>
+struct TargetFileArtifactResultGetter
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent*)
+  {
+    return target->GetFilePrefix(context->Config);
+  }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content)
+  {
+    if (!target->IsLinkable()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_LINKER_PREFIX is allowed only for libraries and "
+                    "executables with ENABLE_EXPORTS.");
+      return std::string();
+    }
+
+    cmStateEnums::ArtifactType artifact =
+      target->HasImportLibrary(context->Config)
+      ? cmStateEnums::ImportLibraryArtifact
+      : cmStateEnums::RuntimeBinaryArtifact;
+
+    return target->GetFilePrefix(context->Config, artifact);
+  }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent*)
+  {
+    return target->GetFileSuffix(context->Config);
+  }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content)
+  {
+    if (!target->IsLinkable()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_LINKER_SUFFIX is allowed only for libraries and "
+                    "executables with ENABLE_EXPORTS.");
+      return std::string();
+    }
+
+    cmStateEnums::ArtifactType artifact =
+      target->HasImportLibrary(context->Config)
+      ? cmStateEnums::ImportLibraryArtifact
+      : cmStateEnums::RuntimeBinaryArtifact;
+
+    return target->GetFileSuffix(context->Config, artifact);
+  }
+};
+
+template <typename ArtifactT>
+struct TargetFileArtifact : public TargetArtifactBase
+{
+  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 1; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    cmGeneratorTarget* target =
+      this->GetTarget(parameters, context, content, dagChecker);
+    if (!target) {
+      return std::string();
+    }
+
+    std::string result =
+      TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content);
+    if (context->HadError) {
+      return std::string();
+    }
+    return result;
+  }
+};
+
+static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
+  targetLinkerFilePrefixNode;
+static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
+  targetLinkerFileSuffixNode;
+
 static const struct ShellPathNode : public cmGeneratorExpressionNode
 {
   ShellPathNode() {} // NOLINT(modernize-use-equals-default)
@@ -2047,88 +2420,114 @@
     const GeneratorExpressionContent* content,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    if (!cmSystemTools::FileIsFullPath(parameters.front())) {
+    std::vector<std::string> listIn;
+    cmSystemTools::ExpandListArgument(parameters.front(), listIn);
+    if (listIn.empty()) {
       reportError(context, content->GetOriginalExpression(),
-                  "\"" + parameters.front() + "\" is not an absolute path.");
+                  "\"\" is not an absolute path.");
       return std::string();
     }
-    cmOutputConverter converter(context->LG->GetStateSnapshot());
-    return converter.ConvertDirectorySeparatorsForShell(parameters.front());
+    cmStateSnapshot snapshot = context->LG->GetStateSnapshot();
+    cmOutputConverter converter(snapshot);
+    const char* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
+    std::vector<std::string> listOut;
+    listOut.reserve(listIn.size());
+    for (auto const& in : listIn) {
+      if (!cmSystemTools::FileIsFullPath(in)) {
+        reportError(context, content->GetOriginalExpression(),
+                    "\"" + in + "\" is not an absolute path.");
+        return std::string();
+      }
+      listOut.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
+    }
+    return cmJoin(listOut, separator);
   }
 } shellPathNode;
 
 const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
   const std::string& identifier)
 {
-  typedef std::map<std::string, const cmGeneratorExpressionNode*> NodeMap;
-  static NodeMap nodeMap;
-  if (nodeMap.empty()) {
-    nodeMap["0"] = &zeroNode;
-    nodeMap["1"] = &oneNode;
-    nodeMap["AND"] = &andNode;
-    nodeMap["OR"] = &orNode;
-    nodeMap["NOT"] = &notNode;
-    nodeMap["C_COMPILER_ID"] = &cCompilerIdNode;
-    nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode;
-    nodeMap["Fortran_COMPILER_ID"] = &fortranCompilerIdNode;
-    nodeMap["VERSION_GREATER"] = &versionGreaterNode;
-    nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode;
-    nodeMap["VERSION_LESS"] = &versionLessNode;
-    nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode;
-    nodeMap["VERSION_EQUAL"] = &versionEqualNode;
-    nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode;
-    nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode;
-    nodeMap["Fortran_COMPILER_VERSION"] = &fortranCompilerVersionNode;
-    nodeMap["PLATFORM_ID"] = &platformIdNode;
-    nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode;
-    nodeMap["CONFIGURATION"] = &configurationNode;
-    nodeMap["CONFIG"] = &configurationTestNode;
-    nodeMap["TARGET_FILE"] = &targetNodeGroup.File;
-    nodeMap["TARGET_LINKER_FILE"] = &targetLinkerNodeGroup.File;
-    nodeMap["TARGET_SONAME_FILE"] = &targetSoNameNodeGroup.File;
-    nodeMap["TARGET_PDB_FILE"] = &targetPdbNodeGroup.File;
-    nodeMap["TARGET_FILE_NAME"] = &targetNodeGroup.FileName;
-    nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerNodeGroup.FileName;
-    nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameNodeGroup.FileName;
-    nodeMap["TARGET_PDB_FILE_NAME"] = &targetPdbNodeGroup.FileName;
-    nodeMap["TARGET_FILE_DIR"] = &targetNodeGroup.FileDir;
-    nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir;
-    nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir;
-    nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir;
-    nodeMap["TARGET_BUNDLE_DIR"] = &targetBundleDirNode;
-    nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode;
-    nodeMap["STREQUAL"] = &strEqualNode;
-    nodeMap["EQUAL"] = &equalNode;
-    nodeMap["IN_LIST"] = &inListNode;
-    nodeMap["LOWER_CASE"] = &lowerCaseNode;
-    nodeMap["UPPER_CASE"] = &upperCaseNode;
-    nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
-    nodeMap["BOOL"] = &boolNode;
-    nodeMap["IF"] = &ifNode;
-    nodeMap["ANGLE-R"] = &angle_rNode;
-    nodeMap["COMMA"] = &commaNode;
-    nodeMap["SEMICOLON"] = &semicolonNode;
-    nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
-    nodeMap["TARGET_NAME"] = &targetNameNode;
-    nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
-    nodeMap["TARGET_POLICY"] = &targetPolicyNode;
-    nodeMap["TARGET_EXISTS"] = &targetExistsNode;
-    nodeMap["TARGET_NAME_IF_EXISTS"] = &targetNameIfExistsNode;
-    nodeMap["TARGET_GENEX_EVAL"] = &targetGenexEvalNode;
-    nodeMap["GENEX_EVAL"] = &genexEvalNode;
-    nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
-    nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;
-    nodeMap["INSTALL_PREFIX"] = &installPrefixNode;
-    nodeMap["JOIN"] = &joinNode;
-    nodeMap["LINK_ONLY"] = &linkOnlyNode;
-    nodeMap["COMPILE_LANGUAGE"] = &languageNode;
-    nodeMap["SHELL_PATH"] = &shellPathNode;
+  static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
+    { "0", &zeroNode },
+    { "1", &oneNode },
+    { "AND", &andNode },
+    { "OR", &orNode },
+    { "NOT", &notNode },
+    { "C_COMPILER_ID", &cCompilerIdNode },
+    { "CXX_COMPILER_ID", &cxxCompilerIdNode },
+    { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
+    { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
+    { "VERSION_GREATER", &versionGreaterNode },
+    { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
+    { "VERSION_LESS", &versionLessNode },
+    { "VERSION_LESS_EQUAL", &versionLessEqNode },
+    { "VERSION_EQUAL", &versionEqualNode },
+    { "C_COMPILER_VERSION", &cCompilerVersionNode },
+    { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
+    { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
+    { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
+    { "PLATFORM_ID", &platformIdNode },
+    { "COMPILE_FEATURES", &compileFeaturesNode },
+    { "CONFIGURATION", &configurationNode },
+    { "CONFIG", &configurationTestNode },
+    { "TARGET_FILE", &targetNodeGroup.File },
+    { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
+    { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
+    { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
+    { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
+    { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
+    { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
+    { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
+    { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
+    { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
+    { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
+    { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
+    { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
+    { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
+    { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
+    { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
+    { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
+    { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
+    { "TARGET_OUTPUT_NAME", &targetOutputNameNode },
+    { "TARGET_LINKER_OUTPUT_NAME", &targetLinkerOutputNameNode },
+    { "TARGET_PDB_OUTPUT_NAME", &targetPdbOutputNameNode },
+    { "STREQUAL", &strEqualNode },
+    { "EQUAL", &equalNode },
+    { "IN_LIST", &inListNode },
+    { "FILTER", &filterNode },
+    { "REMOVE_DUPLICATES", &removeDuplicatesNode },
+    { "LOWER_CASE", &lowerCaseNode },
+    { "UPPER_CASE", &upperCaseNode },
+    { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
+    { "BOOL", &boolNode },
+    { "IF", &ifNode },
+    { "ANGLE-R", &angle_rNode },
+    { "COMMA", &commaNode },
+    { "SEMICOLON", &semicolonNode },
+    { "TARGET_PROPERTY", &targetPropertyNode },
+    { "TARGET_NAME", &targetNameNode },
+    { "TARGET_OBJECTS", &targetObjectsNode },
+    { "TARGET_POLICY", &targetPolicyNode },
+    { "TARGET_EXISTS", &targetExistsNode },
+    { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
+    { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
+    { "GENEX_EVAL", &genexEvalNode },
+    { "BUILD_INTERFACE", &buildInterfaceNode },
+    { "INSTALL_INTERFACE", &installInterfaceNode },
+    { "INSTALL_PREFIX", &installPrefixNode },
+    { "JOIN", &joinNode },
+    { "LINK_ONLY", &linkOnlyNode },
+    { "COMPILE_LANGUAGE", &languageNode },
+    { "SHELL_PATH", &shellPathNode }
+  };
+
+  {
+    auto itr = nodeMap.find(identifier);
+    if (itr != nodeMap.end()) {
+      return itr->second;
+    }
   }
-  NodeMap::const_iterator i = nodeMap.find(identifier);
-  if (i == nodeMap.end()) {
-    return nullptr;
-  }
-  return i->second;
+  return nullptr;
 }
 
 void reportError(cmGeneratorExpressionContext* context,
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
index 949a86d..7aa3314 100644
--- a/Source/cmGeneratorExpressionParser.cxx
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -47,11 +47,11 @@
   if (!result.empty() &&
       (*(result.end() - 1))->GetType() ==
         cmGeneratorExpressionEvaluator::Text &&
-      (*contents.begin())->GetType() == cmGeneratorExpressionEvaluator::Text) {
+      contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
     TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
     textContent->Extend(
-      static_cast<TextContent*>(*contents.begin())->GetLength());
-    delete *contents.begin();
+      static_cast<TextContent*>(contents.front())->GetLength());
+    delete contents.front();
     result.insert(result.end(), contents.begin() + 1, contents.end());
   } else {
     result.insert(result.end(), contents.begin(), contents.end());
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 25349d4..3fb95bf 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -28,6 +28,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPropertyMap.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
 #include "cmState.h"
@@ -64,20 +65,137 @@
 
 class cmGeneratorTarget::TargetPropertyEntry
 {
+protected:
   static cmLinkImplItem NoLinkImplItem;
 
 public:
-  TargetPropertyEntry(std::unique_ptr<cmCompiledGeneratorExpression> cge,
-                      cmLinkImplItem const& item = NoLinkImplItem)
-    : ge(std::move(cge))
-    , LinkImplItem(item)
+  TargetPropertyEntry(cmLinkImplItem const& item)
+    : LinkImplItem(item)
   {
   }
-  const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+  virtual ~TargetPropertyEntry() = default;
+
+  virtual const std::string& Evaluate(
+    cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+    cmGeneratorTarget const* headTarget = nullptr,
+    cmGeneratorTarget const* currentTarget = nullptr,
+    cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+    std::string const& language = std::string()) const = 0;
+  virtual const std::string& Evaluate(
+    cmLocalGenerator* lg, const std::string& config, bool quiet,
+    cmGeneratorTarget const* headTarget,
+    cmGeneratorExpressionDAGChecker* dagChecker,
+    std::string const& language = std::string()) const = 0;
+
+  virtual cmListFileBacktrace GetBacktrace() const = 0;
+  virtual std::string const& GetInput() const = 0;
+  virtual bool GetHadContextSensitiveCondition() const { return false; }
+
   cmLinkImplItem const& LinkImplItem;
+
+private:
+  cmListFileBacktrace Backtrace;
 };
 cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
 
+class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+  TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
+                           cmLinkImplItem const& item = NoLinkImplItem)
+    : cmGeneratorTarget::TargetPropertyEntry(item)
+    , ge(std::move(cge))
+  {
+  }
+
+  const std::string& Evaluate(
+    cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+    cmGeneratorTarget const* headTarget = nullptr,
+    cmGeneratorTarget const* currentTarget = nullptr,
+    cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+    std::string const& language = std::string()) const override
+  {
+    return this->ge->Evaluate(lg, config, quiet, headTarget, currentTarget,
+                              dagChecker, language);
+  }
+  const std::string& Evaluate(
+    cmLocalGenerator* lg, const std::string& config, bool quiet,
+    cmGeneratorTarget const* headTarget,
+    cmGeneratorExpressionDAGChecker* dagChecker,
+    std::string const& language = std::string()) const override
+  {
+    return this->ge->Evaluate(lg, config, quiet, headTarget, dagChecker,
+                              language);
+  }
+
+  cmListFileBacktrace GetBacktrace() const override
+  {
+    return this->ge->GetBacktrace();
+  }
+
+  std::string const& GetInput() const override { return this->ge->GetInput(); }
+
+  bool GetHadContextSensitiveCondition() const override
+  {
+    return this->ge->GetHadContextSensitiveCondition();
+  }
+
+private:
+  const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+};
+
+class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+  TargetPropertyEntryString(std::string propertyValue,
+                            cmListFileBacktrace backtrace,
+                            cmLinkImplItem const& item = NoLinkImplItem)
+    : cmGeneratorTarget::TargetPropertyEntry(item)
+    , PropertyValue(std::move(propertyValue))
+    , Backtrace(std::move(backtrace))
+  {
+  }
+
+  const std::string& Evaluate(cmLocalGenerator*, const std::string&, bool,
+                              cmGeneratorTarget const*,
+                              cmGeneratorTarget const*,
+                              cmGeneratorExpressionDAGChecker*,
+                              std::string const&) const override
+  {
+    return this->PropertyValue;
+  }
+  const std::string& Evaluate(cmLocalGenerator*, const std::string&, bool,
+                              cmGeneratorTarget const*,
+                              cmGeneratorExpressionDAGChecker*,
+                              std::string const&) const override
+  {
+    return this->PropertyValue;
+  }
+
+  cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
+  std::string const& GetInput() const override { return this->PropertyValue; }
+
+private:
+  std::string PropertyValue;
+  cmListFileBacktrace Backtrace;
+};
+
+cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry(
+  const std::string& propertyValue,
+  cmListFileBacktrace backtrace = cmListFileBacktrace(),
+  bool evaluateForBuildsystem = false)
+{
+  if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
+    cmGeneratorExpression ge(std::move(backtrace));
+    std::unique_ptr<cmCompiledGeneratorExpression> cge =
+      ge.Parse(propertyValue);
+    cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
+    return new TargetPropertyEntryGenex(std::move(cge));
+  }
+
+  return new TargetPropertyEntryString(propertyValue, backtrace);
+}
+
 void CreatePropertyGeneratorExpressions(
   cmStringRange entries, cmBacktraceRange backtraces,
   std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
@@ -86,11 +204,8 @@
   std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin();
   for (std::vector<std::string>::const_iterator it = entries.begin();
        it != entries.end(); ++it, ++btIt) {
-    cmGeneratorExpression ge(*btIt);
-    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
-    cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
     items.push_back(
-      new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+      CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
   }
 }
 
@@ -147,7 +262,7 @@
   this->DLLPlatform =
     !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
 
-  this->PolicyMap = t->PolicyMap;
+  this->PolicyMap = t->GetPolicyMap();
 }
 
 cmGeneratorTarget::~cmGeneratorTarget()
@@ -166,7 +281,7 @@
 {
   std::vector<std::string> values;
   for (TargetPropertyEntry* se : this->SourceEntries) {
-    values.push_back(se->ge->GetInput());
+    values.push_back(se->GetInput());
   }
   static std::string value;
   value.clear();
@@ -349,6 +464,134 @@
   return i->second;
 }
 
+std::string cmGeneratorTarget::GetFilePrefix(
+  const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+  if (this->IsImported()) {
+    const char* prefix = this->GetFilePrefixInternal(artifact);
+
+    return prefix ? prefix : std::string();
+  }
+
+  std::string prefix, suffix, base;
+  this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+  return prefix;
+}
+std::string cmGeneratorTarget::GetFileSuffix(
+  const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+  if (this->IsImported()) {
+    const char* suffix = this->GetFileSuffixInternal(artifact);
+
+    return suffix ? suffix : std::string();
+  }
+
+  std::string prefix, suffix, base;
+  this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+  return suffix;
+}
+
+const char* cmGeneratorTarget::GetFilePrefixInternal(
+  cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+  // no prefix for non-main target types.
+  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    return nullptr;
+  }
+
+  const bool isImportedLibraryArtifact =
+    (artifact == cmStateEnums::ImportLibraryArtifact);
+
+  // Return an empty prefix for the import library if this platform
+  // does not support import libraries.
+  if (isImportedLibraryArtifact &&
+      !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+    return nullptr;
+  }
+
+  // The implib option is only allowed for shared libraries, module
+  // libraries, and executables.
+  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    artifact = cmStateEnums::RuntimeBinaryArtifact;
+  }
+
+  // Compute prefix value.
+  const char* targetPrefix =
+    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
+                               : this->GetProperty("PREFIX"));
+
+  if (!targetPrefix) {
+    const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
+    if (!language.empty() && prefixVar && *prefixVar) {
+      std::string langPrefix = prefixVar + std::string("_") + language;
+      targetPrefix = this->Makefile->GetDefinition(langPrefix);
+    }
+
+    // if there is no prefix on the target nor specific language
+    // use the cmake definition.
+    if (!targetPrefix && prefixVar) {
+      targetPrefix = this->Makefile->GetDefinition(prefixVar);
+    }
+  }
+
+  return targetPrefix;
+}
+const char* cmGeneratorTarget::GetFileSuffixInternal(
+  cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+  // no suffix for non-main target types.
+  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    return nullptr;
+  }
+
+  const bool isImportedLibraryArtifact =
+    (artifact == cmStateEnums::ImportLibraryArtifact);
+
+  // Return an empty suffix for the import library if this platform
+  // does not support import libraries.
+  if (isImportedLibraryArtifact &&
+      !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+    return nullptr;
+  }
+
+  // The implib option is only allowed for shared libraries, module
+  // libraries, and executables.
+  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    artifact = cmStateEnums::RuntimeBinaryArtifact;
+  }
+
+  // Compute suffix value.
+  const char* targetSuffix =
+    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
+                               : this->GetProperty("SUFFIX"));
+
+  if (!targetSuffix) {
+    const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
+    if (!language.empty() && suffixVar && *suffixVar) {
+      std::string langSuffix = suffixVar + std::string("_") + language;
+      targetSuffix = this->Makefile->GetDefinition(langSuffix);
+    }
+
+    // if there is no suffix on the target nor specific language
+    // use the cmake definition.
+    if (!targetSuffix && suffixVar) {
+      targetSuffix = this->Makefile->GetDefinition(suffixVar);
+    }
+  }
+
+  return targetSuffix;
+}
+
 void cmGeneratorTarget::ClearSourcesCache()
 {
   this->KindedSourcesMap.clear();
@@ -358,13 +601,9 @@
 
 void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
 {
-  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-  cmGeneratorExpression ge(lfbt);
-  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
-  cge->SetEvaluateForBuildsystem(true);
-  this->SourceEntries.insert(before ? this->SourceEntries.begin()
-                                    : this->SourceEntries.end(),
-                             new TargetPropertyEntry(std::move(cge)));
+  this->SourceEntries.insert(
+    before ? this->SourceEntries.begin() : this->SourceEntries.end(),
+    CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
   this->ClearSourcesCache();
 }
 
@@ -386,14 +625,10 @@
                                             bool before)
 {
   this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
-  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-  cmGeneratorExpression ge(lfbt);
-  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
-  cge->SetEvaluateForBuildsystem(true);
   this->IncludeDirectoriesEntries.insert(
     before ? this->IncludeDirectoriesEntries.begin()
            : this->IncludeDirectoriesEntries.end(),
-    new TargetPropertyEntry(std::move(cge)));
+    CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
 }
 
 std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
@@ -853,8 +1088,7 @@
         cmGeneratorExpression ge(lib.Backtrace);
         std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
         cge->SetEvaluateForBuildsystem(true);
-        entries.push_back(
-          new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
+        entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib));
       }
     }
   }
@@ -876,8 +1110,7 @@
         cmGeneratorExpression ge(lib.Backtrace);
         std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
         cge->SetEvaluateForBuildsystem(true);
-        entries.push_back(
-          new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
+        entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib));
       }
     }
   }
@@ -899,12 +1132,12 @@
     cmLinkImplItem const& item = entry->LinkImplItem;
     std::string const& targetName = item.AsStr();
     std::vector<std::string> entrySources;
-    cmSystemTools::ExpandListArgument(
-      entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
-                          dagChecker),
-      entrySources);
+    cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+                                                      config, false, tgt, tgt,
+                                                      dagChecker),
+                                      entrySources);
 
-    if (entry->ge->GetHadContextSensitiveCondition()) {
+    if (entry->GetHadContextSensitiveCondition()) {
       contextDependent = true;
     }
 
@@ -939,7 +1172,7 @@
     std::string usedSources;
     for (std::string const& src : entrySources) {
       if (uniqueSrcs.insert(src).second) {
-        srcs.emplace_back(src, entry->ge->GetBacktrace());
+        srcs.emplace_back(src, entry->GetBacktrace());
         if (debugSources) {
           usedSources += " * " + src + "\n";
         }
@@ -950,7 +1183,7 @@
         MessageType::LOG,
         std::string("Used sources for target ") + tgt->GetName() + ":\n" +
           usedSources,
-        entry->ge->GetBacktrace());
+        entry->GetBacktrace());
     }
   }
   return contextDependent;
@@ -1606,13 +1839,7 @@
     return "";
   }
   // Compute the soname that will be built.
-  std::string name;
-  std::string soName;
-  std::string realName;
-  std::string impName;
-  std::string pdbName;
-  this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
-  return soName;
+  return this->GetLibraryNames(config).SharedObject;
 }
 
 static bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
@@ -2378,7 +2605,7 @@
   std::set<cmGeneratorTarget*> targets;
 
   for (cmCustomCommandLine const& cCmdLine : cc.GetCommandLines()) {
-    std::string const& command = *cCmdLine.begin();
+    std::string const& command = cCmdLine.front();
     // Check for a target with this name.
     if (cmGeneratorTarget* t =
           this->LocalGenerator->FindGeneratorTargetToUse(command)) {
@@ -2534,10 +2761,10 @@
     bool const fromImported = item.Target && item.Target->IsImported();
     bool const checkCMP0027 = item.FromGenex;
     std::vector<std::string> entryIncludes;
-    cmSystemTools::ExpandListArgument(
-      entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
-                          dagChecker, language),
-      entryIncludes);
+    cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+                                                      config, false, tgt,
+                                                      dagChecker, language),
+                                      entryIncludes);
 
     std::string usedIncludes;
     for (std::string& entryInclude : entryIncludes) {
@@ -2615,7 +2842,7 @@
       std::string inc = entryInclude;
 
       if (uniqueIncludes.insert(inc).second) {
-        includes.emplace_back(inc, entry->ge->GetBacktrace());
+        includes.emplace_back(inc, entry->GetBacktrace());
         if (debugIncludes) {
           usedIncludes += " * " + inc + "\n";
         }
@@ -2626,7 +2853,7 @@
         MessageType::LOG,
         std::string("Used includes for target ") + tgt->GetName() + ":\n" +
           usedIncludes,
-        entry->ge->GetBacktrace());
+        entry->GetBacktrace());
     }
   }
 }
@@ -2678,11 +2905,8 @@
 
       libDir = frameworkCheck.match(1);
 
-      cmGeneratorExpression ge;
-      std::unique_ptr<cmCompiledGeneratorExpression> cge =
-        ge.Parse(libDir.c_str());
       linkInterfaceIncludeDirectoriesEntries.push_back(
-        new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+        CreateTargetPropertyEntry(libDir));
     }
   }
 
@@ -2712,10 +2936,10 @@
 {
   for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
     std::vector<std::string> entryOptions;
-    cmSystemTools::ExpandListArgument(
-      entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
-                          dagChecker, language),
-      entryOptions);
+    cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+                                                      config, false, tgt,
+                                                      dagChecker, language),
+                                      entryOptions);
     std::string usedOptions;
     for (std::string const& opt : entryOptions) {
       if (uniqueOptions.insert(opt).second) {
@@ -2724,10 +2948,10 @@
           std::vector<std::string> tmp;
           cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
           for (std::string& o : tmp) {
-            options.emplace_back(std::move(o), entry->ge->GetBacktrace());
+            options.emplace_back(std::move(o), entry->GetBacktrace());
           }
         } else {
-          options.emplace_back(opt, entry->ge->GetBacktrace());
+          options.emplace_back(opt, entry->GetBacktrace());
         }
         if (debugOptions) {
           usedOptions += " * " + opt + "\n";
@@ -2739,7 +2963,7 @@
         MessageType::LOG,
         std::string("Used ") + logName + std::string(" for target ") +
           tgt->GetName() + ":\n" + usedOptions,
-        entry->ge->GetBacktrace());
+        entry->GetBacktrace());
     }
   }
 }
@@ -2943,11 +3167,8 @@
           CM_FALLTHROUGH;
         }
         case cmPolicies::OLD: {
-          cmGeneratorExpression ge;
-          std::unique_ptr<cmCompiledGeneratorExpression> cge =
-            ge.Parse(configProp);
           linkInterfaceCompileDefinitionsEntries.push_back(
-            new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+            CreateTargetPropertyEntry(configProp));
         } break;
         case cmPolicies::NEW:
         case cmPolicies::REQUIRED_ALWAYS:
@@ -3173,12 +3394,9 @@
 
   if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
     std::vector<std::string> options;
-    cmGeneratorExpression ge;
     cmSystemTools::ExpandListArgument(linkOptions, options);
     for (const auto& option : options) {
-      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(option);
-      entries.push_back(
-        new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+      entries.push_back(CreateTargetPropertyEntry(option));
     }
   }
   processStaticLibraryLinkOptions(this, entries, result, uniqueOptions,
@@ -3202,10 +3420,10 @@
     std::string const& targetName = item.AsStr();
 
     std::vector<std::string> entryDirectories;
-    cmSystemTools::ExpandListArgument(
-      entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
-                          dagChecker, language),
-      entryDirectories);
+    cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+                                                      config, false, tgt,
+                                                      dagChecker, language),
+                                      entryDirectories);
 
     std::string usedDirectories;
     for (std::string& entryDirectory : entryDirectories) {
@@ -3261,7 +3479,7 @@
         MessageType::LOG,
         std::string("Used link directories for target ") + tgt->GetName() +
           ":\n" + usedDirectories,
-        entry->ge->GetBacktrace());
+        entry->GetBacktrace());
     }
   }
 }
@@ -3358,12 +3576,9 @@
 
   if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) {
     std::vector<std::string> depends;
-    cmGeneratorExpression ge;
     cmSystemTools::ExpandListArgument(linkDepends, depends);
     for (const auto& depend : depends) {
-      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depend);
-      linkDependsEntries.push_back(
-        new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+      linkDependsEntries.push_back(CreateTargetPropertyEntry(depend));
     }
   }
   AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS",
@@ -3383,17 +3598,13 @@
   cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
 
   // Get the names.
-  std::string name;
-  std::string soName;
-  std::string realName;
-  std::string impName;
-  std::string pdbName;
+  cmGeneratorTarget::Names targetNames;
   if (this->GetType() == cmStateEnums::EXECUTABLE) {
-    this->GetExecutableNames(name, realName, impName, pdbName, config);
+    targetNames = this->GetExecutableNames(config);
   } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
              this->GetType() == cmStateEnums::SHARED_LIBRARY ||
              this->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
+    targetNames = this->GetLibraryNames(config);
   } else {
     return;
   }
@@ -3404,34 +3615,34 @@
 
   // Add each name.
   std::string f;
-  if (!name.empty()) {
+  if (!targetNames.Output.empty()) {
     f = dir;
     f += "/";
-    f += name;
+    f += targetNames.Output;
     gg->AddToManifest(f);
   }
-  if (!soName.empty()) {
+  if (!targetNames.SharedObject.empty()) {
     f = dir;
     f += "/";
-    f += soName;
+    f += targetNames.SharedObject;
     gg->AddToManifest(f);
   }
-  if (!realName.empty()) {
+  if (!targetNames.Real.empty()) {
     f = dir;
     f += "/";
-    f += realName;
+    f += targetNames.Real;
     gg->AddToManifest(f);
   }
-  if (!pdbName.empty()) {
+  if (!targetNames.PDB.empty()) {
     f = dir;
     f += "/";
-    f += pdbName;
+    f += targetNames.PDB;
     gg->AddToManifest(f);
   }
-  if (!impName.empty()) {
+  if (!targetNames.ImportLibrary.empty()) {
     f = this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
     f += "/";
-    f += impName;
+    f += targetNames.ImportLibrary;
     gg->AddToManifest(f);
   }
 }
@@ -3509,29 +3720,17 @@
 
   if (this->GetType() == cmStateEnums::EXECUTABLE) {
     // Compute the real name that will be built.
-    std::string name;
-    std::string realName;
-    std::string impName;
-    std::string pdbName;
-    this->GetExecutableNames(name, realName, impName, pdbName, config);
-    return realName;
+    return this->GetExecutableNames(config).Real;
   }
   // Compute the real name that will be built.
-  std::string name;
-  std::string soName;
-  std::string realName;
-  std::string impName;
-  std::string pdbName;
-  this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
-  return realName;
+  return this->GetLibraryNames(config).Real;
 }
 
-void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
-                                        std::string& realName,
-                                        std::string& impName,
-                                        std::string& pdbName,
-                                        const std::string& config) const
+cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
+  const std::string& config) const
 {
+  cmGeneratorTarget::Names targetNames;
+
   // This should not be called for imported targets.
   // TODO: Split cmTarget into a class hierarchy to get compile-time
   // enforcement of the limited imported target API.
@@ -3539,7 +3738,6 @@
     std::string msg = "GetLibraryNames called on imported target: ";
     msg += this->GetName();
     this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
-    return;
   }
 
   // Check for library version properties.
@@ -3565,50 +3763,51 @@
 
   // Get the components of the library name.
   std::string prefix;
-  std::string base;
   std::string suffix;
   this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
-                            prefix, base, suffix);
+                            prefix, targetNames.Base, suffix);
 
   // The library name.
-  name = prefix + base + suffix;
+  targetNames.Output = prefix + targetNames.Base + suffix;
 
   if (this->IsFrameworkOnApple()) {
-    realName = prefix;
+    targetNames.Real = prefix;
     if (!this->Makefile->PlatformIsAppleEmbedded()) {
-      realName += "Versions/";
-      realName += this->GetFrameworkVersion();
-      realName += "/";
+      targetNames.Real += "Versions/";
+      targetNames.Real += this->GetFrameworkVersion();
+      targetNames.Real += "/";
     }
-    realName += base;
-    soName = realName;
+    targetNames.Real += targetNames.Base;
+    targetNames.SharedObject = targetNames.Real;
   } else {
     // The library's soname.
-    this->ComputeVersionedName(soName, prefix, base, suffix, name, soversion);
+    this->ComputeVersionedName(targetNames.SharedObject, prefix,
+                               targetNames.Base, suffix, targetNames.Output,
+                               soversion);
 
     // The library's real name on disk.
-    this->ComputeVersionedName(realName, prefix, base, suffix, name, version);
+    this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
+                               suffix, targetNames.Output, version);
   }
 
   // The import library name.
   if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
       this->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    impName =
+    targetNames.ImportLibrary =
       this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
-  } else {
-    impName.clear();
   }
 
   // The program database file name.
-  pdbName = this->GetPDBName(config);
+  targetNames.PDB = this->GetPDBName(config);
+
+  return targetNames;
 }
 
-void cmGeneratorTarget::GetExecutableNames(std::string& name,
-                                           std::string& realName,
-                                           std::string& impName,
-                                           std::string& pdbName,
-                                           const std::string& config) const
+cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
+  const std::string& config) const
 {
+  cmGeneratorTarget::Names targetNames;
+
   // This should not be called for imported targets.
   // TODO: Split cmTarget into a class hierarchy to get compile-time
   // enforcement of the limited imported target API.
@@ -3633,34 +3832,35 @@
 
   // Get the components of the executable name.
   std::string prefix;
-  std::string base;
   std::string suffix;
   this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
-                            prefix, base, suffix);
+                            prefix, targetNames.Base, suffix);
 
   // The executable name.
-  name = prefix + base + suffix;
+  targetNames.Output = prefix + targetNames.Base + suffix;
 
 // The executable's real name on disk.
 #if defined(__CYGWIN__)
-  realName = prefix + base;
+  targetNames.Real = prefix + targetNames.Base;
 #else
-  realName = name;
+  targetNames.Real = targetNames.Output;
 #endif
   if (version) {
-    realName += "-";
-    realName += version;
+    targetNames.Real += "-";
+    targetNames.Real += version;
   }
 #if defined(__CYGWIN__)
-  realName += suffix;
+  targetNames.Real += suffix;
 #endif
 
   // The import library name.
-  impName =
+  targetNames.ImportLibrary =
     this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
 
   // The program database file name.
-  pdbName = this->GetPDBName(config);
+  targetNames.PDB = this->GetPDBName(config);
+
+  return targetNames;
 }
 
 std::string cmGeneratorTarget::GetFullNameInternal(
@@ -3716,6 +3916,11 @@
     return;
   }
 
+  // retrieve prefix and suffix
+  std::string ll = this->GetLinkerLanguage(config);
+  const char* targetPrefix = this->GetFilePrefixInternal(artifact, ll);
+  const char* targetSuffix = this->GetFileSuffixInternal(artifact, ll);
+
   // The implib option is only allowed for shared libraries, module
   // libraries, and executables.
   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
@@ -3725,12 +3930,6 @@
   }
 
   // Compute the full name for main target types.
-  const char* targetPrefix =
-    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
-                               : this->GetProperty("PREFIX"));
-  const char* targetSuffix =
-    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
-                               : this->GetProperty("SUFFIX"));
   const char* configPostfix = nullptr;
   if (!config.empty()) {
     std::string configProp = cmSystemTools::UpperCase(config);
@@ -3742,30 +3941,6 @@
       configPostfix = nullptr;
     }
   }
-  const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
-  const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
-
-  // Check for language-specific default prefix and suffix.
-  std::string ll = this->GetLinkerLanguage(config);
-  if (!ll.empty()) {
-    if (!targetSuffix && suffixVar && *suffixVar) {
-      std::string langSuff = suffixVar + std::string("_") + ll;
-      targetSuffix = this->Makefile->GetDefinition(langSuff);
-    }
-    if (!targetPrefix && prefixVar && *prefixVar) {
-      std::string langPrefix = prefixVar + std::string("_") + ll;
-      targetPrefix = this->Makefile->GetDefinition(langPrefix);
-    }
-  }
-
-  // if there is no prefix on the target use the cmake definition
-  if (!targetPrefix && prefixVar) {
-    targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str();
-  }
-  // if there is no suffix on the target use the cmake definition
-  if (!targetSuffix && suffixVar) {
-    targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str();
-  }
 
   // frameworks have directory prefix but no suffix
   std::string fw_prefix;
@@ -3812,6 +3987,31 @@
   return this->GetLinkClosure(config)->LinkerLanguage;
 }
 
+std::string cmGeneratorTarget::GetPDBOutputName(
+  const std::string& config) const
+{
+  std::string base =
+    this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
+
+  std::vector<std::string> props;
+  std::string configUpper = cmSystemTools::UpperCase(config);
+  if (!configUpper.empty()) {
+    // PDB_NAME_<CONFIG>
+    props.push_back("PDB_NAME_" + configUpper);
+  }
+
+  // PDB_NAME
+  props.emplace_back("PDB_NAME");
+
+  for (std::string const& p : props) {
+    if (const char* outName = this->GetProperty(p)) {
+      base = outName;
+      break;
+    }
+  }
+  return base;
+}
+
 std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
 {
   std::string prefix;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 59d38af..81f5255 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -69,9 +69,9 @@
   std::string GetExportName() const;
 
   std::vector<std::string> GetPropertyKeys() const;
-  ///! Might return a nullptr if the property is not set or invalid
+  //! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
-  ///! Always returns a valid pointer
+  //! Always returns a valid pointer
   const char* GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   void GetSourceFiles(std::vector<cmSourceFile*>& files,
@@ -503,6 +503,9 @@
 
   OutputInfo const* GetOutputInfo(const std::string& config) const;
 
+  // Get the target PDB base name.
+  std::string GetPDBOutputName(const std::string& config) const;
+
   /** Get the name of the pdb file for the target.  */
   std::string GetPDBName(const std::string& config = "") const;
 
@@ -531,6 +534,15 @@
   std::string GetOutputName(const std::string& config,
                             cmStateEnums::ArtifactType artifact) const;
 
+  /** Get target file prefix */
+  std::string GetFilePrefix(const std::string& config,
+                            cmStateEnums::ArtifactType artifact =
+                              cmStateEnums::RuntimeBinaryArtifact) const;
+  /** Get target file prefix */
+  std::string GetFileSuffix(const std::string& config,
+                            cmStateEnums::ArtifactType artifact =
+                              cmStateEnums::RuntimeBinaryArtifact) const;
+
   /** Clears cached meta data for local and external source files.
    * The meta data will be recomputed on demand.
    */
@@ -568,19 +580,25 @@
   void GetAutoUicOptions(std::vector<std::string>& result,
                          const std::string& config) const;
 
+  struct Names
+  {
+    std::string Base;
+    std::string Output;
+    std::string Real;
+    std::string ImportLibrary;
+    std::string PDB;
+    std::string SharedObject;
+  };
+
   /** Get the names of the executable needed to generate a build rule
       that takes into account executable version numbers.  This should
       be called only on an executable target.  */
-  void GetExecutableNames(std::string& name, std::string& realName,
-                          std::string& impName, std::string& pdbName,
-                          const std::string& config) const;
+  Names GetExecutableNames(const std::string& config) const;
 
   /** Get the names of the library needed to generate a build rule
       that takes into account shared library version numbers.  This
       should be called only on a library target.  */
-  void GetLibraryNames(std::string& name, std::string& soName,
-                       std::string& realName, std::string& impName,
-                       std::string& pdbName, const std::string& config) const;
+  Names GetLibraryNames(const std::string& config) const;
 
   /**
    * Compute whether this target must be relinked before installing.
@@ -596,7 +614,7 @@
       pdb output directory is given.  */
   std::string GetPDBDirectory(const std::string& config) const;
 
-  ///! Return the preferred linker language for this target
+  //! Return the preferred linker language for this target
   std::string GetLinkerLanguage(const std::string& config) const;
 
   /** Does this target have a GNU implib to convert to MS format?  */
@@ -719,6 +737,11 @@
 
   mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
 
+  const char* GetFilePrefixInternal(cmStateEnums::ArtifactType artifact,
+                                    const std::string& language = "") const;
+  const char* GetFileSuffixInternal(cmStateEnums::ArtifactType artifact,
+                                    const std::string& language = "") const;
+
   std::string GetFullNameInternal(const std::string& config,
                                   cmStateEnums::ArtifactType artifact) const;
   void GetFullNameInternal(const std::string& config,
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
index c1f0742..da27971 100644
--- a/Source/cmGhsMultiGpj.cxx
+++ b/Source/cmGhsMultiGpj.cxx
@@ -2,16 +2,17 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGhsMultiGpj.h"
 
-#include "cmGeneratedFileStream.h"
+#include <ostream>
 
 static const char* GHS_TAG[] = { "[INTEGRITY Application]",
                                  "[Library]",
                                  "[Project]",
                                  "[Program]",
                                  "[Reference]",
-                                 "[Subproject]" };
+                                 "[Subproject]",
+                                 "[Custom Target]" };
 
-const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
+const char* GhsMultiGpj::GetGpjTag(Types gpjType)
 {
   char const* tag;
   switch (gpjType) {
@@ -21,6 +22,7 @@
     case PROGRAM:
     case REFERENCE:
     case SUBPROJECT:
+    case CUSTOM_TARGET:
       tag = GHS_TAG[gpjType];
       break;
     default:
@@ -29,7 +31,7 @@
   return tag;
 }
 
-void GhsMultiGpj::WriteGpjTag(Types const gpjType, std::ostream& fout)
+void GhsMultiGpj::WriteGpjTag(Types gpjType, std::ostream& fout)
 {
   char const* tag;
   tag = GhsMultiGpj::GetGpjTag(gpjType);
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
index 6d59225..e588150 100644
--- a/Source/cmGhsMultiGpj.h
+++ b/Source/cmGhsMultiGpj.h
@@ -6,8 +6,6 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 #include <iosfwd>
 
-class cmGeneratedFileStream;
-
 class GhsMultiGpj
 {
 public:
@@ -18,12 +16,13 @@
     PROJECT,
     PROGRAM,
     REFERENCE,
-    SUBPROJECT
+    SUBPROJECT,
+    CUSTOM_TARGET
   };
 
-  static void WriteGpjTag(Types const gpjType, std::ostream& fout);
+  static void WriteGpjTag(Types gpjType, std::ostream& fout);
 
-  static const char* GetGpjTag(Types const gpjType);
+  static const char* GetGpjTag(Types gpjType);
 };
 
 #endif // ! cmGhsMultiGpjType_h
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 5fe350c..b80da72 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -2,23 +2,41 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGhsMultiTargetGenerator.h"
 
-#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGhsMultiGenerator.h"
 #include "cmLinkLineComputer.h"
+#include "cmLocalGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
+#include "cmOutputConverter.h"
 #include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
 #include "cmSourceGroup.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
 #include "cmTarget.h"
 
+#include <algorithm>
+#include <ostream>
+#include <set>
+#include <utility>
+
 cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
   : GeneratorTarget(target)
   , LocalGenerator(
       static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
   , Makefile(target->Target->GetMakefile())
   , Name(target->GetName())
+#ifdef _WIN32
+  , CmdWindowsShell(true)
+#else
+  , CmdWindowsShell(false)
+#endif
 {
   // Store the configuration name that is being used
   if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
@@ -30,9 +48,7 @@
   }
 }
 
-cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
-{
-}
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() = default;
 
 void cmGhsMultiTargetGenerator::Generate()
 {
@@ -40,12 +56,8 @@
   switch (this->GeneratorTarget->GetType()) {
     case cmStateEnums::EXECUTABLE: {
       // Get the name of the executable to generate.
-      std::string targetName;
-      std::string targetNameImport;
-      std::string targetNamePDB;
-      this->GeneratorTarget->GetExecutableNames(
-        targetName, this->TargetNameReal, targetNameImport, targetNamePDB,
-        this->ConfigName);
+      this->TargetNameReal =
+        this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
       if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
         this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
       } else {
@@ -54,13 +66,8 @@
       break;
     }
     case cmStateEnums::STATIC_LIBRARY: {
-      std::string targetName;
-      std::string targetNameSO;
-      std::string targetNameImport;
-      std::string targetNamePDB;
-      this->GeneratorTarget->GetLibraryNames(
-        targetName, targetNameSO, this->TargetNameReal, targetNameImport,
-        targetNamePDB, this->ConfigName);
+      this->TargetNameReal =
+        this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
       this->TagType = GhsMultiGpj::LIBRARY;
       break;
     }
@@ -71,13 +78,8 @@
       return;
     }
     case cmStateEnums::OBJECT_LIBRARY: {
-      std::string targetName;
-      std::string targetNameSO;
-      std::string targetNameImport;
-      std::string targetNamePDB;
-      this->GeneratorTarget->GetLibraryNames(
-        targetName, targetNameSO, this->TargetNameReal, targetNameImport,
-        targetNamePDB, this->ConfigName);
+      this->TargetNameReal =
+        this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
       this->TagType = GhsMultiGpj::SUBPROJECT;
       break;
     }
@@ -88,10 +90,19 @@
       return;
     }
     case cmStateEnums::UTILITY: {
-      std::string msg = "add_custom_target(<name> ...) not supported: ";
-      msg += this->Name;
-      cmSystemTools::Message(msg);
-      return;
+      this->TargetNameReal = this->GeneratorTarget->GetName();
+      this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+      break;
+    }
+    case cmStateEnums::GLOBAL_TARGET: {
+      this->TargetNameReal = this->GeneratorTarget->GetName();
+      if (this->TargetNameReal ==
+          this->GetGlobalGenerator()->GetInstallTargetName()) {
+        this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+      } else {
+        return;
+      }
+      break;
     }
     default:
       return;
@@ -108,29 +119,29 @@
 
 void cmGhsMultiTargetGenerator::GenerateTarget()
 {
-  // Open the filestream in copy-if-different mode.
-  std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
-  fname += "/";
-  fname += this->Name;
-  fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
-  cmGeneratedFileStream fout(fname.c_str());
+  // Open the target file in copy-if-different mode.
+  std::string fproj = this->LocalGenerator->GetCurrentBinaryDirectory();
+  fproj += "/";
+  fproj += this->Name;
+  fproj += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+  cmGeneratedFileStream fout(fproj);
   fout.SetCopyIfDifferent(true);
 
   this->GetGlobalGenerator()->WriteFileHeader(fout);
   GhsMultiGpj::WriteGpjTag(this->TagType, fout);
 
-  const std::string language(
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
-
-  this->WriteTargetSpecifics(fout, this->ConfigName);
-  this->SetCompilerFlags(this->ConfigName, language);
-  this->WriteCompilerFlags(fout, this->ConfigName, language);
-  this->WriteCompilerDefinitions(fout, this->ConfigName, language);
-  this->WriteIncludes(fout, this->ConfigName, language);
-  this->WriteTargetLinkLine(fout, this->ConfigName);
-  this->WriteCustomCommands(fout);
+  if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+    const std::string language(
+      this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
+    this->WriteTargetSpecifics(fout, this->ConfigName);
+    this->SetCompilerFlags(this->ConfigName, language);
+    this->WriteCompilerFlags(fout, this->ConfigName, language);
+    this->WriteCompilerDefinitions(fout, this->ConfigName, language);
+    this->WriteIncludes(fout, this->ConfigName, language);
+    this->WriteTargetLinkLine(fout, this->ConfigName);
+    this->WriteBuildEvents(fout);
+  }
   this->WriteSources(fout);
-  this->WriteReferences(fout);
   fout.Close();
 }
 
@@ -224,7 +235,7 @@
   if (flagsByLangI != this->FlagsByLanguage.end()) {
     if (!flagsByLangI->second.empty()) {
       std::vector<std::string> ghsCompFlags =
-        cmSystemTools::ParseArguments(flagsByLangI->second.c_str());
+        cmSystemTools::ParseArguments(flagsByLangI->second);
       for (auto& f : ghsCompFlags) {
         fout << "    " << f << std::endl;
       }
@@ -238,10 +249,8 @@
   std::vector<std::string> compileDefinitions;
   this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
                                                language);
-  for (std::vector<std::string>::const_iterator cdI =
-         compileDefinitions.begin();
-       cdI != compileDefinitions.end(); ++cdI) {
-    fout << "    -D" << (*cdI) << std::endl;
+  for (std::string const& compileDefinition : compileDefinitions) {
+    fout << "    -D" << compileDefinition << std::endl;
   }
 }
 
@@ -253,9 +262,8 @@
   this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
                                               language, config);
 
-  for (std::vector<std::string>::const_iterator includes_i = includes.begin();
-       includes_i != includes.end(); ++includes_i) {
-    fout << "    -I\"" << *includes_i << "\"" << std::endl;
+  for (std::string const& include : includes) {
+    fout << "    -I\"" << include << "\"" << std::endl;
   }
 }
 
@@ -282,16 +290,14 @@
     frameworkPath, linkPath, this->GeneratorTarget);
 
   // write out link options
-  std::vector<std::string> lopts =
-    cmSystemTools::ParseArguments(linkFlags.c_str());
+  std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
   for (auto& l : lopts) {
     fout << "    " << l << std::endl;
   }
 
   // write out link search paths
   // must be quoted for paths that contain spaces
-  std::vector<std::string> lpath =
-    cmSystemTools::ParseArguments(linkPath.c_str());
+  std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
   for (auto& l : lpath) {
     fout << "    -L\"" << l << "\"" << std::endl;
   }
@@ -301,68 +307,161 @@
   std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
 
   std::vector<std::string> llibs =
-    cmSystemTools::ParseArguments(linkLibraries.c_str());
+    cmSystemTools::ParseArguments(linkLibraries);
   for (auto& l : llibs) {
     if (l.compare(0, 2, "-l") == 0) {
       fout << "    \"" << l << "\"" << std::endl;
     } else {
-      std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l);
+      std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
       fout << "    -l\"" << rl << "\"" << std::endl;
     }
   }
 }
 
-void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
+void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream& fout)
 {
-  WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
-                            cmTarget::PRE_BUILD);
-  WriteCustomCommandsHelper(
-    fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
+  this->WriteBuildEventsHelper(
+    fout, this->GeneratorTarget->GetPreBuildCommands(),
+    std::string("prebuild"), std::string("preexecShell"));
+
+  if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+    this->WriteBuildEventsHelper(
+      fout, this->GeneratorTarget->GetPreLinkCommands(),
+      std::string("prelink"), std::string("preexecShell"));
+  }
+
+  this->WriteBuildEventsHelper(
+    fout, this->GeneratorTarget->GetPostBuildCommands(),
+    std::string("postbuild"), std::string("postexecShell"));
 }
 
-void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
-  std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
-  cmTarget::CustomCommandType const commandType)
+void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
+  std::ostream& fout, const std::vector<cmCustomCommand>& ccv,
+  std::string const& name, std::string const& cmd)
 {
-  for (std::vector<cmCustomCommand>::const_iterator commandsSetI =
-         commandsSet.begin();
-       commandsSetI != commandsSet.end(); ++commandsSetI) {
-    cmCustomCommandLines const& commands = commandsSetI->GetCommandLines();
-    for (cmCustomCommandLines::const_iterator commandI = commands.begin();
-         commandI != commands.end(); ++commandI) {
-      switch (commandType) {
-        case cmTarget::PRE_BUILD:
-          fout << "    :preexecShellSafe=";
-          break;
-        case cmTarget::POST_BUILD:
-          fout << "    :postexecShellSafe=";
-          break;
-        default:
-          assert("Only pre and post are supported");
-      }
-      cmCustomCommandLine const& command = *commandI;
-      for (cmCustomCommandLine::const_iterator commandLineI = command.begin();
-           commandLineI != command.end(); ++commandLineI) {
-        std::string subCommandE =
-          this->LocalGenerator->EscapeForShell(*commandLineI, true);
-        if (!command.empty()) {
-          fout << (command.begin() == commandLineI ? "'" : " ");
-          // Need to double escape backslashes
-          cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
-        }
-        fout << subCommandE;
-      }
-      if (!command.empty()) {
-        fout << "'" << std::endl;
-      }
+  int cmdcount = 0;
+
+  for (cmCustomCommand const& cc : ccv) {
+    cmCustomCommandGenerator ccg(cc, this->ConfigName, this->LocalGenerator);
+    // Open the filestream for this custom command
+    std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
+    fname +=
+      "/" + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+    fname += "/" + this->Name + "_" + name;
+    fname += std::to_string(cmdcount++);
+    fname += this->CmdWindowsShell ? ".bat" : ".sh";
+    cmGeneratedFileStream f(fname);
+    f.SetCopyIfDifferent(true);
+    this->WriteCustomCommandsHelper(f, ccg);
+    f.Close();
+    if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+      fout << "    :" << cmd << "=\"" << fname << "\"" << std::endl;
+    } else {
+      fout << fname << std::endl;
+      fout << "    :outputName=\"" << fname << ".rule\"" << std::endl;
+    }
+    for (auto& byp : ccg.GetByproducts()) {
+      fout << "    :extraOutputFile=\"" << byp << "\"" << std::endl;
     }
   }
 }
 
-void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout,
-                                                    const cmSourceFile* sf,
-                                                    std::string propName,
-                                                    std::string propFlag)
+void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
+  std::ostream& fout, cmCustomCommandGenerator const& ccg)
+{
+  std::vector<std::string> cmdLines;
+
+  // if the command specified a working directory use it.
+  std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+  std::string currentBinDir = dir;
+  std::string workingDir = ccg.GetWorkingDirectory();
+  if (!workingDir.empty()) {
+    dir = workingDir;
+  }
+
+  // Line to check for error between commands.
+#ifdef _WIN32
+  std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
+#else
+  std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi";
+#endif
+
+#ifdef _WIN32
+  cmdLines.push_back("@echo off");
+#endif
+  // Echo the custom command's comment text.
+  const char* comment = ccg.GetComment();
+  if (comment && *comment) {
+    std::string echocmd = "echo ";
+    echocmd += comment;
+    cmdLines.push_back(std::move(echocmd));
+  }
+
+  // Switch to working directory
+  std::string cdCmd;
+#ifdef _WIN32
+  std::string cdStr = "cd /D ";
+#else
+  std::string cdStr = "cd ";
+#endif
+  cdCmd = cdStr +
+    this->LocalGenerator->ConvertToOutputFormat(dir, cmOutputConverter::SHELL);
+  cmdLines.push_back(std::move(cdCmd));
+
+  for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+    // Build the command line in a single string.
+    std::string cmd = ccg.GetCommand(c);
+    if (!cmd.empty()) {
+      // Use "call " before any invocations of .bat or .cmd files
+      // invoked as custom commands in the WindowsShell.
+      //
+      bool useCall = false;
+
+      if (this->CmdWindowsShell) {
+        std::string suffix;
+        if (cmd.size() > 4) {
+          suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+          if (suffix == ".bat" || suffix == ".cmd") {
+            useCall = true;
+          }
+        }
+      }
+
+      cmSystemTools::ReplaceString(cmd, "/./", "/");
+      // Convert the command to a relative path only if the current
+      // working directory will be the start-output directory.
+      bool had_slash = cmd.find('/') != std::string::npos;
+      if (workingDir.empty()) {
+        cmd =
+          this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, cmd);
+      }
+      bool has_slash = cmd.find('/') != std::string::npos;
+      if (had_slash && !has_slash) {
+        // This command was specified as a path to a file in the
+        // current directory.  Add a leading "./" so it can run
+        // without the current directory being in the search path.
+        cmd = "./" + cmd;
+      }
+      cmd = this->LocalGenerator->ConvertToOutputFormat(
+        cmd, cmOutputConverter::SHELL);
+      if (useCall) {
+        cmd = "call " + cmd;
+      }
+      ccg.AppendArguments(c, cmd);
+      cmdLines.push_back(std::move(cmd));
+    }
+  }
+
+  // push back the custom commands
+  for (auto const& c : cmdLines) {
+    fout << c << std::endl;
+    fout << check_error << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteSourceProperty(
+  std::ostream& fout, const cmSourceFile* sf, std::string const& propName,
+  std::string const& propFlag)
 {
   const char* prop = sf->GetProperty(propName);
   if (prop) {
@@ -393,12 +492,12 @@
       this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups);
     std::string gn = sourceGroup->GetFullName();
     groupFiles[gn].push_back(sf);
-    groupNames.insert(gn);
+    groupNames.insert(std::move(gn));
   }
 
   /* list of known groups and the order they are displayed in a project file */
   const std::vector<std::string> standardGroups = {
-    "Header Files", "Source Files",     "CMake Rules",
+    "CMake Rules",  "Header Files",     "Source Files",
     "Object Files", "Object Libraries", "Resources"
   };
 
@@ -416,11 +515,19 @@
       groupFilesList[i] = *n;
       i += 1;
       groupNames.erase(gn);
+    } else if (this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+               gn == "CMake Rules") {
+      /* make sure that rules folder always exists in case of custom targets
+       * that have no custom commands except for pre or post build events.
+       */
+      groupFilesList.resize(groupFilesList.size() + 1);
+      groupFilesList[i] = gn;
+      i += 1;
     }
   }
 
   { /* catch-all group - is last item */
-    std::string gn = "";
+    std::string gn;
     auto n = groupNames.find(gn);
     if (n != groupNames.end()) {
       groupFilesList.back() = *n;
@@ -446,7 +553,7 @@
 
   /* write files into the proper project file
    * -- groups go into main project file
-   *    unless FOLDER property or variable is set.
+   *    unless NO_SOURCE_GROUP_FILE property or variable is set.
    */
   for (auto& sg : groupFilesList) {
     std::ostream* fout;
@@ -469,7 +576,7 @@
       std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory();
       fpath += "/";
       fpath += lpath;
-      cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str());
+      cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath);
       f->SetCopyIfDifferent(true);
       gfiles.push_back(f);
       fout = f;
@@ -485,33 +592,98 @@
       } else {
         *fout << "{comment} " << sg << std::endl;
       }
+    } else if (sg.empty()) {
+      *fout << "{comment} Others" << std::endl;
     }
 
-    /* output rule for each source file */
-    for (const cmSourceFile* si : groupFiles[sg]) {
+    if (sg != "CMake Rules") {
+      /* output rule for each source file */
+      for (const cmSourceFile* si : groupFiles[sg]) {
+        bool compile = true;
+        // Convert filename to native system
+        // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
+        // windows when opening some files from the search window.
+        std::string fname(si->GetFullPath());
+        cmSystemTools::ConvertToOutputSlashes(fname);
 
-      // Convert filename to native system
-      // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
-      // windows when opening some files from the search window.
-      std::string fname(si->GetFullPath());
-      cmSystemTools::ConvertToOutputSlashes(fname);
-      *fout << fname << std::endl;
+        /* For custom targets list any associated sources,
+         * comment out source code to prevent it from being
+         * compiled when processing this target.
+         * Otherwise, comment out any custom command (main) dependencies that
+         * are listed as source files to prevent them from being considered
+         * part of the build.
+         */
+        std::string comment;
+        if ((this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+             !si->GetLanguage().empty()) ||
+            si->GetCustomCommand()) {
+          comment = "{comment} ";
+          compile = false;
+        }
 
-      if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
-          "bsp" != si->GetExtension()) {
-        this->WriteObjectLangOverride(*fout, si);
+        *fout << comment << fname << std::endl;
+        if (compile) {
+          if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
+              "bsp" != si->GetExtension()) {
+            WriteObjectLangOverride(*fout, si);
+          }
+
+          this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
+          this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
+          this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
+
+          /* to avoid clutter in the GUI only print out the objectName if it
+           * has been renamed */
+          std::string objectName = this->GeneratorTarget->GetObjectName(si);
+          if (!objectName.empty() &&
+              this->GeneratorTarget->HasExplicitObjectName(si)) {
+            *fout << "    -o " << objectName << std::endl;
+          }
+        }
       }
+    } else {
+      std::vector<cmSourceFile const*> customCommands;
+      if (ComputeCustomCommandOrder(customCommands)) {
+        std::string message = "The custom commands for target [" +
+          this->GeneratorTarget->GetName() + "] had a cycle.\n";
+        cmSystemTools::Error(message);
+      } else {
+        /* Custom targets do not have a dependency on SOURCES files.
+         * Therefore the dependency list may include SOURCES files after the
+         * custom target. Because nothing can depend on the custom target just
+         * move it to the last item.
+         */
+        for (auto sf = customCommands.begin(); sf != customCommands.end();
+             ++sf) {
+          if (((*sf)->GetLocation()).GetName() == this->Name + ".rule") {
+            std::rotate(sf, sf + 1, customCommands.end());
+            break;
+          }
+        }
+        int cmdcount = 0;
+        for (auto& sf : customCommands) {
+          const cmCustomCommand* cc = sf->GetCustomCommand();
+          cmCustomCommandGenerator ccg(*cc, this->ConfigName,
+                                       this->LocalGenerator);
 
-      this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
-      this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
-      this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
-
-      /* to avoid clutter in the gui only print out the objectName if it has
-       * been renamed */
-      std::string objectName = this->GeneratorTarget->GetObjectName(si);
-      if (!objectName.empty() &&
-          this->GeneratorTarget->HasExplicitObjectName(si)) {
-        *fout << "    -o " << objectName << std::endl;
+          // Open the filestream for this custom command
+          std::string fname =
+            this->LocalGenerator->GetCurrentBinaryDirectory();
+          fname += "/" +
+            this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+          fname += "/" + this->Name + "_cc";
+          fname += std::to_string(cmdcount++) + "_";
+          fname += (sf->GetLocation()).GetName();
+          fname += this->CmdWindowsShell ? ".bat" : ".sh";
+          cmGeneratedFileStream f(fname);
+          f.SetCopyIfDifferent(true);
+          this->WriteCustomCommandsHelper(f, ccg);
+          f.Close();
+          this->WriteCustomCommandLine(*fout, fname, ccg);
+        }
+      }
+      if (this->TagType == GhsMultiGpj::CUSTOM_TARGET) {
+        this->WriteBuildEvents(*fout);
       }
     }
   }
@@ -521,62 +693,107 @@
   }
 }
 
+void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
+  std::ostream& fout, std::string& fname, cmCustomCommandGenerator const& ccg)
+{
+  /* NOTE: Customization Files are not well documented.  Testing showed
+   * that ":outputName=file" can only be used once per script.  The
+   * script will only run if ":outputName=file" is missing or just run
+   * once if ":outputName=file" is not specified.  If there are
+   * multiple outputs then the script needs to be listed multiple times
+   * for each output.  Otherwise it won't rerun the script if one of
+   * the outputs is manually deleted.
+   */
+  bool specifyExtra = true;
+  for (auto& out : ccg.GetOutputs()) {
+    fout << fname << std::endl;
+    fout << "    :outputName=\"" << out << "\"" << std::endl;
+    if (specifyExtra) {
+      for (auto& byp : ccg.GetByproducts()) {
+        fout << "    :extraOutputFile=\"" << byp << "\"" << std::endl;
+      }
+      for (auto& dep : ccg.GetDepends()) {
+        fout << "    :depends=\"" << dep << "\"" << std::endl;
+      }
+      specifyExtra = false;
+    }
+  }
+}
+
 void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
   std::ostream& fout, const cmSourceFile* sourceFile)
 {
   const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
-  if (NULL != rawLangProp) {
+  if (nullptr != rawLangProp) {
     std::string sourceLangProp(rawLangProp);
-    std::string extension(sourceFile->GetExtension());
+    std::string const& extension = sourceFile->GetExtension();
     if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
       fout << "    -dotciscxx" << std::endl;
     }
   }
 }
 
-void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
-{
-  // This only applies to INTEGRITY Applications
-  if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
-    return;
-  }
-
-  // Get the targets that this one depends upon
-  cmTargetDependSet unordered =
-    this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
-  cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
-                                                            this->Name);
-  for (auto& t : ordered) {
-    std::string tname = t->GetName();
-    std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
-    std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
-    std::string outpath =
-      this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" +
-      tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
-
-    fout << outpath;
-    fout << "    ";
-    GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
-
-    // Tell the global generator that a refernce project needs to be created
-    t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
-  }
-}
-
-bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void)
+bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
 {
   const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
   if (p) {
     return cmSystemTools::IsOn(
       this->GeneratorTarget->GetProperty("ghs_integrity_app"));
-  } else {
-    std::vector<cmSourceFile*> sources;
-    this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
-    for (auto& sf : sources) {
-      if ("int" == sf->GetExtension()) {
-        return true;
-      }
-    }
-    return false;
   }
+  std::vector<cmSourceFile*> sources;
+  this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
+  for (auto& sf : sources) {
+    if ("int" == sf->GetExtension()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
+  std::vector<cmSourceFile const*>& order)
+{
+  std::set<cmSourceFile const*> temp;
+  std::set<cmSourceFile const*> perm;
+
+  // Collect all custom commands for this target
+  std::vector<cmSourceFile const*> customCommands;
+  this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
+
+  for (cmSourceFile const* si : customCommands) {
+    bool r = VisitCustomCommand(temp, perm, order, si);
+    if (r) {
+      return r;
+    }
+  }
+  return false;
+}
+
+bool cmGhsMultiTargetGenerator::VisitCustomCommand(
+  std::set<cmSourceFile const*>& temp, std::set<cmSourceFile const*>& perm,
+  std::vector<cmSourceFile const*>& order, cmSourceFile const* si)
+{
+  /* check if permanent mark is set*/
+  if (perm.find(si) == perm.end()) {
+    /* set temporary mark; check if revisit*/
+    if (temp.insert(si).second) {
+      for (auto& di : si->GetCustomCommand()->GetDepends()) {
+        cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
+                                   ->GetMakefile()
+                                   ->GetSourceFileWithOutput(di);
+        /* if sf exists then visit */
+        if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
+          return true;
+        }
+      }
+      /* mark as complete; insert into beginning of list*/
+      perm.insert(si);
+      order.push_back(si);
+      return false;
+    }
+    /* revisiting item - not a DAG */
+    return true;
+  }
+  /* already complete */
+  return false;
 }
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
index a241cc6..a131567 100644
--- a/Source/cmGhsMultiTargetGenerator.h
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -5,10 +5,14 @@
 
 #include "cmGhsMultiGpj.h"
 
-#include "cmTarget.h"
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
 
 class cmCustomCommand;
-class cmGeneratedFileStream;
+class cmCustomCommandGenerator;
 class cmGeneratorTarget;
 class cmGlobalGhsMultiGenerator;
 class cmLocalGhsMultiGenerator;
@@ -45,18 +49,27 @@
   void WriteIncludes(std::ostream& fout, const std::string& config,
                      const std::string& language);
   void WriteTargetLinkLine(std::ostream& fout, std::string const& config);
-  void WriteCustomCommands(std::ostream& fout);
-  void WriteCustomCommandsHelper(
-    std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
-    cmTarget::CustomCommandType commandType);
+  void WriteBuildEvents(std::ostream& fout);
+  void WriteBuildEventsHelper(std::ostream& fout,
+                              const std::vector<cmCustomCommand>& ccv,
+                              std::string const& name, std::string const& cmd);
+  void WriteCustomCommandsHelper(std::ostream& fout,
+                                 cmCustomCommandGenerator const& ccg);
+  void WriteCustomCommandLine(std::ostream& fout, std::string& fname,
+                              cmCustomCommandGenerator const& ccg);
+  bool ComputeCustomCommandOrder(std::vector<cmSourceFile const*>& order);
+  bool VisitCustomCommand(std::set<cmSourceFile const*>& temp,
+                          std::set<cmSourceFile const*>& perm,
+                          std::vector<cmSourceFile const*>& order,
+                          cmSourceFile const* sf);
   void WriteSources(std::ostream& fout_proj);
   void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf,
-                           std::string propName, std::string propFlag);
-  void WriteReferences(std::ostream& fout);
+                           std::string const& propName,
+                           std::string const& propFlag);
   static void WriteObjectLangOverride(std::ostream& fout,
                                       const cmSourceFile* sourceFile);
 
-  bool DetermineIfIntegrityApp(void);
+  bool DetermineIfIntegrityApp();
   cmGeneratorTarget* GeneratorTarget;
   cmLocalGhsMultiGenerator* LocalGenerator;
   cmMakefile* Makefile;
@@ -66,7 +79,8 @@
   std::string TargetNameReal;
   GhsMultiGpj::Types TagType;
   std::string const Name;
-  std::string ConfigName; /* CMAKE_BUILD_TYPE */
+  std::string ConfigName;     /* CMAKE_BUILD_TYPE */
+  bool const CmdWindowsShell; /* custom commands run in cmd.exe or /bin/sh */
 };
 
 #endif // ! cmGhsMultiTargetGenerator_h
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
index 5fd890e..9fb4170 100644
--- a/Source/cmGlobVerificationManager.cxx
+++ b/Source/cmGlobVerificationManager.cxx
@@ -25,8 +25,8 @@
   cmGeneratedFileStream verifyScriptFile(scriptFile);
   verifyScriptFile.SetCopyIfDifferent(true);
   if (!verifyScriptFile) {
-    cmSystemTools::Error("Unable to open verification script file for save. ",
-                         scriptFile.c_str());
+    cmSystemTools::Error("Unable to open verification script file for save. " +
+                         scriptFile);
     cmSystemTools::ReportLastSystemError("");
     return false;
   }
@@ -71,8 +71,8 @@
 
   cmsys::ofstream verifyStampFile(stampFile.c_str());
   if (!verifyStampFile) {
-    cmSystemTools::Error("Unable to open verification stamp file for write. ",
-                         stampFile.c_str());
+    cmSystemTools::Error("Unable to open verification stamp file for write. " +
+                         stampFile);
     return false;
   }
   verifyStampFile << "# This file is generated by CMake for checking of the "
diff --git a/Source/cmGlobVerificationManager.h b/Source/cmGlobVerificationManager.h
index f7146be..48606d3 100644
--- a/Source/cmGlobVerificationManager.h
+++ b/Source/cmGlobVerificationManager.h
@@ -22,11 +22,11 @@
 class cmGlobVerificationManager
 {
 protected:
-  ///! Save verification script for given makefile.
-  ///! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
+  //! Save verification script for given makefile.
+  //! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
   bool SaveVerificationScript(const std::string& path);
 
-  ///! Add an entry into the glob cache
+  //! Add an entry into the glob cache
   void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
                      const std::string& relative,
                      const std::string& expression,
@@ -34,13 +34,13 @@
                      const std::string& variable,
                      const cmListFileBacktrace& bt);
 
-  ///! Clear the glob cache for state reset.
+  //! Clear the glob cache for state reset.
   void Reset();
 
-  ///! Check targets should be written in generated build system.
+  //! Check targets should be written in generated build system.
   bool DoWriteVerifyTarget() const;
 
-  ///! Get the paths to the generated script and stamp files
+  //! Get the paths to the generated script and stamp files
   std::string const& GetVerifyScript() const { return this->VerifyScript; }
   std::string const& GetVerifyStamp() const { return this->VerifyStamp; }
 
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index c2eb583..51d681d 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -34,7 +34,7 @@
   this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
 }
 
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
 cmLocalGenerator* cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(
   cmMakefile* mf)
 {
@@ -53,15 +53,16 @@
   entry.Brief = "Generates Borland makefiles.";
 }
 
-void cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& projectDir,
-  const std::string& targetName, const std::string& config, bool fast,
-  int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& projectDir, std::vector<std::string> const& targetNames,
+  const std::string& config, bool fast, int /*jobs*/, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
-  this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeCommand, makeProgram, projectName, projectDir, targetName, config,
-    fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+  return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+    makeProgram, projectName, projectDir, targetNames, config, fast,
+    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
 }
 
 void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index ca04b7b..ee7de70 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -22,7 +22,7 @@
       cmGlobalBorlandMakefileGenerator>();
   }
 
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override
   {
     return cmGlobalBorlandMakefileGenerator::GetActualName();
@@ -32,7 +32,7 @@
   /** Get the documentation entry for this generator.  */
   static void GetDocumentation(cmDocumentationEntry& entry);
 
-  ///! Create a local generator appropriate to this Global Generator
+  //! Create a local generator appropriate to this Global Generator
   cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
 
   /**
@@ -46,15 +46,12 @@
   bool AllowDeleteOnError() const override { return false; }
 
 protected:
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
 };
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 386a3f7..8223dd1 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <assert.h>
 #include <cstring>
+#include <initializer_list>
 #include <iterator>
 #include <sstream>
 #include <stdio.h>
@@ -34,6 +35,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -211,7 +213,7 @@
 
   if (!mf->GetDefinition(langComp)) {
     if (!optional) {
-      cmSystemTools::Error(langComp.c_str(), " not set, after EnableLanguage");
+      cmSystemTools::Error(langComp + " not set, after EnableLanguage");
     }
     return;
   }
@@ -270,8 +272,7 @@
 
 bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
 {
-  std::map<std::string, cmExportBuildFileGenerator*>::iterator it =
-    this->BuildExportSets.find(file);
+  auto const it = this->BuildExportSets.find(file);
   if (it != this->BuildExportSets.end()) {
     bool result = it->second->GenerateImportFile();
 
@@ -297,10 +298,7 @@
 {
   bool failed = false;
   for (cmLocalGenerator* localGen : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& targets =
-      localGen->GetGeneratorTargets();
-
-    for (cmGeneratorTarget* target : targets) {
+    for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
           target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
           target->GetType() == cmStateEnums::TargetType::UTILITY ||
@@ -314,9 +312,11 @@
       if (configs.empty()) {
         target->GetSourceFiles(srcs, "");
       } else {
-        for (std::vector<std::string>::const_iterator ci = configs.begin();
-             ci != configs.end() && srcs.empty(); ++ci) {
-          target->GetSourceFiles(srcs, *ci);
+        for (std::string const& config : configs) {
+          target->GetSourceFiles(srcs, config);
+          if (srcs.empty()) {
+            break;
+          }
         }
       }
       if (srcs.empty()) {
@@ -334,8 +334,7 @@
 bool cmGlobalGenerator::IsExportedTargetsFile(
   const std::string& filename) const
 {
-  const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
-    this->BuildExportSets.find(filename);
+  auto const it = this->BuildExportSets.find(filename);
   if (it == this->BuildExportSets.end()) {
     return false;
   }
@@ -635,8 +634,7 @@
       // to avoid duplicate compiler tests.
       if (cmSystemTools::FileExists(fpath)) {
         if (!mf->ReadListFile(fpath)) {
-          cmSystemTools::Error("Could not find cmake module file: ",
-                               fpath.c_str());
+          cmSystemTools::Error("Could not find cmake module file: " + fpath);
         }
         // if this file was found then the language was already determined
         // to be working
@@ -661,8 +659,8 @@
       determineCompiler += "Compiler.cmake";
       std::string determineFile = mf->GetModulesFile(determineCompiler);
       if (!mf->ReadListFile(determineFile)) {
-        cmSystemTools::Error("Could not find cmake module file: ",
-                             determineCompiler.c_str());
+        cmSystemTools::Error("Could not find cmake module file: " +
+                             determineCompiler);
       }
       if (cmSystemTools::GetFatalErrorOccured()) {
         return;
@@ -680,8 +678,9 @@
         std::string compilerEnv = "CMAKE_";
         compilerEnv += lang;
         compilerEnv += "_COMPILER_ENV_VAR";
-        std::string envVar = mf->GetRequiredDefinition(compilerEnv);
-        std::string envVarValue = mf->GetRequiredDefinition(compilerName);
+        const std::string& envVar = mf->GetRequiredDefinition(compilerEnv);
+        const std::string& envVarValue =
+          mf->GetRequiredDefinition(compilerName);
         std::string env = envVar;
         env += "=";
         env += envVarValue;
@@ -695,8 +694,7 @@
       fpath += lang;
       fpath += "Compiler.cmake";
       if (!mf->ReadListFile(fpath)) {
-        cmSystemTools::Error("Could not find cmake module file: ",
-                             fpath.c_str());
+        cmSystemTools::Error("Could not find cmake module file: " + fpath);
       }
       this->SetLanguageEnabledFlag(lang, mf);
       needSetLanguageEnabledMaps[lang] = true;
@@ -788,11 +786,10 @@
       fpath += "Information.cmake";
       std::string informationFile = mf->GetModulesFile(fpath);
       if (informationFile.empty()) {
-        cmSystemTools::Error("Could not find cmake module file: ",
-                             fpath.c_str());
+        cmSystemTools::Error("Could not find cmake module file: " + fpath);
       } else if (!mf->ReadListFile(informationFile)) {
-        cmSystemTools::Error("Could not process cmake module file: ",
-                             informationFile.c_str());
+        cmSystemTools::Error("Could not process cmake module file: " +
+                             informationFile);
       }
     }
     if (needSetLanguageEnabledMaps[lang]) {
@@ -812,8 +809,8 @@
         testLang += "Compiler.cmake";
         std::string ifpath = mf->GetModulesFile(testLang);
         if (!mf->ReadListFile(ifpath)) {
-          cmSystemTools::Error("Could not find cmake module file: ",
-                               testLang.c_str());
+          cmSystemTools::Error("Could not find cmake module file: " +
+                               testLang);
         }
         std::string compilerWorks = "CMAKE_";
         compilerWorks += lang;
@@ -898,7 +895,7 @@
           /* clang-format off */
           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
             "Converting " << lang <<
-            " compiler id \"AppleClang\" to \"Clang\" for compatibility."
+            R"( compiler id "AppleClang" to "Clang" for compatibility.)"
             ;
           /* clang-format on */
           mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
@@ -928,7 +925,7 @@
           /* clang-format off */
           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
             "Converting " << lang <<
-            " compiler id \"QCC\" to \"GNU\" for compatibility."
+            R"( compiler id "QCC" to "GNU" for compatibility.)"
             ;
           /* clang-format on */
           mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
@@ -954,6 +951,36 @@
         break;
     }
   }
+
+  if (strcmp(compilerId, "XLClang") == 0) {
+    switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
+      case cmPolicies::WARN:
+        if (!this->CMakeInstance->GetIsInTryCompile() &&
+            mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
+          std::ostringstream w;
+          /* clang-format off */
+          w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n"
+            "Converting " << lang <<
+            R"( compiler id "XLClang" to "XL" for compatibility.)"
+            ;
+          /* clang-format on */
+          mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+        }
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        // OLD behavior is to convert XLClang to XL.
+        mf->AddDefinition(compilerIdVar, "XL");
+        break;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+        mf->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
+      case cmPolicies::NEW:
+        // NEW behavior is to keep AppleClang.
+        break;
+    }
+  }
 }
 
 std::string cmGlobalGenerator::GetLanguageOutputExtension(
@@ -961,9 +988,7 @@
 {
   const std::string& lang = source.GetLanguage();
   if (!lang.empty()) {
-    std::map<std::string, std::string>::const_iterator it =
-      this->LanguageToOutputExtension.find(lang);
-
+    auto const it = this->LanguageToOutputExtension.find(lang);
     if (it != this->LanguageToOutputExtension.end()) {
       return it->second;
     }
@@ -988,8 +1013,7 @@
   if (ext && *ext == '.') {
     ++ext;
   }
-  std::map<std::string, std::string>::const_iterator it =
-    this->ExtensionToLanguage.find(ext);
+  auto const it = this->ExtensionToLanguage.find(ext);
   if (it != this->ExtensionToLanguage.end()) {
     return it->second;
   }
@@ -1182,14 +1206,16 @@
   this->ConfigureDoneCMP0026AndCMP0024 = true;
 
   // Put a copy of each global target in every directory.
-  std::vector<GlobalTargetInfo> globalTargets;
-  this->CreateDefaultGlobalTargets(globalTargets);
+  {
+    std::vector<GlobalTargetInfo> globalTargets;
+    this->CreateDefaultGlobalTargets(globalTargets);
 
-  for (cmMakefile* mf : this->Makefiles) {
-    cmTargets* targets = &(mf->GetTargets());
-    for (GlobalTargetInfo const& globalTarget : globalTargets) {
-      targets->insert(cmTargets::value_type(
-        globalTarget.Name, this->CreateGlobalTarget(globalTarget, mf)));
+    for (cmMakefile* mf : this->Makefiles) {
+      auto& targets = mf->GetTargets();
+      for (GlobalTargetInfo const& globalTarget : globalTargets) {
+        targets.emplace(globalTarget.Name,
+                        this->CreateGlobalTarget(globalTarget, mf));
+      }
     }
   }
 
@@ -1222,7 +1248,7 @@
     } else {
       msg << "Configuring done";
     }
-    this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1);
+    this->CMakeInstance->UpdateProgress(msg.str(), -1);
   }
 }
 
@@ -1238,7 +1264,7 @@
   std::vector<const cmGeneratorTarget*>& exports)
 {
   this->CreateGenerationObjects(ImportedOnly);
-  std::vector<cmMakefile*>::iterator mfit =
+  auto const mfit =
     std::find(this->Makefiles.begin(), this->Makefiles.end(), mf);
   cmLocalGenerator* lg =
     this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
@@ -1253,8 +1279,7 @@
 cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
   const std::string& filename) const
 {
-  std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
-    this->BuildExportSets.find(filename);
+  auto const it = this->BuildExportSets.find(filename);
   return it == this->BuildExportSets.end() ? nullptr : it->second;
 }
 
@@ -1468,8 +1493,7 @@
   if (!ctd.Compute()) {
     return false;
   }
-  std::vector<cmGeneratorTarget const*> const& targets = ctd.GetTargets();
-  for (cmGeneratorTarget const* target : targets) {
+  for (cmGeneratorTarget const* target : ctd.GetTargets()) {
     ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
   }
   return true;
@@ -1509,8 +1533,7 @@
     const cmBacktraceRange noconfig_compile_definitions_bts =
       mf->GetCompileDefinitionsBacktraces();
 
-    cmTargets& targets = mf->GetTargets();
-    for (auto& target : targets) {
+    for (auto& target : mf->GetTargets()) {
       cmTarget* t = &target.second;
       if (t->GetType() == cmStateEnums::GLOBAL_TARGET) {
         continue;
@@ -1522,12 +1545,12 @@
         continue;
       }
 
-      cmBacktraceRange::const_iterator btIt =
-        noconfig_compile_definitions_bts.begin();
-      for (cmStringRange::const_iterator it =
-             noconfig_compile_definitions.begin();
-           it != noconfig_compile_definitions.end(); ++it, ++btIt) {
-        t->InsertCompileDefinition(*it, *btIt);
+      {
+        auto btIt = noconfig_compile_definitions_bts.begin();
+        auto it = noconfig_compile_definitions.begin();
+        for (; it != noconfig_compile_definitions.end(); ++it, ++btIt) {
+          t->InsertCompileDefinition(*it, *btIt);
+        }
       }
 
       cmPolicies::PolicyStatus polSt =
@@ -1567,17 +1590,14 @@
   std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
 {
   if (targetTypes == AllTargets) {
-    cmTargets& targets = mf->GetTargets();
-    for (auto& target : targets) {
+    for (auto& target : mf->GetTargets()) {
       cmTarget* t = &target.second;
       cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg);
       lg->AddGeneratorTarget(gt);
     }
   }
 
-  std::vector<cmTarget*> itgts = mf->GetImportedTargets();
-
-  for (cmTarget* t : itgts) {
+  for (cmTarget* t : mf->GetImportedTargets()) {
     lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
   }
 }
@@ -1638,14 +1658,11 @@
   cmState* state = this->GetCMakeInstance()->GetState();
   for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
     this->Makefiles[i]->ConfigureFinalPass();
-    cmTargets& targets = this->Makefiles[i]->GetTargets();
-    for (auto const& target : targets) {
+    for (auto const& target : this->Makefiles[i]->GetTargets()) {
       if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
       }
-      const cmTarget::LinkLibraryVectorType& libs =
-        target.second.GetOriginalLinkLibraries();
-      for (auto const& lib : libs) {
+      for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
         if (lib.first.size() > 9 &&
             cmSystemTools::IsNOTFOUND(lib.first.c_str())) {
           std::string varName = lib.first.substr(0, lib.first.size() - 9);
@@ -1702,8 +1719,8 @@
     cmSystemTools::Error("The following variables are used in this project, "
                          "but they are set to NOTFOUND.\n"
                          "Please set them or make sure they are set and "
-                         "tested correctly in the CMake files:\n",
-                         notFoundVars.c_str());
+                         "tested correctly in the CMake files:\n" +
+                         notFoundVars);
   }
 }
 
@@ -1731,20 +1748,9 @@
                                         this->FirstTimeProgress);
   }
 
-  std::string newTarget;
+  std::vector<std::string> newTarget = {};
   if (!target.empty()) {
-    newTarget += target;
-#if 0
-#  if defined(_WIN32) || defined(__CYGWIN__)
-    std::string tmp = target;
-    // if the target does not already end in . something
-    // then assume .exe
-    if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
-      {
-      newTarget += ".exe";
-      }
-#  endif // WIN32
-#endif
+    newTarget = { target };
   }
   std::string config =
     mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
@@ -1752,14 +1758,16 @@
                      config, false, fast, false, this->TryCompileTimeout);
 }
 
-void cmGlobalGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& /*unused*/,
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGenerator::GenerateBuildCommand(
   const std::string& /*unused*/, const std::string& /*unused*/,
-  const std::string& /*unused*/, const std::string& /*unused*/,
-  bool /*unused*/, int /*unused*/, bool /*unused*/,
-  std::vector<std::string> const& /*unused*/)
+  const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
+  const std::string& /*unused*/, bool /*unused*/, int /*unused*/,
+  bool /*unused*/, std::vector<std::string> const& /*unused*/)
 {
-  makeCommand.add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+  GeneratedMakeCommand makeCommand;
+  makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+  return { std::move(makeCommand) };
 }
 
 void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
@@ -1769,15 +1777,13 @@
   // they do not support certain build command line options
 }
 
-int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
-                             const std::string& bindir,
-                             const std::string& projectName,
-                             const std::string& target, std::string& output,
-                             const std::string& makeCommandCSTR,
-                             const std::string& config, bool clean, bool fast,
-                             bool verbose, cmDuration timeout,
-                             cmSystemTools::OutputOption outputflag,
-                             std::vector<std::string> const& nativeOptions)
+int cmGlobalGenerator::Build(
+  int jobs, const std::string& /*unused*/, const std::string& bindir,
+  const std::string& projectName, const std::vector<std::string>& targets,
+  std::string& output, const std::string& makeCommandCSTR,
+  const std::string& config, bool clean, bool fast, bool verbose,
+  cmDuration timeout, cmSystemTools::OutputOption outputflag,
+  std::vector<std::string> const& nativeOptions)
 {
   bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
 
@@ -1798,32 +1804,37 @@
     return 1;
   }
 
-  int retVal;
+  int retVal = 0;
   cmSystemTools::SetRunCommandHideConsole(true);
   std::string outputBuffer;
   std::string* outputPtr = &outputBuffer;
 
-  GeneratedMakeCommand makeCommand;
-  this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, bindir,
-                             target, config, fast, jobs, verbose,
-                             nativeOptions);
+  std::vector<GeneratedMakeCommand> makeCommand =
+    this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
+                               config, fast, jobs, verbose, nativeOptions);
 
   // Workaround to convince some commands to produce output.
   if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
-      makeCommand.RequiresOutputForward) {
+      makeCommand.back().RequiresOutputForward) {
     outputflag = cmSystemTools::OUTPUT_FORWARD;
   }
 
   // should we do a clean first?
   if (clean) {
-    GeneratedMakeCommand cleanCommand;
-    this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName,
-                               bindir, "clean", config, fast, jobs, verbose);
+    std::vector<GeneratedMakeCommand> cleanCommand =
+      this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
+                                 { "clean" }, config, fast, jobs, verbose);
     output += "\nRun Clean Command:";
-    output += cleanCommand.printable();
+    output += cleanCommand.front().Printable();
     output += "\n";
-
-    if (!cmSystemTools::RunSingleCommand(cleanCommand.PrimaryCommand,
+    if (cleanCommand.size() != 1) {
+      this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
+                                             "The generator did not produce "
+                                             "exactly one command for the "
+                                             "'clean' target");
+      return 1;
+    }
+    if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
                                          outputPtr, outputPtr, &retVal,
                                          nullptr, outputflag, timeout)) {
       cmSystemTools::SetRunCommandHideConsole(hideconsole);
@@ -1837,34 +1848,35 @@
   }
 
   // now build
-  std::string makeCommandStr = makeCommand.printable();
+  std::string makeCommandStr;
   output += "\nRun Build Command(s):";
-  output += makeCommandStr;
-  output += "\n";
 
-  if (!cmSystemTools::RunSingleCommand(makeCommand.PrimaryCommand, outputPtr,
-                                       outputPtr, &retVal, nullptr, outputflag,
-                                       timeout)) {
-    cmSystemTools::SetRunCommandHideConsole(hideconsole);
-    cmSystemTools::Error(
-      "Generator: execution of make failed. Make command was: ",
-      makeCommandStr.c_str());
+  for (auto command = makeCommand.begin(); command != makeCommand.end();
+       ++command) {
+    makeCommandStr = command->Printable();
+    if (command != makeCommand.end()) {
+      makeCommandStr += " && ";
+    }
+
+    output += makeCommandStr;
+    if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
+                                         outputPtr, &retVal, nullptr,
+                                         outputflag, timeout)) {
+      cmSystemTools::SetRunCommandHideConsole(hideconsole);
+      cmSystemTools::Error(
+        "Generator: execution of make failed. Make command was: " +
+        makeCommandStr);
+      output += *outputPtr;
+      output += "\nGenerator: execution of make failed. Make command was: " +
+        makeCommandStr + "\n";
+
+      return 1;
+    }
     output += *outputPtr;
-    output += "\nGenerator: execution of make failed. Make command was: " +
-      makeCommandStr + "\n";
-
-    return 1;
   }
-  output += *outputPtr;
+  output += "\n";
   cmSystemTools::SetRunCommandHideConsole(hideconsole);
 
-  // The SGI MipsPro 7.3 compiler does not return an error code when
-  // the source has a #error in it!  This is a work-around for such
-  // compilers.
-  if ((retVal == 0) && (output.find("#error") != std::string::npos)) {
-    retVal = 1;
-  }
-
   // The OpenWatcom tools do not return an error code when a link
   // library is not found!
   if (this->CMakeInstance->GetState()->UseWatcomWMake() && retVal == 0 &&
@@ -2043,8 +2055,7 @@
 
 int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
 {
-  std::map<std::string, int>::const_iterator it =
-    this->LanguageToLinkerPreference.find(lang);
+  auto const it = this->LanguageToLinkerPreference.find(lang);
   if (it != this->LanguageToLinkerPreference.end()) {
     return it->second;
   }
@@ -2071,9 +2082,9 @@
 
 cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
 {
-  MakefileMap::const_iterator i = this->MakefileSearchIndex.find(start_dir);
-  if (i != this->MakefileSearchIndex.end()) {
-    return i->second;
+  auto const it = this->MakefileSearchIndex.find(start_dir);
+  if (it != this->MakefileSearchIndex.end()) {
+    return it->second;
   }
   return nullptr;
 }
@@ -2081,10 +2092,9 @@
 cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
   cmDirectoryId const& id) const
 {
-  LocalGeneratorMap::const_iterator i =
-    this->LocalGeneratorSearchIndex.find(id.String);
-  if (i != this->LocalGeneratorSearchIndex.end()) {
-    return i->second;
+  auto const it = this->LocalGeneratorSearchIndex.find(id.String);
+  if (it != this->LocalGeneratorSearchIndex.end()) {
+    return it->second;
   }
   return nullptr;
 }
@@ -2114,17 +2124,24 @@
   }
 }
 
+static char const hexDigits[] = "0123456789abcdef";
+
 std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
   cmGeneratorTarget const* gt)
 {
   // Use the pointer value to uniquely identify the target instance.
-  // Use a "T" prefix to indicate that this identifier is for a target.
+  // Use a ":" prefix to avoid conflict with project-defined targets.
   // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
   // other special characters.
-  char buf[64];
-  sprintf(buf, "::T%p",
-          static_cast<void const*>(gt)); // cast avoids format warning
-  std::string id = gt->GetName() + buf;
+  char buf[1 + sizeof(gt) * 2];
+  char* b = buf;
+  *b++ = ':';
+  for (size_t i = 0; i < sizeof(gt); ++i) {
+    unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
+    *b++ = hexDigits[(c & 0xf0) >> 4];
+    *b++ = hexDigits[(c & 0x0f)];
+  }
+  std::string id(buf, sizeof(buf));
   // We internally index pointers to non-const generator targets
   // but our callers only have pointers to const generator targets.
   // They will give up non-const privileges when looking up anyway.
@@ -2151,9 +2168,9 @@
 
 cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
 {
-  TargetMap::const_iterator i = this->TargetSearchIndex.find(name);
-  if (i != this->TargetSearchIndex.end()) {
-    return i->second;
+  auto const it = this->TargetSearchIndex.find(name);
+  if (it != this->TargetSearchIndex.end()) {
+    return it->second;
   }
   return nullptr;
 }
@@ -2161,10 +2178,9 @@
 cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
   std::string const& name) const
 {
-  GeneratorTargetMap::const_iterator i =
-    this->GeneratorTargetSearchIndex.find(name);
-  if (i != this->GeneratorTargetSearchIndex.end()) {
-    return i->second;
+  auto const it = this->GeneratorTargetSearchIndex.find(name);
+  if (it != this->GeneratorTargetSearchIndex.end()) {
+    return it->second;
   }
   return nullptr;
 }
@@ -2173,8 +2189,7 @@
                                         bool excludeAliases) const
 {
   if (!excludeAliases) {
-    std::map<std::string, std::string>::const_iterator ai =
-      this->AliasTargets.find(name);
+    auto const ai = this->AliasTargets.find(name);
     if (ai != this->AliasTargets.end()) {
       return this->FindTargetImpl(ai->second);
     }
@@ -2185,8 +2200,7 @@
 cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
   const std::string& name) const
 {
-  std::map<std::string, std::string>::const_iterator ai =
-    this->AliasTargets.find(name);
+  auto const ai = this->AliasTargets.find(name);
   if (ai != this->AliasTargets.end()) {
     return this->FindGeneratorTargetImpl(ai->second);
   }
@@ -2196,7 +2210,7 @@
 bool cmGlobalGenerator::NameResolvesToFramework(
   const std::string& libname) const
 {
-  if (cmSystemTools::IsPathToFramework(libname.c_str())) {
+  if (cmSystemTools::IsPathToFramework(libname)) {
     return true;
   }
 
@@ -2277,10 +2291,9 @@
     return;
   }
 
-  const char* reservedTargets[] = { "package", "PACKAGE" };
-  for (const char* const* tn = cm::cbegin(reservedTargets);
-       tn != cm::cend(reservedTargets); ++tn) {
-    if (!this->CheckCMP0037(*tn, "when CPack packaging is enabled")) {
+  static const auto reservedTargets = { "package", "PACKAGE" };
+  for (auto const& target : reservedTargets) {
+    if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
       return;
     }
   }
@@ -2327,10 +2340,10 @@
     return;
   }
 
-  const char* reservedTargets[] = { "package_source" };
-  for (const char* const* tn = cm::cbegin(reservedTargets);
-       tn != cm::cend(reservedTargets); ++tn) {
-    if (!this->CheckCMP0037(*tn, "when CPack source packaging is enabled")) {
+  static const auto reservedTargets = { "package_source" };
+  for (auto const& target : reservedTargets) {
+    if (!this->CheckCMP0037(target,
+                            "when CPack source packaging is enabled")) {
       return;
     }
   }
@@ -2357,10 +2370,9 @@
     return;
   }
 
-  const char* reservedTargets[] = { "test", "RUN_TESTS" };
-  for (const char* const* tn = cm::cbegin(reservedTargets);
-       tn != cm::cend(reservedTargets); ++tn) {
-    if (!this->CheckCMP0037(*tn, "when CTest testing is enabled")) {
+  static const auto reservedTargets = { "test", "RUN_TESTS" };
+  for (auto const& target : reservedTargets) {
+    if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
       return;
     }
   }
@@ -2619,8 +2631,7 @@
 std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
   std::string const& l) const
 {
-  std::map<std::string, std::string>::const_iterator it =
-    this->LanguageToOriginalSharedLibFlags.find(l);
+  auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
   if (it != this->LanguageToOriginalSharedLibFlags.end()) {
     return it->second;
   }
@@ -2698,11 +2709,8 @@
     if (this->IsExcluded(root, generator)) {
       continue;
     }
-    // Get the targets in the makefile
-    const std::vector<cmGeneratorTarget*>& tgts =
-      generator->GetGeneratorTargets();
-    // loop over all the targets
-    for (cmGeneratorTarget* target : tgts) {
+    // loop over all the generator targets in the makefile
+    for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
       if (this->IsRootOnlyTarget(target) &&
           target->GetLocalGenerator() != root) {
         continue;
@@ -2728,8 +2736,7 @@
   if (projectTargets.insert(target).second) {
     // This is the first time we have encountered the target.
     // Recursively follow its dependencies.
-    TargetDependSet const& ts = this->GetTargetDirectDepends(target);
-    for (auto const& t : ts) {
+    for (auto const& t : this->GetTargetDirectDepends(target)) {
       this->AddTargetDepends(t, projectTargets);
     }
   }
@@ -2841,8 +2848,7 @@
     fname = line.substr(33);
 
     // Look for a hash for this file's rule.
-    std::map<std::string, RuleHash>::const_iterator rhi =
-      this->RuleHashes.find(fname);
+    auto const rhi = this->RuleHashes.find(fname);
     if (rhi != this->RuleHashes.end()) {
       // Compare the rule hash in the file to that we were given.
       if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
@@ -2892,8 +2898,7 @@
   cmGeneratedFileStream fout(fname);
 
   for (cmLocalGenerator* lg : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* tgt : tgts) {
+    for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
       if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
       }
@@ -2981,12 +2986,9 @@
     for (std::string const& c : configs) {
       target->GetSourceFiles(sources, c);
     }
-    std::vector<cmSourceFile*>::const_iterator sourcesEnd =
-      cmRemoveDuplicates(sources);
-    for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
-         si != sourcesEnd; ++si) {
+    auto const sourcesEnd = cmRemoveDuplicates(sources);
+    for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
       Json::Value& lj_source = lj_sources.append(Json::objectValue);
-      cmSourceFile* sf = *si;
       std::string const& sfp = sf->GetFullPath();
       fout << sfp << "\n";
       lj_source["file"] = sfp;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index ac01326..88c586a 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -13,6 +13,7 @@
 #include <utility>
 #include <vector>
 
+#include "cmAlgorithms.h"
 #include "cmCustomCommandLines.h"
 #include "cmDuration.h"
 #include "cmExportSetMap.h"
@@ -56,33 +57,20 @@
 {
   // Add each argument as a separate element to the vector
   template <typename... T>
-  void add(T&&... args)
+  void Add(T&&... args)
   {
     // iterate the args and append each one
     AppendStrs(PrimaryCommand, std::forward<T>(args)...);
   }
 
   // Add each value in the iterators as a separate element to the vector
-  void add(std::vector<std::string>::const_iterator start,
+  void Add(std::vector<std::string>::const_iterator start,
            std::vector<std::string>::const_iterator end)
   {
     PrimaryCommand.insert(PrimaryCommand.end(), start, end);
   }
 
-  std::string printable() const
-  {
-    std::size_t size = PrimaryCommand.size();
-    for (auto&& i : PrimaryCommand) {
-      size += i.size();
-    }
-    std::string buffer;
-    buffer.reserve(size);
-    for (auto&& i : PrimaryCommand) {
-      buffer.append(i);
-      buffer.append(1, ' ');
-    }
-    return buffer;
-  }
+  std::string Printable() const { return cmJoin(PrimaryCommand, " "); }
 
   std::vector<std::string> PrimaryCommand;
   bool RequiresOutputForward = false;
@@ -98,13 +86,13 @@
 class cmGlobalGenerator
 {
 public:
-  ///! Free any memory allocated with the GlobalGenerator
+  //! Free any memory allocated with the GlobalGenerator
   cmGlobalGenerator(cmake* cm);
   virtual ~cmGlobalGenerator();
 
   virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
 
-  ///! Get the name for this generator
+  //! Get the name for this generator
   virtual std::string GetName() const { return "Generic"; }
 
   /** Check whether the given name matches the current generator.  */
@@ -216,10 +204,10 @@
    */
   int Build(
     int jobs, const std::string& srcdir, const std::string& bindir,
-    const std::string& projectName, const std::string& targetName,
-    std::string& output, const std::string& makeProgram,
-    const std::string& config, bool clean, bool fast, bool verbose,
-    cmDuration timeout,
+    const std::string& projectName,
+    std::vector<std::string> const& targetNames, std::string& output,
+    const std::string& makeProgram, const std::string& config, bool clean,
+    bool fast, bool verbose, cmDuration timeout,
     cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
     std::vector<std::string> const& nativeOptions =
       std::vector<std::string>());
@@ -234,11 +222,10 @@
   {
   };
 
-  virtual void GenerateBuildCommand(
-    GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-    const std::string& projectName, const std::string& projectDir,
-    const std::string& targetName, const std::string& config, bool fast,
-    int jobs, bool verbose,
+  virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
     std::vector<std::string> const& makeOptions = std::vector<std::string>());
 
   virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
@@ -249,7 +236,7 @@
                                         const std::string& native,
                                         bool ignoreErrors);
 
-  ///! Get the CMake instance
+  //! Get the CMake instance
   cmake* GetCMakeInstance() const { return this->CMakeInstance; }
 
   void SetConfiguredFilesPath(cmGlobalGenerator* gen);
@@ -274,7 +261,7 @@
 
   void AddMakefile(cmMakefile* mf);
 
-  ///! Set an generator for an "external makefile based project"
+  //! Set an generator for an "external makefile based project"
   void SetExternalMakefileProjectGenerator(
     cmExternalMakefileProjectGenerator* extraGenerator);
 
@@ -303,19 +290,19 @@
   bool GetForceUnixPaths() const { return this->ForceUnixPaths; }
   bool GetToolSupportsColor() const { return this->ToolSupportsColor; }
 
-  ///! return the language for the given extension
+  //! return the language for the given extension
   std::string GetLanguageFromExtension(const char* ext) const;
-  ///! is an extension to be ignored
+  //! is an extension to be ignored
   bool IgnoreFile(const char* ext) const;
-  ///! What is the preference for linkers and this language (None or Preferred)
+  //! What is the preference for linkers and this language (None or Preferred)
   int GetLinkerPreference(const std::string& lang) const;
-  ///! What is the object file extension for a given source file?
+  //! What is the object file extension for a given source file?
   std::string GetLanguageOutputExtension(cmSourceFile const&) const;
 
-  ///! What is the configurations directory variable called?
+  //! What is the configurations directory variable called?
   virtual const char* GetCMakeCFGIntDir() const { return "."; }
 
-  ///! expand CFGIntDir for a configuration
+  //! expand CFGIntDir for a configuration
   virtual std::string ExpandCFGIntDir(const std::string& str,
                                       const std::string& config) const;
 
@@ -331,7 +318,7 @@
    */
   virtual bool FindMakeProgram(cmMakefile*);
 
-  ///! Find a target by name by searching the local generators.
+  //! Find a target by name by searching the local generators.
   cmTarget* FindTarget(const std::string& name,
                        bool excludeAliases = false) const;
 
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 45fa052..b69dea0 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -2,22 +2,33 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalGhsMultiGenerator.h"
 
-#include "cmsys/SystemTools.hxx"
-
-#include "cmAlgorithms.h"
 #include "cmDocumentationEntry.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
-#include "cmGhsMultiTargetGenerator.h"
+#include "cmGhsMultiGpj.h"
+#include "cmLocalGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
+#include <algorithm>
+#include <map>
+#include <ostream>
+#include <string.h>
+#include <utility>
+
 const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+#ifdef __linux__
+const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
+const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "/usr/ghs";
+#elif defined(_WIN32)
 const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
 const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs";
+#endif
 
 cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
   : cmGlobalGenerator(cm)
@@ -25,9 +36,7 @@
   cm->GetState()->SetGhsMultiIDE(true);
 }
 
-cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
-{
-}
+cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
 
 cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
   cmMakefile* mf)
@@ -64,7 +73,8 @@
   /* no toolset was found */
   if (tsp.empty()) {
     return false;
-  } else if (ts.empty()) {
+  }
+  if (ts.empty()) {
     std::string message;
     message =
       "Green Hills MULTI: -T <toolset> not specified; defaulting to \"";
@@ -86,7 +96,7 @@
   const char* prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
 
   /* check if the toolset changed from last generate */
-  if (prevTool != NULL && (gbuild != prevTool)) {
+  if (prevTool != nullptr && (gbuild != prevTool)) {
     std::string message = "toolset build tool: ";
     message += gbuild;
     message += "\nDoes not match the previously used build tool: ";
@@ -95,13 +105,12 @@
                "directory or choose a different binary directory.";
     cmSystemTools::Error(message);
     return false;
-  } else {
-    /* store the toolset that is being used for this build */
-    mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
-                           "build program to use", cmStateEnums::INTERNAL,
-                           true);
   }
 
+  /* store the toolset that is being used for this build */
+  mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
+                         "build program to use", cmStateEnums::INTERNAL, true);
+
   mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp.c_str());
 
   return true;
@@ -110,10 +119,11 @@
 bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
                                                      cmMakefile* mf)
 {
-  if (p == "") {
+  std::string arch;
+  if (p.empty()) {
     cmSystemTools::Message(
       "Green Hills MULTI: -A <arch> not specified; defaulting to \"arm\"");
-    std::string arch = "arm";
+    arch = "arm";
 
     /* store the platform name for later use
      * -- already done if -A<arch> was specified
@@ -121,19 +131,51 @@
     mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch.c_str(),
                            "Name of generator platform.",
                            cmStateEnums::INTERNAL);
+  } else {
+    arch = p;
   }
 
-  const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
-  if (tgtPlatform == nullptr) {
-    cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
-                           "specified; defaulting to \"integrity\"");
-    tgtPlatform = "integrity";
+  /* check if OS location has been updated by platform scripts */
+  std::string platform = mf->GetSafeDefinition("GHS_TARGET_PLATFORM");
+  std::string osdir = mf->GetSafeDefinition("GHS_OS_DIR");
+  if (cmSystemTools::IsOff(osdir.c_str()) &&
+      platform.find("integrity") != std::string::npos) {
+    if (!this->CMakeInstance->GetIsInTryCompile()) {
+      /* required OS location is not found */
+      std::string m =
+        "Green Hills MULTI: GHS_OS_DIR not specified; No OS found in \"";
+      m += mf->GetSafeDefinition("GHS_OS_ROOT");
+      m += "\"";
+      cmSystemTools::Message(m);
+    }
+    osdir = "GHS_OS_DIR-NOT-SPECIFIED";
+  } else if (!this->CMakeInstance->GetIsInTryCompile() &&
+             cmSystemTools::IsOff(this->OsDir) &&
+             !cmSystemTools::IsOff(osdir)) {
+    /* OS location was updated by auto-selection */
+    std::string m = "Green Hills MULTI: GHS_OS_DIR not specified; found \"";
+    m += osdir;
+    m += "\"";
+    cmSystemTools::Message(m);
   }
+  this->OsDir = osdir;
 
-  /* store the platform name for later use */
-  mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
-                         "Name of GHS target platform.",
-                         cmStateEnums::INTERNAL);
+  // Determine GHS_BSP_NAME
+  std::string bspName = mf->GetSafeDefinition("GHS_BSP_NAME");
+
+  if (cmSystemTools::IsOff(bspName.c_str()) &&
+      platform.find("integrity") != std::string::npos) {
+    bspName = "sim" + arch;
+    /* write back the calculate name for next time */
+    mf->AddCacheDefinition("GHS_BSP_NAME", bspName.c_str(),
+                           "Name of GHS target platform.",
+                           cmStateEnums::STRING, true);
+    std::string m =
+      "Green Hills MULTI: GHS_BSP_NAME not specified; defaulting to \"";
+    m += bspName;
+    m += "\"";
+    cmSystemTools::Message(m);
+  }
 
   return true;
 }
@@ -144,6 +186,21 @@
   mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
 
   mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
+
+  const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
+  if (!tgtPlatform) {
+    cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
+                           "specified; defaulting to \"integrity\"");
+    tgtPlatform = "integrity";
+  }
+
+  /* store the platform name for later use */
+  mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
+                         "Name of GHS target platform.", cmStateEnums::STRING);
+
+  /* store original OS location */
+  this->OsDir = mf->GetSafeDefinition("GHS_OS_DIR");
+
   this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
 }
 
@@ -185,8 +242,7 @@
     }
   } else {
     std::string tryPath;
-    /* CollapseCombinedPath will check if ts is an absolute path */
-    tryPath = cmSystemTools::CollapseCombinedPath(tsd, ts);
+    tryPath = cmSystemTools::CollapseFullPath(ts, tsd);
     if (!cmSystemTools::FileExists(tryPath)) {
       std::string msg = "GHS toolset \"" + tryPath + "\" not found.";
       cmSystemTools::Error(msg);
@@ -202,139 +258,246 @@
   fout << "#!gbuild" << std::endl;
   fout << "#" << std::endl
        << "# CMAKE generated file: DO NOT EDIT!" << std::endl
-       << "# Generated by \"" << this->GetActualName() << "\""
+       << "# Generated by \"" << GetActualName() << "\""
        << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
        << cmVersion::GetMinorVersion() << std::endl
        << "#" << std::endl
        << std::endl;
 }
 
-void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
-  std::ostream& fout, cmLocalGenerator* root,
-  std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
 {
-  WriteFileHeader(fout);
+  fout << "Commands {\n"
+          "  Custom_Rule_Command {\n"
+          "    name = \"Custom Rule Command\"\n"
+          "    exec = \"";
+#ifdef _WIN32
+  fout << "cmd.exe";
+#else
+  fout << "/bin/sh";
+#endif
+  fout << "\"\n"
+          "    options = {\"SpecialOptions\"}\n"
+          "  }\n"
+          "}\n";
 
-  this->WriteMacros(fout);
-  this->WriteHighLevelDirectives(fout);
+  fout << "\n\n";
+  fout << "FileTypes {\n"
+          "  CmakeRule {\n"
+          "    name = \"Custom Rule\"\n"
+          "    action = \"&Run\"\n"
+          "    extensions = {\"";
+#ifdef _WIN32
+  fout << "bat";
+#else
+  fout << "sh";
+#endif
+  fout << "\"}\n"
+          "    grepable = false\n"
+          "    command = \"Custom Rule Command\"\n"
+          "    commandLine = \"$COMMAND ";
+#ifdef _WIN32
+  fout << "/c";
+#endif
+  fout << " $INPUTFILE\"\n"
+          "    progress = \"Processing Custom Rule\"\n"
+          "    promoteToFirstPass = true\n"
+          "    outputType = \"None\"\n"
+          "    color = \"#800080\"\n"
+          "  }\n"
+          "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
+{
+  fout << "FileTypes {\n"
+          "  CmakeTarget {\n"
+          "    name = \"Custom Target\"\n"
+          "    action = \"&Execute\"\n"
+          "    grepable = false\n"
+          "    outputType = \"None\"\n"
+          "    color = \"#800080\"\n"
+          "  }\n"
+          "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
+                                                     cmLocalGenerator* root)
+{
+  this->WriteFileHeader(fout);
+  this->WriteMacros(fout, root);
+  this->WriteHighLevelDirectives(root, fout);
   GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
 
   fout << "# Top Level Project File" << std::endl;
 
   // Specify BSP option if supplied by user
-  // -- not all platforms require this entry in the project file
-  //    integrity platforms require this field; use default if needed
-  std::string platform;
-  if (const char* p =
-        this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM")) {
-    platform = p;
-  }
-
-  std::string bspName;
-  if (char const* bspCache =
-        this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME")) {
-    bspName = bspCache;
-    this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
-  } else {
-    bspName = "IGNORE";
-  }
-
-  if (platform.find("integrity") != std::string::npos &&
-      cmSystemTools::IsOff(bspName.c_str())) {
-    const char* a =
-      this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
-    bspName = "sim";
-    bspName += (a ? a : "");
-  }
-
-  if (!cmSystemTools::IsOff(bspName.c_str())) {
+  const char* bspName =
+    this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+  if (!cmSystemTools::IsOff(bspName)) {
     fout << "    -bsp " << bspName << std::endl;
   }
 
   // Specify OS DIR if supplied by user
   // -- not all platforms require this entry in the project file
-  std::string osDir;
-  std::string osDirOption;
-  if (char const* osDirCache =
-        this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR")) {
-    osDir = osDirCache;
+  if (!cmSystemTools::IsOff(this->OsDir.c_str())) {
+    const char* osDirOption =
+      this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION");
+    std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/');
+    fout << "    ";
+    if (cmSystemTools::IsOff(osDirOption)) {
+      fout << "";
+    } else {
+      fout << osDirOption;
+    }
+    fout << "\"" << this->OsDir << "\"" << std::endl;
   }
-
-  if (char const* osDirOptionCache =
-        this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION")) {
-    osDirOption = osDirOptionCache;
-  }
-
-  if (!cmSystemTools::IsOff(osDir.c_str()) ||
-      platform.find("integrity") != std::string::npos) {
-    std::replace(osDir.begin(), osDir.end(), '\\', '/');
-    fout << "    " << osDirOption << "\"" << osDir << "\"" << std::endl;
-  }
-
-  WriteSubProjects(fout, root, generators);
 }
 
-void cmGlobalGhsMultiGenerator::WriteSubProjects(
-  std::ostream& fout, cmLocalGenerator* root,
-  std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
+                                                 std::string& all_target)
 {
+  fout << "CMakeFiles/" << all_target << " [Project]" << std::endl;
+  // All known targets
+  for (cmGeneratorTarget const* target : this->ProjectTargets) {
+    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+        target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+        target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+        (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+         target->GetName() != GetInstallTargetName())) {
+      continue;
+    }
+    fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
+         << " [Project]" << std::endl;
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteProjectLine(
+  std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root,
+  std::string& rootBinaryDir)
+{
+  const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
+  const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+  if (projName && projType) {
+    cmLocalGenerator* lg = target->GetLocalGenerator();
+    std::string dir = lg->GetCurrentBinaryDirectory();
+    dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
+    if (dir == ".") {
+      dir.clear();
+    } else {
+      if (dir.back() != '/') {
+        dir += "/";
+      }
+    }
+
+    std::string projFile = dir + projName + FILE_EXTENSION;
+    fout << projFile;
+    fout << " " << projType << std::endl;
+  } else {
+    /* Should never happen */
+    std::string message =
+      "The project file for target [" + target->GetName() + "] is missing.\n";
+    cmSystemTools::Error(message);
+    fout << "{comment} " << target->GetName() << " [missing project file]\n";
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
+{
+  std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+  rootBinaryDir += "/CMakeFiles";
+
+  // All known targets
+  for (cmGeneratorTarget const* target : this->ProjectTargets) {
+    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+        target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+        target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+        (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+         target->GetName() != GetInstallTargetName())) {
+      continue;
+    }
+
+    // create target build file
+    std::string name = target->GetName() + ".tgt" + FILE_EXTENSION;
+    std::string fname = rootBinaryDir + "/" + name;
+    cmGeneratedFileStream fbld(fname);
+    fbld.SetCopyIfDifferent(true);
+    this->WriteFileHeader(fbld);
+    GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+    std::vector<cmGeneratorTarget const*> build;
+    if (ComputeTargetBuildOrder(target, build)) {
+      std::string message = "The inter-target dependency graph for target [" +
+        target->GetName() + "] had a cycle.\n";
+      cmSystemTools::Error(message);
+    } else {
+      for (auto& tgt : build) {
+        WriteProjectLine(fbld, tgt, root, rootBinaryDir);
+      }
+    }
+    fbld.Close();
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteAllTarget(
+  cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators,
+  std::string& all_target)
+{
+  this->ProjectTargets.clear();
+
+  // create target build file
+  all_target = root->GetProjectName() + "." + this->GetAllTargetName() +
+    ".tgt" + FILE_EXTENSION;
+  std::string fname =
+    root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target;
+  cmGeneratedFileStream fbld(fname);
+  fbld.SetCopyIfDifferent(true);
+  this->WriteFileHeader(fbld);
+  GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+
   // Collect all targets under this root generator and the transitive
   // closure of their dependencies.
   TargetDependSet projectTargets;
   TargetDependSet originalTargets;
   this->GetTargetSets(projectTargets, originalTargets, root, generators);
-  OrderedTargetDependSet orderedProjectTargets(projectTargets, "");
-
-  // write out all the sub-projects
-  std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
-  for (cmGeneratorTarget const* target : orderedProjectTargets) {
-    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+  OrderedTargetDependSet sortedProjectTargets(projectTargets, "");
+  std::vector<cmGeneratorTarget const*> defaultTargets;
+  for (cmGeneratorTarget const* t : sortedProjectTargets) {
+    /* save list of all targets in sorted order */
+    this->ProjectTargets.push_back(t);
+  }
+  for (cmGeneratorTarget const* t : sortedProjectTargets) {
+    if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
-
-    const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
-    const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
-    if (projName && projType) {
-      cmLocalGenerator* lg = target->GetLocalGenerator();
-      std::string dir = lg->GetCurrentBinaryDirectory();
-      dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir.c_str());
-      if (dir == ".") {
-        dir.clear();
-      } else {
-        if (dir.back() != '/') {
-          dir += "/";
-        }
-      }
-
-      if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) {
-        fout << "{comment} ";
-      }
-      std::string projFile = dir + projName + FILE_EXTENSION;
-      fout << projFile;
-      fout << " " << projType << std::endl;
-
-      if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) {
-        // create reference project
-        std::string fname = dir;
-        fname += target->GetName();
-        fname += "REF";
-        fname += FILE_EXTENSION;
-
-        cmGeneratedFileStream fref(fname.c_str());
-        fref.SetCopyIfDifferent(true);
-
-        this->WriteFileHeader(fref);
-        GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref);
-        fref << "    :reference=" << projFile << std::endl;
-
-        fref.Close();
-      }
+    if (!cmSystemTools::IsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) {
+      defaultTargets.push_back(t);
     }
   }
+  std::vector<cmGeneratorTarget const*> build;
+  if (ComputeTargetBuildOrder(defaultTargets, build)) {
+    std::string message = "The inter-target dependency graph for project [" +
+      root->GetProjectName() + "] had a cycle.\n";
+    cmSystemTools::Error(message);
+  } else {
+    // determine the targets for ALL target
+    std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+    rootBinaryDir += "/CMakeFiles";
+    for (cmGeneratorTarget const* target : build) {
+      if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+          target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+          target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+        continue;
+      }
+      this->WriteProjectLine(fbld, target, root, rootBinaryDir);
+    }
+  }
+  fbld.Close();
 }
 
 void cmGlobalGhsMultiGenerator::Generate()
 {
+  std::string fname;
+
   // first do the superclass method
   this->cmGlobalGenerator::Generate();
 
@@ -342,11 +505,32 @@
   for (auto& it : this->ProjectMap) {
     this->OutputTopLevelProject(it.second[0], it.second);
   }
+
+  // create custom rule BOD file
+  fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+    "/CMakeFiles/custom_rule.bod";
+  cmGeneratedFileStream frule(fname);
+  frule.SetCopyIfDifferent(true);
+  this->WriteFileHeader(frule);
+  this->WriteCustomRuleBOD(frule);
+  frule.Close();
+
+  // create custom target BOD file
+  fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+    "/CMakeFiles/custom_target.bod";
+  cmGeneratedFileStream ftarget(fname);
+  ftarget.SetCopyIfDifferent(true);
+  this->WriteFileHeader(ftarget);
+  this->WriteCustomTargetBOD(ftarget);
+  ftarget.Close();
 }
 
 void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
 {
+  std::string fname;
+  std::string all_target;
+
   if (generators.empty()) {
     return;
   }
@@ -355,86 +539,106 @@
    * with target projects.  This avoid the issue where the project has
    * the same name as the executable target.
    */
-  std::string fname = root->GetCurrentBinaryDirectory();
+  fname = root->GetCurrentBinaryDirectory();
   fname += "/";
   fname += root->GetProjectName();
   fname += ".top";
   fname += FILE_EXTENSION;
 
-  cmGeneratedFileStream fout(fname.c_str());
-  fout.SetCopyIfDifferent(true);
+  cmGeneratedFileStream top(fname);
+  top.SetCopyIfDifferent(true);
+  this->WriteTopLevelProject(top, root);
 
-  this->WriteTopLevelProject(fout, root, generators);
+  this->WriteAllTarget(root, generators, all_target);
+  this->WriteTargets(root);
 
-  fout.Close();
+  this->WriteSubProjects(top, all_target);
+  top.Close();
 }
 
-void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& projectDir,
-  const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
-  int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGhsMultiGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& projectDir, std::vector<std::string> const& targetNames,
+  const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/,
+  std::vector<std::string> const& makeOptions)
 {
-  const char* gbuild =
-    this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
-  makeCommand.add(this->SelectMakeProgram(makeProgram, (std::string)gbuild));
+  GeneratedMakeCommand makeCommand = {};
+  std::string gbuild;
+  if (const char* gbuildCached =
+        this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
+    gbuild = gbuildCached;
+  }
+  makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.add("-parallel");
+    makeCommand.Add("-parallel");
     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.add(std::to_string(jobs));
+      makeCommand.Add(std::to_string(jobs));
     }
   }
 
-  makeCommand.add(makeOptions.begin(), makeOptions.end());
+  makeCommand.Add(makeOptions.begin(), makeOptions.end());
 
   /* determine which top-project file to use */
   std::string proj = projectName + ".top" + FILE_EXTENSION;
   std::vector<std::string> files;
   cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
   if (!files.empty()) {
+    /* if multiple top-projects are found in build directory
+     * then prefer projectName top-project.
+     */
     auto p = std::find(files.begin(), files.end(), proj);
     if (p == files.end()) {
       proj = files.at(0);
     }
   }
 
-  makeCommand.add("-top", proj);
-  if (!targetName.empty()) {
-    if (targetName == "clean") {
-      makeCommand.add("-clean");
+  makeCommand.Add("-top", proj);
+  if (!targetNames.empty()) {
+    if (std::find(targetNames.begin(), targetNames.end(), "clean") !=
+        targetNames.end()) {
+      makeCommand.Add("-clean");
     } else {
-      if (targetName.compare(targetName.size() - 4, 4, ".gpj") == 0) {
-        makeCommand.add(targetName);
-      } else {
-        makeCommand.add(targetName + ".gpj");
+      for (const auto& tname : targetNames) {
+        if (!tname.empty()) {
+          makeCommand.Add(tname + ".tgt.gpj");
+        }
       }
     }
+  } else {
+    /* transform name to default build */;
+    std::string all = proj;
+    all.replace(all.end() - 7, all.end(),
+                std::string(this->GetAllTargetName()) + ".tgt.gpj");
+    makeCommand.Add(all);
   }
+  return { makeCommand };
 }
 
-void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
+                                            cmLocalGenerator* root)
 {
+  fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl;
   char const* ghsGpjMacros =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
-  if (NULL != ghsGpjMacros) {
+  if (nullptr != ghsGpjMacros) {
     std::vector<std::string> expandedList;
     cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList);
-    for (std::vector<std::string>::const_iterator expandedListI =
-           expandedList.begin();
-         expandedListI != expandedList.end(); ++expandedListI) {
-      fout << "macro " << *expandedListI << std::endl;
+    for (std::string const& arg : expandedList) {
+      fout << "macro " << arg << std::endl;
     }
   }
 }
 
-void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
+  cmLocalGenerator* root, std::ostream& fout)
 {
   /* set primary target */
   std::string tgt;
   const char* t =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
-  if (t) {
+  if (t && *t != '\0') {
     tgt = t;
     this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
   } else {
@@ -449,16 +653,20 @@
   }
 
   fout << "primaryTarget=" << tgt << std::endl;
+  fout << "customization=" << root->GetBinaryDirectory()
+       << "/CMakeFiles/custom_rule.bod" << std::endl;
+  fout << "customization=" << root->GetBinaryDirectory()
+       << "/CMakeFiles/custom_target.bod" << std::endl;
 
   char const* const customization =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
-  if (NULL != customization && strlen(customization) > 0) {
-    fout << "customization=" << trimQuotes(customization) << std::endl;
+  if (nullptr != customization && strlen(customization) > 0) {
+    fout << "customization=" << this->TrimQuotes(customization) << std::endl;
     this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
   }
 }
 
-std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
+std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str)
 {
   std::string result;
   result.reserve(str.size());
@@ -491,3 +699,56 @@
 {
   this->insert(targets.begin(), targets.end());
 }
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+  cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
+{
+  std::vector<cmGeneratorTarget const*> t{ tgt };
+  return ComputeTargetBuildOrder(t, build);
+}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+  std::vector<cmGeneratorTarget const*>& tgt,
+  std::vector<cmGeneratorTarget const*>& build)
+{
+  std::set<cmGeneratorTarget const*> temp;
+  std::set<cmGeneratorTarget const*> perm;
+
+  for (auto ti : tgt) {
+    bool r = VisitTarget(temp, perm, build, ti);
+    if (r) {
+      return r;
+    }
+  }
+  return false;
+}
+
+bool cmGlobalGhsMultiGenerator::VisitTarget(
+  std::set<cmGeneratorTarget const*>& temp,
+  std::set<cmGeneratorTarget const*>& perm,
+  std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti)
+{
+  /* check if permanent mark is set*/
+  if (perm.find(ti) == perm.end()) {
+    /* set temporary mark; check if revisit*/
+    if (temp.insert(ti).second) {
+      /* sort targets lexicographically to ensure that nodes are always visited
+       * in the same order */
+      OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
+                                           "");
+      for (auto& di : sortedTargets) {
+        if (this->VisitTarget(temp, perm, order, di)) {
+          return true;
+        }
+      }
+      /* mark as complete; insert into beginning of list*/
+      perm.insert(ti);
+      order.push_back(ti);
+      return false;
+    }
+    /* revisiting item - not a DAG */
+    return true;
+  }
+  /* already complete */
+  return false;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index bc2b199..98358c7 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -5,10 +5,20 @@
 
 #include "cmGlobalGenerator.h"
 
-#include "cmGhsMultiGpj.h"
 #include "cmGlobalGeneratorFactory.h"
+#include "cmTargetDepend.h"
 
-class cmGeneratedFileStream;
+#include <iosfwd>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmake;
+struct cmDocumentationEntry;
 
 class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
 {
@@ -17,21 +27,21 @@
   static const char* FILE_EXTENSION;
 
   cmGlobalGhsMultiGenerator(cmake* cm);
-  ~cmGlobalGhsMultiGenerator();
+  ~cmGlobalGhsMultiGenerator() override;
 
   static cmGlobalGeneratorFactory* NewFactory()
   {
     return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>();
   }
 
-  ///! create the correct local generator
+  //! create the correct local generator
   cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
 
   /// @return the name of this generator.
   static std::string GetActualName() { return "Green Hills MULTI"; }
 
-  ///! Get the name for this generator
-  std::string GetName() const override { return this->GetActualName(); }
+  //! Get the name for this generator
+  std::string GetName() const override { return GetActualName(); }
 
   /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
   static void GetDocumentation(cmDocumentationEntry& entry);
@@ -68,7 +78,54 @@
   // Write the common disclaimer text at the top of each build file.
   void WriteFileHeader(std::ostream& fout);
 
-  // Target dependency sorting
+  const char* GetInstallTargetName() const override { return "install"; }
+
+protected:
+  void Generate() override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
+
+private:
+  void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
+
+  /* top-level project */
+  void OutputTopLevelProject(cmLocalGenerator* root,
+                             std::vector<cmLocalGenerator*>& generators);
+  void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root);
+  void WriteMacros(std::ostream& fout, cmLocalGenerator* root);
+  void WriteHighLevelDirectives(cmLocalGenerator* root, std::ostream& fout);
+  void WriteSubProjects(std::ostream& fout, std::string& all_target);
+  void WriteTargets(cmLocalGenerator* root);
+  void WriteProjectLine(std::ostream& fout, cmGeneratorTarget const* target,
+                        cmLocalGenerator* root, std::string& rootBinaryDir);
+  void WriteCustomRuleBOD(std::ostream& fout);
+  void WriteCustomTargetBOD(std::ostream& fout);
+  void WriteAllTarget(cmLocalGenerator* root,
+                      std::vector<cmLocalGenerator*>& generators,
+                      std::string& all_target);
+
+  std::string TrimQuotes(std::string const& str);
+
+  std::string OsDir;
+  static const char* DEFAULT_BUILD_PROGRAM;
+  static const char* DEFAULT_TOOLSET_ROOT;
+
+  bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt,
+                               std::vector<cmGeneratorTarget const*>& build);
+  bool ComputeTargetBuildOrder(std::vector<cmGeneratorTarget const*>& tgt,
+                               std::vector<cmGeneratorTarget const*>& build);
+  bool VisitTarget(std::set<cmGeneratorTarget const*>& temp,
+                   std::set<cmGeneratorTarget const*>& perm,
+                   std::vector<cmGeneratorTarget const*>& order,
+                   cmGeneratorTarget const* ti);
+
+  std::vector<cmGeneratorTarget const*> ProjectTargets;
+
+  // Target sorting
   class TargetSet : public std::set<cmGeneratorTarget const*>
   {
   };
@@ -77,44 +134,14 @@
     std::string First;
 
   public:
-    TargetCompare(std::string const& first)
-      : First(first)
+    TargetCompare(std::string first)
+      : First(std::move(first))
     {
     }
     bool operator()(cmGeneratorTarget const* l,
                     cmGeneratorTarget const* r) const;
   };
   class OrderedTargetDependSet;
-
-protected:
-  void Generate() override;
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
-
-private:
-  void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
-
-  /* top-level project */
-  void OutputTopLevelProject(cmLocalGenerator* root,
-                             std::vector<cmLocalGenerator*>& generators);
-  void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root,
-                            std::vector<cmLocalGenerator*>& generators);
-  void WriteMacros(std::ostream& fout);
-  void WriteHighLevelDirectives(std::ostream& fout);
-  void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root,
-                        std::vector<cmLocalGenerator*>& generators);
-
-  std::string trimQuotes(std::string const& str);
-
-  static const char* DEFAULT_BUILD_PROGRAM;
-  static const char* DEFAULT_TOOLSET_ROOT;
 };
 
 class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 2b7f486..43c9666 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -54,11 +54,12 @@
   this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
 }
 
-void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& projectDir,
-  const std::string& targetName, const std::string& config, bool fast,
-  int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& projectDir, std::vector<std::string> const& targetNames,
+  const std::string& config, bool fast, int jobs, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
   std::vector<std::string> jomMakeOptions;
 
@@ -75,7 +76,7 @@
     jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
   }
 
-  cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeCommand, makeProgram, projectName, projectDir, targetName, config,
-    fast, jobs, verbose, jomMakeOptions);
+  return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+    makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+    verbose, jomMakeOptions);
 }
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index aa8b5fb..df3aec9 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -20,7 +20,7 @@
   {
     return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>();
   }
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override
   {
     return cmGlobalJOMMakefileGenerator::GetActualName();
@@ -40,15 +40,12 @@
                       bool optional) override;
 
 protected:
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
 private:
   void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
index 3c24556..606febe 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.cxx
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -45,7 +45,8 @@
   std::vector<std::string> const& l, cmMakefile* mf, bool optional)
 {
   this->FindMakeProgram(mf);
-  std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& makeProgram =
+    mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
   std::vector<std::string> locations;
   std::string makeloc = cmSystemTools::GetProgramPath(makeProgram.c_str());
   locations.push_back(this->FindMinGW(makeloc));
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
index 23dbc5e..d6e4847 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.h
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -19,7 +19,7 @@
     return new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>();
   }
 
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   virtual std::string GetName() const
   {
     return cmGlobalMSYSMakefileGenerator::GetActualName();
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
index c6d46e9..e218b4b 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.cxx
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -23,7 +23,8 @@
   std::vector<std::string> const& l, cmMakefile* mf, bool optional)
 {
   this->FindMakeProgram(mf);
-  std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+  const std::string& makeProgram =
+    mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
   std::vector<std::string> locations;
   locations.push_back(cmSystemTools::GetProgramPath(makeProgram));
   locations.push_back("/mingw/bin");
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
index a994c92..15297e3 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.h
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -19,7 +19,7 @@
     return new cmGlobalGeneratorSimpleFactory<
       cmGlobalMinGWMakefileGenerator>();
   }
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   virtual std::string GetName() const
   {
     return cmGlobalMinGWMakefileGenerator::GetActualName();
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index ffe95f9..a4838bc 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -54,11 +54,12 @@
   this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
 }
 
-void cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& projectDir,
-  const std::string& targetName, const std::string& config, bool fast,
-  int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& projectDir, std::vector<std::string> const& targetNames,
+  const std::string& config, bool fast, int /*jobs*/, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
   std::vector<std::string> nmakeMakeOptions;
 
@@ -68,9 +69,9 @@
   nmakeMakeOptions.insert(nmakeMakeOptions.end(), makeOptions.begin(),
                           makeOptions.end());
 
-  this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeCommand, makeProgram, projectName, projectDir, targetName, config,
-    fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
+  return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+    makeProgram, projectName, projectDir, targetNames, config, fast,
+    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
 }
 
 void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 06c48e2..2fdf1ce 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -21,7 +21,7 @@
     return new cmGlobalGeneratorSimpleFactory<
       cmGlobalNMakeMakefileGenerator>();
   }
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override
   {
     return cmGlobalNMakeMakefileGenerator::GetActualName();
@@ -45,15 +45,12 @@
                       bool optional) override;
 
 protected:
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
 
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 920f639..4fa6ee6 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -26,6 +26,7 @@
 #include "cmMessageType.h"
 #include "cmNinjaLinkLineComputer.h"
 #include "cmOutputConverter.h"
+#include "cmRange.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
@@ -136,16 +137,16 @@
   // Make sure there is a rule.
   if (rule.empty()) {
     cmSystemTools::Error("No rule for WriteBuildStatement! called "
-                         "with comment: ",
-                         comment.c_str());
+                         "with comment: " +
+                         comment);
     return;
   }
 
   // Make sure there is at least one output file.
   if (outputs.empty()) {
     cmSystemTools::Error("No output files for WriteBuildStatement! called "
-                         "with comment: ",
-                         comment.c_str());
+                         "with comment: " +
+                         comment);
     return;
   }
 
@@ -334,16 +335,16 @@
   // Make sure the rule has a name.
   if (name.empty()) {
     cmSystemTools::Error("No name given for WriteRuleStatement! called "
-                         "with comment: ",
-                         comment.c_str());
+                         "with comment: " +
+                         comment);
     return;
   }
 
   // Make sure a command is given.
   if (command.empty()) {
     cmSystemTools::Error("No command given for WriteRuleStatement! called "
-                         "with comment: ",
-                         comment.c_str());
+                         "with comment: " +
+                         comment);
     return;
   }
 
@@ -376,7 +377,7 @@
 
   if (!rspfile.empty()) {
     if (rspcontent.empty()) {
-      cmSystemTools::Error("No rspfile_content given!", comment.c_str());
+      cmSystemTools::Error("No rspfile_content given!" + comment);
       return;
     }
     cmGlobalNinjaGenerator::Indent(os, 1);
@@ -407,8 +408,8 @@
   // Make sure we have a name.
   if (name.empty()) {
     cmSystemTools::Error("No name given for WriteVariable! called "
-                         "with comment: ",
-                         comment.c_str());
+                         "with comment: " +
+                         comment);
     return;
   }
 
@@ -676,31 +677,37 @@
 //   cmGlobalXCodeGenerator
 // Called by:
 //   cmGlobalGenerator::Build()
-void cmGlobalNinjaGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& /*projectName*/, const std::string& /*projectDir*/,
-  const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
-  int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNinjaGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& /*projectName*/,
+  const std::string& /*projectDir*/,
+  std::vector<std::string> const& targetNames, const std::string& /*config*/,
+  bool /*fast*/, int jobs, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
-  makeCommand.add(this->SelectMakeProgram(makeProgram));
+  GeneratedMakeCommand makeCommand;
+  makeCommand.Add(this->SelectMakeProgram(makeProgram));
 
   if (verbose) {
-    makeCommand.add("-v");
+    makeCommand.Add("-v");
   }
 
   if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
       (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
-    makeCommand.add("-j", std::to_string(jobs));
+    makeCommand.Add("-j", std::to_string(jobs));
   }
 
-  makeCommand.add(makeOptions.begin(), makeOptions.end());
-  if (!targetName.empty()) {
-    if (targetName == "clean") {
-      makeCommand.add("-t", "clean");
-    } else {
-      makeCommand.add(targetName);
+  makeCommand.Add(makeOptions.begin(), makeOptions.end());
+  for (const auto& tname : targetNames) {
+    if (!tname.empty()) {
+      if (tname == "clean") {
+        makeCommand.Add("-t", "clean");
+      } else {
+        makeCommand.Add(tname);
+      }
     }
   }
+  return { std::move(makeCommand) };
 }
 
 // Non-virtual public methods.
@@ -899,11 +906,11 @@
 
   /* clang-format off */
   *this->CompileCommandsStream << "\n{\n"
-     << "  \"directory\": \""
+     << R"(  "directory": ")"
      << cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
-     << "  \"command\": \""
+     << R"(  "command": ")"
      << cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
-     << "  \"file\": \""
+     << R"(  "file": ")"
      << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
      << "}";
   /* clang-format on */
@@ -1573,12 +1580,13 @@
       command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out &&
                 cmake -E cmake_ninja_depends \
                   --tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \
-                  --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE
+                  --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \
+                  --lang=Fortran
 
-    build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90
+    build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90
       OBJ_FILE = src.f90.o
-      DEP_FILE = src.f90-pp.f90.d
-      DYNDEP_INTERMEDIATE_FILE = src.f90-pp.f90.ddi
+      DEP_FILE = src.f90.o.d
+      DYNDEP_INTERMEDIATE_FILE = src.f90.o.ddi
 
    The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output
    and generates the ninja depfile for preprocessor dependencies.  It also
@@ -1592,9 +1600,9 @@
 
     rule Fortran_DYNDEP
       command = cmake -E cmake_ninja_dyndep \
-                  --tdi=FortranDependInfo.json --dd=$out $in
+                  --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in
 
-    build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi
+    build Fortran.dd: Fortran_DYNDEP src1.f90.o.ddi src2.f90.o.ddi
 
    The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all
    sources in the target and the ``FortranModules.json`` files from targets
@@ -1632,6 +1640,19 @@
    (because the latter consumes the module).
 */
 
+struct cmSourceInfo
+{
+  // Set of provided and required modules.
+  std::set<std::string> Provides;
+  std::set<std::string> Requires;
+
+  // Set of files included in the translation unit.
+  std::set<std::string> Includes;
+};
+
+static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+  std::string const& arg_tdi, std::string const& arg_pp);
+
 int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
                               std::vector<std::string>::const_iterator argEnd)
 {
@@ -1640,8 +1661,8 @@
   std::string arg_dep;
   std::string arg_obj;
   std::string arg_ddi;
-  for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
-    std::string const& arg = *a;
+  std::string arg_lang;
+  for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
     if (cmHasLiteralPrefix(arg, "--tdi=")) {
       arg_tdi = arg.substr(6);
     } else if (cmHasLiteralPrefix(arg, "--pp=")) {
@@ -1652,9 +1673,10 @@
       arg_obj = arg.substr(6);
     } else if (cmHasLiteralPrefix(arg, "--ddi=")) {
       arg_ddi = arg.substr(6);
+    } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+      arg_lang = arg.substr(7);
     } else {
-      cmSystemTools::Error("-E cmake_ninja_depends unknown argument: ",
-                           arg.c_str());
+      cmSystemTools::Error("-E cmake_ninja_depends unknown argument: " + arg);
       return 1;
     }
   }
@@ -1678,7 +1700,61 @@
     cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi=");
     return 1;
   }
+  if (arg_lang.empty()) {
+    cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang=");
+    return 1;
+  }
 
+  std::unique_ptr<cmSourceInfo> info;
+  if (arg_lang == "Fortran") {
+    info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp);
+  } else {
+    cmSystemTools::Error("-E cmake_ninja_depends does not understand the " +
+                         arg_lang + " language");
+    return 1;
+  }
+
+  if (!info) {
+    // The error message is already expected to have been output.
+    return 1;
+  }
+
+  {
+    cmGeneratedFileStream depfile(arg_dep);
+    depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
+    for (std::string const& include : info->Includes) {
+      depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
+    }
+    depfile << "\n";
+  }
+
+  Json::Value ddi(Json::objectValue);
+  ddi["object"] = arg_obj;
+
+  Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
+  for (std::string const& provide : info->Provides) {
+    ddi_provides.append(provide);
+  }
+  Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
+  for (std::string const& r : info->Requires) {
+    // Require modules not provided in the same source.
+    if (!info->Provides.count(r)) {
+      ddi_requires.append(r);
+    }
+  }
+
+  cmGeneratedFileStream ddif(arg_ddi);
+  ddif << ddi;
+  if (!ddif) {
+    cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi);
+    return 1;
+  }
+  return 0;
+}
+
+std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+  std::string const& arg_tdi, std::string const& arg_pp)
+{
   cmFortranCompiler fc;
   std::vector<std::string> includes;
   {
@@ -1688,10 +1764,9 @@
       cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
       Json::Reader reader;
       if (!reader.parse(tdif, tdio, false)) {
-        cmSystemTools::Error("-E cmake_ninja_depends failed to parse ",
-                             arg_tdi.c_str(),
-                             reader.getFormattedErrorMessages().c_str());
-        return 1;
+        cmSystemTools::Error("-E cmake_ninja_depends failed to parse " +
+                             arg_tdi + reader.getFormattedErrorMessages());
+        return nullptr;
       }
     }
 
@@ -1712,54 +1787,26 @@
     fc.SModExt = tdi_submodule_ext.asString();
   }
 
-  cmFortranSourceInfo info;
+  cmFortranSourceInfo finfo;
   std::set<std::string> defines;
-  cmFortranParser parser(fc, includes, defines, info);
+  cmFortranParser parser(fc, includes, defines, finfo);
   if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) {
-    cmSystemTools::Error("-E cmake_ninja_depends failed to open ",
-                         arg_pp.c_str());
-    return 1;
+    cmSystemTools::Error("-E cmake_ninja_depends failed to open " + arg_pp);
+    return nullptr;
   }
   if (cmFortran_yyparse(parser.Scanner) != 0) {
     // Failed to parse the file.
-    return 1;
+    return nullptr;
   }
 
-  {
-    cmGeneratedFileStream depfile(arg_dep);
-    depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
-    for (std::string const& include : info.Includes) {
-      depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
-    }
-    depfile << "\n";
-  }
-
-  Json::Value ddi(Json::objectValue);
-  ddi["object"] = arg_obj;
-
-  Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
-  for (std::string const& provide : info.Provides) {
-    ddi_provides.append(provide);
-  }
-  Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
-  for (std::string const& r : info.Requires) {
-    // Require modules not provided in the same source.
-    if (!info.Provides.count(r)) {
-      ddi_requires.append(r);
-    }
-  }
-
-  cmGeneratedFileStream ddif(arg_ddi);
-  ddif << ddi;
-  if (!ddif) {
-    cmSystemTools::Error("-E cmake_ninja_depends failed to write ",
-                         arg_ddi.c_str());
-    return 1;
-  }
-  return 0;
+  auto info = cm::make_unique<cmSourceInfo>();
+  info->Provides = finfo.Provides;
+  info->Requires = finfo.Requires;
+  info->Includes = finfo.Includes;
+  return info;
 }
 
-struct cmFortranObjectInfo
+struct cmDyndepObjectInfo
 {
   std::string Object;
   std::vector<std::string> Provides;
@@ -1771,7 +1818,8 @@
   std::string const& dir_cur_src, std::string const& dir_cur_bld,
   std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
   std::string const& module_dir,
-  std::vector<std::string> const& linked_target_dirs)
+  std::vector<std::string> const& linked_target_dirs,
+  std::string const& arg_lang)
 {
   // Setup path conversions.
   {
@@ -1788,7 +1836,7 @@
     this->LocalGenerators.push_back(lgd.release());
   }
 
-  std::vector<cmFortranObjectInfo> objects;
+  std::vector<cmDyndepObjectInfo> objects;
   for (std::string const& arg_ddi : arg_ddis) {
     // Load the ddi file and compute the module file paths it provides.
     Json::Value ddio;
@@ -1796,13 +1844,12 @@
     cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
     if (!reader.parse(ddif, ddio, false)) {
-      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
-                           arg_ddi.c_str(),
-                           reader.getFormattedErrorMessages().c_str());
+      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_ddi +
+                           reader.getFormattedErrorMessages());
       return false;
     }
 
-    cmFortranObjectInfo info;
+    cmDyndepObjectInfo info;
     info.Object = ddi["object"].asString();
     Json::Value const& ddi_provides = ddi["provides"];
     if (ddi_provides.isArray()) {
@@ -1824,14 +1871,15 @@
 
   // Populate the module map with those provided by linked targets first.
   for (std::string const& linked_target_dir : linked_target_dirs) {
-    std::string const ltmn = linked_target_dir + "/FortranModules.json";
+    std::string const ltmn =
+      linked_target_dir + "/" + arg_lang + "Modules.json";
     Json::Value ltm;
     cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
     if (ltmf && !reader.parse(ltmf, ltm, false)) {
-      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
-                           linked_target_dir.c_str(),
-                           reader.getFormattedErrorMessages().c_str());
+      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " +
+                           linked_target_dir +
+                           reader.getFormattedErrorMessages());
       return false;
     }
     if (ltm.isObject()) {
@@ -1845,7 +1893,7 @@
   // We do this after loading the modules provided by linked targets
   // in case we have one of the same name that must be preferred.
   Json::Value tm = Json::objectValue;
-  for (cmFortranObjectInfo const& object : objects) {
+  for (cmDyndepObjectInfo const& object : objects) {
     for (std::string const& p : object.Provides) {
       std::string const mod = module_dir + p;
       mod_files[p] = mod;
@@ -1856,7 +1904,7 @@
   cmGeneratedFileStream ddf(arg_dd);
   ddf << "ninja_dyndep_version = 1.0\n";
 
-  for (cmFortranObjectInfo const& object : objects) {
+  for (cmDyndepObjectInfo const& object : objects) {
     std::string const ddComment;
     std::string const ddRule = "dyndep";
     cmNinjaDeps ddOutputs;
@@ -1887,7 +1935,7 @@
   // Store the map of modules provided by this target in a file for
   // use by dependents that reference this target in linked-target-dirs.
   std::string const target_mods_file =
-    cmSystemTools::GetFilenamePath(arg_dd) + "/FortranModules.json";
+    cmSystemTools::GetFilenamePath(arg_dd) + "/" + arg_lang + "Modules.json";
   cmGeneratedFileStream tmf(target_mods_file);
   tmf << tm;
 
@@ -1901,19 +1949,21 @@
     cmSystemTools::HandleResponseFile(argBeg, argEnd);
 
   std::string arg_dd;
+  std::string arg_lang;
   std::string arg_tdi;
   std::vector<std::string> arg_ddis;
   for (std::string const& arg : arg_full) {
     if (cmHasLiteralPrefix(arg, "--tdi=")) {
       arg_tdi = arg.substr(6);
+    } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+      arg_lang = arg.substr(7);
     } else if (cmHasLiteralPrefix(arg, "--dd=")) {
       arg_dd = arg.substr(5);
     } else if (!cmHasLiteralPrefix(arg, "--") &&
                cmHasLiteralSuffix(arg, ".ddi")) {
       arg_ddis.push_back(arg);
     } else {
-      cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: ",
-                           arg.c_str());
+      cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: " + arg);
       return 1;
     }
   }
@@ -1921,6 +1971,10 @@
     cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi=");
     return 1;
   }
+  if (arg_lang.empty()) {
+    cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --lang=");
+    return 1;
+  }
   if (arg_dd.empty()) {
     cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd=");
     return 1;
@@ -1932,9 +1986,8 @@
     cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
     if (!reader.parse(tdif, tdio, false)) {
-      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
-                           arg_tdi.c_str(),
-                           reader.getFormattedErrorMessages().c_str());
+      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_tdi +
+                           reader.getFormattedErrorMessages());
       return 1;
     }
   }
@@ -1944,7 +1997,7 @@
   std::string const dir_top_bld = tdi["dir-top-bld"].asString();
   std::string const dir_top_src = tdi["dir-top-src"].asString();
   std::string module_dir = tdi["module-dir"].asString();
-  if (!module_dir.empty()) {
+  if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) {
     module_dir += "/";
   }
   std::vector<std::string> linked_target_dirs;
@@ -1962,8 +2015,8 @@
     static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja")));
   if (!ggd ||
       !ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld,
-                            arg_dd, arg_ddis, module_dir,
-                            linked_target_dirs)) {
+                            arg_dd, arg_ddis, module_dir, linked_target_dirs,
+                            arg_lang)) {
     return 1;
   }
   return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index c619e67..efd1d8f 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -200,15 +200,12 @@
   void EnableLanguage(std::vector<std::string> const& languages,
                       cmMakefile* mf, bool optional) override;
 
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   // Setup target names
   const char* GetAllTargetName() const override { return "all"; }
@@ -365,7 +362,8 @@
                        std::string const& arg_dd,
                        std::vector<std::string> const& arg_ddis,
                        std::string const& module_dir,
-                       std::vector<std::string> const& linked_target_dirs);
+                       std::vector<std::string> const& linked_target_dirs,
+                       std::string const& arg_lang);
 
 protected:
   void Generate() override;
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index dac6ea6..65d816e 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -57,7 +57,7 @@
   }
 }
 
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
 cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(
   cmMakefile* mf)
 {
@@ -177,13 +177,13 @@
     *this->CommandDatabase << "," << std::endl;
   }
   *this->CommandDatabase << "{" << std::endl
-                         << "  \"directory\": \""
+                         << R"(  "directory": ")"
                          << cmGlobalGenerator::EscapeJSON(workingDirectory)
                          << "\"," << std::endl
-                         << "  \"command\": \""
+                         << R"(  "command": ")"
                          << cmGlobalGenerator::EscapeJSON(compileCommand)
                          << "\"," << std::endl
-                         << "  \"file\": \""
+                         << R"(  "file": ")"
                          << cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
                          << std::endl
                          << "}";
@@ -494,11 +494,13 @@
   this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
 }
 
-void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& /*projectName*/, const std::string& /*projectDir*/,
-  const std::string& targetName, const std::string& /*config*/, bool fast,
-  int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& /*projectName*/,
+  const std::string& /*projectDir*/,
+  std::vector<std::string> const& targetNames, const std::string& /*config*/,
+  bool fast, int jobs, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
   std::unique_ptr<cmMakefile> mfu;
   cmMakefile* mf;
@@ -515,34 +517,38 @@
     mf = mfu.get();
   }
 
+  GeneratedMakeCommand makeCommand;
+
   // Make it possible to set verbosity also from command line
   if (verbose) {
-    makeCommand.add(cmSystemTools::GetCMakeCommand());
-    makeCommand.add("-E");
-    makeCommand.add("env");
-    makeCommand.add("VERBOSE=1");
+    makeCommand.Add(cmSystemTools::GetCMakeCommand());
+    makeCommand.Add("-E");
+    makeCommand.Add("env");
+    makeCommand.Add("VERBOSE=1");
   }
-  makeCommand.add(this->SelectMakeProgram(makeProgram));
+  makeCommand.Add(this->SelectMakeProgram(makeProgram));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.add("-j");
+    makeCommand.Add("-j");
     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.add(std::to_string(jobs));
+      makeCommand.Add(std::to_string(jobs));
     }
   }
 
-  makeCommand.add(makeOptions.begin(), makeOptions.end());
-  if (!targetName.empty()) {
-    std::string tname = targetName;
-    if (fast) {
-      tname += "/fast";
+  makeCommand.Add(makeOptions.begin(), makeOptions.end());
+  for (auto tname : targetNames) {
+    if (!tname.empty()) {
+      if (fast) {
+        tname += "/fast";
+      }
+      tname =
+        mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
+          mf->GetState()->GetBinaryDirectory(), tname);
+      cmSystemTools::ConvertToOutputSlashes(tname);
+      makeCommand.Add(std::move(tname));
     }
-    tname =
-      mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
-        mf->GetState()->GetBinaryDirectory(), tname);
-    cmSystemTools::ConvertToOutputSlashes(tname);
-    makeCommand.add(std::move(tname));
   }
+  return { std::move(makeCommand) };
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 8a80acc..e919d38 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -67,7 +67,7 @@
       cmGlobalUnixMakefileGenerator3>();
   }
 
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override
   {
     return cmGlobalUnixMakefileGenerator3::GetActualName();
@@ -127,15 +127,12 @@
   std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
 
   // change the build command for speed
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   /** Record per-target progress information.  */
   void RecordTargetProgress(cmMakefileTargetGenerator* tg);
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index d8b2e89..4fa89d0 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -509,7 +509,7 @@
   return "";
 }
 
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
 cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
   cmMakefile* mf)
 {
@@ -878,12 +878,14 @@
   return true;
 }
 
-void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& projectDir,
-  const std::string& targetName, const std::string& config, bool fast,
-  int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio10Generator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& projectDir, std::vector<std::string> const& targetNames,
+  const std::string& config, bool fast, int jobs, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
+  std::vector<GeneratedMakeCommand> makeCommands;
   // Select the caller- or user-preferred make program, else MSBuild.
   std::string makeProgramSelected =
     this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
@@ -895,7 +897,7 @@
                     makeProgramLower.find("vcexpress") != std::string::npos);
 
   // Workaround to convince VCExpress.exe to produce output.
-  makeCommand.RequiresOutputForward =
+  const bool requiresOutputForward =
     (makeProgramLower.find("vcexpress") != std::string::npos);
 
   // MSBuild is preferred (and required for VS Express), but if the .sln has
@@ -913,10 +915,11 @@
     if (parser.ParseFile(slnFile, slnData,
                          cmVisualStudioSlnParser::DataGroupProjects)) {
       std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
-      for (std::vector<cmSlnProjectEntry>::const_iterator i =
-             slnProjects.cbegin();
-           !useDevEnv && i != slnProjects.cend(); ++i) {
-        std::string proj = i->GetRelativePath();
+      for (cmSlnProjectEntry const& project : slnProjects) {
+        if (useDevEnv) {
+          break;
+        }
+        std::string proj = project.GetRelativePath();
         if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
           useDevEnv = true;
         }
@@ -925,62 +928,71 @@
   }
   if (useDevEnv) {
     // Use devenv to build solutions containing Intel Fortran projects.
-    cmGlobalVisualStudio7Generator::GenerateBuildCommand(
-      makeCommand, makeProgram, projectName, projectDir, targetName, config,
-      fast, jobs, verbose, makeOptions);
-    return;
+    return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+      makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+      verbose, makeOptions);
   }
 
-  makeCommand.add(makeProgramSelected);
-
-  std::string realTarget = targetName;
-  // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
-  //                         /m
-  if (realTarget.empty()) {
-    realTarget = "ALL_BUILD";
+  std::vector<std::string> realTargetNames = targetNames;
+  if (targetNames.empty() ||
+      ((targetNames.size() == 1) && targetNames.front().empty())) {
+    realTargetNames = { "ALL_BUILD" };
   }
-  if (realTarget == "clean") {
-    makeCommand.add(std::string(projectName) + ".sln");
-    makeCommand.add("/t:Clean");
-  } else {
-    std::string targetProject(realTarget);
-    targetProject += ".vcxproj";
-    if (targetProject.find('/') == std::string::npos) {
-      // it might be in a subdir
-      if (cmSlnProjectEntry const* proj =
-            slnData.GetProjectByName(realTarget)) {
-        targetProject = proj->GetRelativePath();
-        cmSystemTools::ConvertToUnixSlashes(targetProject);
-      }
+  for (const auto& tname : realTargetNames) {
+    // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
+    // /target:ALL_BUILD
+    //                         /m
+    if (tname.empty()) {
+      continue;
     }
-    makeCommand.add(std::move(targetProject));
-  }
-  std::string configArg = "/p:Configuration=";
-  if (!config.empty()) {
-    configArg += config;
-  } else {
-    configArg += "Debug";
-  }
-  makeCommand.add(configArg);
-  makeCommand.add(std::string("/p:Platform=") + this->GetPlatformName());
-  makeCommand.add(std::string("/p:VisualStudioVersion=") +
-                  this->GetIDEVersion());
 
-  if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.add("/m");
+    GeneratedMakeCommand makeCommand;
+    makeCommand.RequiresOutputForward = requiresOutputForward;
+    makeCommand.Add(makeProgramSelected);
+
+    if (tname == "clean") {
+      makeCommand.Add(std::string(projectName) + ".sln");
+      makeCommand.Add("/t:Clean");
     } else {
-      makeCommand.add(std::string("/m:") + std::to_string(jobs));
+      std::string targetProject(tname);
+      targetProject += ".vcxproj";
+      if (targetProject.find('/') == std::string::npos) {
+        // it might be in a subdir
+        if (cmSlnProjectEntry const* proj = slnData.GetProjectByName(tname)) {
+          targetProject = proj->GetRelativePath();
+          cmSystemTools::ConvertToUnixSlashes(targetProject);
+        }
+      }
+      makeCommand.Add(std::move(targetProject));
     }
-    // Having msbuild.exe and cl.exe using multiple jobs is discouraged
-    makeCommand.add("/p:CL_MPCount=1");
+    std::string configArg = "/p:Configuration=";
+    if (!config.empty()) {
+      configArg += config;
+    } else {
+      configArg += "Debug";
+    }
+    makeCommand.Add(configArg);
+    makeCommand.Add(std::string("/p:Platform=") + this->GetPlatformName());
+    makeCommand.Add(std::string("/p:VisualStudioVersion=") +
+                    this->GetIDEVersion());
+
+    if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+      if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+        makeCommand.Add("/m");
+      } else {
+        makeCommand.Add(std::string("/m:") + std::to_string(jobs));
+      }
+      // Having msbuild.exe and cl.exe using multiple jobs is discouraged
+      makeCommand.Add("/p:CL_MPCount=1");
+    }
+
+    // Respect the verbosity: 'n' normal will show build commands
+    //                        'm' minimal only the build step's title
+    makeCommand.Add(std::string("/v:") + ((verbose) ? "n" : "m"));
+    makeCommand.Add(makeOptions.begin(), makeOptions.end());
+    makeCommands.emplace_back(std::move(makeCommand));
   }
-
-  // Respect the verbosity: 'n' normal will show build commands
-  //                        'm' minimal only the build step's title
-  makeCommand.add(std::string("/v:") + ((verbose) ? "n" : "m"));
-
-  makeCommand.add(makeOptions.begin(), makeOptions.end());
+  return makeCommands;
 }
 
 bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
@@ -1005,7 +1017,7 @@
         winSDK_7_1)) {
     std::ostringstream m;
     m << "Found Windows SDK v7.1: " << winSDK_7_1;
-    mf->DisplayStatus(m.str().c_str(), -1);
+    mf->DisplayStatus(m.str(), -1);
     this->DefaultPlatformToolset = "Windows7.1SDK";
     return true;
   } else {
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 3ef7abf..2f532a6 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -22,17 +22,14 @@
   bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
   bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
 
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
-  ///! create the correct local generator
+  //! create the correct local generator
   cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
 
   /**
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 4eb78ba..4b74ef1 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -252,15 +252,10 @@
   return ret;
 }
 
-bool cmGlobalVisualStudio11Generator::NeedsDeploy(
-  cmStateEnums::TargetType type) const
+bool cmGlobalVisualStudio11Generator::TargetSystemSupportsDeployment() const
 {
-  if ((type == cmStateEnums::EXECUTABLE ||
-       type == cmStateEnums::SHARED_LIBRARY) &&
-      (this->SystemIsWindowsPhone || this->SystemIsWindowsStore)) {
-    return true;
-  }
-  return cmGlobalVisualStudio10Generator::NeedsDeploy(type);
+  return this->SystemIsWindowsPhone || this->SystemIsWindowsStore ||
+    cmGlobalVisualStudio10Generator::TargetSystemSupportsDeployment();
 }
 
 bool cmGlobalVisualStudio11Generator::IsWindowsDesktopToolsetInstalled() const
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index 8b4c8b7..f8cce18 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -45,8 +45,8 @@
   bool UseFolderProperty() const override;
   static std::set<std::string> GetInstalledWindowsCESDKs();
 
-  /** Return true if the configuration needs to be deployed */
-  bool NeedsDeploy(cmStateEnums::TargetType type) const override;
+  /** Return true if target system supports debugging deployment. */
+  bool TargetSystemSupportsDeployment() const override;
 
 private:
   class Factory;
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 2025867..6509b56 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -179,7 +179,7 @@
     std::ostringstream e;
     e << "Selecting Windows SDK version " << this->WindowsTargetPlatformVersion
       << " to target Windows " << this->SystemVersion << ".";
-    mf->DisplayStatus(e.str().c_str(), -1);
+    mf->DisplayStatus(e.str(), -1);
   }
   mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
                     this->WindowsTargetPlatformVersion.c_str());
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index d457f60..d7630e4 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -190,11 +190,14 @@
   }
   return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
 }
-void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& /*projectDir*/,
-  const std::string& targetName, const std::string& config, bool /*fast*/,
-  int /*jobs*/, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& /*projectDir*/,
+  std::vector<std::string> const& targetNames, const std::string& config,
+  bool /*fast*/, int /*jobs*/, bool /*verbose*/,
+  std::vector<std::string> const& makeOptions)
 {
   // Select the caller- or user-preferred make program, else devenv.
   std::string makeProgramSelected =
@@ -210,27 +213,42 @@
   }
 
   // Workaround to convince VCExpress.exe to produce output.
-  makeCommand.RequiresOutputForward =
+  const bool requiresOutputForward =
     (makeProgramLower.find("vcexpress") != std::string::npos);
+  std::vector<GeneratedMakeCommand> makeCommands;
 
-  makeCommand.add(makeProgramSelected);
-
-  makeCommand.add(std::string(projectName) + ".sln");
-  std::string realTarget = targetName;
-  bool clean = false;
-  if (realTarget == "clean") {
-    clean = true;
-    realTarget = "ALL_BUILD";
+  std::vector<std::string> realTargetNames = targetNames;
+  if (targetNames.empty() ||
+      ((targetNames.size() == 1) && targetNames.front().empty())) {
+    realTargetNames = { "ALL_BUILD" };
   }
-
-  makeCommand.add((clean ? "/clean" : "/build"));
-  makeCommand.add((config.empty() ? "Debug" : config));
-  makeCommand.add("/project");
-  makeCommand.add((realTarget.empty() ? "ALL_BUILD" : realTarget));
-  makeCommand.add(makeOptions.begin(), makeOptions.end());
+  for (const auto& tname : realTargetNames) {
+    std::string realTarget;
+    if (!tname.empty()) {
+      realTarget = tname;
+    } else {
+      continue;
+    }
+    bool clean = false;
+    if (realTarget == "clean") {
+      clean = true;
+      realTarget = "ALL_BUILD";
+    }
+    GeneratedMakeCommand makeCommand;
+    makeCommand.RequiresOutputForward = requiresOutputForward;
+    makeCommand.Add(makeProgramSelected);
+    makeCommand.Add(std::string(projectName) + ".sln");
+    makeCommand.Add((clean ? "/clean" : "/build"));
+    makeCommand.Add((config.empty() ? "Debug" : config));
+    makeCommand.Add("/project");
+    makeCommand.Add(realTarget);
+    makeCommand.Add(makeOptions.begin(), makeOptions.end());
+    makeCommands.emplace_back(std::move(makeCommand));
+  }
+  return makeCommands;
 }
 
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
 cmLocalGenerator* cmGlobalVisualStudio7Generator::CreateLocalGenerator(
   cmMakefile* mf)
 {
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 3f1c173..1e76383 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -20,7 +20,7 @@
 public:
   ~cmGlobalVisualStudio7Generator();
 
-  ///! Create a local generator appropriate to this Global Generator
+  //! Create a local generator appropriate to this Global Generator
   cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -52,22 +52,19 @@
    * Try running cmake and building a file. This is used for dynamically
    * loaded commands, not as part of the usual build process.
    */
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   /**
    * Generate the DSW workspace file.
    */
   virtual void OutputSLNFile();
 
-  ///! Lookup a stored GUID or compute one deterministically.
+  //! Lookup a stored GUID or compute one deterministically.
   std::string GetGUID(std::string const& name);
 
   /** Append the subdirectory for the given configuration.  */
@@ -76,7 +73,7 @@
                                 const std::string& suffix,
                                 std::string& dir) override;
 
-  ///! What is the configurations directory variable called?
+  //! What is the configurations directory variable called?
   const char* GetCMakeCFGIntDir() const override
   {
     return "$(ConfigurationName)";
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index f6db018..21abdf7 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -205,7 +205,7 @@
           "Checking Build System", no_working_directory, true, false)) {
       gt->AddSource(file->GetFullPath());
     } else {
-      cmSystemTools::Error("Error adding rule for ", stamps[0].c_str());
+      cmSystemTools::Error("Error adding rule for " + stamps[0]);
     }
   }
 
@@ -273,7 +273,7 @@
                                         : this->GetPlatformName())
            << "\n";
     }
-    if (this->NeedsDeploy(target.GetType())) {
+    if (this->NeedsDeploy(target, dstConfig)) {
       fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
            << ".Deploy.0 = " << dstConfig << "|"
            << (!platformMapping.empty() ? platformMapping
@@ -284,11 +284,32 @@
 }
 
 bool cmGlobalVisualStudio8Generator::NeedsDeploy(
-  cmStateEnums::TargetType type) const
+  cmGeneratorTarget const& target, const char* config) const
 {
-  bool needsDeploy =
-    (type == cmStateEnums::EXECUTABLE || type == cmStateEnums::SHARED_LIBRARY);
-  return this->TargetsWindowsCE() && needsDeploy;
+  cmStateEnums::TargetType type = target.GetType();
+  bool noDeploy = DeployInhibited(target, config);
+  return !noDeploy &&
+    (type == cmStateEnums::EXECUTABLE ||
+     type == cmStateEnums::SHARED_LIBRARY) &&
+    this->TargetSystemSupportsDeployment();
+}
+
+bool cmGlobalVisualStudio8Generator::DeployInhibited(
+  cmGeneratorTarget const& target, const char* config) const
+{
+  bool rVal = false;
+  if (const char* propStr = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) {
+    cmGeneratorExpression ge;
+    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propStr);
+    std::string prop = cge->Evaluate(target.LocalGenerator, config);
+    rVal = cmSystemTools::IsOn(prop);
+  }
+  return rVal;
+}
+
+bool cmGlobalVisualStudio8Generator::TargetSystemSupportsDeployment() const
+{
+  return this->TargetsWindowsCE();
 }
 
 bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 8719bf3..352bc3c 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -13,7 +13,7 @@
 class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator
 {
 public:
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override { return this->Name; }
 
   /** Get the name of the main stamp list file. */
@@ -54,7 +54,15 @@
   bool AddCheckTarget();
 
   /** Return true if the configuration needs to be deployed */
-  virtual bool NeedsDeploy(cmStateEnums::TargetType type) const;
+  virtual bool NeedsDeploy(cmGeneratorTarget const& target,
+                           const char* config) const;
+
+  /** Returns true if deployment has been disabled in cmake file. */
+  bool DeployInhibited(cmGeneratorTarget const& target,
+                       const char* config) const;
+
+  /** Returns true if the target system support debugging deployment. */
+  virtual bool TargetSystemSupportsDeployment() const;
 
   static cmIDEFlagTable const* GetExtraFlagTableVS8();
   void WriteSolutionConfigurations(
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 639dc22..280c986 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -12,6 +12,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmCallVisualStudioMacro.h"
+#include "cmCustomCommand.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmLocalVisualStudioGenerator.h"
@@ -922,7 +923,7 @@
   cmdl.push_back(objs_file);
   cmGeneratedFileStream fout(objs_file.c_str());
   if (!fout) {
-    cmSystemTools::Error("could not open ", objs_file.c_str());
+    cmSystemTools::Error("could not open " + objs_file);
     return;
   }
 
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index f52abd0..2ba1aff 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -211,8 +211,8 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                                   cmake* cm) const
+  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+                                           cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS16GenName(name, genName);
@@ -226,7 +226,7 @@
     return 0;
   }
 
-  virtual void GetDocumentation(cmDocumentationEntry& entry) const
+  void GetDocumentation(cmDocumentationEntry& entry) const override
   {
     entry.Name = std::string(vs16generatorName);
     entry.Brief = "Generates Visual Studio 2019 project files.  "
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index c02c471..8a27384 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -3,6 +3,7 @@
 #include "cmGlobalWatcomWMakeGenerator.h"
 
 #include "cmDocumentationEntry.h"
+#include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmake.h"
@@ -50,15 +51,16 @@
   entry.Brief = "Generates Watcom WMake makefiles.";
 }
 
-void cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& projectDir,
-  const std::string& targetName, const std::string& config, bool fast,
-  int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& projectDir, std::vector<std::string> const& targetNames,
+  const std::string& config, bool fast, int /*jobs*/, bool verbose,
+  std::vector<std::string> const& makeOptions)
 {
-  this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeCommand, makeProgram, projectName, projectDir, targetName, config,
-    fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+  return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+    makeProgram, projectName, projectDir, targetNames, config, fast,
+    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
 }
 
 void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index 6680b19..3ca5e7d 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -29,7 +29,7 @@
   {
     return new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>();
   }
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override
   {
     return cmGlobalWatcomWMakeGenerator::GetActualName();
@@ -50,15 +50,12 @@
   bool AllowDeleteOnError() const override { return false; }
 
 protected:
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
 };
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 51c001e..db673bb 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -12,6 +12,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmDocumentationEntry.h"
 #include "cmGeneratedFileStream.h"
@@ -217,7 +218,7 @@
   sscanf(version_string.c_str(), "%u.%u", &v[0], &v[1]);
   unsigned int version_number = 10 * v[0] + v[1];
 
-  if (version_number < 30) {
+  if (version_number < 50) {
     cm->IssueMessage(MessageType::FATAL_ERROR,
                      "Xcode " + version_string + " not supported.");
     return nullptr;
@@ -256,15 +257,11 @@
 
 std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand()
 {
-  if (this->XcodeVersion >= 40) {
-    std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
-    if (makeProgram.empty()) {
-      makeProgram = "xcodebuild";
-    }
-    return makeProgram;
+  std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
+  if (makeProgram.empty()) {
+    makeProgram = "xcodebuild";
   }
-  // Use cmakexbuild wrapper to suppress environment dump from output.
-  return cmSystemTools::GetCMakeCommand() + "xbuild";
+  return makeProgram;
 }
 
 bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
@@ -338,49 +335,61 @@
   return ret;
 }
 
-void cmGlobalXCodeGenerator::GenerateBuildCommand(
-  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
-  const std::string& projectName, const std::string& /*projectDir*/,
-  const std::string& targetName, const std::string& config, bool /*fast*/,
-  int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalXCodeGenerator::GenerateBuildCommand(
+  const std::string& makeProgram, const std::string& projectName,
+  const std::string& /*projectDir*/,
+  std::vector<std::string> const& targetNames, const std::string& config,
+  bool /*fast*/, int jobs, bool /*verbose*/,
+  std::vector<std::string> const& makeOptions)
 {
+  GeneratedMakeCommand makeCommand;
   // now build the test
-  makeCommand.add(
+  makeCommand.Add(
     this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
 
   if (!projectName.empty()) {
-    makeCommand.add("-project");
+    makeCommand.Add("-project");
     std::string projectArg = projectName;
     projectArg += ".xcode";
     projectArg += "proj";
-    makeCommand.add(projectArg);
+    makeCommand.Add(projectArg);
+  }
+  if (std::find(targetNames.begin(), targetNames.end(), "clean") !=
+      targetNames.end()) {
+    makeCommand.Add("clean");
+    makeCommand.Add("-target", "ALL_BUILD");
+  } else {
+    makeCommand.Add("build");
+    if (targetNames.empty() ||
+        ((targetNames.size() == 1) && targetNames.front().empty())) {
+      makeCommand.Add("-target", "ALL_BUILD");
+    } else {
+      for (const auto& tname : targetNames) {
+        if (!tname.empty()) {
+          makeCommand.Add("-target", tname);
+        }
+      }
+    }
   }
 
-  bool clean = false;
-  std::string realTarget = targetName;
-  if (realTarget == "clean") {
-    clean = true;
-    realTarget = "ALL_BUILD";
-  }
-
-  makeCommand.add((clean ? "clean" : "build"));
-  makeCommand.add("-target", (realTarget.empty() ? "ALL_BUILD" : realTarget));
-  makeCommand.add("-configuration", (config.empty() ? "Debug" : config));
+  makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.add("-jobs");
+    makeCommand.Add("-jobs");
     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.add(std::to_string(jobs));
+      makeCommand.Add(std::to_string(jobs));
     }
   }
 
   if (this->XcodeVersion >= 70) {
-    makeCommand.add("-hideShellScriptEnvironment");
+    makeCommand.Add("-hideShellScriptEnvironment");
   }
-  makeCommand.add(makeOptions.begin(), makeOptions.end());
+  makeCommand.Add(makeOptions.begin(), makeOptions.end());
+  return { std::move(makeCommand) };
 }
 
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
 cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf)
 {
   return new cmLocalXCodeGenerator(this, mf);
@@ -550,12 +559,7 @@
       // run the depend check makefile as a post build rule
       // this will make sure that when the next target is built
       // things are up-to-date
-      if (target->GetType() == cmStateEnums::OBJECT_LIBRARY ||
-          (this->XcodeVersion < 50 &&
-           (target->GetType() == cmStateEnums::EXECUTABLE ||
-            target->GetType() == cmStateEnums::STATIC_LIBRARY ||
-            target->GetType() == cmStateEnums::SHARED_LIBRARY ||
-            target->GetType() == cmStateEnums::MODULE_LIBRARY))) {
+      if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
         makeHelper.back() = // fill placeholder
           this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
         cmCustomCommandLines commandLines;
@@ -1019,7 +1023,7 @@
                         this->CreateString(fileType));
 
   // Store the file path relative to the top of the source tree.
-  std::string path = this->RelativeToSource(fullpath.c_str());
+  std::string path = this->RelativeToSource(fullpath);
   std::string name = cmSystemTools::GetFilenameName(path);
   const char* sourceTree =
     (cmSystemTools::FileIsFullPath(path.c_str()) ? "<absolute>"
@@ -1142,6 +1146,13 @@
   // Add CMakeLists.txt file for user convenience.
   this->AddXCodeProjBuildRule(gtgt, classes);
 
+  // Add the Info.plist we are about to generate for an App Bundle.
+  if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+    std::string plist = this->ComputeInfoPListLocation(gtgt);
+    cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(plist, true);
+    classes.push_back(sf);
+  }
+
   std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare());
 
   gtgt->ComputeObjectMapping();
@@ -1183,23 +1194,6 @@
     }
   }
 
-  if (this->XcodeVersion < 50) {
-    // Add object library contents as external objects. (Equivalent to
-    // the externalObjFiles above, except each one is not a cmSourceFile
-    // within the target.)
-    std::vector<cmSourceFile const*> objs;
-    gtgt->GetExternalObjects(objs, "");
-    for (auto sourceFile : objs) {
-      if (sourceFile->GetObjectLibrary().empty()) {
-        continue;
-      }
-      std::string const& obj = sourceFile->GetFullPath();
-      cmXCodeObject* xsf =
-        this->CreateXCodeSourceFileFromPath(obj, gtgt, "", nullptr);
-      externalObjFiles.push_back(xsf);
-    }
-  }
-
   // some build phases only apply to bundles and/or frameworks
   bool isFrameworkTarget = gtgt->IsFrameworkOnApple();
   bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE");
@@ -1813,6 +1807,10 @@
     this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
                                                   configName);
 
+    if (gtgt->IsIPOEnabled(lang, configName)) {
+      this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
+    }
+
     // Add shared-library flags if needed.
     this->CurrentLocalGenerator->AddCMP0018Flags(flags, gtgt, lang,
                                                  configName);
@@ -2002,7 +2000,7 @@
         // so let it replace the framework name. This avoids creating
         // a per-configuration Info.plist file.
         this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
-          gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+          gtgt, "$(EXECUTABLE_NAME)", plist);
         buildSettings->AddAttribute("INFOPLIST_FILE",
                                     this->CreateString(plist));
         buildSettings->AddAttribute("MACH_O_TYPE",
@@ -2043,7 +2041,7 @@
         // a per-configuration Info.plist file. The cfbundle plist
         // is very similar to the application bundle plist
         this->CurrentLocalGenerator->GenerateAppleInfoPList(
-          gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+          gtgt, "$(EXECUTABLE_NAME)", plist);
         buildSettings->AddAttribute("INFOPLIST_FILE",
                                     this->CreateString(plist));
       } else {
@@ -2077,7 +2075,7 @@
         // so let it replace the framework name. This avoids creating
         // a per-configuration Info.plist file.
         this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
-          gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+          gtgt, "$(EXECUTABLE_NAME)", plist);
         buildSettings->AddAttribute("INFOPLIST_FILE",
                                     this->CreateString(plist));
       } else {
@@ -2115,7 +2113,7 @@
         // so let it replace the executable name.  This avoids creating
         // a per-configuration Info.plist file.
         this->CurrentLocalGenerator->GenerateAppleInfoPList(
-          gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+          gtgt, "$(EXECUTABLE_NAME)", plist);
         buildSettings->AddAttribute("INFOPLIST_FILE",
                                     this->CreateString(plist));
       }
@@ -2123,9 +2121,6 @@
     default:
       break;
   }
-  if (this->XcodeVersion < 40) {
-    buildSettings->AddAttribute("PREBINDING", this->CreateString("NO"));
-  }
 
   BuildObjectListOrString dirs(this, true);
   BuildObjectListOrString fdirs(this, true);
@@ -2775,8 +2770,7 @@
 
   // Loop over configuration types and set per-configuration info.
   for (auto const& configName : this->CurrentConfigurationTypes) {
-    // Get the current configuration name.
-    if (this->XcodeVersion >= 50) {
+    {
       // Add object library contents as link flags.
       std::string linkObjs;
       const char* sep = "";
@@ -2875,27 +2869,22 @@
         continue;
       }
 
-      // add the soon to be generated Info.plist file as a source for a
-      // MACOSX_BUNDLE file
-      if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
-        std::string plist = this->ComputeInfoPListLocation(gtgt);
-        mf->GetOrCreateSource(plist, true);
-        gtgt->AddSource(plist);
-      }
-
-      // Put cmSourceFile instances in proper groups:
-      for (auto const& si : gtgt->GetAllConfigSources()) {
-        cmSourceFile const* sf = si.Source;
-        if (this->XcodeVersion >= 50 && !sf->GetObjectLibrary().empty()) {
-          // Object library files go on the link line instead.
-          continue;
-        }
-        // Add the file to the list of sources.
-        std::string const& source = sf->GetFullPath();
+      auto addSourceToGroup = [this, mf, gtgt,
+                               &sourceGroups](std::string const& source) {
         cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups);
         cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
         std::string key = GetGroupMapKeyFromPath(gtgt, source);
         this->GroupMap[key] = pbxgroup;
+      };
+
+      // Put cmSourceFile instances in proper groups:
+      for (auto const& si : gtgt->GetAllConfigSources()) {
+        cmSourceFile const* sf = si.Source;
+        if (!sf->GetObjectLibrary().empty()) {
+          // Object library files go on the link line instead.
+          continue;
+        }
+        addSourceToGroup(sf->GetFullPath());
       }
 
       // Add CMakeLists.txt file for user convenience.
@@ -2904,11 +2893,14 @@
           gtgt->GetLocalGenerator()->GetCurrentSourceDirectory();
         listfile += "/CMakeLists.txt";
         cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(listfile);
-        std::string const& source = sf->GetFullPath();
-        cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups);
-        cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
-        std::string key = GetGroupMapKeyFromPath(gtgt, source);
-        this->GroupMap[key] = pbxgroup;
+        addSourceToGroup(sf->GetFullPath());
+      }
+
+      // Add the Info.plist we are about to generate for an App Bundle.
+      if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+        std::string plist = this->ComputeInfoPListLocation(gtgt);
+        cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(plist, true);
+        addSourceToGroup(sf->GetFullPath());
       }
     }
   }
@@ -3076,20 +3068,12 @@
   v << std::setfill('0') << std::setw(4) << XcodeVersion * 10;
   group->AddAttribute("LastUpgradeCheck", this->CreateString(v.str()));
   this->RootObject->AddAttribute("attributes", group);
-  if (this->XcodeVersion >= 32) {
-    this->RootObject->AddAttribute("compatibilityVersion",
-                                   this->CreateString("Xcode 3.2"));
-  } else if (this->XcodeVersion >= 31) {
-    this->RootObject->AddAttribute("compatibilityVersion",
-                                   this->CreateString("Xcode 3.1"));
-  } else {
-    this->RootObject->AddAttribute("compatibilityVersion",
-                                   this->CreateString("Xcode 3.0"));
-  }
+  this->RootObject->AddAttribute("compatibilityVersion",
+                                 this->CreateString("Xcode 3.2"));
   // Point Xcode at the top of the source tree.
   {
     std::string pdir =
-      this->RelativeToBinary(root->GetCurrentSourceDirectory().c_str());
+      this->RelativeToBinary(root->GetCurrentSourceDirectory());
     this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir));
     this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
   }
@@ -3428,10 +3412,8 @@
   }
   this->WriteXCodePBXProj(fout, root, generators);
 
-  if (this->IsGeneratingScheme(root)) {
-    this->OutputXCodeSharedSchemes(xcodeDir);
-  }
-  this->OutputXCodeWorkspaceSettings(xcodeDir, root);
+  bool hasGeneratedSchemes = this->OutputXCodeSharedSchemes(xcodeDir, root);
+  this->OutputXCodeWorkspaceSettings(xcodeDir, hasGeneratedSchemes);
 
   this->ClearXCodeObjects();
 
@@ -3441,17 +3423,8 @@
     root->GetBinaryDirectory());
 }
 
-bool cmGlobalXCodeGenerator::IsGeneratingScheme(cmLocalGenerator* root) const
-{
-  // Since the lowest available Xcode version for testing was 6.4,
-  // I'm setting this as a limit then
-  return this->XcodeVersion >= 64 &&
-    (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
-     root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_SCHEME"));
-}
-
-void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
-  const std::string& xcProjDir)
+bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
+  const std::string& xcProjDir, cmLocalGenerator* root)
 {
   // collect all tests for the targets
   std::map<std::string, cmXCodeScheme::TestObjects> testables;
@@ -3475,21 +3448,33 @@
   }
 
   // generate scheme
-  for (auto obj : this->XCodeObjects) {
-    if (obj->GetType() == cmXCodeObject::OBJECT &&
-        (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
-         obj->GetIsA() == cmXCodeObject::PBXAggregateTarget)) {
-      const std::string& targetName = obj->GetTarget()->GetName();
-      cmXCodeScheme schm(obj, testables[targetName],
-                         this->CurrentConfigurationTypes, this->XcodeVersion);
-      schm.WriteXCodeSharedScheme(xcProjDir,
-                                  this->RelativeToSource(xcProjDir.c_str()));
+  bool ret = false;
+
+  // Since the lowest available Xcode version for testing was 6.4,
+  // I'm setting this as a limit then
+  if (this->XcodeVersion >= 64) {
+    for (auto obj : this->XCodeObjects) {
+      if (obj->GetType() == cmXCodeObject::OBJECT &&
+          (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
+           obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) &&
+          (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
+           obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) {
+        const std::string& targetName = obj->GetTarget()->GetName();
+        cmXCodeScheme schm(obj, testables[targetName],
+                           this->CurrentConfigurationTypes,
+                           this->XcodeVersion);
+        schm.WriteXCodeSharedScheme(xcProjDir,
+                                    this->RelativeToSource(xcProjDir));
+        ret = true;
+      }
     }
   }
+
+  return ret;
 }
 
 void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
-  const std::string& xcProjDir, cmLocalGenerator* root)
+  const std::string& xcProjDir, bool hasGeneratedSchemes)
 {
   std::string xcodeSharedDataDir = xcProjDir;
   xcodeSharedDataDir += "/project.xcworkspace/xcshareddata";
@@ -3515,7 +3500,7 @@
     xout.Element("key", "BuildSystemType");
     xout.Element("string", "Original");
   }
-  if (this->IsGeneratingScheme(root)) {
+  if (hasGeneratedSchemes) {
     xout.Element("key",
                  "IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded");
     xout.Element("false");
@@ -3540,13 +3525,7 @@
   cmXCodeObject::Indent(1, fout);
   fout << "};\n";
   cmXCodeObject::Indent(1, fout);
-  if (this->XcodeVersion >= 32) {
-    fout << "objectVersion = 46;\n";
-  } else if (this->XcodeVersion >= 31) {
-    fout << "objectVersion = 45;\n";
-  } else {
-    fout << "objectVersion = 44;\n";
-  }
+  fout << "objectVersion = 46;\n";
   cmXCode21Object::PrintList(this->XCodeObjects, fout);
   cmXCodeObject::Indent(1, fout);
   fout << "rootObject = " << this->RootObject->GetId()
@@ -3591,7 +3570,7 @@
   return cmSystemTools::ConvertToOutputPath(p);
 }
 
-std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
+std::string cmGlobalXCodeGenerator::RelativeToSource(const std::string& p)
 {
   // We force conversion because Xcode breakpoints do not work unless
   // they are in a file named relative to the source tree.
@@ -3599,7 +3578,7 @@
     cmSystemTools::JoinPath(this->ProjectSourceDirectoryComponents), p);
 }
 
-std::string cmGlobalXCodeGenerator::RelativeToBinary(const char* p)
+std::string cmGlobalXCodeGenerator::RelativeToBinary(const std::string& p)
 {
   return this->CurrentLocalGenerator->MaybeConvertToRelativePath(
     cmSystemTools::JoinPath(this->ProjectOutputDirectoryComponents), p);
@@ -3714,11 +3693,7 @@
   // Flag value with escaped quotes and backslashes.
   for (auto c : flag) {
     if (c == '\'') {
-      if (this->XcodeVersion >= 40) {
-        flags += "'\\''";
-      } else {
-        flags += "\\'";
-      }
+      flags += "'\\''";
     } else if (c == '\\') {
       flags += "\\\\";
     } else {
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index e1e412d..71446f9 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -36,7 +36,7 @@
                          unsigned int version_number);
   static cmGlobalGeneratorFactory* NewFactory();
 
-  ///! Get the name for the generator.
+  //! Get the name for the generator.
   std::string GetName() const override
   {
     return cmGlobalXCodeGenerator::GetActualName();
@@ -46,7 +46,7 @@
   /** Get the documentation entry for this generator.  */
   static void GetDocumentation(cmDocumentationEntry& entry);
 
-  ///! Create a local generator appropriate to this Global Generator
+  //! Create a local generator appropriate to this Global Generator
   cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
 
   /**
@@ -66,15 +66,12 @@
    * Try running cmake and building a file. This is used for dynalically
    * loaded commands, not as part of the usual build process.
    */
-  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
-                            const std::string& makeProgram,
-                            const std::string& projectName,
-                            const std::string& projectDir,
-                            const std::string& targetName,
-                            const std::string& config, bool fast, int jobs,
-                            bool verbose,
-                            std::vector<std::string> const& makeOptions =
-                              std::vector<std::string>()) override;
+  std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+    const std::string& makeProgram, const std::string& projectName,
+    const std::string& projectDir, std::vector<std::string> const& targetNames,
+    const std::string& config, bool fast, int jobs, bool verbose,
+    std::vector<std::string> const& makeOptions =
+      std::vector<std::string>()) override;
 
   /** Append the subdirectory for the given configuration.  */
   void AppendDirectoryForConfig(const std::string& prefix,
@@ -84,9 +81,9 @@
 
   bool FindMakeProgram(cmMakefile*) override;
 
-  ///! What is the configurations directory variable called?
+  //! What is the configurations directory variable called?
   const char* GetCMakeCFGIntDir() const override;
-  ///! expand CFGIntDir
+  //! expand CFGIntDir
   std::string ExpandCFGIntDir(const std::string& str,
                               const std::string& config) const override;
 
@@ -122,8 +119,8 @@
                                 const std::string& name);
   bool CreateGroups(std::vector<cmLocalGenerator*>& generators);
   std::string XCodeEscapePath(const std::string& p);
-  std::string RelativeToSource(const char* p);
-  std::string RelativeToBinary(const char* p);
+  std::string RelativeToSource(const std::string& p);
+  std::string RelativeToBinary(const std::string& p);
   std::string ConvertToRelativeForMake(std::string const& p);
   void CreateCustomCommands(cmXCodeObject* buildPhases,
                             cmXCodeObject* sourceBuildPhase,
@@ -189,11 +186,12 @@
                           std::vector<cmLocalGenerator*>& generators);
   void OutputXCodeProject(cmLocalGenerator* root,
                           std::vector<cmLocalGenerator*>& generators);
-  bool IsGeneratingScheme(cmLocalGenerator* root) const;
   // Write shared scheme files for all the native targets
-  void OutputXCodeSharedSchemes(const std::string& xcProjDir);
+  //  return true if any were written
+  bool OutputXCodeSharedSchemes(const std::string& xcProjDir,
+                                cmLocalGenerator* root);
   void OutputXCodeWorkspaceSettings(const std::string& xcProjDir,
-                                    cmLocalGenerator* root);
+                                    bool hasGeneratedSchemes);
   void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
                          std::vector<cmLocalGenerator*>& generators);
   cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string& fullpath,
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 20d1a31..dba4bbb 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallCommand.h"
 
+#include "cm_static_string_view.hxx"
 #include "cmsys/Glob.hxx"
 #include <set>
 #include <sstream>
@@ -9,7 +10,7 @@
 #include <utility>
 
 #include "cmAlgorithms.h"
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
 #include "cmExportSet.h"
 #include "cmExportSetMap.h"
 #include "cmGeneratorExpression.h"
@@ -219,49 +220,51 @@
   return true;
 }
 
-/*struct InstallPart
-{
-  InstallPart(cmCommandArgumentsHelper* helper, const char* key,
-         cmCommandArgumentGroup* group);
-  cmCAStringVector argVector;
-  cmInstallCommandArguments args;
-};*/
-
 bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
 {
   // This is the TARGETS mode.
   std::vector<cmTarget*> targets;
 
-  cmCommandArgumentsHelper argHelper;
-  cmCommandArgumentGroup group;
-  cmCAStringVector genericArgVector(&argHelper, nullptr);
-  cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group);
-  cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group);
-  cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group);
-  cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group);
-  cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group);
-  cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group);
-  cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group);
-  cmCAStringVector privateHeaderArgVector(&argHelper, "PRIVATE_HEADER",
-                                          &group);
-  cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group);
-  cmCAStringVector resourceArgVector(&argHelper, "RESOURCE", &group);
-  genericArgVector.Follows(nullptr);
-  group.Follows(&genericArgVector);
+  struct ArgVectors
+  {
+    std::vector<std::string> Archive;
+    std::vector<std::string> Library;
+    std::vector<std::string> Runtime;
+    std::vector<std::string> Object;
+    std::vector<std::string> Framework;
+    std::vector<std::string> Bundle;
+    std::vector<std::string> Includes;
+    std::vector<std::string> PrivateHeader;
+    std::vector<std::string> PublicHeader;
+    std::vector<std::string> Resource;
+  };
 
-  argHelper.Parse(&args, nullptr);
+  static auto const argHelper =
+    cmArgumentParser<ArgVectors>{}
+      .Bind("ARCHIVE"_s, &ArgVectors::Archive)
+      .Bind("LIBRARY"_s, &ArgVectors::Library)
+      .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+      .Bind("OBJECTS"_s, &ArgVectors::Object)
+      .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
+      .Bind("BUNDLE"_s, &ArgVectors::Bundle)
+      .Bind("INCLUDES"_s, &ArgVectors::Includes)
+      .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
+      .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
+      .Bind("RESOURCE"_s, &ArgVectors::Resource);
+
+  std::vector<std::string> genericArgVector;
+  ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
 
   // now parse the generic args (i.e. the ones not specialized on LIBRARY/
   // ARCHIVE, RUNTIME etc. (see above)
   // These generic args also contain the targets and the export stuff
+  std::vector<std::string> targetList;
+  std::string exports;
   std::vector<std::string> unknownArgs;
   cmInstallCommandArguments genericArgs(this->DefaultComponentName);
-  cmCAStringVector targetList(&genericArgs.Parser, "TARGETS");
-  cmCAString exports(&genericArgs.Parser, "EXPORT",
-                     &genericArgs.ArgumentGroup);
-  targetList.Follows(nullptr);
-  genericArgs.ArgumentGroup.Follows(&targetList);
-  genericArgs.Parse(&genericArgVector.GetVector(), &unknownArgs);
+  genericArgs.Bind("TARGETS"_s, targetList);
+  genericArgs.Bind("EXPORT"_s, exports);
+  genericArgs.Parse(genericArgVector, &unknownArgs);
   bool success = genericArgs.Finalize();
 
   cmInstallCommandArguments archiveArgs(this->DefaultComponentName);
@@ -277,16 +280,16 @@
 
   // now parse the args for specific parts of the target (e.g. LIBRARY,
   // RUNTIME, ARCHIVE etc.
-  archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs);
-  libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs);
-  runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs);
-  objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs);
-  frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs);
-  bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs);
-  privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
-  publicHeaderArgs.Parse(&publicHeaderArgVector.GetVector(), &unknownArgs);
-  resourceArgs.Parse(&resourceArgVector.GetVector(), &unknownArgs);
-  includesArgs.Parse(&includesArgVector.GetVector(), &unknownArgs);
+  archiveArgs.Parse(argVectors.Archive, &unknownArgs);
+  libraryArgs.Parse(argVectors.Library, &unknownArgs);
+  runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+  objectArgs.Parse(argVectors.Object, &unknownArgs);
+  frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+  bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
+  privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs);
+  publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
+  resourceArgs.Parse(argVectors.Resource, &unknownArgs);
+  includesArgs.Parse(&argVectors.Includes, &unknownArgs);
 
   if (!unknownArgs.empty()) {
     // Unknown argument.
@@ -382,7 +385,7 @@
   }
 
   // Check if there is something to do.
-  if (targetList.GetVector().empty()) {
+  if (targetList.empty()) {
     return true;
   }
 
@@ -390,7 +393,7 @@
   bool dll_platform =
     !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
 
-  for (std::string const& tgt : targetList.GetVector()) {
+  for (std::string const& tgt : targetList) {
 
     if (this->Makefile->IsAlias(tgt)) {
       std::ostringstream e;
@@ -663,8 +666,7 @@
     // generators for them.
     bool createInstallGeneratorsForTargetFileSets = true;
 
-    if (target.IsFrameworkOnApple() ||
-        target.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+    if (target.IsFrameworkOnApple()) {
       createInstallGeneratorsForTargetFileSets = false;
     }
 
@@ -748,7 +750,7 @@
 
     // Add this install rule to an export if one was specified and
     // this is not a namelink-only rule.
-    if (!exports.GetString().empty() && !namelinkOnly) {
+    if (!exports.empty() && !namelinkOnly) {
       cmTargetExport* te = new cmTargetExport;
       te->TargetName = target.GetName();
       te->ArchiveGenerator = archiveGenerator;
@@ -759,7 +761,7 @@
       te->RuntimeGenerator = runtimeGenerator;
       te->ObjectsGenerator = objectGenerator;
       this->Makefile->GetGlobalGenerator()
-        ->GetExportSets()[exports.GetString()]
+        ->GetExportSets()[exports]
         ->AddTargetExport(te);
 
       te->InterfaceIncludeDirectories =
@@ -818,11 +820,10 @@
   // This is the FILES mode.
   bool programs = (args[0] == "PROGRAMS");
   cmInstallCommandArguments ica(this->DefaultComponentName);
-  cmCAStringVector files(&ica.Parser, programs ? "PROGRAMS" : "FILES");
-  files.Follows(nullptr);
-  ica.ArgumentGroup.Follows(&files);
+  std::vector<std::string> files;
+  ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
   std::vector<std::string> unknownArgs;
-  ica.Parse(&args, &unknownArgs);
+  ica.Parse(args, &unknownArgs);
 
   if (!unknownArgs.empty()) {
     // Unknown argument.
@@ -840,7 +841,7 @@
     return false;
   }
 
-  const std::vector<std::string>& filesVector = files.GetVector();
+  const std::vector<std::string>& filesVector = files;
 
   // Check if there is something to do.
   if (filesVector.empty()) {
@@ -1271,16 +1272,19 @@
 #ifdef CMAKE_BUILD_WITH_CMAKE
   // This is the EXPORT mode.
   cmInstallCommandArguments ica(this->DefaultComponentName);
-  cmCAString exp(&ica.Parser, "EXPORT_ANDROID_MK");
-  cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
-  cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES",
-                        &ica.ArgumentGroup);
-  cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
-  exp.Follows(nullptr);
 
-  ica.ArgumentGroup.Follows(&exp);
+  std::string exp;
+  std::string name_space;
+  bool exportOld = false;
+  std::string filename;
+
+  ica.Bind("EXPORT_ANDROID_MK"_s, exp);
+  ica.Bind("NAMESPACE"_s, name_space);
+  ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+  ica.Bind("FILE"_s, filename);
+
   std::vector<std::string> unknownArgs;
-  ica.Parse(&args, &unknownArgs);
+  ica.Parse(args, &unknownArgs);
 
   if (!unknownArgs.empty()) {
     // Unknown argument.
@@ -1304,7 +1308,7 @@
   }
 
   // Check the file name.
-  std::string fname = filename.GetString();
+  std::string fname = filename;
   if (fname.find_first_of(":/\\") != std::string::npos) {
     std::ostringstream e;
     e << args[0] << " given invalid export file name \"" << fname << "\".  "
@@ -1325,7 +1329,7 @@
   }
   if (fname.find_first_of(":/\\") != std::string::npos) {
     std::ostringstream e;
-    e << args[0] << " given export name \"" << exp.GetString() << "\".  "
+    e << args[0] << " given export name \"" << exp << "\".  "
       << "This name cannot be safely converted to a file name.  "
       << "Specify a different export name or use the FILE option to set "
       << "a file name explicitly.";
@@ -1338,7 +1342,7 @@
   }
 
   cmExportSet* exportSet =
-    this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
+    this->Makefile->GetGlobalGenerator()->GetExportSets()[exp];
 
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(this->Makefile);
@@ -1347,8 +1351,8 @@
   cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
     exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
     ica.GetConfigurations(), ica.GetComponent().c_str(), message,
-    ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(),
-    exportOld.IsEnabled(), true);
+    ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
+    true);
   this->Makefile->AddInstallGenerator(exportGenerator);
 
   return true;
@@ -1363,16 +1367,19 @@
 {
   // This is the EXPORT mode.
   cmInstallCommandArguments ica(this->DefaultComponentName);
-  cmCAString exp(&ica.Parser, "EXPORT");
-  cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
-  cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES",
-                        &ica.ArgumentGroup);
-  cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
-  exp.Follows(nullptr);
 
-  ica.ArgumentGroup.Follows(&exp);
+  std::string exp;
+  std::string name_space;
+  bool exportOld = false;
+  std::string filename;
+
+  ica.Bind("EXPORT"_s, exp);
+  ica.Bind("NAMESPACE"_s, name_space);
+  ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+  ica.Bind("FILE"_s, filename);
+
   std::vector<std::string> unknownArgs;
-  ica.Parse(&args, &unknownArgs);
+  ica.Parse(args, &unknownArgs);
 
   if (!unknownArgs.empty()) {
     // Unknown argument.
@@ -1396,7 +1403,7 @@
   }
 
   // Check the file name.
-  std::string fname = filename.GetString();
+  std::string fname = filename;
   if (fname.find_first_of(":/\\") != std::string::npos) {
     std::ostringstream e;
     e << args[0] << " given invalid export file name \"" << fname << "\".  "
@@ -1418,12 +1425,12 @@
 
   // Construct the file name.
   if (fname.empty()) {
-    fname = exp.GetString();
+    fname = exp;
     fname += ".cmake";
 
     if (fname.find_first_of(":/\\") != std::string::npos) {
       std::ostringstream e;
-      e << args[0] << " given export name \"" << exp.GetString() << "\".  "
+      e << args[0] << " given export name \"" << exp << "\".  "
         << "This name cannot be safely converted to a file name.  "
         << "Specify a different export name or use the FILE option to set "
         << "a file name explicitly.";
@@ -1433,8 +1440,8 @@
   }
 
   cmExportSet* exportSet =
-    this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
-  if (exportOld.IsEnabled()) {
+    this->Makefile->GetGlobalGenerator()->GetExportSets()[exp];
+  if (exportOld) {
     for (cmTargetExport* te : *exportSet->GetTargetExports()) {
       cmTarget* tgt =
         this->Makefile->GetGlobalGenerator()->FindTarget(te->TargetName);
@@ -1461,8 +1468,8 @@
   cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
     exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
     ica.GetConfigurations(), ica.GetComponent().c_str(), message,
-    ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(),
-    exportOld.IsEnabled(), false);
+    ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
+    false);
   this->Makefile->AddInstallGenerator(exportGenerator);
 
   return true;
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
index 155f055..8b33782 100644
--- a/Source/cmInstallCommandArguments.cxx
+++ b/Source/cmInstallCommandArguments.cxx
@@ -2,7 +2,9 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallCommandArguments.h"
 
+#include "cmRange.h"
 #include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
 
 #include <utility>
 
@@ -17,20 +19,19 @@
 
 cmInstallCommandArguments::cmInstallCommandArguments(
   std::string defaultComponent)
-  : Destination(&Parser, "DESTINATION", &ArgumentGroup)
-  , Component(&Parser, "COMPONENT", &ArgumentGroup)
-  , NamelinkComponent(&Parser, "NAMELINK_COMPONENT", &ArgumentGroup)
-  , ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup)
-  , Rename(&Parser, "RENAME", &ArgumentGroup)
-  , Permissions(&Parser, "PERMISSIONS", &ArgumentGroup)
-  , Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup)
-  , Optional(&Parser, "OPTIONAL", &ArgumentGroup)
-  , NamelinkOnly(&Parser, "NAMELINK_ONLY", &ArgumentGroup)
-  , NamelinkSkip(&Parser, "NAMELINK_SKIP", &ArgumentGroup)
-  , Type(&Parser, "TYPE", &ArgumentGroup)
-  , GenericArguments(nullptr)
-  , DefaultComponentName(std::move(defaultComponent))
+  : DefaultComponentName(std::move(defaultComponent))
 {
+  this->Bind("DESTINATION"_s, this->Destination);
+  this->Bind("COMPONENT"_s, this->Component);
+  this->Bind("NAMELINK_COMPONENT"_s, this->NamelinkComponent);
+  this->Bind("EXCLUDE_FROM_ALL"_s, this->ExcludeFromAll);
+  this->Bind("RENAME"_s, this->Rename);
+  this->Bind("PERMISSIONS"_s, this->Permissions);
+  this->Bind("CONFIGURATIONS"_s, this->Configurations);
+  this->Bind("OPTIONAL"_s, this->Optional);
+  this->Bind("NAMELINK_ONLY"_s, this->NamelinkOnly);
+  this->Bind("NAMELINK_SKIP"_s, this->NamelinkSkip);
+  this->Bind("TYPE"_s, this->Type);
 }
 
 const std::string& cmInstallCommandArguments::GetDestination() const
@@ -46,8 +47,8 @@
 
 const std::string& cmInstallCommandArguments::GetComponent() const
 {
-  if (!this->Component.GetString().empty()) {
-    return this->Component.GetString();
+  if (!this->Component.empty()) {
+    return this->Component;
   }
   if (this->GenericArguments != nullptr) {
     return this->GenericArguments->GetComponent();
@@ -61,16 +62,16 @@
 
 const std::string& cmInstallCommandArguments::GetNamelinkComponent() const
 {
-  if (!this->NamelinkComponent.GetString().empty()) {
-    return this->NamelinkComponent.GetString();
+  if (!this->NamelinkComponent.empty()) {
+    return this->NamelinkComponent;
   }
   return this->GetComponent();
 }
 
 const std::string& cmInstallCommandArguments::GetRename() const
 {
-  if (!this->Rename.GetString().empty()) {
-    return this->Rename.GetString();
+  if (!this->Rename.empty()) {
+    return this->Rename;
   }
   if (this->GenericArguments != nullptr) {
     return this->GenericArguments->GetRename();
@@ -91,7 +92,7 @@
 
 bool cmInstallCommandArguments::GetOptional() const
 {
-  if (this->Optional.IsEnabled()) {
+  if (this->Optional) {
     return true;
   }
   if (this->GenericArguments != nullptr) {
@@ -102,7 +103,7 @@
 
 bool cmInstallCommandArguments::GetExcludeFromAll() const
 {
-  if (this->ExcludeFromAll.IsEnabled()) {
+  if (this->ExcludeFromAll) {
     return true;
   }
   if (this->GenericArguments != nullptr) {
@@ -113,7 +114,7 @@
 
 bool cmInstallCommandArguments::GetNamelinkOnly() const
 {
-  if (this->NamelinkOnly.IsEnabled()) {
+  if (this->NamelinkOnly) {
     return true;
   }
   if (this->GenericArguments != nullptr) {
@@ -124,7 +125,7 @@
 
 bool cmInstallCommandArguments::GetNamelinkSkip() const
 {
-  if (this->NamelinkSkip.IsEnabled()) {
+  if (this->NamelinkSkip) {
     return true;
   }
   if (this->GenericArguments != nullptr) {
@@ -135,7 +136,7 @@
 
 bool cmInstallCommandArguments::HasNamelinkComponent() const
 {
-  if (!this->NamelinkComponent.GetString().empty()) {
+  if (!this->NamelinkComponent.empty()) {
     return true;
   }
   if (this->GenericArguments != nullptr) {
@@ -146,19 +147,19 @@
 
 const std::string& cmInstallCommandArguments::GetType() const
 {
-  return this->Type.GetString();
+  return this->Type;
 }
 
 const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
   const
 {
-  if (!this->Configurations.GetVector().empty()) {
-    return this->Configurations.GetVector();
+  if (!this->Configurations.empty()) {
+    return this->Configurations;
   }
   if (this->GenericArguments != nullptr) {
     return this->GenericArguments->GetConfigurations();
   }
-  return this->Configurations.GetVector();
+  return this->Configurations;
 }
 
 bool cmInstallCommandArguments::Finalize()
@@ -166,21 +167,15 @@
   if (!this->CheckPermissions()) {
     return false;
   }
-  this->DestinationString = this->Destination.GetString();
+  this->DestinationString = this->Destination;
   cmSystemTools::ConvertToUnixSlashes(this->DestinationString);
   return true;
 }
 
-void cmInstallCommandArguments::Parse(const std::vector<std::string>* args,
-                                      std::vector<std::string>* unconsumedArgs)
-{
-  this->Parser.Parse(args, unconsumedArgs);
-}
-
 bool cmInstallCommandArguments::CheckPermissions()
 {
   this->PermissionsString.clear();
-  for (std::string const& perm : this->Permissions.GetVector()) {
+  for (std::string const& perm : this->Permissions) {
     if (!cmInstallCommandArguments::CheckPermissions(
           perm, this->PermissionsString)) {
       return false;
@@ -220,10 +215,7 @@
   if (args->empty()) {
     return;
   }
-  std::vector<std::string>::const_iterator it = args->begin();
-  ++it;
-  for (; it != args->end(); ++it) {
-    std::string dir = *it;
+  for (std::string dir : cmMakeRange(*args).advance(1)) {
     cmSystemTools::ConvertToUnixSlashes(dir);
     this->IncludeDirs.push_back(std::move(dir));
   }
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
index 9c0d417..5d2ee0a 100644
--- a/Source/cmInstallCommandArguments.h
+++ b/Source/cmInstallCommandArguments.h
@@ -8,9 +8,9 @@
 #include <string>
 #include <vector>
 
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
 
-class cmInstallCommandArguments
+class cmInstallCommandArguments : public cmArgumentParser<void>
 {
 public:
   cmInstallCommandArguments(std::string defaultComponent);
@@ -18,8 +18,6 @@
   {
     this->GenericArguments = args;
   }
-  void Parse(const std::vector<std::string>* args,
-             std::vector<std::string>* unconsumedArgs);
 
   // Compute destination path.and check permissions
   bool Finalize();
@@ -37,30 +35,25 @@
   bool HasNamelinkComponent() const;
   const std::string& GetType() const;
 
-  // once HandleDirectoryMode() is also switched to using
-  // cmInstallCommandArguments then these two functions can become non-static
-  // private member functions without arguments
   static bool CheckPermissions(const std::string& onePerm, std::string& perm);
-  cmCommandArgumentsHelper Parser;
-  cmCommandArgumentGroup ArgumentGroup;
 
 private:
-  cmCAString Destination;
-  cmCAString Component;
-  cmCAString NamelinkComponent;
-  cmCAEnabler ExcludeFromAll;
-  cmCAString Rename;
-  cmCAStringVector Permissions;
-  cmCAStringVector Configurations;
-  cmCAEnabler Optional;
-  cmCAEnabler NamelinkOnly;
-  cmCAEnabler NamelinkSkip;
-  cmCAString Type;
+  std::string Destination;
+  std::string Component;
+  std::string NamelinkComponent;
+  bool ExcludeFromAll = false;
+  std::string Rename;
+  std::vector<std::string> Permissions;
+  std::vector<std::string> Configurations;
+  bool Optional = false;
+  bool NamelinkOnly = false;
+  bool NamelinkSkip = false;
+  std::string Type;
 
   std::string DestinationString;
   std::string PermissionsString;
 
-  cmInstallCommandArguments* GenericArguments;
+  cmInstallCommandArguments* GenericArguments = nullptr;
   static const char* PermissionsTable[];
   static const std::string EmptyString;
   std::string DefaultComponentName;
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index a88c7af..62ce9f2 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -31,10 +31,12 @@
   }
 
   // We need per-config actions if any directories have generator expressions.
-  for (std::vector<std::string>::const_iterator i = dirs.begin();
-       !this->ActionsPerConfig && i != dirs.end(); ++i) {
-    if (cmGeneratorExpression::Find(*i) != std::string::npos) {
-      this->ActionsPerConfig = true;
+  if (!this->ActionsPerConfig) {
+    for (std::string const& dir : dirs) {
+      if (cmGeneratorExpression::Find(dir) != std::string::npos) {
+        this->ActionsPerConfig = true;
+        break;
+      }
     }
   }
 }
diff --git a/Source/cmInstallExportAndroidMKGenerator.cxx b/Source/cmInstallExportAndroidMKGenerator.cxx
index 85b7021..186b9df 100644
--- a/Source/cmInstallExportAndroidMKGenerator.cxx
+++ b/Source/cmInstallExportAndroidMKGenerator.cxx
@@ -67,10 +67,8 @@
       this->EFGen->AddConfiguration("");
     }
   } else {
-    for (std::vector<std::string>::const_iterator ci =
-           this->ConfigurationTypes->begin();
-         ci != this->ConfigurationTypes->end(); ++ci) {
-      this->EFGen->AddConfiguration(*ci);
+    for (std::string const& config : this->ConfigurationTypes) {
+      this->EFGen->AddConfiguration(config);
     }
   }
   this->EFGen->GenerateImportFile();
@@ -88,11 +86,9 @@
   // Now create a configuration-specific install rule for the import
   // file of each configuration.
   std::vector<std::string> files;
-  for (std::map<std::string, std::string>::const_iterator i =
-         this->EFGen->GetConfigImportFiles().begin();
-       i != this->EFGen->GetConfigImportFiles().end(); ++i) {
-    files.push_back(i->second);
-    std::string config_test = this->CreateConfigTest(i->first);
+  for (auto const& pair : this->EFGen->GetConfigImportFiles()) {
+    files.push_back(pair.second);
+    std::string config_test = this->CreateConfigTest(pair.first);
     os << indent << "if(" << config_test << ")\n";
     this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
                          false, this->FilePermissions.c_str(), nullptr,
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 47b9785..73a37cb 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -202,7 +202,7 @@
   os << indentNN << "file(GLOB OLD_CONFIG_FILES \"" << installedDir
      << this->EFGen->GetConfigImportFileGlob() << "\")\n";
   os << indentNN << "if(OLD_CONFIG_FILES)\n";
-  os << indentNNN << "message(STATUS \"Old export file \\\"" << installedFile
+  os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile
      << "\\\" will be replaced.  Removing files [${OLD_CONFIG_FILES}].\")\n";
   os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n";
   os << indentNN << "endif()\n";
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
index 4dde18f..b068e46 100644
--- a/Source/cmInstallFilesCommand.cxx
+++ b/Source/cmInstallFilesCommand.cxx
@@ -7,6 +7,7 @@
 #include "cmInstallFilesGenerator.h"
 #include "cmInstallGenerator.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 
 class cmExecutionStatus;
@@ -27,10 +28,9 @@
 
   if ((args.size() > 1) && (args[1] == "FILES")) {
     this->IsFilesForm = true;
-    for (std::vector<std::string>::const_iterator s = args.begin() + 2;
-         s != args.end(); ++s) {
+    for (std::string const& arg : cmMakeRange(args).advance(2)) {
       // Find the source location for each file listed.
-      this->Files.push_back(this->FindInstallSource(s->c_str()));
+      this->Files.push_back(this->FindInstallSource(arg.c_str()));
     }
     this->CreateInstallGenerator();
   } else {
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index 07094cb..9eb8ad4 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -29,11 +29,13 @@
     this->ActionsPerConfig = true;
   }
 
-  // We need per-config actions if any files have generator expressions.
-  for (std::vector<std::string>::const_iterator i = files.begin();
-       !this->ActionsPerConfig && i != files.end(); ++i) {
-    if (cmGeneratorExpression::Find(*i) != std::string::npos) {
-      this->ActionsPerConfig = true;
+  // We need per-config actions if any directories have generator expressions.
+  if (!this->ActionsPerConfig) {
+    for (std::string const& file : files) {
+      if (cmGeneratorExpression::Find(file) != std::string::npos) {
+        this->ActionsPerConfig = true;
+        break;
+      }
     }
   }
 }
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index d139190..2ffca30 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -69,17 +69,18 @@
   if (cmSystemTools::FileIsFullPath(dest)) {
     os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
     os << indent << " \"";
-    for (std::vector<std::string>::const_iterator fi = files.begin();
-         fi != files.end(); ++fi) {
-      if (fi != files.begin()) {
+    bool firstIteration = true;
+    for (std::string const& file : files) {
+      if (!firstIteration) {
         os << ";";
       }
       os << dest << "/";
       if (rename && *rename) {
         os << rename;
       } else {
-        os << cmSystemTools::GetFilenameName(*fi);
+        os << cmSystemTools::GetFilenameName(file);
       }
+      firstIteration = false;
     }
     os << "\")\n";
     os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
@@ -141,7 +142,7 @@
 std::string cmInstallGenerator::CreateComponentTest(const char* component,
                                                     bool exclude_from_all)
 {
-  std::string result = "\"x${CMAKE_INSTALL_COMPONENT}x\" STREQUAL \"x";
+  std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)";
   result += component;
   result += "x\"";
   if (!exclude_from_all) {
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 9d3a6bb..4fefe23 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -107,19 +107,15 @@
     // There is a bug in cmInstallCommand if this fails.
     assert(this->NamelinkMode == NamelinkModeNone);
 
-    std::string targetName;
-    std::string targetNameReal;
-    std::string targetNameImport;
-    std::string targetNamePDB;
-    this->Target->GetExecutableNames(targetName, targetNameReal,
-                                     targetNameImport, targetNamePDB, config);
+    cmGeneratorTarget::Names targetNames =
+      this->Target->GetExecutableNames(config);
     if (this->ImportLibrary) {
-      std::string from1 = fromDirConfig + targetNameImport;
-      std::string to1 = toDir + targetNameImport;
+      std::string from1 = fromDirConfig + targetNames.ImportLibrary;
+      std::string to1 = toDir + targetNames.ImportLibrary;
       filesFrom.push_back(std::move(from1));
       filesTo.push_back(std::move(to1));
       std::string targetNameImportLib;
-      if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
+      if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
                                          targetNameImportLib)) {
         filesFrom.push_back(fromDirConfig + targetNameImportLib);
         filesTo.push_back(toDir + targetNameImportLib);
@@ -128,8 +124,8 @@
       // An import library looks like a static library.
       type = cmInstallType_STATIC_LIBRARY;
     } else {
-      std::string from1 = fromDirConfig + targetName;
-      std::string to1 = toDir + targetName;
+      std::string from1 = fromDirConfig + targetNames.Output;
+      std::string to1 = toDir + targetNames.Output;
 
       // Handle OSX Bundles.
       if (this->Target->IsAppBundleOnApple()) {
@@ -154,12 +150,12 @@
         if (!mf->PlatformIsAppleEmbedded()) {
           to1 += "Contents/MacOS/";
         }
-        to1 += targetName;
+        to1 += targetNames.Output;
       } else {
         // Tweaks apply to the real file, so list it first.
-        if (targetNameReal != targetName) {
-          std::string from2 = fromDirConfig + targetNameReal;
-          std::string to2 = toDir += targetNameReal;
+        if (targetNames.Real != targetNames.Output) {
+          std::string from2 = fromDirConfig + targetNames.Real;
+          std::string to2 = toDir += targetNames.Real;
           filesFrom.push_back(std::move(from2));
           filesTo.push_back(std::move(to2));
         }
@@ -169,23 +165,18 @@
       filesTo.push_back(std::move(to1));
     }
   } else {
-    std::string targetName;
-    std::string targetNameSO;
-    std::string targetNameReal;
-    std::string targetNameImport;
-    std::string targetNamePDB;
-    this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
-                                  targetNameImport, targetNamePDB, config);
+    cmGeneratorTarget::Names targetNames =
+      this->Target->GetLibraryNames(config);
     if (this->ImportLibrary) {
       // There is a bug in cmInstallCommand if this fails.
       assert(this->NamelinkMode == NamelinkModeNone);
 
-      std::string from1 = fromDirConfig + targetNameImport;
-      std::string to1 = toDir + targetNameImport;
+      std::string from1 = fromDirConfig + targetNames.ImportLibrary;
+      std::string to1 = toDir + targetNames.ImportLibrary;
       filesFrom.push_back(std::move(from1));
       filesTo.push_back(std::move(to1));
       std::string targetNameImportLib;
-      if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
+      if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
                                          targetNameImportLib)) {
         filesFrom.push_back(fromDirConfig + targetNameImportLib);
         filesTo.push_back(toDir + targetNameImportLib);
@@ -227,11 +218,11 @@
       type = cmInstallType_DIRECTORY;
       literal_args += " USE_SOURCE_PERMISSIONS";
 
-      std::string from1 = fromDirConfig + targetName;
+      std::string from1 = fromDirConfig + targetNames.Output;
       from1 = cmSystemTools::GetFilenamePath(from1);
 
       // Tweaks apply to the binary inside the bundle.
-      std::string to1 = toDir + targetNameReal;
+      std::string to1 = toDir + targetNames.Real;
 
       filesFrom.push_back(std::move(from1));
       filesTo.push_back(std::move(to1));
@@ -240,10 +231,11 @@
       type = cmInstallType_DIRECTORY;
       literal_args += " USE_SOURCE_PERMISSIONS";
 
-      std::string targetNameBase = targetName.substr(0, targetName.find('/'));
+      std::string targetNameBase =
+        targetNames.Output.substr(0, targetNames.Output.find('/'));
 
       std::string from1 = fromDirConfig + targetNameBase;
-      std::string to1 = toDir + targetName;
+      std::string to1 = toDir + targetNames.Output;
 
       filesFrom.push_back(std::move(from1));
       filesTo.push_back(std::move(to1));
@@ -251,25 +243,26 @@
       bool haveNamelink = false;
 
       // Library link name.
-      std::string fromName = fromDirConfig + targetName;
-      std::string toName = toDir + targetName;
+      std::string fromName = fromDirConfig + targetNames.Output;
+      std::string toName = toDir + targetNames.Output;
 
       // Library interface name.
       std::string fromSOName;
       std::string toSOName;
-      if (targetNameSO != targetName) {
+      if (targetNames.SharedObject != targetNames.Output) {
         haveNamelink = true;
-        fromSOName = fromDirConfig + targetNameSO;
-        toSOName = toDir + targetNameSO;
+        fromSOName = fromDirConfig + targetNames.SharedObject;
+        toSOName = toDir + targetNames.SharedObject;
       }
 
       // Library implementation name.
       std::string fromRealName;
       std::string toRealName;
-      if (targetNameReal != targetName && targetNameReal != targetNameSO) {
+      if (targetNames.Real != targetNames.Output &&
+          targetNames.Real != targetNames.SharedObject) {
         haveNamelink = true;
-        fromRealName = fromDirConfig + targetNameReal;
-        toRealName = toDir + targetNameReal;
+        fromRealName = fromDirConfig + targetNames.Real;
+        toRealName = toDir + targetNames.Real;
       }
 
       // Add the names based on the current namelink mode.
@@ -400,48 +393,37 @@
   std::string fname;
   // Compute the name of the library.
   if (target->GetType() == cmStateEnums::EXECUTABLE) {
-    std::string targetName;
-    std::string targetNameReal;
-    std::string targetNameImport;
-    std::string targetNamePDB;
-    target->GetExecutableNames(targetName, targetNameReal, targetNameImport,
-                               targetNamePDB, config);
+    cmGeneratorTarget::Names targetNames = target->GetExecutableNames(config);
     if (nameType == NameImplib) {
       // Use the import library name.
-      if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
+      if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
                                     "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
-        fname = targetNameImport;
+        fname = targetNames.ImportLibrary;
       }
     } else if (nameType == NameReal) {
       // Use the canonical name.
-      fname = targetNameReal;
+      fname = targetNames.Real;
     } else {
       // Use the canonical name.
-      fname = targetName;
+      fname = targetNames.Output;
     }
   } else {
-    std::string targetName;
-    std::string targetNameSO;
-    std::string targetNameReal;
-    std::string targetNameImport;
-    std::string targetNamePDB;
-    target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
-                            targetNameImport, targetNamePDB, config);
+    cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config);
     if (nameType == NameImplib) {
       // Use the import library name.
-      if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
+      if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
                                     "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
-        fname = targetNameImport;
+        fname = targetNames.ImportLibrary;
       }
     } else if (nameType == NameSO) {
       // Use the soname.
-      fname = targetNameSO;
+      fname = targetNames.SharedObject;
     } else if (nameType == NameReal) {
       // Use the real name.
-      fname = targetNameReal;
+      fname = targetNames.Real;
     } else {
       // Use the canonical name.
-      fname = targetName;
+      fname = targetNames.Output;
     }
   }
 
@@ -809,7 +791,7 @@
     return;
   }
 
-  std::string ranlib =
+  const std::string& ranlib =
     this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
   if (ranlib.empty()) {
     return;
diff --git a/Source/cmInstallTargetsCommand.cxx b/Source/cmInstallTargetsCommand.cxx
index d721ca0..7e67d4e 100644
--- a/Source/cmInstallTargetsCommand.cxx
+++ b/Source/cmInstallTargetsCommand.cxx
@@ -40,8 +40,8 @@
     } else {
       cmTargets::iterator ti = tgts.find(*s);
       if (ti != tgts.end()) {
-        ti->second.SetInstallPath(args[0].c_str());
-        ti->second.SetRuntimeInstallPath(runtime_dir.c_str());
+        ti->second.SetInstallPath(args[0]);
+        ti->second.SetRuntimeInstallPath(runtime_dir);
         ti->second.SetHaveInstallRule(true);
       } else {
         std::string str = "Cannot find target: \"" + *s + "\" to install.";
diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h
index 070b954..b7d602e 100644
--- a/Source/cmInstalledFile.h
+++ b/Source/cmInstalledFile.h
@@ -32,6 +32,9 @@
     Property();
     ~Property();
 
+    Property(const Property&) = delete;
+    Property& operator=(const Property&) = delete;
+
     ExpressionVectorType ValueExpressions;
   };
 
@@ -41,6 +44,9 @@
 
   ~cmInstalledFile();
 
+  cmInstalledFile(const cmInstalledFile&) = delete;
+  cmInstalledFile& operator=(const cmInstalledFile&) = delete;
+
   void RemoveProperty(const std::string& prop);
 
   void SetProperty(cmMakefile const* mf, const std::string& prop,
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 297babf..5474afa 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -19,6 +19,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmStringReplaceHelper.h"
 #include "cmSystemTools.h"
 
@@ -42,6 +43,15 @@
   if (subCommand == "APPEND") {
     return this->HandleAppendCommand(args);
   }
+  if (subCommand == "PREPEND") {
+    return this->HandlePrependCommand(args);
+  }
+  if (subCommand == "POP_BACK") {
+    return this->HandlePopBackCommand(args);
+  }
+  if (subCommand == "POP_FRONT") {
+    return this->HandlePopFrontCommand(args);
+  }
   if (subCommand == "FIND") {
     return this->HandleFindCommand(args);
   }
@@ -222,20 +232,141 @@
     return true;
   }
 
-  const std::string& listName = args[1];
+  std::string const& listName = args[1];
   // expand the variable
   std::string listString;
   this->GetListString(listString, listName);
 
-  if (!listString.empty() && !args.empty()) {
-    listString += ";";
-  }
-  listString += cmJoin(cmMakeRange(args).advance(2), ";");
+  // If `listString` or `args` is empty, no need to append `;`,
+  // then index is going to be `1` and points to the end-of-string ";"
+  auto const offset =
+    std::string::size_type(listString.empty() || args.empty());
+  listString += &";"[offset] + cmJoin(cmMakeRange(args).advance(2), ";");
 
   this->Makefile->AddDefinition(listName, listString.c_str());
   return true;
 }
 
+bool cmListCommand::HandlePrependCommand(std::vector<std::string> const& args)
+{
+  assert(args.size() >= 2);
+
+  // Skip if nothing to prepend.
+  if (args.size() < 3) {
+    return true;
+  }
+
+  std::string const& listName = args[1];
+  // expand the variable
+  std::string listString;
+  this->GetListString(listString, listName);
+
+  // If `listString` or `args` is empty, no need to append `;`,
+  // then `offset` is going to be `1` and points to the end-of-string ";"
+  auto const offset =
+    std::string::size_type(listString.empty() || args.empty());
+  listString.insert(0,
+                    cmJoin(cmMakeRange(args).advance(2), ";") + &";"[offset]);
+
+  this->Makefile->AddDefinition(listName, listString.c_str());
+  return true;
+}
+
+bool cmListCommand::HandlePopBackCommand(std::vector<std::string> const& args)
+{
+  assert(args.size() >= 2);
+
+  auto ai = args.cbegin();
+  ++ai; // Skip subcommand name
+  std::string const& listName = *ai++;
+  std::vector<std::string> varArgsExpanded;
+  if (!this->GetList(varArgsExpanded, listName)) {
+    // Can't get the list definition... undefine any vars given after.
+    for (; ai != args.cend(); ++ai) {
+      this->Makefile->RemoveDefinition(*ai);
+    }
+    return true;
+  }
+
+  if (!varArgsExpanded.empty()) {
+    if (ai == args.cend()) {
+      // No variables are given... Just remove one element.
+      varArgsExpanded.pop_back();
+    } else {
+      // Ok, assign elements to be removed to the given variables
+      for (; !varArgsExpanded.empty() && ai != args.cend(); ++ai) {
+        assert(!ai->empty());
+        this->Makefile->AddDefinition(*ai, varArgsExpanded.back().c_str());
+        varArgsExpanded.pop_back();
+      }
+      // Undefine the rest variables if the list gets empty earlier...
+      for (; ai != args.cend(); ++ai) {
+        this->Makefile->RemoveDefinition(*ai);
+      }
+    }
+
+    this->Makefile->AddDefinition(listName,
+                                  cmJoin(varArgsExpanded, ";").c_str());
+
+  } else if (ai !=
+             args.cend()) { // The list is empty, but some args were given
+    // Need to *undefine* 'em all, cuz there are no items to assign...
+    for (; ai != args.cend(); ++ai) {
+      this->Makefile->RemoveDefinition(*ai);
+    }
+  }
+
+  return true;
+}
+
+bool cmListCommand::HandlePopFrontCommand(std::vector<std::string> const& args)
+{
+  assert(args.size() >= 2);
+
+  auto ai = args.cbegin();
+  ++ai; // Skip subcommand name
+  std::string const& listName = *ai++;
+  std::vector<std::string> varArgsExpanded;
+  if (!this->GetList(varArgsExpanded, listName)) {
+    // Can't get the list definition... undefine any vars given after.
+    for (; ai != args.cend(); ++ai) {
+      this->Makefile->RemoveDefinition(*ai);
+    }
+    return true;
+  }
+
+  if (!varArgsExpanded.empty()) {
+    if (ai == args.cend()) {
+      // No variables are given... Just remove one element.
+      varArgsExpanded.erase(varArgsExpanded.begin());
+    } else {
+      // Ok, assign elements to be removed to the given variables
+      auto vi = varArgsExpanded.begin();
+      for (; vi != varArgsExpanded.end() && ai != args.cend(); ++ai, ++vi) {
+        assert(!ai->empty());
+        this->Makefile->AddDefinition(*ai, varArgsExpanded.front().c_str());
+      }
+      varArgsExpanded.erase(varArgsExpanded.begin(), vi);
+      // Undefine the rest variables if the list gets empty earlier...
+      for (; ai != args.cend(); ++ai) {
+        this->Makefile->RemoveDefinition(*ai);
+      }
+    }
+
+    this->Makefile->AddDefinition(listName,
+                                  cmJoin(varArgsExpanded, ";").c_str());
+
+  } else if (ai !=
+             args.cend()) { // The list is empty, but some args were given
+    // Need to *undefine* 'em all, cuz there are no items to assign...
+    for (; ai != args.cend(); ++ai) {
+      this->Makefile->RemoveDefinition(*ai);
+    }
+  }
+
+  return true;
+}
+
 bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
 {
   if (args.size() != 4) {
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
index 76a9856..ea3d643 100644
--- a/Source/cmListCommand.h
+++ b/Source/cmListCommand.h
@@ -35,6 +35,9 @@
   bool HandleLengthCommand(std::vector<std::string> const& args);
   bool HandleGetCommand(std::vector<std::string> const& args);
   bool HandleAppendCommand(std::vector<std::string> const& args);
+  bool HandlePrependCommand(std::vector<std::string> const& args);
+  bool HandlePopBackCommand(std::vector<std::string> const& args);
+  bool HandlePopFrontCommand(std::vector<std::string> const& args);
   bool HandleFindCommand(std::vector<std::string> const& args);
   bool HandleInsertCommand(std::vector<std::string> const& args);
   bool HandleJoinCommand(std::vector<std::string> const& args);
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index f855119..f99caed 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -27,6 +27,8 @@
   cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
                    cmMessenger* messenger, const char* filename);
   ~cmListFileParser();
+  cmListFileParser(const cmListFileParser&) = delete;
+  cmListFileParser& operator=(const cmListFileParser&) = delete;
   void IssueFileOpenError(std::string const& text) const;
   void IssueError(std::string const& text) const;
   bool ParseFile();
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index cd71518..69751b6 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -33,7 +33,7 @@
     this->info.CAPI = &cmStaticCAPI;
   }
 
-  ///! clean up any memory allocated by the plugin
+  //! clean up any memory allocated by the plugin
   ~cmLoadedCommand() override;
 
   /**
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 7e15234..67763d4 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -34,6 +34,7 @@
 #include "cmsys/RegularExpression.hxx"
 #include <algorithm>
 #include <assert.h>
+#include <initializer_list>
 #include <iterator>
 #include <sstream>
 #include <stdio.h>
@@ -51,25 +52,23 @@
 // replaced in the form <var> with GetSafeDefinition(var).
 // ${LANG} is replaced in the variable first with all enabled
 // languages.
-static const char* ruleReplaceVars[] = {
-  "CMAKE_${LANG}_COMPILER",
-  "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
-  "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
-  "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
-  "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
-  "CMAKE_${LANG}_LINK_FLAGS",
-  "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
-  "CMAKE_${LANG}_ARCHIVE",
-  "CMAKE_AR",
-  "CMAKE_CURRENT_SOURCE_DIR",
-  "CMAKE_CURRENT_BINARY_DIR",
-  "CMAKE_RANLIB",
-  "CMAKE_LINKER",
-  "CMAKE_MT",
-  "CMAKE_CUDA_HOST_COMPILER",
-  "CMAKE_CUDA_HOST_LINK_LAUNCHER",
-  "CMAKE_CL_SHOWINCLUDES_PREFIX"
-};
+static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
+                                "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
+                                "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
+                                "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
+                                "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
+                                "CMAKE_${LANG}_LINK_FLAGS",
+                                "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
+                                "CMAKE_${LANG}_ARCHIVE",
+                                "CMAKE_AR",
+                                "CMAKE_CURRENT_SOURCE_DIR",
+                                "CMAKE_CURRENT_BINARY_DIR",
+                                "CMAKE_RANLIB",
+                                "CMAKE_LINKER",
+                                "CMAKE_MT",
+                                "CMAKE_CUDA_HOST_COMPILER",
+                                "CMAKE_CUDA_HOST_LINK_LAUNCHER",
+                                "CMAKE_CL_SHOWINCLUDES_PREFIX" };
 
 cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
   : cmOutputConverter(makefile->GetStateSnapshot())
@@ -138,15 +137,13 @@
     this->VariableMappings[compilerOptionSysroot] =
       this->Makefile->GetSafeDefinition(compilerOptionSysroot);
 
-    for (const char* const* replaceIter = cm::cbegin(ruleReplaceVars);
-         replaceIter != cm::cend(ruleReplaceVars); ++replaceIter) {
-      std::string actualReplace = *replaceIter;
-      if (actualReplace.find("${LANG}") != std::string::npos) {
-        cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang);
+    for (std::string replaceVar : ruleReplaceVars) {
+      if (replaceVar.find("${LANG}") != std::string::npos) {
+        cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
       }
 
-      this->VariableMappings[actualReplace] =
-        this->Makefile->GetSafeDefinition(actualReplace);
+      this->VariableMappings[replaceVar] =
+        this->Makefile->GetSafeDefinition(replaceVar);
     }
   }
 }
@@ -369,8 +366,8 @@
                           std::back_inserter(intersection));
     if (!intersection.empty()) {
       cmSystemTools::Error("Files to be generated by multiple different "
-                           "commands: ",
-                           cmWrap('"', intersection, '"', " ").c_str());
+                           "commands: " +
+                           cmWrap('"', intersection, '"', " "));
       return;
     }
 
@@ -460,7 +457,7 @@
        << "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
        << "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
        << "endif()" << std::endl
-       << "string(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX "
+       << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
        << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
        << std::endl;
 
@@ -779,7 +776,7 @@
 #endif
   for (std::string const& i : includes) {
     if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
-        cmSystemTools::IsPathToFramework(i.c_str())) {
+        cmSystemTools::IsPathToFramework(i)) {
       std::string frameworkDir = i;
       frameworkDir += "/../";
       frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
@@ -1182,8 +1179,8 @@
       }
       if (linkLanguage.empty()) {
         cmSystemTools::Error(
-          "CMake can not determine linker language for target: ",
-          target->GetName().c_str());
+          "CMake can not determine linker language for target: " +
+          target->GetName());
         return;
       }
       this->AddLanguageFlagsForLinking(flags, target, linkLanguage, buildType);
@@ -1261,6 +1258,10 @@
   // Add language-specific flags.
   this->AddLanguageFlags(flags, target, lang, config);
 
+  if (target->IsIPOEnabled(lang, config)) {
+    this->AppendFeatureOptions(flags, lang, "IPO");
+  }
+
   this->AddArchitectureFlags(flags, target, lang, config);
 
   if (lang == "Fortran") {
@@ -1382,9 +1383,9 @@
 
   std::string linkLanguage = cli.GetLinkLanguage();
 
-  std::string libPathFlag =
+  const std::string& libPathFlag =
     this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
-  std::string libPathTerminator =
+  const std::string& libPathTerminator =
     this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
 
   // Add standard libraries for this language.
@@ -1518,9 +1519,8 @@
   flagsVar += "_FLAGS";
   this->AddConfigVariableFlags(flags, flagsVar, config);
 
-  if (target->IsIPOEnabled(lang, config)) {
-    this->AppendFeatureOptions(flags, lang, "IPO");
-  }
+  // Placeholder for possible future per-target flags.
+  static_cast<void>(target);
 }
 
 void cmLocalGenerator::AddLanguageFlagsForLinking(
@@ -1537,6 +1537,10 @@
   }
 
   this->AddLanguageFlags(flags, target, lang, config);
+
+  if (target->IsIPOEnabled(lang, config)) {
+    this->AppendFeatureOptions(flags, lang, "IPO");
+  }
 }
 
 cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
@@ -2241,11 +2245,8 @@
       dflag = df;
     }
   }
-
-  std::set<std::string>::const_iterator defineIt = defines.begin();
-  const std::set<std::string>::const_iterator defineEnd = defines.end();
   const char* itemSeparator = definesString.empty() ? "" : " ";
-  for (; defineIt != defineEnd; ++defineIt) {
+  for (std::string const& define : defines) {
     // Append the definition with proper escaping.
     std::string def = dflag;
     if (this->GetState()->UseWatcomWMake()) {
@@ -2259,7 +2260,7 @@
       // command line without any escapes.  However we still have to
       // get the '$' and '#' characters through WMake as '$$' and
       // '$#'.
-      for (const char* c = defineIt->c_str(); *c; ++c) {
+      for (const char* c = define.c_str(); *c; ++c) {
         if (*c == '$' || *c == '#') {
           def += '$';
         }
@@ -2268,11 +2269,11 @@
     } else {
       // Make the definition appear properly on the command line.  Use
       // -DNAME="value" instead of -D"NAME=value" for historical reasons.
-      std::string::size_type eq = defineIt->find("=");
-      def += defineIt->substr(0, eq);
+      std::string::size_type eq = define.find('=');
+      def += define.substr(0, eq);
       if (eq != std::string::npos) {
         def += "=";
-        def += this->EscapeForShell(defineIt->c_str() + eq + 1, true);
+        def += this->EscapeForShell(define.substr(eq + 1), true);
       }
     }
     definesString += itemSeparator;
@@ -2829,7 +2830,7 @@
 
 void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
                                               const std::string& targetName,
-                                              const char* fname)
+                                              const std::string& fname)
 {
   // Find the Info.plist template.
   const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
@@ -2863,11 +2864,12 @@
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
-  mf->ConfigureFile(inFile.c_str(), fname, false, false, false);
+  mf->ConfigureFile(inFile, fname, false, false, false);
 }
 
 void cmLocalGenerator::GenerateFrameworkInfoPList(
-  cmGeneratorTarget* target, const std::string& targetName, const char* fname)
+  cmGeneratorTarget* target, const std::string& targetName,
+  const std::string& fname)
 {
   // Find the Info.plist template.
   const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
@@ -2897,5 +2899,5 @@
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
-  mf->ConfigureFile(inFile.c_str(), fname, false, false, false);
+  mf->ConfigureFile(inFile, fname, false, false, false);
 }
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index f9839f6..67e3c58 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -76,13 +76,13 @@
 
   bool IsRootMakefile() const;
 
-  ///! Get the makefile for this generator
+  //! Get the makefile for this generator
   cmMakefile* GetMakefile() { return this->Makefile; }
 
-  ///! Get the makefile for this generator, const version
+  //! Get the makefile for this generator, const version
   const cmMakefile* GetMakefile() const { return this->Makefile; }
 
-  ///! Get the GlobalGenerator this is associated with
+  //! Get the GlobalGenerator this is associated with
   cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
   const cmGlobalGenerator* GetGlobalGenerator() const
   {
@@ -118,7 +118,7 @@
   void AddCompilerRequirementFlag(std::string& flags,
                                   cmGeneratorTarget const* target,
                                   const std::string& lang);
-  ///! Append flags to a string.
+  //! Append flags to a string.
   virtual void AppendFlags(std::string& flags,
                            const std::string& newFlags) const;
   virtual void AppendFlags(std::string& flags, const char* newFlags) const;
@@ -131,7 +131,7 @@
                                             cmGeneratorTarget* target,
                                             const std::string& config,
                                             const std::string& lang);
-  ///! Get the include flags for the current makefile and language
+  //! Get the include flags for the current makefile and language
   std::string GetIncludeFlags(const std::vector<std::string>& includes,
                               cmGeneratorTarget* target,
                               const std::string& lang,
@@ -340,14 +340,14 @@
    */
   void GenerateAppleInfoPList(cmGeneratorTarget* target,
                               const std::string& targetName,
-                              const char* fname);
+                              const std::string& fname);
 
   /**
    * Generate a macOS framework Info.plist file.
    */
   void GenerateFrameworkInfoPList(cmGeneratorTarget* target,
                                   const std::string& targetName,
-                                  const char* fname);
+                                  const std::string& fname);
   /** Construct a comment for a custom command.  */
   std::string ConstructComment(cmCustomCommandGenerator const& ccg,
                                const char* default_comment = "");
@@ -403,7 +403,7 @@
                               const std::string& prop);
 
 protected:
-  ///! put all the libraries for a target on into the given stream
+  //! put all the libraries for a target on into the given stream
   void OutputLinkLibraries(cmComputeLinkInformation* pcli,
                            cmLinkLineComputer* linkLineComputer,
                            std::string& linkLibraries,
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
index 125e8b5..bf25f98 100644
--- a/Source/cmLocalGhsMultiGenerator.cxx
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -2,12 +2,15 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmLocalGhsMultiGenerator.h"
 
-#include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGhsMultiTargetGenerator.h"
-#include "cmGlobalGhsMultiGenerator.h"
-#include "cmMakefile.h"
+#include "cmGlobalGenerator.h"
 #include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+#include <algorithm>
+#include <utility>
 
 cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
                                                    cmMakefile* mf)
@@ -15,9 +18,7 @@
 {
 }
 
-cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator()
-{
-}
+cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator() = default;
 
 std::string cmLocalGhsMultiGenerator::GetTargetDirectory(
   cmGeneratorTarget const* target) const
diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h
index d5bec42..b6ccd08 100644
--- a/Source/cmLocalGhsMultiGenerator.h
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -5,7 +5,14 @@
 
 #include "cmLocalGenerator.h"
 
-class cmGeneratedFileStream;
+#include <map>
+#include <string>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
 
 /** \class cmLocalGhsMultiGenerator
  * \brief Write Green Hills MULTI project files.
@@ -18,12 +25,12 @@
 public:
   cmLocalGhsMultiGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
 
-  virtual ~cmLocalGhsMultiGenerator();
+  ~cmLocalGhsMultiGenerator() override;
 
   /**
    * Generate the makefile for this directory.
    */
-  virtual void Generate();
+  void Generate() override;
 
   std::string GetTargetDirectory(
     cmGeneratorTarget const* target) const override;
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index c0afc25..f4e3ed8 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -232,8 +232,8 @@
         os << "  depth = " << jobs << std::endl;
         os << std::endl;
       } else {
-        cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': ",
-                             pool.c_str());
+        cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': " +
+                             pool);
       }
     }
   }
@@ -466,10 +466,12 @@
   cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()), ninjaDeps;
 
   bool symbolic = false;
-  for (std::vector<std::string>::const_iterator o = outputs.begin();
-       !symbolic && o != outputs.end(); ++o) {
-    if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
+  for (std::string const& output : outputs) {
+    if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
       symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+      if (symbolic) {
+        break;
+      }
     }
   }
 
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 7eb4a03..bece12e 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -11,8 +11,9 @@
 #include <utility>
 
 #include "cmAlgorithms.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
 #include "cmCustomCommandGenerator.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -22,6 +23,7 @@
 #include "cmMakefile.h"
 #include "cmMakefileTargetGenerator.h"
 #include "cmOutputConverter.h"
+#include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
@@ -1054,7 +1056,7 @@
   std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
   cmsys::ofstream fout(cleanfilePath.c_str());
   if (!fout) {
-    cmSystemTools::Error("Could not create ", cleanfilePath.c_str());
+    cmSystemTools::Error("Could not create " + cleanfilePath);
   }
   if (!files.empty()) {
     fout << "file(REMOVE_RECURSE\n";
@@ -1263,21 +1265,20 @@
   // Check if any multiple output pairs have a missing file.
   this->CheckMultipleOutputs(verbose);
 
-  std::string dir = cmSystemTools::GetFilenamePath(tgtInfo);
-  std::string internalDependFile = dir + "/depend.internal";
-  std::string dependFile = dir + "/depend.make";
+  std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
+  std::string const internalDependFile = targetDir + "/depend.internal";
+  std::string const dependFile = targetDir + "/depend.make";
 
   // If the target DependInfo.cmake file has changed since the last
   // time dependencies were scanned then force rescanning.  This may
   // happen when a new source file is added and CMake regenerates the
   // project but no other sources were touched.
   bool needRescanDependInfo = false;
-  cmFileTimeComparison* ftc =
-    this->GlobalGenerator->GetCMakeInstance()->GetFileComparison();
+  cmFileTimeCache* ftc =
+    this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
   {
     int result;
-    if (!ftc->FileTimeCompare(internalDependFile, tgtInfo, &result) ||
-        result < 0) {
+    if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
       if (verbose) {
         std::ostringstream msg;
         msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
@@ -1291,12 +1292,12 @@
   // If the directory information is newer than depend.internal, include dirs
   // may have changed. In this case discard all old dependencies.
   bool needRescanDirInfo = false;
-  std::string dirInfoFile = this->GetCurrentBinaryDirectory();
-  dirInfoFile += "/CMakeFiles";
-  dirInfoFile += "/CMakeDirectoryInformation.cmake";
   {
+    std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+    dirInfoFile += "/CMakeFiles";
+    dirInfoFile += "/CMakeDirectoryInformation.cmake";
     int result;
-    if (!ftc->FileTimeCompare(internalDependFile, dirInfoFile, &result) ||
+    if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
         result < 0) {
       if (verbose) {
         std::ostringstream msg;
@@ -1312,12 +1313,12 @@
   // The build.make file may have explicit dependencies for the object
   // files but these will not affect the scanning process so they need
   // not be considered.
-  std::map<std::string, cmDepends::DependencyVector> validDependencies;
+  cmDepends::DependencyMap validDependencies;
   bool needRescanDependencies = false;
   if (!needRescanDirInfo) {
     cmDependsC checker;
     checker.SetVerbose(verbose);
-    checker.SetFileComparison(ftc);
+    checker.SetFileTimeCache(ftc);
     // cmDependsC::Check() fills the vector validDependencies() with the
     // dependencies for those files where they are still valid, i.e. neither
     // the files themselves nor any files they depend on have changed.
@@ -1334,7 +1335,7 @@
 
   if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
     // The dependencies must be regenerated.
-    std::string targetName = cmSystemTools::GetFilenameName(dir);
+    std::string targetName = cmSystemTools::GetFilenameName(targetDir);
     targetName = targetName.substr(0, targetName.length() - 4);
     std::string message = "Scanning dependencies of target ";
     message += targetName;
@@ -1342,7 +1343,8 @@
                                        cmsysTerminal_Color_ForegroundBold,
                                      message.c_str(), true, color);
 
-    return this->ScanDependencies(dir, validDependencies);
+    return this->ScanDependencies(targetDir, dependFile, internalDependFile,
+                                  validDependencies);
   }
 
   // The dependencies are already up-to-date.
@@ -1350,17 +1352,20 @@
 }
 
 bool cmLocalUnixMakefileGenerator3::ScanDependencies(
-  const std::string& targetDir,
-  std::map<std::string, cmDepends::DependencyVector>& validDeps)
+  std::string const& targetDir, std::string const& dependFile,
+  std::string const& internalDependFile, cmDepends::DependencyMap& validDeps)
 {
   // Read the directory information file.
   cmMakefile* mf = this->Makefile;
   bool haveDirectoryInfo = false;
-  std::string dirInfoFile = this->GetCurrentBinaryDirectory();
-  dirInfoFile += "/CMakeFiles";
-  dirInfoFile += "/CMakeDirectoryInformation.cmake";
-  if (mf->ReadListFile(dirInfoFile) && !cmSystemTools::GetErrorOccuredFlag()) {
-    haveDirectoryInfo = true;
+  {
+    std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+    dirInfoFile += "/CMakeFiles";
+    dirInfoFile += "/CMakeDirectoryInformation.cmake";
+    if (mf->ReadListFile(dirInfoFile) &&
+        !cmSystemTools::GetErrorOccuredFlag()) {
+      haveDirectoryInfo = true;
+    }
   }
 
   // Lookup useful directory information.
@@ -1389,10 +1394,8 @@
 
   // Open the make depends file.  This should be copy-if-different
   // because the make tool may try to reload it needlessly otherwise.
-  std::string ruleFileNameFull = targetDir;
-  ruleFileNameFull += "/depend.make";
   cmGeneratedFileStream ruleFileStream(
-    ruleFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
+    dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
   ruleFileStream.SetCopyIfDifferent(true);
   if (!ruleFileStream) {
     return false;
@@ -1401,11 +1404,8 @@
   // Open the cmake dependency tracking file.  This should not be
   // copy-if-different because dependencies are re-scanned when it is
   // older than the DependInfo.cmake.
-  std::string internalRuleFileNameFull = targetDir;
-  internalRuleFileNameFull += "/depend.internal";
   cmGeneratedFileStream internalRuleFileStream(
-    internalRuleFileNameFull, false,
-    this->GlobalGenerator->GetMakefileEncoding());
+    internalDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
   if (!internalRuleFileStream) {
     return false;
   }
@@ -1414,39 +1414,35 @@
   this->WriteDisclaimer(internalRuleFileStream);
 
   // for each language we need to scan, scan it
-  std::string const& langStr =
-    mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES");
   std::vector<std::string> langs;
-  cmSystemTools::ExpandListArgument(langStr, langs);
+  cmSystemTools::ExpandListArgument(
+    mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"), langs);
   for (std::string const& lang : langs) {
     // construct the checker
     // Create the scanner for this language
-    cmDepends* scanner = nullptr;
+    std::unique_ptr<cmDepends> scanner;
     if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
         lang == "CUDA") {
       // TODO: Handle RC (resource files) dependencies correctly.
-      scanner = new cmDependsC(this, targetDir, lang, &validDeps);
+      scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
     }
 #ifdef CMAKE_BUILD_WITH_CMAKE
     else if (lang == "Fortran") {
       ruleFileStream << "# Note that incremental build could trigger "
                      << "a call to cmake_copy_f90_mod on each re-build\n";
-      scanner = new cmDependsFortran(this);
+      scanner = cm::make_unique<cmDependsFortran>(this);
     } else if (lang == "Java") {
-      scanner = new cmDependsJava();
+      scanner = cm::make_unique<cmDependsJava>();
     }
 #endif
 
     if (scanner) {
       scanner->SetLocalGenerator(this);
-      scanner->SetFileComparison(
-        this->GlobalGenerator->GetCMakeInstance()->GetFileComparison());
+      scanner->SetFileTimeCache(
+        this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache());
       scanner->SetLanguage(lang);
       scanner->SetTargetDirectory(targetDir);
       scanner->Write(ruleFileStream, internalRuleFileStream);
-
-      // free the scanner for this language
-      delete scanner;
     }
   }
 
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index ced2dbd..7a0ea98 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -143,8 +143,7 @@
 
   // File pairs for implicit dependency scanning.  The key of the map
   // is the depender and the value is the explicit dependee.
-  struct ImplicitDependFileMap
-    : public std::map<std::string, cmDepends::DependencyVector>
+  struct ImplicitDependFileMap : public cmDepends::DependencyMap
   {
   };
   struct ImplicitDependLanguageMap
@@ -230,9 +229,10 @@
                           const char* filename = nullptr);
 
   // Helper methods for dependency updates.
-  bool ScanDependencies(
-    const std::string& targetDir,
-    std::map<std::string, cmDepends::DependencyVector>& validDeps);
+  bool ScanDependencies(std::string const& targetDir,
+                        std::string const& dependFile,
+                        std::string const& internalDependFile,
+                        cmDepends::DependencyMap& validDeps);
   void CheckMultipleOutputs(bool verbose);
 
 private:
diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h
index a4150b9..5c6400e 100644
--- a/Source/cmLocalVisualStudio10Generator.h
+++ b/Source/cmLocalVisualStudio10Generator.h
@@ -21,7 +21,7 @@
 class cmLocalVisualStudio10Generator : public cmLocalVisualStudio7Generator
 {
 public:
-  ///! Set cache only and recurse to false by default.
+  //! Set cache only and recurse to false by default.
   cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf);
 
   virtual ~cmLocalVisualStudio10Generator();
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 7019552..7ba3471 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmLocalVisualStudio7Generator.h"
 
+#include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalVisualStudio7Generator.h"
@@ -118,8 +119,8 @@
   // If not an in source build, then create the output directory
   if (this->GetCurrentBinaryDirectory() != this->GetSourceDirectory()) {
     if (!cmSystemTools::MakeDirectory(this->GetCurrentBinaryDirectory())) {
-      cmSystemTools::Error("Error creating directory ",
-                           this->GetCurrentBinaryDirectory().c_str());
+      cmSystemTools::Error("Error creating directory " +
+                           this->GetCurrentBinaryDirectory());
     }
   }
 
@@ -283,7 +284,7 @@
     file->GetFullPath();
     return file;
   } else {
-    cmSystemTools::Error("Error adding rule for ", makefileIn.c_str());
+    cmSystemTools::Error("Error adding rule for " + makefileIn);
     return nullptr;
   }
 }
@@ -293,9 +294,8 @@
   const std::string& libName, cmGeneratorTarget* target)
 {
   fout << "\t<Configurations>\n";
-  for (std::vector<std::string>::const_iterator i = configs.begin();
-       i != configs.end(); ++i) {
-    this->WriteConfiguration(fout, i->c_str(), libName, target);
+  for (std::string const& config : configs) {
+    this->WriteConfiguration(fout, config.c_str(), libName, target);
   }
   fout << "\t</Configurations>\n";
 }
@@ -569,9 +569,8 @@
   void Finish() { this->Stream << (this->First ? "" : "\"") << "/>\n"; }
   void Write(std::vector<cmCustomCommand> const& ccs)
   {
-    for (std::vector<cmCustomCommand>::const_iterator ci = ccs.begin();
-         ci != ccs.end(); ++ci) {
-      this->Write(*ci);
+    for (cmCustomCommand const& command : ccs) {
+      this->Write(command);
     }
   }
   void Write(cmCustomCommand const& cc)
@@ -656,21 +655,14 @@
                             : target->GetLinkerLanguage(configName));
     if (linkLanguage.empty()) {
       cmSystemTools::Error(
-        "CMake can not determine linker language for target: ",
-        target->GetName().c_str());
+        "CMake can not determine linker language for target: " +
+        target->GetName());
       return;
     }
     langForClCompile = linkLanguage;
     if (langForClCompile == "C" || langForClCompile == "CXX" ||
         langForClCompile == "Fortran") {
-      std::string baseFlagVar = "CMAKE_";
-      baseFlagVar += langForClCompile;
-      baseFlagVar += "_FLAGS";
-      flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
-      std::string flagVar =
-        baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName);
-      flags += " ";
-      flags += this->Makefile->GetRequiredDefinition(flagVar);
+      this->AddLanguageFlags(flags, target, langForClCompile, configName);
     }
     // set the correct language
     if (linkLanguage == "C") {
@@ -897,10 +889,8 @@
     target->GetManifests(manifest_srcs, configName);
     if (!manifest_srcs.empty()) {
       fout << "\n\t\t\t\tAdditionalManifestFiles=\"";
-      for (std::vector<cmSourceFile const*>::const_iterator mi =
-             manifest_srcs.begin();
-           mi != manifest_srcs.end(); ++mi) {
-        std::string m = (*mi)->GetFullPath();
+      for (cmSourceFile const* manifest : manifest_srcs) {
+        std::string m = manifest->GetFullPath();
         fout << this->ConvertToXMLOutputPath(m.c_str()) << ";";
       }
       fout << "\"";
@@ -931,7 +921,7 @@
   std::string extraLinkOptionsBuildTypeDef =
     rootLinkerFlags + "_" + configTypeUpper;
 
-  std::string extraLinkOptionsBuildType =
+  const std::string& extraLinkOptionsBuildType =
     this->Makefile->GetRequiredDefinition(extraLinkOptionsBuildTypeDef);
 
   return extraLinkOptionsBuildType;
@@ -947,21 +937,18 @@
   std::string extraLinkOptions;
   if (target->GetType() == cmStateEnums::EXECUTABLE) {
     extraLinkOptions =
-      this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") +
-      std::string(" ") +
+      this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") + " " +
       GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName);
   }
   if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
     extraLinkOptions =
       this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS") +
-      std::string(" ") +
-      GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
+      " " + GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
   }
   if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
     extraLinkOptions =
       this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS") +
-      std::string(" ") +
-      GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
+      " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
   }
 
   const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
@@ -1050,13 +1037,8 @@
     }
     case cmStateEnums::SHARED_LIBRARY:
     case cmStateEnums::MODULE_LIBRARY: {
-      std::string targetName;
-      std::string targetNameSO;
-      std::string targetNameFull;
-      std::string targetNameImport;
-      std::string targetNamePDB;
-      target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
-                              targetNameImport, targetNamePDB, configName);
+      cmGeneratorTarget::Names targetNames =
+        target->GetLibraryNames(configName);
 
       // Compute the link library and directory information.
       cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
@@ -1092,7 +1074,7 @@
       fout << "\"\n";
       temp = target->GetDirectory(configName);
       temp += "/";
-      temp += targetNameFull;
+      temp += targetNames.Output;
       fout << "\t\t\t\tOutputFile=\""
            << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
       this->WriteTargetVersionAttribute(fout, target);
@@ -1102,7 +1084,7 @@
       fout << "\"\n";
       temp = target->GetPDBDirectory(configName);
       temp += "/";
-      temp += targetNamePDB;
+      temp += targetNames.PDB;
       fout << "\t\t\t\tProgramDatabaseFile=\""
            << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
       if (targetOptions.IsDebug()) {
@@ -1125,7 +1107,7 @@
       temp =
         target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact);
       temp += "/";
-      temp += targetNameImport;
+      temp += targetNames.ImportLibrary;
       fout << "\t\t\t\tImportLibrary=\""
            << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"";
       if (this->FortranProject) {
@@ -1134,12 +1116,8 @@
       fout << "/>\n";
     } break;
     case cmStateEnums::EXECUTABLE: {
-      std::string targetName;
-      std::string targetNameFull;
-      std::string targetNameImport;
-      std::string targetNamePDB;
-      target->GetExecutableNames(targetName, targetNameFull, targetNameImport,
-                                 targetNamePDB, configName);
+      cmGeneratorTarget::Names targetNames =
+        target->GetExecutableNames(configName);
 
       // Compute the link library and directory information.
       cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
@@ -1177,7 +1155,7 @@
       fout << "\"\n";
       temp = target->GetDirectory(configName);
       temp += "/";
-      temp += targetNameFull;
+      temp += targetNames.Output;
       fout << "\t\t\t\tOutputFile=\""
            << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
       this->WriteTargetVersionAttribute(fout, target);
@@ -1187,8 +1165,8 @@
       fout << "\"\n";
       std::string path = this->ConvertToXMLOutputPathSingle(
         target->GetPDBDirectory(configName).c_str());
-      fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNamePDB
-           << "\"\n";
+      fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/"
+           << targetNames.PDB << "\"\n";
       if (targetOptions.IsDebug()) {
         fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
       }
@@ -1223,7 +1201,7 @@
       temp =
         target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact);
       temp += "/";
-      temp += targetNameImport;
+      temp += targetNames.ImportLibrary;
       fout << "\t\t\t\tImportLibrary=\""
            << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"/>\n";
       break;
@@ -1303,14 +1281,14 @@
 {
   cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
   std::string currentBinDir = lg->GetCurrentBinaryDirectory();
-  for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) {
-    if (l->IsPath) {
+  for (auto const& lib : libs) {
+    if (lib.IsPath) {
       std::string rel =
-        lg->MaybeConvertToRelativePath(currentBinDir, l->Value.c_str());
+        lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.c_str());
       fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
-    } else if (!l->Target ||
-               l->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
-      fout << l->Value << " ";
+    } else if (!lib.Target ||
+               lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+      fout << lib.Value << " ";
     }
   }
 }
@@ -1328,10 +1306,9 @@
   gt->GetExternalObjects(objs, configName);
 
   const char* sep = isep ? isep : "";
-  for (std::vector<cmSourceFile const*>::const_iterator i = objs.begin();
-       i != objs.end(); ++i) {
-    if (!(*i)->GetObjectLibrary().empty()) {
-      std::string const& objFile = (*i)->GetFullPath();
+  for (cmSourceFile const* obj : objs) {
+    if (!obj->GetObjectLibrary().empty()) {
+      std::string const& objFile = obj->GetFullPath();
       std::string rel = lg->MaybeConvertToRelativePath(currentBinDir, objFile);
       fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
       sep = " ";
@@ -1344,10 +1321,8 @@
 {
   const char* comma = "";
   std::string currentBinDir = this->GetCurrentBinaryDirectory();
-  for (std::vector<std::string>::const_iterator d = dirs.begin();
-       d != dirs.end(); ++d) {
+  for (std::string dir : dirs) {
     // Remove any trailing slash and skip empty paths.
-    std::string dir = *d;
     if (dir.back() == '/') {
       dir = dir.substr(0, dir.size() - 1);
     }
@@ -1483,9 +1458,8 @@
 
   // Compute per-source, per-config information.
   size_t ci = 0;
-  for (std::vector<std::string>::const_iterator i = configs.begin();
-       i != configs.end(); ++i, ++ci) {
-    std::string configUpper = cmSystemTools::UpperCase(*i);
+  for (std::string const& config : configs) {
+    std::string configUpper = cmSystemTools::UpperCase(config);
     cmLVS7GFileConfig fc;
 
     std::string lang =
@@ -1498,7 +1472,7 @@
       lang = sourceLang;
     }
 
-    cmGeneratorExpressionInterpreter genexInterpreter(lg, *i, gt, lang);
+    cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gt, lang);
 
     bool needfc = false;
     if (!objectName.empty()) {
@@ -1564,7 +1538,7 @@
       }
     }
 
-    const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str());
+    const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str());
     // If HEADER_FILE_ONLY is set, we must suppress this generation in
     // the project file
     fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
@@ -1589,8 +1563,9 @@
     }
 
     if (needfc) {
-      this->FileConfigMap[*i] = fc;
+      this->FileConfigMap[config] = fc;
     }
+    ++ci;
   }
 }
 
@@ -1654,16 +1629,14 @@
   }
 
   // Loop through each source in the source group.
-  for (std::vector<const cmSourceFile*>::const_iterator sf =
-         sourceFiles.begin();
-       sf != sourceFiles.end(); ++sf) {
-    std::string source = (*sf)->GetFullPath();
+  for (const cmSourceFile* sf : sourceFiles) {
+    std::string source = sf->GetFullPath();
 
     if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
         target->GetType() == cmStateEnums::GLOBAL_TARGET) {
       // Look up the source kind and configs.
       std::map<cmSourceFile const*, size_t>::const_iterator map_it =
-        sources.Index.find(*sf);
+        sources.Index.find(sf);
       // The map entry must exist because we populated it earlier.
       assert(map_it != sources.Index.end());
       cmGeneratorTarget::AllConfigSource const& acs =
@@ -1676,7 +1649,7 @@
       // Tell MS-Dev what the source is.  If the compiler knows how to
       // build it, then it will.
       fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
-      if (cmCustomCommand const* command = (*sf)->GetCustomCommand()) {
+      if (cmCustomCommand const* command = sf->GetCustomCommand()) {
         this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo);
       } else if (!fcinfo.FileConfigMap.empty()) {
         const char* aCompilerTool = "VCCLCompilerTool";
@@ -1684,8 +1657,8 @@
         if (this->FortranProject) {
           aCompilerTool = "VFFortranCompilerTool";
         }
-        std::string const& lang = (*sf)->GetLanguage();
-        std::string ext = (*sf)->GetExtension();
+        std::string const& lang = sf->GetLanguage();
+        std::string ext = sf->GetExtension();
         ext = cmSystemTools::LowerCase(ext);
         if (ext == "idl") {
           aCompilerTool = "VCMIDLTool";
@@ -1713,12 +1686,10 @@
         if (acs.Kind == cmGeneratorTarget::SourceKindExternalObject) {
           aCompilerTool = "VCCustomBuildTool";
         }
-        for (std::map<std::string, cmLVS7GFileConfig>::const_iterator fci =
-               fcinfo.FileConfigMap.begin();
-             fci != fcinfo.FileConfigMap.end(); ++fci) {
-          cmLVS7GFileConfig const& fc = fci->second;
+        for (auto const& fci : fcinfo.FileConfigMap) {
+          cmLVS7GFileConfig const& fc = fci.second;
           fout << "\t\t\t\t<FileConfiguration\n"
-               << "\t\t\t\t\tName=\"" << fci->first << "|"
+               << "\t\t\t\t\tName=\"" << fci.first << "|"
                << gg->GetPlatformName() << "\"";
           if (fc.ExcludedFromBuild) {
             fout << " ExcludedFromBuild=\"true\"";
@@ -1741,7 +1712,7 @@
             fileOptions.AddDefines(fc.CompileDefsConfig);
             // validate source level include directories
             std::vector<std::string> includes;
-            this->AppendIncludeDirectories(includes, fc.IncludeDirs, **sf);
+            this->AppendIncludeDirectories(includes, fc.IncludeDirs, *sf);
             fileOptions.AddIncludes(includes);
             fileOptions.OutputFlagMap(fout, 5);
             fileOptions.OutputAdditionalIncludeDirectories(
@@ -1794,12 +1765,11 @@
   if (this->FortranProject) {
     customTool = "VFCustomBuildTool";
   }
-  for (std::vector<std::string>::const_iterator i = configs.begin();
-       i != configs.end(); ++i) {
-    cmCustomCommandGenerator ccg(command, *i, this);
-    cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[*i];
+  for (std::string const& config : configs) {
+    cmCustomCommandGenerator ccg(command, config, this);
+    cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[config];
     fout << "\t\t\t\t<FileConfiguration\n";
-    fout << "\t\t\t\t\tName=\"" << *i << "|" << gg->GetPlatformName()
+    fout << "\t\t\t\t\tName=\"" << config << "|" << gg->GetPlatformName()
          << "\">\n";
     if (!fc.CompileFlags.empty()) {
       fout << "\t\t\t\t\t<Tool\n"
@@ -1811,7 +1781,7 @@
     std::string comment = this->ConstructComment(ccg);
     std::string script = this->ConstructScript(ccg);
     if (this->FortranProject) {
-      cmSystemTools::ReplaceString(script, "$(Configuration)", i->c_str());
+      cmSystemTools::ReplaceString(script, "$(Configuration)", config.c_str());
     }
     /* clang-format off */
     fout << "\t\t\t\t\t<Tool\n"
@@ -1832,12 +1802,10 @@
       fout << this->ConvertToXMLOutputPath(source);
     } else {
       // Write out the dependencies for the rule.
-      for (std::vector<std::string>::const_iterator d =
-             ccg.GetDepends().begin();
-           d != ccg.GetDepends().end(); ++d) {
+      for (std::string const& d : ccg.GetDepends()) {
         // Get the real name of the dependency in case it is a CMake target.
         std::string dep;
-        if (this->GetRealDependency(d->c_str(), i->c_str(), dep)) {
+        if (this->GetRealDependency(d.c_str(), config.c_str(), dep)) {
           fout << this->ConvertToXMLOutputPath(dep.c_str()) << ";";
         }
       }
@@ -1849,10 +1817,8 @@
     } else {
       // Write a rule for the output generated by this command.
       const char* sep = "";
-      for (std::vector<std::string>::const_iterator o =
-             ccg.GetOutputs().begin();
-           o != ccg.GetOutputs().end(); ++o) {
-        fout << sep << this->ConvertToXMLOutputPathSingle(o->c_str());
+      for (std::string const& output : ccg.GetOutputs()) {
+        fout << sep << this->ConvertToXMLOutputPathSingle(output.c_str());
         sep = ";";
       }
     }
@@ -2063,16 +2029,14 @@
 {
   fout << "\t<Globals>\n";
 
-  std::vector<std::string> const& props = target->GetPropertyKeys();
-  for (std::vector<std::string>::const_iterator i = props.begin();
-       i != props.end(); ++i) {
-    if (i->find("VS_GLOBAL_") == 0) {
-      std::string name = i->substr(10);
+  for (std::string const& key : target->GetPropertyKeys()) {
+    if (key.find("VS_GLOBAL_") == 0) {
+      std::string name = key.substr(10);
       if (!name.empty()) {
         /* clang-format off */
         fout << "\t\t<Global\n"
              << "\t\t\tName=\"" << name << "\"\n"
-             << "\t\t\tValue=\"" << target->GetProperty(*i) << "\"\n"
+             << "\t\t\tValue=\"" << target->GetProperty(key) << "\"\n"
              << "\t\t/>\n";
         /* clang-format on */
       }
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index b093e6f..ce8eceb 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -43,7 +43,7 @@
 class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator
 {
 public:
-  ///! Set cache only and recurse to false by default.
+  //! Set cache only and recurse to false by default.
   cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf);
 
   virtual ~cmLocalVisualStudio7Generator();
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index 660729c..f3f2042 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmLocalVisualStudioGenerator.h"
 
+#include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h
index 5c22dcf..42de20b 100644
--- a/Source/cmLocalXCodeGenerator.h
+++ b/Source/cmLocalXCodeGenerator.h
@@ -24,7 +24,7 @@
 class cmLocalXCodeGenerator : public cmLocalGenerator
 {
 public:
-  ///! Set cache only and recurse to false by default.
+  //! Set cache only and recurse to false by default.
   cmLocalXCodeGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
 
   ~cmLocalXCodeGenerator() override;
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index 7279d5f..6565f02 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -10,6 +10,7 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
+#include "cmRange.h"
 #include "cmState.h"
 #include "cmSystemTools.h"
 
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 7e33bda..3832427 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -31,6 +31,7 @@
 #include "cmInstallSubdirectoryGenerator.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
 #include "cmState.h"
@@ -292,13 +293,14 @@
   std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
   bool trace = trace_only_this_files.empty();
   if (!trace) {
-    for (std::vector<std::string>::const_iterator i =
-           trace_only_this_files.begin();
-         !trace && i != trace_only_this_files.end(); ++i) {
-      std::string::size_type const pos = full_path.rfind(*i);
+    for (std::string const& file : trace_only_this_files) {
+      std::string::size_type const pos = full_path.rfind(file);
       trace = (pos != std::string::npos) &&
-        ((pos + i->size()) == full_path.size()) &&
-        (only_filename == cmSystemTools::GetFilenameName(*i));
+        ((pos + file.size()) == full_path.size()) &&
+        (only_filename == cmSystemTools::GetFilenameName(file));
+      if (trace) {
+        break;
+      }
     }
     // Do nothing if current file wasn't requested for trace...
     if (!trace) {
@@ -347,6 +349,9 @@
     this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
   }
 
+  cmMakefileCall(const cmMakefileCall&) = delete;
+  cmMakefileCall& operator=(const cmMakefileCall&) = delete;
+
 private:
   cmMakefile* Makefile;
 };
@@ -438,6 +443,9 @@
   ~IncludeScope();
   void Quiet() { this->ReportError = false; }
 
+  IncludeScope(const IncludeScope&) = delete;
+  IncludeScope& operator=(const IncludeScope&) = delete;
+
 private:
   cmMakefile* Makefile;
   bool NoPolicyScope;
@@ -605,6 +613,9 @@
 
   void Quiet() { this->ReportError = false; }
 
+  ListFileScope(const ListFileScope&) = delete;
+  ListFileScope& operator=(const ListFileScope&) = delete;
+
 private:
   cmMakefile* Makefile;
   bool ReportError;
@@ -949,9 +960,8 @@
     if (file && file->GetCustomCommand() && !replace) {
       // The rule file already exists.
       if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
-        cmSystemTools::Error("Attempt to add a custom rule to output \"",
-                             outName.c_str(),
-                             "\" which already has a custom rule.");
+        cmSystemTools::Error("Attempt to add a custom rule to output \"" +
+                             outName + "\" which already has a custom rule.");
       }
       return file;
     }
@@ -1091,8 +1101,8 @@
         ti->second.AddSource(sf->GetFullPath());
       } else {
         cmSystemTools::Error("Attempt to add a custom rule to a target "
-                             "that does not exist yet for target ",
-                             target.c_str());
+                             "that does not exist yet for target " +
+                             target);
         return;
       }
     }
@@ -1179,8 +1189,7 @@
     if (sf) {
       sf->SetProperty("SYMBOLIC", "1");
     } else {
-      cmSystemTools::Error("Could not get source file entry for ",
-                           force.c_str());
+      cmSystemTools::Error("Could not get source file entry for " + force);
     }
 
     // Always create the byproduct sources and mark them generated.
@@ -1496,6 +1505,9 @@
 
   void Quiet() { this->ReportError = false; }
 
+  BuildsystemFileScope(const BuildsystemFileScope&) = delete;
+  BuildsystemFileScope& operator=(const BuildsystemFileScope&) = delete;
+
 private:
   cmMakefile* Makefile;
   cmGlobalGenerator* GG;
@@ -1848,10 +1860,8 @@
   if (!this->WarnUnused) {
     return;
   }
-  const std::vector<std::string>& unused = this->StateSnapshot.UnusedKeys();
-  std::vector<std::string>::const_iterator it = unused.begin();
-  for (; it != unused.end(); ++it) {
-    this->LogUnused("out of scope", *it);
+  for (const std::string& key : this->StateSnapshot.UnusedKeys()) {
+    this->LogUnused("out of scope", key);
   }
 }
 
@@ -2013,8 +2023,7 @@
 {
   cmTargets::iterator it =
     this->Targets
-      .insert(cmTargets::value_type(
-        name, cmTarget(name, type, cmTarget::VisibilityNormal, this)))
+      .emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this))
       .first;
   this->GetGlobalGenerator()->IndexTarget(&it->second);
   this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
@@ -2195,7 +2204,7 @@
   }
 
   // Shouldn't get here, but just in case, return the default group.
-  return &groups.front();
+  return groups.data();
 }
 #endif
 
@@ -2427,16 +2436,19 @@
     cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory());
 }
 
-std::string cmMakefile::GetRequiredDefinition(const std::string& name) const
+const std::string& cmMakefile::GetRequiredDefinition(
+  const std::string& name) const
 {
-  const char* ret = this->GetDefinition(name);
-  if (!ret) {
+  static std::string const empty;
+  const std::string* def = GetDef(name);
+  if (!def) {
     cmSystemTools::Error("Error required internal CMake variable not "
-                         "set, cmake may not be built correctly.\n",
-                         "Missing variable is:\n", name.c_str());
-    return std::string();
+                         "set, cmake may not be built correctly.\n"
+                         "Missing variable is:\n" +
+                         name);
+    return empty;
   }
-  return std::string(ret);
+  return *def;
 }
 
 bool cmMakefile::IsDefinitionSet(const std::string& name) const
@@ -3057,10 +3069,8 @@
 
   // loop over all function blockers to see if any block this command
   // evaluate in reverse, this is critical for balanced IF statements etc
-  std::vector<cmFunctionBlocker*>::reverse_iterator pos;
-  for (pos = this->FunctionBlockers.rbegin();
-       pos != this->FunctionBlockers.rend(); ++pos) {
-    if ((*pos)->IsFunctionBlocked(lff, *this, status)) {
+  for (cmFunctionBlocker* pos : cmReverseRange(this->FunctionBlockers)) {
+    if (pos->IsFunctionBlocked(lff, *this, status)) {
       return true;
     }
   }
@@ -3548,7 +3558,7 @@
   return this->GetCMakeInstance()->GetState();
 }
 
-void cmMakefile::DisplayStatus(const char* message, float s) const
+void cmMakefile::DisplayStatus(const std::string& message, float s) const
 {
   cmake* cm = this->GetCMakeInstance();
   if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
@@ -3718,22 +3728,23 @@
                                 lineNumber, true, true);
 }
 
-int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
-                              bool copyonly, bool atOnly, bool escapeQuotes,
+int cmMakefile::ConfigureFile(const std::string& infile,
+                              const std::string& outfile, bool copyonly,
+                              bool atOnly, bool escapeQuotes,
                               cmNewLineStyle newLine)
 {
   int res = 1;
   if (!this->CanIWriteThisFile(outfile)) {
-    cmSystemTools::Error("Attempt to write file: ", outfile,
+    cmSystemTools::Error("Attempt to write file: " + outfile +
                          " into a source directory.");
     return 0;
   }
   if (!cmSystemTools::FileExists(infile)) {
-    cmSystemTools::Error("File ", infile, " does not exist.");
+    cmSystemTools::Error("File " + infile + " does not exist.");
     return 0;
   }
   std::string soutfile = outfile;
-  std::string sinfile = infile;
+  const std::string& sinfile = infile;
   this->AddCMakeDependFile(sinfile);
   cmSystemTools::ConvertToUnixSlashes(soutfile);
 
@@ -3767,15 +3778,15 @@
     tempOutputFile += ".tmp";
     cmsys::ofstream fout(tempOutputFile.c_str(), omode);
     if (!fout) {
-      cmSystemTools::Error("Could not open file for write in copy operation ",
-                           tempOutputFile.c_str());
+      cmSystemTools::Error("Could not open file for write in copy operation " +
+                           tempOutputFile);
       cmSystemTools::ReportLastSystemError("");
       return 0;
     }
     cmsys::ifstream fin(sinfile.c_str());
     if (!fin) {
-      cmSystemTools::Error("Could not open file for read in copy operation ",
-                           sinfile.c_str());
+      cmSystemTools::Error("Could not open file for read in copy operation " +
+                           sinfile);
       return 0;
     }
 
@@ -4275,7 +4286,7 @@
 
   // Deprecate old policies, especially those that require a lot
   // of code to maintain the old behavior.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0065 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0066 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4713,6 +4724,13 @@
                                needCxx17, needCxx20);
 
   const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
+  if (existingCxxStandard == nullptr) {
+    const char* defaultCxxStandard =
+      this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
+    if (defaultCxxStandard && *defaultCxxStandard) {
+      existingCxxStandard = defaultCxxStandard;
+    }
+  }
   const char* const* existingCxxLevel = nullptr;
   if (existingCxxStandard) {
     existingCxxLevel =
@@ -4815,6 +4833,13 @@
   this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
 
   const char* existingCStandard = target->GetProperty("C_STANDARD");
+  if (existingCStandard == nullptr) {
+    const char* defaultCStandard =
+      this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
+    if (defaultCStandard && *defaultCStandard) {
+      existingCStandard = defaultCStandard;
+    }
+  }
   if (existingCStandard) {
     if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
                      cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) {
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 70a5689..8cc14f3 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -257,7 +257,7 @@
    * can be used in CMake to refer to lists, directories, etc.
    */
   void AddDefinition(const std::string& name, const char* value);
-  ///! Add a definition to this makefile and the global cmake cache.
+  //! Add a definition to this makefile and the global cmake cache.
   void AddCacheDefinition(const std::string& name, const char* value,
                           const char* doc, cmStateEnums::CacheEntryType type,
                           bool force = false);
@@ -272,7 +272,7 @@
    * for cache entries, and will only affect the current makefile.
    */
   void RemoveDefinition(const std::string& name);
-  ///! Remove a definition from the cache.
+  //! Remove a definition from the cache.
   void RemoveCacheDefinition(const std::string& name);
 
   /**
@@ -313,6 +313,9 @@
     PolicyPushPop(cmMakefile* m);
     ~PolicyPushPop();
 
+    PolicyPushPop(const PolicyPushPop&) = delete;
+    PolicyPushPop& operator=(const PolicyPushPop&) = delete;
+
   private:
     cmMakefile* Makefile;
   };
@@ -436,7 +439,7 @@
   const char* GetDefinition(const std::string&) const;
   const std::string* GetDef(const std::string&) const;
   const std::string& GetSafeDefinition(const std::string&) const;
-  std::string GetRequiredDefinition(const std::string& name) const;
+  const std::string& GetRequiredDefinition(const std::string& name) const;
   bool IsDefinitionSet(const std::string&) const;
   /**
    * Get the list of all variables in the current space. If argument
@@ -545,7 +548,7 @@
   {
     return this->ListFiles;
   }
-  ///! When the file changes cmake will be re-run from the build system.
+  //! When the file changes cmake will be re-run from the build system.
   void AddCMakeDependFile(const std::string& file)
   {
     this->ListFiles.push_back(file);
@@ -607,8 +610,8 @@
   /**
    * Copy file but change lines according to ConfigureString
    */
-  int ConfigureFile(const char* infile, const char* outfile, bool copyonly,
-                    bool atOnly, bool escapeQuotes,
+  int ConfigureFile(const std::string& infile, const std::string& outfile,
+                    bool copyonly, bool atOnly, bool escapeQuotes,
                     cmNewLineStyle = cmNewLineStyle());
 
   /**
@@ -623,7 +626,7 @@
   bool ExecuteCommand(const cmListFileFunction& lff,
                       cmExecutionStatus& status);
 
-  ///! Enable support for named language, if nil then all languages are
+  //! Enable support for named language, if nil then all languages are
   /// enabled.
   void EnableLanguage(std::vector<std::string> const& languages,
                       bool optional);
@@ -638,8 +641,8 @@
   cmVariableWatch* GetVariableWatch() const;
 #endif
 
-  ///! Display progress or status message.
-  void DisplayStatus(const char*, float) const;
+  //! Display progress or status message.
+  void DisplayStatus(const std::string&, float) const;
 
   /**
    * Expand the given list file arguments into the full set after
@@ -674,7 +677,7 @@
    */
   cmSourceFile* GetSourceFileWithOutput(const std::string& outName) const;
 
-  ///! Add a new cmTest to the list of tests for this makefile.
+  //! Add a new cmTest to the list of tests for this makefile.
   cmTest* CreateTest(const std::string& testName);
 
   /** Get a cmTest pointer for a given test name, if the name is
@@ -698,7 +701,7 @@
 
   std::string GetModulesFile(const std::string& name, bool& system) const;
 
-  ///! Set/Get a property of this directory
+  //! Set/Get a property of this directory
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
@@ -707,7 +710,7 @@
   bool GetPropertyAsBool(const std::string& prop) const;
   std::vector<std::string> GetPropertyKeys() const;
 
-  ///! Initialize a makefile from its parent
+  //! Initialize a makefile from its parent
   void InitializeFromParent(cmMakefile* parent);
 
   void AddInstallGenerator(cmInstallGenerator* g)
@@ -743,6 +746,9 @@
                     cmPolicies::PolicyMap const& pm);
     ~FunctionPushPop();
 
+    FunctionPushPop(const FunctionPushPop&) = delete;
+    FunctionPushPop& operator=(const FunctionPushPop&) = delete;
+
     void Quiet() { this->ReportError = false; }
 
   private:
@@ -757,6 +763,9 @@
                  cmPolicies::PolicyMap const& pm);
     ~MacroPushPop();
 
+    MacroPushPop(const MacroPushPop&) = delete;
+    MacroPushPop& operator=(const MacroPushPop&) = delete;
+
     void Quiet() { this->ReportError = false; }
 
   private:
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index e8ae5ae..984cd85 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -31,9 +31,8 @@
   : cmMakefileTargetGenerator(target)
 {
   this->CustomCommandDriver = OnDepends;
-  this->GeneratorTarget->GetExecutableNames(
-    this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
-    this->TargetNamePDB, this->ConfigName);
+  this->TargetNames =
+    this->GeneratorTarget->GetExecutableNames(this->ConfigName);
 
   this->OSXBundleGenerator =
     new cmOSXBundleGenerator(target, this->ConfigName);
@@ -305,18 +304,13 @@
   std::vector<std::string> commands;
 
   // Get the name of the executable to generate.
-  std::string targetName;
-  std::string targetNameReal;
-  std::string targetNameImport;
-  std::string targetNamePDB;
-  this->GeneratorTarget->GetExecutableNames(targetName, targetNameReal,
-                                            targetNameImport, targetNamePDB,
-                                            this->ConfigName);
+  cmGeneratorTarget::Names targetNames =
+    this->GeneratorTarget->GetExecutableNames(this->ConfigName);
 
   // Construct the full path version of the names.
   std::string outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
   if (this->GeneratorTarget->IsAppBundleOnApple()) {
-    this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);
+    this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath);
   }
   outpath += "/";
   std::string outpathImp;
@@ -326,12 +320,12 @@
     outpath += "/CMakeRelink.dir";
     cmSystemTools::MakeDirectory(outpath);
     outpath += "/";
-    if (!targetNameImport.empty()) {
+    if (!targetNames.ImportLibrary.empty()) {
       outpathImp = outpath;
     }
   } else {
     cmSystemTools::MakeDirectory(outpath);
-    if (!targetNameImport.empty()) {
+    if (!targetNames.ImportLibrary.empty()) {
       outpathImp = this->GeneratorTarget->GetDirectory(
         this->ConfigName, cmStateEnums::ImportLibraryArtifact);
       cmSystemTools::MakeDirectory(outpathImp);
@@ -348,10 +342,10 @@
   cmSystemTools::MakeDirectory(pdbOutputPath);
   pdbOutputPath += "/";
 
-  std::string targetFullPath = outpath + targetName;
-  std::string targetFullPathReal = outpath + targetNameReal;
-  std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
-  std::string targetFullPathImport = outpathImp + targetNameImport;
+  std::string targetFullPath = outpath + targetNames.Output;
+  std::string targetFullPathReal = outpath + targetNames.Real;
+  std::string targetFullPathPDB = pdbOutputPath + targetNames.PDB;
+  std::string targetFullPathImport = outpathImp + targetNames.ImportLibrary;
   std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
     targetFullPathPDB, cmOutputConverter::SHELL);
   // Convert to the output path to use in constructing commands.
@@ -376,8 +370,8 @@
 
   // Make sure we have a link language.
   if (linkLanguage.empty()) {
-    cmSystemTools::Error("Cannot determine link language for target \"",
-                         this->GeneratorTarget->GetName().c_str(), "\".");
+    cmSystemTools::Error("Cannot determine link language for target \"" +
+                         this->GeneratorTarget->GetName() + "\".");
     return;
   }
 
@@ -468,11 +462,11 @@
     this->LocalGenerator->GetCurrentBinaryDirectory(),
     targetFullPath + ".manifest"));
 #endif
-  if (targetNameReal != targetName) {
+  if (this->TargetNames.Real != this->TargetNames.Output) {
     exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
       this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
   }
-  if (!targetNameImport.empty()) {
+  if (!this->TargetNames.ImportLibrary.empty()) {
     exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
       this->LocalGenerator->GetCurrentBinaryDirectory(),
       targetFullPathImport));
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 5a1ef4e..44e6547 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -32,9 +32,8 @@
 {
   this->CustomCommandDriver = OnDepends;
   if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
-    this->GeneratorTarget->GetLibraryNames(
-      this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
-      this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
+    this->TargetNames =
+      this->GeneratorTarget->GetLibraryNames(this->ConfigName);
   }
 
   this->OSXBundleGenerator =
@@ -463,8 +462,8 @@
 
   // Make sure we have a link language.
   if (linkLanguage.empty()) {
-    cmSystemTools::Error("Cannot determine link language for target \"",
-                         this->GeneratorTarget->GetName().c_str(), "\".");
+    cmSystemTools::Error("Cannot determine link language for target \"" +
+                         this->GeneratorTarget->GetName() + "\".");
     return;
   }
 
@@ -489,25 +488,20 @@
   }
 
   // Construct the name of the library.
-  std::string targetName;
-  std::string targetNameSO;
-  std::string targetNameReal;
-  std::string targetNameImport;
-  std::string targetNamePDB;
-  this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
-                                         targetNameReal, targetNameImport,
-                                         targetNamePDB, this->ConfigName);
+  this->GeneratorTarget->GetLibraryNames(this->ConfigName);
 
   // Construct the full path version of the names.
   std::string outpath;
   std::string outpathImp;
   if (this->GeneratorTarget->IsFrameworkOnApple()) {
     outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
-    this->OSXBundleGenerator->CreateFramework(targetName, outpath);
+    this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
+                                              outpath);
     outpath += "/";
   } else if (this->GeneratorTarget->IsCFBundleOnApple()) {
     outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
-    this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
+    this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
+                                             outpath);
     outpath += "/";
   } else if (relink) {
     outpath = this->Makefile->GetCurrentBinaryDirectory();
@@ -515,14 +509,14 @@
     outpath += "/CMakeRelink.dir";
     cmSystemTools::MakeDirectory(outpath);
     outpath += "/";
-    if (!targetNameImport.empty()) {
+    if (!this->TargetNames.ImportLibrary.empty()) {
       outpathImp = outpath;
     }
   } else {
     outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
     cmSystemTools::MakeDirectory(outpath);
     outpath += "/";
-    if (!targetNameImport.empty()) {
+    if (!this->TargetNames.ImportLibrary.empty()) {
       outpathImp = this->GeneratorTarget->GetDirectory(
         this->ConfigName, cmStateEnums::ImportLibraryArtifact);
       cmSystemTools::MakeDirectory(outpathImp);
@@ -539,11 +533,12 @@
   cmSystemTools::MakeDirectory(pdbOutputPath);
   pdbOutputPath += "/";
 
-  std::string targetFullPath = outpath + targetName;
-  std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
-  std::string targetFullPathSO = outpath + targetNameSO;
-  std::string targetFullPathReal = outpath + targetNameReal;
-  std::string targetFullPathImport = outpathImp + targetNameImport;
+  std::string targetFullPath = outpath + this->TargetNames.Output;
+  std::string targetFullPathPDB = pdbOutputPath + this->TargetNames.PDB;
+  std::string targetFullPathSO = outpath + this->TargetNames.SharedObject;
+  std::string targetFullPathReal = outpath + this->TargetNames.Real;
+  std::string targetFullPathImport =
+    outpathImp + this->TargetNames.ImportLibrary;
 
   // Construct the output path version of the names for use in command
   // arguments.
@@ -616,15 +611,16 @@
     commands1.clear();
   }
 
-  if (targetName != targetNameReal) {
+  if (this->TargetNames.Output != this->TargetNames.Real) {
     libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
       this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
   }
-  if (targetNameSO != targetNameReal && targetNameSO != targetName) {
+  if (this->TargetNames.SharedObject != this->TargetNames.Real &&
+      this->TargetNames.SharedObject != this->TargetNames.Output) {
     libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
       this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO));
   }
-  if (!targetNameImport.empty()) {
+  if (!this->TargetNames.ImportLibrary.empty()) {
     libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
       this->LocalGenerator->GetCurrentBinaryDirectory(),
       targetFullPathImport));
@@ -820,7 +816,7 @@
     vars.ObjectsQuoted = buildObjs.c_str();
     if (this->GeneratorTarget->HasSOName(this->ConfigName)) {
       vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
-      vars.TargetSOName = targetNameSO.c_str();
+      vars.TargetSOName = this->TargetNames.SharedObject.c_str();
     }
     vars.LinkFlags = linkFlags.c_str();
 
@@ -981,10 +977,11 @@
 
   // Compute the list of outputs.
   std::vector<std::string> outputs(1, targetFullPathReal);
-  if (targetNameSO != targetNameReal) {
+  if (this->TargetNames.SharedObject != this->TargetNames.Real) {
     outputs.push_back(targetFullPathSO);
   }
-  if (targetName != targetNameSO && targetName != targetNameReal) {
+  if (this->TargetNames.Output != this->TargetNames.SharedObject &&
+      this->TargetNames.Output != this->TargetNames.Real) {
     outputs.push_back(targetFullPath);
   }
 
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index af34169..340e405 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -21,6 +21,7 @@
 #include "cmMakefileLibraryTargetGenerator.h"
 #include "cmMakefileUtilityTargetGenerator.h"
 #include "cmOutputConverter.h"
+#include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
@@ -654,19 +655,20 @@
       std::string cmdVar;
       if (this->GeneratorTarget->GetPropertyAsBool(
             "CUDA_SEPARABLE_COMPILATION")) {
-        cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+        cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
       } else if (this->GeneratorTarget->GetPropertyAsBool(
                    "CUDA_PTX_COMPILATION")) {
-        cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+        cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
       } else {
-        cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+        cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
       }
-      std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar);
+      const std::string& compileRule =
+        this->Makefile->GetRequiredDefinition(cmdVar);
       cmSystemTools::ExpandListArgument(compileRule, compileCommands);
     } else {
-      const std::string cmdVar =
-        std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
-      std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar);
+      const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+      const std::string& compileRule =
+        this->Makefile->GetRequiredDefinition(cmdVar);
       cmSystemTools::ExpandListArgument(compileRule, compileCommands);
     }
 
@@ -974,18 +976,17 @@
   // For multiple outputs, make the extra ones depend on the first one.
   std::vector<std::string> const output_depends(1, outputs[0]);
   std::string binDir = this->LocalGenerator->GetBinaryDirectory();
-  for (std::vector<std::string>::const_iterator o = outputs.begin() + 1;
-       o != outputs.end(); ++o) {
+  for (std::string const& output : cmMakeRange(outputs).advance(1)) {
     // Touch the extra output so "make" knows that it was updated,
     // but only if the output was actually created.
     std::string const out = this->LocalGenerator->ConvertToOutputFormat(
-      this->LocalGenerator->MaybeConvertToRelativePath(binDir, *o),
+      this->LocalGenerator->MaybeConvertToRelativePath(binDir, output),
       cmOutputConverter::SHELL);
     std::vector<std::string> output_commands;
 
     bool o_symbolic = false;
     if (need_symbolic) {
-      if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
+      if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
         o_symbolic = sf->GetPropertyAsBool("SYMBOLIC");
       }
     }
@@ -994,13 +995,13 @@
     if (!o_symbolic) {
       output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
     }
-    this->LocalGenerator->WriteMakeRule(os, nullptr, *o, output_depends,
+    this->LocalGenerator->WriteMakeRule(os, nullptr, output, output_depends,
                                         output_commands, o_symbolic, in_help);
 
     if (!o_symbolic) {
       // At build time, remove the first output if this one does not exist
       // so that "make" will rerun the real commands that create this one.
-      MultipleOutputPairsType::value_type p(*o, outputs[0]);
+      MultipleOutputPairsType::value_type p(output, outputs[0]);
       this->MultipleOutputPairs.insert(p);
     }
   }
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index 529b4db..c053d5b 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -12,12 +12,12 @@
 #include <vector>
 
 #include "cmCommonTargetGenerator.h"
+#include "cmGeneratorTarget.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmOSXBundleGenerator.h"
 
 class cmCustomCommandGenerator;
 class cmGeneratedFileStream;
-class cmGeneratorTarget;
 class cmGlobalUnixMakefileGenerator3;
 class cmLinkLineComputer;
 class cmOutputConverter;
@@ -231,11 +231,7 @@
                      bool in_help = false);
 
   // Target name info.
-  std::string TargetNameOut;
-  std::string TargetNameSO;
-  std::string TargetNameReal;
-  std::string TargetNameImport;
-  std::string TargetNamePDB;
+  cmGeneratorTarget::Names TargetNames;
 
   // macOS content info.
   std::set<std::string> MacContentFolders;
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 95f5fcb..2724030 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -6,6 +6,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmMessenger.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 
 class cmExecutionStatus;
@@ -68,7 +69,7 @@
     m->DisplayMessage(type, message, this->Makefile->GetBacktrace());
   } else {
     if (status) {
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     } else {
       cmSystemTools::Message(message);
     }
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index cbc0103..3300fef 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include "cmAlgorithms.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
 #include "cmCustomCommandGenerator.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
@@ -32,8 +33,6 @@
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 
-class cmCustomCommand;
-
 cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
   cmGeneratorTarget* target)
   : cmNinjaTargetGenerator(target)
@@ -41,13 +40,10 @@
 {
   this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
   if (target->GetType() == cmStateEnums::EXECUTABLE) {
-    this->GetGeneratorTarget()->GetExecutableNames(
-      this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
-      this->TargetNamePDB, GetLocalGenerator()->GetConfigName());
+    this->TargetNames = this->GetGeneratorTarget()->GetExecutableNames(
+      GetLocalGenerator()->GetConfigName());
   } else {
-    this->GetGeneratorTarget()->GetLibraryNames(
-      this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
-      this->TargetNameImport, this->TargetNamePDB,
+    this->TargetNames = this->GetGeneratorTarget()->GetLibraryNames(
       GetLocalGenerator()->GetConfigName());
   }
 
@@ -71,8 +67,8 @@
 {
   if (this->TargetLinkLanguage.empty()) {
     cmSystemTools::Error("CMake can not determine linker language for "
-                         "target: ",
-                         this->GetGeneratorTarget()->GetName().c_str());
+                         "target: " +
+                         this->GetGeneratorTarget()->GetName());
     return;
   }
 
@@ -286,6 +282,11 @@
       cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
 
     vars.Language = this->TargetLinkLanguage.c_str();
+    if (this->TargetLinkLanguage == "Swift") {
+      vars.SwiftPartialModules = "$SWIFT_PARTIAL_MODULES";
+      vars.TargetSwiftModule = "$TARGET_SWIFT_MODULE";
+      vars.TargetSwiftDoc = "$TARGET_SWIFT_DOC";
+    }
 
     std::string responseFlag;
     if (!useResponseFile) {
@@ -395,7 +396,7 @@
                                         /*generator*/ false);
   }
 
-  if (this->TargetNameOut != this->TargetNameReal &&
+  if (this->TargetNames.Output != this->TargetNames.Real &&
       !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
     std::string cmakeCommand =
       this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -676,7 +677,7 @@
   if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
     vars["SONAME_FLAG"] =
       this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
-    vars["SONAME"] = this->TargetNameSO;
+    vars["SONAME"] = this->TargetNames.SharedObject;
     if (targetType == cmStateEnums::SHARED_LIBRARY) {
       std::string install_dir =
         this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
@@ -687,7 +688,7 @@
     }
   }
 
-  if (!this->TargetNameImport.empty()) {
+  if (!this->TargetNames.ImportLibrary.empty()) {
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
@@ -749,24 +750,25 @@
   if (gt.IsAppBundleOnApple()) {
     // Create the app bundle
     std::string outpath = gt.GetDirectory(cfgName);
-    this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
+    this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output,
+                                              outpath);
 
     // Calculate the output path
     targetOutput = outpath;
     targetOutput += "/";
-    targetOutput += this->TargetNameOut;
+    targetOutput += this->TargetNames.Output;
     targetOutput = this->ConvertToNinjaPath(targetOutput);
     targetOutputReal = outpath;
     targetOutputReal += "/";
-    targetOutputReal += this->TargetNameReal;
+    targetOutputReal += this->TargetNames.Real;
     targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
   } else if (gt.IsFrameworkOnApple()) {
     // Create the library framework.
-    this->OSXBundleGenerator->CreateFramework(this->TargetNameOut,
+    this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
                                               gt.GetDirectory(cfgName));
   } else if (gt.IsCFBundleOnApple()) {
     // Create the core foundation bundle.
-    this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut,
+    this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
                                              gt.GetDirectory(cfgName));
   }
 
@@ -789,6 +791,34 @@
   cmNinjaDeps outputs;
   outputs.push_back(targetOutputReal);
 
+  if (this->TargetLinkLanguage == "Swift") {
+    if (const char* name = gt.GetProperty("SWIFT_MODULE_NAME")) {
+      vars["TARGET_SWIFT_DOC"] = std::string(name) + ".swiftdoc";
+      vars["TARGET_SWIFT_MODULE"] = std::string(name) + ".swiftmodule";
+    } else {
+      vars["TARGET_SWIFT_DOC"] = gt.GetName() + ".swiftdoc";
+      vars["TARGET_SWIFT_MODULE"] = gt.GetName() + ".swiftmodule";
+    }
+    outputs.push_back(vars["TARGET_SWIFT_DOC"]);
+    outputs.push_back(vars["TARGET_SWIFT_MODULE"]);
+
+    cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
+
+    std::string partials;
+    std::vector<cmSourceFile const*> sources;
+    gt.GetObjectSources(sources, this->GetConfigName());
+    for (cmSourceFile const* source : sources) {
+      partials += " ";
+      if (const char* partial = source->GetProperty("SWIFT_PARTIAL_MODULE")) {
+        partials += partial;
+      } else {
+        partials += localGen.GetTargetDirectory(&gt) + "/" +
+          gt.GetObjectName(source) + ".swiftmodule";
+      }
+    }
+    vars["SWIFT_PARTIAL_MODULES"] = partials;
+  }
+
   // Compute specific libraries to link with.
   cmNinjaDeps explicitDeps = this->GetObjects();
   cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
@@ -801,10 +831,9 @@
 
   std::string frameworkPath;
   std::string linkPath;
-  cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
 
-  std::string createRule = genTarget.GetCreateRuleVariable(
-    this->TargetLinkLanguage, this->GetConfigName());
+  std::string createRule =
+    gt.GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName());
   bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
   cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
 
@@ -817,9 +846,9 @@
       this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()));
   linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
 
-  localGen.GetTargetFlags(
-    linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
-    vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
+  localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(),
+                          vars["LINK_LIBRARIES"], vars["FLAGS"],
+                          vars["LINK_FLAGS"], frameworkPath, linkPath, &gt);
 
   // Add OS X version flags, if any.
   if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
@@ -840,7 +869,7 @@
 
   vars["LINK_PATH"] = frameworkPath + linkPath;
   std::string lwyuFlags;
-  if (genTarget.GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+  if (gt.GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
     lwyuFlags = " -Wl,--no-as-needed";
   }
 
@@ -849,22 +878,21 @@
   // code between the Makefile executable and library generators.
   if (targetType == cmStateEnums::EXECUTABLE) {
     std::string t = vars["FLAGS"];
-    localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+    localGen.AddArchitectureFlags(t, &gt, TargetLinkLanguage, cfgName);
     t += lwyuFlags;
     vars["FLAGS"] = t;
   } else {
     std::string t = vars["ARCH_FLAGS"];
-    localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+    localGen.AddArchitectureFlags(t, &gt, TargetLinkLanguage, cfgName);
     vars["ARCH_FLAGS"] = t;
     t.clear();
     t += lwyuFlags;
-    localGen.AddLanguageFlagsForLinking(t, &genTarget, TargetLinkLanguage,
-                                        cfgName);
+    localGen.AddLanguageFlagsForLinking(t, &gt, TargetLinkLanguage, cfgName);
     vars["LANGUAGE_COMPILE_FLAGS"] = t;
   }
   if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
     vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
-    vars["SONAME"] = this->TargetNameSO;
+    vars["SONAME"] = this->TargetNames.SharedObject;
     if (targetType == cmStateEnums::SHARED_LIBRARY) {
       std::string install_dir =
         this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
@@ -877,12 +905,12 @@
 
   cmNinjaDeps byproducts;
 
-  if (!this->TargetNameImport.empty()) {
+  if (!this->TargetNames.ImportLibrary.empty()) {
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
     EnsureParentDirectoryExists(impLibPath);
-    if (genTarget.HasImportLibrary(cfgName)) {
+    if (gt.HasImportLibrary(cfgName)) {
       byproducts.push_back(targetOutputImplib);
     }
   }
@@ -1037,8 +1065,8 @@
         emptyDeps, emptyDeps, symlinkVars);
     } else {
       cmNinjaDeps symlinks;
-      std::string const soName =
-        this->ConvertToNinjaPath(this->GetTargetFilePath(this->TargetNameSO));
+      std::string const soName = this->ConvertToNinjaPath(
+        this->GetTargetFilePath(this->TargetNames.SharedObject));
       // If one link has to be created.
       if (targetOutputReal == soName || targetOutput == soName) {
         symlinkVars["SONAME"] = soName;
@@ -1056,7 +1084,7 @@
   }
 
   // Add aliases for the file name and the target name.
-  globalGen.AddTargetAlias(this->TargetNameOut, &gt);
+  globalGen.AddTargetAlias(this->TargetNames.Output, &gt);
   globalGen.AddTargetAlias(this->GetTargetName(), &gt);
 }
 
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index 01cc881..14991a2 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -5,13 +5,12 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include "cmGeneratorTarget.h"
 #include "cmNinjaTargetGenerator.h"
 
 #include <string>
 #include <vector>
 
-class cmGeneratorTarget;
-
 class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
 {
 public:
@@ -40,11 +39,7 @@
 
 private:
   // Target name info.
-  std::string TargetNameOut;
-  std::string TargetNameSO;
-  std::string TargetNameReal;
-  std::string TargetNameImport;
-  std::string TargetNamePDB;
+  cmGeneratorTarget::Names TargetNames;
   std::string TargetLinkLanguage;
   std::string DeviceLinkObject;
 };
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 82bc5f2..1ad26dd 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -102,6 +102,12 @@
   return lang == "Fortran";
 }
 
+bool cmNinjaTargetGenerator::UsePreprocessedSource(
+  std::string const& lang) const
+{
+  return lang == "Fortran";
+}
+
 std::string cmNinjaTargetGenerator::LanguageDyndepRule(
   const std::string& lang) const
 {
@@ -454,6 +460,9 @@
   if (lang == "Swift") {
     vars.SwiftAuxiliarySources = "$SWIFT_AUXILIARY_SOURCES";
     vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
+    vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
+    vars.SwiftPartialModule = "$SWIFT_PARTIAL_MODULE";
+    vars.SwiftPartialDoc = "$SWIFT_PARTIAL_DOC";
   }
 
   // For some cases we do an explicit preprocessor invocation.
@@ -493,7 +502,7 @@
   if (explicitPP) {
     // Lookup the explicit preprocessing rule.
     std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
-    std::string const ppCmd =
+    std::string const& ppCmd =
       this->GetMakefile()->GetRequiredDefinition(ppVar);
 
     // Explicit preprocessing always uses a depfile.
@@ -555,7 +564,7 @@
       cmake +
       " -E cmake_ninja_depends"
       " --tdi=" +
-      tdi +
+      tdi + " --lang=" + lang +
       " --pp=$out"
       " --dep=$DEP_FILE" +
       (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
@@ -585,13 +594,14 @@
     std::string ddRspContent = "$in";
     std::string ddInput = "@" + ddRspFile;
 
-    // Run CMake dependency scanner on preprocessed output.
+    // Run CMake dependency scanner on the source file (using the preprocessed
+    // source if that was performed).
     std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
     ddCmds.push_back(cmake +
                      " -E cmake_ninja_dyndep"
                      " --tdi=" +
-                     tdi +
+                     tdi + " --lang=" + lang +
                      " --dd=$out"
                      " " +
                      ddInput);
@@ -671,19 +681,18 @@
     std::string cmdVar;
     if (this->GeneratorTarget->GetPropertyAsBool(
           "CUDA_SEPARABLE_COMPILATION")) {
-      cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+      cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
     } else if (this->GeneratorTarget->GetPropertyAsBool(
                  "CUDA_PTX_COMPILATION")) {
-      cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+      cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
     } else {
-      cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+      cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
     }
-    std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+    const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
   } else {
-    const std::string cmdVar =
-      std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
-    std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+    const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+    const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
   }
 
@@ -866,24 +875,27 @@
     this->WriteObjectBuildStatement(sf);
   }
 
-  if (!this->DDIFiles.empty()) {
+  for (auto const& langDDIFiles : this->DDIFiles) {
+    std::string const& language = langDDIFiles.first;
+    cmNinjaDeps const& ddiFiles = langDDIFiles.second;
+
     std::string const ddComment;
-    std::string const ddRule = this->LanguageDyndepRule("Fortran");
+    std::string const ddRule = this->LanguageDyndepRule(language);
     cmNinjaDeps ddOutputs;
     cmNinjaDeps ddImplicitOuts;
-    cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
+    cmNinjaDeps const& ddExplicitDeps = ddiFiles;
     cmNinjaDeps ddImplicitDeps;
     cmNinjaDeps ddOrderOnlyDeps;
     cmNinjaVars ddVars;
 
-    this->WriteTargetDependInfo("Fortran");
+    this->WriteTargetDependInfo(language);
 
-    ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
+    ddOutputs.push_back(this->GetDyndepFilePath(language));
 
     // Make sure dyndep files for all our dependencies have already
-    // been generated so that the 'FortranModules.json' files they
+    // been generated so that the '<LANG>Modules.json' files they
     // produced as side-effects are available for us to read.
-    // Ideally we should depend on the 'FortranModules.json' files
+    // Ideally we should depend on the '<LANG>Modules.json' files
     // from our dependencies directly, but we don't know which of
     // our dependencies produces them.  Fixing this will require
     // refactoring the Ninja generator to generate targets in
@@ -941,6 +953,22 @@
     } else {
       vars["SWIFT_MODULE_NAME"] = this->GeneratorTarget->GetName();
     }
+
+    cmGeneratorTarget::Names targetNames =
+      this->GeneratorTarget->GetLibraryNames(this->GetConfigName());
+    vars["SWIFT_LIBRARY_NAME"] = targetNames.Base;
+
+    if (const char* partial = source->GetProperty("SWIFT_PARTIAL_MODULE")) {
+      vars["SWIFT_PARTIAL_MODULE"] = partial;
+    } else {
+      vars["SWIFT_PARTIAL_MODULE"] = objectFileName + ".swiftmodule";
+    }
+
+    if (const char* partial = source->GetProperty("SWIFT_PARTIAL_DOC")) {
+      vars["SWIFT_PARTIAL_DOC"] = partial;
+    } else {
+      vars["SWIFT_PARTIAL_DOC"] = objectFileName + ".swiftdoc";
+    }
   }
 
   if (!this->NeedDepTypeMSVC(language)) {
@@ -1014,6 +1042,7 @@
   // For some cases we do an explicit preprocessor invocation.
   bool const explicitPP = this->NeedExplicitPreprocessing(language);
   if (explicitPP) {
+    bool const compilePP = this->UsePreprocessedSource(language);
     std::string const ppComment;
     std::string const ppRule = this->LanguagePreprocessRule(language);
     cmNinjaDeps ppOutputs;
@@ -1027,61 +1056,80 @@
       this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
     ppOutputs.push_back(ppFileName);
 
-    // Move compilation dependencies to the preprocessing build statement.
-    std::swap(ppExplicitDeps, explicitDeps);
-    std::swap(ppImplicitDeps, implicitDeps);
-    std::swap(ppOrderOnlyDeps, orderOnlyDeps);
-    std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
+    if (compilePP) {
+      // Move compilation dependencies to the preprocessing build statement.
+      std::swap(ppExplicitDeps, explicitDeps);
+      std::swap(ppImplicitDeps, implicitDeps);
+      std::swap(ppOrderOnlyDeps, orderOnlyDeps);
+      std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
 
-    // The actual compilation will now use the preprocessed source.
-    explicitDeps.push_back(ppFileName);
+      // The actual compilation will now use the preprocessed source.
+      explicitDeps.push_back(ppFileName);
+    } else {
+      // Copy compilation dependencies to the preprocessing build statement.
+      ppExplicitDeps = explicitDeps;
+      ppImplicitDeps = implicitDeps;
+      ppOrderOnlyDeps = orderOnlyDeps;
+      ppVars["IN_ABS"] = vars["IN_ABS"];
+    }
 
     // Preprocessing and compilation generally use the same flags.
     ppVars["FLAGS"] = vars["FLAGS"];
 
-    // In case compilation requires flags that are incompatible with
-    // preprocessing, include them here.
-    std::string const postFlag =
-      this->Makefile->GetSafeDefinition("CMAKE_Fortran_POSTPROCESS_FLAG");
-    this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+    if (compilePP) {
+      // In case compilation requires flags that are incompatible with
+      // preprocessing, include them here.
+      std::string const postFlag = this->Makefile->GetSafeDefinition(
+        "CMAKE_" + language + "_POSTPROCESS_FLAG");
+      this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+    }
 
-    // Move preprocessor definitions to the preprocessor build statement.
-    std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+    if (compilePP) {
+      // Move preprocessor definitions to the preprocessor build statement.
+      std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+    } else {
+      // Copy preprocessor definitions to the preprocessor build statement.
+      ppVars["DEFINES"] = vars["DEFINES"];
+    }
 
     // Copy include directories to the preprocessor build statement.  The
     // Fortran compilation build statement still needs them for the INCLUDE
     // directive.
     ppVars["INCLUDES"] = vars["INCLUDES"];
 
-    // Prepend source file's original directory as an include directory
-    // so e.g. Fortran INCLUDE statements can look for files in it.
-    std::vector<std::string> sourceDirectory;
-    sourceDirectory.push_back(
-      cmSystemTools::GetParentDirectory(source->GetFullPath()));
+    if (compilePP) {
+      // Prepend source file's original directory as an include directory
+      // so e.g. Fortran INCLUDE statements can look for files in it.
+      std::vector<std::string> sourceDirectory;
+      sourceDirectory.push_back(
+        cmSystemTools::GetParentDirectory(source->GetFullPath()));
 
-    std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
-      sourceDirectory, this->GeneratorTarget, language, false, false,
-      this->GetConfigName());
+      std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
+        sourceDirectory, this->GeneratorTarget, language, false, false,
+        this->GetConfigName());
 
-    vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+      vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+    }
 
     // Explicit preprocessing always uses a depfile.
     ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-      ppFileName + ".d", cmOutputConverter::SHELL);
-    // The actual compilation does not need a depfile because it
-    // depends on the already-preprocessed source.
-    vars.erase("DEP_FILE");
+      objectFileName + ".pp.d", cmOutputConverter::SHELL);
+    if (compilePP) {
+      // The actual compilation does not need a depfile because it
+      // depends on the already-preprocessed source.
+      vars.erase("DEP_FILE");
+    }
 
     if (needDyndep) {
       // Tell dependency scanner the object file that will result from
-      // compiling the preprocessed source.
+      // compiling the source.
       ppVars["OBJ_FILE"] = objectFileName;
 
       // Tell dependency scanner where to store dyndep intermediate results.
-      std::string const ddiFile = ppFileName + ".ddi";
+      std::string const ddiFile = objectFileName + ".ddi";
       ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
       ppImplicitOuts.push_back(ddiFile);
-      this->DDIFiles.push_back(ddiFile);
+      this->DDIFiles[language].push_back(ddiFile);
     }
 
     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
@@ -1217,20 +1265,19 @@
     std::string cmdVar;
     if (this->GeneratorTarget->GetPropertyAsBool(
           "CUDA_SEPARABLE_COMPILATION")) {
-      cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+      cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
     } else if (this->GeneratorTarget->GetPropertyAsBool(
                  "CUDA_PTX_COMPILATION")) {
-      cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+      cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
     } else {
-      cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+      cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
     }
-    std::string compileCmd =
+    const std::string& compileCmd =
       this->GetMakefile()->GetRequiredDefinition(cmdVar);
     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
   } else {
-    const std::string cmdVar =
-      std::string("CMAKE_") + language + "_COMPILE_OBJECT";
-    std::string compileCmd =
+    const std::string cmdVar = "CMAKE_" + language + "_COMPILE_OBJECT";
+    const std::string& compileCmd =
       this->GetMakefile()->GetRequiredDefinition(cmdVar);
     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
   }
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 373c693..6a42da0 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -10,6 +10,7 @@
 #include "cmNinjaTypes.h"
 #include "cmOSXBundleGenerator.h"
 
+#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -64,6 +65,7 @@
   bool NeedExplicitPreprocessing(std::string const& lang) const;
   std::string LanguageDyndepRule(std::string const& lang) const;
   bool NeedDyndep(std::string const& lang) const;
+  bool UsePreprocessedSource(std::string const& lang) const;
 
   std::string OrderDependsTargetForTarget();
 
@@ -165,7 +167,7 @@
   cmLocalNinjaGenerator* LocalGenerator;
   /// List of object files for this target.
   cmNinjaDeps Objects;
-  cmNinjaDeps DDIFiles; // TODO: Make per-language.
+  std::map<std::string, cmNinjaDeps> DDIFiles;
   std::vector<cmCustomCommand const*> CustomCommands;
   cmNinjaDeps ExtraFiles;
 };
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index 6857d5a..47a8df4 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -54,8 +54,7 @@
   plist += this->GT->GetAppBundleDirectory(this->ConfigName,
                                            cmGeneratorTarget::ContentLevel);
   plist += "/Info.plist";
-  this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName,
-                                               plist.c_str());
+  this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName, plist);
   this->Makefile->AddCMakeOutputFile(plist);
   outpath = out;
 }
@@ -90,8 +89,7 @@
   }
   plist += "/Info.plist";
   std::string name = cmSystemTools::GetFilenameName(targetName);
-  this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name,
-                                                   plist.c_str());
+  this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist);
 
   // Generate Versions directory only for MacOSX frameworks
   if (this->Makefile->PlatformIsAppleEmbedded()) {
@@ -184,7 +182,7 @@
                                    cmGeneratorTarget::ContentLevel);
   plist += "/Info.plist";
   std::string name = cmSystemTools::GetFilenameName(targetName);
-  this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist.c_str());
+  this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist);
   this->Makefile->AddCMakeOutputFile(plist);
 }
 
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
index 5916f7a..23e61d6 100644
--- a/Source/cmOrderDirectories.h
+++ b/Source/cmOrderDirectories.h
@@ -25,6 +25,8 @@
   cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target,
                      const char* purpose);
   ~cmOrderDirectories();
+  cmOrderDirectories(const cmOrderDirectories&) = delete;
+  cmOrderDirectories& operator=(const cmOrderDirectories&) = delete;
   void AddRuntimeLibrary(std::string const& fullPath,
                          const char* soname = nullptr);
   void AddLinkLibrary(std::string const& fullPath);
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
index 6438c7b..deca767 100644
--- a/Source/cmOutputConverter.h
+++ b/Source/cmOutputConverter.h
@@ -27,7 +27,7 @@
   std::string ConvertDirectorySeparatorsForShell(
     const std::string& source) const;
 
-  ///! for existing files convert to output path and short path if spaces
+  //! for existing files convert to output path and short path if spaces
   std::string ConvertToOutputForExisting(const std::string& remote,
                                          OutputFormat format = SHELL) const;
 
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
index 46d04a6..cb9433f 100644
--- a/Source/cmOutputRequiredFilesCommand.cxx
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -92,6 +92,9 @@
    */
   ~cmLBDepend() { cmDeleteAll(this->DependInformationMap); }
 
+  cmLBDepend(const cmLBDepend&) = delete;
+  cmLBDepend& operator=(const cmLBDepend&) = delete;
+
   /**
    * Set the makefile that is used as a source of classes.
    */
@@ -163,7 +166,7 @@
   {
     cmsys::ifstream fin(info->FullPath.c_str());
     if (!fin) {
-      cmSystemTools::Error("error can not open ", info->FullPath.c_str());
+      cmSystemTools::Error("error can not open " + info->FullPath);
       return;
     }
 
@@ -178,7 +181,7 @@
           qstart = line.find('<', 8);
           // if a < is not found then move on
           if (qstart == std::string::npos) {
-            cmSystemTools::Error("unknown include directive ", line.c_str());
+            cmSystemTools::Error("unknown include directive " + line);
             continue;
           }
           qend = line.find('>', qstart + 1);
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 796974c..5213432 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -8,13 +8,16 @@
 #include <utility>
 
 #include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
+#include "cm_string_view.hxx"
 
 class cmExecutionStatus;
 
-static std::string escape_arg(const std::string& arg)
+static std::string EscapeArg(const std::string& arg)
 {
   // replace ";" with "\;" so output argument lists will split correctly
   std::string escapedArg;
@@ -27,6 +30,82 @@
   return escapedArg;
 }
 
+static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+{
+  return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
+                : cmJoin(cmMakeRange(arg), ";");
+}
+
+namespace {
+
+typedef std::map<std::string, bool> options_map;
+typedef std::map<std::string, std::string> single_map;
+typedef std::map<std::string, std::vector<std::string>> multi_map;
+typedef std::set<std::string> options_set;
+
+struct UserArgumentParser : public cmArgumentParser<void>
+{
+  template <typename T, typename H>
+  void Bind(std::vector<std::string> const& names,
+            std::map<std::string, T>& ref, H duplicateKey)
+  {
+    for (std::string const& key : names) {
+      auto const it = ref.emplace(key, T{}).first;
+      bool const inserted = this->cmArgumentParser<void>::Bind(
+        cm::string_view(it->first), it->second);
+      if (!inserted) {
+        duplicateKey(key);
+      }
+    }
+  }
+};
+
+} // namespace
+
+static void PassParsedArguments(
+  const std::string& prefix, cmMakefile& makefile, const options_map& options,
+  const single_map& singleValArgs, const multi_map& multiValArgs,
+  const std::vector<std::string>& unparsed,
+  const options_set& keywordsMissingValues, bool parseFromArgV)
+{
+  for (auto const& iter : options) {
+    makefile.AddDefinition(prefix + iter.first,
+                           iter.second ? "TRUE" : "FALSE");
+  }
+
+  for (auto const& iter : singleValArgs) {
+    if (!iter.second.empty()) {
+      makefile.AddDefinition(prefix + iter.first, iter.second.c_str());
+    } else {
+      makefile.RemoveDefinition(prefix + iter.first);
+    }
+  }
+
+  for (auto const& iter : multiValArgs) {
+    if (!iter.second.empty()) {
+      makefile.AddDefinition(prefix + iter.first,
+                             JoinList(iter.second, parseFromArgV).c_str());
+    } else {
+      makefile.RemoveDefinition(prefix + iter.first);
+    }
+  }
+
+  if (!unparsed.empty()) {
+    makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
+                           JoinList(unparsed, parseFromArgV).c_str());
+  } else {
+    makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
+  }
+
+  if (!keywordsMissingValues.empty()) {
+    makefile.AddDefinition(
+      prefix + "KEYWORDS_MISSING_VALUES",
+      cmJoin(cmMakeRange(keywordsMissingValues), ";").c_str());
+  } else {
+    makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
+  }
+}
+
 bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
                                           cmExecutionStatus&)
 {
@@ -65,11 +144,10 @@
   // the first argument is the prefix
   const std::string prefix = (*argIter++) + "_";
 
+  UserArgumentParser parser;
+
   // define the result maps holding key/value pairs for
   // options, single values and multi values
-  typedef std::map<std::string, bool> options_map;
-  typedef std::map<std::string, std::string> single_map;
-  typedef std::map<std::string, std::vector<std::string>> multi_map;
   options_map options;
   single_map singleValArgs;
   multi_map multiValArgs;
@@ -77,50 +155,25 @@
   // anything else is put into a vector of unparsed strings
   std::vector<std::string> unparsed;
 
-  // remember already defined keywords
-  std::set<std::string> used_keywords;
-  const std::string dup_warning = "keyword defined more than once: ";
+  auto const duplicateKey = [this](std::string const& key) {
+    this->GetMakefile()->IssueMessage(
+      MessageType::WARNING, "keyword defined more than once: " + key);
+  };
 
   // the second argument is a (cmake) list of options without argument
   std::vector<std::string> list;
   cmSystemTools::ExpandListArgument(*argIter++, list);
-  for (std::string const& iter : list) {
-    if (!used_keywords.insert(iter).second) {
-      this->GetMakefile()->IssueMessage(MessageType::WARNING,
-                                        dup_warning + iter);
-    }
-    options[iter]; // default initialize
-  }
+  parser.Bind(list, options, duplicateKey);
 
   // the third argument is a (cmake) list of single argument options
   list.clear();
   cmSystemTools::ExpandListArgument(*argIter++, list);
-  for (std::string const& iter : list) {
-    if (!used_keywords.insert(iter).second) {
-      this->GetMakefile()->IssueMessage(MessageType::WARNING,
-                                        dup_warning + iter);
-    }
-    singleValArgs[iter]; // default initialize
-  }
+  parser.Bind(list, singleValArgs, duplicateKey);
 
   // the fourth argument is a (cmake) list of multi argument options
   list.clear();
   cmSystemTools::ExpandListArgument(*argIter++, list);
-  for (std::string const& iter : list) {
-    if (!used_keywords.insert(iter).second) {
-      this->GetMakefile()->IssueMessage(MessageType::WARNING,
-                                        dup_warning + iter);
-    }
-    multiValArgs[iter]; // default initialize
-  }
-
-  enum insideValues
-  {
-    NONE,
-    SINGLE,
-    MULTI
-  } insideValues = NONE;
-  std::string currentArgName;
+  parser.Bind(list, multiValArgs, duplicateKey);
 
   list.clear();
   if (!parseFromArgV) {
@@ -155,81 +208,14 @@
     }
   }
 
-  // iterate over the arguments list and fill in the values where applicable
-  for (std::string const& arg : list) {
-    const options_map::iterator optIter = options.find(arg);
-    if (optIter != options.end()) {
-      insideValues = NONE;
-      optIter->second = true;
-      continue;
-    }
+  std::vector<std::string> keywordsMissingValues;
 
-    const single_map::iterator singleIter = singleValArgs.find(arg);
-    if (singleIter != singleValArgs.end()) {
-      insideValues = SINGLE;
-      currentArgName = arg;
-      continue;
-    }
+  parser.Parse(list, &unparsed, &keywordsMissingValues);
 
-    const multi_map::iterator multiIter = multiValArgs.find(arg);
-    if (multiIter != multiValArgs.end()) {
-      insideValues = MULTI;
-      currentArgName = arg;
-      continue;
-    }
-
-    switch (insideValues) {
-      case SINGLE:
-        singleValArgs[currentArgName] = arg;
-        insideValues = NONE;
-        break;
-      case MULTI:
-        if (parseFromArgV) {
-          multiValArgs[currentArgName].push_back(escape_arg(arg));
-        } else {
-          multiValArgs[currentArgName].push_back(arg);
-        }
-        break;
-      default:
-        if (parseFromArgV) {
-          unparsed.push_back(escape_arg(arg));
-        } else {
-          unparsed.push_back(arg);
-        }
-        break;
-    }
-  }
-
-  // now iterate over the collected values and update their definition
-  // within the current scope. undefine if necessary.
-
-  for (auto const& iter : options) {
-    this->Makefile->AddDefinition(prefix + iter.first,
-                                  iter.second ? "TRUE" : "FALSE");
-  }
-  for (auto const& iter : singleValArgs) {
-    if (!iter.second.empty()) {
-      this->Makefile->AddDefinition(prefix + iter.first, iter.second.c_str());
-    } else {
-      this->Makefile->RemoveDefinition(prefix + iter.first);
-    }
-  }
-
-  for (auto const& iter : multiValArgs) {
-    if (!iter.second.empty()) {
-      this->Makefile->AddDefinition(
-        prefix + iter.first, cmJoin(cmMakeRange(iter.second), ";").c_str());
-    } else {
-      this->Makefile->RemoveDefinition(prefix + iter.first);
-    }
-  }
-
-  if (!unparsed.empty()) {
-    this->Makefile->AddDefinition(prefix + "UNPARSED_ARGUMENTS",
-                                  cmJoin(cmMakeRange(unparsed), ";").c_str());
-  } else {
-    this->Makefile->RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
-  }
+  PassParsedArguments(
+    prefix, *this->Makefile, options, singleValArgs, multiValArgs, unparsed,
+    options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()),
+    parseFromArgV);
 
   return true;
 }
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 0a234c5..ec40136 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -145,7 +145,7 @@
   } else {
     std::ostringstream e;
     e << defaultVar << " has value \"" << defaultValue
-      << "\" but must be \"OLD\", \"NEW\", or \"\" (empty).";
+      << R"(" but must be "OLD", "NEW", or "" (empty).)";
     mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return false;
   }
@@ -299,7 +299,7 @@
   return stringToId(id, pid);
 }
 
-///! return a warning string for a given policy
+//! return a warning string for a given policy
 std::string cmPolicies::GetPolicyWarning(cmPolicies::PolicyID id)
 {
   std::ostringstream msg;
@@ -333,7 +333,7 @@
   return msg.str();
 }
 
-///! return an error string for when a required policy is unspecified
+//! return an error string for when a required policy is unspecified
 std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
 {
   std::ostringstream error;
@@ -359,7 +359,7 @@
   return error.str();
 }
 
-///! Get the default status for a policy
+//! Get the default status for a policy
 cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus(
   cmPolicies::PolicyID /*unused*/)
 {
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 314f27d..02a6295 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -261,7 +261,13 @@
          3, 14, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0088,                                                     \
          "FindBISON runs bison in CMAKE_CURRENT_BINARY_DIR when executing.",  \
-         3, 14, 0, cmPolicies::WARN)
+         3, 14, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0089,                                                     \
+         "Compiler id for IBM Clang-based XL compilers is now XLClang.", 3,   \
+         15, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0090,                                                     \
+         "export(PACKAGE) does not populate package registry by default.", 3, \
+         15, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -326,27 +332,27 @@
     CMPCOUNT
   };
 
-  ///! convert a string policy ID into a number
+  //! convert a string policy ID into a number
   static bool GetPolicyID(const char* id, /* out */ cmPolicies::PolicyID& pid);
 
-  ///! Get the default status for a policy
+  //! Get the default status for a policy
   static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
 
-  ///! Set a policy level for this listfile
+  //! Set a policy level for this listfile
   static bool ApplyPolicyVersion(cmMakefile* mf,
                                  std::string const& version_min,
                                  std::string const& version_max);
   static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer,
                                  unsigned int minorVer, unsigned int patchVer);
 
-  ///! return a warning string for a given policy
+  //! return a warning string for a given policy
   static std::string GetPolicyWarning(cmPolicies::PolicyID id);
   static std::string GetPolicyDeprecatedWarning(cmPolicies::PolicyID id);
 
-  ///! return an error string for when a required policy is unspecified
+  //! return an error string for when a required policy is unspecified
   static std::string GetRequiredPolicyError(cmPolicies::PolicyID id);
 
-  ///! return an error string for when a required policy is unspecified
+  //! return an error string for when a required policy is unspecified
   static std::string GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id);
 
   /** Represent a set of policy values.  */
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 2fe9fe8..8615ecc 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -25,6 +25,10 @@
     return false;
   }
 
+  if (!this->IncludeByVariable("CMAKE_PROJECT_INCLUDE_BEFORE")) {
+    return false;
+  }
+
   std::string const& projectName = args[0];
 
   this->Makefile->SetProjectName(projectName);
@@ -214,7 +218,7 @@
     }
 
     cmsys::RegularExpression vx(
-      "^([0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?)?$");
+      R"(^([0-9]+(\.[0-9]+(\.[0-9]+(\.[0-9]+)?)?)?)?$)");
     if (!vx.find(version)) {
       std::string e = "VERSION \"" + version + "\" format invalid.";
       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
@@ -319,21 +323,41 @@
     languages.emplace_back("CXX");
   }
   this->Makefile->EnableLanguage(languages, false);
-  std::string extraInclude = "CMAKE_PROJECT_" + projectName + "_INCLUDE";
-  const char* include = this->Makefile->GetDefinition(extraInclude);
-  if (include) {
-    bool readit = this->Makefile->ReadDependentFile(include);
-    if (!readit && !cmSystemTools::GetFatalErrorOccured()) {
-      std::string m = "could not find file:\n"
-                      "  ";
-      m += include;
-      this->SetError(m);
-      return false;
-    }
+
+  if (!this->IncludeByVariable("CMAKE_PROJECT_INCLUDE")) {
+    return false;
   }
+
+  if (!this->IncludeByVariable("CMAKE_PROJECT_" + projectName + "_INCLUDE")) {
+    return false;
+  }
+
   return true;
 }
 
+bool cmProjectCommand::IncludeByVariable(const std::string& variable)
+{
+  const char* include = this->Makefile->GetDefinition(variable);
+  if (!include) {
+    return true;
+  }
+
+  const bool readit = this->Makefile->ReadDependentFile(include);
+  if (readit) {
+    return true;
+  }
+
+  if (cmSystemTools::GetFatalErrorOccured()) {
+    return true;
+  }
+
+  std::string m = "could not find file:\n"
+                  "  ";
+  m += include;
+  this->SetError(m);
+  return false;
+}
+
 void cmProjectCommand::TopLevelCMakeVarCondSet(const char* const name,
                                                const char* const value)
 {
diff --git a/Source/cmProjectCommand.h b/Source/cmProjectCommand.h
index 365d448..f1d03e7 100644
--- a/Source/cmProjectCommand.h
+++ b/Source/cmProjectCommand.h
@@ -36,6 +36,7 @@
                    cmExecutionStatus& status) override;
 
 private:
+  bool IncludeByVariable(const std::string& variable);
   void TopLevelCMakeVarCondSet(const char* name, const char* value);
 };
 
diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx
index 6acc7ef..9a764c6 100644
--- a/Source/cmQTWrapCPPCommand.cxx
+++ b/Source/cmQTWrapCPPCommand.cxx
@@ -4,6 +4,7 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
 
@@ -29,13 +30,13 @@
   std::string sourceListValue = this->Makefile->GetSafeDefinition(sourceList);
 
   // Create a rule for all sources listed.
-  for (std::vector<std::string>::const_iterator j = (args.begin() + 2);
-       j != args.end(); ++j) {
-    cmSourceFile* curr = this->Makefile->GetSource(*j);
+  for (std::string const& arg : cmMakeRange(args).advance(2)) {
+    cmSourceFile* curr = this->Makefile->GetSource(arg);
     // if we should wrap the class
     if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
       // Compute the name of the file to generate.
-      std::string srcName = cmSystemTools::GetFilenameWithoutLastExtension(*j);
+      std::string srcName =
+        cmSystemTools::GetFilenameWithoutLastExtension(arg);
       std::string newName = this->Makefile->GetCurrentBinaryDirectory();
       newName += "/moc_";
       newName += srcName;
@@ -47,8 +48,8 @@
 
       // Compute the name of the header from which to generate the file.
       std::string hname;
-      if (cmSystemTools::FileIsFullPath(*j)) {
-        hname = *j;
+      if (cmSystemTools::FileIsFullPath(arg)) {
+        hname = arg;
       } else {
         if (curr && curr->GetIsGenerated()) {
           hname = this->Makefile->GetCurrentBinaryDirectory();
@@ -56,7 +57,7 @@
           hname = this->Makefile->GetCurrentSourceDirectory();
         }
         hname += "/";
-        hname += *j;
+        hname += arg;
       }
 
       // Append the generated source file to the list.
diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx
index 43b1fb9..2223e2d 100644
--- a/Source/cmQTWrapUICommand.cxx
+++ b/Source/cmQTWrapUICommand.cxx
@@ -4,6 +4,7 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
 
@@ -33,13 +34,13 @@
   std::string sourceListValue = this->Makefile->GetSafeDefinition(sourceList);
 
   // Create rules for all sources listed.
-  for (std::vector<std::string>::const_iterator j = (args.begin() + 3);
-       j != args.end(); ++j) {
-    cmSourceFile* curr = this->Makefile->GetSource(*j);
+  for (std::string const& arg : cmMakeRange(args).advance(3)) {
+    cmSourceFile* curr = this->Makefile->GetSource(arg);
     // if we should wrap the class
     if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
       // Compute the name of the files to generate.
-      std::string srcName = cmSystemTools::GetFilenameWithoutLastExtension(*j);
+      std::string srcName =
+        cmSystemTools::GetFilenameWithoutLastExtension(arg);
       std::string hName = this->Makefile->GetCurrentBinaryDirectory();
       hName += "/";
       hName += srcName;
@@ -55,8 +56,8 @@
 
       // Compute the name of the ui file from which to generate others.
       std::string uiName;
-      if (cmSystemTools::FileIsFullPath(*j)) {
-        uiName = *j;
+      if (cmSystemTools::FileIsFullPath(arg)) {
+        uiName = arg;
       } else {
         if (curr && curr->GetIsGenerated()) {
           uiName = this->Makefile->GetCurrentBinaryDirectory();
@@ -64,7 +65,7 @@
           uiName = this->Makefile->GetCurrentSourceDirectory();
         }
         uiName += "/";
-        uiName += *j;
+        uiName += arg;
       }
 
       // create the list of headers
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx
index 653caf7..9918c35 100644
--- a/Source/cmQtAutoGen.cxx
+++ b/Source/cmQtAutoGen.cxx
@@ -1,23 +1,19 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmQtAutoGen.h"
-#include "cmAlgorithms.h"
-#include "cmSystemTools.h"
 
+#include "cmAlgorithms.h"
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+#include "cmSystemTools.h"
+#include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
 #include <algorithm>
-#include <iterator>
+#include <array>
 #include <sstream>
 #include <utility>
 
-// - Static variables
-
-std::string const genNameGen = "AutoGen";
-std::string const genNameMoc = "AutoMoc";
-std::string const genNameUic = "AutoUic";
-std::string const genNameRcc = "AutoRcc";
-
 // - Static functions
 
 /// @brief Merges newOpts into baseOpts
@@ -77,27 +73,47 @@
 
 // - Class definitions
 
-std::string const cmQtAutoGen::ListSep = "<<<S>>>";
 unsigned int const cmQtAutoGen::ParallelMax = 64;
+std::string const cmQtAutoGen::ListSep = "<<<S>>>";
 
-std::string const& cmQtAutoGen::GeneratorName(GeneratorT type)
+std::string const& cmQtAutoGen::GeneratorName(GenT genType)
 {
-  switch (type) {
-    case GeneratorT::GEN:
-      return genNameGen;
-    case GeneratorT::MOC:
-      return genNameMoc;
-    case GeneratorT::UIC:
-      return genNameUic;
-    case GeneratorT::RCC:
-      return genNameRcc;
+  static const std::string AutoGen("AutoGen");
+  static const std::string AutoMoc("AutoMoc");
+  static const std::string AutoUic("AutoUic");
+  static const std::string AutoRcc("AutoRcc");
+
+  switch (genType) {
+    case GenT::GEN:
+      return AutoGen;
+    case GenT::MOC:
+      return AutoMoc;
+    case GenT::UIC:
+      return AutoUic;
+    case GenT::RCC:
+      return AutoRcc;
   }
-  return genNameGen;
+  return AutoGen;
 }
 
-std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType)
+std::string const& cmQtAutoGen::GeneratorNameUpper(GenT genType)
 {
-  return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType));
+  static const std::string AUTOGEN("AUTOGEN");
+  static const std::string AUTOMOC("AUTOMOC");
+  static const std::string AUTOUIC("AUTOUIC");
+  static const std::string AUTORCC("AUTORCC");
+
+  switch (genType) {
+    case GenT::GEN:
+      return AUTOGEN;
+    case GenT::MOC:
+      return AUTOMOC;
+    case GenT::UIC:
+      return AUTOUIC;
+    case GenT::RCC:
+      return AUTORCC;
+  }
+  return AUTOGEN;
 }
 
 std::string cmQtAutoGen::Tools(bool moc, bool uic, bool rcc)
@@ -137,13 +153,21 @@
 
 std::string cmQtAutoGen::Quoted(std::string const& text)
 {
-  static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
-                                 "\b", "\\b",  "\f", "\\f",  "\n", "\\n",
-                                 "\r", "\\r",  "\t", "\\t",  "\v", "\\v" };
+  const std::array<std::pair<const char*, const char*>, 9> replaces = {
+    { { "\\", "\\\\" },
+      { "\"", "\\\"" },
+      { "\a", "\\a" },
+      { "\b", "\\b" },
+      { "\f", "\\f" },
+      { "\n", "\\n" },
+      { "\r", "\\r" },
+      { "\t", "\\t" },
+      { "\v", "\\v" } }
+  };
 
   std::string res = text;
-  for (const char* const* it = cm::cbegin(rep); it != cm::cend(rep); it += 2) {
-    cmSystemTools::ReplaceString(res, *it, *(it + 1));
+  for (auto const& pair : replaces) {
+    cmSystemTools::ReplaceString(res, pair.first, pair.second);
   }
   res = '"' + res;
   res += '"';
@@ -216,8 +240,8 @@
   MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
 }
 
-void cmQtAutoGen::RccListParseContent(std::string const& content,
-                                      std::vector<std::string>& files)
+static void RccListParseContent(std::string const& content,
+                                std::vector<std::string>& files)
 {
   cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
   cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
@@ -234,10 +258,10 @@
   }
 }
 
-bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut,
-                                     std::string const& rccStdErr,
-                                     std::vector<std::string>& files,
-                                     std::string& error)
+static bool RccListParseOutput(std::string const& rccStdOut,
+                               std::string const& rccStdErr,
+                               std::vector<std::string>& files,
+                               std::string& error)
 {
   // Lambda to strip CR characters
   auto StripCR = [](std::string& line) {
@@ -284,11 +308,104 @@
   return true;
 }
 
-void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir,
-                                         std::vector<std::string>& files)
+cmQtAutoGen::RccLister::RccLister() = default;
+
+cmQtAutoGen::RccLister::RccLister(std::string rccExecutable,
+                                  std::vector<std::string> listOptions)
+  : RccExcutable_(std::move(rccExecutable))
+  , ListOptions_(std::move(listOptions))
 {
-  for (std::string& entry : files) {
-    std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry);
-    entry = std::move(tmp);
+}
+
+bool cmQtAutoGen::RccLister::list(std::string const& qrcFile,
+                                  std::vector<std::string>& files,
+                                  std::string& error, bool verbose) const
+{
+  error.clear();
+
+  if (!cmSystemTools::FileExists(qrcFile, true)) {
+    error = "The resource file ";
+    error += Quoted(qrcFile);
+    error += " does not exist.";
+    return false;
   }
+
+  // Run rcc list command in the directory of the qrc file with the pathless
+  // qrc file name argument.  This way rcc prints relative paths.
+  // This avoids issues on Windows when the qrc file is in a path that
+  // contains non-ASCII characters.
+  std::string const fileDir = cmSystemTools::GetFilenamePath(qrcFile);
+
+  if (!this->RccExcutable_.empty() &&
+      cmSystemTools::FileExists(this->RccExcutable_, true) &&
+      !this->ListOptions_.empty()) {
+
+    bool result = false;
+    int retVal = 0;
+    std::string rccStdOut;
+    std::string rccStdErr;
+    {
+      std::vector<std::string> cmd;
+      cmd.emplace_back(this->RccExcutable_);
+      cmd.insert(cmd.end(), this->ListOptions_.begin(),
+                 this->ListOptions_.end());
+      cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile));
+
+      // Log command
+      if (verbose) {
+        std::string msg = "Running command:\n";
+        msg += QuotedCommand(cmd);
+        msg += '\n';
+        cmSystemTools::Stdout(msg);
+      }
+
+      result = cmSystemTools::RunSingleCommand(
+        cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
+        cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+    }
+    if (!result || retVal) {
+      error = "The rcc list process failed for ";
+      error += Quoted(qrcFile);
+      error += "\n";
+      if (!rccStdOut.empty()) {
+        error += rccStdOut;
+        error += "\n";
+      }
+      if (!rccStdErr.empty()) {
+        error += rccStdErr;
+        error += "\n";
+      }
+      return false;
+    }
+    if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+      return false;
+    }
+  } else {
+    // We can't use rcc for the file listing.
+    // Read the qrc file content into string and parse it.
+    {
+      std::string qrcContents;
+      {
+        cmsys::ifstream ifs(qrcFile.c_str());
+        if (ifs) {
+          std::ostringstream osst;
+          osst << ifs.rdbuf();
+          qrcContents = osst.str();
+        } else {
+          error = "The resource file ";
+          error += Quoted(qrcFile);
+          error += " is not readable\n";
+          return false;
+        }
+      }
+      // Parse string content
+      RccListParseContent(qrcContents, files);
+    }
+  }
+
+  // Convert relative paths to absolute paths
+  for (std::string& entry : files) {
+    entry = cmSystemTools::CollapseFullPath(entry, fileDir);
+  }
+  return true;
 }
diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h
index 96d1946..3a346b5 100644
--- a/Source/cmQtAutoGen.h
+++ b/Source/cmQtAutoGen.h
@@ -14,20 +14,6 @@
 class cmQtAutoGen
 {
 public:
-  /// @brief Nested lists separator
-  static std::string const ListSep;
-  /// @brief Maximum number of parallel threads/processes in a generator
-  static unsigned int const ParallelMax;
-
-  /// @brief AutoGen generator type
-  enum class GeneratorT
-  {
-    GEN, // General
-    MOC,
-    UIC,
-    RCC
-  };
-
   /// @brief Integer version
   struct IntegerVersion
   {
@@ -54,11 +40,25 @@
     }
   };
 
+  /// @brief AutoGen generator type
+  enum class GenT
+  {
+    GEN, // AUTOGEN
+    MOC, // AUTOMOC
+    UIC, // AUTOUIC
+    RCC  // AUTORCC
+  };
+
+  /// @brief Nested lists separator
+  static std::string const ListSep;
+  /// @brief Maximum number of parallel threads/processes in a generator
+  static unsigned int const ParallelMax;
+
 public:
   /// @brief Returns the generator name
-  static std::string const& GeneratorName(GeneratorT genType);
+  static std::string const& GeneratorName(GenT genType);
   /// @brief Returns the generator name in upper case
-  static std::string GeneratorNameUpper(GeneratorT genType);
+  static std::string const& GeneratorNameUpper(GenT genType);
 
   /// @brief Returns a string with the requested tool names
   static std::string Tools(bool moc, bool uic, bool rcc);
@@ -85,21 +85,44 @@
                               std::vector<std::string> const& newOpts,
                               bool isQt5);
 
-  /// @brief Parses the content of a qrc file
-  ///
-  /// Use when rcc does not support the "--list" option
-  static void RccListParseContent(std::string const& content,
-                                  std::vector<std::string>& files);
+  /** @class RccLister
+   * @brief Lists files in qrc resource files
+   */
+  class RccLister
+  {
+  public:
+    RccLister();
+    RccLister(std::string rccExecutable, std::vector<std::string> listOptions);
 
-  /// @brief Parses the output of the "rcc --list ..." command
-  static bool RccListParseOutput(std::string const& rccStdOut,
-                                 std::string const& rccStdErr,
-                                 std::vector<std::string>& files,
-                                 std::string& error);
+    //! The rcc executable
+    std::string const& RccExcutable() const { return RccExcutable_; }
+    void SetRccExecutable(std::string const& rccExecutable)
+    {
+      RccExcutable_ = rccExecutable;
+    }
 
-  /// @brief Converts relative qrc entry paths to full paths
-  static void RccListConvertFullPath(std::string const& qrcFileDir,
-                                     std::vector<std::string>& files);
+    //! The rcc executable list options
+    std::vector<std::string> const& ListOptions() const
+    {
+      return ListOptions_;
+    }
+    void SetListOptions(std::vector<std::string> const& listOptions)
+    {
+      ListOptions_ = listOptions;
+    }
+
+    /**
+     * @brief Lists a files in the qrcFile
+     * @arg files The file names are appended to this list
+     * @arg error contains the error message when the function fails
+     */
+    bool list(std::string const& qrcFile, std::vector<std::string>& files,
+              std::string& error, bool verbose = false) const;
+
+  private:
+    std::string RccExcutable_;
+    std::vector<std::string> ListOptions_;
+  };
 };
 
 #endif
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 3ad91ee..59e17d7 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -20,6 +20,24 @@
 #include <memory>
 #include <utility>
 
+cmQtAutoGenGlobalInitializer::Keywords::Keywords()
+  : AUTOMOC("AUTOMOC")
+  , AUTOUIC("AUTOUIC")
+  , AUTORCC("AUTORCC")
+  , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE")
+  , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE")
+  , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE")
+  , SKIP_AUTOGEN("SKIP_AUTOGEN")
+  , SKIP_AUTOMOC("SKIP_AUTOMOC")
+  , SKIP_AUTOUIC("SKIP_AUTOUIC")
+  , SKIP_AUTORCC("SKIP_AUTORCC")
+  , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS")
+  , AUTORCC_OPTIONS("AUTORCC_OPTIONS")
+  , qrc("qrc")
+  , ui("ui")
+{
+}
+
 cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
   std::vector<cmLocalGenerator*> const& localGenerators)
 {
@@ -74,16 +92,16 @@
         continue;
       }
 
-      bool const moc = target->GetPropertyAsBool("AUTOMOC");
-      bool const uic = target->GetPropertyAsBool("AUTOUIC");
-      bool const rcc = target->GetPropertyAsBool("AUTORCC");
+      bool const moc = target->GetPropertyAsBool(kw().AUTOMOC);
+      bool const uic = target->GetPropertyAsBool(kw().AUTOUIC);
+      bool const rcc = target->GetPropertyAsBool(kw().AUTORCC);
       if (moc || uic || rcc) {
         std::string const mocExec =
-          target->GetSafeProperty("AUTOMOC_EXECUTABLE");
+          target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE);
         std::string const uicExec =
-          target->GetSafeProperty("AUTOUIC_EXECUTABLE");
+          target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE);
         std::string const rccExec =
-          target->GetSafeProperty("AUTORCC_EXECUTABLE");
+          target->GetSafeProperty(kw().AUTORCC_EXECUTABLE);
 
         // We support Qt4, Qt5 and Qt6
         auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h
index 74184a0..77429b7 100644
--- a/Source/cmQtAutoGenGlobalInitializer.h
+++ b/Source/cmQtAutoGenGlobalInitializer.h
@@ -18,10 +18,39 @@
 class cmQtAutoGenGlobalInitializer
 {
 public:
+  /// @brief Collection of QtAutogen related keywords
+  class Keywords
+  {
+  public:
+    Keywords();
+
+    std::string AUTOMOC;
+    std::string AUTOUIC;
+    std::string AUTORCC;
+
+    std::string AUTOMOC_EXECUTABLE;
+    std::string AUTOUIC_EXECUTABLE;
+    std::string AUTORCC_EXECUTABLE;
+
+    std::string SKIP_AUTOGEN;
+    std::string SKIP_AUTOMOC;
+    std::string SKIP_AUTOUIC;
+    std::string SKIP_AUTORCC;
+
+    std::string AUTOUIC_OPTIONS;
+    std::string AUTORCC_OPTIONS;
+
+    std::string qrc;
+    std::string ui;
+  };
+
+public:
   cmQtAutoGenGlobalInitializer(
     std::vector<cmLocalGenerator*> const& localGenerators);
   ~cmQtAutoGenGlobalInitializer();
 
+  Keywords const& kw() const { return Keywords_; };
+
   bool generate();
 
 private:
@@ -48,6 +77,7 @@
   std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
   std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
   std::unordered_map<std::string, std::string> ExecutableTestOutputs_;
+  Keywords const Keywords_;
 };
 
 #endif
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 614a88b..be96f1a 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -7,7 +7,6 @@
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
-#include "cmDuration.h"
 #include "cmFilePathChecksum.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
@@ -19,14 +18,14 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProcessOutput.h"
 #include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
 #include "cmSourceGroup.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
-#include "cmsys/FStream.hxx"
+#include "cmake.h"
 #include "cmsys/SystemInformation.hxx"
 
 #include <algorithm>
@@ -34,27 +33,10 @@
 #include <deque>
 #include <map>
 #include <set>
-#include <sstream>
 #include <string>
-#include <type_traits>
 #include <utility>
 #include <vector>
 
-std::string GetQtExecutableTargetName(
-  const cmQtAutoGen::IntegerVersion& qtVersion, std::string const& executable)
-{
-  if (qtVersion.Major == 6) {
-    return ("Qt6::" + executable);
-  }
-  if (qtVersion.Major == 5) {
-    return ("Qt5::" + executable);
-  }
-  if (qtVersion.Major == 4) {
-    return ("Qt4::" + executable);
-  }
-  return ("");
-}
-
 static std::size_t GetParallelCPUCount()
 {
   static std::size_t count = 0;
@@ -69,58 +51,6 @@
   return count;
 }
 
-static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
-                             cmQtAutoGen::GeneratorT genType)
-{
-  cmSourceGroup* sourceGroup = nullptr;
-  // Acquire source group
-  {
-    std::string property;
-    std::string groupName;
-    {
-      std::array<std::string, 2> props;
-      // Use generator specific group name
-      switch (genType) {
-        case cmQtAutoGen::GeneratorT::MOC:
-          props[0] = "AUTOMOC_SOURCE_GROUP";
-          break;
-        case cmQtAutoGen::GeneratorT::RCC:
-          props[0] = "AUTORCC_SOURCE_GROUP";
-          break;
-        default:
-          props[0] = "AUTOGEN_SOURCE_GROUP";
-          break;
-      }
-      props[1] = "AUTOGEN_SOURCE_GROUP";
-      for (std::string& prop : props) {
-        const char* propName = makefile->GetState()->GetGlobalProperty(prop);
-        if ((propName != nullptr) && (*propName != '\0')) {
-          groupName = propName;
-          property = std::move(prop);
-          break;
-        }
-      }
-    }
-    // Generate a source group on demand
-    if (!groupName.empty()) {
-      sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
-      if (sourceGroup == nullptr) {
-        std::ostringstream ost;
-        ost << cmQtAutoGen::GeneratorNameUpper(genType);
-        ost << ": " << property;
-        ost << ": Could not find or create the source group ";
-        ost << cmQtAutoGen::Quoted(groupName);
-        cmSystemTools::Error(ost.str());
-        return false;
-      }
-    }
-  }
-  if (sourceGroup != nullptr) {
-    sourceGroup->AddGroupFile(fileName);
-  }
-  return true;
-}
-
 static void AddCleanFile(cmMakefile* makefile, std::string const& fileName)
 {
   makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(),
@@ -343,6 +273,26 @@
     }
   }
 
+  // Check status of policy CMP0071
+  {
+    cmPolicies::PolicyStatus const CMP0071_status =
+      makefile->GetPolicyStatus(cmPolicies::CMP0071);
+    switch (CMP0071_status) {
+      case cmPolicies::WARN:
+        this->CMP0071Warn = true;
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        // Ignore GENERATED file
+        break;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+      case cmPolicies::NEW:
+        // Process GENERATED file
+        this->CMP0071Accept = true;
+        break;
+    }
+  }
+
   // Common directories
   {
     // Collapsed current binary directory
@@ -392,23 +342,15 @@
   }
 
   // Moc, Uic and _autogen target settings
-  if (this->Moc.Enabled || this->Uic.Enabled) {
+  if (this->MocOrUicEnabled()) {
     // Init moc specific settings
     if (this->Moc.Enabled && !InitMoc()) {
       return false;
     }
 
     // Init uic specific settings
-    if (this->Uic.Enabled) {
-      if (InitUic()) {
-        auto* uicTarget = makefile->FindTargetToUse(
-          GetQtExecutableTargetName(this->QtVersion, "uic"));
-        if (uicTarget != nullptr) {
-          this->AutogenTarget.DependTargets.insert(uicTarget);
-        }
-      } else {
-        return false;
-      }
+    if (this->Uic.Enabled && !InitUic()) {
+      return false;
     }
 
     // Autogen target name
@@ -449,12 +391,6 @@
       this->AutogenTarget.DependOrigin =
         this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
 
-      auto* mocTarget = makefile->FindTargetToUse(
-        GetQtExecutableTargetName(this->QtVersion, "moc"));
-      if (mocTarget != nullptr) {
-        this->AutogenTarget.DependTargets.insert(mocTarget);
-      }
-
       std::string const deps =
         this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
       if (!deps.empty()) {
@@ -479,8 +415,7 @@
   }
 
   // Add autogen include directory to the origin target INCLUDE_DIRECTORIES
-  if (this->Moc.Enabled || this->Uic.Enabled ||
-      (this->Rcc.Enabled && this->MultiConfig)) {
+  if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) {
     this->Target->AddIncludeDirectory(this->Dir.Include, true);
   }
 
@@ -490,7 +425,7 @@
   }
 
   // Create autogen target
-  if ((this->Moc.Enabled || this->Uic.Enabled) && !this->InitAutogenTarget()) {
+  if (this->MocOrUicEnabled() && !this->InitAutogenTarget()) {
     return false;
   }
 
@@ -575,7 +510,18 @@
   }
 
   // Moc executable
-  return GetMocExecutable();
+  {
+    if (!this->GetQtExecutable(this->Moc, "moc", false, nullptr)) {
+      return false;
+    }
+    // Let the _autogen target depend on the moc executable
+    if (this->Moc.ExecutableTarget != nullptr) {
+      this->AutogenTarget.DependTargets.insert(
+        this->Moc.ExecutableTarget->Target);
+    }
+  }
+
+  return true;
 }
 
 bool cmQtAutoGenInitializer::InitUic()
@@ -618,83 +564,118 @@
   }
 
   // Uic executable
-  return GetUicExecutable();
+  {
+    if (!this->GetQtExecutable(this->Uic, "uic", true, nullptr)) {
+      return false;
+    }
+    // Let the _autogen target depend on the uic executable
+    if (this->Uic.ExecutableTarget != nullptr) {
+      this->AutogenTarget.DependTargets.insert(
+        this->Uic.ExecutableTarget->Target);
+    }
+  }
+
+  return true;
 }
 
 bool cmQtAutoGenInitializer::InitRcc()
 {
-  return GetRccExecutable();
+  // Rcc executable
+  {
+    std::string stdOut;
+    if (!this->GetQtExecutable(this->Rcc, "rcc", false, &stdOut)) {
+      return false;
+    }
+    // Evaluate test output
+    if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
+      if (stdOut.find("--list") != std::string::npos) {
+        this->Rcc.ListOptions.emplace_back("--list");
+      } else if (stdOut.find("-list") != std::string::npos) {
+        this->Rcc.ListOptions.emplace_back("-list");
+      }
+    }
+  }
+
+  return true;
 }
 
 bool cmQtAutoGenInitializer::InitScanFiles()
 {
   cmMakefile* makefile = this->Target->Target->GetMakefile();
+  auto const& kw = this->GlobalInitializer->kw();
 
-  // String constants
-  std::string const SKIP_AUTOGEN_str = "SKIP_AUTOGEN";
-  std::string const SKIP_AUTOMOC_str = "SKIP_AUTOMOC";
-  std::string const SKIP_AUTOUIC_str = "SKIP_AUTOUIC";
+  auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
+                                bool muIt) -> MUFileHandle {
+    MUFileHandle muf = cm::make_unique<MUFile>();
+    muf->RealPath = cmSystemTools::GetRealPath(fullPath);
+    muf->SF = sf;
+    muf->Generated = sf->GetIsGenerated();
+    bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+    muf->SkipMoc = this->Moc.Enabled &&
+      (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOMOC));
+    muf->SkipUic = this->Uic.Enabled &&
+      (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+    if (muIt) {
+      muf->MocIt = this->Moc.Enabled && !muf->SkipMoc;
+      muf->UicIt = this->Uic.Enabled && !muf->SkipUic;
+    }
+    return muf;
+  };
+
+  auto addMUFile = [&](MUFileHandle&& muf, bool isHeader) {
+    if ((muf->MocIt || muf->UicIt) && muf->Generated) {
+      this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
+    }
+    if (isHeader) {
+      this->AutogenTarget.Headers.emplace(muf->SF, std::move(muf));
+    } else {
+      this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
+    }
+  };
 
   // Scan through target files
   {
-    // String constants
-    std::string const qrc_str = "qrc";
-    std::string const SKIP_AUTORCC_str = "SKIP_AUTORCC";
-    std::string const AUTORCC_OPTIONS_str = "AUTORCC_OPTIONS";
-
     // Scan through target files
     std::vector<cmSourceFile*> srcFiles;
     this->Target->GetConfigCommonSourceFiles(srcFiles);
     for (cmSourceFile* sf : srcFiles) {
-      if (sf->GetPropertyAsBool(SKIP_AUTOGEN_str)) {
+      // sf->GetExtension() is only valid after sf->GetFullPath() ...
+      // Since we're iterating over source files that might be not in the
+      // target we need to check for path errors (not existing files).
+      std::string pathError;
+      std::string const& fullPath = sf->GetFullPath(&pathError);
+      if (!pathError.empty() || fullPath.empty()) {
         continue;
       }
-
-      // sf->GetExtension() is only valid after sf->GetFullPath() ...
-      std::string const& fPath = sf->GetFullPath();
       std::string const& ext = sf->GetExtension();
 
-      // Register generated files that will be scanned by moc or uic
-      if (this->Moc.Enabled || this->Uic.Enabled) {
-        cmSystemTools::FileFormat const fileType =
-          cmSystemTools::GetFileFormat(ext);
-        if ((fileType == cmSystemTools::CXX_FILE_FORMAT) ||
-            (fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
-          std::string const absPath = cmSystemTools::GetRealPath(fPath);
-          if ((this->Moc.Enabled &&
-               !sf->GetPropertyAsBool(SKIP_AUTOMOC_str)) ||
-              (this->Uic.Enabled &&
-               !sf->GetPropertyAsBool(SKIP_AUTOUIC_str))) {
-            // Register source
-            const bool generated = sf->GetIsGenerated();
-            if (fileType == cmSystemTools::HEADER_FILE_FORMAT) {
-              if (generated) {
-                this->AutogenTarget.HeadersGenerated.push_back(absPath);
-              } else {
-                this->AutogenTarget.Headers.push_back(absPath);
-              }
-            } else {
-              if (generated) {
-                this->AutogenTarget.SourcesGenerated.push_back(absPath);
-              } else {
-                this->AutogenTarget.Sources.push_back(absPath);
-              }
-            }
-          }
+      // Register files that will be scanned by moc or uic
+      if (this->MocOrUicEnabled()) {
+        switch (cmSystemTools::GetFileFormat(ext)) {
+          case cmSystemTools::HEADER_FILE_FORMAT:
+            addMUFile(makeMUFile(sf, fullPath, true), true);
+            break;
+          case cmSystemTools::CXX_FILE_FORMAT:
+            addMUFile(makeMUFile(sf, fullPath, true), false);
+            break;
+          default:
+            break;
         }
       }
+
       // Register rcc enabled files
       if (this->Rcc.Enabled) {
-        if ((ext == qrc_str) && !sf->GetPropertyAsBool(SKIP_AUTORCC_str)) {
+        if ((ext == kw.qrc) && !sf->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
+            !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
           // Register qrc file
           Qrc qrc;
-          qrc.QrcFile = cmSystemTools::GetRealPath(fPath);
+          qrc.QrcFile = cmSystemTools::GetRealPath(fullPath);
           qrc.QrcName =
             cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
           qrc.Generated = sf->GetIsGenerated();
           // RCC options
           {
-            std::string const opts = sf->GetSafeProperty(AUTORCC_OPTIONS_str);
+            std::string const opts = sf->GetSafeProperty(kw.AUTORCC_OPTIONS);
             if (!opts.empty()) {
               cmSystemTools::ExpandListArgument(opts, qrc.Options);
             }
@@ -710,15 +691,72 @@
   // mocs_compilation.cpp source acknowledged by this target.
   this->Target->ClearSourcesCache();
 
+  // For source files find additional headers and private headers
+  if (this->MocOrUicEnabled()) {
+    std::vector<MUFileHandle> extraHeaders;
+    extraHeaders.reserve(this->AutogenTarget.Sources.size() * 2);
+    // Header search suffixes and extensions
+    std::array<std::string, 2> const suffixes{ { "", "_p" } };
+    auto const& exts = makefile->GetCMakeInstance()->GetHeaderExtensions();
+    // Scan through sources
+    for (auto const& pair : this->AutogenTarget.Sources) {
+      MUFile const& muf = *pair.second;
+      if (muf.MocIt || muf.UicIt) {
+        // Search for the default header file and a private header
+        std::string const& realPath = muf.RealPath;
+        std::string basePath = cmQtAutoGen::SubDirPrefix(realPath);
+        basePath += cmSystemTools::GetFilenameWithoutLastExtension(realPath);
+        for (auto const& suffix : suffixes) {
+          std::string const suffixedPath = basePath + suffix;
+          for (auto const& ext : exts) {
+            std::string fullPath = suffixedPath;
+            fullPath += '.';
+            fullPath += ext;
+
+            auto constexpr locationKind = cmSourceFileLocationKind::Known;
+            cmSourceFile* sf = makefile->GetSource(fullPath, locationKind);
+            if (sf != nullptr) {
+              // Check if we know about this header already
+              if (this->AutogenTarget.Headers.find(sf) !=
+                  this->AutogenTarget.Headers.end()) {
+                continue;
+              }
+              // We only accept not-GENERATED files that do exist.
+              if (!sf->GetIsGenerated() &&
+                  !cmSystemTools::FileExists(fullPath)) {
+                continue;
+              }
+            } else if (cmSystemTools::FileExists(fullPath)) {
+              // Create a new source file for the existing file
+              sf = makefile->CreateSource(fullPath, false, locationKind);
+            }
+
+            if (sf != nullptr) {
+              auto eMuf = makeMUFile(sf, fullPath, true);
+              // Ony process moc/uic when the parent is processed as well
+              if (!muf.MocIt) {
+                eMuf->MocIt = false;
+              }
+              if (!muf.UicIt) {
+                eMuf->UicIt = false;
+              }
+              extraHeaders.emplace_back(std::move(eMuf));
+            }
+          }
+        }
+      }
+    }
+    // Move generated files to main headers list
+    for (auto& eMuf : extraHeaders) {
+      addMUFile(std::move(eMuf), true);
+    }
+  }
+
   // Scan through all source files in the makefile to extract moc and uic
   // parameters.  Historically we support non target source file parameters.
   // The reason is that their file names might be discovered from source files
   // at generation time.
-  if (this->Moc.Enabled || this->Uic.Enabled) {
-    // String constants
-    std::string const ui_str = "ui";
-    std::string const AUTOUIC_OPTIONS_str = "AUTOUIC_OPTIONS";
-
+  if (this->MocOrUicEnabled()) {
     for (cmSourceFile* sf : makefile->GetSourceFiles()) {
       // sf->GetExtension() is only valid after sf->GetFullPath() ...
       // Since we're iterating over source files that might be not in the
@@ -728,139 +766,94 @@
       if (!pathError.empty() || fullPath.empty()) {
         continue;
       }
+      std::string const& ext = sf->GetExtension();
 
-      // Check file type
-      auto const fileType = cmSystemTools::GetFileFormat(sf->GetExtension());
-      bool const isSource = (fileType == cmSystemTools::CXX_FILE_FORMAT) ||
-        (fileType == cmSystemTools::HEADER_FILE_FORMAT);
-      bool const isUi = (this->Moc.Enabled && sf->GetExtension() == ui_str);
-
-      // Process only certain file types
-      if (isSource || isUi) {
-        std::string const absFile = cmSystemTools::GetRealPath(fullPath);
-        // Acquire file properties
-        bool const skipAUTOGEN = sf->GetPropertyAsBool(SKIP_AUTOGEN_str);
-        bool const skipMoc = (this->Moc.Enabled && isSource) &&
-          (skipAUTOGEN || sf->GetPropertyAsBool(SKIP_AUTOMOC_str));
-        bool const skipUic = this->Uic.Enabled &&
-          (skipAUTOGEN || sf->GetPropertyAsBool(SKIP_AUTOUIC_str));
-
-        // Register moc and uic skipped file
-        if (skipMoc) {
-          this->Moc.Skip.insert(absFile);
+      auto const fileFormat = cmSystemTools::GetFileFormat(ext);
+      if (fileFormat == cmSystemTools::HEADER_FILE_FORMAT) {
+        if (this->AutogenTarget.Headers.find(sf) ==
+            this->AutogenTarget.Headers.end()) {
+          auto muf = makeMUFile(sf, fullPath, false);
+          if (muf->SkipMoc || muf->SkipUic) {
+            this->AutogenTarget.Headers.emplace(sf, std::move(muf));
+          }
         }
-        if (skipUic) {
-          this->Uic.Skip.insert(absFile);
+      } else if (fileFormat == cmSystemTools::CXX_FILE_FORMAT) {
+        if (this->AutogenTarget.Sources.find(sf) ==
+            this->AutogenTarget.Sources.end()) {
+          auto muf = makeMUFile(sf, fullPath, false);
+          if (muf->SkipMoc || muf->SkipUic) {
+            this->AutogenTarget.Sources.emplace(sf, std::move(muf));
+          }
         }
-
-        // Check if the .ui file has uic options
-        if (isUi && !skipUic) {
-          std::string const uicOpts = sf->GetSafeProperty(AUTOUIC_OPTIONS_str);
+      } else if (this->Uic.Enabled && (ext == kw.ui)) {
+        // .ui file
+        std::string realPath = cmSystemTools::GetRealPath(fullPath);
+        bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+        bool const skipUic =
+          (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+        if (!skipUic) {
+          // Check if the .ui file has uic options
+          std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
           if (!uicOpts.empty()) {
-            this->Uic.FileFiles.push_back(absFile);
+            this->Uic.FileFiles.push_back(std::move(realPath));
             std::vector<std::string> optsVec;
             cmSystemTools::ExpandListArgument(uicOpts, optsVec);
             this->Uic.FileOptions.push_back(std::move(optsVec));
           }
+        } else {
+          // Register skipped .ui file
+          this->Uic.SkipUi.insert(std::move(realPath));
         }
       }
     }
   }
 
   // Process GENERATED sources and headers
-  if (this->Moc.Enabled || this->Uic.Enabled) {
-    if (!this->AutogenTarget.SourcesGenerated.empty() ||
-        !this->AutogenTarget.HeadersGenerated.empty()) {
-      // Check status of policy CMP0071
-      bool policyAccept = false;
-      bool policyWarn = false;
-      cmPolicies::PolicyStatus const CMP0071_status =
-        makefile->GetPolicyStatus(cmPolicies::CMP0071);
-      switch (CMP0071_status) {
-        case cmPolicies::WARN:
-          policyWarn = true;
-          CM_FALLTHROUGH;
-        case cmPolicies::OLD:
-          // Ignore GENERATED file
-          break;
-        case cmPolicies::REQUIRED_IF_USED:
-        case cmPolicies::REQUIRED_ALWAYS:
-        case cmPolicies::NEW:
-          // Process GENERATED file
-          policyAccept = true;
-          break;
+  if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
+    if (this->CMP0071Accept) {
+      // Let the autogen target depend on the GENERATED files
+      for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+        this->AutogenTarget.DependFiles.insert(muf->RealPath);
       }
-
-      if (policyAccept) {
-        // Accept GENERATED sources
-        for (std::string const& absFile :
-             this->AutogenTarget.HeadersGenerated) {
-          this->AutogenTarget.Headers.push_back(absFile);
-          this->AutogenTarget.DependFiles.insert(absFile);
-        }
-        for (std::string const& absFile :
-             this->AutogenTarget.SourcesGenerated) {
-          this->AutogenTarget.Sources.push_back(absFile);
-          this->AutogenTarget.DependFiles.insert(absFile);
-        }
-      } else {
-        if (policyWarn) {
-          std::string msg;
-          msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
-          msg += "\n";
-          std::string tools;
-          std::string property;
-          if (this->Moc.Enabled && this->Uic.Enabled) {
-            tools = "AUTOMOC and AUTOUIC";
-            property = "SKIP_AUTOGEN";
-          } else if (this->Moc.Enabled) {
-            tools = "AUTOMOC";
-            property = "SKIP_AUTOMOC";
-          } else if (this->Uic.Enabled) {
-            tools = "AUTOUIC";
-            property = "SKIP_AUTOUIC";
-          }
-          msg += "For compatibility, CMake is excluding the GENERATED source "
-                 "file(s):\n";
-          for (const std::string& absFile :
-               this->AutogenTarget.HeadersGenerated) {
-            msg.append("  ").append(Quoted(absFile)).append("\n");
-          }
-          for (const std::string& absFile :
-               this->AutogenTarget.SourcesGenerated) {
-            msg.append("  ").append(Quoted(absFile)).append("\n");
-          }
-          msg += "from processing by ";
-          msg += tools;
-          msg +=
-            ". If any of the files should be processed, set CMP0071 to NEW. "
-            "If any of the files should not be processed, "
-            "explicitly exclude them by setting the source file property ";
-          msg += property;
-          msg += ":\n  set_property(SOURCE file.h PROPERTY ";
-          msg += property;
-          msg += " ON)\n";
-          makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
-        }
+    } else if (this->CMP0071Warn) {
+      std::string msg;
+      msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
+      msg += '\n';
+      std::string property;
+      if (this->Moc.Enabled && this->Uic.Enabled) {
+        property = kw.SKIP_AUTOGEN;
+      } else if (this->Moc.Enabled) {
+        property = kw.SKIP_AUTOMOC;
+      } else if (this->Uic.Enabled) {
+        property = kw.SKIP_AUTOUIC;
       }
+      msg += "For compatibility, CMake is excluding the GENERATED source "
+             "file(s):\n";
+      for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+        msg += "  ";
+        msg += Quoted(muf->RealPath);
+        msg += '\n';
+      }
+      msg += "from processing by ";
+      msg += cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false);
+      msg += ". If any of the files should be processed, set CMP0071 to NEW. "
+             "If any of the files should not be processed, "
+             "explicitly exclude them by setting the source file property ";
+      msg += property;
+      msg += ":\n  set_property(SOURCE file.h PROPERTY ";
+      msg += property;
+      msg += " ON)\n";
+      makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
     }
   }
 
-  // Sort headers and sources
-  if (this->Moc.Enabled || this->Uic.Enabled) {
-    std::sort(this->AutogenTarget.Headers.begin(),
-              this->AutogenTarget.Headers.end());
-    std::sort(this->AutogenTarget.Sources.begin(),
-              this->AutogenTarget.Sources.end());
-  }
-
   // Process qrc files
   if (!this->Rcc.Qrcs.empty()) {
     const bool modernQt = (this->QtVersion.Major >= 5);
     // Target rcc options
     std::vector<std::string> optionsTarget;
     cmSystemTools::ExpandListArgument(
-      this->Target->GetSafeProperty("AUTORCC_OPTIONS"), optionsTarget);
+      this->Target->GetSafeProperty(kw.AUTORCC_OPTIONS), optionsTarget);
 
     // Check if file name is unique
     for (Qrc& qrc : this->Rcc.Qrcs) {
@@ -938,7 +931,8 @@
     for (Qrc& qrc : this->Rcc.Qrcs) {
       if (!qrc.Generated) {
         std::string error;
-        if (!RccListInputs(qrc.QrcFile, qrc.Resources, error)) {
+        RccLister const lister(this->Rcc.Executable, this->Rcc.ListOptions);
+        if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
           cmSystemTools::Error(error);
           return false;
         }
@@ -961,7 +955,7 @@
   // Files provided by the autogen target
   std::vector<std::string> autogenProvides;
   if (this->Moc.Enabled) {
-    this->AddGeneratedSource(this->Moc.MocsCompilation, GeneratorT::MOC, true);
+    this->AddGeneratedSource(this->Moc.MocsCompilation, this->Moc, true);
     autogenProvides.push_back(this->Moc.MocsCompilation);
   }
 
@@ -1109,13 +1103,12 @@
 {
   cmMakefile* makefile = this->Target->Target->GetMakefile();
   cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
-  auto rccTargetName = GetQtExecutableTargetName(this->QtVersion, "rcc");
 
   for (Qrc const& qrc : this->Rcc.Qrcs) {
     // Register info file as generated by CMake
     makefile->AddCMakeOutputFile(qrc.InfoFile);
     // Register file at target
-    this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC);
+    this->AddGeneratedSource(qrc.RccFile, this->Rcc);
 
     std::vector<std::string> ccOutput;
     ccOutput.push_back(qrc.RccFile);
@@ -1174,8 +1167,8 @@
         if (!this->TargetsFolder.empty()) {
           autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
         }
-        if (!rccTargetName.empty()) {
-          autoRccTarget->AddUtility(rccTargetName, makefile);
+        if (!this->Rcc.ExecutableTargetName.empty()) {
+          autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, makefile);
         }
       }
       // Add autogen target to the origin target dependencies
@@ -1195,8 +1188,8 @@
           // Add resource file to the custom command dependencies
           ccDepends.push_back(fileName);
         }
-        if (!rccTargetName.empty()) {
-          ccDepends.push_back(rccTargetName);
+        if (!this->Rcc.ExecutableTargetName.empty()) {
+          ccDepends.push_back(this->Rcc.ExecutableTargetName);
         }
         makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends,
                                            /*main_dependency*/ std::string(),
@@ -1222,7 +1215,7 @@
   }
 
   // Generate autogen target info file
-  if (this->Moc.Enabled || this->Uic.Enabled) {
+  if (this->MocOrUicEnabled()) {
     // Write autogen target info files
     if (!this->SetupWriteAutogenInfo()) {
       return false;
@@ -1262,22 +1255,74 @@
     ofs.Write("AM_INCLUDE_DIR", this->Dir.Include);
     ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude);
 
-    ofs.Write("# Files\n");
-    ofs.WriteStrings("AM_SOURCES", this->AutogenTarget.Sources);
-    ofs.WriteStrings("AM_HEADERS", this->AutogenTarget.Headers);
-    ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
-    ofs.WriteConfig("AM_SETTINGS_FILE",
-                    this->AutogenTarget.ConfigSettingsFile);
+    // Use sorted sets
+    std::set<std::string> headers;
+    std::set<std::string> sources;
+    std::set<std::string> moc_headers;
+    std::set<std::string> moc_sources;
+    std::set<std::string> moc_skip;
+    std::set<std::string> uic_headers;
+    std::set<std::string> uic_sources;
+    std::set<std::string> uic_skip;
+    // Filter headers
+    for (auto const& pair : this->AutogenTarget.Headers) {
+      MUFile const& muf = *pair.second;
+      if (muf.Generated && !this->CMP0071Accept) {
+        continue;
+      }
+      if (muf.SkipMoc) {
+        moc_skip.insert(muf.RealPath);
+      }
+      if (muf.SkipUic) {
+        uic_skip.insert(muf.RealPath);
+      }
+      if (muf.MocIt && muf.UicIt) {
+        headers.insert(muf.RealPath);
+      } else if (muf.MocIt) {
+        moc_headers.insert(muf.RealPath);
+      } else if (muf.UicIt) {
+        uic_headers.insert(muf.RealPath);
+      }
+    }
+    // Filter sources
+    for (auto const& pair : this->AutogenTarget.Sources) {
+      MUFile const& muf = *pair.second;
+      if (muf.Generated && !this->CMP0071Accept) {
+        continue;
+      }
+      if (muf.SkipMoc) {
+        moc_skip.insert(muf.RealPath);
+      }
+      if (muf.SkipUic) {
+        uic_skip.insert(muf.RealPath);
+      }
+      if (muf.MocIt && muf.UicIt) {
+        sources.insert(muf.RealPath);
+      } else if (muf.MocIt) {
+        moc_sources.insert(muf.RealPath);
+      } else if (muf.UicIt) {
+        uic_sources.insert(muf.RealPath);
+      }
+    }
 
     ofs.Write("# Qt\n");
     ofs.WriteUInt("AM_QT_VERSION_MAJOR", this->QtVersion.Major);
     ofs.Write("AM_QT_MOC_EXECUTABLE", this->Moc.Executable);
     ofs.Write("AM_QT_UIC_EXECUTABLE", this->Uic.Executable);
 
+    ofs.Write("# Files\n");
+    ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
+    ofs.WriteConfig("AM_SETTINGS_FILE",
+                    this->AutogenTarget.ConfigSettingsFile);
+    ofs.WriteStrings("AM_HEADERS", headers);
+    ofs.WriteStrings("AM_SOURCES", sources);
+
     // Write moc settings
     if (this->Moc.Enabled) {
       ofs.Write("# MOC settings\n");
-      ofs.WriteStrings("AM_MOC_SKIP", this->Moc.Skip);
+      ofs.WriteStrings("AM_MOC_HEADERS", moc_headers);
+      ofs.WriteStrings("AM_MOC_SOURCES", moc_sources);
+      ofs.WriteStrings("AM_MOC_SKIP", moc_skip);
       ofs.WriteStrings("AM_MOC_DEFINITIONS", this->Moc.Defines);
       ofs.WriteConfigStrings("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines);
       ofs.WriteStrings("AM_MOC_INCLUDES", this->Moc.Includes);
@@ -1294,8 +1339,13 @@
 
     // Write uic settings
     if (this->Uic.Enabled) {
+      // Add skipped .ui files
+      uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
+
       ofs.Write("# UIC settings\n");
-      ofs.WriteStrings("AM_UIC_SKIP", this->Uic.Skip);
+      ofs.WriteStrings("AM_UIC_HEADERS", uic_headers);
+      ofs.WriteStrings("AM_UIC_SOURCES", uic_sources);
+      ofs.WriteStrings("AM_UIC_SKIP", uic_skip);
       ofs.WriteStrings("AM_UIC_TARGET_OPTIONS", this->Uic.Options);
       ofs.WriteConfigStrings("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions);
       ofs.WriteStrings("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles);
@@ -1353,23 +1403,68 @@
   return true;
 }
 
-void cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
-                                                GeneratorT genType,
+void cmQtAutoGenInitializer::RegisterGeneratedSource(
+  std::string const& filename)
+{
+  cmMakefile* makefile = this->Target->Target->GetMakefile();
+  cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
+  gFile->SetProperty("GENERATED", "1");
+  gFile->SetProperty("SKIP_AUTOGEN", "1");
+}
+
+bool cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
+                                                GenVarsT const& genVars,
                                                 bool prepend)
 {
-  // Register source file in makefile
-  cmMakefile* makefile = this->Target->Target->GetMakefile();
-  {
-    cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
-    gFile->SetProperty("GENERATED", "1");
-    gFile->SetProperty("SKIP_AUTOGEN", "On");
-  }
-
-  // Add source file to source group
-  AddToSourceGroup(makefile, filename, genType);
-
+  // Register source at makefile
+  this->RegisterGeneratedSource(filename);
   // Add source file to target
   this->Target->AddSource(filename, prepend);
+  // Add source file to source group
+  return this->AddToSourceGroup(filename, genVars.GenNameUpper);
+}
+
+bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
+                                              std::string const& genNameUpper)
+{
+  cmMakefile* makefile = this->Target->Target->GetMakefile();
+  cmSourceGroup* sourceGroup = nullptr;
+  // Acquire source group
+  {
+    std::string property;
+    std::string groupName;
+    {
+      // Prefer generator specific source group name
+      std::array<std::string, 2> props{ { genNameUpper + "_SOURCE_GROUP",
+                                          "AUTOGEN_SOURCE_GROUP" } };
+      for (std::string& prop : props) {
+        const char* propName = makefile->GetState()->GetGlobalProperty(prop);
+        if ((propName != nullptr) && (*propName != '\0')) {
+          groupName = propName;
+          property = std::move(prop);
+          break;
+        }
+      }
+    }
+    // Generate a source group on demand
+    if (!groupName.empty()) {
+      sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
+      if (sourceGroup == nullptr) {
+        std::string err;
+        err += genNameUpper;
+        err += " error in ";
+        err += property;
+        err += ": Could not find or create the source group ";
+        err += cmQtAutoGen::Quoted(groupName);
+        cmSystemTools::Error(err);
+        return false;
+      }
+    }
+  }
+  if (sourceGroup != nullptr) {
+    sourceGroup->AddGroupFile(fileName);
+  }
+  return true;
 }
 
 static unsigned int CharPtrToUInt(const char* const input)
@@ -1384,8 +1479,12 @@
 static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions(
   cmGeneratorTarget const* target)
 {
-  cmMakefile* makefile = target->Target->GetMakefile();
+  // Qt version variable prefixes
+  static std::array<std::string, 3> const prefixes{ { "Qt6Core", "Qt5Core",
+                                                      "QT" } };
+
   std::vector<cmQtAutoGen::IntegerVersion> result;
+  result.reserve(prefixes.size() * 2);
   // Adds a version to the result (nullptr safe)
   auto addVersion = [&result](const char* major, const char* minor) {
     cmQtAutoGen::IntegerVersion ver(CharPtrToUInt(major),
@@ -1394,8 +1493,7 @@
       result.emplace_back(ver);
     }
   };
-  // Qt version variable prefixes
-  std::array<std::string, 3> const prefixes{ { "Qt6Core", "Qt5Core", "QT" } };
+  cmMakefile* makefile = target->Target->GetMakefile();
 
   // Read versions from variables
   for (const std::string& prefix : prefixes) {
@@ -1439,181 +1537,93 @@
   return res;
 }
 
-std::pair<bool, std::string> cmQtAutoGenInitializer::GetQtExecutable(
-  const std::string& executable, bool ignoreMissingTarget, std::string* output)
+bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
+                                             const std::string& executable,
+                                             bool ignoreMissingTarget,
+                                             std::string* output) const
 {
-  const std::string upperExecutable = cmSystemTools::UpperCase(executable);
-  std::string result = this->Target->Target->GetSafeProperty(
-    "AUTO" + upperExecutable + "_EXECUTABLE");
-  if (!result.empty()) {
-    cmListFileBacktrace lfbt =
-      this->Target->Target->GetMakefile()->GetBacktrace();
-    cmGeneratorExpression ge(lfbt);
-    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(result);
-    result = cge->Evaluate(this->Target->GetLocalGenerator(), "");
+  auto print_err = [this, &genVars](std::string const& err) {
+    std::string msg = genVars.GenNameUpper;
+    msg += " for target ";
+    msg += this->Target->GetName();
+    msg += ": ";
+    msg += err;
+    cmSystemTools::Error(msg);
+  };
 
-    return std::make_pair(true, result);
+  // Custom executable
+  {
+    std::string const prop = genVars.GenNameUpper + "_EXECUTABLE";
+    std::string const val = this->Target->Target->GetSafeProperty(prop);
+    if (!val.empty()) {
+      // Evaluate generator expression
+      {
+        cmListFileBacktrace lfbt =
+          this->Target->Target->GetMakefile()->GetBacktrace();
+        cmGeneratorExpression ge(lfbt);
+        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
+        genVars.Executable =
+          cge->Evaluate(this->Target->GetLocalGenerator(), "");
+      }
+      if (genVars.Executable.empty() && !ignoreMissingTarget) {
+        print_err(prop + " evaluates to an empty value");
+        return false;
+      }
+
+      // Check if the provided executable already exists (it's possible for it
+      // not to exist when building Qt itself).
+      genVars.ExecutableExists = cmSystemTools::FileExists(genVars.Executable);
+      return true;
+    }
   }
 
-  std::string err;
-
-  // Find executable
+  // Find executable target
   {
-    const std::string targetName =
-      GetQtExecutableTargetName(this->QtVersion, executable);
-    if (targetName.empty()) {
-      err = "The AUTO" + upperExecutable + " feature ";
-      err += "supports only Qt 4, Qt 5 and Qt 6.";
-    } else {
-      cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
-      cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
-      if (tgt != nullptr) {
-        if (tgt->IsImported()) {
-          result = tgt->ImportedGetLocation("");
-        } else {
-          result = tgt->GetLocation("");
-        }
-      } else {
-        if (ignoreMissingTarget) {
-          return std::make_pair(true, "");
-        }
+    // Find executable target name
+    std::string targetName;
+    if (this->QtVersion.Major == 4) {
+      targetName = "Qt4::";
+    } else if (this->QtVersion.Major == 5) {
+      targetName = "Qt5::";
+    } else if (this->QtVersion.Major == 6) {
+      targetName = "Qt6::";
+    }
+    targetName += executable;
 
-        err = "Could not find target " + targetName;
+    // Find target
+    cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
+    cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(targetName);
+    if (target != nullptr) {
+      genVars.ExecutableTargetName = targetName;
+      genVars.ExecutableTarget = target;
+      if (target->IsImported()) {
+        genVars.Executable = target->ImportedGetLocation("");
+      } else {
+        genVars.Executable = target->GetLocation("");
       }
+    } else {
+      if (ignoreMissingTarget) {
+        return true;
+      }
+      std::string err = "Could not find ";
+      err += executable;
+      err += " executable target ";
+      err += targetName;
+      print_err(err);
+      return false;
     }
   }
 
   // Test executable
-  if (err.empty()) {
-    this->GlobalInitializer->GetExecutableTestOutput(executable, result, err,
-                                                     output);
-  }
-
-  // Print error
-  if (!err.empty()) {
-    std::string msg = "AutoGen (";
-    msg += this->Target->GetName();
-    msg += "): ";
-    msg += err;
-    cmSystemTools::Error(msg);
-    return std::make_pair(false, "");
-  }
-
-  return std::make_pair(true, result);
-}
-
-bool cmQtAutoGenInitializer::GetMocExecutable()
-{
-  const auto result = this->GetQtExecutable("moc", false, nullptr);
-  this->Moc.Executable = result.second;
-  return result.first;
-}
-
-bool cmQtAutoGenInitializer::GetUicExecutable()
-{
-  const auto result = this->GetQtExecutable("uic", true, nullptr);
-  this->Uic.Executable = result.second;
-  return result.first;
-}
-
-bool cmQtAutoGenInitializer::GetRccExecutable()
-{
-  std::string stdOut;
-  const auto result = this->GetQtExecutable("rcc", false, &stdOut);
-  this->Rcc.Executable = result.second;
-  if (!result.first) {
-    return false;
-  }
-
-  if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
-    if (stdOut.find("--list") != std::string::npos) {
-      this->Rcc.ListOptions.emplace_back("--list");
-    } else {
-      this->Rcc.ListOptions.emplace_back("-list");
-    }
-  }
-  return true;
-}
-
-/// @brief Reads the resource files list from from a .qrc file
-/// @arg fileName Must be the absolute path of the .qrc file
-/// @return True if the rcc file was successfully read
-bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName,
-                                           std::vector<std::string>& files,
-                                           std::string& error)
-{
-  if (!cmSystemTools::FileExists(fileName)) {
-    error = "rcc resource file does not exist:\n  ";
-    error += Quoted(fileName);
-    error += "\n";
-    return false;
-  }
-  if (!this->Rcc.ListOptions.empty()) {
-    // Use rcc for file listing
-    if (this->Rcc.Executable.empty()) {
-      error = "rcc executable not available";
+  {
+    std::string err;
+    if (!this->GlobalInitializer->GetExecutableTestOutput(
+          executable, genVars.Executable, err, output)) {
+      print_err(err);
       return false;
     }
-
-    // Run rcc list command in the directory of the qrc file with the
-    // pathless
-    // qrc file name argument. This way rcc prints relative paths.
-    // This avoids issues on Windows when the qrc file is in a path that
-    // contains non-ASCII characters.
-    std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
-    std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
-
-    bool result = false;
-    int retVal = 0;
-    std::string rccStdOut;
-    std::string rccStdErr;
-    {
-      std::vector<std::string> cmd;
-      cmd.push_back(this->Rcc.Executable);
-      cmd.insert(cmd.end(), this->Rcc.ListOptions.begin(),
-                 this->Rcc.ListOptions.end());
-      cmd.push_back(fileNameName);
-      result = cmSystemTools::RunSingleCommand(
-        cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
-        cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
-    }
-    if (!result || retVal) {
-      error = "rcc list process failed for:\n  ";
-      error += Quoted(fileName);
-      error += "\n";
-      error += rccStdOut;
-      error += "\n";
-      error += rccStdErr;
-      error += "\n";
-      return false;
-    }
-    if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
-      return false;
-    }
-  } else {
-    // We can't use rcc for the file listing.
-    // Read the qrc file content into string and parse it.
-    {
-      std::string qrcContents;
-      {
-        cmsys::ifstream ifs(fileName.c_str());
-        if (ifs) {
-          std::ostringstream osst;
-          osst << ifs.rdbuf();
-          qrcContents = osst.str();
-        } else {
-          error = "rcc file not readable:\n  ";
-          error += Quoted(fileName);
-          error += "\n";
-          return false;
-        }
-      }
-      // Parse string content
-      RccListParseContent(qrcContents, files);
-    }
+    genVars.ExecutableExists = true;
   }
 
-  // Convert relative paths to absolute paths
-  RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files);
   return true;
 }
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index 781dd15..7ff33c3 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -8,15 +8,18 @@
 #include "cmQtAutoGen.h"
 
 #include <map>
+#include <memory> // IWYU pragma: keep
 #include <ostream>
 #include <set>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
 class cmGeneratorTarget;
 class cmTarget;
 class cmQtAutoGenGlobalInitializer;
+class cmSourceFile;
 
 /// @brief Initializes the QtAutoGen generators
 class cmQtAutoGenInitializer : public cmQtAutoGen
@@ -40,6 +43,38 @@
     std::vector<std::string> Resources;
   };
 
+  /// @brief Moc/Uic file
+  struct MUFile
+  {
+    std::string RealPath;
+    cmSourceFile* SF = nullptr;
+    bool Generated = false;
+    bool SkipMoc = false;
+    bool SkipUic = false;
+    bool MocIt = false;
+    bool UicIt = false;
+  };
+  typedef std::unique_ptr<MUFile> MUFileHandle;
+
+  /// @brief Abstract moc/uic/rcc generator variables base class
+  struct GenVarsT
+  {
+    bool Enabled = false;
+    // Generator type/name
+    GenT Gen;
+    std::string const& GenNameUpper;
+    // Executable
+    std::string ExecutableTargetName;
+    cmGeneratorTarget* ExecutableTarget = nullptr;
+    std::string Executable;
+    bool ExecutableExists = false;
+
+    /// @brief Constructor
+    GenVarsT(GenT gen)
+      : Gen(gen)
+      , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
+  };
+
   /// @brief Writes a CMake info file
   class InfoWriter
   {
@@ -88,6 +123,12 @@
   bool SetupCustomTargets();
 
 private:
+  /// @brief If moc or uic is enabled, the autogen target will be generated
+  bool MocOrUicEnabled() const
+  {
+    return (this->Moc.Enabled || this->Uic.Enabled);
+  }
+
   bool InitMoc();
   bool InitUic();
   bool InitRcc();
@@ -99,20 +140,14 @@
   bool SetupWriteAutogenInfo();
   bool SetupWriteRccInfo();
 
-  void AddGeneratedSource(std::string const& filename, GeneratorT genType,
+  void RegisterGeneratedSource(std::string const& filename);
+  bool AddGeneratedSource(std::string const& filename, GenVarsT const& genVars,
                           bool prepend = false);
+  bool AddToSourceGroup(std::string const& fileName,
+                        std::string const& genNameUpper);
 
-  bool GetMocExecutable();
-  bool GetUicExecutable();
-  bool GetRccExecutable();
-
-  bool RccListInputs(std::string const& fileName,
-                     std::vector<std::string>& files,
-                     std::string& errorMessage);
-
-  std::pair<bool, std::string> GetQtExecutable(const std::string& executable,
-                                               bool ignoreMissingTarget,
-                                               std::string* output);
+  bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
+                       bool ignoreMissingTarget, std::string* output) const;
 
 private:
   cmQtAutoGenGlobalInitializer* GlobalInitializer;
@@ -125,6 +160,8 @@
   std::vector<std::string> ConfigsList;
   std::string Verbosity;
   std::string TargetsFolder;
+  bool CMP0071Accept = false;
+  bool CMP0071Warn = false;
 
   /// @brief Common directories
   struct
@@ -152,47 +189,51 @@
     std::set<std::string> DependFiles;
     std::set<cmTarget*> DependTargets;
     // Sources to process
-    std::vector<std::string> Headers;
-    std::vector<std::string> Sources;
-    std::vector<std::string> HeadersGenerated;
-    std::vector<std::string> SourcesGenerated;
+    std::unordered_map<cmSourceFile*, MUFileHandle> Headers;
+    std::unordered_map<cmSourceFile*, MUFileHandle> Sources;
+    std::vector<MUFile*> FilesGenerated;
   } AutogenTarget;
 
   /// @brief Moc only variables
-  struct
+  struct MocT : public GenVarsT
   {
-    bool Enabled = false;
-    std::string Executable;
     std::string PredefsCmd;
-    std::set<std::string> Skip;
     std::vector<std::string> Includes;
     std::map<std::string, std::vector<std::string>> ConfigIncludes;
     std::set<std::string> Defines;
     std::map<std::string, std::set<std::string>> ConfigDefines;
     std::string MocsCompilation;
+
+    /// @brief Constructor
+    MocT()
+      : GenVarsT(GenT::MOC){};
   } Moc;
 
-  ///@brief Uic only variables
-  struct
+  /// @brief Uic only variables
+  struct UicT : public GenVarsT
   {
-    bool Enabled = false;
-    std::string Executable;
-    std::set<std::string> Skip;
+    std::set<std::string> SkipUi;
     std::vector<std::string> SearchPaths;
     std::vector<std::string> Options;
     std::map<std::string, std::vector<std::string>> ConfigOptions;
     std::vector<std::string> FileFiles;
     std::vector<std::vector<std::string>> FileOptions;
+
+    /// @brief Constructor
+    UicT()
+      : GenVarsT(GenT::UIC){};
   } Uic;
 
   /// @brief Rcc only variables
-  struct
+  struct RccT : public GenVarsT
   {
-    bool Enabled = false;
     bool GlobalTarget = false;
-    std::string Executable;
     std::vector<std::string> ListOptions;
     std::vector<Qrc> Qrcs;
+
+    /// @brief Constructor
+    RccT()
+      : GenVarsT(GenT::RCC){};
   } Rcc;
 };
 
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index e2d7deb..f115016 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -15,10 +15,39 @@
 #include "cmake.h"
 
 #include <algorithm>
+#include <sstream>
 #include <utility>
 
 // -- Class methods
 
+cmQtAutoGenerator::Logger::Logger()
+{
+  // Initialize logger
+  {
+    std::string verbose;
+    if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
+      unsigned long iVerbose = 0;
+      if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
+        SetVerbosity(static_cast<unsigned int>(iVerbose));
+      } else {
+        // Non numeric verbosity
+        SetVerbose(cmSystemTools::IsOn(verbose));
+      }
+    }
+  }
+  {
+    std::string colorEnv;
+    cmSystemTools::GetEnv("COLOR", colorEnv);
+    if (!colorEnv.empty()) {
+      SetColorOutput(cmSystemTools::IsOn(colorEnv));
+    } else {
+      SetColorOutput(true);
+    }
+  }
+}
+
+cmQtAutoGenerator::Logger::~Logger() = default;
+
 void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value)
 {
   unsigned long verbosity = 0;
@@ -43,8 +72,7 @@
   return head;
 }
 
-void cmQtAutoGenerator::Logger::Info(GeneratorT genType,
-                                     std::string const& message)
+void cmQtAutoGenerator::Logger::Info(GenT genType, std::string const& message)
 {
   std::string msg = GeneratorName(genType);
   msg += ": ";
@@ -58,7 +86,7 @@
   }
 }
 
-void cmQtAutoGenerator::Logger::Warning(GeneratorT genType,
+void cmQtAutoGenerator::Logger::Warning(GenT genType,
                                         std::string const& message)
 {
   std::string msg;
@@ -82,7 +110,7 @@
   }
 }
 
-void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType,
+void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
                                             std::string const& filename,
                                             std::string const& message)
 {
@@ -94,8 +122,7 @@
   Warning(genType, msg);
 }
 
-void cmQtAutoGenerator::Logger::Error(GeneratorT genType,
-                                      std::string const& message)
+void cmQtAutoGenerator::Logger::Error(GenT genType, std::string const& message)
 {
   std::string msg;
   msg += HeadLine(GeneratorName(genType) + " error");
@@ -111,7 +138,7 @@
   }
 }
 
-void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType,
+void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
                                           std::string const& filename,
                                           std::string const& message)
 {
@@ -124,7 +151,7 @@
 }
 
 void cmQtAutoGenerator::Logger::ErrorCommand(
-  GeneratorT genType, std::string const& message,
+  GenT genType, std::string const& message,
   std::vector<std::string> const& command, std::string const& output)
 {
   std::string msg;
@@ -153,6 +180,91 @@
   }
 }
 
+bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
+{
+  bool success = true;
+  std::string const dirName = cmSystemTools::GetFilenamePath(filename);
+  if (!dirName.empty()) {
+    success = cmSystemTools::MakeDirectory(dirName);
+  }
+  return success;
+}
+
+bool cmQtAutoGenerator::FileRead(std::string& content,
+                                 std::string const& filename,
+                                 std::string* error)
+{
+  content.clear();
+  if (!cmSystemTools::FileExists(filename, true)) {
+    if (error != nullptr) {
+      error->append("Not a file.");
+    }
+    return false;
+  }
+
+  unsigned long const length = cmSystemTools::FileLength(filename);
+  cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
+
+  // Use lambda to save destructor calls of ifs
+  return [&ifs, length, &content, error]() -> bool {
+    if (!ifs) {
+      if (error != nullptr) {
+        error->append("Opening the file for reading failed.");
+      }
+      return false;
+    }
+    content.reserve(length);
+    typedef std::istreambuf_iterator<char> IsIt;
+    content.assign(IsIt{ ifs }, IsIt{});
+    if (!ifs) {
+      content.clear();
+      if (error != nullptr) {
+        error->append("Reading from the file failed.");
+      }
+      return false;
+    }
+    return true;
+  }();
+}
+
+bool cmQtAutoGenerator::FileWrite(std::string const& filename,
+                                  std::string const& content,
+                                  std::string* error)
+{
+  // Make sure the parent directory exists
+  if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
+    if (error != nullptr) {
+      error->assign("Could not create parent directory.");
+    }
+    return false;
+  }
+  cmsys::ofstream ofs;
+  ofs.open(filename.c_str(),
+           (std::ios::out | std::ios::binary | std::ios::trunc));
+
+  // Use lambda to save destructor calls of ofs
+  return [&ofs, &content, error]() -> bool {
+    if (!ofs) {
+      if (error != nullptr) {
+        error->assign("Opening file for writing failed.");
+      }
+      return false;
+    }
+    ofs << content;
+    if (!ofs.good()) {
+      if (error != nullptr) {
+        error->assign("File writing failed.");
+      }
+      return false;
+    }
+    return true;
+  }();
+}
+
+cmQtAutoGenerator::FileSystem::FileSystem() = default;
+
+cmQtAutoGenerator::FileSystem::~FileSystem() = default;
+
 std::string cmQtAutoGenerator::FileSystem::GetRealPath(
   std::string const& filename)
 {
@@ -160,11 +272,11 @@
   return cmSystemTools::GetRealPath(filename);
 }
 
-std::string cmQtAutoGenerator::FileSystem::CollapseCombinedPath(
-  std::string const& dir, std::string const& file)
+std::string cmQtAutoGenerator::FileSystem::CollapseFullPath(
+  std::string const& file, std::string const& dir)
 {
   std::lock_guard<std::mutex> lock(Mutex_);
-  return cmSystemTools::CollapseCombinedPath(dir, file);
+  return cmSystemTools::CollapseFullPath(file, dir);
 }
 
 void cmQtAutoGenerator::FileSystem::SplitPath(
@@ -268,91 +380,16 @@
                                              std::string const& filename,
                                              std::string* error)
 {
-  bool success = false;
-  if (FileExists(filename, true)) {
-    unsigned long const length = FileLength(filename);
-    {
-      std::lock_guard<std::mutex> lock(Mutex_);
-      cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
-      if (ifs) {
-        content.reserve(length);
-        content.assign(std::istreambuf_iterator<char>{ ifs },
-                       std::istreambuf_iterator<char>{});
-        if (ifs) {
-          success = true;
-        } else {
-          content.clear();
-          if (error != nullptr) {
-            error->append("Reading from the file failed.");
-          }
-        }
-      } else if (error != nullptr) {
-        error->append("Opening the file for reading failed.");
-      }
-    }
-  } else if (error != nullptr) {
-    error->append(
-      "The file does not exist, is not readable or is a directory.");
-  }
-  return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRead(GeneratorT genType,
-                                             std::string& content,
-                                             std::string const& filename)
-{
-  std::string error;
-  if (!FileRead(content, filename, &error)) {
-    Log()->ErrorFile(genType, filename, error);
-    return false;
-  }
-  return true;
+  std::lock_guard<std::mutex> lock(Mutex_);
+  return cmQtAutoGenerator::FileRead(content, filename, error);
 }
 
 bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename,
                                               std::string const& content,
                                               std::string* error)
 {
-  bool success = false;
-  // Make sure the parent directory exists
-  if (MakeParentDirectory(filename)) {
-    std::lock_guard<std::mutex> lock(Mutex_);
-    cmsys::ofstream outfile;
-    outfile.open(filename.c_str(),
-                 (std::ios::out | std::ios::binary | std::ios::trunc));
-    if (outfile) {
-      outfile << content;
-      // Check for write errors
-      if (outfile.good()) {
-        success = true;
-      } else {
-        if (error != nullptr) {
-          error->assign("File writing failed");
-        }
-      }
-    } else {
-      if (error != nullptr) {
-        error->assign("Opening file for writing failed");
-      }
-    }
-  } else {
-    if (error != nullptr) {
-      error->assign("Could not create parent directory");
-    }
-  }
-  return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileWrite(GeneratorT genType,
-                                              std::string const& filename,
-                                              std::string const& content)
-{
-  std::string error;
-  if (!FileWrite(filename, content, &error)) {
-    Log()->ErrorFile(genType, filename, error);
-    return false;
-  }
-  return true;
+  std::lock_guard<std::mutex> lock(Mutex_);
+  return cmQtAutoGenerator::FileWrite(filename, content, error);
 }
 
 bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename,
@@ -387,35 +424,11 @@
   return cmSystemTools::MakeDirectory(dirname);
 }
 
-bool cmQtAutoGenerator::FileSystem::MakeDirectory(GeneratorT genType,
-                                                  std::string const& dirname)
-{
-  if (!MakeDirectory(dirname)) {
-    Log()->ErrorFile(genType, dirname, "Could not create directory");
-    return false;
-  }
-  return true;
-}
-
 bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
   std::string const& filename)
 {
-  bool success = true;
-  std::string const dirName = cmSystemTools::GetFilenamePath(filename);
-  if (!dirName.empty()) {
-    success = MakeDirectory(dirName);
-  }
-  return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
-  GeneratorT genType, std::string const& filename)
-{
-  if (!MakeParentDirectory(filename)) {
-    Log()->ErrorFile(genType, filename, "Could not create parent directory");
-    return false;
-  }
-  return true;
+  std::lock_guard<std::mutex> lock(Mutex_);
+  return cmQtAutoGenerator::MakeParentDirectory(filename);
 }
 
 int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop,
@@ -447,7 +460,7 @@
 {
   auto& pipe = *reinterpret_cast<PipeT*>(handle->data);
   pipe.Buffer_.resize(suggestedSize);
-  buf->base = &pipe.Buffer_.front();
+  buf->base = pipe.Buffer_.data();
   buf->len = pipe.Buffer_.size();
 }
 
@@ -506,6 +519,13 @@
   Setup_.MergedOutput = mergedOutput;
 }
 
+static std::string getUVError(const char* prefixString, int uvErrorCode)
+{
+  std::ostringstream ost;
+  ost << prefixString << ": " << uv_strerror(uvErrorCode);
+  return ost.str();
+}
+
 bool cmQtAutoGenerator::ReadOnlyProcessT::start(
   uv_loop_t* uv_loop, std::function<void()>&& finishedCallback)
 {
@@ -555,15 +575,17 @@
     std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
     UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit;
     UVOptions_.file = CommandPtr_[0];
-    UVOptions_.args = const_cast<char**>(&CommandPtr_.front());
+    UVOptions_.args = const_cast<char**>(CommandPtr_.data());
     UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
     UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
     UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
-    UVOptions_.stdio = &UVOptionsStdIO_.front();
+    UVOptions_.stdio = UVOptionsStdIO_.data();
 
     // -- Spawn process
-    if (UVProcess_.spawn(*uv_loop, UVOptions_, this) != 0) {
-      Result()->ErrorMessage = "libuv process spawn failed";
+    int uvErrorCode = UVProcess_.spawn(*uv_loop, UVOptions_, this);
+    if (uvErrorCode != 0) {
+      Result()->ErrorMessage =
+        getUVError("libuv process spawn failed ", uvErrorCode);
     }
   }
   // -- Start reading from stdio streams
@@ -635,46 +657,9 @@
   }
 }
 
-cmQtAutoGenerator::cmQtAutoGenerator()
-  : FileSys_(&Logger_)
-{
-  // Initialize logger
-  {
-    std::string verbose;
-    if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
-      unsigned long iVerbose = 0;
-      if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
-        Logger_.SetVerbosity(static_cast<unsigned int>(iVerbose));
-      } else {
-        // Non numeric verbosity
-        Logger_.SetVerbose(cmSystemTools::IsOn(verbose));
-      }
-    }
-  }
-  {
-    std::string colorEnv;
-    cmSystemTools::GetEnv("COLOR", colorEnv);
-    if (!colorEnv.empty()) {
-      Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv));
-    } else {
-      Logger_.SetColorOutput(true);
-    }
-  }
+cmQtAutoGenerator::cmQtAutoGenerator() = default;
 
-  // Initialize libuv loop
-  uv_disable_stdio_inheritance();
-#ifdef CMAKE_UV_SIGNAL_HACK
-  UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>();
-#endif
-  UVLoop_ = cm::make_unique<uv_loop_t>();
-  uv_loop_init(UVLoop());
-}
-
-cmQtAutoGenerator::~cmQtAutoGenerator()
-{
-  // Close libuv loop
-  uv_loop_close(UVLoop());
-}
+cmQtAutoGenerator::~cmQtAutoGenerator() = default;
 
 bool cmQtAutoGenerator::Run(std::string const& infoFile,
                             std::string const& config)
diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h
index 9956a99..479d357 100644
--- a/Source/cmQtAutoGenerator.h
+++ b/Source/cmQtAutoGenerator.h
@@ -8,7 +8,6 @@
 #include "cmFilePathChecksum.h"
 #include "cmQtAutoGen.h"
 #include "cmUVHandlePtr.h"
-#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
 #include "cm_uv.h"
 
 #include <array>
@@ -31,25 +30,29 @@
   class Logger
   {
   public:
+    // -- Construction
+    Logger();
+    ~Logger();
     // -- Verbosity
     unsigned int Verbosity() const { return this->Verbosity_; }
     void SetVerbosity(unsigned int value) { this->Verbosity_ = value; }
     void RaiseVerbosity(std::string const& value);
     bool Verbose() const { return (this->Verbosity_ != 0); }
     void SetVerbose(bool value) { this->Verbosity_ = value ? 1 : 0; }
+    // -- Color output
     bool ColorOutput() const { return this->ColorOutput_; }
     void SetColorOutput(bool value);
     // -- Log info
-    void Info(GeneratorT genType, std::string const& message);
+    void Info(GenT genType, std::string const& message);
     // -- Log warning
-    void Warning(GeneratorT genType, std::string const& message);
-    void WarningFile(GeneratorT genType, std::string const& filename,
+    void Warning(GenT genType, std::string const& message);
+    void WarningFile(GenT genType, std::string const& filename,
                      std::string const& message);
     // -- Log error
-    void Error(GeneratorT genType, std::string const& message);
-    void ErrorFile(GeneratorT genType, std::string const& filename,
+    void Error(GenT genType, std::string const& message);
+    void ErrorFile(GenT genType, std::string const& filename,
                    std::string const& message);
-    void ErrorCommand(GeneratorT genType, std::string const& message,
+    void ErrorCommand(GenT genType, std::string const& message,
                       std::vector<std::string> const& command,
                       std::string const& output);
 
@@ -62,24 +65,27 @@
     bool ColorOutput_ = false;
   };
 
+  // -- File system methods
+  static bool MakeParentDirectory(std::string const& filename);
+  static bool FileRead(std::string& content, std::string const& filename,
+                       std::string* error = nullptr);
+  static bool FileWrite(std::string const& filename,
+                        std::string const& content,
+                        std::string* error = nullptr);
+
   /// @brief Thread safe file system interface
   class FileSystem
   {
   public:
-    FileSystem(Logger* log)
-      : Log_(log)
-    {
-    }
-
-    /// @brief Logger
-    Logger* Log() const { return Log_; }
+    FileSystem();
+    ~FileSystem();
 
     // -- Paths
     /// @brief Wrapper for cmSystemTools::GetRealPath
     std::string GetRealPath(std::string const& filename);
-    /// @brief Wrapper for cmSystemTools::CollapseCombinedPath
-    std::string CollapseCombinedPath(std::string const& dir,
-                                     std::string const& file);
+    /// @brief Wrapper for cmSystemTools::CollapseFullPath
+    std::string CollapseFullPath(std::string const& file,
+                                 std::string const& dir);
     /// @brief Wrapper for cmSystemTools::SplitPath
     void SplitPath(const std::string& p, std::vector<std::string>& components,
                    bool expand_home_dir = true);
@@ -113,15 +119,9 @@
 
     bool FileRead(std::string& content, std::string const& filename,
                   std::string* error = nullptr);
-    /// @brief Error logging version
-    bool FileRead(GeneratorT genType, std::string& content,
-                  std::string const& filename);
 
     bool FileWrite(std::string const& filename, std::string const& content,
                    std::string* error = nullptr);
-    /// @brief Error logging version
-    bool FileWrite(GeneratorT genType, std::string const& filename,
-                   std::string const& content);
 
     bool FileDiffers(std::string const& filename, std::string const& content);
 
@@ -130,17 +130,11 @@
 
     // -- Directory access
     bool MakeDirectory(std::string const& dirname);
-    /// @brief Error logging version
-    bool MakeDirectory(GeneratorT genType, std::string const& dirname);
-
     bool MakeParentDirectory(std::string const& filename);
-    /// @brief Error logging version
-    bool MakeParentDirectory(GeneratorT genType, std::string const& filename);
 
   private:
     std::mutex Mutex_;
     cmFilePathChecksum FilePathChecksum_;
-    Logger* Log_;
   };
 
   /// @brief Return value and output of an external process
@@ -250,18 +244,10 @@
   // -- Run
   bool Run(std::string const& infoFile, std::string const& config);
 
-  // -- Accessors
-  // Logging
-  Logger& Log() { return Logger_; }
-  // File System
-  FileSystem& FileSys() { return FileSys_; }
   // InfoFile
   std::string const& InfoFile() const { return InfoFile_; }
   std::string const& InfoDir() const { return InfoDir_; }
   std::string const& InfoConfig() const { return InfoConfig_; }
-  // libuv loop
-  uv_loop_t* UVLoop() { return UVLoop_.get(); }
-  cm::uv_async_ptr& UVRequest() { return UVRequest_; }
 
   // -- Utility
   static std::string SettingsFind(std::string const& content, const char* key);
@@ -272,19 +258,10 @@
   virtual bool Process() = 0;
 
 private:
-  // -- Logging
-  Logger Logger_;
-  FileSystem FileSys_;
   // -- Info settings
   std::string InfoFile_;
   std::string InfoDir_;
   std::string InfoConfig_;
-// -- libuv loop
-#ifdef CMAKE_UV_SIGNAL_HACK
-  std::unique_ptr<cmUVSignalHackRAII> UVHackRAII_;
-#endif
-  std::unique_ptr<uv_loop_t> UVLoop_;
-  cm::uv_async_ptr UVRequest_;
 };
 
 #endif
diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx
index ddff4cf..ec1a1aa 100644
--- a/Source/cmQtAutoGeneratorMocUic.cxx
+++ b/Source/cmQtAutoGeneratorMocUic.cxx
@@ -5,7 +5,6 @@
 #include <algorithm>
 #include <array>
 #include <cstddef>
-#include <functional>
 #include <list>
 #include <memory>
 #include <set>
@@ -28,7 +27,7 @@
 std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath(
   std::string const& relativePath) const
 {
-  return FileSys->CollapseCombinedPath(AutogenBuildDir, relativePath);
+  return FileSys->CollapseFullPath(relativePath, AutogenBuildDir);
 }
 
 /**
@@ -184,11 +183,10 @@
           ParseUic(wrk, meta);
         }
       } else {
-        wrk.LogFileWarning(GeneratorT::GEN, FileName,
-                           "The source file is empty");
+        wrk.LogFileWarning(GenT::GEN, FileName, "The source file is empty");
       }
     } else {
-      wrk.LogFileError(GeneratorT::GEN, FileName,
+      wrk.LogFileError(GenT::GEN, FileName,
                        "Could not read the file: " + error);
     }
   }
@@ -275,7 +273,7 @@
         emsg += ", but the header ";
         emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
         emsg += " could not be found.";
-        wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+        wrk.LogFileError(GenT::MOC, FileName, emsg);
       }
       return false;
     }
@@ -314,7 +312,7 @@
               emsg += Quoted("moc_" + mocInc.Base + ".cpp");
               emsg += " for a compatibility with strict mode.\n"
                       "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
-              wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+              wrk.LogFileWarning(GenT::MOC, FileName, emsg);
             } else {
               std::string emsg = "The file includes the moc file ";
               emsg += Quoted(mocInc.Inc);
@@ -326,7 +324,7 @@
               emsg += Quoted("moc_" + mocInc.Base + ".cpp");
               emsg += " for compatibility with strict mode.\n"
                       "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
-              wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+              wrk.LogFileWarning(GenT::MOC, FileName, emsg);
             }
           }
         } else {
@@ -338,7 +336,7 @@
                     "matching header ";
             emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
             emsg += " could not be found.";
-            wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+            wrk.LogFileError(GenT::MOC, FileName, emsg);
           }
           return false;
         }
@@ -356,7 +354,7 @@
           emsg += ", but does not contain a ";
           emsg += wrk.Moc().MacrosString();
           emsg += " macro.";
-          wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+          wrk.LogFileWarning(GenT::MOC, FileName, emsg);
         }
       } else {
         // Don't allow <BASE>.moc include other than self in strict mode
@@ -367,7 +365,7 @@
                   "source file.\nThis is not supported. Include ";
           emsg += Quoted(meta.FileBase + ".moc");
           emsg += " to run moc on this source file.";
-          wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+          wrk.LogFileError(GenT::MOC, FileName, emsg);
         }
         return false;
       }
@@ -410,7 +408,7 @@
         emsg += Quoted(meta.FileBase + ".moc");
         emsg += " for compatibility with strict mode.\n"
                 "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
-        wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
+        wrk.LogFileWarning(GenT::MOC, FileName, emsg);
       }
       // Add own source job
       jobs.emplace_back(
@@ -425,7 +423,7 @@
         emsg += "!\nConsider to\n - add #include \"";
         emsg += meta.FileBase;
         emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
-        wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
+        wrk.LogFileError(GenT::MOC, FileName, emsg);
       }
       return false;
     }
@@ -433,8 +431,8 @@
 
   // Convert pre jobs to actual jobs
   for (JobPre& jobPre : jobs) {
-    JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName,
-                                     std::move(jobPre.IncludeString)));
+    JobHandleT jobHandle = cm::make_unique<JobMocT>(
+      std::move(jobPre.SourceFile), FileName, std::move(jobPre.IncludeString));
     if (jobPre.self) {
       // Read dependencies from this source
       static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
@@ -452,8 +450,8 @@
   bool success = true;
   std::string const macroName = wrk.Moc().FindMacro(meta.Content);
   if (!macroName.empty()) {
-    JobHandleT jobHandle(
-      new JobMocT(std::string(FileName), std::string(), std::string()));
+    JobHandleT jobHandle = cm::make_unique<JobMocT>(
+      std::string(FileName), std::string(), std::string());
     // Read dependencies from this source
     static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
     success = wrk.Gen().ParallelJobPushMoc(jobHandle);
@@ -519,8 +517,8 @@
   std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString);
   if (!uiInputFile.empty()) {
     if (!wrk.Uic().skipped(uiInputFile)) {
-      JobHandleT jobHandle(new JobUicT(std::move(uiInputFile), FileName,
-                                       std::move(includeString)));
+      JobHandleT jobHandle = cm::make_unique<JobUicT>(
+        std::move(uiInputFile), FileName, std::move(includeString));
       success = wrk.Gen().ParallelJobPushUic(jobHandle);
     } else {
       // A skipped file is successful
@@ -586,7 +584,7 @@
       emsg += Quoted(testFile);
       emsg += "\n";
     }
-    wrk.LogFileError(GeneratorT::UIC, FileName, emsg);
+    wrk.LogFileError(GenT::UIC, FileName, emsg);
   }
 
   return res;
@@ -602,7 +600,7 @@
       std::string reason = "Generating ";
       reason += Quoted(wrk.Moc().PredefsFileRel);
       reason += " because it doesn't exist";
-      wrk.LogInfo(GeneratorT::MOC, reason);
+      wrk.LogInfo(GenT::MOC, reason);
     }
     generate = true;
   } else if (wrk.Moc().SettingsChanged) {
@@ -610,7 +608,7 @@
       std::string reason = "Generating ";
       reason += Quoted(wrk.Moc().PredefsFileRel);
       reason += " because the settings changed.";
-      wrk.LogInfo(GeneratorT::MOC, reason);
+      wrk.LogInfo(GenT::MOC, reason);
     }
     generate = true;
   }
@@ -627,12 +625,12 @@
         cmd.push_back("-D" + def);
       }
       // Execute command
-      if (!wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
+      if (!wrk.RunProcess(GenT::MOC, result, cmd)) {
         std::string emsg = "The content generation command for ";
         emsg += Quoted(wrk.Moc().PredefsFileRel);
         emsg += " failed.\n";
         emsg += result.ErrorMessage;
-        wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
+        wrk.LogCommandError(GenT::MOC, emsg, cmd, result.StdOut);
       }
     }
 
@@ -640,14 +638,16 @@
     if (!result.error()) {
       if (!fileExists ||
           wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) {
-        if (wrk.FileSys().FileWrite(GeneratorT::MOC, wrk.Moc().PredefsFileAbs,
-                                    result.StdOut)) {
+        std::string error;
+        if (wrk.FileSys().FileWrite(wrk.Moc().PredefsFileAbs, result.StdOut,
+                                    &error)) {
           // Success
         } else {
           std::string emsg = "Writing ";
           emsg += Quoted(wrk.Moc().PredefsFileRel);
-          emsg += " failed.";
-          wrk.LogFileError(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, emsg);
+          emsg += " failed. ";
+          emsg += error;
+          wrk.LogFileError(GenT::MOC, wrk.Moc().PredefsFileAbs, emsg);
         }
       } else {
         // Touch to update the time stamp
@@ -655,7 +655,7 @@
           std::string msg = "Touching ";
           msg += Quoted(wrk.Moc().PredefsFileRel);
           msg += ".";
-          wrk.LogInfo(GeneratorT::MOC, msg);
+          wrk.LogInfo(GenT::MOC, msg);
         }
         wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs);
       }
@@ -713,7 +713,7 @@
       reason += " from its source file ";
       reason += Quoted(SourceFile);
       reason += " because it doesn't exist";
-      wrk.LogInfo(GeneratorT::MOC, reason);
+      wrk.LogInfo(GenT::MOC, reason);
     }
     return true;
   }
@@ -726,7 +726,7 @@
       reason += " from ";
       reason += Quoted(SourceFile);
       reason += " because the MOC settings changed";
-      wrk.LogInfo(GeneratorT::MOC, reason);
+      wrk.LogInfo(GenT::MOC, reason);
     }
     return true;
   }
@@ -739,7 +739,7 @@
       isOlder = wrk.FileSys().FileIsOlderThan(
         BuildFile, wrk.Moc().PredefsFileAbs, &error);
       if (!isOlder && !error.empty()) {
-        wrk.LogError(GeneratorT::MOC, error);
+        wrk.LogError(GenT::MOC, error);
         return false;
       }
     }
@@ -749,7 +749,7 @@
         reason += Quoted(BuildFile);
         reason += " because it's older than: ";
         reason += Quoted(wrk.Moc().PredefsFileAbs);
-        wrk.LogInfo(GeneratorT::MOC, reason);
+        wrk.LogInfo(GenT::MOC, reason);
       }
       return true;
     }
@@ -762,7 +762,7 @@
       std::string error;
       isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
       if (!isOlder && !error.empty()) {
-        wrk.LogError(GeneratorT::MOC, error);
+        wrk.LogError(GenT::MOC, error);
         return false;
       }
     }
@@ -772,7 +772,7 @@
         reason += Quoted(BuildFile);
         reason += " because it's older than its source file ";
         reason += Quoted(SourceFile);
-        wrk.LogInfo(GeneratorT::MOC, reason);
+        wrk.LogInfo(GenT::MOC, reason);
       }
       return true;
     }
@@ -794,7 +794,7 @@
           emsg += Quoted(IncluderFile);
           emsg += ".\n";
           emsg += error;
-          wrk.LogError(GeneratorT::MOC, emsg);
+          wrk.LogError(GenT::MOC, emsg);
           return false;
         }
       }
@@ -815,18 +815,18 @@
             reason += Quoted(SourceFile);
             reason += " because it is older than it's dependency file ";
             reason += Quoted(depFileAbs);
-            wrk.LogInfo(GeneratorT::MOC, reason);
+            wrk.LogInfo(GenT::MOC, reason);
           }
           return true;
         }
         if (!error.empty()) {
-          wrk.LogError(GeneratorT::MOC, error);
+          wrk.LogError(GenT::MOC, error);
           return false;
         }
       } else {
         std::string message = "Could not find dependency file ";
         message += Quoted(depFileRel);
-        wrk.LogFileWarning(GeneratorT::MOC, SourceFile, message);
+        wrk.LogFileWarning(GenT::MOC, SourceFile, message);
       }
     }
   }
@@ -837,7 +837,12 @@
 void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk)
 {
   // Make sure the parent directory exists
-  if (wrk.FileSys().MakeParentDirectory(GeneratorT::MOC, BuildFile)) {
+  if (!wrk.FileSys().MakeParentDirectory(BuildFile)) {
+    wrk.LogFileError(GenT::MOC, BuildFile,
+                     "Could not create parent directory.");
+    return;
+  }
+  {
     // Compose moc command
     std::vector<std::string> cmd;
     cmd.push_back(wrk.Moc().Executable);
@@ -855,11 +860,11 @@
 
     // Execute moc command
     ProcessResultT result;
-    if (wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
+    if (wrk.RunProcess(GenT::MOC, result, cmd)) {
       // Moc command success
       // Print moc output
       if (!result.StdOut.empty()) {
-        wrk.LogInfo(GeneratorT::MOC, result.StdOut);
+        wrk.LogInfo(GenT::MOC, result.StdOut);
       }
       // Notify the generator that a not included file changed (on demand)
       if (IncludeString.empty()) {
@@ -874,7 +879,7 @@
         emsg += Quoted(BuildFile);
         emsg += ".\n";
         emsg += result.ErrorMessage;
-        wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
+        wrk.LogCommandError(GenT::MOC, emsg, cmd, result.StdOut);
       }
       wrk.FileSys().FileRemove(BuildFile);
     }
@@ -905,7 +910,7 @@
       reason += " from its source file ";
       reason += Quoted(SourceFile);
       reason += " because it doesn't exist";
-      wrk.LogInfo(GeneratorT::UIC, reason);
+      wrk.LogInfo(GenT::UIC, reason);
     }
     return true;
   }
@@ -918,7 +923,7 @@
       reason += " from ";
       reason += Quoted(SourceFile);
       reason += " because the UIC settings changed";
-      wrk.LogInfo(GeneratorT::UIC, reason);
+      wrk.LogInfo(GenT::UIC, reason);
     }
     return true;
   }
@@ -930,7 +935,7 @@
       std::string error;
       isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
       if (!isOlder && !error.empty()) {
-        wrk.LogError(GeneratorT::UIC, error);
+        wrk.LogError(GenT::UIC, error);
         return false;
       }
     }
@@ -940,7 +945,7 @@
         reason += Quoted(BuildFile);
         reason += " because it's older than its source file ";
         reason += Quoted(SourceFile);
-        wrk.LogInfo(GeneratorT::UIC, reason);
+        wrk.LogInfo(GenT::UIC, reason);
       }
       return true;
     }
@@ -952,7 +957,12 @@
 void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk)
 {
   // Make sure the parent directory exists
-  if (wrk.FileSys().MakeParentDirectory(GeneratorT::UIC, BuildFile)) {
+  if (!wrk.FileSys().MakeParentDirectory(BuildFile)) {
+    wrk.LogFileError(GenT::UIC, BuildFile,
+                     "Could not create parent directory.");
+    return;
+  }
+  {
     // Compose uic command
     std::vector<std::string> cmd;
     cmd.push_back(wrk.Uic().Executable);
@@ -970,11 +980,11 @@
     cmd.push_back(SourceFile);
 
     ProcessResultT result;
-    if (wrk.RunProcess(GeneratorT::UIC, result, cmd)) {
+    if (wrk.RunProcess(GenT::UIC, result, cmd)) {
       // Uic command success
       // Print uic output
       if (!result.StdOut.empty()) {
-        wrk.LogInfo(GeneratorT::UIC, result.StdOut);
+        wrk.LogInfo(GenT::UIC, result.StdOut);
       }
     } else {
       // Uic command failed
@@ -987,18 +997,13 @@
         emsg += Quoted(IncluderFile);
         emsg += ".\n";
         emsg += result.ErrorMessage;
-        wrk.LogCommandError(GeneratorT::UIC, emsg, cmd, result.StdOut);
+        wrk.LogCommandError(GenT::UIC, emsg, cmd, result.StdOut);
       }
       wrk.FileSys().FileRemove(BuildFile);
     }
   }
 }
 
-void cmQtAutoGeneratorMocUic::JobDeleterT::operator()(JobT* job)
-{
-  delete job;
-}
-
 cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen,
                                           uv_loop_t* uvLoop)
   : Gen_(gen)
@@ -1018,41 +1023,39 @@
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::LogInfo(
-  GeneratorT genType, std::string const& message) const
+  GenT genType, std::string const& message) const
 {
-  return Log().Info(genType, message);
+  Log().Info(genType, message);
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::LogWarning(
-  GeneratorT genType, std::string const& message) const
+  GenT genType, std::string const& message) const
 {
-  return Log().Warning(genType, message);
+  Log().Warning(genType, message);
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning(
-  GeneratorT genType, std::string const& filename,
-  std::string const& message) const
+  GenT genType, std::string const& filename, std::string const& message) const
 {
-  return Log().WarningFile(genType, filename, message);
+  Log().WarningFile(genType, filename, message);
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::LogError(
-  GeneratorT genType, std::string const& message) const
+  GenT genType, std::string const& message) const
 {
   Gen().ParallelRegisterJobError();
   Log().Error(genType, message);
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::LogFileError(
-  GeneratorT genType, std::string const& filename,
-  std::string const& message) const
+  GenT genType, std::string const& filename, std::string const& message) const
 {
   Gen().ParallelRegisterJobError();
   Log().ErrorFile(genType, filename, message);
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError(
-  GeneratorT genType, std::string const& message,
+  GenT genType, std::string const& message,
   std::vector<std::string> const& command, std::string const& output) const
 {
   Gen().ParallelRegisterJobError();
@@ -1060,7 +1063,7 @@
 }
 
 bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess(
-  GeneratorT genType, ProcessResultT& result,
+  GenT genType, ProcessResultT& result,
   std::vector<std::string> const& command)
 {
   if (command.empty()) {
@@ -1116,13 +1119,17 @@
       wrk.Process_->start(handle->loop, [&wrk] { wrk.UVProcessFinished(); });
     }
   }
+
+  if (!wrk.Process_->IsStarted()) {
+    wrk.UVProcessFinished();
+  }
 }
 
 void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished()
 {
   {
     std::lock_guard<std::mutex> lock(ProcessMutex_);
-    if (Process_ && Process_->IsFinished()) {
+    if (Process_ && (Process_->IsFinished() || !Process_->IsStarted())) {
       Process_.reset();
     }
   }
@@ -1141,11 +1148,23 @@
   Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
                              "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
 
+  // Initialize libuv loop
+  uv_disable_stdio_inheritance();
+#ifdef CMAKE_UV_SIGNAL_HACK
+  UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>();
+#endif
+  UVLoop_ = cm::make_unique<uv_loop_t>();
+  uv_loop_init(UVLoop());
+
   // Initialize libuv asynchronous iteration request
   UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this);
 }
 
-cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() = default;
+cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic()
+{
+  // Close libuv loop
+  uv_loop_close(UVLoop());
+}
 
 bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile)
 {
@@ -1213,7 +1232,7 @@
 
   // -- Read info file
   if (!makefile->ReadListFile(InfoFile())) {
-    Log().ErrorFile(GeneratorT::GEN, InfoFile(), "File processing failed");
+    Log().ErrorFile(GenT::GEN, InfoFile(), "File processing failed");
     return false;
   }
 
@@ -1238,14 +1257,13 @@
     InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
   Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
   if (Base_.AutogenBuildDir.empty()) {
-    Log().ErrorFile(GeneratorT::GEN, InfoFile(),
-                    "Autogen build directory missing");
+    Log().ErrorFile(GenT::GEN, InfoFile(), "Autogen build directory missing");
     return false;
   }
   // include directory
   Base_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
   if (Base_.AutogenIncludeDir.empty()) {
-    Log().ErrorFile(GeneratorT::GEN, InfoFile(),
+    Log().ErrorFile(GenT::GEN, InfoFile(),
                     "Autogen include directory missing");
     return false;
   }
@@ -1253,7 +1271,7 @@
   // - Files
   SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
   if (SettingsFile_.empty()) {
-    Log().ErrorFile(GeneratorT::GEN, InfoFile(), "Settings file name missing");
+    Log().ErrorFile(GenT::GEN, InfoFile(), "Settings file name missing");
     return false;
   }
 
@@ -1270,9 +1288,8 @@
   Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
   Moc_.Enabled = !Moc().Executable.empty();
   if (Moc().Enabled) {
-    {
-      auto lst = InfoGetList("AM_MOC_SKIP");
-      Moc_.SkipList.insert(lst.begin(), lst.end());
+    for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) {
+      Moc_.SkipList.insert(std::move(sfl));
     }
     Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
     Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
@@ -1334,20 +1351,20 @@
           }
         } else {
           Log().ErrorFile(
-            GeneratorT::MOC, InfoFile(),
+            GenT::MOC, InfoFile(),
             "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
           return false;
         }
       }
       if (!error.empty()) {
-        Log().ErrorFile(GeneratorT::MOC, InfoFile(), error);
+        Log().ErrorFile(GenT::MOC, InfoFile(), error);
         return false;
       }
     }
     Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
     // Install moc predefs job
     if (!Moc().PredefsCmd.empty()) {
-      JobQueues_.MocPredefs.emplace_back(new JobMocPredefsT());
+      JobQueues_.MocPredefs.emplace_back(cm::make_unique<JobMocPredefsT>());
     }
   }
 
@@ -1355,9 +1372,8 @@
   Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
   Uic_.Enabled = !Uic().Executable.empty();
   if (Uic().Enabled) {
-    {
-      auto lst = InfoGetList("AM_UIC_SKIP");
-      Uic_.SkipList.insert(lst.begin(), lst.end());
+    for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) {
+      Uic_.SkipList.insert(std::move(sfl));
     }
     Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
     Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
@@ -1369,7 +1385,7 @@
         std::ostringstream ost;
         ost << "files/options lists sizes mismatch (" << sources.size() << "/"
             << options.size() << ")";
-        Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str());
+        Log().ErrorFile(GenT::UIC, InfoFile(), ost.str());
         return false;
       }
       auto fitEnd = sources.cend();
@@ -1383,53 +1399,44 @@
     }
   }
 
-  // Initialize source file jobs
+  // - Headers and sources
   {
-    std::hash<std::string> stringHash;
-    std::set<std::size_t> uniqueHeaders;
+    auto addHeader = [this](std::string&& hdr, bool moc, bool uic) {
+      this->JobQueues_.Headers.emplace_back(
+        cm::make_unique<JobParseT>(std::move(hdr), moc, uic, true));
+    };
+    auto addSource = [this](std::string&& src, bool moc, bool uic) {
+      this->JobQueues_.Sources.emplace_back(
+        cm::make_unique<JobParseT>(std::move(src), moc, uic, false));
+    };
 
-    // Add header jobs
+    // Add headers
     for (std::string& hdr : InfoGetList("AM_HEADERS")) {
-      const bool moc = !Moc().skipped(hdr);
-      const bool uic = !Uic().skipped(hdr);
-      if ((moc || uic) && uniqueHeaders.emplace(stringHash(hdr)).second) {
-        JobQueues_.Headers.emplace_back(
-          new JobParseT(std::move(hdr), moc, uic, true));
+      addHeader(std::move(hdr), true, true);
+    }
+    if (Moc().Enabled) {
+      for (std::string& hdr : InfoGetList("AM_MOC_HEADERS")) {
+        addHeader(std::move(hdr), true, false);
       }
     }
-    // Add source jobs
-    {
-      std::vector<std::string> sources = InfoGetList("AM_SOURCES");
-      // Add header(s) for the source file
-      for (std::string& src : sources) {
-        const bool srcMoc = !Moc().skipped(src);
-        const bool srcUic = !Uic().skipped(src);
-        if (!srcMoc && !srcUic) {
-          continue;
-        }
-        // Search for the default header file and a private header
-        {
-          std::array<std::string, 2> bases;
-          bases[0] = FileSys().SubDirPrefix(src);
-          bases[0] += FileSys().GetFilenameWithoutLastExtension(src);
-          bases[1] = bases[0];
-          bases[1] += "_p";
-          for (std::string const& headerBase : bases) {
-            std::string header;
-            if (Base().FindHeader(header, headerBase)) {
-              const bool moc = srcMoc && !Moc().skipped(header);
-              const bool uic = srcUic && !Uic().skipped(header);
-              if ((moc || uic) &&
-                  uniqueHeaders.emplace(stringHash(header)).second) {
-                JobQueues_.Headers.emplace_back(
-                  new JobParseT(std::move(header), moc, uic, true));
-              }
-            }
-          }
-        }
-        // Add source job
-        JobQueues_.Sources.emplace_back(
-          new JobParseT(std::move(src), srcMoc, srcUic));
+    if (Uic().Enabled) {
+      for (std::string& hdr : InfoGetList("AM_UIC_HEADERS")) {
+        addHeader(std::move(hdr), false, true);
+      }
+    }
+
+    // Add sources
+    for (std::string& src : InfoGetList("AM_SOURCES")) {
+      addSource(std::move(src), true, true);
+    }
+    if (Moc().Enabled) {
+      for (std::string& src : InfoGetList("AM_MOC_SOURCES")) {
+        addSource(std::move(src), true, false);
+      }
+    }
+    if (Uic().Enabled) {
+      for (std::string& src : InfoGetList("AM_UIC_SOURCES")) {
+        addSource(std::move(src), false, true);
       }
     }
   }
@@ -1690,8 +1697,7 @@
   // Only write if any setting changed
   if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) {
     if (Log().Verbose()) {
-      Log().Info(GeneratorT::GEN,
-                 "Writing settings file " + Quoted(SettingsFile_));
+      Log().Info(GenT::GEN, "Writing settings file " + Quoted(SettingsFile_));
     }
     // Compose settings file content
     std::string content;
@@ -1709,9 +1715,10 @@
       SettingAppend("uic", SettingsStringUic_);
     }
     // Write settings file
-    if (!FileSys().FileWrite(GeneratorT::GEN, SettingsFile_, content)) {
-      Log().ErrorFile(GeneratorT::GEN, SettingsFile_,
-                      "Settings file writing failed");
+    std::string error;
+    if (!FileSys().FileWrite(SettingsFile_, content, &error)) {
+      Log().ErrorFile(GenT::GEN, SettingsFile_,
+                      "Settings file writing failed. " + error);
       // Remove old settings file to trigger a full rebuild on the next run
       FileSys().FileRemove(SettingsFile_);
       RegisterJobError();
@@ -1722,7 +1729,9 @@
 void cmQtAutoGeneratorMocUic::CreateDirectories()
 {
   // Create AUTOGEN include directory
-  if (!FileSys().MakeDirectory(GeneratorT::GEN, Base().AutogenIncludeDir)) {
+  if (!FileSys().MakeDirectory(Base().AutogenIncludeDir)) {
+    Log().ErrorFile(GenT::GEN, Base().AutogenIncludeDir,
+                    "Could not create directory.");
     RegisterJobError();
   }
 }
@@ -1802,7 +1811,7 @@
 {
   bool const jobProcessed(jobHandle);
   if (jobProcessed) {
-    jobHandle.reset(nullptr);
+    jobHandle.reset();
   }
   {
     std::unique_lock<std::mutex> jobsLock(JobsMutex_);
@@ -1882,7 +1891,7 @@
                        "- add a directory prefix to a \"<NAME>.moc\" include "
                        "(e.g \"sub/<NAME>.moc\")\n"
                        "- rename the source file(s)\n";
-              Log().Error(GeneratorT::MOC, error);
+              Log().Error(GenT::MOC, error);
               RegisterJobError();
             }
             // Do not push this job in since the included moc file already
@@ -1932,7 +1941,7 @@
             "(e.g \"sub/ui_<NAME>.h\")\n"
             "- rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
             "include(s)\n";
-          Log().Error(GeneratorT::UIC, error);
+          Log().Error(GenT::UIC, error);
           RegisterJobError();
         }
         // Do not push this job in since the uic file already
@@ -2019,18 +2028,19 @@
       if (FileSys().FileDiffers(compAbs, content)) {
         // Actually write mocs compilation file
         if (Log().Verbose()) {
-          Log().Info(GeneratorT::MOC, "Generating MOC compilation " + compAbs);
+          Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs);
         }
-        if (!FileSys().FileWrite(GeneratorT::MOC, compAbs, content)) {
-          Log().ErrorFile(GeneratorT::MOC, compAbs,
-                          "mocs compilation file writing failed");
+        std::string error;
+        if (!FileSys().FileWrite(compAbs, content, &error)) {
+          Log().ErrorFile(GenT::MOC, compAbs,
+                          "mocs compilation file writing failed. " + error);
           RegisterJobError();
           return;
         }
       } else if (MocAutoFileUpdated_) {
         // Only touch mocs compilation file
         if (Log().Verbose()) {
-          Log().Info(GeneratorT::MOC, "Touching mocs compilation " + compAbs);
+          Log().Info(GenT::MOC, "Touching mocs compilation " + compAbs);
         }
         FileSys().Touch(compAbs);
       }
diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h
index c22df29..27d73a7 100644
--- a/Source/cmQtAutoGeneratorMocUic.h
+++ b/Source/cmQtAutoGeneratorMocUic.h
@@ -8,6 +8,7 @@
 #include "cmQtAutoGen.h"
 #include "cmQtAutoGenerator.h"
 #include "cmUVHandlePtr.h"
+#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
 #include "cm_uv.h"
 #include "cmsys/RegularExpression.hxx"
 
@@ -20,6 +21,7 @@
 #include <set>
 #include <string>
 #include <thread>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -133,7 +135,7 @@
     std::string CompFileAbs;
     std::string PredefsFileRel;
     std::string PredefsFileAbs;
-    std::set<std::string> SkipList;
+    std::unordered_set<std::string> SkipList;
     std::vector<std::string> IncludePaths;
     std::vector<std::string> Includes;
     std::vector<std::string> Definitions;
@@ -164,7 +166,7 @@
     bool Enabled = false;
     bool SettingsChanged = false;
     std::string Executable;
-    std::set<std::string> SkipList;
+    std::unordered_set<std::string> SkipList;
     std::vector<std::string> TargetOptions;
     std::map<std::string, std::vector<std::string>> Options;
     std::vector<std::string> SearchPaths;
@@ -186,15 +188,8 @@
     virtual void Process(WorkerT& wrk) = 0;
   };
 
-  /// @brief Deleter for classes derived from Job
-  ///
-  struct JobDeleterT
-  {
-    void operator()(JobT* job);
-  };
-
   // Job management types
-  typedef std::unique_ptr<JobT, JobDeleterT> JobHandleT;
+  typedef std::unique_ptr<JobT> JobHandleT;
   typedef std::deque<JobHandleT> JobQueueT;
 
   /// @brief Parse source job
@@ -321,22 +316,22 @@
     const UicSettingsT& Uic() const { return Gen_->Uic(); }
 
     // -- Log info
-    void LogInfo(GeneratorT genType, std::string const& message) const;
+    void LogInfo(GenT genType, std::string const& message) const;
     // -- Log warning
-    void LogWarning(GeneratorT genType, std::string const& message) const;
-    void LogFileWarning(GeneratorT genType, std::string const& filename,
+    void LogWarning(GenT genType, std::string const& message) const;
+    void LogFileWarning(GenT genType, std::string const& filename,
                         std::string const& message) const;
     // -- Log error
-    void LogError(GeneratorT genType, std::string const& message) const;
-    void LogFileError(GeneratorT genType, std::string const& filename,
+    void LogError(GenT genType, std::string const& message) const;
+    void LogFileError(GenT genType, std::string const& filename,
                       std::string const& message) const;
-    void LogCommandError(GeneratorT genType, std::string const& message,
+    void LogCommandError(GenT genType, std::string const& message,
                          std::vector<std::string> const& command,
                          std::string const& output) const;
 
     // -- External processes
     /// @brief Verbose logging version
-    bool RunProcess(GeneratorT genType, ProcessResultT& result,
+    bool RunProcess(GenT genType, ProcessResultT& result,
                     std::vector<std::string> const& command);
 
   private:
@@ -393,6 +388,12 @@
   void ParallelMocAutoUpdated();
 
 private:
+  // -- Utility accessors
+  Logger& Log() { return Logger_; }
+  FileSystem& FileSys() { return FileSys_; }
+  // -- libuv loop accessors
+  uv_loop_t* UVLoop() { return UVLoop_.get(); }
+  cm::uv_async_ptr& UVRequest() { return UVRequest_; }
   // -- Abstract processing interface
   bool Init(cmMakefile* makefile) override;
   bool Process() override;
@@ -413,11 +414,19 @@
   void MocGenerateCompilation();
 
 private:
+  // -- Utility
+  Logger Logger_;
+  FileSystem FileSys_;
   // -- Settings
   BaseSettingsT Base_;
   MocSettingsT Moc_;
   UicSettingsT Uic_;
-  // -- Progress
+  // -- libuv loop
+#ifdef CMAKE_UV_SIGNAL_HACK
+  std::unique_ptr<cmUVSignalHackRAII> UVHackRAII_;
+#endif
+  std::unique_ptr<uv_loop_t> UVLoop_;
+  cm::uv_async_ptr UVRequest_;
   StageT Stage_ = StageT::SETTINGS_READ;
   // -- Job queues
   std::mutex JobsMutex_;
diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx
deleted file mode 100644
index 021a15f..0000000
--- a/Source/cmQtAutoGeneratorRcc.cxx
+++ /dev/null
@@ -1,672 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmQtAutoGeneratorRcc.h"
-#include "cmQtAutoGen.h"
-
-#include "cmAlgorithms.h"
-#include "cmCryptoHash.h"
-#include "cmFileLockResult.h"
-#include "cmMakefile.h"
-#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-
-// -- Class methods
-
-cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc()
-{
-  // Initialize libuv asynchronous iteration request
-  UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this);
-}
-
-cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() = default;
-
-bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile)
-{
-  // -- Utility lambdas
-  auto InfoGet = [makefile](std::string const& key) {
-    return makefile->GetSafeDefinition(key);
-  };
-  auto InfoGetList =
-    [makefile](std::string const& key) -> std::vector<std::string> {
-    std::vector<std::string> list;
-    cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
-    return list;
-  };
-  auto InfoGetConfig = [makefile,
-                        this](std::string const& key) -> std::string {
-    const char* valueConf = nullptr;
-    {
-      std::string keyConf = key;
-      keyConf += '_';
-      keyConf += InfoConfig();
-      valueConf = makefile->GetDefinition(keyConf);
-    }
-    if (valueConf == nullptr) {
-      return makefile->GetSafeDefinition(key);
-    }
-    return std::string(valueConf);
-  };
-  auto InfoGetConfigList =
-    [&InfoGetConfig](std::string const& key) -> std::vector<std::string> {
-    std::vector<std::string> list;
-    cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
-    return list;
-  };
-
-  // -- Read info file
-  if (!makefile->ReadListFile(InfoFile())) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "File processing failed");
-    return false;
-  }
-
-  // - Configurations
-  Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
-  MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
-
-  // - Directories
-  AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
-  if (AutogenBuildDir_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Build directory empty");
-    return false;
-  }
-
-  IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
-  if (IncludeDir_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Include directory empty");
-    return false;
-  }
-
-  // - Rcc executable
-  RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
-  RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
-
-  // - Job
-  LockFile_ = InfoGet("ARCC_LOCK_FILE");
-  QrcFile_ = InfoGet("ARCC_SOURCE");
-  QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
-  QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
-  RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM");
-  RccFileName_ = InfoGet("ARCC_OUTPUT_NAME");
-  Options_ = InfoGetConfigList("ARCC_OPTIONS");
-  Inputs_ = InfoGetList("ARCC_INPUTS");
-
-  // - Settings file
-  SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
-
-  // - Validity checks
-  if (LockFile_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Lock file name missing");
-    return false;
-  }
-  if (SettingsFile_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Settings file name missing");
-    return false;
-  }
-  if (AutogenBuildDir_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(),
-                    "Autogen build directory missing");
-    return false;
-  }
-  if (RccExecutable_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc executable missing");
-    return false;
-  }
-  if (QrcFile_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc input file missing");
-    return false;
-  }
-  if (RccFileName_.empty()) {
-    Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc output file missing");
-    return false;
-  }
-
-  // Init derived information
-  // ------------------------
-
-  RccFilePublic_ = AutogenBuildDir_;
-  RccFilePublic_ += '/';
-  RccFilePublic_ += RccPathChecksum_;
-  RccFilePublic_ += '/';
-  RccFilePublic_ += RccFileName_;
-
-  // Compute rcc output file name
-  if (IsMultiConfig()) {
-    RccFileOutput_ = IncludeDir_;
-    RccFileOutput_ += '/';
-    RccFileOutput_ += MultiConfigOutput();
-  } else {
-    RccFileOutput_ = RccFilePublic_;
-  }
-
-  return true;
-}
-
-bool cmQtAutoGeneratorRcc::Process()
-{
-  // Run libuv event loop
-  UVRequest().send();
-  if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
-    if (Error_) {
-      return false;
-    }
-  } else {
-    return false;
-  }
-  return true;
-}
-
-void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle)
-{
-  reinterpret_cast<cmQtAutoGeneratorRcc*>(handle->data)->PollStage();
-}
-
-void cmQtAutoGeneratorRcc::PollStage()
-{
-  switch (Stage_) {
-    // -- Initialize
-    case StageT::SETTINGS_READ:
-      if (SettingsFileRead()) {
-        SetStage(StageT::TEST_QRC_RCC_FILES);
-      } else {
-        SetStage(StageT::FINISH);
-      }
-      break;
-
-    // -- Change detection
-    case StageT::TEST_QRC_RCC_FILES:
-      if (TestQrcRccFiles()) {
-        SetStage(StageT::GENERATE);
-      } else {
-        SetStage(StageT::TEST_RESOURCES_READ);
-      }
-      break;
-    case StageT::TEST_RESOURCES_READ:
-      if (TestResourcesRead()) {
-        SetStage(StageT::TEST_RESOURCES);
-      }
-      break;
-    case StageT::TEST_RESOURCES:
-      if (TestResources()) {
-        SetStage(StageT::GENERATE);
-      } else {
-        SetStage(StageT::TEST_INFO_FILE);
-      }
-      break;
-    case StageT::TEST_INFO_FILE:
-      TestInfoFile();
-      SetStage(StageT::GENERATE_WRAPPER);
-      break;
-
-    // -- Generation
-    case StageT::GENERATE:
-      GenerateParentDir();
-      SetStage(StageT::GENERATE_RCC);
-      break;
-    case StageT::GENERATE_RCC:
-      if (GenerateRcc()) {
-        SetStage(StageT::GENERATE_WRAPPER);
-      }
-      break;
-    case StageT::GENERATE_WRAPPER:
-      GenerateWrapper();
-      SetStage(StageT::SETTINGS_WRITE);
-      break;
-
-    // -- Finalize
-    case StageT::SETTINGS_WRITE:
-      SettingsFileWrite();
-      SetStage(StageT::FINISH);
-      break;
-    case StageT::FINISH:
-      // Clear all libuv handles
-      UVRequest().reset();
-      // Set highest END stage manually
-      Stage_ = StageT::END;
-      break;
-    case StageT::END:
-      break;
-  }
-}
-
-void cmQtAutoGeneratorRcc::SetStage(StageT stage)
-{
-  if (Error_) {
-    stage = StageT::FINISH;
-  }
-  // Only allow to increase the stage
-  if (Stage_ < stage) {
-    Stage_ = stage;
-    UVRequest().send();
-  }
-}
-
-std::string cmQtAutoGeneratorRcc::MultiConfigOutput() const
-{
-  static std::string const suffix = "_CMAKE_";
-  std::string res;
-  res += RccPathChecksum_;
-  res += '/';
-  res += AppendFilenameSuffix(RccFileName_, suffix);
-  return res;
-}
-
-bool cmQtAutoGeneratorRcc::SettingsFileRead()
-{
-  // Compose current settings strings
-  {
-    cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
-    std::string const sep(" ~~~ ");
-    {
-      std::string str;
-      str += RccExecutable_;
-      str += sep;
-      str += cmJoin(RccListOptions_, ";");
-      str += sep;
-      str += QrcFile_;
-      str += sep;
-      str += RccPathChecksum_;
-      str += sep;
-      str += RccFileName_;
-      str += sep;
-      str += cmJoin(Options_, ";");
-      str += sep;
-      str += cmJoin(Inputs_, ";");
-      str += sep;
-      SettingsString_ = crypt.HashString(str);
-    }
-  }
-
-  // Make sure the settings file exists
-  if (!FileSys().FileExists(SettingsFile_, true)) {
-    // Touch the settings file to make sure it exists
-    FileSys().Touch(SettingsFile_, true);
-  }
-
-  // Lock the lock file
-  {
-    // Make sure the lock file exists
-    if (!FileSys().FileExists(LockFile_, true)) {
-      if (!FileSys().Touch(LockFile_, true)) {
-        Log().ErrorFile(GeneratorT::RCC, LockFile_,
-                        "Lock file creation failed");
-        Error_ = true;
-        return false;
-      }
-    }
-    // Lock the lock file
-    cmFileLockResult lockResult =
-      LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
-    if (!lockResult.IsOk()) {
-      Log().ErrorFile(GeneratorT::RCC, LockFile_,
-                      "File lock failed: " + lockResult.GetOutputMessage());
-      Error_ = true;
-      return false;
-    }
-  }
-
-  // Read old settings
-  {
-    std::string content;
-    if (FileSys().FileRead(content, SettingsFile_)) {
-      SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc"));
-      // In case any setting changed clear the old settings file.
-      // This triggers a full rebuild on the next run if the current
-      // build is aborted before writing the current settings in the end.
-      if (SettingsChanged_) {
-        FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, "");
-      }
-    } else {
-      SettingsChanged_ = true;
-    }
-  }
-
-  return true;
-}
-
-void cmQtAutoGeneratorRcc::SettingsFileWrite()
-{
-  // Only write if any setting changed
-  if (SettingsChanged_) {
-    if (Log().Verbose()) {
-      Log().Info(GeneratorT::RCC,
-                 "Writing settings file " + Quoted(SettingsFile_));
-    }
-    // Write settings file
-    std::string content = "rcc:";
-    content += SettingsString_;
-    content += '\n';
-    if (!FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, content)) {
-      Log().ErrorFile(GeneratorT::RCC, SettingsFile_,
-                      "Settings file writing failed");
-      // Remove old settings file to trigger a full rebuild on the next run
-      FileSys().FileRemove(SettingsFile_);
-      Error_ = true;
-    }
-  }
-
-  // Unlock the lock file
-  LockFileLock_.Release();
-}
-
-bool cmQtAutoGeneratorRcc::TestQrcRccFiles()
-{
-  // Do basic checks if rcc generation is required
-
-  // Test if the rcc output file exists
-  if (!FileSys().FileExists(RccFileOutput_)) {
-    if (Log().Verbose()) {
-      std::string reason = "Generating ";
-      reason += Quoted(RccFileOutput_);
-      reason += " from its source file ";
-      reason += Quoted(QrcFile_);
-      reason += " because it doesn't exist";
-      Log().Info(GeneratorT::RCC, reason);
-    }
-    Generate_ = true;
-    return Generate_;
-  }
-
-  // Test if the settings changed
-  if (SettingsChanged_) {
-    if (Log().Verbose()) {
-      std::string reason = "Generating ";
-      reason += Quoted(RccFileOutput_);
-      reason += " from ";
-      reason += Quoted(QrcFile_);
-      reason += " because the RCC settings changed";
-      Log().Info(GeneratorT::RCC, reason);
-    }
-    Generate_ = true;
-    return Generate_;
-  }
-
-  // Test if the rcc output file is older than the .qrc file
-  {
-    bool isOlder = false;
-    {
-      std::string error;
-      isOlder = FileSys().FileIsOlderThan(RccFileOutput_, QrcFile_, &error);
-      if (!error.empty()) {
-        Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
-        Error_ = true;
-      }
-    }
-    if (isOlder) {
-      if (Log().Verbose()) {
-        std::string reason = "Generating ";
-        reason += Quoted(RccFileOutput_);
-        reason += " because it is older than ";
-        reason += Quoted(QrcFile_);
-        Log().Info(GeneratorT::RCC, reason);
-      }
-      Generate_ = true;
-    }
-  }
-
-  return Generate_;
-}
-
-bool cmQtAutoGeneratorRcc::TestResourcesRead()
-{
-  if (!Inputs_.empty()) {
-    // Inputs are known already
-    return true;
-  }
-
-  if (!RccListOptions_.empty()) {
-    // Start a rcc list process and parse the output
-    if (Process_) {
-      // Process is running already
-      if (Process_->IsFinished()) {
-        // Process is finished
-        if (!ProcessResult_.error()) {
-          // Process success
-          std::string parseError;
-          if (!RccListParseOutput(ProcessResult_.StdOut, ProcessResult_.StdErr,
-                                  Inputs_, parseError)) {
-            Log().ErrorFile(GeneratorT::RCC, QrcFile_, parseError);
-            Error_ = true;
-          }
-        } else {
-          Log().ErrorFile(GeneratorT::RCC, QrcFile_,
-                          ProcessResult_.ErrorMessage);
-          Error_ = true;
-        }
-        // Clean up
-        Process_.reset();
-        ProcessResult_.reset();
-      } else {
-        // Process is not finished, yet.
-        return false;
-      }
-    } else {
-      // Start a new process
-      // rcc prints relative entry paths when started in the directory of the
-      // qrc file with a pathless qrc file name argument.
-      // This is important because on Windows absolute paths returned by rcc
-      // might contain bad multibyte characters when the qrc file path
-      // contains non-ASCII pcharacters.
-      std::vector<std::string> cmd;
-      cmd.push_back(RccExecutable_);
-      cmd.insert(cmd.end(), RccListOptions_.begin(), RccListOptions_.end());
-      cmd.push_back(QrcFileName_);
-      // We're done here if the process fails to start
-      return !StartProcess(QrcFileDir_, cmd, false);
-    }
-  } else {
-    // rcc does not support the --list command.
-    // Read the qrc file content and parse it.
-    std::string qrcContent;
-    if (FileSys().FileRead(GeneratorT::RCC, qrcContent, QrcFile_)) {
-      RccListParseContent(qrcContent, Inputs_);
-    }
-  }
-
-  if (!Inputs_.empty()) {
-    // Convert relative paths to absolute paths
-    RccListConvertFullPath(QrcFileDir_, Inputs_);
-  }
-
-  return true;
-}
-
-bool cmQtAutoGeneratorRcc::TestResources()
-{
-  if (Inputs_.empty()) {
-    return true;
-  }
-  {
-    std::string error;
-    for (std::string const& resFile : Inputs_) {
-      // Check if the resource file exists
-      if (!FileSys().FileExists(resFile)) {
-        error = "Could not find the resource file\n  ";
-        error += Quoted(resFile);
-        error += '\n';
-        Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
-        Error_ = true;
-        break;
-      }
-      // Check if the resource file is newer than the build file
-      if (FileSys().FileIsOlderThan(RccFileOutput_, resFile, &error)) {
-        if (Log().Verbose()) {
-          std::string reason = "Generating ";
-          reason += Quoted(RccFileOutput_);
-          reason += " from ";
-          reason += Quoted(QrcFile_);
-          reason += " because it is older than ";
-          reason += Quoted(resFile);
-          Log().Info(GeneratorT::RCC, reason);
-        }
-        Generate_ = true;
-        break;
-      }
-      // Print error and break on demand
-      if (!error.empty()) {
-        Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
-        Error_ = true;
-        break;
-      }
-    }
-  }
-
-  return Generate_;
-}
-
-void cmQtAutoGeneratorRcc::TestInfoFile()
-{
-  // Test if the rcc output file is older than the info file
-  {
-    bool isOlder = false;
-    {
-      std::string error;
-      isOlder = FileSys().FileIsOlderThan(RccFileOutput_, InfoFile(), &error);
-      if (!error.empty()) {
-        Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
-        Error_ = true;
-      }
-    }
-    if (isOlder) {
-      if (Log().Verbose()) {
-        std::string reason = "Touching ";
-        reason += Quoted(RccFileOutput_);
-        reason += " because it is older than ";
-        reason += Quoted(InfoFile());
-        Log().Info(GeneratorT::RCC, reason);
-      }
-      // Touch build file
-      FileSys().Touch(RccFileOutput_);
-      BuildFileChanged_ = true;
-    }
-  }
-}
-
-void cmQtAutoGeneratorRcc::GenerateParentDir()
-{
-  // Make sure the parent directory exists
-  if (!FileSys().MakeParentDirectory(GeneratorT::RCC, RccFileOutput_)) {
-    Error_ = true;
-  }
-}
-
-/**
- * @return True when finished
- */
-bool cmQtAutoGeneratorRcc::GenerateRcc()
-{
-  if (!Generate_) {
-    // Nothing to do
-    return true;
-  }
-
-  if (Process_) {
-    // Process is running already
-    if (Process_->IsFinished()) {
-      // Process is finished
-      if (!ProcessResult_.error()) {
-        // Rcc process success
-        // Print rcc output
-        if (!ProcessResult_.StdOut.empty()) {
-          Log().Info(GeneratorT::RCC, ProcessResult_.StdOut);
-        }
-        BuildFileChanged_ = true;
-      } else {
-        // Rcc process failed
-        {
-          std::string emsg = "The rcc process failed to compile\n  ";
-          emsg += Quoted(QrcFile_);
-          emsg += "\ninto\n  ";
-          emsg += Quoted(RccFileOutput_);
-          if (ProcessResult_.error()) {
-            emsg += "\n";
-            emsg += ProcessResult_.ErrorMessage;
-          }
-          Log().ErrorCommand(GeneratorT::RCC, emsg, Process_->Setup().Command,
-                             ProcessResult_.StdOut);
-        }
-        FileSys().FileRemove(RccFileOutput_);
-        Error_ = true;
-      }
-      // Clean up
-      Process_.reset();
-      ProcessResult_.reset();
-    } else {
-      // Process is not finished, yet.
-      return false;
-    }
-  } else {
-    // Start a rcc process
-    std::vector<std::string> cmd;
-    cmd.push_back(RccExecutable_);
-    cmd.insert(cmd.end(), Options_.begin(), Options_.end());
-    cmd.emplace_back("-o");
-    cmd.push_back(RccFileOutput_);
-    cmd.push_back(QrcFile_);
-    // We're done here if the process fails to start
-    return !StartProcess(AutogenBuildDir_, cmd, true);
-  }
-
-  return true;
-}
-
-void cmQtAutoGeneratorRcc::GenerateWrapper()
-{
-  // Generate a wrapper source file on demand
-  if (IsMultiConfig()) {
-    // Wrapper file content
-    std::string content;
-    content += "// This is an autogenerated configuration wrapper file.\n";
-    content += "// Changes will be overwritten.\n";
-    content += "#include <";
-    content += MultiConfigOutput();
-    content += ">\n";
-
-    // Write content to file
-    if (FileSys().FileDiffers(RccFilePublic_, content)) {
-      // Write new wrapper file
-      if (Log().Verbose()) {
-        Log().Info(GeneratorT::RCC,
-                   "Generating RCC wrapper file " + RccFilePublic_);
-      }
-      if (!FileSys().FileWrite(GeneratorT::RCC, RccFilePublic_, content)) {
-        Log().ErrorFile(GeneratorT::RCC, RccFilePublic_,
-                        "RCC wrapper file writing failed");
-        Error_ = true;
-      }
-    } else if (BuildFileChanged_) {
-      // Just touch the wrapper file
-      if (Log().Verbose()) {
-        Log().Info(GeneratorT::RCC,
-                   "Touching RCC wrapper file " + RccFilePublic_);
-      }
-      FileSys().Touch(RccFilePublic_);
-    }
-  }
-}
-
-bool cmQtAutoGeneratorRcc::StartProcess(
-  std::string const& workingDirectory, std::vector<std::string> const& command,
-  bool mergedOutput)
-{
-  // Log command
-  if (Log().Verbose()) {
-    std::string msg = "Running command:\n";
-    msg += QuotedCommand(command);
-    msg += '\n';
-    Log().Info(GeneratorT::RCC, msg);
-  }
-
-  // Create process handler
-  Process_ = cm::make_unique<ReadOnlyProcessT>();
-  Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory);
-  // Start process
-  if (!Process_->start(UVLoop(), [this] { UVRequest().send(); })) {
-    Log().ErrorFile(GeneratorT::RCC, QrcFile_, ProcessResult_.ErrorMessage);
-    Error_ = true;
-    // Clean up
-    Process_.reset();
-    ProcessResult_.reset();
-    return false;
-  }
-  return true;
-}
diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h
deleted file mode 100644
index 1ec1c4a..0000000
--- a/Source/cmQtAutoGeneratorRcc.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#ifndef cmQtAutoGeneratorRcc_h
-#define cmQtAutoGeneratorRcc_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include "cmFileLock.h"
-#include "cmQtAutoGenerator.h"
-#include "cm_uv.h"
-
-#include <string>
-#include <vector>
-
-class cmMakefile;
-
-// @brief AUTORCC generator
-class cmQtAutoGeneratorRcc : public cmQtAutoGenerator
-{
-public:
-  cmQtAutoGeneratorRcc();
-  ~cmQtAutoGeneratorRcc() override;
-
-  cmQtAutoGeneratorRcc(cmQtAutoGeneratorRcc const&) = delete;
-  cmQtAutoGeneratorRcc& operator=(cmQtAutoGeneratorRcc const&) = delete;
-
-private:
-  // -- Types
-
-  /// @brief Processing stage
-  enum class StageT : unsigned char
-  {
-    SETTINGS_READ,
-    TEST_QRC_RCC_FILES,
-    TEST_RESOURCES_READ,
-    TEST_RESOURCES,
-    TEST_INFO_FILE,
-    GENERATE,
-    GENERATE_RCC,
-    GENERATE_WRAPPER,
-    SETTINGS_WRITE,
-    FINISH,
-    END
-  };
-
-  // -- Abstract processing interface
-  bool Init(cmMakefile* makefile) override;
-  bool Process() override;
-  // -- Process stage
-  static void UVPollStage(uv_async_t* handle);
-  void PollStage();
-  void SetStage(StageT stage);
-  // -- Settings file
-  bool SettingsFileRead();
-  void SettingsFileWrite();
-  // -- Tests
-  bool TestQrcRccFiles();
-  bool TestResourcesRead();
-  bool TestResources();
-  void TestInfoFile();
-  // -- Generation
-  void GenerateParentDir();
-  bool GenerateRcc();
-  void GenerateWrapper();
-
-  // -- Utility
-  bool IsMultiConfig() const { return MultiConfig_; }
-  std::string MultiConfigOutput() const;
-  bool StartProcess(std::string const& workingDirectory,
-                    std::vector<std::string> const& command,
-                    bool mergedOutput);
-
-private:
-  // -- Config settings
-  bool MultiConfig_ = false;
-  // -- Directories
-  std::string AutogenBuildDir_;
-  std::string IncludeDir_;
-  // -- Qt environment
-  std::string RccExecutable_;
-  std::vector<std::string> RccListOptions_;
-  // -- Job
-  std::string LockFile_;
-  cmFileLock LockFileLock_;
-  std::string QrcFile_;
-  std::string QrcFileName_;
-  std::string QrcFileDir_;
-  std::string RccPathChecksum_;
-  std::string RccFileName_;
-  std::string RccFileOutput_;
-  std::string RccFilePublic_;
-  std::vector<std::string> Options_;
-  std::vector<std::string> Inputs_;
-  // -- Subprocess
-  ProcessResultT ProcessResult_;
-  std::unique_ptr<ReadOnlyProcessT> Process_;
-  // -- Settings file
-  std::string SettingsFile_;
-  std::string SettingsString_;
-  bool SettingsChanged_ = false;
-  // -- libuv loop
-  StageT Stage_ = StageT::SETTINGS_READ;
-  bool Error_ = false;
-  bool Generate_ = false;
-  bool BuildFileChanged_ = false;
-};
-
-#endif
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
new file mode 100644
index 0000000..e58324d
--- /dev/null
+++ b/Source/cmQtAutoRcc.cxx
@@ -0,0 +1,516 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmQtAutoRcc.h"
+#include "cmQtAutoGen.h"
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmDuration.h"
+#include "cmFileLockResult.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmSystemTools.h"
+
+// -- Class methods
+
+cmQtAutoRcc::cmQtAutoRcc() = default;
+
+cmQtAutoRcc::~cmQtAutoRcc() = default;
+
+bool cmQtAutoRcc::Init(cmMakefile* makefile)
+{
+  // -- Utility lambdas
+  auto InfoGet = [makefile](std::string const& key) {
+    return makefile->GetSafeDefinition(key);
+  };
+  auto InfoGetList =
+    [makefile](std::string const& key) -> std::vector<std::string> {
+    std::vector<std::string> list;
+    cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
+    return list;
+  };
+  auto InfoGetConfig = [makefile,
+                        this](std::string const& key) -> std::string {
+    const char* valueConf = nullptr;
+    {
+      std::string keyConf = key;
+      keyConf += '_';
+      keyConf += InfoConfig();
+      valueConf = makefile->GetDefinition(keyConf);
+    }
+    if (valueConf == nullptr) {
+      return makefile->GetSafeDefinition(key);
+    }
+    return std::string(valueConf);
+  };
+  auto InfoGetConfigList =
+    [&InfoGetConfig](std::string const& key) -> std::vector<std::string> {
+    std::vector<std::string> list;
+    cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
+    return list;
+  };
+
+  // -- Read info file
+  if (!makefile->ReadListFile(InfoFile())) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed.");
+    return false;
+  }
+
+  // - Configurations
+  Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
+  MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
+
+  // - Directories
+  AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
+  if (AutogenBuildDir_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty.");
+    return false;
+  }
+
+  IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
+  if (IncludeDir_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty.");
+    return false;
+  }
+
+  // - Rcc executable
+  RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
+  RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
+
+  // - Job
+  LockFile_ = InfoGet("ARCC_LOCK_FILE");
+  QrcFile_ = InfoGet("ARCC_SOURCE");
+  QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
+  QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
+  RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM");
+  RccFileName_ = InfoGet("ARCC_OUTPUT_NAME");
+  Options_ = InfoGetConfigList("ARCC_OPTIONS");
+  Inputs_ = InfoGetList("ARCC_INPUTS");
+
+  // - Settings file
+  SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
+
+  // - Validity checks
+  if (LockFile_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing.");
+    return false;
+  }
+  if (SettingsFile_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing.");
+    return false;
+  }
+  if (AutogenBuildDir_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing.");
+    return false;
+  }
+  if (RccExecutable_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing.");
+    return false;
+  }
+  if (QrcFile_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing.");
+    return false;
+  }
+  if (RccFileName_.empty()) {
+    Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing.");
+    return false;
+  }
+
+  // Init derived information
+  // ------------------------
+
+  RccFilePublic_ = AutogenBuildDir_;
+  RccFilePublic_ += '/';
+  RccFilePublic_ += RccPathChecksum_;
+  RccFilePublic_ += '/';
+  RccFilePublic_ += RccFileName_;
+
+  // Compute rcc output file name
+  if (IsMultiConfig()) {
+    RccFileOutput_ = IncludeDir_;
+    RccFileOutput_ += '/';
+    RccFileOutput_ += MultiConfigOutput();
+  } else {
+    RccFileOutput_ = RccFilePublic_;
+  }
+
+  return true;
+}
+
+bool cmQtAutoRcc::Process()
+{
+  if (!SettingsFileRead()) {
+    return false;
+  }
+
+  // Test if the rcc output needs to be regenerated
+  bool generate = false;
+  if (!TestQrcRccFiles(generate)) {
+    return false;
+  }
+  if (!generate && !TestResources(generate)) {
+    return false;
+  }
+  // Generate on demand
+  if (generate) {
+    if (!GenerateRcc()) {
+      return false;
+    }
+  } else {
+    // Test if the info file is newer than the output file
+    if (!TestInfoFile()) {
+      return false;
+    }
+  }
+
+  if (!GenerateWrapper()) {
+    return false;
+  }
+
+  return SettingsFileWrite();
+}
+
+std::string cmQtAutoRcc::MultiConfigOutput() const
+{
+  static std::string const suffix = "_CMAKE_";
+  std::string res;
+  res += RccPathChecksum_;
+  res += '/';
+  res += AppendFilenameSuffix(RccFileName_, suffix);
+  return res;
+}
+
+bool cmQtAutoRcc::SettingsFileRead()
+{
+  // Compose current settings strings
+  {
+    cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
+    std::string const sep(" ~~~ ");
+    {
+      std::string str;
+      str += RccExecutable_;
+      str += sep;
+      str += cmJoin(RccListOptions_, ";");
+      str += sep;
+      str += QrcFile_;
+      str += sep;
+      str += RccPathChecksum_;
+      str += sep;
+      str += RccFileName_;
+      str += sep;
+      str += cmJoin(Options_, ";");
+      str += sep;
+      str += cmJoin(Inputs_, ";");
+      str += sep;
+      SettingsString_ = crypt.HashString(str);
+    }
+  }
+
+  // Make sure the settings file exists
+  if (!cmSystemTools::FileExists(SettingsFile_, true)) {
+    // Touch the settings file to make sure it exists
+    if (!cmSystemTools::Touch(SettingsFile_, true)) {
+      Log().ErrorFile(GenT::RCC, SettingsFile_,
+                      "Settings file creation failed.");
+      return false;
+    }
+  }
+
+  // Lock the lock file
+  {
+    // Make sure the lock file exists
+    if (!cmSystemTools::FileExists(LockFile_, true)) {
+      if (!cmSystemTools::Touch(LockFile_, true)) {
+        Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed.");
+        return false;
+      }
+    }
+    // Lock the lock file
+    cmFileLockResult lockResult =
+      LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
+    if (!lockResult.IsOk()) {
+      Log().ErrorFile(GenT::RCC, LockFile_,
+                      "File lock failed: " + lockResult.GetOutputMessage());
+      return false;
+    }
+  }
+
+  // Read old settings
+  {
+    std::string content;
+    if (FileRead(content, SettingsFile_)) {
+      SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc"));
+      // In case any setting changed clear the old settings file.
+      // This triggers a full rebuild on the next run if the current
+      // build is aborted before writing the current settings in the end.
+      if (SettingsChanged_) {
+        std::string error;
+        if (!FileWrite(SettingsFile_, "", &error)) {
+          Log().ErrorFile(GenT::RCC, SettingsFile_,
+                          "Settings file clearing failed. " + error);
+          return false;
+        }
+      }
+    } else {
+      SettingsChanged_ = true;
+    }
+  }
+
+  return true;
+}
+
+bool cmQtAutoRcc::SettingsFileWrite()
+{
+  // Only write if any setting changed
+  if (SettingsChanged_) {
+    if (Log().Verbose()) {
+      Log().Info(GenT::RCC, "Writing settings file " + Quoted(SettingsFile_));
+    }
+    // Write settings file
+    std::string content = "rcc:";
+    content += SettingsString_;
+    content += '\n';
+    std::string error;
+    if (!FileWrite(SettingsFile_, content, &error)) {
+      Log().ErrorFile(GenT::RCC, SettingsFile_,
+                      "Settings file writing failed. " + error);
+      // Remove old settings file to trigger a full rebuild on the next run
+      cmSystemTools::RemoveFile(SettingsFile_);
+      return false;
+    }
+  }
+
+  // Unlock the lock file
+  LockFileLock_.Release();
+  return true;
+}
+
+/// Do basic checks if rcc generation is required
+bool cmQtAutoRcc::TestQrcRccFiles(bool& generate)
+{
+  // Test if the rcc input file exists
+  if (!QrcFileTime_.Load(QrcFile_)) {
+    std::string error;
+    error = "The resources file ";
+    error += Quoted(QrcFile_);
+    error += " does not exist";
+    Log().ErrorFile(GenT::RCC, QrcFile_, error);
+    return false;
+  }
+
+  // Test if the rcc output file exists
+  if (!RccFileTime_.Load(RccFileOutput_)) {
+    if (Log().Verbose()) {
+      std::string reason = "Generating ";
+      reason += Quoted(RccFileOutput_);
+      reason += " from its source file ";
+      reason += Quoted(QrcFile_);
+      reason += " because it doesn't exist";
+      Log().Info(GenT::RCC, reason);
+    }
+    generate = true;
+    return true;
+  }
+
+  // Test if the settings changed
+  if (SettingsChanged_) {
+    if (Log().Verbose()) {
+      std::string reason = "Generating ";
+      reason += Quoted(RccFileOutput_);
+      reason += " from ";
+      reason += Quoted(QrcFile_);
+      reason += " because the RCC settings changed";
+      Log().Info(GenT::RCC, reason);
+    }
+    generate = true;
+    return true;
+  }
+
+  // Test if the rcc output file is older than the .qrc file
+  if (RccFileTime_.Older(QrcFileTime_)) {
+    if (Log().Verbose()) {
+      std::string reason = "Generating ";
+      reason += Quoted(RccFileOutput_);
+      reason += " because it is older than ";
+      reason += Quoted(QrcFile_);
+      Log().Info(GenT::RCC, reason);
+    }
+    generate = true;
+    return true;
+  }
+
+  return true;
+}
+
+bool cmQtAutoRcc::TestResources(bool& generate)
+{
+  // Read resource files list
+  if (Inputs_.empty()) {
+    std::string error;
+    RccLister const lister(RccExecutable_, RccListOptions_);
+    if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) {
+      Log().ErrorFile(GenT::RCC, QrcFile_, error);
+      return false;
+    }
+  }
+
+  for (std::string const& resFile : Inputs_) {
+    // Check if the resource file exists
+    cmFileTime fileTime;
+    if (!fileTime.Load(resFile)) {
+      std::string error;
+      error = "Could not find the resource file\n  ";
+      error += Quoted(resFile);
+      error += '\n';
+      Log().ErrorFile(GenT::RCC, QrcFile_, error);
+      return false;
+    }
+    // Check if the resource file is newer than the build file
+    if (RccFileTime_.Older(fileTime)) {
+      if (Log().Verbose()) {
+        std::string reason = "Generating ";
+        reason += Quoted(RccFileOutput_);
+        reason += " from ";
+        reason += Quoted(QrcFile_);
+        reason += " because it is older than ";
+        reason += Quoted(resFile);
+        Log().Info(GenT::RCC, reason);
+      }
+      generate = true;
+      break;
+    }
+  }
+  return true;
+}
+
+bool cmQtAutoRcc::TestInfoFile()
+{
+  // Test if the rcc output file is older than the info file
+
+  cmFileTime infoFileTime;
+  if (!infoFileTime.Load(InfoFile())) {
+    std::string error;
+    error = "Could not find the info file ";
+    error += Quoted(InfoFile());
+    error += '\n';
+    Log().ErrorFile(GenT::RCC, QrcFile_, error);
+    return false;
+  }
+  if (RccFileTime_.Older(infoFileTime)) {
+    if (Log().Verbose()) {
+      std::string reason = "Touching ";
+      reason += Quoted(RccFileOutput_);
+      reason += " because it is older than ";
+      reason += Quoted(InfoFile());
+      Log().Info(GenT::RCC, reason);
+    }
+    // Touch build file
+    if (!cmSystemTools::Touch(RccFileOutput_, false)) {
+      Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed");
+      return false;
+    }
+    BuildFileChanged_ = true;
+  }
+
+  return true;
+}
+
+bool cmQtAutoRcc::GenerateRcc()
+{
+  // Make parent directory
+  if (!MakeParentDirectory(RccFileOutput_)) {
+    Log().ErrorFile(GenT::RCC, RccFileOutput_,
+                    "Could not create parent directory");
+    return false;
+  }
+
+  // Start a rcc process
+  std::vector<std::string> cmd;
+  cmd.push_back(RccExecutable_);
+  cmd.insert(cmd.end(), Options_.begin(), Options_.end());
+  cmd.emplace_back("-o");
+  cmd.push_back(RccFileOutput_);
+  cmd.push_back(QrcFile_);
+
+  // Log command
+  if (Log().Verbose()) {
+    std::string msg = "Running command:\n";
+    msg += QuotedCommand(cmd);
+    msg += '\n';
+    cmSystemTools::Stdout(msg);
+  }
+
+  std::string rccStdOut;
+  std::string rccStdErr;
+  int retVal = 0;
+  bool result = cmSystemTools::RunSingleCommand(
+    cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(),
+    cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+  if (!result || (retVal != 0)) {
+    // rcc process failed
+    {
+      std::string err = "The rcc process failed to compile\n  ";
+      err += Quoted(QrcFile_);
+      err += "\ninto\n  ";
+      err += Quoted(RccFileOutput_);
+      Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr);
+    }
+    cmSystemTools::RemoveFile(RccFileOutput_);
+    return false;
+  }
+
+  // rcc process success
+  // Print rcc output
+  if (!rccStdOut.empty()) {
+    Log().Info(GenT::RCC, rccStdOut);
+  }
+  BuildFileChanged_ = true;
+
+  return true;
+}
+
+bool cmQtAutoRcc::GenerateWrapper()
+{
+  // Generate a wrapper source file on demand
+  if (IsMultiConfig()) {
+    // Wrapper file content
+    std::string content;
+    content += "// This is an autogenerated configuration wrapper file.\n";
+    content += "// Changes will be overwritten.\n";
+    content += "#include <";
+    content += MultiConfigOutput();
+    content += ">\n";
+
+    // Compare with existing file content
+    bool fileDiffers = true;
+    {
+      std::string oldContents;
+      if (FileRead(oldContents, RccFilePublic_)) {
+        fileDiffers = (oldContents != content);
+      }
+    }
+    if (fileDiffers) {
+      // Write new wrapper file
+      if (Log().Verbose()) {
+        Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_);
+      }
+      std::string error;
+      if (!FileWrite(RccFilePublic_, content, &error)) {
+        Log().ErrorFile(GenT::RCC, RccFilePublic_,
+                        "RCC wrapper file writing failed. " + error);
+        return false;
+      }
+    } else if (BuildFileChanged_) {
+      // Just touch the wrapper file
+      if (Log().Verbose()) {
+        Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_);
+      }
+      if (!cmSystemTools::Touch(RccFilePublic_, false)) {
+        Log().ErrorFile(GenT::RCC, RccFilePublic_,
+                        "RCC wrapper file touch failed.");
+        return false;
+      }
+    }
+  }
+  return true;
+}
diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h
new file mode 100644
index 0000000..8dc9179
--- /dev/null
+++ b/Source/cmQtAutoRcc.h
@@ -0,0 +1,79 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmQtAutoRcc_h
+#define cmQtAutoRcc_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileLock.h"
+#include "cmFileTime.h"
+#include "cmQtAutoGenerator.h"
+
+#include <string>
+#include <vector>
+
+class cmMakefile;
+
+// @brief AUTORCC generator
+class cmQtAutoRcc : public cmQtAutoGenerator
+{
+public:
+  cmQtAutoRcc();
+  ~cmQtAutoRcc() override;
+
+  cmQtAutoRcc(cmQtAutoRcc const&) = delete;
+  cmQtAutoRcc& operator=(cmQtAutoRcc const&) = delete;
+
+private:
+  // -- Utility
+  Logger& Log() { return Logger_; }
+  bool IsMultiConfig() const { return MultiConfig_; }
+  std::string MultiConfigOutput() const;
+
+  // -- Abstract processing interface
+  bool Init(cmMakefile* makefile) override;
+  bool Process() override;
+  // -- Settings file
+  bool SettingsFileRead();
+  bool SettingsFileWrite();
+  // -- Tests
+  bool TestQrcRccFiles(bool& generate);
+  bool TestResources(bool& generate);
+  bool TestInfoFile();
+  // -- Generation
+  bool GenerateRcc();
+  bool GenerateWrapper();
+
+private:
+  // -- Logging
+  Logger Logger_;
+  // -- Config settings
+  bool MultiConfig_ = false;
+  // -- Directories
+  std::string AutogenBuildDir_;
+  std::string IncludeDir_;
+  // -- Qt environment
+  std::string RccExecutable_;
+  std::vector<std::string> RccListOptions_;
+  // -- Job
+  std::string LockFile_;
+  cmFileLock LockFileLock_;
+  std::string QrcFile_;
+  std::string QrcFileName_;
+  std::string QrcFileDir_;
+  cmFileTime QrcFileTime_;
+  std::string RccPathChecksum_;
+  std::string RccFileName_;
+  std::string RccFileOutput_;
+  std::string RccFilePublic_;
+  cmFileTime RccFileTime_;
+  std::vector<std::string> Options_;
+  std::vector<std::string> Inputs_;
+  // -- Settings file
+  std::string SettingsFile_;
+  std::string SettingsString_;
+  bool SettingsChanged_ = false;
+  bool BuildFileChanged_ = false;
+};
+
+#endif
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index 55204d7..2064275 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -3,6 +3,7 @@
 #include "cmRST.h"
 
 #include "cmAlgorithms.h"
+#include "cmRange.h"
 #include "cmSystemTools.h"
 #include "cmVersion.h"
 
@@ -32,7 +33,7 @@
   , TocTreeDirective("^.. toctree::[ \t]*(.*)$")
   , ProductionListDirective("^.. productionlist::[ \t]*(.*)$")
   , NoteDirective("^.. note::[ \t]*(.*)$")
-  , ModuleRST("^#\\[(=*)\\[\\.rst:$")
+  , ModuleRST(R"(^#\[(=*)\[\.rst:$)")
   , CMakeRole("(:cmake)?:("
               "command|cpack_gen|generator|variable|envvar|module|policy|"
               "prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
@@ -456,6 +457,12 @@
   size_t trailingEmpty =
     std::distance(rit, cmFindNot(cmReverseRange(lines), std::string()));
 
+  if ((leadingEmpty + trailingEmpty) >= lines.size()) {
+    // All lines are empty.  The markup block is empty.  Leave only one.
+    lines.resize(1);
+    return;
+  }
+
   std::vector<std::string>::iterator contentEnd = cmRotate(
     lines.begin(), lines.begin() + leadingEmpty, lines.end() - trailingEmpty);
   lines.erase(contentEnd, lines.end());
diff --git a/Source/cmRange.h b/Source/cmRange.h
new file mode 100644
index 0000000..3be5193
--- /dev/null
+++ b/Source/cmRange.h
@@ -0,0 +1,239 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmRange_h
+#define cmRange_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+namespace RangeIterators {
+
+template <typename Iter, typename UnaryPredicate>
+class FilterIterator
+{
+public:
+  using iterator_category = std::bidirectional_iterator_tag;
+  using value_type = typename std::iterator_traits<Iter>::value_type;
+  using difference_type = typename std::iterator_traits<Iter>::difference_type;
+  using pointer = typename std::iterator_traits<Iter>::pointer;
+  using reference = typename std::iterator_traits<Iter>::reference;
+
+  FilterIterator(Iter b, Iter e, UnaryPredicate p)
+    : Cur(std::move(b))
+    , End(std::move(e))
+    , Pred(std::move(p))
+  {
+    this->SatisfyPredicate();
+  }
+
+  FilterIterator& operator++()
+  {
+    ++this->Cur;
+    this->SatisfyPredicate();
+    return *this;
+  }
+
+  FilterIterator& operator--()
+  {
+    do {
+      --this->Cur;
+    } while (!this->Pred(*this->Cur));
+    return *this;
+  }
+
+  bool operator==(FilterIterator const& other) const
+  {
+    return this->Cur == other.Cur;
+  }
+
+  bool operator!=(FilterIterator const& other) const
+  {
+    return !this->operator==(other);
+  }
+
+  auto operator*() const -> decltype(*std::declval<Iter>())
+  {
+    return *this->Cur;
+  }
+
+private:
+  void SatisfyPredicate()
+  {
+    while (this->Cur != this->End && !this->Pred(*this->Cur)) {
+      ++this->Cur;
+    }
+  }
+
+  Iter Cur;
+  Iter End;
+  UnaryPredicate Pred;
+};
+
+template <typename Iter, typename UnaryFunction>
+class TransformIterator
+{
+public:
+  using iterator_category = std::bidirectional_iterator_tag;
+  using value_type =
+    typename std::remove_cv<typename std::remove_reference<decltype(
+      std::declval<UnaryFunction>()(*std::declval<Iter>()))>::type>::type;
+  using difference_type = typename std::iterator_traits<Iter>::difference_type;
+  using pointer = value_type const*;
+  using reference = value_type const&;
+
+  TransformIterator(Iter i, UnaryFunction f)
+    : Base(std::move(i))
+    , Func(std::move(f))
+  {
+  }
+
+  TransformIterator& operator++()
+  {
+    ++this->Base;
+    return *this;
+  }
+
+  TransformIterator& operator--()
+  {
+    --this->Base;
+    return *this;
+  }
+
+  bool operator==(TransformIterator const& other) const
+  {
+    return this->Base == other.Base;
+  }
+
+  bool operator!=(TransformIterator const& other) const
+  {
+    return !this->operator==(other);
+  }
+
+  auto operator*() const
+    -> decltype(std::declval<UnaryFunction>()(*std::declval<Iter>()))
+  {
+    return this->Func(*this->Base);
+  }
+
+private:
+  Iter Base;
+  UnaryFunction Func;
+};
+
+} // namespace RangeIterators
+
+template <typename Iter>
+class cmRange
+{
+public:
+  using const_iterator = Iter;
+  using value_type = typename std::iterator_traits<Iter>::value_type;
+  using difference_type = typename std::iterator_traits<Iter>::difference_type;
+
+  cmRange(Iter b, Iter e)
+    : Begin(std::move(b))
+    , End(std::move(e))
+  {
+  }
+
+  Iter begin() const { return this->Begin; }
+  Iter end() const { return this->End; }
+  bool empty() const { return this->Begin == this->End; }
+
+  difference_type size() const
+  {
+    return std::distance(this->Begin, this->End);
+  }
+
+  cmRange& advance(difference_type amount) &
+  {
+    std::advance(this->Begin, amount);
+    return *this;
+  }
+
+  cmRange advance(difference_type amount) &&
+  {
+    std::advance(this->Begin, amount);
+    return std::move(*this);
+  }
+
+  cmRange& retreat(difference_type amount) &
+  {
+    std::advance(this->End, -amount);
+    return *this;
+  }
+
+  cmRange retreat(difference_type amount) &&
+  {
+    std::advance(this->End, -amount);
+    return std::move(*this);
+  }
+
+  template <typename UnaryPredicate>
+  bool all_of(UnaryPredicate p) const
+  {
+    return std::all_of(this->Begin, this->End, std::ref(p));
+  }
+
+  template <typename UnaryPredicate>
+  bool any_of(UnaryPredicate p) const
+  {
+    return std::any_of(this->Begin, this->End, std::ref(p));
+  }
+
+  template <typename UnaryPredicate>
+  bool none_of(UnaryPredicate p) const
+  {
+    return std::none_of(this->Begin, this->End, std::ref(p));
+  }
+
+  template <typename UnaryPredicate>
+  auto filter(UnaryPredicate p) const
+    -> cmRange<RangeIterators::FilterIterator<Iter, UnaryPredicate>>
+  {
+    using It = RangeIterators::FilterIterator<Iter, UnaryPredicate>;
+    return { It(this->Begin, this->End, p), It(this->End, this->End, p) };
+  }
+
+  template <typename UnaryFunction>
+  auto transform(UnaryFunction f) const
+    -> cmRange<RangeIterators::TransformIterator<Iter, UnaryFunction>>
+  {
+    using It = RangeIterators::TransformIterator<Iter, UnaryFunction>;
+    return { It(this->Begin, f), It(this->End, f) };
+  }
+
+private:
+  Iter Begin;
+  Iter End;
+};
+
+template <typename Iter1, typename Iter2>
+bool operator==(cmRange<Iter1> const& left, cmRange<Iter2> const& right)
+{
+  return left.size() == right.size() &&
+    std::equal(left.begin(), left.end(), right.begin());
+}
+
+template <typename Iter1, typename Iter2>
+auto cmMakeRange(Iter1 begin, Iter2 end) -> cmRange<Iter1>
+{
+  return { begin, end };
+}
+
+template <typename Range>
+auto cmMakeRange(Range const& range) -> cmRange<decltype(range.begin())>
+{
+  return { range.begin(), range.end() };
+}
+
+template <typename Range>
+auto cmReverseRange(Range const& range) -> cmRange<decltype(range.rbegin())>
+{
+  return { range.rbegin(), range.rend() };
+}
+
+#endif
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index e347a2c..309ee30 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -172,6 +172,36 @@
       return replaceValues.SwiftModuleName;
     }
   }
+  if (replaceValues.SwiftLibraryName) {
+    if (variable == "SWIFT_LIBRARY_NAME") {
+      return replaceValues.SwiftLibraryName;
+    }
+  }
+  if (replaceValues.SwiftPartialDoc) {
+    if (variable == "SWIFT_PARTIAL_DOC") {
+      return replaceValues.SwiftPartialDoc;
+    }
+  }
+  if (replaceValues.SwiftPartialModule) {
+    if (variable == "SWIFT_PARTIAL_MODULE") {
+      return replaceValues.SwiftPartialModule;
+    }
+  }
+  if (replaceValues.SwiftPartialModules) {
+    if (variable == "SWIFT_PARTIAL_MODULES") {
+      return replaceValues.SwiftPartialModules;
+    }
+  }
+  if (replaceValues.TargetSwiftDoc) {
+    if (variable == "TARGET_SWIFT_DOC") {
+      return replaceValues.TargetSwiftDoc;
+    }
+  }
+  if (replaceValues.TargetSwiftModule) {
+    if (variable == "TARGET_SWIFT_MODULE") {
+      return replaceValues.TargetSwiftModule;
+    }
+  }
   if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
       variable == "TARGET_INSTALLNAME_DIR") {
     // All these variables depend on TargetSOName
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 5c03637..ebd4d41 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -60,6 +60,12 @@
     const char* FilterPrefix;
     const char* SwiftAuxiliarySources;
     const char* SwiftModuleName;
+    const char* SwiftLibraryName;
+    const char* SwiftPartialModule;
+    const char* SwiftPartialDoc;
+    const char* TargetSwiftModule;
+    const char* TargetSwiftDoc;
+    const char* SwiftPartialModules;
   };
 
   // Expand rule variables in CMake of the type found in language rules
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index 0f51e0e..f98984e 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -144,7 +144,7 @@
     // this will get incorrectly considered a network
     // path on windows and cause huge delays.
     std::string p = inPath;
-    if (!p.empty() && *p.rbegin() != '/') {
+    if (!p.empty() && p.back() != '/') {
       p += "/";
     }
 
@@ -176,7 +176,7 @@
 
   for (std::string const& path : paths) {
     std::string dir = path;
-    if (!subdir.empty() && !dir.empty() && *dir.rbegin() != '/') {
+    if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
       dir += "/";
     }
     if (subdir == "include" || subdir == "lib") {
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index e740c05..1903fd9 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -97,13 +97,13 @@
   }
 
   cmSystemTools::SetMessageCallback(
-    [&request](const char* msg, const char* title) {
+    [&request](const std::string& msg, const char* title) {
       reportMessage(msg, title, request);
     });
 
   if (this->Protocol) {
     this->Protocol->CMakeInstance()->SetProgressCallback(
-      [&request](const char* msg, float prog) {
+      [&request](const std::string& msg, float prog) {
         reportProgress(msg, prog, request);
       });
     this->WriteResponse(connection, this->Protocol->Process(request),
@@ -155,7 +155,7 @@
   this->WriteJsonObject(connection, hello, nullptr);
 }
 
-void cmServer::reportProgress(const char* msg, float progress,
+void cmServer::reportProgress(const std::string& msg, float progress,
                               const cmServerRequest& request)
 {
   if (progress < 0.0f || progress > 1.0f) {
@@ -165,15 +165,14 @@
   }
 }
 
-void cmServer::reportMessage(const char* msg, const char* title,
+void cmServer::reportMessage(const std::string& msg, const char* title,
                              const cmServerRequest& request)
 {
-  assert(msg);
   std::string titleString;
   if (title) {
     titleString = title;
   }
-  request.ReportMessage(std::string(msg), titleString);
+  request.ReportMessage(msg, titleString);
 }
 
 cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
diff --git a/Source/cmServer.h b/Source/cmServer.h
index e1ed27a..aba4924 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -119,9 +119,9 @@
   void OnConnected(cmConnection* connection) override;
 
 private:
-  static void reportProgress(const char* msg, float progress,
+  static void reportProgress(const std::string& msg, float progress,
                              const cmServerRequest& request);
-  static void reportMessage(const char* msg, const char* title,
+  static void reportMessage(const std::string& msg, const char* title,
                             const cmServerRequest& request);
 
   // Handle requests:
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index 844a858..a878890 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -29,7 +29,7 @@
       tty.init(*this->Server->GetLoop(), file_id, file_id == 0,
                static_cast<cmEventBasedConnection*>(this));
       uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL);
-      return std::move(tty);
+      return { std::move(tty) };
     }
     case UV_FILE:
       if (file_id == 0) {
@@ -43,7 +43,7 @@
       pipe.init(*this->Server->GetLoop(), 0,
                 static_cast<cmEventBasedConnection*>(this));
       uv_pipe_open(pipe, file_id);
-      return std::move(pipe);
+      return { std::move(pipe) };
     }
     default:
       assert(false && "Unable to determine stream type");
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 6bd071c..41555e8 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -5,6 +5,7 @@
 #include "cmAlgorithms.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 3c4111b..e9343c7 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -8,6 +8,7 @@
 #include "cmInstalledFile.h"
 #include "cmMakefile.h"
 #include "cmProperty.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmSystemTools.h"
@@ -33,25 +34,25 @@
   }
 
   // Get the scope on which to set the property.
-  std::vector<std::string>::const_iterator arg = args.begin();
+  std::string const& scopeName = args.front();
   cmProperty::ScopeType scope;
-  if (*arg == "GLOBAL") {
+  if (scopeName == "GLOBAL") {
     scope = cmProperty::GLOBAL;
-  } else if (*arg == "DIRECTORY") {
+  } else if (scopeName == "DIRECTORY") {
     scope = cmProperty::DIRECTORY;
-  } else if (*arg == "TARGET") {
+  } else if (scopeName == "TARGET") {
     scope = cmProperty::TARGET;
-  } else if (*arg == "SOURCE") {
+  } else if (scopeName == "SOURCE") {
     scope = cmProperty::SOURCE_FILE;
-  } else if (*arg == "TEST") {
+  } else if (scopeName == "TEST") {
     scope = cmProperty::TEST;
-  } else if (*arg == "CACHE") {
+  } else if (scopeName == "CACHE") {
     scope = cmProperty::CACHE;
-  } else if (*arg == "INSTALL") {
+  } else if (scopeName == "INSTALL") {
     scope = cmProperty::INSTALL;
   } else {
     std::ostringstream e;
-    e << "given invalid scope " << *arg << ".  "
+    e << "given invalid scope " << scopeName << ".  "
       << "Valid scopes are GLOBAL, DIRECTORY, "
          "TARGET, SOURCE, TEST, CACHE, INSTALL.";
     this->SetError(e.str());
@@ -68,32 +69,32 @@
   };
   Doing doing = DoingNames;
   const char* sep = "";
-  for (++arg; arg != args.end(); ++arg) {
-    if (*arg == "PROPERTY") {
+  for (std::string const& arg : cmMakeRange(args).advance(1)) {
+    if (arg == "PROPERTY") {
       doing = DoingProperty;
-    } else if (*arg == "APPEND") {
+    } else if (arg == "APPEND") {
       doing = DoingNone;
       this->AppendMode = true;
       this->Remove = false;
       this->AppendAsString = false;
-    } else if (*arg == "APPEND_STRING") {
+    } else if (arg == "APPEND_STRING") {
       doing = DoingNone;
       this->AppendMode = true;
       this->Remove = false;
       this->AppendAsString = true;
     } else if (doing == DoingNames) {
-      this->Names.insert(*arg);
+      this->Names.insert(arg);
     } else if (doing == DoingProperty) {
-      this->PropertyName = *arg;
+      this->PropertyName = arg;
       doing = DoingValues;
     } else if (doing == DoingValues) {
       this->PropertyValue += sep;
       sep = ";";
-      this->PropertyValue += *arg;
+      this->PropertyValue += arg;
       this->Remove = false;
     } else {
       std::ostringstream e;
-      e << "given invalid argument \"" << *arg << "\".";
+      e << "given invalid argument \"" << arg << "\".";
       this->SetError(e.str());
       return false;
     }
@@ -334,7 +335,7 @@
         !cmSystemTools::IsOff(this->PropertyValue)) {
       std::ostringstream e;
       e << "given non-boolean value \"" << this->PropertyValue
-        << "\" for CACHE property \"ADVANCED\".  ";
+        << R"(" for CACHE property "ADVANCED".  )";
       this->SetError(e.str());
       return false;
     }
diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx
index 01758ee..9f041bc 100644
--- a/Source/cmSiteNameCommand.cxx
+++ b/Source/cmSiteNameCommand.cxx
@@ -52,9 +52,8 @@
   // try to find the hostname for this computer
   if (!cmSystemTools::IsOff(hostname_cmd)) {
     std::string host;
-    cmSystemTools::RunSingleCommand(hostname_cmd.c_str(), &host, nullptr,
-                                    nullptr, nullptr,
-                                    cmSystemTools::OUTPUT_NONE);
+    cmSystemTools::RunSingleCommand(hostname_cmd, &host, nullptr, nullptr,
+                                    nullptr, cmSystemTools::OUTPUT_NONE);
 
     // got the hostname
     if (!host.empty()) {
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index a82a58a..edad4c7 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -34,6 +34,9 @@
 
   ~cmSourceFile();
 
+  cmSourceFile(const cmSourceFile&) = delete;
+  cmSourceFile& operator=(const cmSourceFile&) = delete;
+
   /**
    * Get the list of the custom commands for this source file
    */
@@ -41,13 +44,13 @@
   cmCustomCommand const* GetCustomCommand() const;
   void SetCustomCommand(cmCustomCommand* cc);
 
-  ///! Set/Get a property of this source file
+  //! Set/Get a property of this source file
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
-  ///! Might return a nullptr if the property is not set or invalid
+  //! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
-  ///! Always returns a valid pointer
+  //! Always returns a valid pointer
   const char* GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
 
@@ -55,7 +58,7 @@
       command like get_property or get_source_file_property.  */
   const char* GetPropertyForUser(const std::string& prop);
 
-  ///! Checks is the GENERATED property is set and true
+  //! Checks is the GENERATED property is set and true
   /// @return Equivalent to GetPropertyAsBool("GENERATED")
   bool GetIsGenerated() const { return this->IsGenerated; }
 
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index 34ded38..2bc4c39 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -77,6 +77,7 @@
   const std::string& currentSourceDir)
 {
   std::vector<std::string> prepared;
+  prepared.reserve(filesPaths.size());
 
   for (auto const& filePath : filesPaths) {
     prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index a08e9b8..fa7df0b 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -556,9 +556,28 @@
   if (prop == "CMAKE_C_KNOWN_FEATURES") {
     return &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1];
   }
+  if (prop == "CMAKE_C90_KNOWN_FEATURES") {
+    return &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
+  if (prop == "CMAKE_C99_KNOWN_FEATURES") {
+    return &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
+  if (prop == "CMAKE_C11_KNOWN_FEATURES") {
+    return &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
   if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
     return &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1];
   }
+  if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
+    return &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
+  if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
+    return &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
+  if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
+    return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
+
 #undef STRING_LIST_ELEMENT
   return this->GlobalProperties.GetPropertyValue(prop);
 }
diff --git a/Source/cmState.h b/Source/cmState.h
index f755f83..6abe71c 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -35,6 +35,9 @@
   cmState();
   ~cmState();
 
+  cmState(const cmState&) = delete;
+  cmState& operator=(const cmState&) = delete;
+
   enum Mode
   {
     Unknown,
@@ -104,7 +107,7 @@
   void RemoveCacheEntryProperty(std::string const& key,
                                 std::string const& propertyName);
 
-  ///! Break up a line like VAR:type="value" into var, type and value
+  //! Break up a line like VAR:type="value" into var, type and value
   static bool ParseCacheEntry(const std::string& entry, std::string& var,
                               std::string& value,
                               cmStateEnums::CacheEntryType& type);
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 6752743..31273cc 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -8,8 +8,10 @@
 #include <iterator>
 #include <utility>
 
+#include "cmAlgorithms.h"
 #include "cmProperty.h"
 #include "cmPropertyMap.h"
+#include "cmRange.h"
 #include "cmState.h"
 #include "cmStatePrivate.h"
 #include "cmStateTypes.h"
@@ -40,9 +42,8 @@
 
   std::string result = snapshots.front().GetDirectory().GetCurrentSource();
 
-  for (std::vector<cmStateSnapshot>::const_iterator it = snapshots.begin() + 1;
-       it != snapshots.end(); ++it) {
-    std::string currentSource = it->GetDirectory().GetCurrentSource();
+  for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+    std::string currentSource = snp.GetDirectory().GetCurrentSource();
     if (cmSystemTools::IsSubDirectory(result, currentSource)) {
       result = currentSource;
     }
@@ -66,9 +67,8 @@
 
   std::string result = snapshots.front().GetDirectory().GetCurrentBinary();
 
-  for (std::vector<cmStateSnapshot>::const_iterator it = snapshots.begin() + 1;
-       it != snapshots.end(); ++it) {
-    std::string currentBinary = it->GetDirectory().GetCurrentBinary();
+  for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+    std::string currentBinary = snp.GetDirectory().GetCurrentBinary();
     if (cmSystemTools::IsSubDirectory(result, currentBinary)) {
       result = currentBinary;
     }
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 91d6190..252d985 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -13,6 +13,7 @@
 #include "cmCryptoHash.h"
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
 #include "cmStringReplaceHelper.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
@@ -771,7 +772,7 @@
   }
   result.push_back(0);
 
-  this->Makefile->AddDefinition(variableName, &*result.begin());
+  this->Makefile->AddDefinition(variableName, result.data());
   return true;
 }
 
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 1d20e2f..212608d 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -5,6 +5,7 @@
 #include "cmAlgorithms.h"
 #include "cmDuration.h"
 #include "cmProcessOutput.h"
+#include "cmRange.h"
 #include "cm_sys_stat.h"
 #include "cm_uv.h"
 
@@ -323,16 +324,16 @@
   }
 }
 
-void cmSystemTools::Message(const char* m1, const char* title)
+void cmSystemTools::Message(const std::string& m, const char* title)
 {
   if (s_DisableMessages) {
     return;
   }
   if (s_MessageCallback) {
-    s_MessageCallback(m1, title);
+    s_MessageCallback(m, title);
     return;
   }
-  std::cerr << m1 << std::endl << std::flush;
+  std::cerr << m << std::endl << std::flush;
 }
 
 void cmSystemTools::ReportLastSystemError(const char* msg)
@@ -521,6 +522,8 @@
     }
     free(this->ArgV);
   }
+  cmSystemToolsArgV(const cmSystemToolsArgV&) = delete;
+  cmSystemToolsArgV& operator=(const cmSystemToolsArgV&) = delete;
   void Store(std::vector<std::string>& args) const
   {
     for (char** arg = this->ArgV; arg && *arg; ++arg) {
@@ -533,7 +536,7 @@
                                          std::vector<std::string>& args)
 {
   // Invoke the underlying parser.
-  cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
+  cmSystemToolsArgV argv(cmsysSystem_Parse_CommandForUnix(command, 0));
   argv.Store(args);
 }
 
@@ -542,8 +545,7 @@
   std::vector<std::string>::const_iterator argEnd)
 {
   std::vector<std::string> arg_full;
-  for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
-    std::string const& arg = *a;
+  for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
     if (cmHasLiteralPrefix(arg, "@")) {
       cmsys::ifstream responseFile(arg.substr(1).c_str(), std::ios::in);
       if (!responseFile) {
@@ -570,13 +572,14 @@
   return arg_full;
 }
 
-std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
+std::vector<std::string> cmSystemTools::ParseArguments(const std::string& cmd)
 {
   std::vector<std::string> args;
   std::string arg;
 
   bool win_path = false;
 
+  const char* command = cmd.c_str();
   if (command[0] && command[1] &&
       ((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
        (command[0] == '\"' && command[1] != '/' && command[2] == ':' &&
@@ -740,7 +743,7 @@
   argv.push_back(nullptr);
 
   cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
+  cmsysProcess_SetCommand(cp, argv.data());
   cmsysProcess_SetWorkingDirectory(cp, dir);
   if (cmSystemTools::GetRunCommandHideConsole()) {
     cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -867,7 +870,7 @@
   return result;
 }
 
-bool cmSystemTools::RunSingleCommand(const char* command,
+bool cmSystemTools::RunSingleCommand(const std::string& command,
                                      std::string* captureStdOut,
                                      std::string* captureStdErr, int* retVal,
                                      const char* dir, OutputOption outputflag,
@@ -897,7 +900,7 @@
 }
 
 bool cmSystemTools::DoesFileExistWithExtensions(
-  const char* name, const std::vector<std::string>& headerExts)
+  const std::string& name, const std::vector<std::string>& headerExts)
 {
   std::string hname;
 
@@ -912,9 +915,9 @@
   return false;
 }
 
-std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
-                                                         const char* directory,
-                                                         const char* toplevel)
+std::string cmSystemTools::FileExistsInParentDirectories(
+  const std::string& fname, const std::string& directory,
+  const std::string& toplevel)
 {
   std::string file = fname;
   cmSystemTools::ConvertToUnixSlashes(file);
@@ -926,7 +929,7 @@
     if (cmSystemTools::FileExists(path)) {
       return path;
     }
-    if (dir.size() < strlen(toplevel)) {
+    if (dir.size() < toplevel.size()) {
       break;
     }
     prevDir = dir;
@@ -935,12 +938,6 @@
   return "";
 }
 
-bool cmSystemTools::cmCopyFile(const std::string& source,
-                               const std::string& destination)
-{
-  return Superclass::CopyFileAlways(source, destination);
-}
-
 #ifdef _WIN32
 cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
 {
@@ -1219,9 +1216,8 @@
 void cmSystemTools::ExpandList(std::vector<std::string> const& arguments,
                                std::vector<std::string>& newargs)
 {
-  std::vector<std::string>::const_iterator i;
-  for (i = arguments.begin(); i != arguments.end(); ++i) {
-    cmSystemTools::ExpandListArgument(*i, newargs);
+  for (std::string const& arg : arguments) {
+    cmSystemTools::ExpandListArgument(arg, newargs);
   }
 }
 
@@ -1389,14 +1385,6 @@
   return cmSystemTools::UNKNOWN_FILE_FORMAT;
 }
 
-bool cmSystemTools::Split(const char* s, std::vector<std::string>& l)
-{
-  std::vector<std::string> temp;
-  bool res = Superclass::Split(s, temp);
-  l.insert(l.end(), temp.begin(), temp.end());
-  return res;
-}
-
 std::string cmSystemTools::ConvertToOutputPath(std::string const& path)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1424,7 +1412,7 @@
 #endif
 }
 
-std::string cmSystemTools::ConvertToRunCommandPath(const char* path)
+std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
   return cmSystemTools::ConvertToWindowsOutputPath(path);
@@ -1438,12 +1426,12 @@
                                         std::string const& remote)
 {
   if (!cmSystemTools::FileIsFullPath(local)) {
-    cmSystemTools::Error("RelativePath must be passed a full path to local: ",
-                         local.c_str());
+    cmSystemTools::Error("RelativePath must be passed a full path to local: " +
+                         local);
   }
   if (!cmSystemTools::FileIsFullPath(remote)) {
-    cmSystemTools::Error("RelativePath must be passed a full path to remote: ",
-                         remote.c_str());
+    cmSystemTools::Error(
+      "RelativePath must be passed a full path to remote: " + remote);
   }
   return cmsys::SystemTools::RelativePath(local, remote);
 }
@@ -1522,36 +1510,6 @@
   return relative;
 }
 
-std::string cmSystemTools::CollapseCombinedPath(std::string const& dir,
-                                                std::string const& file)
-{
-  if (dir.empty() || dir == ".") {
-    return file;
-  }
-
-  std::vector<std::string> dirComponents;
-  std::vector<std::string> fileComponents;
-  cmSystemTools::SplitPath(dir, dirComponents);
-  cmSystemTools::SplitPath(file, fileComponents);
-
-  if (fileComponents.empty()) {
-    return dir;
-  }
-  if (!fileComponents[0].empty()) {
-    // File is not a relative path.
-    return file;
-  }
-
-  std::vector<std::string>::iterator i = fileComponents.begin() + 1;
-  while (i != fileComponents.end() && *i == ".." && dirComponents.size() > 1) {
-    ++i;                      // Remove ".." file component.
-    dirComponents.pop_back(); // Remove last dir component.
-  }
-
-  dirComponents.insert(dirComponents.end(), i, fileComponents.end());
-  return cmSystemTools::JoinPath(dirComponents);
-}
-
 #ifdef CMAKE_BUILD_WITH_CMAKE
 bool cmSystemTools::UnsetEnv(const char* value)
 {
@@ -1627,7 +1585,7 @@
 #endif
 }
 
-bool cmSystemTools::IsPathToFramework(const char* path)
+bool cmSystemTools::IsPathToFramework(const std::string& path)
 {
   return (cmSystemTools::FileIsFullPath(path) &&
           cmHasLiteralSuffix(path, ".framework"));
@@ -1670,20 +1628,18 @@
 
   a.SetMTime(mtime);
   a.SetVerbose(verbose);
+  bool tarCreatedSuccessfully = true;
   for (auto path : files) {
     if (cmSystemTools::FileIsFullPath(path)) {
       // Get the relative path to the file.
       path = cmSystemTools::RelativePath(cwd, path);
     }
     if (!a.Add(path)) {
-      break;
+      cmSystemTools::Error(a.GetError());
+      tarCreatedSuccessfully = false;
     }
   }
-  if (!a) {
-    cmSystemTools::Error(a.GetError());
-    return false;
-  }
-  return true;
+  return tarCreatedSuccessfully;
 #else
   (void)outFileName;
   (void)files;
@@ -1922,8 +1878,8 @@
       else {
         cmSystemTools::Error("Problem with archive_write_header(): ",
                              archive_error_string(ext));
-        cmSystemTools::Error("Current file: ",
-                             cm_archive_entry_pathname(entry).c_str());
+        cmSystemTools::Error("Current file: " +
+                             cm_archive_entry_pathname(entry));
         break;
       }
     }
@@ -2082,7 +2038,8 @@
 #endif
 }
 
-bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
+bool cmSystemTools::CopyFileTime(const std::string& fromFile,
+                                 const std::string& toFile)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
   cmSystemToolsWindowsHandle hFrom = CreateFileW(
@@ -2103,14 +2060,14 @@
   return SetFileTime(hTo, &timeCreation, &timeLastAccess, &timeLastWrite) != 0;
 #else
   struct stat fromStat;
-  if (stat(fromFile, &fromStat) < 0) {
+  if (stat(fromFile.c_str(), &fromStat) < 0) {
     return false;
   }
 
   struct utimbuf buf;
   buf.actime = fromStat.st_atime;
   buf.modtime = fromStat.st_mtime;
-  return utime(toFile, &buf) >= 0;
+  return utime(toFile.c_str(), &buf) >= 0;
 #endif
 }
 
@@ -2124,7 +2081,8 @@
   delete t;
 }
 
-bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t)
+bool cmSystemTools::FileTimeGet(const std::string& fname,
+                                cmSystemToolsFileTime* t)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
   cmSystemToolsWindowsHandle h = CreateFileW(
@@ -2139,7 +2097,7 @@
   }
 #else
   struct stat st;
-  if (stat(fname, &st) < 0) {
+  if (stat(fname.c_str(), &st) < 0) {
     return false;
   }
   t->timeBuf.actime = st.st_atime;
@@ -2148,7 +2106,8 @@
   return true;
 }
 
-bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t)
+bool cmSystemTools::FileTimeSet(const std::string& fname,
+                                const cmSystemToolsFileTime* t)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
   cmSystemToolsWindowsHandle h = CreateFileW(
@@ -2160,7 +2119,7 @@
   return SetFileTime(h, &t->timeCreation, &t->timeLastAccess,
                      &t->timeLastWrite) != 0;
 #else
-  return utime(fname, &t->timeBuf) >= 0;
+  return utime(fname.c_str(), &t->timeBuf) >= 0;
 #endif
 }
 
@@ -3015,7 +2974,7 @@
 #endif
 }
 
-bool cmSystemTools::RepeatedRemoveDirectory(const char* dir)
+bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
 {
   // Windows sometimes locks files temporarily so try a few times.
   for (int i = 0; i < 10; ++i) {
@@ -3064,6 +3023,12 @@
 {
   errno = 0;
   char* endp;
+  while (isspace(*str)) {
+    ++str;
+  }
+  if (*str == '-') {
+    return false;
+  }
   *value = strtoul(str, &endp, 10);
   return (*endp == '\0') && (endp != str) && (errno == 0);
 }
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 0f92fe2..a8b2d37 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -45,7 +45,7 @@
   static void ExpandRegistryValues(std::string& source,
                                    KeyWOW64 view = KeyWOW64_Default);
 
-  ///! Escape quotes in a string.
+  //! Escape quotes in a string.
   static std::string EscapeQuotes(const std::string& str);
 
   /** Map help document name to file name.  */
@@ -56,7 +56,7 @@
    */
   static std::string TrimWhitespace(const std::string& s);
 
-  using MessageCallback = std::function<void(const char*, const char*)>;
+  using MessageCallback = std::function<void(const std::string&, const char*)>;
   /**
    *  Set the function used by GUIs to display error messages
    *  Function gets passed: message as a const char*,
@@ -74,19 +74,15 @@
   /**
    * Display a message.
    */
-  static void Message(const char* m, const char* title = nullptr);
-  static void Message(const std::string& m, const char* title = nullptr)
-  {
-    Message(m.c_str(), title);
-  }
+  static void Message(const std::string& m, const char* title = nullptr);
 
   using OutputCallback = std::function<void(std::string const&)>;
 
-  ///! Send a string to stdout
+  //! Send a string to stdout
   static void Stdout(const std::string& s);
   static void SetStdoutCallback(OutputCallback f);
 
-  ///! Send a string to stderr
+  //! Send a string to stderr
   static void Stderr(const std::string& s);
   static void SetStderrCallback(OutputCallback f);
 
@@ -94,25 +90,25 @@
   static void SetInterruptCallback(InterruptCallback f);
   static bool GetInterruptFlag();
 
-  ///! Return true if there was an error at any point.
+  //! Return true if there was an error at any point.
   static bool GetErrorOccuredFlag()
   {
     return cmSystemTools::s_ErrorOccured ||
       cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
   }
-  ///! If this is set to true, cmake stops processing commands.
+  //! If this is set to true, cmake stops processing commands.
   static void SetFatalErrorOccured()
   {
     cmSystemTools::s_FatalErrorOccured = true;
   }
   static void SetErrorOccured() { cmSystemTools::s_ErrorOccured = true; }
-  ///! Return true if there was an error at any point.
+  //! Return true if there was an error at any point.
   static bool GetFatalErrorOccured()
   {
     return cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
   }
 
-  ///! Set the error occurred flag and fatal error back to false
+  //! Set the error occurred flag and fatal error back to false
   static void ResetErrorOccuredFlag()
   {
     cmSystemTools::s_FatalErrorOccured = false;
@@ -142,22 +138,22 @@
   static bool IsOff(const char* val);
   static bool IsOff(const std::string& val);
 
-  ///! Return true if value is NOTFOUND or ends in -NOTFOUND.
+  //! Return true if value is NOTFOUND or ends in -NOTFOUND.
   static bool IsNOTFOUND(const char* value);
-  ///! Return true if the path is a framework
-  static bool IsPathToFramework(const char* value);
+  //! Return true if the path is a framework
+  static bool IsPathToFramework(const std::string& value);
 
   static bool DoesFileExistWithExtensions(
-    const char* name, const std::vector<std::string>& sourceExts);
+    const std::string& name, const std::vector<std::string>& sourceExts);
 
   /**
    * Check if the given file exists in one of the parent directory of the
    * given file or directory and if it does, return the name of the file.
    * Toplevel specifies the top-most directory to where it will look.
    */
-  static std::string FileExistsInParentDirectories(const char* fname,
-                                                   const char* directory,
-                                                   const char* toplevel);
+  static std::string FileExistsInParentDirectories(
+    const std::string& fname, const std::string& directory,
+    const std::string& toplevel);
 
   static void Glob(const std::string& directory, const std::string& regexp,
                    std::vector<std::string>& files);
@@ -176,23 +172,19 @@
   static bool SimpleGlob(const std::string& glob,
                          std::vector<std::string>& files, int type = 0);
 
-  ///! Copy a file.
-  static bool cmCopyFile(const std::string& source,
-                         const std::string& destination);
-
   /** Rename a file or directory within a single disk volume (atomic
       if possible).  */
   static bool RenameFile(const std::string& oldname,
                          const std::string& newname);
 
-  ///! Compute the hash of a file
+  //! Compute the hash of a file
   static std::string ComputeFileHash(const std::string& source,
                                      cmCryptoHash::Algo algo);
 
   /** Compute the md5sum of a string.  */
   static std::string ComputeStringMD5(const std::string& input);
 
-  ///! Get the SHA thumbprint for a certificate file
+  //! Get the SHA thumbprint for a certificate file
   static std::string ComputeCertificateThumbprint(const std::string& source);
 
   /**
@@ -224,7 +216,7 @@
     OUTPUT_FORWARD,
     OUTPUT_PASSTHROUGH
   };
-  static bool RunSingleCommand(const char* command,
+  static bool RunSingleCommand(const std::string& command,
                                std::string* captureStdOut = nullptr,
                                std::string* captureStdErr = nullptr,
                                int* retVal = nullptr,
@@ -250,7 +242,7 @@
   /**
    * Parse arguments out of a single string command
    */
-  static std::vector<std::string> ParseArguments(const char* command);
+  static std::vector<std::string> ParseArguments(const std::string& command);
 
   /** Parse arguments out of a windows command line string.  */
   static void ParseWindowsCommandLine(const char* command,
@@ -351,9 +343,6 @@
                          cmDuration timeout, std::vector<char>& out,
                          std::vector<char>& err);
 
-  /** Split a string on its newlines into multiple lines.  Returns
-      false only if the last line stored had no newline.  */
-  static bool Split(const char* s, std::vector<std::string>& l);
   static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
   static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
 
@@ -364,7 +353,7 @@
   // ConvertToRunCommandPath does not use s_ForceUnixPaths and should
   // be used when RunCommand is called from cmake, because the
   // running cmake needs paths to be in its format
-  static std::string ConvertToRunCommandPath(const char* path);
+  static std::string ConvertToRunCommandPath(const std::string& path);
 
   /** compute the relative path from local to remote.  local must
       be a directory.  remote can be a file or a directory.
@@ -385,12 +374,6 @@
   static std::string ForceToRelativePath(std::string const& local_path,
                                          std::string const& remote_path);
 
-  /** Joins two paths while collapsing x/../ parts
-   * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d"
-   */
-  static std::string CollapseCombinedPath(std::string const& dir,
-                                          std::string const& file);
-
 #ifdef CMAKE_BUILD_WITH_CMAKE
   /** Remove an environment variable */
   static bool UnsetEnv(const char* value);
@@ -423,6 +406,14 @@
   /** Setup the environment to enable VS 8 IDE output.  */
   static void EnableVSConsoleOutput();
 
+  enum cmTarAction
+  {
+    TarActionCreate,
+    TarActionList,
+    TarActionExtract,
+    TarActionNone
+  };
+
   /** Create tar */
   enum cmTarCompression
   {
@@ -431,6 +422,7 @@
     TarCompressXZ,
     TarCompressNone
   };
+
   static bool ListTar(const char* outFileName, bool verbose);
   static bool CreateTar(const char* outFileName,
                         const std::vector<std::string>& files,
@@ -447,13 +439,15 @@
 
   /** Copy the file create/access/modify times from the file named by
       the first argument to that named by the second.  */
-  static bool CopyFileTime(const char* fromFile, const char* toFile);
+  static bool CopyFileTime(const std::string& fromFile,
+                           const std::string& toFile);
 
   /** Save and restore file times.  */
   static cmSystemToolsFileTime* FileTimeNew();
   static void FileTimeDelete(cmSystemToolsFileTime*);
-  static bool FileTimeGet(const char* fname, cmSystemToolsFileTime* t);
-  static bool FileTimeSet(const char* fname, cmSystemToolsFileTime* t);
+  static bool FileTimeGet(const std::string& fname, cmSystemToolsFileTime* t);
+  static bool FileTimeSet(const std::string& fname,
+                          const cmSystemToolsFileTime* t);
 
   /** Random seed generation.  */
   static unsigned int RandomSeed();
@@ -497,7 +491,7 @@
   static bool CheckRPath(std::string const& file, std::string const& newRPath);
 
   /** Remove a directory; repeat a few times in case of locked files.  */
-  static bool RepeatedRemoveDirectory(const char* dir);
+  static bool RepeatedRemoveDirectory(const std::string& dir);
 
   /** Tokenize a string */
   static std::vector<std::string> tokenize(const std::string& str,
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 93cdd46..dc9b6d2 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -5,6 +5,7 @@
 #include "cmsys/RegularExpression.hxx"
 #include <algorithm>
 #include <assert.h>
+#include <initializer_list>
 #include <iterator>
 #include <set>
 #include <sstream>
@@ -12,6 +13,7 @@
 #include <unordered_set>
 
 #include "cmAlgorithms.h"
+#include "cmCustomCommand.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -20,6 +22,8 @@
 #include "cmMessageType.h"
 #include "cmMessenger.h"
 #include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
 #include "cmSourceFileLocationKind.h"
@@ -30,6 +34,13 @@
 #include "cmTargetPropertyComputer.h"
 #include "cmake.h"
 
+//! Append all elements from the second container to the first container
+template <class C, class R>
+static inline void CApp(C& container, R const& range)
+{
+  container.insert(container.end(), range.begin(), range.end());
+}
+
 template <>
 const char* cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
   cmTarget const* tgt)
@@ -155,6 +166,26 @@
 class cmTargetInternals
 {
 public:
+  cmStateEnums::TargetType TargetType;
+  cmMakefile* Makefile;
+  cmPolicies::PolicyMap PolicyMap;
+  std::string Name;
+  std::string InstallPath;
+  std::string RuntimeInstallPath;
+  cmPropertyMap Properties;
+  bool IsGeneratorProvided;
+  bool HaveInstallRule;
+  bool DLLPlatform;
+  bool IsAndroid;
+  bool IsImportedTarget;
+  bool ImportedGloballyVisible;
+  bool BuildInterfaceIncludesAppended;
+  std::set<BT<std::string>> Utilities;
+  std::vector<cmCustomCommand> PreBuildCommands;
+  std::vector<cmCustomCommand> PreLinkCommands;
+  std::vector<cmCustomCommand> PostBuildCommands;
+  std::set<std::string> SystemIncludeDirectories;
+  cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
   std::vector<std::string> IncludeDirectoriesEntries;
   std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
   std::vector<std::string> CompileOptionsEntries;
@@ -171,166 +202,184 @@
   std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
   std::vector<std::string> LinkImplementationPropertyEntries;
   std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
+  std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
+    TLLCommands;
+  cmListFileBacktrace Backtrace;
+
+public:
+  bool CheckImportedLibName(std::string const& prop,
+                            std::string const& value) const;
+
+  std::string ProcessSourceItemCMP0049(const std::string& s);
 };
 
 cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
                    Visibility vis, cmMakefile* mf)
+  : impl(cm::make_unique<cmTargetInternals>())
 {
   assert(mf);
-  this->IsGeneratorProvided = false;
-  this->Name = name;
-  this->TargetTypeValue = type;
-  this->Makefile = mf;
-  this->HaveInstallRule = false;
-  this->DLLPlatform = false;
-  this->IsAndroid = false;
-  this->IsImportedTarget =
+  impl->TargetType = type;
+  impl->Makefile = mf;
+  impl->Name = name;
+  impl->IsGeneratorProvided = false;
+  impl->HaveInstallRule = false;
+  impl->DLLPlatform = false;
+  impl->IsAndroid = false;
+  impl->IsImportedTarget =
     (vis == VisibilityImported || vis == VisibilityImportedGlobally);
-  this->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
-  this->BuildInterfaceIncludesAppended = false;
+  impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
+  impl->BuildInterfaceIncludesAppended = false;
 
   // Check whether this is a DLL platform.
-  this->DLLPlatform =
-    !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
+  impl->DLLPlatform =
+    !impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
 
   // Check whether we are targeting an Android platform.
-  this->IsAndroid =
-    (this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+  impl->IsAndroid =
+    (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+
+  std::string gKey;
+  gKey.reserve(128);
+  gKey += "CMAKE_";
+  auto InitProperty = [this, mf, &gKey](const std::string& property,
+                                        const char* default_value) {
+    // Replace everything after "CMAKE_"
+    gKey.replace(gKey.begin() + 6, gKey.end(), property);
+    if (const char* value = mf->GetDefinition(gKey)) {
+      this->SetProperty(property, value);
+    } else if (default_value) {
+      this->SetProperty(property, default_value);
+    }
+  };
 
   // Setup default property values.
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
       this->GetType() != cmStateEnums::UTILITY) {
-    this->SetPropertyDefault("ANDROID_API", nullptr);
-    this->SetPropertyDefault("ANDROID_API_MIN", nullptr);
-    this->SetPropertyDefault("ANDROID_ARCH", nullptr);
-    this->SetPropertyDefault("ANDROID_STL_TYPE", nullptr);
-    this->SetPropertyDefault("ANDROID_SKIP_ANT_STEP", nullptr);
-    this->SetPropertyDefault("ANDROID_PROCESS_MAX", nullptr);
-    this->SetPropertyDefault("ANDROID_PROGUARD", nullptr);
-    this->SetPropertyDefault("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
-    this->SetPropertyDefault("ANDROID_SECURE_PROPS_PATH", nullptr);
-    this->SetPropertyDefault("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
-    this->SetPropertyDefault("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
-    this->SetPropertyDefault("ANDROID_JAVA_SOURCE_DIR", nullptr);
-    this->SetPropertyDefault("ANDROID_JAR_DIRECTORIES", nullptr);
-    this->SetPropertyDefault("ANDROID_JAR_DEPENDENCIES", nullptr);
-    this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", nullptr);
-    this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
-    this->SetPropertyDefault("BUILD_RPATH", nullptr);
-    this->SetPropertyDefault("BUILD_RPATH_USE_ORIGIN", nullptr);
-    this->SetPropertyDefault("INSTALL_NAME_DIR", nullptr);
-    this->SetPropertyDefault("INSTALL_RPATH", "");
-    this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
-    this->SetPropertyDefault("INTERPROCEDURAL_OPTIMIZATION", nullptr);
-    this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
-    this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
-    this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
-    this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", nullptr);
-    this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", nullptr);
-    this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", nullptr);
-    this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
-    this->SetPropertyDefault("Fortran_FORMAT", nullptr);
-    this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", nullptr);
-    this->SetPropertyDefault("Fortran_COMPILER_LAUNCHER", nullptr);
-    this->SetPropertyDefault("GNUtoMS", nullptr);
-    this->SetPropertyDefault("OSX_ARCHITECTURES", nullptr);
-    this->SetPropertyDefault("IOS_INSTALL_COMBINED", nullptr);
-    this->SetPropertyDefault("AUTOMOC", nullptr);
-    this->SetPropertyDefault("AUTOUIC", nullptr);
-    this->SetPropertyDefault("AUTORCC", nullptr);
-    this->SetPropertyDefault("AUTOGEN_ORIGIN_DEPENDS", nullptr);
-    this->SetPropertyDefault("AUTOGEN_PARALLEL", nullptr);
-    this->SetPropertyDefault("AUTOMOC_COMPILER_PREDEFINES", nullptr);
-    this->SetPropertyDefault("AUTOMOC_DEPEND_FILTERS", nullptr);
-    this->SetPropertyDefault("AUTOMOC_MACRO_NAMES", nullptr);
-    this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", nullptr);
-    this->SetPropertyDefault("AUTOUIC_OPTIONS", nullptr);
-    this->SetPropertyDefault("AUTOUIC_SEARCH_PATHS", nullptr);
-    this->SetPropertyDefault("AUTORCC_OPTIONS", nullptr);
-    this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", nullptr);
-    this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", nullptr);
-    this->SetPropertyDefault("WIN32_EXECUTABLE", nullptr);
-    this->SetPropertyDefault("MACOSX_BUNDLE", nullptr);
-    this->SetPropertyDefault("MACOSX_RPATH", nullptr);
-    this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", nullptr);
-    this->SetPropertyDefault("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
-    this->SetPropertyDefault("C_CLANG_TIDY", nullptr);
-    this->SetPropertyDefault("C_COMPILER_LAUNCHER", nullptr);
-    this->SetPropertyDefault("C_CPPLINT", nullptr);
-    this->SetPropertyDefault("C_CPPCHECK", nullptr);
-    this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", nullptr);
-    this->SetPropertyDefault("LINK_WHAT_YOU_USE", nullptr);
-    this->SetPropertyDefault("C_STANDARD", nullptr);
-    this->SetPropertyDefault("C_STANDARD_REQUIRED", nullptr);
-    this->SetPropertyDefault("C_EXTENSIONS", nullptr);
-    this->SetPropertyDefault("CXX_CLANG_TIDY", nullptr);
-    this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", nullptr);
-    this->SetPropertyDefault("CXX_CPPLINT", nullptr);
-    this->SetPropertyDefault("CXX_CPPCHECK", nullptr);
-    this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
-    this->SetPropertyDefault("CXX_STANDARD", nullptr);
-    this->SetPropertyDefault("CXX_STANDARD_REQUIRED", nullptr);
-    this->SetPropertyDefault("CXX_EXTENSIONS", nullptr);
-    this->SetPropertyDefault("CUDA_STANDARD", nullptr);
-    this->SetPropertyDefault("CUDA_STANDARD_REQUIRED", nullptr);
-    this->SetPropertyDefault("CUDA_EXTENSIONS", nullptr);
-    this->SetPropertyDefault("CUDA_COMPILER_LAUNCHER", nullptr);
-    this->SetPropertyDefault("CUDA_SEPARABLE_COMPILATION", nullptr);
-    this->SetPropertyDefault("LINK_SEARCH_START_STATIC", nullptr);
-    this->SetPropertyDefault("LINK_SEARCH_END_STATIC", nullptr);
-    this->SetPropertyDefault("FOLDER", nullptr);
+    InitProperty("ANDROID_API", nullptr);
+    InitProperty("ANDROID_API_MIN", nullptr);
+    InitProperty("ANDROID_ARCH", nullptr);
+    InitProperty("ANDROID_STL_TYPE", nullptr);
+    InitProperty("ANDROID_SKIP_ANT_STEP", nullptr);
+    InitProperty("ANDROID_PROCESS_MAX", nullptr);
+    InitProperty("ANDROID_PROGUARD", nullptr);
+    InitProperty("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
+    InitProperty("ANDROID_SECURE_PROPS_PATH", nullptr);
+    InitProperty("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
+    InitProperty("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
+    InitProperty("ANDROID_JAVA_SOURCE_DIR", nullptr);
+    InitProperty("ANDROID_JAR_DIRECTORIES", nullptr);
+    InitProperty("ANDROID_JAR_DEPENDENCIES", nullptr);
+    InitProperty("ANDROID_ASSETS_DIRECTORIES", nullptr);
+    InitProperty("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
+    InitProperty("BUILD_RPATH", nullptr);
+    InitProperty("BUILD_RPATH_USE_ORIGIN", nullptr);
+    InitProperty("INSTALL_NAME_DIR", nullptr);
+    InitProperty("INSTALL_RPATH", "");
+    InitProperty("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+    InitProperty("INTERPROCEDURAL_OPTIMIZATION", nullptr);
+    InitProperty("SKIP_BUILD_RPATH", "OFF");
+    InitProperty("BUILD_WITH_INSTALL_RPATH", "OFF");
+    InitProperty("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
+    InitProperty("LIBRARY_OUTPUT_DIRECTORY", nullptr);
+    InitProperty("RUNTIME_OUTPUT_DIRECTORY", nullptr);
+    InitProperty("PDB_OUTPUT_DIRECTORY", nullptr);
+    InitProperty("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
+    InitProperty("Fortran_FORMAT", nullptr);
+    InitProperty("Fortran_MODULE_DIRECTORY", nullptr);
+    InitProperty("Fortran_COMPILER_LAUNCHER", nullptr);
+    InitProperty("GNUtoMS", nullptr);
+    InitProperty("OSX_ARCHITECTURES", nullptr);
+    InitProperty("IOS_INSTALL_COMBINED", nullptr);
+    InitProperty("AUTOMOC", nullptr);
+    InitProperty("AUTOUIC", nullptr);
+    InitProperty("AUTORCC", nullptr);
+    InitProperty("AUTOGEN_ORIGIN_DEPENDS", nullptr);
+    InitProperty("AUTOGEN_PARALLEL", nullptr);
+    InitProperty("AUTOMOC_COMPILER_PREDEFINES", nullptr);
+    InitProperty("AUTOMOC_DEPEND_FILTERS", nullptr);
+    InitProperty("AUTOMOC_MACRO_NAMES", nullptr);
+    InitProperty("AUTOMOC_MOC_OPTIONS", nullptr);
+    InitProperty("AUTOUIC_OPTIONS", nullptr);
+    InitProperty("AUTOUIC_SEARCH_PATHS", nullptr);
+    InitProperty("AUTORCC_OPTIONS", nullptr);
+    InitProperty("LINK_DEPENDS_NO_SHARED", nullptr);
+    InitProperty("LINK_INTERFACE_LIBRARIES", nullptr);
+    InitProperty("WIN32_EXECUTABLE", nullptr);
+    InitProperty("MACOSX_BUNDLE", nullptr);
+    InitProperty("MACOSX_RPATH", nullptr);
+    InitProperty("NO_SYSTEM_FROM_IMPORTED", nullptr);
+    InitProperty("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
+    InitProperty("C_CLANG_TIDY", nullptr);
+    InitProperty("C_COMPILER_LAUNCHER", nullptr);
+    InitProperty("C_CPPLINT", nullptr);
+    InitProperty("C_CPPCHECK", nullptr);
+    InitProperty("C_INCLUDE_WHAT_YOU_USE", nullptr);
+    InitProperty("LINK_WHAT_YOU_USE", nullptr);
+    InitProperty("C_STANDARD", nullptr);
+    InitProperty("C_STANDARD_REQUIRED", nullptr);
+    InitProperty("C_EXTENSIONS", nullptr);
+    InitProperty("CXX_CLANG_TIDY", nullptr);
+    InitProperty("CXX_COMPILER_LAUNCHER", nullptr);
+    InitProperty("CXX_CPPLINT", nullptr);
+    InitProperty("CXX_CPPCHECK", nullptr);
+    InitProperty("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
+    InitProperty("CXX_STANDARD", nullptr);
+    InitProperty("CXX_STANDARD_REQUIRED", nullptr);
+    InitProperty("CXX_EXTENSIONS", nullptr);
+    InitProperty("CUDA_STANDARD", nullptr);
+    InitProperty("CUDA_STANDARD_REQUIRED", nullptr);
+    InitProperty("CUDA_EXTENSIONS", nullptr);
+    InitProperty("CUDA_COMPILER_LAUNCHER", nullptr);
+    InitProperty("CUDA_SEPARABLE_COMPILATION", nullptr);
+    InitProperty("LINK_SEARCH_START_STATIC", nullptr);
+    InitProperty("LINK_SEARCH_END_STATIC", nullptr);
+    InitProperty("FOLDER", nullptr);
 #ifdef __APPLE__
     if (this->GetGlobalGenerator()->IsXcode()) {
-      this->SetPropertyDefault("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
-      this->SetPropertyDefault(
-        "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER",
-                               nullptr);
-      this->SetPropertyDefault(
-        "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER",
-                               nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP",
-                               nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_GUARD_MALLOC", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_MALLOC_STACK", nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE",
-                               nullptr);
-      this->SetPropertyDefault("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
+      InitProperty("XCODE_GENERATE_SCHEME", nullptr);
+      InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
+      InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
+      InitProperty("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
+      InitProperty("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
+      InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER", nullptr);
+      InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
+      InitProperty("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER", nullptr);
+      InitProperty("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP", nullptr);
+      InitProperty("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
+      InitProperty("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
+      InitProperty("XCODE_SCHEME_GUARD_MALLOC", nullptr);
+      InitProperty("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
+      InitProperty("XCODE_SCHEME_MALLOC_STACK", nullptr);
+      InitProperty("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE", nullptr);
+      InitProperty("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
     }
 #endif
   }
 
-  // Collect the set of configuration types.
-  std::vector<std::string> configNames;
-  mf->GetConfigurations(configNames);
-
   // Setup per-configuration property default values.
   if (this->GetType() != cmStateEnums::UTILITY) {
-    const char* configProps[] = {
+    static const auto configProps = {
       /* clang-format needs this comment to break after the opening brace */
       "ARCHIVE_OUTPUT_DIRECTORY_",     "LIBRARY_OUTPUT_DIRECTORY_",
       "RUNTIME_OUTPUT_DIRECTORY_",     "PDB_OUTPUT_DIRECTORY_",
       "COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_",
-      "INTERPROCEDURAL_OPTIMIZATION_", nullptr
+      "INTERPROCEDURAL_OPTIMIZATION_"
     };
+    // Collect the set of configuration types.
+    std::vector<std::string> configNames;
+    mf->GetConfigurations(configNames);
     for (std::string const& configName : configNames) {
       std::string configUpper = cmSystemTools::UpperCase(configName);
-      for (const char** p = configProps; *p; ++p) {
+      for (auto const& prop : configProps) {
         // Interface libraries have no output locations, so honor only
         // the configuration map.
-        if (this->TargetTypeValue == cmStateEnums::INTERFACE_LIBRARY &&
-            strcmp(*p, "MAP_IMPORTED_CONFIG_") != 0) {
+        if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
+            strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) {
           continue;
         }
-        std::string property = *p;
+        std::string property = prop;
         property += configUpper;
-        this->SetPropertyDefault(property, nullptr);
+        InitProperty(property, nullptr);
       }
 
       // Initialize per-configuration name postfix property from the
@@ -338,122 +387,92 @@
       // compatibility with previous CMake versions in which executables
       // did not support this variable.  Projects may still specify the
       // property directly.
-      if (this->TargetTypeValue != cmStateEnums::EXECUTABLE &&
-          this->TargetTypeValue != cmStateEnums::INTERFACE_LIBRARY) {
+      if (impl->TargetType != cmStateEnums::EXECUTABLE &&
+          impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
         std::string property = cmSystemTools::UpperCase(configName);
         property += "_POSTFIX";
-        this->SetPropertyDefault(property, nullptr);
+        InitProperty(property, nullptr);
       }
     }
   }
 
   // Save the backtrace of target construction.
-  this->Backtrace = this->Makefile->GetBacktrace();
+  impl->Backtrace = impl->Makefile->GetBacktrace();
 
   if (!this->IsImported()) {
     // Initialize the INCLUDE_DIRECTORIES property based on the current value
     // of the same directory property:
-    const cmStringRange parentIncludes =
-      this->Makefile->GetIncludeDirectoriesEntries();
-    const cmBacktraceRange parentIncludesBts =
-      this->Makefile->GetIncludeDirectoriesBacktraces();
+    CApp(impl->IncludeDirectoriesEntries,
+         impl->Makefile->GetIncludeDirectoriesEntries());
+    CApp(impl->IncludeDirectoriesBacktraces,
+         impl->Makefile->GetIncludeDirectoriesBacktraces());
 
-    this->Internal->IncludeDirectoriesEntries.insert(
-      this->Internal->IncludeDirectoriesEntries.end(), parentIncludes.begin(),
-      parentIncludes.end());
-    this->Internal->IncludeDirectoriesBacktraces.insert(
-      this->Internal->IncludeDirectoriesBacktraces.end(),
-      parentIncludesBts.begin(), parentIncludesBts.end());
+    {
+      auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories();
+      impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end());
+    }
 
-    const std::set<std::string> parentSystemIncludes =
-      this->Makefile->GetSystemIncludeDirectories();
+    CApp(impl->CompileOptionsEntries,
+         impl->Makefile->GetCompileOptionsEntries());
+    CApp(impl->CompileOptionsBacktraces,
+         impl->Makefile->GetCompileOptionsBacktraces());
 
-    this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
-                                          parentSystemIncludes.end());
+    CApp(impl->LinkOptionsEntries, impl->Makefile->GetLinkOptionsEntries());
+    CApp(impl->LinkOptionsBacktraces,
+         impl->Makefile->GetLinkOptionsBacktraces());
 
-    const cmStringRange parentCompileOptions =
-      this->Makefile->GetCompileOptionsEntries();
-    const cmBacktraceRange parentCompileOptionsBts =
-      this->Makefile->GetCompileOptionsBacktraces();
-
-    this->Internal->CompileOptionsEntries.insert(
-      this->Internal->CompileOptionsEntries.end(),
-      parentCompileOptions.begin(), parentCompileOptions.end());
-    this->Internal->CompileOptionsBacktraces.insert(
-      this->Internal->CompileOptionsBacktraces.end(),
-      parentCompileOptionsBts.begin(), parentCompileOptionsBts.end());
-
-    const cmStringRange parentLinkOptions =
-      this->Makefile->GetLinkOptionsEntries();
-    const cmBacktraceRange parentLinkOptionsBts =
-      this->Makefile->GetLinkOptionsBacktraces();
-
-    this->Internal->LinkOptionsEntries.insert(
-      this->Internal->LinkOptionsEntries.end(), parentLinkOptions.begin(),
-      parentLinkOptions.end());
-    this->Internal->LinkOptionsBacktraces.insert(
-      this->Internal->LinkOptionsBacktraces.end(),
-      parentLinkOptionsBts.begin(), parentLinkOptionsBts.end());
-
-    const cmStringRange parentLinkDirectories =
-      this->Makefile->GetLinkDirectoriesEntries();
-    const cmBacktraceRange parentLinkDirectoriesBts =
-      this->Makefile->GetLinkDirectoriesBacktraces();
-
-    this->Internal->LinkDirectoriesEntries.insert(
-      this->Internal->LinkDirectoriesEntries.end(),
-      parentLinkDirectories.begin(), parentLinkDirectories.end());
-    this->Internal->LinkDirectoriesBacktraces.insert(
-      this->Internal->LinkDirectoriesBacktraces.end(),
-      parentLinkDirectoriesBts.begin(), parentLinkDirectoriesBts.end());
+    CApp(impl->LinkDirectoriesEntries,
+         impl->Makefile->GetLinkDirectoriesEntries());
+    CApp(impl->LinkDirectoriesBacktraces,
+         impl->Makefile->GetLinkDirectoriesBacktraces());
   }
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
       this->GetType() != cmStateEnums::UTILITY) {
-    this->SetPropertyDefault("C_VISIBILITY_PRESET", nullptr);
-    this->SetPropertyDefault("CXX_VISIBILITY_PRESET", nullptr);
-    this->SetPropertyDefault("CUDA_VISIBILITY_PRESET", nullptr);
-    this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", nullptr);
+    InitProperty("C_VISIBILITY_PRESET", nullptr);
+    InitProperty("CXX_VISIBILITY_PRESET", nullptr);
+    InitProperty("CUDA_VISIBILITY_PRESET", nullptr);
+    InitProperty("VISIBILITY_INLINES_HIDDEN", nullptr);
   }
 
-  if (this->TargetTypeValue == cmStateEnums::EXECUTABLE) {
-    this->SetPropertyDefault("ANDROID_GUI", nullptr);
-    this->SetPropertyDefault("CROSSCOMPILING_EMULATOR", nullptr);
-    this->SetPropertyDefault("ENABLE_EXPORTS", nullptr);
+  if (impl->TargetType == cmStateEnums::EXECUTABLE) {
+    InitProperty("ANDROID_GUI", nullptr);
+    InitProperty("CROSSCOMPILING_EMULATOR", nullptr);
+    InitProperty("ENABLE_EXPORTS", nullptr);
   }
-  if (this->TargetTypeValue == cmStateEnums::SHARED_LIBRARY ||
-      this->TargetTypeValue == cmStateEnums::MODULE_LIBRARY) {
+  if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+      impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
     this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
   }
-  if (this->TargetTypeValue == cmStateEnums::SHARED_LIBRARY ||
-      this->TargetTypeValue == cmStateEnums::EXECUTABLE) {
-    this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
+  if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+      impl->TargetType == cmStateEnums::EXECUTABLE) {
+    InitProperty("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
   }
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
       this->GetType() != cmStateEnums::UTILITY) {
-    this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", nullptr);
+    InitProperty("POSITION_INDEPENDENT_CODE", nullptr);
   }
 
   // Record current policies for later use.
-  this->Makefile->RecordPolicies(this->PolicyMap);
+  impl->Makefile->RecordPolicies(impl->PolicyMap);
 
-  if (this->TargetTypeValue == cmStateEnums::INTERFACE_LIBRARY) {
+  if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
     // This policy is checked in a few conditions. The properties relevant
     // to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY
     // targets,
     // so ensure that the conditions don't lead to nonsense.
-    this->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+    impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
   }
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
       this->GetType() != cmStateEnums::UTILITY) {
-    this->SetPropertyDefault("JOB_POOL_COMPILE", nullptr);
-    this->SetPropertyDefault("JOB_POOL_LINK", nullptr);
+    InitProperty("JOB_POOL_COMPILE", nullptr);
+    InitProperty("JOB_POOL_LINK", nullptr);
   }
 
-  if (this->TargetTypeValue <= cmStateEnums::UTILITY) {
-    this->SetPropertyDefault("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
+  if (impl->TargetType <= cmStateEnums::UTILITY) {
+    InitProperty("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
   }
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -474,7 +493,7 @@
           if (assignment != std::string::npos) {
             const std::string propName = vsGlobal + i.substr(0, assignment);
             const std::string propValue = i.substr(assignment + 1);
-            this->SetPropertyDefault(propName, propValue.c_str());
+            InitProperty(propName, propValue.c_str());
           }
         }
       }
@@ -482,20 +501,56 @@
   }
 }
 
-cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
+cmTarget::cmTarget(cmTarget&&) noexcept = default;
+cmTarget::~cmTarget() = default;
+
+cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
+
+cmStateEnums::TargetType cmTarget::GetType() const
 {
-  return this->GetMakefile()->GetGlobalGenerator();
+  return impl->TargetType;
 }
 
-void cmTarget::AddUtility(std::string const& u, cmMakefile* mf)
+cmMakefile* cmTarget::GetMakefile() const
 {
-  BT<std::string> util(u, mf ? mf->GetBacktrace() : cmListFileBacktrace());
-  this->Utilities.insert(util);
+  return impl->Makefile;
+}
+
+cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
+{
+  return impl->PolicyMap;
+}
+
+const std::string& cmTarget::GetName() const
+{
+  return impl->Name;
+}
+
+cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
+  cmPolicies::PolicyID policy) const
+{
+  return impl->PolicyMap.Get(policy);
+}
+
+cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
+{
+  return impl->Makefile->GetGlobalGenerator();
+}
+
+void cmTarget::AddUtility(std::string const& name, cmMakefile* mf)
+{
+  impl->Utilities.insert(
+    BT<std::string>(name, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
+}
+
+std::set<BT<std::string>> const& cmTarget::GetUtilities() const
+{
+  return impl->Utilities;
 }
 
 cmListFileBacktrace const& cmTarget::GetBacktrace() const
 {
-  return this->Backtrace;
+  return impl->Backtrace;
 }
 
 bool cmTarget::IsExecutableWithExports() const
@@ -504,34 +559,57 @@
           this->GetPropertyAsBool("ENABLE_EXPORTS"));
 }
 
-bool cmTarget::HasImportLibrary() const
-{
-  return (this->DLLPlatform &&
-          (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
-           this->IsExecutableWithExports()));
-}
-
 bool cmTarget::IsFrameworkOnApple() const
 {
   return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
            this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
-          this->Makefile->IsOn("APPLE") &&
+          impl->Makefile->IsOn("APPLE") &&
           this->GetPropertyAsBool("FRAMEWORK"));
 }
 
 bool cmTarget::IsAppBundleOnApple() const
 {
   return (this->GetType() == cmStateEnums::EXECUTABLE &&
-          this->Makefile->IsOn("APPLE") &&
+          impl->Makefile->IsOn("APPLE") &&
           this->GetPropertyAsBool("MACOSX_BUNDLE"));
 }
 
+std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
+{
+  return impl->PreBuildCommands;
+}
+
+void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
+{
+  impl->PreBuildCommands.push_back(cmd);
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
+{
+  return impl->PreLinkCommands;
+}
+
+void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
+{
+  impl->PreLinkCommands.push_back(cmd);
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
+{
+  return impl->PostBuildCommands;
+}
+
+void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
+{
+  impl->PostBuildCommands.push_back(cmd);
+}
+
 void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
 {
   if (!srcs.empty()) {
-    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    this->Internal->SourceEntries.push_back(cmJoin(srcs, ";"));
-    this->Internal->SourceBacktraces.push_back(lfbt);
+    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+    impl->SourceEntries.push_back(cmJoin(srcs, ";"));
+    impl->SourceBacktraces.push_back(lfbt);
   }
 }
 
@@ -542,25 +620,25 @@
   for (auto filename : srcs) {
     if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
       if (!filename.empty()) {
-        filename = this->ProcessSourceItemCMP0049(filename);
+        filename = impl->ProcessSourceItemCMP0049(filename);
         if (filename.empty()) {
           return;
         }
       }
-      this->Makefile->GetOrCreateSource(filename);
+      impl->Makefile->GetOrCreateSource(filename);
     }
     srcFiles += sep;
     srcFiles += filename;
     sep = ";";
   }
   if (!srcFiles.empty()) {
-    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    this->Internal->SourceEntries.push_back(std::move(srcFiles));
-    this->Internal->SourceBacktraces.push_back(lfbt);
+    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+    impl->SourceEntries.push_back(std::move(srcFiles));
+    impl->SourceBacktraces.push_back(lfbt);
   }
 }
 
-std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
+std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s)
 {
   std::string src = s;
 
@@ -585,7 +663,7 @@
     }
     if (!noMessage) {
       e << "Legacy variable expansion in source file \"" << s
-        << "\" expanded to \"" << src << "\" in target \"" << this->GetName()
+        << "\" expanded to \"" << src << "\" in target \"" << this->Name
         << "\".  This behavior will be removed in a "
            "future version of CMake.";
       this->Makefile->IssueMessage(messageType, e.str());
@@ -599,7 +677,7 @@
 
 cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
 {
-  std::string src = this->ProcessSourceItemCMP0049(s);
+  std::string src = impl->ProcessSourceItemCMP0049(s);
   if (!s.empty() && src.empty()) {
     return nullptr;
   }
@@ -663,26 +741,22 @@
 
 cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
 {
-  cmSourceFileLocation sfl(this->Makefile, src,
+  cmSourceFileLocation sfl(impl->Makefile, src,
                            cmSourceFileLocationKind::Known);
-  if (std::find_if(this->Internal->SourceEntries.begin(),
-                   this->Internal->SourceEntries.end(),
+  if (std::find_if(impl->SourceEntries.begin(), impl->SourceEntries.end(),
                    TargetPropertyEntryFinder(sfl)) ==
-      this->Internal->SourceEntries.end()) {
-    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    this->Internal->SourceEntries.insert(
-      before ? this->Internal->SourceEntries.begin()
-             : this->Internal->SourceEntries.end(),
-      src);
-    this->Internal->SourceBacktraces.insert(
-      before ? this->Internal->SourceBacktraces.begin()
-             : this->Internal->SourceBacktraces.end(),
-      lfbt);
+      impl->SourceEntries.end()) {
+    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+    impl->SourceEntries.insert(
+      before ? impl->SourceEntries.begin() : impl->SourceEntries.end(), src);
+    impl->SourceBacktraces.insert(before ? impl->SourceBacktraces.begin()
+                                         : impl->SourceBacktraces.end(),
+                                  lfbt);
   }
   if (cmGeneratorExpression::Find(src) != std::string::npos) {
     return nullptr;
   }
-  return this->Makefile->GetOrCreateSource(src, false,
+  return impl->Makefile->GetOrCreateSource(src, false,
                                            cmSourceFileLocationKind::Known);
 }
 
@@ -702,15 +776,13 @@
 
   // Get the list of configurations considered to be DEBUG.
   std::vector<std::string> debugConfigs =
-    this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+    impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
 
   std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
 
   if (debugConfigs.size() > 1) {
-    for (std::vector<std::string>::const_iterator li =
-           debugConfigs.begin() + 1;
-         li != debugConfigs.end(); ++li) {
-      configString += ",$<CONFIG:" + *li + ">";
+    for (std::string const& conf : cmMakeRange(debugConfigs).advance(1)) {
+      configString += ",$<CONFIG:" + conf + ">";
     }
     configString = "$<OR:" + configString + ">";
   }
@@ -730,13 +802,13 @@
                                    cmListFileContext const& lfc)
 {
   bool ret = true;
-  if (!this->TLLCommands.empty()) {
-    if (this->TLLCommands.back().first != signature) {
+  if (!impl->TLLCommands.empty()) {
+    if (impl->TLLCommands.back().first != signature) {
       ret = false;
     }
   }
-  if (this->TLLCommands.empty() || this->TLLCommands.back().second != lfc) {
-    this->TLLCommands.emplace_back(signature, lfc);
+  if (impl->TLLCommands.empty() || impl->TLLCommands.back().second != lfc) {
+    impl->TLLCommands.emplace_back(signature, lfc);
   }
   return ret;
 }
@@ -746,18 +818,63 @@
   const char* sigString =
     (sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
   s << "The uses of the " << sigString << " signature are here:\n";
-  cmStateDirectory cmDir =
-    this->GetMakefile()->GetStateSnapshot().GetDirectory();
-  for (auto const& cmd : this->TLLCommands) {
+  cmStateDirectory cmDir = impl->Makefile->GetStateSnapshot().GetDirectory();
+  for (auto const& cmd : impl->TLLCommands) {
     if (cmd.first == sig) {
       cmListFileContext lfc = cmd.second;
       lfc.FilePath = cmDir.ConvertToRelPathIfNotContained(
-        this->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
+        impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
       s << " * " << lfc << std::endl;
     }
   }
 }
 
+std::string const& cmTarget::GetInstallPath() const
+{
+  return impl->InstallPath;
+}
+
+void cmTarget::SetInstallPath(std::string const& name)
+{
+  impl->InstallPath = name;
+}
+
+std::string const& cmTarget::GetRuntimeInstallPath() const
+{
+  return impl->RuntimeInstallPath;
+}
+
+void cmTarget::SetRuntimeInstallPath(std::string const& name)
+{
+  impl->RuntimeInstallPath = name;
+}
+
+bool cmTarget::GetHaveInstallRule() const
+{
+  return impl->HaveInstallRule;
+}
+
+void cmTarget::SetHaveInstallRule(bool hir)
+{
+  impl->HaveInstallRule = hir;
+}
+
+bool cmTarget::GetIsGeneratorProvided() const
+{
+  return impl->IsGeneratorProvided;
+}
+
+void cmTarget::SetIsGeneratorProvided(bool igp)
+{
+  impl->IsGeneratorProvided = igp;
+}
+
+cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
+  const
+{
+  return impl->OriginalLinkLibraries;
+}
+
 void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
                               cmTargetLinkLibraryType llt)
 {
@@ -785,11 +902,11 @@
       (tgt &&
        (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
         tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
-      (this->Name == lib)) {
+      (impl->Name == lib)) {
     return;
   }
 
-  this->OriginalLinkLibraries.emplace_back(lib, llt);
+  impl->OriginalLinkLibraries.emplace_back(lib, llt);
 
   // Add the explicit dependency information for libraries. This is
   // simply a set of libraries separated by ";". There should always
@@ -799,11 +916,11 @@
   // may be purposefully duplicated to handle recursive dependencies,
   // and we removing one instance will break the link line. Duplicates
   // will be appropriately eliminated at emit time.
-  if (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY &&
-      this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY &&
+  if (impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
+      impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
       (this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
        this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
-    std::string targetEntry = this->Name;
+    std::string targetEntry = impl->Name;
     targetEntry += "_LIB_DEPENDS";
     std::string dependencies;
     const char* old_val = mf.GetDefinition(targetEntry);
@@ -831,94 +948,99 @@
 
 void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
 {
-  this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+  impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+}
+
+std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
+{
+  return impl->SystemIncludeDirectories;
 }
 
 cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
 {
-  return cmMakeRange(this->Internal->IncludeDirectoriesEntries);
+  return cmMakeRange(impl->IncludeDirectoriesEntries);
 }
 
 cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
 {
-  return cmMakeRange(this->Internal->IncludeDirectoriesBacktraces);
+  return cmMakeRange(impl->IncludeDirectoriesBacktraces);
 }
 
 cmStringRange cmTarget::GetCompileOptionsEntries() const
 {
-  return cmMakeRange(this->Internal->CompileOptionsEntries);
+  return cmMakeRange(impl->CompileOptionsEntries);
 }
 
 cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
 {
-  return cmMakeRange(this->Internal->CompileOptionsBacktraces);
+  return cmMakeRange(impl->CompileOptionsBacktraces);
 }
 
 cmStringRange cmTarget::GetCompileFeaturesEntries() const
 {
-  return cmMakeRange(this->Internal->CompileFeaturesEntries);
+  return cmMakeRange(impl->CompileFeaturesEntries);
 }
 
 cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
 {
-  return cmMakeRange(this->Internal->CompileFeaturesBacktraces);
+  return cmMakeRange(impl->CompileFeaturesBacktraces);
 }
 
 cmStringRange cmTarget::GetCompileDefinitionsEntries() const
 {
-  return cmMakeRange(this->Internal->CompileDefinitionsEntries);
+  return cmMakeRange(impl->CompileDefinitionsEntries);
 }
 
 cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
 {
-  return cmMakeRange(this->Internal->CompileDefinitionsBacktraces);
+  return cmMakeRange(impl->CompileDefinitionsBacktraces);
 }
 
 cmStringRange cmTarget::GetSourceEntries() const
 {
-  return cmMakeRange(this->Internal->SourceEntries);
+  return cmMakeRange(impl->SourceEntries);
 }
 
 cmBacktraceRange cmTarget::GetSourceBacktraces() const
 {
-  return cmMakeRange(this->Internal->SourceBacktraces);
+  return cmMakeRange(impl->SourceBacktraces);
 }
 
 cmStringRange cmTarget::GetLinkOptionsEntries() const
 {
-  return cmMakeRange(this->Internal->LinkOptionsEntries);
+  return cmMakeRange(impl->LinkOptionsEntries);
 }
 
 cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
 {
-  return cmMakeRange(this->Internal->LinkOptionsBacktraces);
+  return cmMakeRange(impl->LinkOptionsBacktraces);
 }
 
 cmStringRange cmTarget::GetLinkDirectoriesEntries() const
 {
-  return cmMakeRange(this->Internal->LinkDirectoriesEntries);
+  return cmMakeRange(impl->LinkDirectoriesEntries);
 }
 
 cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
 {
-  return cmMakeRange(this->Internal->LinkDirectoriesBacktraces);
+  return cmMakeRange(impl->LinkDirectoriesBacktraces);
 }
 
 cmStringRange cmTarget::GetLinkImplementationEntries() const
 {
-  return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
+  return cmMakeRange(impl->LinkImplementationPropertyEntries);
 }
 
 cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
 {
-  return cmMakeRange(this->Internal->LinkImplementationPropertyBacktraces);
+  return cmMakeRange(impl->LinkImplementationPropertyBacktraces);
 }
 
 void cmTarget::SetProperty(const std::string& prop, const char* value)
 {
   if (!cmTargetPropertyComputer::PassesWhitelist(
-        this->GetType(), prop, this->Makefile->GetMessenger(),
-        this->Makefile->GetBacktrace())) {
+        this->GetType(), prop, impl->Makefile->GetMessenger(),
+        impl->Makefile->GetBacktrace())) {
     return;
   }
 #define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
@@ -940,133 +1062,133 @@
   if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
     std::ostringstream e;
     e << "MANUALLY_ADDED_DEPENDENCIES property is read-only\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propNAME) {
     std::ostringstream e;
     e << "NAME property is read-only\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propTYPE) {
     std::ostringstream e;
     e << "TYPE property is read-only\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propEXPORT_NAME && this->IsImported()) {
     std::ostringstream e;
     e << "EXPORT_NAME property can't be set on imported targets (\""
-      << this->Name << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << impl->Name << "\")\n";
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propSOURCES && this->IsImported()) {
     std::ostringstream e;
-    e << "SOURCES property can't be set on imported targets (\"" << this->Name
+    e << "SOURCES property can't be set on imported targets (\"" << impl->Name
       << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propIMPORTED_GLOBAL && !this->IsImported()) {
     std::ostringstream e;
     e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\""
-      << this->Name << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << impl->Name << "\")\n";
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
 
   if (prop == propINCLUDE_DIRECTORIES) {
-    this->Internal->IncludeDirectoriesEntries.clear();
-    this->Internal->IncludeDirectoriesBacktraces.clear();
+    impl->IncludeDirectoriesEntries.clear();
+    impl->IncludeDirectoriesBacktraces.clear();
     if (value) {
-      this->Internal->IncludeDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+      impl->IncludeDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->IncludeDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == propCOMPILE_OPTIONS) {
-    this->Internal->CompileOptionsEntries.clear();
-    this->Internal->CompileOptionsBacktraces.clear();
+    impl->CompileOptionsEntries.clear();
+    impl->CompileOptionsBacktraces.clear();
     if (value) {
-      this->Internal->CompileOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+      impl->CompileOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->CompileOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == propCOMPILE_FEATURES) {
-    this->Internal->CompileFeaturesEntries.clear();
-    this->Internal->CompileFeaturesBacktraces.clear();
+    impl->CompileFeaturesEntries.clear();
+    impl->CompileFeaturesBacktraces.clear();
     if (value) {
-      this->Internal->CompileFeaturesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+      impl->CompileFeaturesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->CompileFeaturesBacktraces.push_back(lfbt);
     }
   } else if (prop == propCOMPILE_DEFINITIONS) {
-    this->Internal->CompileDefinitionsEntries.clear();
-    this->Internal->CompileDefinitionsBacktraces.clear();
+    impl->CompileDefinitionsEntries.clear();
+    impl->CompileDefinitionsBacktraces.clear();
     if (value) {
-      this->Internal->CompileDefinitionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+      impl->CompileDefinitionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->CompileDefinitionsBacktraces.push_back(lfbt);
     }
   } else if (prop == propLINK_OPTIONS) {
-    this->Internal->LinkOptionsEntries.clear();
-    this->Internal->LinkOptionsBacktraces.clear();
+    impl->LinkOptionsEntries.clear();
+    impl->LinkOptionsBacktraces.clear();
     if (value) {
-      this->Internal->LinkOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+      impl->LinkOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->LinkOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == propLINK_DIRECTORIES) {
-    this->Internal->LinkDirectoriesEntries.clear();
-    this->Internal->LinkDirectoriesBacktraces.clear();
+    impl->LinkDirectoriesEntries.clear();
+    impl->LinkDirectoriesBacktraces.clear();
     if (value) {
-      this->Internal->LinkDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+      impl->LinkDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->LinkDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == propLINK_LIBRARIES) {
-    this->Internal->LinkImplementationPropertyEntries.clear();
-    this->Internal->LinkImplementationPropertyBacktraces.clear();
+    impl->LinkImplementationPropertyEntries.clear();
+    impl->LinkImplementationPropertyBacktraces.clear();
     if (value) {
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->LinkImplementationPropertyEntries.emplace_back(value);
-      this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->LinkImplementationPropertyEntries.emplace_back(value);
+      impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
     }
   } else if (prop == propSOURCES) {
-    this->Internal->SourceEntries.clear();
-    this->Internal->SourceBacktraces.clear();
+    impl->SourceEntries.clear();
+    impl->SourceBacktraces.clear();
     if (value) {
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->SourceEntries.emplace_back(value);
-      this->Internal->SourceBacktraces.push_back(lfbt);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->SourceEntries.emplace_back(value);
+      impl->SourceBacktraces.push_back(lfbt);
     }
   } else if (prop == propIMPORTED_GLOBAL) {
     if (!cmSystemTools::IsOn(value)) {
       std::ostringstream e;
       e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
-        << this->Name << "\")\n";
-      this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+        << impl->Name << "\")\n";
+      impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return;
     }
     /* no need to change anything if value does not change */
-    if (!this->ImportedGloballyVisible) {
-      this->ImportedGloballyVisible = true;
+    if (!impl->ImportedGloballyVisible) {
+      impl->ImportedGloballyVisible = true;
       this->GetGlobalGenerator()->IndexTarget(this);
     }
   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
-             !this->CheckImportedLibName(prop, value ? value : "")) {
+             !impl->CheckImportedLibName(prop, value ? value : "")) {
     /* error was reported by check method */
   } else if (prop == propCUDA_PTX_COMPILATION &&
              this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
     std::ostringstream e;
     e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT "
          "targets (\""
-      << this->Name << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << impl->Name << "\")\n";
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   } else {
-    this->Properties.SetProperty(prop, value);
+    impl->Properties.SetProperty(prop, value);
   }
 }
 
@@ -1074,89 +1196,89 @@
                               bool asString)
 {
   if (!cmTargetPropertyComputer::PassesWhitelist(
-        this->GetType(), prop, this->Makefile->GetMessenger(),
-        this->Makefile->GetBacktrace())) {
+        this->GetType(), prop, impl->Makefile->GetMessenger(),
+        impl->Makefile->GetBacktrace())) {
     return;
   }
   if (prop == "NAME") {
     std::ostringstream e;
     e << "NAME property is read-only\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "EXPORT_NAME" && this->IsImported()) {
     std::ostringstream e;
     e << "EXPORT_NAME property can't be set on imported targets (\""
-      << this->Name << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << impl->Name << "\")\n";
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "SOURCES" && this->IsImported()) {
     std::ostringstream e;
-    e << "SOURCES property can't be set on imported targets (\"" << this->Name
+    e << "SOURCES property can't be set on imported targets (\"" << impl->Name
       << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "IMPORTED_GLOBAL") {
     std::ostringstream e;
     e << "IMPORTED_GLOBAL property can't be appended, only set on imported "
          "targets (\""
-      << this->Name << "\")\n";
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << impl->Name << "\")\n";
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "INCLUDE_DIRECTORIES") {
     if (value && *value) {
-      this->Internal->IncludeDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+      impl->IncludeDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->IncludeDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_OPTIONS") {
     if (value && *value) {
-      this->Internal->CompileOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+      impl->CompileOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->CompileOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_FEATURES") {
     if (value && *value) {
-      this->Internal->CompileFeaturesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+      impl->CompileFeaturesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->CompileFeaturesBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_DEFINITIONS") {
     if (value && *value) {
-      this->Internal->CompileDefinitionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+      impl->CompileDefinitionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->CompileDefinitionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_OPTIONS") {
     if (value && *value) {
-      this->Internal->LinkOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+      impl->LinkOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->LinkOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_DIRECTORIES") {
     if (value && *value) {
-      this->Internal->LinkDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+      impl->LinkDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->LinkDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_LIBRARIES") {
     if (value && *value) {
-      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-      this->Internal->LinkImplementationPropertyEntries.emplace_back(value);
-      this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+      impl->LinkImplementationPropertyEntries.emplace_back(value);
+      impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
     }
   } else if (prop == "SOURCES") {
-    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    this->Internal->SourceEntries.emplace_back(value);
-    this->Internal->SourceBacktraces.push_back(lfbt);
+    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+    impl->SourceEntries.emplace_back(value);
+    impl->SourceBacktraces.push_back(lfbt);
   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
                                  prop + " property may not be APPENDed.");
   } else {
-    this->Properties.AppendProperty(prop, value, asString);
+    impl->Properties.AppendProperty(prop, value, asString);
   }
 }
 
@@ -1169,17 +1291,17 @@
       !this->IsExecutableWithExports()) {
     return;
   }
-  if (this->BuildInterfaceIncludesAppended) {
+  if (impl->BuildInterfaceIncludesAppended) {
     return;
   }
-  this->BuildInterfaceIncludesAppended = true;
+  impl->BuildInterfaceIncludesAppended = true;
 
-  if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
-    std::string dirs = this->Makefile->GetCurrentBinaryDirectory();
+  if (impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
+    std::string dirs = impl->Makefile->GetCurrentBinaryDirectory();
     if (!dirs.empty()) {
       dirs += ';';
     }
-    dirs += this->Makefile->GetCurrentSourceDirectory();
+    dirs += impl->Makefile->GetCurrentSourceDirectory();
     if (!dirs.empty()) {
       this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
                            ("$<BUILD_INTERFACE:" + dirs + ">").c_str());
@@ -1191,67 +1313,66 @@
                              cmListFileBacktrace const& bt, bool before)
 {
   std::vector<std::string>::iterator position = before
-    ? this->Internal->IncludeDirectoriesEntries.begin()
-    : this->Internal->IncludeDirectoriesEntries.end();
+    ? impl->IncludeDirectoriesEntries.begin()
+    : impl->IncludeDirectoriesEntries.end();
 
   std::vector<cmListFileBacktrace>::iterator btPosition = before
-    ? this->Internal->IncludeDirectoriesBacktraces.begin()
-    : this->Internal->IncludeDirectoriesBacktraces.end();
+    ? impl->IncludeDirectoriesBacktraces.begin()
+    : impl->IncludeDirectoriesBacktraces.end();
 
-  this->Internal->IncludeDirectoriesEntries.insert(position, entry);
-  this->Internal->IncludeDirectoriesBacktraces.insert(btPosition, bt);
+  impl->IncludeDirectoriesEntries.insert(position, entry);
+  impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertCompileOption(std::string const& entry,
                                    cmListFileBacktrace const& bt, bool before)
 {
   std::vector<std::string>::iterator position = before
-    ? this->Internal->CompileOptionsEntries.begin()
-    : this->Internal->CompileOptionsEntries.end();
+    ? impl->CompileOptionsEntries.begin()
+    : impl->CompileOptionsEntries.end();
 
   std::vector<cmListFileBacktrace>::iterator btPosition = before
-    ? this->Internal->CompileOptionsBacktraces.begin()
-    : this->Internal->CompileOptionsBacktraces.end();
+    ? impl->CompileOptionsBacktraces.begin()
+    : impl->CompileOptionsBacktraces.end();
 
-  this->Internal->CompileOptionsEntries.insert(position, entry);
-  this->Internal->CompileOptionsBacktraces.insert(btPosition, bt);
+  impl->CompileOptionsEntries.insert(position, entry);
+  impl->CompileOptionsBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertCompileDefinition(std::string const& entry,
                                        cmListFileBacktrace const& bt)
 {
-  this->Internal->CompileDefinitionsEntries.push_back(entry);
-  this->Internal->CompileDefinitionsBacktraces.push_back(bt);
+  impl->CompileDefinitionsEntries.push_back(entry);
+  impl->CompileDefinitionsBacktraces.push_back(bt);
 }
 
 void cmTarget::InsertLinkOption(std::string const& entry,
                                 cmListFileBacktrace const& bt, bool before)
 {
-  std::vector<std::string>::iterator position = before
-    ? this->Internal->LinkOptionsEntries.begin()
-    : this->Internal->LinkOptionsEntries.end();
+  std::vector<std::string>::iterator position =
+    before ? impl->LinkOptionsEntries.begin() : impl->LinkOptionsEntries.end();
 
   std::vector<cmListFileBacktrace>::iterator btPosition = before
-    ? this->Internal->LinkOptionsBacktraces.begin()
-    : this->Internal->LinkOptionsBacktraces.end();
+    ? impl->LinkOptionsBacktraces.begin()
+    : impl->LinkOptionsBacktraces.end();
 
-  this->Internal->LinkOptionsEntries.insert(position, entry);
-  this->Internal->LinkOptionsBacktraces.insert(btPosition, bt);
+  impl->LinkOptionsEntries.insert(position, entry);
+  impl->LinkOptionsBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertLinkDirectory(std::string const& entry,
                                    cmListFileBacktrace const& bt, bool before)
 {
   std::vector<std::string>::iterator position = before
-    ? this->Internal->LinkDirectoriesEntries.begin()
-    : this->Internal->LinkDirectoriesEntries.end();
+    ? impl->LinkDirectoriesEntries.begin()
+    : impl->LinkDirectoriesEntries.end();
 
   std::vector<cmListFileBacktrace>::iterator btPosition = before
-    ? this->Internal->LinkDirectoriesBacktraces.begin()
-    : this->Internal->LinkDirectoriesBacktraces.end();
+    ? impl->LinkDirectoriesBacktraces.begin()
+    : impl->LinkDirectoriesBacktraces.end();
 
-  this->Internal->LinkDirectoriesEntries.insert(position, entry);
-  this->Internal->LinkDirectoriesBacktraces.insert(btPosition, bt);
+  impl->LinkDirectoriesEntries.insert(position, entry);
+  impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
 }
 
 static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
@@ -1402,12 +1523,12 @@
   }
   if (specialProps.count(prop)) {
     if (prop == propLINK_LIBRARIES) {
-      if (this->Internal->LinkImplementationPropertyEntries.empty()) {
+      if (impl->LinkImplementationPropertyEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->LinkImplementationPropertyEntries, ";");
+      output = cmJoin(impl->LinkImplementationPropertyEntries, ";");
       return output.c_str();
     }
     // the type property returns what type the target is
@@ -1415,67 +1536,67 @@
       return cmState::GetTargetTypeName(this->GetType());
     }
     if (prop == propINCLUDE_DIRECTORIES) {
-      if (this->Internal->IncludeDirectoriesEntries.empty()) {
+      if (impl->IncludeDirectoriesEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";");
+      output = cmJoin(impl->IncludeDirectoriesEntries, ";");
       return output.c_str();
     }
     if (prop == propCOMPILE_FEATURES) {
-      if (this->Internal->CompileFeaturesEntries.empty()) {
+      if (impl->CompileFeaturesEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->CompileFeaturesEntries, ";");
+      output = cmJoin(impl->CompileFeaturesEntries, ";");
       return output.c_str();
     }
     if (prop == propCOMPILE_OPTIONS) {
-      if (this->Internal->CompileOptionsEntries.empty()) {
+      if (impl->CompileOptionsEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->CompileOptionsEntries, ";");
+      output = cmJoin(impl->CompileOptionsEntries, ";");
       return output.c_str();
     }
     if (prop == propCOMPILE_DEFINITIONS) {
-      if (this->Internal->CompileDefinitionsEntries.empty()) {
+      if (impl->CompileDefinitionsEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
+      output = cmJoin(impl->CompileDefinitionsEntries, ";");
       return output.c_str();
     }
     if (prop == propLINK_OPTIONS) {
-      if (this->Internal->LinkOptionsEntries.empty()) {
+      if (impl->LinkOptionsEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->LinkOptionsEntries, ";");
+      output = cmJoin(impl->LinkOptionsEntries, ";");
       return output.c_str();
     }
     if (prop == propLINK_DIRECTORIES) {
-      if (this->Internal->LinkDirectoriesEntries.empty()) {
+      if (impl->LinkDirectoriesEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Internal->LinkDirectoriesEntries, ";");
+      output = cmJoin(impl->LinkDirectoriesEntries, ";");
 
       return output.c_str();
     }
     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
-      if (this->Utilities.empty()) {
+      if (impl->Utilities.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(this->Utilities, ";");
+      output = cmJoin(impl->Utilities, ";");
       return output.c_str();
     }
     if (prop == propIMPORTED) {
@@ -1488,27 +1609,25 @@
       return this->GetName().c_str();
     }
     if (prop == propBINARY_DIR) {
-      return this->GetMakefile()
-        ->GetStateSnapshot()
+      return impl->Makefile->GetStateSnapshot()
         .GetDirectory()
         .GetCurrentBinary()
         .c_str();
     }
     if (prop == propSOURCE_DIR) {
-      return this->GetMakefile()
-        ->GetStateSnapshot()
+      return impl->Makefile->GetStateSnapshot()
         .GetDirectory()
         .GetCurrentSource()
         .c_str();
     }
   }
 
-  const char* retVal = this->Properties.GetPropertyValue(prop);
+  const char* retVal = impl->Properties.GetPropertyValue(prop);
   if (!retVal) {
-    const bool chain = this->GetMakefile()->GetState()->IsPropertyChained(
-      prop, cmProperty::TARGET);
+    const bool chain =
+      impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET);
     if (chain) {
-      return this->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
+      return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
         prop, chain);
     }
   }
@@ -1529,6 +1648,21 @@
   return cmSystemTools::IsOn(this->GetProperty(prop));
 }
 
+cmPropertyMap const& cmTarget::GetProperties() const
+{
+  return impl->Properties;
+}
+
+bool cmTarget::IsImported() const
+{
+  return impl->IsImportedTarget;
+}
+
+bool cmTarget::IsImportedGloballyVisible() const
+{
+  return impl->ImportedGloballyVisible;
+}
+
 const char* cmTarget::GetSuffixVariableInternal(
   cmStateEnums::ArtifactType artifact) const
 {
@@ -1556,7 +1690,7 @@
         case cmStateEnums::RuntimeBinaryArtifact:
           // Android GUI application packages store the native
           // binary as a shared library.
-          return (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+          return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
                     ? "CMAKE_SHARED_LIBRARY_SUFFIX"
                     : "CMAKE_EXECUTABLE_SUFFIX");
         case cmStateEnums::ImportLibraryArtifact:
@@ -1596,7 +1730,7 @@
         case cmStateEnums::RuntimeBinaryArtifact:
           // Android GUI application packages store the native
           // binary as a shared library.
-          return (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+          return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
                     ? "CMAKE_SHARED_LIBRARY_PREFIX"
                     : "");
         case cmStateEnums::ImportLibraryArtifact:
@@ -1670,25 +1804,11 @@
   return result;
 }
 
-void cmTarget::SetPropertyDefault(const std::string& property,
-                                  const char* default_value)
+bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
+                                             std::string const& value) const
 {
-  // Compute the name of the variable holding the default value.
-  std::string var = "CMAKE_";
-  var += property;
-
-  if (const char* value = this->Makefile->GetDefinition(var)) {
-    this->SetProperty(property, value);
-  } else if (default_value) {
-    this->SetProperty(property, default_value);
-  }
-}
-
-bool cmTarget::CheckImportedLibName(std::string const& prop,
-                                    std::string const& value) const
-{
-  if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY ||
-      !this->IsImported()) {
+  if (this->TargetType != cmStateEnums::INTERFACE_LIBRARY ||
+      !this->IsImportedTarget) {
     this->Makefile->IssueMessage(
       MessageType::FATAL_ERROR,
       prop +
@@ -1748,7 +1868,9 @@
   // If we needed to find one of the mapped configurations but did not
   // On a DLL platform there may be only IMPORTED_IMPLIB for a shared
   // library or an executable with exports.
-  bool allowImp = this->HasImportLibrary();
+  bool allowImp = (impl->DLLPlatform &&
+                   (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+                    this->IsExecutableWithExports()));
 
   // If a mapping was found, check its configurations.
   for (std::vector<std::string>::const_iterator mci = mappedConfigs.begin();
@@ -1851,37 +1973,3 @@
 
   return true;
 }
-
-cmTargetInternalPointer::cmTargetInternalPointer()
-{
-  this->Pointer = new cmTargetInternals;
-}
-
-cmTargetInternalPointer::cmTargetInternalPointer(
-  cmTargetInternalPointer const& r)
-{
-  // Ideally cmTarget instances should never be copied.  However until
-  // we can make a sweep to remove that, this copy constructor avoids
-  // allowing the resources (Internals) to be copied.
-  this->Pointer = new cmTargetInternals(*r.Pointer);
-}
-
-cmTargetInternalPointer::~cmTargetInternalPointer()
-{
-  delete this->Pointer;
-}
-
-cmTargetInternalPointer& cmTargetInternalPointer::operator=(
-  cmTargetInternalPointer const& r)
-{
-  if (this == &r) {
-    return *this;
-  } // avoid warning on HP about self check
-  // Ideally cmTarget instances should never be copied.  However until
-  // we can make a sweep to remove that, this copy constructor avoids
-  // allowing the resources (Internals) to be copied.
-  cmTargetInternals* oldPointer = this->Pointer;
-  this->Pointer = new cmTargetInternals(*r.Pointer);
-  delete oldPointer;
-  return *this;
-}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 24b3742..0ac5ca7 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory> // IWYU pragma: keep
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -13,38 +14,23 @@
 #include <vector>
 
 #include "cmAlgorithms.h"
-#include "cmCustomCommand.h"
 #include "cmListFileCache.h"
 #include "cmPolicies.h"
-#include "cmPropertyMap.h"
 #include "cmStateTypes.h"
 #include "cmTargetLinkLibraryType.h"
 
+class cmCustomCommand;
 class cmGlobalGenerator;
 class cmMakefile;
 class cmMessenger;
+class cmPropertyMap;
 class cmSourceFile;
 class cmTargetInternals;
 
-class cmTargetInternalPointer
-{
-public:
-  cmTargetInternalPointer();
-  cmTargetInternalPointer(cmTargetInternalPointer const& r);
-  ~cmTargetInternalPointer();
-  cmTargetInternalPointer& operator=(cmTargetInternalPointer const& r);
-  cmTargetInternals* operator->() const { return this->Pointer; }
-  cmTargetInternals* Get() const { return this->Pointer; }
-
-private:
-  cmTargetInternals* Pointer;
-};
-
 /** \class cmTarget
  * \brief Represent a library or executable target loaded from a makefile.
  *
- * cmTarget represents a target loaded from
- * a makefile.
+ * cmTarget represents a target loaded from a makefile.
  */
 class cmTarget
 {
@@ -56,9 +42,6 @@
     VisibilityImportedGlobally
   };
 
-  cmTarget(std::string const& name, cmStateEnums::TargetType type,
-           Visibility vis, cmMakefile* mf);
-
   enum CustomCommandType
   {
     PRE_BUILD,
@@ -66,77 +49,68 @@
     POST_BUILD
   };
 
-  /**
-   * Return the type of target.
-   */
-  cmStateEnums::TargetType GetType() const { return this->TargetTypeValue; }
+  cmTarget(std::string const& name, cmStateEnums::TargetType type,
+           Visibility vis, cmMakefile* mf);
 
+  cmTarget(cmTarget const&) = delete;
+  cmTarget(cmTarget&&) noexcept;
+  ~cmTarget();
+
+  cmTarget& operator=(cmTarget const&) = delete;
+  cmTarget& operator=(cmTarget&&) noexcept;
+
+  //! Return the type of target.
+  cmStateEnums::TargetType GetType() const;
+
+  //! Get the cmMakefile that owns this target.
+  cmMakefile* GetMakefile() const;
+
+  //! Return the global generator.
   cmGlobalGenerator* GetGlobalGenerator() const;
 
-  ///! Set/Get the name of the target
-  const std::string& GetName() const { return this->Name; }
+  //! Set/Get the name of the target
+  const std::string& GetName() const;
 
-  /** Get the cmMakefile that owns this target.  */
-  cmMakefile* GetMakefile() const { return this->Makefile; }
+  //! Get the policy map
+  cmPolicies::PolicyMap const& GetPolicyMap() const;
+
+  //! Get policy status
+  cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID policy) const;
 
 #define DECLARE_TARGET_POLICY(POLICY)                                         \
   cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const                    \
   {                                                                           \
-    return this->PolicyMap.Get(cmPolicies::POLICY);                           \
+    return this->GetPolicyStatus(cmPolicies::POLICY);                         \
   }
 
   CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY)
 
 #undef DECLARE_TARGET_POLICY
 
-  /**
-   * Get the list of the custom commands for this target
-   */
-  std::vector<cmCustomCommand> const& GetPreBuildCommands() const
-  {
-    return this->PreBuildCommands;
-  }
-  std::vector<cmCustomCommand> const& GetPreLinkCommands() const
-  {
-    return this->PreLinkCommands;
-  }
-  std::vector<cmCustomCommand> const& GetPostBuildCommands() const
-  {
-    return this->PostBuildCommands;
-  }
-  void AddPreBuildCommand(cmCustomCommand const& cmd)
-  {
-    this->PreBuildCommands.push_back(cmd);
-  }
-  void AddPreLinkCommand(cmCustomCommand const& cmd)
-  {
-    this->PreLinkCommands.push_back(cmd);
-  }
-  void AddPostBuildCommand(cmCustomCommand const& cmd)
-  {
-    this->PostBuildCommands.push_back(cmd);
-  }
+  //! Get the list of the PRE_BUILD custom commands for this target
+  std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
+  void AddPreBuildCommand(cmCustomCommand const& cmd);
 
-  /**
-   * Add sources to the target.
-   */
+  //! Get the list of the PRE_LINK custom commands for this target
+  std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
+  void AddPreLinkCommand(cmCustomCommand const& cmd);
+
+  //! Get the list of the POST_BUILD custom commands for this target
+  std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
+  void AddPostBuildCommand(cmCustomCommand const& cmd);
+
+  //! Add sources to the target.
   void AddSources(std::vector<std::string> const& srcs);
   void AddTracedSources(std::vector<std::string> const& srcs);
   cmSourceFile* AddSourceCMP0049(const std::string& src);
   cmSourceFile* AddSource(const std::string& src, bool before = false);
 
-  //* how we identify a library, by name and type
+  //! how we identify a library, by name and type
   typedef std::pair<std::string, cmTargetLinkLibraryType> LibraryID;
-
   typedef std::vector<LibraryID> LinkLibraryVectorType;
-  const LinkLibraryVectorType& GetOriginalLinkLibraries() const
-  {
-    return this->OriginalLinkLibraries;
-  }
+  LinkLibraryVectorType const& GetOriginalLinkLibraries() const;
 
-  /**
-   * Clear the dependency information recorded for this target, if any.
-   */
+  //! Clear the dependency information recorded for this target, if any.
   void ClearDependencyInformation(cmMakefile& mf);
 
   void AddLinkLibrary(cmMakefile& mf, const std::string& lib,
@@ -157,83 +131,69 @@
    * Set the path where this target should be installed. This is relative to
    * INSTALL_PREFIX
    */
-  std::string GetInstallPath() const { return this->InstallPath; }
-  void SetInstallPath(const char* name) { this->InstallPath = name; }
+  std::string const& GetInstallPath() const;
+  void SetInstallPath(std::string const& name);
 
   /**
    * Set the path where this target (if it has a runtime part) should be
    * installed. This is relative to INSTALL_PREFIX
    */
-  std::string GetRuntimeInstallPath() const
-  {
-    return this->RuntimeInstallPath;
-  }
-  void SetRuntimeInstallPath(const char* name)
-  {
-    this->RuntimeInstallPath = name;
-  }
+  std::string const& GetRuntimeInstallPath() const;
+  void SetRuntimeInstallPath(std::string const& name);
 
   /**
    * Get/Set whether there is an install rule for this target.
    */
-  bool GetHaveInstallRule() const { return this->HaveInstallRule; }
-  void SetHaveInstallRule(bool h) { this->HaveInstallRule = h; }
+  bool GetHaveInstallRule() const;
+  void SetHaveInstallRule(bool hir);
 
   /**
    * Get/Set whether this target was auto-created by a generator.
    */
-  bool GetIsGeneratorProvided() const { return this->IsGeneratorProvided; }
-  void SetIsGeneratorProvided(bool igp) { this->IsGeneratorProvided = igp; }
+  bool GetIsGeneratorProvided() const;
+  void SetIsGeneratorProvided(bool igp);
 
-  /** Add a utility on which this project depends. A utility is an executable
+  /**
+   * Add a utility on which this project depends. A utility is an executable
    * name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE
    * commands. It is not a full path nor does it have an extension.
    */
-  void AddUtility(std::string const& u, cmMakefile* mf = nullptr);
-  ///! Get the utilities used by this target
-  std::set<BT<std::string>> const& GetUtilities() const
-  {
-    return this->Utilities;
-  }
+  void AddUtility(std::string const& name, cmMakefile* mf = nullptr);
+  //! Get the utilities used by this target
+  std::set<BT<std::string>> const& GetUtilities() const;
 
-  ///! Set/Get a property of this target file
+  //! Set/Get a property of this target file
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
-  ///! Might return a nullptr if the property is not set or invalid
+  //! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
-  ///! Always returns a valid pointer
+  //! Always returns a valid pointer
   const char* GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   void CheckProperty(const std::string& prop, cmMakefile* context) const;
   const char* GetComputedProperty(const std::string& prop,
                                   cmMessenger* messenger,
                                   cmListFileBacktrace const& context) const;
+  //! Get all properties
+  cmPropertyMap const& GetProperties() const;
 
-  bool IsImported() const { return this->IsImportedTarget; }
-  bool IsImportedGloballyVisible() const
-  {
-    return this->ImportedGloballyVisible;
-  }
-
-  // Get the properties
-  cmPropertyMap const& GetProperties() const { return this->Properties; }
+  bool IsImported() const;
+  bool IsImportedGloballyVisible() const;
 
   bool GetMappedConfig(std::string const& desired_config, const char** loc,
                        const char** imp, std::string& suffix) const;
 
-  /** Return whether this target is an executable with symbol exports
-      enabled.  */
+  //! Return whether this target is an executable with symbol exports enabled.
   bool IsExecutableWithExports() const;
 
-  /** Return whether this target is a shared library Framework on
-      Apple.  */
+  //! Return whether this target is a shared library Framework on Apple.
   bool IsFrameworkOnApple() const;
 
-  /** Return whether this target is an executable Bundle on Apple.  */
+  //! Return whether this target is an executable Bundle on Apple.
   bool IsAppBundleOnApple() const;
 
-  /** Get a backtrace from the creation of the target.  */
+  //! Get a backtrace from the creation of the target.
   cmListFileBacktrace const& GetBacktrace() const;
 
   void InsertInclude(std::string const& entry, cmListFileBacktrace const& bt,
@@ -252,11 +212,8 @@
   std::string GetDebugGeneratorExpressions(const std::string& value,
                                            cmTargetLinkLibraryType llt) const;
 
-  void AddSystemIncludeDirectories(const std::set<std::string>& incs);
-  std::set<std::string> const& GetSystemIncludeDirectories() const
-  {
-    return this->SystemIncludeDirectories;
-  }
+  void AddSystemIncludeDirectories(std::set<std::string> const& incs);
+  std::set<std::string> const& GetSystemIncludeDirectories() const;
 
   cmStringRange GetIncludeDirectoriesEntries() const;
   cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
@@ -282,63 +239,25 @@
   cmStringRange GetLinkImplementationEntries() const;
   cmBacktraceRange GetLinkImplementationBacktraces() const;
 
+  std::string ImportedGetFullPath(const std::string& config,
+                                  cmStateEnums::ArtifactType artifact) const;
+
   struct StrictTargetComparison
   {
     bool operator()(cmTarget const* t1, cmTarget const* t2) const;
   };
 
-  std::string ImportedGetFullPath(const std::string& config,
-                                  cmStateEnums::ArtifactType artifact) const;
-
 private:
+  // Internal representation details.
+  friend class cmGeneratorTarget;
+
   const char* GetSuffixVariableInternal(
     cmStateEnums::ArtifactType artifact) const;
   const char* GetPrefixVariableInternal(
     cmStateEnums::ArtifactType artifact) const;
 
-  // Use a makefile variable to set a default for the given property.
-  // If the variable is not defined use the given default instead.
-  void SetPropertyDefault(const std::string& property,
-                          const char* default_value);
-
-  bool CheckImportedLibName(std::string const& prop,
-                            std::string const& value) const;
-
 private:
-  bool IsGeneratorProvided;
-  cmPropertyMap Properties;
-  std::set<std::string> SystemIncludeDirectories;
-  std::set<BT<std::string>> Utilities;
-  cmPolicies::PolicyMap PolicyMap;
-  std::string Name;
-  std::string InstallPath;
-  std::string RuntimeInstallPath;
-  std::vector<cmCustomCommand> PreBuildCommands;
-  std::vector<cmCustomCommand> PreLinkCommands;
-  std::vector<cmCustomCommand> PostBuildCommands;
-  std::vector<std::pair<TLLSignature, cmListFileContext>> TLLCommands;
-  LinkLibraryVectorType OriginalLinkLibraries;
-  cmMakefile* Makefile;
-  cmTargetInternalPointer Internal;
-  cmStateEnums::TargetType TargetTypeValue;
-  bool HaveInstallRule;
-  bool DLLPlatform;
-  bool IsAndroid;
-  bool IsImportedTarget;
-  bool ImportedGloballyVisible;
-  bool BuildInterfaceIncludesAppended;
-
-  std::string ProcessSourceItemCMP0049(const std::string& s);
-
-  /** Return whether or not the target has a DLL import library.  */
-  bool HasImportLibrary() const;
-
-  // Internal representation details.
-  friend class cmTargetInternals;
-  friend class cmGeneratorTarget;
-  friend class cmTargetTraceDependencies;
-
-  cmListFileBacktrace Backtrace;
+  std::unique_ptr<cmTargetInternals> impl;
 };
 
 typedef std::unordered_map<std::string, cmTarget> cmTargets;
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
index d2c3496..994fcf7 100644
--- a/Source/cmTargetPropertyComputer.cxx
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -67,6 +67,8 @@
     builtIns.insert("IMPORTED_GLOBAL");
     builtIns.insert("MANUALLY_ADDED_DEPENDENCIES");
     builtIns.insert("NAME");
+    builtIns.insert("PRIVATE_HEADER");
+    builtIns.insert("PUBLIC_HEADER");
     builtIns.insert("TYPE");
   }
 
diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h
index 97e4fba..efbf95f 100644
--- a/Source/cmTargetPropertyComputer.h
+++ b/Source/cmTargetPropertyComputer.h
@@ -81,7 +81,7 @@
                                           context)) {
           return nullptr;
         }
-        const char* configName = prop.c_str() + 9;
+        std::string configName = prop.substr(9);
         return ComputeLocation(tgt, configName);
       }
 
diff --git a/Source/cmTest.h b/Source/cmTest.h
index d4839d1..88dc730 100644
--- a/Source/cmTest.h
+++ b/Source/cmTest.h
@@ -26,14 +26,14 @@
   cmTest(cmMakefile* mf);
   ~cmTest();
 
-  ///! Set the test name
+  //! Set the test name
   void SetName(const std::string& name);
   std::string GetName() const { return this->Name; }
 
   void SetCommand(std::vector<std::string> const& command);
   std::vector<std::string> const& GetCommand() const { return this->Command; }
 
-  ///! Set/Get a property of this source file
+  //! Set/Get a property of this source file
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 5102613..571cd09 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -12,6 +12,7 @@
 #include "cmOutputConverter.h"
 #include "cmProperty.h"
 #include "cmPropertyMap.h"
+#include "cmRange.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTest.h"
@@ -94,10 +95,8 @@
       std::string emulatorExe(emulatorWithArgs[0]);
       cmSystemTools::ConvertToUnixSlashes(emulatorExe);
       os << cmOutputConverter::EscapeForCMake(emulatorExe) << " ";
-      for (std::vector<std::string>::const_iterator ei =
-             emulatorWithArgs.begin() + 1;
-           ei != emulatorWithArgs.end(); ++ei) {
-        os << cmOutputConverter::EscapeForCMake(*ei) << " ";
+      for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
+        os << cmOutputConverter::EscapeForCMake(arg) << " ";
       }
     }
   } else {
@@ -108,11 +107,10 @@
 
   // Generate the command line with full escapes.
   os << cmOutputConverter::EscapeForCMake(exe);
-  for (std::vector<std::string>::const_iterator ci = command.begin() + 1;
-       ci != command.end(); ++ci) {
+  for (std::string const& arg : cmMakeRange(command).advance(1)) {
     os << " "
        << cmOutputConverter::EscapeForCMake(
-            ge.Parse(*ci)->Evaluate(this->LG, config));
+            ge.Parse(arg)->Evaluate(this->LG, config));
   }
 
   // Finish the test command.
@@ -157,12 +155,11 @@
   fout << "add_test(";
   fout << this->Test->GetName() << " \"" << exe << "\"";
 
-  for (std::vector<std::string>::const_iterator argit = command.begin() + 1;
-       argit != command.end(); ++argit) {
+  for (std::string const& arg : cmMakeRange(command).advance(1)) {
     // Just double-quote all arguments so they are re-parsed
     // correctly by the test system.
     fout << " \"";
-    for (char c : *argit) {
+    for (char c : arg) {
       // Escape quotes within arguments.  We should escape
       // backslashes too but we cannot because it makes the result
       // inconsistent with previous behavior of this command.
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index c57aabd..4b0707b 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -8,6 +8,7 @@
 #include "cmDuration.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmRange.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
@@ -172,25 +173,22 @@
     std::vector<std::string> emulatorWithArgs;
     cmSystemTools::ExpandListArgument(emulator, emulatorWithArgs);
     finalCommand +=
-      cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0].c_str());
+      cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0]);
     finalCommand += " ";
-    for (std::vector<std::string>::const_iterator ei =
-           emulatorWithArgs.begin() + 1;
-         ei != emulatorWithArgs.end(); ++ei) {
+    for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
       finalCommand += "\"";
-      finalCommand += *ei;
+      finalCommand += arg;
       finalCommand += "\"";
       finalCommand += " ";
     }
   }
-  finalCommand +=
-    cmSystemTools::ConvertToRunCommandPath(this->OutputFile.c_str());
+  finalCommand += cmSystemTools::ConvertToRunCommandPath(this->OutputFile);
   if (!runArgs.empty()) {
     finalCommand += runArgs;
   }
   bool worked = cmSystemTools::RunSingleCommand(
-    finalCommand.c_str(), out, out, &retVal, nullptr,
-    cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+    finalCommand, out, out, &retVal, nullptr, cmSystemTools::OUTPUT_NONE,
+    cmDuration::zero());
   // set the run var
   char retChar[16];
   const char* retStr;
diff --git a/Source/cmUseMangledMesaCommand.cxx b/Source/cmUseMangledMesaCommand.cxx
index 9648b21..88e415a 100644
--- a/Source/cmUseMangledMesaCommand.cxx
+++ b/Source/cmUseMangledMesaCommand.cxx
@@ -19,7 +19,7 @@
     this->SetError("called with incorrect number of arguments");
     return false;
   }
-  const char* inputDir = args[0].c_str();
+  const std::string& inputDir = args[0];
   std::string glh = inputDir;
   glh += "/";
   glh += "gl.h";
@@ -34,7 +34,7 @@
   std::vector<std::string> files;
   cmSystemTools::Glob(inputDir, "\\.h$", files);
   if (files.empty()) {
-    cmSystemTools::Error("Could not open Mesa Directory ", inputDir);
+    cmSystemTools::Error("Could not open Mesa Directory " + inputDir);
     return false;
   }
   cmSystemTools::MakeDirectory(destDir);
@@ -60,8 +60,8 @@
   tempOutputFile += ".tmp";
   cmsys::ofstream fout(tempOutputFile.c_str());
   if (!fout) {
-    cmSystemTools::Error("Could not open file for write in copy operation: ",
-                         tempOutputFile.c_str(), outdir);
+    cmSystemTools::Error("Could not open file for write in copy operation: " +
+                         tempOutputFile + outdir);
     cmSystemTools::ReportLastSystemError("");
     return;
   }
@@ -78,7 +78,7 @@
   cmsys::RegularExpression includeLine(
     "^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
   // regular expression for gl/ or GL/ in a file (match(1) of above)
-  cmsys::RegularExpression glDirLine("(gl|GL)(/|\\\\)([^<\"]+)");
+  cmsys::RegularExpression glDirLine(R"((gl|GL)(/|\\)([^<"]+))");
   // regular expression for gl GL or xmesa in a file (match(1) of above)
   cmsys::RegularExpression glLine("(gl|GL|xmesa)");
   while (cmSystemTools::GetLineFromStream(fin, inLine)) {
diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx
index 231bca4..b59a587 100644
--- a/Source/cmUtilitySourceCommand.cxx
+++ b/Source/cmUtilitySourceCommand.cxx
@@ -79,7 +79,7 @@
   }
 
   // The source exists.
-  std::string cmakeCFGout =
+  const std::string& cmakeCFGout =
     this->Makefile->GetRequiredDefinition("CMAKE_CFG_INTDIR");
   std::string utilityDirectory = this->Makefile->GetCurrentBinaryDirectory();
   std::string exePath;
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
index 201e1cc..51ecbd1 100644
--- a/Source/cmUuid.cxx
+++ b/Source/cmUuid.cxx
@@ -4,16 +4,10 @@
 
 #include "cmCryptoHash.h"
 
+#include <array>
 #include <string.h>
 
-cmUuid::cmUuid()
-{
-  Groups.push_back(4);
-  Groups.push_back(2);
-  Groups.push_back(2);
-  Groups.push_back(2);
-  Groups.push_back(6);
-}
+static const std::array<int, 5> kUuidGroups = { { 4, 2, 2, 2, 6 } };
 
 std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
                             std::string const& name) const
@@ -83,11 +77,11 @@
     return false;
   }
   size_t index = 0;
-  for (size_t i = 0; i < this->Groups.size(); ++i) {
+  for (size_t i = 0; i < kUuidGroups.size(); ++i) {
     if (i != 0 && input[index++] != '-') {
       return false;
     }
-    size_t digits = this->Groups[i] * 2;
+    size_t digits = kUuidGroups[i] * 2;
     if (!StringToBinaryImpl(input.substr(index, digits), output)) {
       return false;
     }
@@ -103,12 +97,12 @@
   std::string output;
 
   size_t inputIndex = 0;
-  for (size_t i = 0; i < this->Groups.size(); ++i) {
+  for (size_t i = 0; i < kUuidGroups.size(); ++i) {
     if (i != 0) {
       output += '-';
     }
 
-    size_t bytes = this->Groups[i];
+    size_t bytes = kUuidGroups[i];
     for (size_t j = 0; j < bytes; ++j) {
       unsigned char byte = input[inputIndex++];
       output += this->ByteToHex(byte);
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
index 158ce6e..7de20dd 100644
--- a/Source/cmUuid.h
+++ b/Source/cmUuid.h
@@ -15,8 +15,6 @@
 class cmUuid
 {
 public:
-  cmUuid();
-
   std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
                       std::string const& name) const;
 
@@ -42,8 +40,6 @@
   std::string BinaryToString(const unsigned char* input) const;
 
   bool IntFromHexDigit(char input, char& output) const;
-
-  std::vector<int> Groups;
 };
 
 #endif
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
index 5855fed..1230101 100644
--- a/Source/cmVariableWatch.h
+++ b/Source/cmVariableWatch.h
@@ -72,6 +72,9 @@
         this->DeleteDataCall(this->ClientData);
       }
     }
+    Pair() = default;
+    Pair(const Pair&) = delete;
+    Pair& operator=(const Pair&) = delete;
   };
 
   typedef std::vector<std::shared_ptr<Pair>> VectorOfPairs;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 7736e59..0cec2fb 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -4,6 +4,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
@@ -623,8 +624,8 @@
         propsLocal += this->DefaultArtifactDir;
         propsLocal += "\\nasm.props";
         ConvertToWindowsSlash(propsLocal);
-        this->Makefile->ConfigureFile(propsTemplate.c_str(),
-                                      propsLocal.c_str(), false, true, true);
+        this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
+                                      true);
         Elem(e1, "Import").Attribute("Project", propsLocal);
       }
     }
@@ -1322,8 +1323,7 @@
         std::string error = "Could not create file: [";
         error += sourcePath;
         error += "]  ";
-        cmSystemTools::Error(error.c_str(),
-                             cmSystemTools::GetLastSystemError().c_str());
+        cmSystemTools::Error(error + cmSystemTools::GetLastSystemError());
       }
     }
   }
@@ -1430,10 +1430,10 @@
 static void ConvertToWindowsSlash(std::string& s)
 {
   // first convert all of the slashes
-  std::string::size_type pos = 0;
-  while ((pos = s.find('/', pos)) != std::string::npos) {
-    s[pos] = '\\';
-    pos++;
+  for (auto& ch : s) {
+    if (ch == '/') {
+      ch = '\\';
+    }
   }
 }
 
@@ -1449,7 +1449,7 @@
   std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
     this->GeneratorTarget->GetAllConfigSources();
 
-  std::set<cmSourceGroup*> groupsUsed;
+  std::set<cmSourceGroup const*> groupsUsed;
   for (cmGeneratorTarget::AllConfigSource const& si : sources) {
     std::string const& source = si.Source->GetFullPath();
     cmSourceGroup* sourceGroup =
@@ -1534,13 +1534,13 @@
     {
       Elem e1(e0, "ItemGroup");
       e1.SetHasElements();
-      std::vector<cmSourceGroup*> groupsVec(groupsUsed.begin(),
-                                            groupsUsed.end());
+      std::vector<cmSourceGroup const*> groupsVec(groupsUsed.begin(),
+                                                  groupsUsed.end());
       std::sort(groupsVec.begin(), groupsVec.end(),
-                [](cmSourceGroup* l, cmSourceGroup* r) {
+                [](cmSourceGroup const* l, cmSourceGroup const* r) {
                   return l->GetFullName() < r->GetFullName();
                 });
-      for (cmSourceGroup* sg : groupsVec) {
+      for (cmSourceGroup const* sg : groupsVec) {
         std::string const& name = sg->GetFullName();
         if (!name.empty()) {
           std::string guidName = "SG_Filter_" + name;
@@ -1572,7 +1572,7 @@
 
 // Add to groupsUsed empty source groups that have non-empty children.
 void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
-  std::set<cmSourceGroup*>& groupsUsed,
+  std::set<cmSourceGroup const*>& groupsUsed,
   const std::vector<cmSourceGroup>& allGroups)
 {
   for (cmSourceGroup const& current : allGroups) {
@@ -1583,17 +1583,15 @@
 
     this->AddMissingSourceGroups(groupsUsed, children);
 
-    cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(&current);
-    if (groupsUsed.find(current_ptr) != groupsUsed.end()) {
+    if (groupsUsed.count(&current) > 0) {
       continue; // group has already been added to set
     }
 
     // check if it least one of the group's descendants is not empty
     // (at least one child must already have been added)
-    std::vector<cmSourceGroup>::const_iterator child_it = children.begin();
+    auto child_it = children.begin();
     while (child_it != children.end()) {
-      cmSourceGroup* child_ptr = const_cast<cmSourceGroup*>(&(*child_it));
-      if (groupsUsed.find(child_ptr) != groupsUsed.end()) {
+      if (groupsUsed.count(&(*child_it)) > 0) {
         break; // found a child that was already added => add current group too
       }
       child_it++;
@@ -1603,7 +1601,7 @@
       continue; // no descendants have source files => ignore this group
     }
 
-    groupsUsed.insert(current_ptr);
+    groupsUsed.insert(&current);
   }
 }
 
@@ -2515,8 +2513,7 @@
     this->GeneratorTarget->GetLinkerLanguage(configName);
   if (linkLanguage.empty()) {
     cmSystemTools::Error(
-      "CMake can not determine linker language for target: ",
-      this->Name.c_str());
+      "CMake can not determine linker language for target: " + this->Name);
     return false;
   }
 
@@ -2531,24 +2528,17 @@
   } else {
     std::set<std::string> languages;
     this->GeneratorTarget->GetLanguages(languages, configName);
-    for (const char* const* l = cm::cbegin(clLangs); l != cm::cend(clLangs);
-         ++l) {
-      if (languages.find(*l) != languages.end()) {
-        langForClCompile = *l;
+    for (const char* l : clLangs) {
+      if (languages.count(l)) {
+        langForClCompile = l;
         break;
       }
     }
   }
   this->LangForClCompile = langForClCompile;
   if (!langForClCompile.empty()) {
-    std::string baseFlagVar = "CMAKE_";
-    baseFlagVar += langForClCompile;
-    baseFlagVar += "_FLAGS";
-    flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
-    std::string flagVar =
-      baseFlagVar + "_" + cmSystemTools::UpperCase(configName);
-    flags += " ";
-    flags += this->Makefile->GetRequiredDefinition(flagVar);
+    this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+                                           langForClCompile, configName);
     this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
                                             langForClCompile, configName);
   }
@@ -3346,8 +3336,7 @@
   const std::string& linkLanguage = linkClosure->LinkerLanguage;
   if (linkLanguage.empty()) {
     cmSystemTools::Error(
-      "CMake can not determine linker language for target: ",
-      this->Name.c_str());
+      "CMake can not determine linker language for target: " + this->Name);
     return false;
   }
 
@@ -3392,8 +3381,8 @@
     this->GeneratorTarget->GetLinkInformation(config);
   if (!pcli) {
     cmSystemTools::Error(
-      "CMake can not compute cmComputeLinkInformation for target: ",
-      this->Name.c_str());
+      "CMake can not compute cmComputeLinkInformation for target: " +
+      this->Name);
     return false;
   }
   cmComputeLinkInformation& cli = *pcli;
@@ -3440,18 +3429,11 @@
   linkDirs.push_back("%(AdditionalLibraryDirectories)");
   linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs);
 
-  std::string targetName;
-  std::string targetNameSO;
-  std::string targetNameFull;
-  std::string targetNameImport;
-  std::string targetNamePDB;
+  cmGeneratorTarget::Names targetNames;
   if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
-    this->GeneratorTarget->GetExecutableNames(
-      targetName, targetNameFull, targetNameImport, targetNamePDB, config);
+    targetNames = this->GeneratorTarget->GetExecutableNames(config);
   } else {
-    this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
-                                           targetNameFull, targetNameImport,
-                                           targetNamePDB, config);
+    targetNames = this->GeneratorTarget->GetLibraryNames(config);
   }
 
   if (this->MSTools) {
@@ -3492,11 +3474,11 @@
 
     std::string pdb = this->GeneratorTarget->GetPDBDirectory(config);
     pdb += "/";
-    pdb += targetNamePDB;
+    pdb += targetNames.PDB;
     std::string imLib = this->GeneratorTarget->GetDirectory(
       config, cmStateEnums::ImportLibraryArtifact);
     imLib += "/";
-    imLib += targetNameImport;
+    imLib += targetNames.ImportLibrary;
 
     linkOptions.AddFlag("ImportLibrary", imLib);
     linkOptions.AddFlag("ProgramDataBaseFile", pdb);
@@ -3520,7 +3502,7 @@
       linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib");
     }
   } else if (this->NsightTegra) {
-    linkOptions.AddFlag("SoName", targetNameSO);
+    linkOptions.AddFlag("SoName", targetNames.SharedObject);
   }
 
   linkOptions.Parse(flags);
@@ -3580,8 +3562,8 @@
     this->GeneratorTarget->GetLinkInformation(config);
   if (!pcli) {
     cmSystemTools::Error(
-      "CMake can not compute cmComputeLinkInformation for target: ",
-      this->Name.c_str());
+      "CMake can not compute cmComputeLinkInformation for target: " +
+      this->Name);
     return false;
   }
 
@@ -4073,10 +4055,7 @@
 {
   std::set<std::string> expectedResxHeaders;
   this->GeneratorTarget->GetExpectedResxHeaders(expectedResxHeaders, "");
-
-  std::set<std::string>::const_iterator it =
-    expectedResxHeaders.find(headerFile);
-  return it != expectedResxHeaders.end();
+  return expectedResxHeaders.count(headerFile) > 0;
 }
 
 bool cmVisualStudio10TargetGenerator::IsXamlHeader(
@@ -4084,10 +4063,7 @@
 {
   std::set<std::string> expectedXamlHeaders;
   this->GeneratorTarget->GetExpectedXamlHeaders(expectedXamlHeaders, "");
-
-  std::set<std::string>::const_iterator it =
-    expectedXamlHeaders.find(headerFile);
-  return it != expectedXamlHeaders.end();
+  return expectedXamlHeaders.count(headerFile) > 0;
 }
 
 bool cmVisualStudio10TargetGenerator::IsXamlSource(
@@ -4095,10 +4071,7 @@
 {
   std::set<std::string> expectedXamlSources;
   this->GeneratorTarget->GetExpectedXamlSources(expectedXamlSources, "");
-
-  std::set<std::string>::const_iterator it =
-    expectedXamlSources.find(sourceFile);
-  return it != expectedXamlSources.end();
+  return expectedXamlSources.count(sourceFile) > 0;
 }
 
 void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
@@ -4669,10 +4642,8 @@
 void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties(
   Elem& e2, const std::map<std::string, std::string>& tags)
 {
-  if (!tags.empty()) {
-    for (const auto& i : tags) {
-      e2.Element(i.first.c_str(), i.second);
-    }
+  for (const auto& i : tags) {
+    e2.Element(i.first.c_str(), i.second);
   }
 }
 
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 5901004..6a1ee1d 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -165,7 +165,7 @@
   void WriteGroupSources(Elem& e0, std::string const& name,
                          ToolSources const& sources,
                          std::vector<cmSourceGroup>&);
-  void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed,
+  void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed,
                               const std::vector<cmSourceGroup>& allGroups);
   bool IsResxHeader(const std::string& headerFile);
   bool IsXamlHeader(const std::string& headerFile);
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 5c3e533..e8b2668 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -438,14 +438,13 @@
   const char* sep = "";
   std::vector<std::string>::const_iterator de =
     cmRemoveDuplicates(this->Defines);
-  for (std::vector<std::string>::const_iterator di = this->Defines.begin();
-       di != de; ++di) {
+  for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
     // Escape the definition for the compiler.
     std::string define;
     if (this->Version < cmGlobalVisualStudioGenerator::VS10) {
-      define = this->LocalGenerator->EscapeForShell(*di, true);
+      define = this->LocalGenerator->EscapeForShell(di, true);
     } else {
-      define = *di;
+      define = di;
     }
     // Escape this flag for the MSBuild.
     if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h
index 1f18ce7..d4a164d 100644
--- a/Source/cmWorkingDirectory.h
+++ b/Source/cmWorkingDirectory.h
@@ -22,6 +22,9 @@
   cmWorkingDirectory(std::string const& newdir);
   ~cmWorkingDirectory();
 
+  cmWorkingDirectory(const cmWorkingDirectory&) = delete;
+  cmWorkingDirectory& operator=(const cmWorkingDirectory&) = delete;
+
   bool SetDirectory(std::string const& newdir);
   void Pop();
   bool Failed() const { return ResultCode != 0; }
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index 1b16198..c33bb7e 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -177,6 +177,11 @@
   WriteLaunchActionAttribute(xout, "stopOnEveryMainThreadCheckerIssue",
                              "XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
 
+  if (this->Target->GetTarget()->GetPropertyAsBool(
+        "XCODE_SCHEME_DEBUG_AS_ROOT")) {
+    xout.Attribute("debugAsWhichUser", "root");
+  }
+
   // Diagnostics tab end
 
   if (IsExecutable(this->Target)) {
diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx
index 9d2a3c4..f1ce608 100644
--- a/Source/cmXMLWriter.cxx
+++ b/Source/cmXMLWriter.cxx
@@ -23,7 +23,7 @@
 
 void cmXMLWriter::StartDocument(const char* encoding)
 {
-  this->Output << "<?xml version=\"1.0\" encoding=\"" << encoding << "\"?>";
+  this->Output << R"(<?xml version="1.0" encoding=")" << encoding << "\"?>";
 }
 
 void cmXMLWriter::EndDocument()
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
index 1df8a09..512e103 100644
--- a/Source/cmXMLWriter.h
+++ b/Source/cmXMLWriter.h
@@ -146,6 +146,8 @@
     xmlwr.StartDocument();
   }
   ~cmXMLDocument() { xmlwr.EndDocument(); }
+  cmXMLDocument(const cmXMLDocument&) = delete;
+  cmXMLDocument& operator=(const cmXMLDocument&) = delete;
 
 private:
   friend class cmXMLElement;
@@ -172,6 +174,9 @@
   }
   ~cmXMLElement() { xmlwr.EndElement(); }
 
+  cmXMLElement(const cmXMLElement&) = delete;
+  cmXMLElement& operator=(const cmXMLElement&) = delete;
+
   template <typename T>
   cmXMLElement& Attribute(const char* name, T const& value)
   {
diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c
index 52af4a6..62e7e8c 100644
--- a/Source/cm_utf8.c
+++ b/Source/cm_utf8.c
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cm_utf8.h"
 
+#include <string.h>
+
 /*
   RFC 3629
   07-bit: 0xxxxxxx
@@ -71,7 +73,34 @@
       return 0;
     }
 
+    /* UTF-16 surrogate halves. */
+    if (0xD800 <= uc && uc <= 0xDFFF) {
+      return 0;
+    }
+
+    /* Invalid codepoints. */
+    if (0x10FFFF < uc) {
+      return 0;
+    }
+
     *pc = uc;
     return first;
   }
 }
+
+int cm_utf8_is_valid(const char* s)
+{
+  if (!s) {
+    return 0;
+  }
+
+  const char* last = s + strlen(s);
+  const char* pos = s;
+  unsigned int pc;
+
+  while (pos != last && (pos = cm_utf8_decode_character(pos, last, &pc))) {
+    /* Nothing to do. */
+  }
+
+  return pos == last;
+}
diff --git a/Source/cm_utf8.h b/Source/cm_utf8.h
index fcb43e0..27dc559 100644
--- a/Source/cm_utf8.h
+++ b/Source/cm_utf8.h
@@ -13,6 +13,10 @@
 const char* cm_utf8_decode_character(const char* first, const char* last,
                                      unsigned int* pc);
 
+/** Returns whether a C string is a sequence of valid UTF-8 encoded Unicode
+    codepoints.  Returns non-zero on success. */
+int cm_utf8_is_valid(const char* s);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 8023298..fc24ac0 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -9,7 +9,7 @@
 #include "cmDocumentationFormatter.h"
 #include "cmDuration.h"
 #include "cmExternalMakefileProjectGenerator.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
@@ -48,7 +48,6 @@
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #  if !defined(CMAKE_BOOT_MINGW)
 #    include "cmGlobalBorlandMakefileGenerator.h"
-#    include "cmGlobalGhsMultiGenerator.h"
 #    include "cmGlobalJOMMakefileGenerator.h"
 #    include "cmGlobalNMakeMakefileGenerator.h"
 #    include "cmGlobalVisualStudio10Generator.h"
@@ -84,6 +83,10 @@
 #  include "cmExtraEclipseCDT4Generator.h"
 #endif
 
+#if defined(__linux__) || defined(_WIN32)
+#  include "cmGlobalGhsMultiGenerator.h"
+#endif
+
 #if defined(__APPLE__)
 #  if defined(CMAKE_BUILD_WITH_CMAKE)
 #    include "cmGlobalXCodeGenerator.h"
@@ -99,6 +102,7 @@
 #include "cmsys/RegularExpression.hxx"
 #include <algorithm>
 #include <cstring>
+#include <initializer_list>
 #include <iostream>
 #include <iterator>
 #include <memory> // IWYU pragma: keep
@@ -115,10 +119,8 @@
 
 } // namespace
 
-static bool cmakeCheckStampFile(const std::string& stampName,
-                                bool verbose = true);
-static bool cmakeCheckStampList(const std::string& stampList,
-                                bool verbose = true);
+static bool cmakeCheckStampFile(const std::string& stampName);
+static bool cmakeCheckStampList(const std::string& stampList);
 
 void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
                             void* ctx, const char* /*unused*/,
@@ -139,7 +141,7 @@
   this->DebugOutput = false;
   this->DebugTryCompile = false;
   this->ClearBuildSystem = false;
-  this->FileComparison = new cmFileTimeComparison;
+  this->FileTimeCache = new cmFileTimeCache;
 
   this->State = new cmState;
   this->State->SetMode(mode);
@@ -223,7 +225,7 @@
 #ifdef CMAKE_BUILD_WITH_CMAKE
   delete this->VariableWatch;
 #endif
-  delete this->FileComparison;
+  delete this->FileTimeCache;
 }
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -708,6 +710,7 @@
       this->GraphVizFile = path;
       if (this->GraphVizFile.empty()) {
         cmSystemTools::Error("No file specified for --graphviz");
+        return;
       }
     } else if (arg.find("--debug-trycompile", 0) == 0) {
       std::cout << "debug trycompile on\n";
@@ -787,17 +790,17 @@
       }
       cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
       if (!gen) {
-        const char* kdevError = nullptr;
+        std::string kdevError;
         if (value.find("KDevelop3", 0) != std::string::npos) {
           kdevError = "\nThe KDevelop3 generator is not supported anymore.";
         }
 
-        cmSystemTools::Error("Could not create named generator ",
-                             value.c_str(), kdevError);
+        cmSystemTools::Error("Could not create named generator " + value +
+                             kdevError);
         this->PrintGeneratorList();
-      } else {
-        this->SetGlobalGenerator(gen);
+        return;
       }
+      this->SetGlobalGenerator(gen);
     }
     // no option assume it is the path to the source or an existing build
     else {
@@ -937,8 +940,8 @@
     cmSystemTools::Error(
       "Could not find CMAKE_ROOT !!!\n"
       "CMake has most likely not been installed correctly.\n"
-      "Modules directory not found in\n",
-      cmSystemTools::GetCMakeRoot().c_str());
+      "Modules directory not found in\n" +
+      cmSystemTools::GetCMakeRoot());
     return 0;
   }
   this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(),
@@ -1105,7 +1108,7 @@
     if (cmSystemTools::FileExists(cmakeFiles)) {
       std::string cachePathFound =
         cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt",
-                                                     cachePath.c_str(), "/");
+                                                     cachePath, "/");
       if (!cachePathFound.empty()) {
         cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
       }
@@ -1705,7 +1708,7 @@
   ret = this->Generate();
   std::string message = "Build files have been written to: ";
   message += this->GetHomeOutputDirectory();
-  this->UpdateProgress(message.c_str(), -1);
+  this->UpdateProgress(message, -1);
   return ret;
 }
 
@@ -1834,13 +1837,15 @@
   this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory());
   this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory());
   this->Generators.push_back(cmGlobalJOMMakefileGenerator::NewFactory());
-  this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
 #  endif
   this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory());
   this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
 #endif
   this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
 #if defined(CMAKE_BUILD_WITH_CMAKE)
+#  if defined(__linux__) || defined(_WIN32)
+  this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
+#  endif
   this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
 #endif
 #if defined(CMAKE_USE_WMAKE)
@@ -1892,11 +1897,10 @@
                       std::set<std::string>& includes)
 {
   bool result = this->State->LoadCache(path, internal, excludes, includes);
-  static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
-                                   "CMAKE_CACHE_MINOR_VERSION" };
-  for (const char* const* nameIt = cm::cbegin(entries);
-       nameIt != cm::cend(entries); ++nameIt) {
-    this->UnwatchUnusedCli(*nameIt);
+  static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+                                "CMAKE_CACHE_MINOR_VERSION" };
+  for (auto const& entry : entries) {
+    this->UnwatchUnusedCli(entry);
   }
   return result;
 }
@@ -1904,13 +1908,12 @@
 bool cmake::SaveCache(const std::string& path)
 {
   bool result = this->State->SaveCache(path, this->GetMessenger());
-  static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
-                                   "CMAKE_CACHE_MINOR_VERSION",
-                                   "CMAKE_CACHE_PATCH_VERSION",
-                                   "CMAKE_CACHEFILE_DIR" };
-  for (const char* const* nameIt = cm::cbegin(entries);
-       nameIt != cm::cend(entries); ++nameIt) {
-    this->UnwatchUnusedCli(*nameIt);
+  static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+                                "CMAKE_CACHE_MINOR_VERSION",
+                                "CMAKE_CACHE_PATCH_VERSION",
+                                "CMAKE_CACHEFILE_DIR" };
+  for (auto const& entry : entries) {
+    this->UnwatchUnusedCli(entry);
   }
   return result;
 }
@@ -1925,7 +1928,7 @@
   this->ProgressCallback = std::move(f);
 }
 
-void cmake::UpdateProgress(const char* msg, float prog)
+void cmake::UpdateProgress(const std::string& msg, float prog)
 {
   if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
     this->ProgressCallback(msg, prog);
@@ -2017,8 +2020,8 @@
   if (tablepath) {
     cmsys::ifstream table(tablepath->c_str());
     if (!table) {
-      cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to ",
-                           tablepath->c_str(), ". CMake can not open file.");
+      cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to " + *tablepath +
+                           ". CMake can not open file.");
       cmSystemTools::ReportLastSystemError("CMake can not open file.");
     } else {
       std::string a, b;
@@ -2142,7 +2145,7 @@
   std::string dep_newest = *dep++;
   for (; dep != depends.end(); ++dep) {
     int result = 0;
-    if (this->FileComparison->FileTimeCompare(dep_newest, *dep, &result)) {
+    if (this->FileTimeCache->Compare(dep_newest, *dep, &result)) {
       if (result < 0) {
         dep_newest = *dep;
       }
@@ -2161,7 +2164,7 @@
   std::string out_oldest = *out++;
   for (; out != outputs.end(); ++out) {
     int result = 0;
-    if (this->FileComparison->FileTimeCompare(out_oldest, *out, &result)) {
+    if (this->FileTimeCache->Compare(out_oldest, *out, &result)) {
       if (result > 0) {
         out_oldest = *out;
       }
@@ -2178,8 +2181,7 @@
   // If any output is older than any dependency then rerun.
   {
     int result = 0;
-    if (!this->FileComparison->FileTimeCompare(out_oldest, dep_newest,
-                                               &result) ||
+    if (!this->FileTimeCache->Compare(out_oldest, dep_newest, &result) ||
         result < 0) {
       if (verbose) {
         std::ostringstream msg;
@@ -2326,8 +2328,7 @@
       }
       cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
       if (!gen) {
-        cmSystemTools::Error("Could not create named generator ",
-                             value.c_str());
+        cmSystemTools::Error("Could not create named generator " + value);
         this->PrintGeneratorList();
       } else {
         this->SetGlobalGenerator(gen);
@@ -2354,7 +2355,7 @@
   outFile += "/CMakeLists.txt";
 
   // Copy file
-  if (!cmSystemTools::cmCopyFile(inFile, outFile)) {
+  if (!cmsys::SystemTools::CopyFileAlways(inFile, outFile)) {
     std::cerr << "Error copying file \"" << inFile << "\" to \"" << outFile
               << "\".\n";
     return 1;
@@ -2412,7 +2413,7 @@
   return 0;
 }
 
-static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
+static bool cmakeCheckStampFile(const std::string& stampName)
 {
   // The stamp file does not exist.  Use the stamp dependencies to
   // determine whether it is really out of date.  This works in
@@ -2435,20 +2436,22 @@
   }
 
   // Compare the stamp dependencies against the dependency file itself.
-  cmFileTimeComparison ftc;
-  std::string dep;
-  while (cmSystemTools::GetLineFromStream(fin, dep)) {
-    int result;
-    if (!dep.empty() && dep[0] != '#' &&
-        (!ftc.FileTimeCompare(stampDepends, dep, &result) || result < 0)) {
-      // The stamp depends file is older than this dependency.  The
-      // build system is really out of date.
-      std::cout << "CMake is re-running because " << stampName
-                << " is out-of-date.\n";
-      std::cout << "  the file '" << dep << "'\n";
-      std::cout << "  is newer than '" << stampDepends << "'\n";
-      std::cout << "  result='" << result << "'\n";
-      return false;
+  {
+    cmFileTimeCache ftc;
+    std::string dep;
+    while (cmSystemTools::GetLineFromStream(fin, dep)) {
+      int result;
+      if (!dep.empty() && dep[0] != '#' &&
+          (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
+        // The stamp depends file is older than this dependency.  The
+        // build system is really out of date.
+        std::cout << "CMake is re-running because " << stampName
+                  << " is out-of-date.\n";
+        std::cout << "  the file '" << dep << "'\n";
+        std::cout << "  is newer than '" << stampDepends << "'\n";
+        std::cout << "  result='" << result << "'\n";
+        return false;
+      }
     }
   }
 
@@ -2464,21 +2467,15 @@
     stamp << "# CMake generation timestamp file for this directory.\n";
   }
   if (cmSystemTools::RenameFile(stampTemp, stampName)) {
-    if (verbose) {
-      // Notify the user why CMake is not re-running.  It is safe to
-      // just print to stdout here because this code is only reachable
-      // through an undocumented flag used by the VS generator.
-      std::cout << "CMake does not need to re-run because " << stampName
-                << " is up-to-date.\n";
-    }
+    // CMake does not need to re-run because the stamp file is up-to-date.
     return true;
   }
   cmSystemTools::RemoveFile(stampTemp);
-  cmSystemTools::Error("Cannot restore timestamp ", stampName.c_str());
+  cmSystemTools::Error("Cannot restore timestamp " + stampName);
   return false;
 }
 
-static bool cmakeCheckStampList(const std::string& stampList, bool verbose)
+static bool cmakeCheckStampList(const std::string& stampList)
 {
   // If the stamp list does not exist CMake must rerun to generate it.
   if (!cmSystemTools::FileExists(stampList)) {
@@ -2496,7 +2493,7 @@
   // Check each stamp.
   std::string stampName;
   while (cmSystemTools::GetLineFromStream(fin, stampName)) {
-    if (!cmakeCheckStampFile(stampName, verbose)) {
+    if (!cmakeCheckStampFile(stampName)) {
       return false;
     }
   }
@@ -2531,7 +2528,8 @@
   return this->Messenger;
 }
 
-int cmake::Build(int jobs, const std::string& dir, const std::string& target,
+int cmake::Build(int jobs, const std::string& dir,
+                 const std::vector<std::string>& targets,
                  const std::string& config,
                  const std::vector<std::string>& nativeOptions, bool clean,
                  bool verbose)
@@ -2617,7 +2615,7 @@
       }
     }
 
-    if (!cmakeCheckStampList(stampList, false)) {
+    if (!cmakeCheckStampList(stampList)) {
       // Correctly initialize the home (=source) and home output (=binary)
       // directories, which is required for running the generation step.
       std::string homeOrig = this->GetHomeDirectory();
@@ -2640,7 +2638,7 @@
       }
       std::string message = "Build files have been written to: ";
       message += this->GetHomeOutputDirectory();
-      this->UpdateProgress(message.c_str(), -1);
+      this->UpdateProgress(message, -1);
 
       // Restore the previously set directories to their original value.
       this->SetHomeDirectory(homeOrig);
@@ -2650,9 +2648,8 @@
 #endif
 
   gen->PrintBuildCommandAdvice(std::cerr, jobs);
-
-  return gen->Build(jobs, "", dir, projName, target, output, "", config, clean,
-                    false, verbose, cmDuration::zero(),
+  return gen->Build(jobs, "", dir, projName, targets, output, "", config,
+                    clean, false, verbose, cmDuration::zero(),
                     cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
 }
 
diff --git a/Source/cmake.h b/Source/cmake.h
index 53d44f1..8b4b396 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -26,7 +26,7 @@
 
 class cmExternalMakefileProjectGeneratorFactory;
 class cmFileAPI;
-class cmFileTimeComparison;
+class cmFileTimeCache;
 class cmGlobalGenerator;
 class cmGlobalGeneratorFactory;
 class cmMakefile;
@@ -162,7 +162,7 @@
   int Configure();
   int ActualConfigure();
 
-  ///! Break up a line like VAR:type="value" into var, type and value
+  //! Break up a line like VAR:type="value" into var, type and value
   static bool ParseCacheEntry(const std::string& entry, std::string& var,
                               std::string& value,
                               cmStateEnums::CacheEntryType& type);
@@ -176,40 +176,40 @@
   bool DeleteCache(const std::string& path);
   void PreLoadCMakeFiles();
 
-  ///! Create a GlobalGenerator
+  //! Create a GlobalGenerator
   cmGlobalGenerator* CreateGlobalGenerator(const std::string& name);
 
-  ///! Return the global generator assigned to this instance of cmake
+  //! Return the global generator assigned to this instance of cmake
   cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
-  ///! Return the global generator assigned to this instance of cmake, const
+  //! Return the global generator assigned to this instance of cmake, const
   const cmGlobalGenerator* GetGlobalGenerator() const
   {
     return this->GlobalGenerator;
   }
 
-  ///! Return the full path to where the CMakeCache.txt file should be.
+  //! Return the full path to where the CMakeCache.txt file should be.
   static std::string FindCacheFile(const std::string& binaryDir);
 
-  ///! Return the global generator assigned to this instance of cmake
+  //! Return the global generator assigned to this instance of cmake
   void SetGlobalGenerator(cmGlobalGenerator*);
 
-  ///! Get the names of the current registered generators
+  //! Get the names of the current registered generators
   void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
                                bool includeNamesWithPlatform = true) const;
 
-  ///! Set the name of the selected generator-specific instance.
+  //! Set the name of the selected generator-specific instance.
   void SetGeneratorInstance(std::string const& instance)
   {
     this->GeneratorInstance = instance;
   }
 
-  ///! Set the name of the selected generator-specific platform.
+  //! Set the name of the selected generator-specific platform.
   void SetGeneratorPlatform(std::string const& ts)
   {
     this->GeneratorPlatform = ts;
   }
 
-  ///! Set the name of the selected generator-specific toolset.
+  //! Set the name of the selected generator-specific toolset.
   void SetGeneratorToolset(std::string const& ts)
   {
     this->GeneratorToolset = ts;
@@ -244,7 +244,7 @@
    * Given a variable name, return its value (as a string).
    */
   const char* GetCacheDefinition(const std::string&) const;
-  ///! Add an entry into the cache
+  //! Add an entry into the cache
   void AddCacheEntry(const std::string& key, const char* value,
                      const char* helpString, int type);
 
@@ -263,17 +263,17 @@
    */
   int GetSystemInformation(std::vector<std::string>&);
 
-  ///! Parse command line arguments
+  //! Parse command line arguments
   void SetArgs(const std::vector<std::string>& args);
 
-  ///! Is this cmake running as a result of a TRY_COMPILE command
+  //! Is this cmake running as a result of a TRY_COMPILE command
   bool GetIsInTryCompile() const;
   void SetIsInTryCompile(bool b);
 
-  ///! Parse command line arguments that might set cache values
+  //! Parse command line arguments that might set cache values
   bool SetCacheArgs(const std::vector<std::string>&);
 
-  using ProgressCallbackType = std::function<void(const char*, float)>;
+  using ProgressCallbackType = std::function<void(const std::string&, float)>;
   /**
    *  Set the function used by GUIs to receive progress updates
    *  Function gets passed: message as a const char*, a progress
@@ -283,24 +283,24 @@
    */
   void SetProgressCallback(ProgressCallbackType f);
 
-  ///! this is called by generators to update the progress
-  void UpdateProgress(const char* msg, float prog);
+  //! this is called by generators to update the progress
+  void UpdateProgress(const std::string& msg, float prog);
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
-  ///! Get the variable watch object
+  //! Get the variable watch object
   cmVariableWatch* GetVariableWatch() { return this->VariableWatch; }
 #endif
 
   std::vector<cmDocumentationEntry> GetGeneratorsDocumentation();
 
-  ///! Set/Get a property of this target file
+  //! Set/Get a property of this target file
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
   const char* GetProperty(const std::string& prop);
   bool GetPropertyAsBool(const std::string& prop);
 
-  ///! Get or create an cmInstalledFile instance and return a pointer to it
+  //! Get or create an cmInstalledFile instance and return a pointer to it
   cmInstalledFile* GetOrCreateInstalledFile(cmMakefile* mf,
                                             const std::string& name);
 
@@ -311,13 +311,13 @@
     return this->InstalledFiles;
   }
 
-  ///! Do all the checks before running configure
+  //! Do all the checks before running configure
   int DoPreConfigureChecks();
 
   void SetWorkingMode(WorkingMode mode) { this->CurrentWorkingMode = mode; }
   WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; }
 
-  ///! Debug the try compile stuff by not deleting the files
+  //! Debug the try compile stuff by not deleting the files
   bool GetDebugTryCompile() { return this->DebugTryCompile; }
   void DebugTryCompileOn() { this->DebugTryCompile = true; }
 
@@ -329,7 +329,7 @@
   /**
    * Get the file comparison class
    */
-  cmFileTimeComparison* GetFileComparison() { return this->FileComparison; }
+  cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; }
 
   // Do we want debug output during the cmake run.
   bool GetDebugOutput() { return this->DebugOutput; }
@@ -423,13 +423,13 @@
     MessageType t, std::string const& text,
     cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
 
-  ///! run the --build option
-  int Build(int jobs, const std::string& dir, const std::string& target,
-            const std::string& config,
+  //! run the --build option
+  int Build(int jobs, const std::string& dir,
+            const std::vector<std::string>& targets, const std::string& config,
             const std::vector<std::string>& nativeOptions, bool clean,
             bool verbose);
 
-  ///! run the --open option
+  //! run the --open option
   bool Open(const std::string& dir, bool dryRun);
 
   void UnwatchUnusedCli(const std::string& var);
@@ -462,12 +462,12 @@
   std::string GeneratorPlatform;
   std::string GeneratorToolset;
 
-  ///! read in a cmake list file to initialize the cache
+  //! read in a cmake list file to initialize the cache
   void ReadListFile(const std::vector<std::string>& args,
                     const std::string& path);
   bool FindPackage(const std::vector<std::string>& args);
 
-  ///! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
+  //! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
   ///  If it is set, truncate it to 50kb
   void TruncateOutputLog(const char* fname);
 
@@ -509,7 +509,7 @@
   std::unordered_set<std::string> HeaderFileExtensionsSet;
   bool ClearBuildSystem;
   bool DebugTryCompile;
-  cmFileTimeComparison* FileComparison;
+  cmFileTimeCache* FileTimeCache;
   std::string GraphVizFile;
   InstalledFilesMap InstalledFiles;
 
@@ -562,40 +562,38 @@
       "not errors."                                                           \
   }
 
+#define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes)
+
+#define FOR_EACH_C99_FEATURE(F)                                               \
+  F(c_restrict)                                                               \
+  F(c_variadic_macros)
+
+#define FOR_EACH_C11_FEATURE(F) F(c_static_assert)
+
 #define FOR_EACH_C_FEATURE(F)                                                 \
   F(c_std_90)                                                                 \
   F(c_std_99)                                                                 \
   F(c_std_11)                                                                 \
-  F(c_function_prototypes)                                                    \
-  F(c_restrict)                                                               \
-  F(c_static_assert)                                                          \
-  F(c_variadic_macros)
+  FOR_EACH_C90_FEATURE(F)                                                     \
+  FOR_EACH_C99_FEATURE(F)                                                     \
+  FOR_EACH_C11_FEATURE(F)
 
-#define FOR_EACH_CXX_FEATURE(F)                                               \
-  F(cxx_std_98)                                                               \
-  F(cxx_std_11)                                                               \
-  F(cxx_std_14)                                                               \
-  F(cxx_std_17)                                                               \
-  F(cxx_std_20)                                                               \
-  F(cxx_aggregate_default_initializers)                                       \
+#define FOR_EACH_CXX98_FEATURE(F) F(cxx_template_template_parameters)
+
+#define FOR_EACH_CXX11_FEATURE(F)                                             \
   F(cxx_alias_templates)                                                      \
   F(cxx_alignas)                                                              \
   F(cxx_alignof)                                                              \
   F(cxx_attributes)                                                           \
-  F(cxx_attribute_deprecated)                                                 \
   F(cxx_auto_type)                                                            \
-  F(cxx_binary_literals)                                                      \
   F(cxx_constexpr)                                                            \
-  F(cxx_contextual_conversions)                                               \
   F(cxx_decltype)                                                             \
-  F(cxx_decltype_auto)                                                        \
   F(cxx_decltype_incomplete_return_types)                                     \
   F(cxx_default_function_template_args)                                       \
   F(cxx_defaulted_functions)                                                  \
   F(cxx_defaulted_move_initializers)                                          \
   F(cxx_delegating_constructors)                                              \
   F(cxx_deleted_functions)                                                    \
-  F(cxx_digit_separators)                                                     \
   F(cxx_enum_forward_declarations)                                            \
   F(cxx_explicit_conversions)                                                 \
   F(cxx_extended_friend_declarations)                                         \
@@ -603,11 +601,9 @@
   F(cxx_final)                                                                \
   F(cxx_func_identifier)                                                      \
   F(cxx_generalized_initializers)                                             \
-  F(cxx_generic_lambdas)                                                      \
   F(cxx_inheriting_constructors)                                              \
   F(cxx_inline_namespaces)                                                    \
   F(cxx_lambdas)                                                              \
-  F(cxx_lambda_init_captures)                                                 \
   F(cxx_local_type_template_args)                                             \
   F(cxx_long_long_type)                                                       \
   F(cxx_noexcept)                                                             \
@@ -617,22 +613,41 @@
   F(cxx_range_for)                                                            \
   F(cxx_raw_string_literals)                                                  \
   F(cxx_reference_qualified_functions)                                        \
-  F(cxx_relaxed_constexpr)                                                    \
-  F(cxx_return_type_deduction)                                                \
   F(cxx_right_angle_brackets)                                                 \
   F(cxx_rvalue_references)                                                    \
   F(cxx_sizeof_member)                                                        \
   F(cxx_static_assert)                                                        \
   F(cxx_strong_enums)                                                         \
-  F(cxx_template_template_parameters)                                         \
   F(cxx_thread_local)                                                         \
   F(cxx_trailing_return_types)                                                \
   F(cxx_unicode_literals)                                                     \
   F(cxx_uniform_initialization)                                               \
   F(cxx_unrestricted_unions)                                                  \
   F(cxx_user_literals)                                                        \
-  F(cxx_variable_templates)                                                   \
   F(cxx_variadic_macros)                                                      \
   F(cxx_variadic_templates)
 
+#define FOR_EACH_CXX14_FEATURE(F)                                             \
+  F(cxx_aggregate_default_initializers)                                       \
+  F(cxx_attribute_deprecated)                                                 \
+  F(cxx_binary_literals)                                                      \
+  F(cxx_contextual_conversions)                                               \
+  F(cxx_decltype_auto)                                                        \
+  F(cxx_digit_separators)                                                     \
+  F(cxx_generic_lambdas)                                                      \
+  F(cxx_lambda_init_captures)                                                 \
+  F(cxx_relaxed_constexpr)                                                    \
+  F(cxx_return_type_deduction)                                                \
+  F(cxx_variable_templates)
+
+#define FOR_EACH_CXX_FEATURE(F)                                               \
+  F(cxx_std_98)                                                               \
+  F(cxx_std_11)                                                               \
+  F(cxx_std_14)                                                               \
+  F(cxx_std_17)                                                               \
+  F(cxx_std_20)                                                               \
+  FOR_EACH_CXX98_FEATURE(F)                                                   \
+  FOR_EACH_CXX11_FEATURE(F)                                                   \
+  FOR_EACH_CXX14_FEATURE(F)
+
 #endif
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index a83f7dc..d70c9d9 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -23,6 +23,7 @@
 #  include "cmsys/ConsoleBuf.hxx"
 #endif
 
+#include <cassert>
 #include <ctype.h>
 #include <iostream>
 #include <string.h>
@@ -54,29 +55,38 @@
 
 #  define CMAKE_BUILD_OPTIONS                                                 \
     "  <dir>          = Project binary directory to be built.\n"              \
-    "  -j [<jobs>] --parallel [<jobs>] = Build in parallel using\n"           \
-    "                   the given number of jobs. If <jobs> is omitted\n"     \
-    "                   the native build tool's default number is used.\n"    \
+    "  --parallel [<jobs>], -j [<jobs>]\n"                                    \
+    "                 = Build in parallel using the given number of jobs. \n" \
+    "                   If <jobs> is omitted the native build tool's \n"      \
+    "                   default number is used.\n"                            \
     "                   The CMAKE_BUILD_PARALLEL_LEVEL environment "          \
     "variable\n"                                                              \
     "                   specifies a default parallel level when this "        \
     "option\n"                                                                \
     "                   is not given.\n"                                      \
-    "  --target <tgt> = Build <tgt> instead of default targets.\n"            \
-    "                   May only be specified once.\n"                        \
+    "  --target <tgt>..., -t <tgt>... \n"                                     \
+    "                 = Build <tgt> instead of default targets.\n"            \
     "  --config <cfg> = For multi-configuration tools, choose <cfg>.\n"       \
     "  --clean-first  = Build target 'clean' first, then build.\n"            \
     "                   (To clean only, use --target 'clean'.)\n"             \
-    "  --use-stderr   = Ignored.  Behavior is default in CMake >= 3.0.\n"     \
-    "  -v --verbose   = Enable verbose output - if supported - including\n"   \
+    " --verbose, -v   = Enable verbose output - if supported - including\n"   \
     "                   the build commands to be executed. \n"                \
     "  --             = Pass remaining options to the native tool.\n"
 
+#  define CMAKE_INSTALL_OPTIONS                                               \
+    "  <dir>              = Project binary directory to install.\n"           \
+    "  --config <cfg>     = For multi-configuration tools, choose <cfg>.\n"   \
+    "  --component <comp> = Component-based install. Only install <comp>.\n"  \
+    "  --prefix <prefix>  = The installation prefix CMAKE_INSTALL_PREFIX.\n"  \
+    "  --strip            = Performing install/strip.\n"                      \
+    "  -v --verbose       = Enable verbose output.\n"
+
 static const char* cmDocumentationOptions[][2] = {
   CMAKE_STANDARD_OPTIONS_TABLE,
   { "-E", "CMake command mode." },
   { "-L[A][H]", "List non-advanced cached variables." },
   { "--build <dir>", "Build a CMake-generated project binary tree." },
+  { "--install <dir>", "Install a CMake-generated project binary tree." },
   { "--open <dir>", "Open generated project in the associated application." },
   { "-N", "View mode only." },
   { "-P <file>", "Process script mode." },
@@ -115,6 +125,7 @@
 
 int do_cmake(int ac, char const* const* av);
 static int do_build(int ac, char const* const* av);
+static int do_install(int ac, char const* const* av);
 static int do_open(int ac, char const* const* av);
 
 static cmMakefile* cmakemainGetMakefile(cmake* cm)
@@ -142,20 +153,21 @@
   return msg;
 }
 
-static void cmakemainMessageCallback(const char* m, const char* /*unused*/,
-                                     cmake* cm)
+static void cmakemainMessageCallback(const std::string& m,
+                                     const char* /*unused*/, cmake* cm)
 {
   std::cerr << m << cmakemainGetStack(cm) << std::endl << std::flush;
 }
 
-static void cmakemainProgressCallback(const char* m, float prog, cmake* cm)
+static void cmakemainProgressCallback(const std::string& m, float prog,
+                                      cmake* cm)
 {
   cmMakefile* mf = cmakemainGetMakefile(cm);
   std::string dir;
-  if ((mf) && (strstr(m, "Configuring") == m) && (prog < 0)) {
+  if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
     dir = " ";
     dir += mf->GetCurrentSourceDirectory();
-  } else if ((mf) && (strstr(m, "Generating") == m)) {
+  } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
     dir = " ";
     dir += mf->GetCurrentBinaryDirectory();
   }
@@ -188,6 +200,9 @@
     if (strcmp(av[1], "--build") == 0) {
       return do_build(ac, av);
     }
+    if (strcmp(av[1], "--install") == 0) {
+      return do_install(ac, av);
+    }
     if (strcmp(av[1], "--open") == 0) {
       return do_open(ac, av);
     }
@@ -319,10 +334,11 @@
   cmake cm(role, mode);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
-  cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
-    cmakemainMessageCallback(msg, title, &cm);
-  });
-  cm.SetProgressCallback([&cm](const char* msg, float prog) {
+  cmSystemTools::SetMessageCallback(
+    [&cm](const std::string& msg, const char* title) {
+      cmakemainMessageCallback(msg, title, &cm);
+    });
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
   cm.SetWorkingMode(workingMode);
@@ -393,13 +409,14 @@
   return -1;
 #else
   int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
-  std::string target;
+  std::vector<std::string> targets;
   std::string config = "Debug";
   std::string dir;
   std::vector<std::string> nativeOptions;
-  bool clean = false;
+  bool cleanFirst = false;
+  bool foundClean = false;
+  bool foundNonClean = false;
   bool verbose = cmSystemTools::HasEnv("VERBOSE");
-  bool hasTarget = false;
 
   enum Doing
   {
@@ -419,25 +436,21 @@
       if (jobs < 0) {
         dir.clear();
       }
+      doing = DoingNone;
     } else if (cmHasLiteralPrefix(av[i], "--parallel")) {
       const char* nextArg = ((i + 1 < ac) ? av[i + 1] : nullptr);
       jobs = extract_job_number(i, av[i], nextArg, sizeof("--parallel") - 1);
       if (jobs < 0) {
         dir.clear();
       }
-    } else if (strcmp(av[i], "--target") == 0) {
-      if (!hasTarget) {
-        doing = DoingTarget;
-        hasTarget = true;
-      } else {
-        std::cerr << "'--target' may not be specified more than once.\n\n";
-        dir.clear();
-        break;
-      }
+      doing = DoingNone;
+    } else if ((strcmp(av[i], "--target") == 0) ||
+               (strcmp(av[i], "-t") == 0)) {
+      doing = DoingTarget;
     } else if (strcmp(av[i], "--config") == 0) {
       doing = DoingConfig;
     } else if (strcmp(av[i], "--clean-first") == 0) {
-      clean = true;
+      cleanFirst = true;
       doing = DoingNone;
     } else if ((strcmp(av[i], "--verbose") == 0) ||
                (strcmp(av[i], "-v") == 0)) {
@@ -454,8 +467,23 @@
           doing = DoingNone;
           break;
         case DoingTarget:
-          target = av[i];
-          doing = DoingNone;
+          if (strlen(av[i]) == 0) {
+            std::cerr << "Warning: Argument number " << i
+                      << " after --target option is empty." << std::endl;
+          } else {
+            targets.emplace_back(av[i]);
+            if (strcmp(av[i], "clean") == 0) {
+              foundClean = true;
+            } else {
+              foundNonClean = true;
+            }
+          }
+          if (foundClean && foundNonClean) {
+            std::cerr << "Error: Building 'clean' and other targets together "
+                         "is not supported."
+                      << std::endl;
+            dir.clear();
+          }
           break;
         case DoingConfig:
           config = av[i];
@@ -499,13 +527,126 @@
   }
 
   cmake cm(cmake::RoleInternal, cmState::Project);
-  cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
-    cmakemainMessageCallback(msg, title, &cm);
-  });
-  cm.SetProgressCallback([&cm](const char* msg, float prog) {
+  cmSystemTools::SetMessageCallback(
+    [&cm](const std::string& msg, const char* title) {
+      cmakemainMessageCallback(msg, title, &cm);
+    });
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
-  return cm.Build(jobs, dir, target, config, nativeOptions, clean, verbose);
+  return cm.Build(jobs, dir, targets, config, nativeOptions, cleanFirst,
+                  verbose);
+#endif
+}
+
+static int do_install(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+  std::cerr << "This cmake does not support --install\n";
+  return -1;
+#else
+  assert(1 < ac);
+
+  std::string config;
+  std::string component;
+  std::string prefix;
+  std::string dir;
+  bool strip = false;
+  bool verbose = cmSystemTools::HasEnv("VERBOSE");
+
+  enum Doing
+  {
+    DoingNone,
+    DoingDir,
+    DoingConfig,
+    DoingComponent,
+    DoingPrefix,
+  };
+
+  Doing doing = DoingDir;
+
+  for (int i = 2; i < ac; ++i) {
+    if (strcmp(av[i], "--config") == 0) {
+      doing = DoingConfig;
+    } else if (strcmp(av[i], "--component") == 0) {
+      doing = DoingComponent;
+    } else if (strcmp(av[i], "--prefix") == 0) {
+      doing = DoingPrefix;
+    } else if (strcmp(av[i], "--strip") == 0) {
+      strip = true;
+      doing = DoingNone;
+    } else if ((strcmp(av[i], "--verbose") == 0) ||
+               (strcmp(av[i], "-v") == 0)) {
+      verbose = true;
+      doing = DoingNone;
+    } else {
+      switch (doing) {
+        case DoingDir:
+          dir = cmSystemTools::CollapseFullPath(av[i]);
+          doing = DoingNone;
+          break;
+        case DoingConfig:
+          config = av[i];
+          doing = DoingNone;
+          break;
+        case DoingComponent:
+          component = av[i];
+          doing = DoingNone;
+          break;
+        case DoingPrefix:
+          prefix = av[i];
+          doing = DoingNone;
+          break;
+        default:
+          std::cerr << "Unknown argument " << av[i] << std::endl;
+          dir.clear();
+          break;
+      }
+    }
+  }
+
+  if (dir.empty()) {
+    std::cerr << "Usage: cmake --install <dir> "
+                 "[options]\nOptions:\n" CMAKE_INSTALL_OPTIONS;
+    return 1;
+  }
+
+  cmake cm(cmake::RoleScript, cmState::Script);
+
+  cmSystemTools::SetMessageCallback(
+    [&cm](const std::string& msg, const char* title) {
+      cmakemainMessageCallback(msg, title, &cm);
+    });
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+    cmakemainProgressCallback(msg, prog, &cm);
+  });
+  cm.SetHomeDirectory("");
+  cm.SetHomeOutputDirectory("");
+  cm.SetDebugOutputOn(verbose);
+  cm.SetWorkingMode(cmake::SCRIPT_MODE);
+
+  std::vector<std::string> args{ av[0] };
+
+  if (!prefix.empty()) {
+    args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
+  }
+
+  if (!component.empty()) {
+    args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
+  }
+
+  if (strip) {
+    args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
+  }
+
+  if (!config.empty()) {
+    args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
+  }
+
+  args.emplace_back("-P");
+  args.emplace_back(dir + "/cmake_install.cmake");
+
+  return cm.Run(args) ? 1 : 0;
 #endif
 }
 
@@ -541,10 +682,11 @@
   }
 
   cmake cm(cmake::RoleInternal, cmState::Unknown);
-  cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
-    cmakemainMessageCallback(msg, title, &cm);
-  });
-  cm.SetProgressCallback([&cm](const char* msg, float prog) {
+  cmSystemTools::SetMessageCallback(
+    [&cm](const std::string& msg, const char* title) {
+      cmakemainMessageCallback(msg, title, &cm);
+    });
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
   return cm.Open(dir, false) ? 0 : 1;
diff --git a/Source/cmakexbuild.cxx b/Source/cmakexbuild.cxx
deleted file mode 100644
index 2951945..0000000
--- a/Source/cmakexbuild.cxx
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include "cmsys/Process.h"
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include "cmDuration.h"
-#include "cmSystemTools.h"
-
-// This is a wrapper program for xcodebuild
-// it calls xcodebuild, and does two things
-// it removes much of the output, all the setenv
-// stuff.  Also, it checks for the text file busy
-// error, and re-runs xcodebuild until that error does
-// not show up.
-
-int RunXCode(std::vector<const char*>& argv, bool& hitbug)
-{
-  hitbug = false;
-  cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
-  cmsysProcess_SetTimeout(cp, 0);
-  cmsysProcess_Execute(cp);
-  std::vector<char> out;
-  std::vector<char> err;
-  std::string line;
-  int pipe =
-    cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
-  while (pipe != cmsysProcess_Pipe_None) {
-    if (line.find("/bin/sh: bad interpreter: Text file busy") !=
-        std::string::npos) {
-      hitbug = true;
-      std::cerr << "Hit xcodebuild bug : " << line << "\n";
-    }
-    // if the bug is hit, no more output should be generated
-    // because it may contain bogus errors
-    // also remove all output with setenv in it to tone down
-    // the verbosity of xcodebuild
-    if (!hitbug && (line.find("setenv") == std::string::npos)) {
-      if (pipe == cmsysProcess_Pipe_STDERR) {
-        std::cerr << line << "\n";
-      } else if (pipe == cmsysProcess_Pipe_STDOUT) {
-        std::cout << line << "\n";
-      }
-    }
-    pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
-                                      err);
-  }
-  cmsysProcess_WaitForExit(cp, nullptr);
-  if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
-    return cmsysProcess_GetExitValue(cp);
-  }
-  if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
-    return -1;
-  }
-  return -1;
-}
-
-int main(int ac, char* av[])
-{
-  std::vector<const char*> argv;
-  argv.push_back("xcodebuild");
-  for (int i = 1; i < ac; i++) {
-    argv.push_back(av[i]);
-  }
-  argv.push_back(nullptr);
-  bool hitbug = true;
-  int ret = 0;
-  while (hitbug) {
-    ret = RunXCode(argv, hitbug);
-  }
-  if (ret < 0) {
-    return 255;
-  }
-  return ret;
-}
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 1a10666..19d0d38 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -276,7 +276,7 @@
 
     std::string clrest = rest;
     // rc: /fo x.dir\x.rc.res  ->  cl: /out:x.dir\x.rc.res.dep.obj
-    clrest = replace(clrest, "/fo", "/out:");
+    clrest = replace(clrest, "/fo ", "/out:");
     clrest = replace(clrest, objfile, objfile + ".dep.obj ");
 
     cl = "\"" + cl + "\" /P /DRC_INVOKED /TC ";
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index d20c5d2..c18c256 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -8,7 +8,8 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmQtAutoGeneratorMocUic.h"
-#include "cmQtAutoGeneratorRcc.h"
+#include "cmQtAutoRcc.h"
+#include "cmRange.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
@@ -37,6 +38,7 @@
 #include "cmsys/Process.h"
 #include "cmsys/Terminal.h"
 #include <algorithm>
+#include <array>
 #include <iostream>
 #include <iterator>
 #include <memory> // IWYU pragma: keep
@@ -109,8 +111,8 @@
     << "  tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
     << "                            - create or extract a tar or zip archive\n"
     << "  time command [args...]    - run command and display elapsed time\n"
-    << "  touch file                - touch a file.\n"
-    << "  touch_nocreate file       - touch a file but do not create it.\n"
+    << "  touch <file>...           - touch a <file>.\n"
+    << "  touch_nocreate <file>...  - touch a <file> but do not create it.\n"
     << "  create_symlink old new    - create a symbolic link new -> old\n"
 #if defined(_WIN32) && !defined(__CYGWIN__)
     << "Available on Windows only:\n"
@@ -350,12 +352,13 @@
   bool NoOriginalCommand;
 };
 
-static CoCompiler CoCompilers[] = { // Table of options and handlers.
-  { "--cppcheck=", HandleCppCheck, false },
-  { "--cpplint=", HandleCppLint, false },
-  { "--iwyu=", HandleIWYU, false },
-  { "--lwyu=", HandleLWYU, true },
-  { "--tidy=", HandleTidy, false }
+static const std::array<CoCompiler, 5> CoCompilers = {
+  { // Table of options and handlers.
+    { "--cppcheck=", HandleCppCheck, false },
+    { "--cpplint=", HandleCppLint, false },
+    { "--iwyu=", HandleIWYU, false },
+    { "--lwyu=", HandleLWYU, true },
+    { "--tidy=", HandleTidy, false } }
 };
 
 struct CoCompileJob
@@ -365,7 +368,7 @@
 };
 
 // called when args[0] == "__run_co_compile"
-int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
+int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
 {
   std::vector<CoCompileJob> jobs;
   std::string sourceFile;             // store --source=
@@ -378,24 +381,22 @@
 
   std::vector<std::string> orig_cmd;
   bool doing_options = true;
-  for (std::string::size_type i = 2; i < args.size(); ++i) {
-    std::string const& arg = args[i];
+  for (std::string const& arg : cmMakeRange(args).advance(2)) {
     // if the arg is -- then the rest of the args after
     // go into orig_cmd
     if (arg == "--") {
       doing_options = false;
     } else if (doing_options) {
       bool optionFound = false;
-      for (CoCompiler const* cc = cm::cbegin(CoCompilers);
-           cc != cm::cend(CoCompilers); ++cc) {
-        size_t optionLen = strlen(cc->Option);
-        if (arg.compare(0, optionLen, cc->Option) == 0) {
+      for (CoCompiler const& cc : CoCompilers) {
+        size_t optionLen = strlen(cc.Option);
+        if (arg.compare(0, optionLen, cc.Option) == 0) {
           optionFound = true;
           CoCompileJob job;
           job.Command = arg.substr(optionLen);
-          job.Handler = cc->Handler;
+          job.Handler = cc.Handler;
           jobs.push_back(std::move(job));
-          if (cc->NoOriginalCommand) {
+          if (cc.NoOriginalCommand) {
             runOriginalCmd = false;
           }
         }
@@ -419,9 +420,8 @@
   if (jobs.empty()) {
     std::cerr << "__run_co_compile missing command to run. "
                  "Looking for one or more of the following:\n";
-    for (CoCompiler const* cc = cm::cbegin(CoCompilers);
-         cc != cm::cend(CoCompilers); ++cc) {
-      std::cerr << cc->Option << "\n";
+    for (CoCompiler const& cc : CoCompilers) {
+      std::cerr << cc.Option << "\n";
     }
     return 1;
   }
@@ -465,7 +465,7 @@
   return ret;
 }
 
-int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
+int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
 {
   // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
   if (args.size() > 1) {
@@ -481,9 +481,9 @@
       }
       // If error occurs we want to continue copying next files.
       bool return_value = false;
-      for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
-        if (!cmSystemTools::cmCopyFile(args[cc], args.back())) {
-          std::cerr << "Error copying file \"" << args[cc] << "\" to \""
+      for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+        if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) {
+          std::cerr << "Error copying file \"" << arg << "\" to \""
                     << args.back() << "\".\n";
           return_value = true;
         }
@@ -503,9 +503,9 @@
       }
       // If error occurs we want to continue copying next files.
       bool return_value = false;
-      for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
-        if (!cmSystemTools::CopyFileIfDifferent(args[cc], args.back())) {
-          std::cerr << "Error copying file (if different) from \"" << args[cc]
+      for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+        if (!cmSystemTools::CopyFileIfDifferent(arg, args.back())) {
+          std::cerr << "Error copying file (if different) from \"" << arg
                     << "\" to \"" << args.back() << "\".\n";
           return_value = true;
         }
@@ -517,10 +517,10 @@
     if (args[1] == "copy_directory" && args.size() > 3) {
       // If error occurs we want to continue copying next files.
       bool return_value = false;
-      for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
-        if (!cmSystemTools::CopyADirectory(args[cc], args.back())) {
-          std::cerr << "Error copying directory from \"" << args[cc]
-                    << "\" to \"" << args.back() << "\".\n";
+      for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+        if (!cmSystemTools::CopyADirectory(arg, args.back())) {
+          std::cerr << "Error copying directory from \"" << arg << "\" to \""
+                    << args.back() << "\".\n";
           return_value = true;
         }
       }
@@ -613,13 +613,13 @@
     }
 
     if (args[1] == "env") {
-      std::vector<std::string>::const_iterator ai = args.begin() + 2;
-      std::vector<std::string>::const_iterator ae = args.end();
+      auto ai = args.cbegin() + 2;
+      auto ae = args.cend();
       for (; ai != ae; ++ai) {
         std::string const& a = *ai;
         if (cmHasLiteralPrefix(a, "--unset=")) {
           // Unset environment variable.
-          cmSystemTools::UnPutEnv(a.c_str() + 8);
+          cmSystemTools::UnPutEnv(a.substr(8));
         } else if (!a.empty() && a[0] == '-') {
           // Environment variable and command names cannot start in '-',
           // so this must be an unknown option.
@@ -653,10 +653,8 @@
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
     if (args[1] == "environment") {
-      std::vector<std::string> env = cmSystemTools::GetEnvironmentVariables();
-      std::vector<std::string>::iterator it;
-      for (it = env.begin(); it != env.end(); ++it) {
-        std::cout << *it << std::endl;
+      for (auto const& env : cmSystemTools::GetEnvironmentVariables()) {
+        std::cout << env << std::endl;
       }
       return 0;
     }
@@ -665,9 +663,9 @@
     if (args[1] == "make_directory" && args.size() > 2) {
       // If error occurs we want to continue copying next files.
       bool return_value = false;
-      for (std::string::size_type cc = 2; cc < args.size(); cc++) {
-        if (!cmSystemTools::MakeDirectory(args[cc])) {
-          std::cerr << "Error creating directory \"" << args[cc] << "\".\n";
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
+        if (!cmSystemTools::MakeDirectory(arg)) {
+          std::cerr << "Error creating directory \"" << arg << "\".\n";
           return_value = true;
         }
       }
@@ -686,14 +684,14 @@
     // Remove file
     if (args[1] == "remove" && args.size() > 2) {
       bool force = false;
-      for (std::string::size_type cc = 2; cc < args.size(); cc++) {
-        if (args[cc] == "\\-f" || args[cc] == "-f") {
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
+        if (arg == "\\-f" || arg == "-f") {
           force = true;
         } else {
           // Complain if the file could not be removed, still exists,
           // and the -f option was not given.
-          if (!cmSystemTools::RemoveFile(args[cc]) && !force &&
-              cmSystemTools::FileExists(args[cc])) {
+          if (!cmSystemTools::RemoveFile(arg) && !force &&
+              cmSystemTools::FileExists(arg)) {
             return 1;
           }
         }
@@ -703,10 +701,10 @@
 
     // Touch file
     if (args[1] == "touch" && args.size() > 2) {
-      for (std::string::size_type cc = 2; cc < args.size(); cc++) {
-        if (!cmSystemTools::Touch(args[cc], true)) {
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
+        if (!cmSystemTools::Touch(arg, true)) {
           std::cerr << "cmake -E touch: failed to update \"";
-          std::cerr << args[cc] << "\".\n";
+          std::cerr << arg << "\".\n";
           return 1;
         }
       }
@@ -715,10 +713,10 @@
 
     // Touch file
     if (args[1] == "touch_nocreate" && args.size() > 2) {
-      for (std::string::size_type cc = 2; cc < args.size(); cc++) {
-        if (!cmSystemTools::Touch(args[cc], false)) {
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
+        if (!cmSystemTools::Touch(arg, false)) {
           std::cerr << "cmake -E touch_nocreate: failed to update \"";
-          std::cerr << args[cc] << "\".\n";
+          std::cerr << arg << "\".\n";
           return 1;
         }
       }
@@ -743,15 +741,15 @@
     // Sleep command
     if (args[1] == "sleep" && args.size() > 2) {
       double total = 0;
-      for (size_t i = 2; i < args.size(); ++i) {
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
         double num = 0.0;
         char unit;
         char extra;
-        int n = sscanf(args[i].c_str(), "%lg%c%c", &num, &unit, &extra);
+        int n = sscanf(arg.c_str(), "%lg%c%c", &num, &unit, &extra);
         if ((n == 1 || (n == 2 && unit == 's')) && num >= 0) {
           total += num;
         } else {
-          std::cerr << "Unknown sleep time format \"" << args[i] << "\".\n";
+          std::cerr << "Unknown sleep time format \"" << arg << "\".\n";
           return 1;
         }
       }
@@ -817,8 +815,8 @@
     if (args[1] == "chdir" && args.size() >= 4) {
       std::string const& directory = args[2];
       if (!cmSystemTools::FileExists(directory)) {
-        cmSystemTools::Error("Directory does not exist for chdir command: ",
-                             args[2].c_str());
+        cmSystemTools::Error("Directory does not exist for chdir command: " +
+                             args[2]);
         return 1;
       }
 
@@ -826,7 +824,7 @@
         cmWrap('"', cmMakeRange(args).advance(3), '"', " ");
       int retval = 0;
       if (cmSystemTools::RunSingleCommand(
-            command.c_str(), nullptr, nullptr, &retval, directory.c_str(),
+            command, nullptr, nullptr, &retval, directory.c_str(),
             cmSystemTools::OUTPUT_PASSTHROUGH, cmDuration::zero())) {
         return retval;
       }
@@ -1026,7 +1024,7 @@
       return autoGen.Run(infoDir, config) ? 0 : 1;
     }
     if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) {
-      cmQtAutoGeneratorRcc autoGen;
+      cmQtAutoRcc autoGen;
       std::string const& infoFile = args[2];
       std::string config;
       if (args.size() > 3) {
@@ -1046,8 +1044,7 @@
       std::string mtime;
       std::string format;
       bool doing_options = true;
-      for (std::string::size_type cc = 4; cc < args.size(); cc++) {
-        std::string const& arg = args[cc];
+      for (auto const& arg : cmMakeRange(args).advance(4)) {
         if (doing_options && cmHasLiteralPrefix(arg, "--")) {
           if (arg == "--") {
             doing_options = false;
@@ -1065,37 +1062,63 @@
                         format) != cm::cend(knownFormats);
 
             if (!isKnown) {
-              cmSystemTools::Error("Unknown -E tar --format= argument: ",
-                                   format.c_str());
+              cmSystemTools::Error("Unknown -E tar --format= argument: " +
+                                   format);
               return 1;
             }
           } else {
-            cmSystemTools::Error("Unknown option to -E tar: ", arg.c_str());
+            cmSystemTools::Error("Unknown option to -E tar: " + arg);
             return 1;
           }
         } else {
           files.push_back(arg);
         }
       }
+      cmSystemTools::cmTarAction action = cmSystemTools::TarActionNone;
       cmSystemTools::cmTarCompression compress =
         cmSystemTools::TarCompressNone;
       bool verbose = false;
       int nCompress = 0;
-      if (flags.find_first_of('j') != std::string::npos) {
-        compress = cmSystemTools::TarCompressBZip2;
-        ++nCompress;
-      }
-      if (flags.find_first_of('J') != std::string::npos) {
-        compress = cmSystemTools::TarCompressXZ;
-        ++nCompress;
-      }
-      if (flags.find_first_of('z') != std::string::npos) {
-        compress = cmSystemTools::TarCompressGZip;
-        ++nCompress;
+
+      for (auto flag : flags) {
+        switch (flag) {
+          case '-':
+          case 'f': {
+            // Keep for backward compatibility. Ignored
+          } break;
+          case 'j': {
+            compress = cmSystemTools::TarCompressBZip2;
+            ++nCompress;
+          } break;
+          case 'J': {
+            compress = cmSystemTools::TarCompressXZ;
+            ++nCompress;
+          } break;
+          case 'z': {
+            compress = cmSystemTools::TarCompressGZip;
+            ++nCompress;
+          } break;
+          case 'v': {
+            verbose = true;
+          } break;
+          case 't': {
+            action = cmSystemTools::TarActionList;
+          } break;
+          case 'c': {
+            action = cmSystemTools::TarActionCreate;
+          } break;
+          case 'x': {
+            action = cmSystemTools::TarActionExtract;
+          } break;
+          default: {
+            cmSystemTools::Message(
+              std::string("tar: Unknown argument: ") + flag, "Warning");
+          }
+        }
       }
       if ((format == "7zip" || format == "zip") && nCompress > 0) {
-        cmSystemTools::Error("Can not use compression flags with format: ",
-                             format.c_str());
+        cmSystemTools::Error("Can not use compression flags with format: " +
+                             format);
         return 1;
       }
       if (nCompress > 1) {
@@ -1103,24 +1126,24 @@
                              "at most one flag of z, j, or J may be used");
         return 1;
       }
-      if (flags.find_first_of('v') != std::string::npos) {
-        verbose = true;
-      }
-
-      if (flags.find_first_of('t') != std::string::npos) {
+      if (action == cmSystemTools::TarActionList) {
         if (!cmSystemTools::ListTar(outFile.c_str(), verbose)) {
-          cmSystemTools::Error("Problem listing tar: ", outFile.c_str());
+          cmSystemTools::Error("Problem listing tar: " + outFile);
           return 1;
         }
-      } else if (flags.find_first_of('c') != std::string::npos) {
+      } else if (action == cmSystemTools::TarActionCreate) {
+        if (files.empty()) {
+          cmSystemTools::Message("tar: No files or directories specified",
+                                 "Warning");
+        }
         if (!cmSystemTools::CreateTar(outFile.c_str(), files, compress,
                                       verbose, mtime, format)) {
-          cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
+          cmSystemTools::Error("Problem creating tar: " + outFile);
           return 1;
         }
-      } else if (flags.find_first_of('x') != std::string::npos) {
+      } else if (action == cmSystemTools::TarActionExtract) {
         if (!cmSystemTools::ExtractTar(outFile.c_str(), verbose)) {
-          cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
+          cmSystemTools::Error("Problem extracting tar: " + outFile);
           return 1;
         }
 #ifdef WIN32
@@ -1139,6 +1162,10 @@
           cmSystemTools::Delay(delay);
         }
 #endif
+      } else {
+        cmSystemTools::Error("tar: No action specified. Please choose: 't' "
+                             "(list), 'c' (create) or 'x' (extract)");
+        return 1;
       }
       return 0;
     }
@@ -1149,17 +1176,15 @@
       bool isDebug = false;
       std::string pipe;
 
-      for (size_t i = 2; i < args.size(); ++i) {
-        const std::string& a = args[i];
-
-        if (a == "--experimental") {
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
+        if (arg == "--experimental") {
           supportExperimental = true;
-        } else if (a == "--debug") {
+        } else if (arg == "--debug") {
           pipe.clear();
           isDebug = true;
-        } else if (a.substr(0, pipePrefix.size()) == pipePrefix) {
+        } else if (arg.substr(0, pipePrefix.size()) == pipePrefix) {
           isDebug = false;
-          pipe = a.substr(pipePrefix.size());
+          pipe = arg.substr(pipePrefix.size());
           if (pipe.empty()) {
             cmSystemTools::Error("No pipe given after --pipe=");
             return 2;
@@ -1231,15 +1256,15 @@
   return 1;
 }
 
-int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo)
+int cmcmd::HashSumFile(std::vector<std::string> const& args,
+                       cmCryptoHash::Algo algo)
 {
   if (args.size() < 3) {
     return -1;
   }
   int retval = 0;
 
-  for (std::string::size_type cc = 2; cc < args.size(); cc++) {
-    const char* filename = args[cc].c_str();
+  for (auto const& filename : cmMakeRange(args).advance(2)) {
     // Cannot compute sum of a directory
     if (cmSystemTools::FileIsDirectory(filename)) {
       std::cerr << "Error: " << filename << " is a directory" << std::endl;
@@ -1258,7 +1283,7 @@
   return retval;
 }
 
-int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
+int cmcmd::SymlinkLibrary(std::vector<std::string> const& args)
 {
   int result = 0;
   std::string realName = args[2];
@@ -1282,7 +1307,7 @@
   return result;
 }
 
-int cmcmd::SymlinkExecutable(std::vector<std::string>& args)
+int cmcmd::SymlinkExecutable(std::vector<std::string> const& args)
 {
   int result = 0;
   std::string const& realName = args[2];
@@ -1356,7 +1381,7 @@
   }
 }
 
-int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
+int cmcmd::ExecuteEchoColor(std::vector<std::string> const& args)
 {
   // The arguments are
   //   args[0] == <cmake-executable>
@@ -1366,55 +1391,54 @@
   int color = cmsysTerminal_Color_Normal;
   bool newline = true;
   std::string progressDir;
-  for (unsigned int i = 2; i < args.size(); ++i) {
-    if (args[i].find("--switch=") == 0) {
+  for (auto const& arg : cmMakeRange(args).advance(2)) {
+    if (arg.find("--switch=") == 0) {
       // Enable or disable color based on the switch value.
-      std::string value = args[i].substr(9);
+      std::string value = arg.substr(9);
       if (!value.empty()) {
         enabled = cmSystemTools::IsOn(value);
       }
-    } else if (cmHasLiteralPrefix(args[i], "--progress-dir=")) {
-      progressDir = args[i].substr(15);
-    } else if (cmHasLiteralPrefix(args[i], "--progress-num=")) {
+    } else if (cmHasLiteralPrefix(arg, "--progress-dir=")) {
+      progressDir = arg.substr(15);
+    } else if (cmHasLiteralPrefix(arg, "--progress-num=")) {
       if (!progressDir.empty()) {
-        std::string const& progressNum = args[i].substr(15);
+        std::string const& progressNum = arg.substr(15);
         cmcmdProgressReport(progressDir, progressNum);
       }
-    } else if (args[i] == "--normal") {
+    } else if (arg == "--normal") {
       color = cmsysTerminal_Color_Normal;
-    } else if (args[i] == "--black") {
+    } else if (arg == "--black") {
       color = cmsysTerminal_Color_ForegroundBlack;
-    } else if (args[i] == "--red") {
+    } else if (arg == "--red") {
       color = cmsysTerminal_Color_ForegroundRed;
-    } else if (args[i] == "--green") {
+    } else if (arg == "--green") {
       color = cmsysTerminal_Color_ForegroundGreen;
-    } else if (args[i] == "--yellow") {
+    } else if (arg == "--yellow") {
       color = cmsysTerminal_Color_ForegroundYellow;
-    } else if (args[i] == "--blue") {
+    } else if (arg == "--blue") {
       color = cmsysTerminal_Color_ForegroundBlue;
-    } else if (args[i] == "--magenta") {
+    } else if (arg == "--magenta") {
       color = cmsysTerminal_Color_ForegroundMagenta;
-    } else if (args[i] == "--cyan") {
+    } else if (arg == "--cyan") {
       color = cmsysTerminal_Color_ForegroundCyan;
-    } else if (args[i] == "--white") {
+    } else if (arg == "--white") {
       color = cmsysTerminal_Color_ForegroundWhite;
-    } else if (args[i] == "--bold") {
+    } else if (arg == "--bold") {
       color |= cmsysTerminal_Color_ForegroundBold;
-    } else if (args[i] == "--no-newline") {
+    } else if (arg == "--no-newline") {
       newline = false;
-    } else if (args[i] == "--newline") {
+    } else if (arg == "--newline") {
       newline = true;
     } else {
       // Color is enabled.  Print with the current color.
-      cmSystemTools::MakefileColorEcho(color, args[i].c_str(), newline,
-                                       enabled);
+      cmSystemTools::MakefileColorEcho(color, arg.c_str(), newline, enabled);
     }
   }
 
   return 0;
 }
 
-int cmcmd::ExecuteLinkScript(std::vector<std::string>& args)
+int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
 {
   // The arguments are
   //   args[0] == <cmake-executable>
@@ -1627,9 +1651,9 @@
   return stream;
 }
 
-static bool RunCommand(const char* comment, std::vector<std::string>& command,
-                       bool verbose, NumberFormat exitFormat,
-                       int* retCodeOut = nullptr,
+static bool RunCommand(const char* comment,
+                       std::vector<std::string> const& command, bool verbose,
+                       NumberFormat exitFormat, int* retCodeOut = nullptr,
                        bool (*retCodeOkay)(int) = nullptr)
 {
   if (verbose) {
@@ -1830,7 +1854,8 @@
   // Compile the resource file.
   std::vector<std::string> rcCommand;
   rcCommand.push_back(this->RcPath.empty() ? "rc" : this->RcPath);
-  rcCommand.push_back("/fo" + this->ManifestFileRes);
+  rcCommand.emplace_back("/fo");
+  rcCommand.push_back(this->ManifestFileRes);
   rcCommand.push_back(this->ManifestFileRC);
   if (!RunCommand("RC Pass 1", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
     return -1;
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
index d1e03d0..69a7ecb 100644
--- a/Source/cmcmd.h
+++ b/Source/cmcmd.h
@@ -16,18 +16,18 @@
    * Execute commands during the build process. Supports options such
    * as echo, remove file etc.
    */
-  static int ExecuteCMakeCommand(std::vector<std::string>&);
+  static int ExecuteCMakeCommand(std::vector<std::string> const&);
 
 protected:
-  static int HandleCoCompileCommands(std::vector<std::string>& args);
-  static int HashSumFile(std::vector<std::string>& args,
+  static int HandleCoCompileCommands(std::vector<std::string> const& args);
+  static int HashSumFile(std::vector<std::string> const& args,
                          cmCryptoHash::Algo algo);
-  static int SymlinkLibrary(std::vector<std::string>& args);
-  static int SymlinkExecutable(std::vector<std::string>& args);
+  static int SymlinkLibrary(std::vector<std::string> const& args);
+  static int SymlinkExecutable(std::vector<std::string> const& args);
   static bool SymlinkInternal(std::string const& file,
                               std::string const& link);
-  static int ExecuteEchoColor(std::vector<std::string>& args);
-  static int ExecuteLinkScript(std::vector<std::string>& args);
+  static int ExecuteEchoColor(std::vector<std::string> const& args);
+  static int ExecuteLinkScript(std::vector<std::string> const& args);
   static int WindowsCEEnvironment(const char* version,
                                   const std::string& name);
   static int VisualStudioLink(std::vector<std::string> const& args, int type);
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 4a2531a..461021b 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -191,8 +191,7 @@
     doc.addCTestStandardDocSections();
     if (doc.CheckOptions(argc, argv)) {
       // Construct and print requested documentation.
-      cmCTestScriptHandler* ch =
-        static_cast<cmCTestScriptHandler*>(inst.GetHandler("script"));
+      cmCTestScriptHandler* ch = inst.GetScriptHandler();
       ch->CreateCMake();
 
       doc.SetShowGenerators(false);
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index e7da994..db4ef90 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -172,6 +172,9 @@
 IF(KWSYS_USE_Directory)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
+IF(KWSYS_USE_DynamicLoader)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
 IF(KWSYS_USE_FStream)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
@@ -179,13 +182,6 @@
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
 
-# Setup the large file support default.
-IF(KWSYS_LFS_DISABLE)
-  SET(KWSYS_LFS_REQUESTED 0)
-ELSE()
-  SET(KWSYS_LFS_REQUESTED 1)
-ENDIF()
-
 # Specify default 8 bit encoding for Windows
 IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
   SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
@@ -353,30 +349,6 @@
 ENDIF()
 
 #-----------------------------------------------------------------------------
-# Configure Large File Support.
-KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CSTDIO
-  "Checking whether header cstdio is available" DIRECT)
-SET(KWSYS_LFS_AVAILABLE 0)
-IF(KWSYS_LFS_REQUESTED)
-  # Large File Support is requested.
-  SET(KWSYS_LFS_REQUESTED 1)
-
-  # Check for large file support.
-  SET(KWSYS_PLATFORM_CXX_TEST_DEFINES
-    -DKWSYS_CXX_HAS_CSTDIO=${KWSYS_CXX_HAS_CSTDIO})
-  KWSYS_PLATFORM_CXX_TEST_RUN(KWSYS_LFS_WORKS
-    "Checking for Large File Support" DIRECT)
-  SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
-
-  IF(KWSYS_LFS_WORKS)
-    SET(KWSYS_LFS_AVAILABLE 1)
-  ENDIF()
-ELSE()
-  # Large File Support is not requested.
-  SET(KWSYS_LFS_REQUESTED 0)
-ENDIF()
-
-#-----------------------------------------------------------------------------
 # Configure the standard library header wrappers based on compiler's
 # capabilities and parent project's request.  Enforce 0/1 as only
 # possible values for configuration into Configure.hxx.
@@ -575,9 +547,6 @@
         COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
     ENDIF()
   ENDIF()
-  IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE)
-    SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1)
-  ENDIF()
   KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
     "Checking whether CXX compiler has rlimit64" DIRECT)
   SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
@@ -1130,6 +1099,20 @@
       ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c)
       SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB})
       ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE})
+
+      if (WIN32)
+        # Windows tests supported flags.
+        add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+        add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
+        add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+        add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
+        target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
+      endif ()
     ENDIF()
     CREATE_TEST_SOURCELIST(
       KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in
index 31115e5..7db9015 100644
--- a/Source/kwsys/CommandLineArguments.hxx.in
+++ b/Source/kwsys/CommandLineArguments.hxx.in
@@ -62,6 +62,9 @@
   CommandLineArguments();
   ~CommandLineArguments();
 
+  CommandLineArguments(const CommandLineArguments&) = delete;
+  CommandLineArguments& operator=(const CommandLineArguments&) = delete;
+
   /**
    * Various argument types.
    */
diff --git a/Source/kwsys/Configure.h.in b/Source/kwsys/Configure.h.in
index bec1abc..5323c57 100644
--- a/Source/kwsys/Configure.h.in
+++ b/Source/kwsys/Configure.h.in
@@ -28,43 +28,6 @@
 /* Whether kwsys namespace is "kwsys".  */
 #define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@
 
-/* Whether Large File Support is requested.  */
-#define @KWSYS_NAMESPACE@_LFS_REQUESTED @KWSYS_LFS_REQUESTED@
-
-/* Whether Large File Support is available.  */
-#if @KWSYS_NAMESPACE@_LFS_REQUESTED
-#  define @KWSYS_NAMESPACE@_LFS_AVAILABLE @KWSYS_LFS_AVAILABLE@
-#endif
-
-/* Setup Large File Support if requested.  */
-#if @KWSYS_NAMESPACE@_LFS_REQUESTED
-/* Since LFS is requested this header must be included before system
-   headers whether or not LFS is available. */
-#  if 0 && (defined(_SYS_TYPES_H) || defined(_SYS_TYPES_INCLUDED))
-#    error "@KWSYS_NAMESPACE@/Configure.h must be included before sys/types.h"
-#  endif
-/* Enable the large file API if it is available.  */
-#  if @KWSYS_NAMESPACE@_LFS_AVAILABLE &&                                      \
-    !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINES)
-#    if !defined(_LARGEFILE_SOURCE) &&                                        \
-      !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE_SOURCE)
-#      define _LARGEFILE_SOURCE
-#    endif
-#    if !defined(_LARGEFILE64_SOURCE) &&                                      \
-      !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE64_SOURCE)
-#      define _LARGEFILE64_SOURCE
-#    endif
-#    if !defined(_LARGE_FILES) &&                                             \
-      !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGE_FILES)
-#      define _LARGE_FILES
-#    endif
-#    if !defined(_FILE_OFFSET_BITS) &&                                        \
-      !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_FILE_OFFSET_BITS)
-#      define _FILE_OFFSET_BITS 64
-#    endif
-#  endif
-#endif
-
 /* Setup the export macro.  */
 #if @KWSYS_BUILD_SHARED@
 #  if defined(_WIN32) || defined(__CYGWIN__)
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 31b1c15..59530a4 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -102,7 +102,7 @@
 #  endif
   char* buf;
   size_t n = name.size();
-  if (*name.rbegin() == '/' || *name.rbegin() == '\\') {
+  if (name.back() == '/' || name.back() == '\\') {
     buf = new char[n + 1 + 1];
     sprintf(buf, "%s*", name.c_str());
   } else {
@@ -144,7 +144,7 @@
 #  endif
   char* buf;
   size_t n = name.size();
-  if (*name.rbegin() == '/') {
+  if (name.back() == '/') {
     buf = new char[n + 1 + 1];
     sprintf(buf, "%s*", name.c_str());
   } else {
diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx
index a85690f..b93a215 100644
--- a/Source/kwsys/DynamicLoader.cxx
+++ b/Source/kwsys/DynamicLoader.cxx
@@ -1,9 +1,14 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#if defined(_WIN32)
+#  define NOMINMAX // hide min,max to not conflict with <limits>
+#endif
+
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(DynamicLoader.hxx)
 
 #include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
@@ -25,6 +30,28 @@
 // Each part of the ifdef contains a complete implementation for
 // the static methods of DynamicLoader.
 
+#define CHECK_OPEN_FLAGS(var, supported, ret)                                 \
+  do {                                                                        \
+    /* Check for unknown flags. */                                            \
+    if ((var & AllOpenFlags) != var) {                                        \
+      return ret;                                                             \
+    }                                                                         \
+                                                                              \
+    /* Check for unsupported flags. */                                        \
+    if ((var & (supported)) != var) {                                         \
+      return ret;                                                             \
+    }                                                                         \
+  } while (0)
+
+namespace KWSYS_NAMESPACE {
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  return DynamicLoader::OpenLibrary(libname, 0);
+}
+}
+
 #if !KWSYS_SUPPORTS_SHARED_LIBS
 // Implementation for environments without dynamic libs
 #  include <string.h> // for strerror()
@@ -32,7 +59,7 @@
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
   return 0;
 }
@@ -67,8 +94,10 @@
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, 0);
+
   return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
 }
 
@@ -130,8 +159,10 @@
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, 0);
+
   NSObjectFileImageReturnCode rc;
   NSObjectFileImage image = 0;
 
@@ -185,19 +216,22 @@
 // Implementation for Windows win32 code but not cygwin
 #  include <windows.h>
 
+#  include <stdio.h>
+
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
-  DynamicLoader::LibraryHandle lh;
-  int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
-  wchar_t* wchars = new wchar_t[length + 1];
-  wchars[0] = '\0';
-  MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
-  lh = LoadLibraryW(wchars);
-  delete[] wchars;
-  return lh;
+  CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, NULL);
+
+  DWORD llFlags = 0;
+  if (flags & SearchBesideLibrary) {
+    llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH;
+  }
+
+  return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), NULL,
+                        llFlags);
 }
 
 int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
@@ -247,24 +281,38 @@
 #  endif
 }
 
+#  define DYNLOAD_ERROR_BUFFER_SIZE 1024
+
 const char* DynamicLoader::LastError()
 {
-  LPVOID lpMsgBuf = NULL;
+  wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1];
 
-  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-                NULL, GetLastError(),
-                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
-                (LPTSTR)&lpMsgBuf, 0, NULL);
+  DWORD error = GetLastError();
+  DWORD length = FormatMessageW(
+    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+    lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, NULL);
 
-  if (!lpMsgBuf) {
-    return NULL;
+  static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+  if (length < 1) {
+    /* FormatMessage failed.  Use a default message.  */
+    _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+              "DynamicLoader encountered error 0x%X.  "
+              "FormatMessage failed with error 0x%X",
+              error, GetLastError());
+    return str;
   }
 
-  static char* str = 0;
-  delete[] str;
-  str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
-  // Free the buffer.
-  LocalFree(lpMsgBuf);
+  if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str,
+                           DYNLOAD_ERROR_BUFFER_SIZE, NULL, NULL)) {
+    /* WideCharToMultiByte failed.  Use a default message.  */
+    _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+              "DynamicLoader encountered error 0x%X.  "
+              "WideCharToMultiByte failed with error 0x%X",
+              error, GetLastError());
+  }
+
   return str;
 }
 
@@ -282,8 +330,10 @@
 static image_id last_dynamic_err = B_OK;
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, 0);
+
   // image_id's are integers, errors are negative. Add one just in case we
   //  get a valid image_id of zero (is that even possible?).
   image_id rc = load_add_on(libname.c_str());
@@ -360,8 +410,10 @@
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, NULL);
+
   char* name = (char*)calloc(1, libname.size() + 1);
   dld_init(program_invocation_name);
   strncpy(name, libname.c_str(), libname.size());
@@ -404,8 +456,10 @@
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, NULL);
+
   return dlopen(libname.c_str(), RTLD_LAZY);
 }
 
diff --git a/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in
index 08f2790..539c742 100644
--- a/Source/kwsys/DynamicLoader.hxx.in
+++ b/Source/kwsys/DynamicLoader.hxx.in
@@ -66,10 +66,23 @@
   // Return type from DynamicLoader::GetSymbolAddress.
   typedef void (*SymbolPointer)();
 
+  enum OpenFlags
+  {
+    // Search for dependent libraries beside the library being loaded.
+    //
+    // This is currently only supported on Windows.
+    SearchBesideLibrary = 0x00000001,
+
+    AllOpenFlags = SearchBesideLibrary
+  };
+
   /** Load a dynamic library into the current process.
    * The returned LibraryHandle can be used to access the symbols in the
-   * library. */
+   * library. The optional second argument is a set of flags to use when
+   * opening the library. If unrecognized or unsupported flags are specified,
+   * the library is not opened. */
   static LibraryHandle OpenLibrary(const std::string&);
+  static LibraryHandle OpenLibrary(const std::string&, int);
 
   /** Attempt to detach a dynamic library from the
    * process.  A value of true is returned if it is successful. */
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 6952d24..829c138 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -263,7 +263,7 @@
       }
     } else {
       if (!this->Internals->Expressions.empty() &&
-          this->Internals->Expressions.rbegin()->find(fname)) {
+          this->Internals->Expressions.back().find(fname)) {
         this->AddFile(this->Internals->Files, realname);
       }
     }
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index bd4a176..4c3bde1 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -41,17 +41,9 @@
       , content(c)
     {
     }
-    Message(const Message& msg)
-      : type(msg.type)
-      , content(msg.content)
-    {
-    }
-    Message& operator=(Message const& msg)
-    {
-      this->type = msg.type;
-      this->content = msg.content;
-      return *this;
-    }
+    ~Message() = default;
+    Message(const Message& msg) = default;
+    Message& operator=(Message const& msg) = default;
   };
 
   typedef std::vector<Message> GlobMessages;
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index f323efc..4354753 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -4620,7 +4620,7 @@
 
   // Run the application
   kwsysProcess* gp = kwsysProcess_New();
-  kwsysProcess_SetCommand(gp, &*args.begin());
+  kwsysProcess_SetCommand(gp, args.data());
   kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1);
 
   kwsysProcess_Execute(gp);
diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in
index 9e1ce6c..5e93878 100644
--- a/Source/kwsys/SystemInformation.hxx.in
+++ b/Source/kwsys/SystemInformation.hxx.in
@@ -56,6 +56,9 @@
   SystemInformation();
   ~SystemInformation();
 
+  SystemInformation(const SystemInformation&) = delete;
+  SystemInformation& operator=(const SystemInformation&) = delete;
+
   const char* GetVendorString();
   const char* GetVendorID();
   std::string GetTypeID();
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index d8904fe..87da80e 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -28,6 +28,7 @@
 #include <iostream>
 #include <set>
 #include <sstream>
+#include <utility>
 #include <vector>
 
 // Work-around CMake dependency scanning limitation.  This must
@@ -363,10 +364,6 @@
 #endif
 }
 
-class SystemToolsTranslationMap : public std::map<std::string, std::string>
-{
-};
-
 /* Type of character storing the environment.  */
 #if defined(_WIN32)
 typedef wchar_t envchar;
@@ -416,6 +413,9 @@
     {
     }
     ~Free() { free(const_cast<envchar*>(this->Env)); }
+
+    Free(const Free&) = delete;
+    Free& operator=(const Free&) = delete;
   };
 
   const envchar* Release(const envchar* env)
@@ -444,15 +444,139 @@
 #  endif
   }
 };
+#endif
 
-class SystemToolsPathCaseMap
-  : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
+/**
+ * SystemTools static variables singleton class.
+ */
+class SystemToolsStatic
 {
+public:
+  typedef std::map<std::string, std::string> StringMap;
+  /**
+   * Path translation table from dir to refdir
+   * Each time 'dir' will be found it will be replace by 'refdir'
+   */
+  StringMap TranslationMap;
+#ifdef _WIN32
+  static std::string GetCasePathName(std::string const& pathIn);
+  static std::string GetActualCaseForPathCached(std::string const& path);
+  static const char* GetEnvBuffered(const char* key);
+  std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
+  std::map<std::string, std::string> EnvMap;
+#endif
+#ifdef __CYGWIN__
+  StringMap Cyg2Win32Map;
+#endif
+
+  /**
+   * Actual implementation of ReplaceString.
+   */
+  static void ReplaceString(std::string& source, const char* replace,
+                            size_t replaceSize, const std::string& with);
+
+  /**
+   * Actual implementation of FileIsFullPath.
+   */
+  static bool FileIsFullPath(const char*, size_t);
+
+  /**
+   * Find a filename (file or directory) in the system PATH, with
+   * optional extra paths.
+   */
+  static std::string FindName(
+    const std::string& name,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
 };
 
-class SystemToolsEnvMap : public std::map<std::string, std::string>
+#ifdef _WIN32
+std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
 {
-};
+  std::string casePath;
+
+  // First check if the file is relative. We don't fix relative paths since the
+  // real case depends on the root directory and the given path fragment may
+  // have meaning elsewhere in the project.
+  if (!SystemTools::FileIsFullPath(pathIn)) {
+    // This looks unnecessary, but it allows for the return value optimization
+    // since all return paths return the same local variable.
+    casePath = pathIn;
+    return casePath;
+  }
+
+  std::vector<std::string> path_components;
+  SystemTools::SplitPath(pathIn, path_components);
+
+  // Start with root component.
+  std::vector<std::string>::size_type idx = 0;
+  casePath = path_components[idx++];
+  // make sure drive letter is always upper case
+  if (casePath.size() > 1 && casePath[1] == ':') {
+    casePath[0] = toupper(casePath[0]);
+  }
+  const char* sep = "";
+
+  // If network path, fill casePath with server/share so FindFirstFile
+  // will work after that.  Maybe someday call other APIs to get
+  // actual case of servers and shares.
+  if (path_components.size() > 2 && path_components[0] == "//") {
+    casePath += path_components[idx++];
+    casePath += "/";
+    casePath += path_components[idx++];
+    sep = "/";
+  }
+
+  // Convert case of all components that exist.
+  bool converting = true;
+  for (; idx < path_components.size(); idx++) {
+    casePath += sep;
+    sep = "/";
+
+    if (converting) {
+      // If path component contains wildcards, we skip matching
+      // because these filenames are not allowed on windows,
+      // and we do not want to match a different file.
+      if (path_components[idx].find('*') != std::string::npos ||
+          path_components[idx].find('?') != std::string::npos) {
+        converting = false;
+      } else {
+        std::string test_str = casePath;
+        test_str += path_components[idx];
+        WIN32_FIND_DATAW findData;
+        HANDLE hFind =
+          ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
+        if (INVALID_HANDLE_VALUE != hFind) {
+          path_components[idx] = Encoding::ToNarrow(findData.cFileName);
+          ::FindClose(hFind);
+        } else {
+          converting = false;
+        }
+      }
+    }
+
+    casePath += path_components[idx];
+  }
+  return casePath;
+}
+
+std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p)
+{
+  // Check to see if actual case has already been called
+  // for this path, and the result is stored in the PathCaseMap
+  auto& pcm = SystemTools::Statics->PathCaseMap;
+  {
+    auto itr = pcm.find(p);
+    if (itr != pcm.end()) {
+      return itr->second;
+    }
+  }
+  std::string casePath = SystemToolsStatic::GetCasePathName(p);
+  if (casePath.size() <= MAX_PATH) {
+    pcm[p] = casePath;
+  }
+  return casePath;
+}
 #endif
 
 // adds the elements of the env variable path to the arg passed in
@@ -473,7 +597,7 @@
   }
 
   // A hack to make the below algorithm work.
-  if (!pathEnv.empty() && *pathEnv.rbegin() != pathSep) {
+  if (!pathEnv.empty() && pathEnv.back() != pathSep) {
     pathEnv += pathSep;
   }
   std::string::size_type start = 0;
@@ -493,30 +617,35 @@
   }
 }
 
-const char* SystemTools::GetEnvImpl(const char* key)
-{
-  const char* v = KWSYS_NULLPTR;
 #if defined(_WIN32)
+const char* SystemToolsStatic::GetEnvBuffered(const char* key)
+{
   std::string env;
   if (SystemTools::GetEnv(key, env)) {
-    std::string& menv = (*SystemTools::EnvMap)[key];
-    menv = env;
-    v = menv.c_str();
+    std::string& menv = SystemTools::Statics->EnvMap[key];
+    menv = std::move(env);
+    return menv.c_str();
   }
-#else
-  v = getenv(key);
-#endif
-  return v;
+  return KWSYS_NULLPTR;
 }
+#endif
 
 const char* SystemTools::GetEnv(const char* key)
 {
-  return SystemTools::GetEnvImpl(key);
+#if defined(_WIN32)
+  return SystemToolsStatic::GetEnvBuffered(key);
+#else
+  return getenv(key);
+#endif
 }
 
 const char* SystemTools::GetEnv(const std::string& key)
 {
-  return SystemTools::GetEnvImpl(key.c_str());
+#if defined(_WIN32)
+  return SystemToolsStatic::GetEnvBuffered(key.c_str());
+#else
+  return getenv(key.c_str());
+#endif
 }
 
 bool SystemTools::GetEnv(const char* key, std::string& result)
@@ -819,7 +948,8 @@
     return;
   }
 
-  SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with);
+  SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(),
+                                   with);
 }
 
 void SystemTools::ReplaceString(std::string& source, const char* replace,
@@ -830,12 +960,13 @@
     return;
   }
 
-  SystemTools::ReplaceString(source, replace, strlen(replace),
-                             with ? with : "");
+  SystemToolsStatic::ReplaceString(source, replace, strlen(replace),
+                                   with ? with : "");
 }
 
-void SystemTools::ReplaceString(std::string& source, const char* replace,
-                                size_t replaceSize, const std::string& with)
+void SystemToolsStatic::ReplaceString(std::string& source, const char* replace,
+                                      size_t replaceSize,
+                                      const std::string& with)
 {
   const char* src = source.c_str();
   char* searchPos = const_cast<char*>(strstr(src, replace));
@@ -1313,18 +1444,16 @@
 #ifdef __CYGWIN__
 bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path)
 {
-  SystemToolsTranslationMap::iterator i =
-    SystemTools::Cyg2Win32Map->find(path);
-
-  if (i != SystemTools::Cyg2Win32Map->end()) {
-    strncpy(win32_path, i->second.c_str(), MAX_PATH);
+  auto itr = SystemTools::Statics->Cyg2Win32Map.find(path);
+  if (itr != SystemTools::Statics->Cyg2Win32Map.end()) {
+    strncpy(win32_path, itr->second.c_str(), MAX_PATH);
   } else {
     if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) !=
         0) {
       win32_path[0] = 0;
     }
-    SystemToolsTranslationMap::value_type entry(path, win32_path);
-    SystemTools::Cyg2Win32Map->insert(entry);
+    SystemTools::Statics->Cyg2Win32Map.insert(
+      SystemToolsStatic::StringMap::value_type(path, win32_path));
   }
   return win32_path[0] != 0;
 }
@@ -1943,7 +2072,7 @@
   // a single /
   pathCString = path.c_str();
   size_t size = path.size();
-  if (size > 1 && *path.rbegin() == '/') {
+  if (size > 1 && path.back() == '/') {
     // if it is c:/ then do not remove the trailing slash
     if (!((size == 3 && pathCString[1] == ':'))) {
       path.resize(size - 1);
@@ -2670,9 +2799,9 @@
  * the system search path.  Returns the full path to the file if it is
  * found.  Otherwise, the empty string is returned.
  */
-std::string SystemTools::FindName(const std::string& name,
-                                  const std::vector<std::string>& userPaths,
-                                  bool no_system_path)
+std::string SystemToolsStatic::FindName(
+  const std::string& name, const std::vector<std::string>& userPaths,
+  bool no_system_path)
 {
   // Add the system search path to our path first
   std::vector<std::string> path;
@@ -2692,7 +2821,7 @@
     for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
          ++i) {
       std::string& p = *i;
-      if (p.empty() || *p.rbegin() != '/') {
+      if (p.empty() || p.back() != '/') {
         p += "/";
       }
     }
@@ -2720,7 +2849,8 @@
                                   const std::vector<std::string>& userPaths,
                                   bool no_system_path)
 {
-  std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+  std::string tryPath =
+    SystemToolsStatic::FindName(name, userPaths, no_system_path);
   if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) {
     return SystemTools::CollapseFullPath(tryPath);
   }
@@ -2737,7 +2867,8 @@
   const std::string& name, const std::vector<std::string>& userPaths,
   bool no_system_path)
 {
-  std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+  std::string tryPath =
+    SystemToolsStatic::FindName(name, userPaths, no_system_path);
   if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) {
     return SystemTools::CollapseFullPath(tryPath);
   }
@@ -2810,7 +2941,7 @@
     for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
          ++i) {
       std::string& p = *i;
-      if (p.empty() || *p.rbegin() != '/') {
+      if (p.empty() || p.back() != '/') {
         p += "/";
       }
     }
@@ -2888,7 +3019,7 @@
     for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
          ++i) {
       std::string& p = *i;
-      if (p.empty() || *p.rbegin() != '/') {
+      if (p.empty() || p.back() != '/') {
         p += "/";
       }
     }
@@ -3234,15 +3365,16 @@
     if (SystemTools::FileIsFullPath(path_b) &&
         path_b.find("..") == std::string::npos) {
       // Before inserting make sure path ends with '/'
-      if (!path_a.empty() && *path_a.rbegin() != '/') {
+      if (!path_a.empty() && path_a.back() != '/') {
         path_a += '/';
       }
-      if (!path_b.empty() && *path_b.rbegin() != '/') {
+      if (!path_b.empty() && path_b.back() != '/') {
         path_b += '/';
       }
       if (!(path_a == path_b)) {
-        SystemTools::TranslationMap->insert(
-          SystemToolsTranslationMap::value_type(path_a, path_b));
+        SystemTools::Statics->TranslationMap.insert(
+          SystemToolsStatic::StringMap::value_type(std::move(path_a),
+                                                   std::move(path_b)));
       }
     }
   }
@@ -3266,21 +3398,19 @@
   // Always add a trailing slash before translation.  It does not
   // matter if this adds an extra slash, but we do not want to
   // translate part of a directory (like the foo part of foo-dir).
-  path += "/";
+  path += '/';
 
   // In case a file was specified we still have to go through this:
   // Now convert any path found in the table back to the one desired:
-  std::map<std::string, std::string>::const_iterator it;
-  for (it = SystemTools::TranslationMap->begin();
-       it != SystemTools::TranslationMap->end(); ++it) {
+  for (auto const& pair : SystemTools::Statics->TranslationMap) {
     // We need to check of the path is a substring of the other path
-    if (path.find(it->first) == 0) {
-      path = path.replace(0, it->first.size(), it->second);
+    if (path.find(pair.first) == 0) {
+      path = path.replace(0, pair.first.size(), pair.second);
     }
   }
 
   // Remove the trailing slash we added before.
-  path.erase(path.end() - 1, path.end());
+  path.pop_back();
 }
 
 static void SystemToolsAppendComponents(
@@ -3368,7 +3498,7 @@
 
   SystemTools::CheckTranslationPath(newPath);
 #ifdef _WIN32
-  newPath = SystemTools::GetActualCaseForPathCached(newPath);
+  newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath);
   SystemTools::ConvertToUnixSlashes(newPath);
 #endif
   // Return the reconstructed path.
@@ -3446,7 +3576,7 @@
   // between each entry that does not already have one
   for (std::vector<std::string>::iterator vit1 = finalPath.begin();
        vit1 != finalPath.end(); ++vit1) {
-    if (!relativePath.empty() && *relativePath.rbegin() != '/') {
+    if (!relativePath.empty() && relativePath.back() != '/') {
       relativePath += "/";
     }
     relativePath += *vit1;
@@ -3454,103 +3584,14 @@
   return relativePath;
 }
 
-#ifdef _WIN32
-static std::string GetCasePathName(std::string const& pathIn)
-{
-  std::string casePath;
-
-  // First check if the file is relative. We don't fix relative paths since the
-  // real case depends on the root directory and the given path fragment may
-  // have meaning elsewhere in the project.
-  if (!SystemTools::FileIsFullPath(pathIn)) {
-    // This looks unnecessary, but it allows for the return value optimization
-    // since all return paths return the same local variable.
-    casePath = pathIn;
-    return casePath;
-  }
-
-  std::vector<std::string> path_components;
-  SystemTools::SplitPath(pathIn, path_components);
-
-  // Start with root component.
-  std::vector<std::string>::size_type idx = 0;
-  casePath = path_components[idx++];
-  // make sure drive letter is always upper case
-  if (casePath.size() > 1 && casePath[1] == ':') {
-    casePath[0] = toupper(casePath[0]);
-  }
-  const char* sep = "";
-
-  // If network path, fill casePath with server/share so FindFirstFile
-  // will work after that.  Maybe someday call other APIs to get
-  // actual case of servers and shares.
-  if (path_components.size() > 2 && path_components[0] == "//") {
-    casePath += path_components[idx++];
-    casePath += "/";
-    casePath += path_components[idx++];
-    sep = "/";
-  }
-
-  // Convert case of all components that exist.
-  bool converting = true;
-  for (; idx < path_components.size(); idx++) {
-    casePath += sep;
-    sep = "/";
-
-    if (converting) {
-      // If path component contains wildcards, we skip matching
-      // because these filenames are not allowed on windows,
-      // and we do not want to match a different file.
-      if (path_components[idx].find('*') != std::string::npos ||
-          path_components[idx].find('?') != std::string::npos) {
-        converting = false;
-      } else {
-        std::string test_str = casePath;
-        test_str += path_components[idx];
-        WIN32_FIND_DATAW findData;
-        HANDLE hFind =
-          ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
-        if (INVALID_HANDLE_VALUE != hFind) {
-          path_components[idx] = Encoding::ToNarrow(findData.cFileName);
-          ::FindClose(hFind);
-        } else {
-          converting = false;
-        }
-      }
-    }
-
-    casePath += path_components[idx];
-  }
-  return casePath;
-}
-#endif
-
 std::string SystemTools::GetActualCaseForPath(const std::string& p)
 {
-#ifndef _WIN32
-  return p;
-#else
-  return GetCasePathName(p);
-#endif
-}
-
 #ifdef _WIN32
-std::string SystemTools::GetActualCaseForPathCached(std::string const& p)
-{
-  // Check to see if actual case has already been called
-  // for this path, and the result is stored in the PathCaseMap
-  SystemToolsPathCaseMap::iterator i = SystemTools::PathCaseMap->find(p);
-  if (i != SystemTools::PathCaseMap->end()) {
-    return i->second;
-  }
-  std::string casePath = GetCasePathName(p);
-  if (casePath.size() > MAX_PATH) {
-    return casePath;
-  }
-  (*SystemTools::PathCaseMap)[p] = casePath;
-  return casePath;
-}
+  return SystemToolsStatic::GetCasePathName(p);
+#else
+  return p;
 #endif
+}
 
 const char* SystemTools::SplitPathRootComponent(const std::string& p,
                                                 std::string* root)
@@ -3648,7 +3689,7 @@
       }
 #endif
       if (!homedir.empty() &&
-          (*homedir.rbegin() == '/' || *homedir.rbegin() == '\\')) {
+          (homedir.back() == '/' || homedir.back() == '\\')) {
         homedir.resize(homedir.size() - 1);
       }
       SystemTools::SplitPath(homedir, components);
@@ -4016,7 +4057,7 @@
         filename_dir = SystemTools::GetFilenamePath(filename_dir);
         filename_dir_base = SystemTools::GetFilenameName(filename_dir);
 #if defined(_WIN32)
-        if (filename_dir_base.empty() || *filename_dir_base.rbegin() == ':')
+        if (filename_dir_base.empty() || filename_dir_base.back() == ':')
 #else
         if (filename_dir_base.empty())
 #endif
@@ -4044,16 +4085,16 @@
 
 bool SystemTools::FileIsFullPath(const std::string& in_name)
 {
-  return SystemTools::FileIsFullPath(in_name.c_str(), in_name.size());
+  return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size());
 }
 
 bool SystemTools::FileIsFullPath(const char* in_name)
 {
-  return SystemTools::FileIsFullPath(in_name,
-                                     in_name[0] ? (in_name[1] ? 2 : 1) : 0);
+  return SystemToolsStatic::FileIsFullPath(
+    in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
 }
 
-bool SystemTools::FileIsFullPath(const char* in_name, size_t len)
+bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len)
 {
 #if defined(_WIN32) || defined(__CYGWIN__)
   // On Windows, the name must be at least two characters long.
@@ -4092,7 +4133,7 @@
   std::string tempPath = path; // create a buffer
 
   // if the path passed in has quotes around it, first remove the quotes
-  if (!path.empty() && path[0] == '"' && *path.rbegin() == '"') {
+  if (!path.empty() && path[0] == '"' && path.back() == '"') {
     tempPath = path.substr(1, path.length() - 2);
   }
 
@@ -4169,7 +4210,7 @@
   bool haveData = !line.empty() || !is.eof();
   if (!line.empty()) {
     // Avoid storing a carriage return character.
-    if (*line.rbegin() == '\r') {
+    if (line.back() == '\r') {
       line.resize(line.size() - 1);
     }
 
@@ -4307,7 +4348,7 @@
   if (subdir.size() <= dir.size() || dir.empty()) {
     return false;
   }
-  bool isRootPath = *dir.rbegin() == '/'; // like "/" or "C:/"
+  bool isRootPath = dir.back() == '/'; // like "/" or "C:/"
   size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size();
   if (subdir[expectedSlashPosition] != '/') {
     return false;
@@ -4651,14 +4692,7 @@
 // These must NOT be initialized.  Default initialization to zero is
 // necessary.
 static unsigned int SystemToolsManagerCount;
-SystemToolsTranslationMap* SystemTools::TranslationMap;
-#ifdef _WIN32
-SystemToolsPathCaseMap* SystemTools::PathCaseMap;
-SystemToolsEnvMap* SystemTools::EnvMap;
-#endif
-#ifdef __CYGWIN__
-SystemToolsTranslationMap* SystemTools::Cyg2Win32Map;
-#endif
+SystemToolsStatic* SystemTools::Statics;
 
 // SystemToolsManager manages the SystemTools singleton.
 // SystemToolsManager should be included in any translation unit
@@ -4699,15 +4733,9 @@
 #ifdef __VMS
   SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1);
 #endif
-  // Allocate the translation map first.
-  SystemTools::TranslationMap = new SystemToolsTranslationMap;
-#ifdef _WIN32
-  SystemTools::PathCaseMap = new SystemToolsPathCaseMap;
-  SystemTools::EnvMap = new SystemToolsEnvMap;
-#endif
-#ifdef __CYGWIN__
-  SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap;
-#endif
+
+  // Create statics singleton instance
+  SystemTools::Statics = new SystemToolsStatic;
 
 // Add some special translation paths for unix.  These are not added
 // for windows because drive letters need to be maintained.  Also,
@@ -4755,14 +4783,7 @@
 
 void SystemTools::ClassFinalize()
 {
-  delete SystemTools::TranslationMap;
-#ifdef _WIN32
-  delete SystemTools::PathCaseMap;
-  delete SystemTools::EnvMap;
-#endif
-#ifdef __CYGWIN__
-  delete SystemTools::Cyg2Win32Map;
-#endif
+  delete SystemTools::Statics;
 }
 
 } // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index 1967860..cdc9483 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -41,9 +41,7 @@
 
 namespace @KWSYS_NAMESPACE@ {
 
-class SystemToolsTranslationMap;
-class SystemToolsPathCaseMap;
-class SystemToolsEnvMap;
+class SystemToolsStatic;
 
 /** \class SystemToolsManager
  * \brief Use to make sure SystemTools is initialized before it is used
@@ -54,6 +52,9 @@
 public:
   SystemToolsManager();
   ~SystemToolsManager();
+
+  SystemToolsManager(const SystemToolsManager&) = delete;
+  SystemToolsManager& operator=(const SystemToolsManager&) = delete;
 };
 
 // This instance will show up in any translation unit that uses
@@ -964,41 +965,8 @@
     return &SystemToolsManagerInstance;
   }
 
-  /**
-   * Actual implementation of ReplaceString.
-   */
-  static void ReplaceString(std::string& source, const char* replace,
-                            size_t replaceSize, const std::string& with);
-
-  /**
-   * Actual implementation of FileIsFullPath.
-   */
-  static bool FileIsFullPath(const char*, size_t);
-
-  /**
-   * Find a filename (file or directory) in the system PATH, with
-   * optional extra paths.
-   */
-  static std::string FindName(
-    const std::string& name,
-    const std::vector<std::string>& path = std::vector<std::string>(),
-    bool no_system_path = false);
-
-  static const char* GetEnvImpl(const char* key);
-
-  /**
-   * Path translation table from dir to refdir
-   * Each time 'dir' will be found it will be replace by 'refdir'
-   */
-  static SystemToolsTranslationMap* TranslationMap;
-#ifdef _WIN32
-  static std::string GetActualCaseForPathCached(std::string const& path);
-  static SystemToolsPathCaseMap* PathCaseMap;
-  static SystemToolsEnvMap* EnvMap;
-#endif
-#ifdef __CYGWIN__
-  static SystemToolsTranslationMap* Cyg2Win32Map;
-#endif
+  static SystemToolsStatic* Statics;
+  friend class SystemToolsStatic;
   friend class SystemToolsManager;
 };
 
diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in
index fc0d60e..0981c66 100644
--- a/Source/kwsys/hashtable.hxx.in
+++ b/Source/kwsys/hashtable.hxx.in
@@ -73,7 +73,7 @@
   void public_method_to_quiet_warning_about_all_methods_private();
 
 private:
-  void operator=(_Hashtable_node<_Val> const&); // poison node assignment
+  void operator=(_Hashtable_node<_Val> const&) = delete;
 };
 
 template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx
index b77d729..cfd5666 100644
--- a/Source/kwsys/kwsysPlatformTestsCXX.cxx
+++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx
@@ -136,42 +136,6 @@
 }
 #endif
 
-#ifdef TEST_KWSYS_LFS_WORKS
-/* Return 0 when LFS is available and 1 otherwise.  */
-#  define _LARGEFILE_SOURCE
-#  define _LARGEFILE64_SOURCE
-#  define _LARGE_FILES
-#  define _FILE_OFFSET_BITS 64
-#  include <sys/types.h>
-
-#  include <assert.h>
-#  include <sys/stat.h>
-#  if KWSYS_CXX_HAS_CSTDIO
-#    include <cstdio>
-#  endif
-#  include <stdio.h>
-
-int main(int, char** argv)
-{
-/* check that off_t can hold 2^63 - 1 and perform basic operations... */
-#  define OFF_T_64 (((off_t)1 << 62) - 1 + ((off_t)1 << 62))
-  if (OFF_T_64 % 2147483647 != 1)
-    return 1;
-
-  // stat breaks on SCO OpenServer
-  struct stat buf;
-  stat(argv[0], &buf);
-  if (!S_ISREG(buf.st_mode))
-    return 2;
-
-  FILE* file = fopen(argv[0], "r");
-  off_t offset = ftello(file);
-  fseek(file, offset, SEEK_CUR);
-  fclose(file);
-  return 0;
-}
-#endif
-
 #ifdef TEST_KWSYS_CXX_HAS_SETENV
 #  include <stdlib.h>
 int main()
@@ -212,12 +176,6 @@
 #endif
 
 #ifdef TEST_KWSYS_CXX_HAS_RLIMIT64
-#  if defined(KWSYS_HAS_LFS)
-#    define _LARGEFILE_SOURCE
-#    define _LARGEFILE64_SOURCE
-#    define _LARGE_FILES
-#    define _FILE_OFFSET_BITS 64
-#  endif
 #  include <sys/resource.h>
 int main()
 {
diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
index ce87117..eff2ed7 100644
--- a/Source/kwsys/testDynamicLoader.cxx
+++ b/Source/kwsys/testDynamicLoader.cxx
@@ -21,11 +21,15 @@
 // left on disk.
 #include <testSystemTools.h>
 
-static std::string GetLibName(const char* lname)
+static std::string GetLibName(const char* lname, const char* subdir = NULL)
 {
   // Construct proper name of lib
   std::string slname;
   slname = EXECUTABLE_OUTPUT_PATH;
+  if (subdir) {
+    slname += "/";
+    slname += subdir;
+  }
 #ifdef CMAKE_INTDIR
   slname += "/";
   slname += CMAKE_INTDIR;
@@ -45,26 +49,29 @@
  * r3: should CloseLibrary succeed ?
  */
 static int TestDynamicLoader(const char* libname, const char* symbol, int r1,
-                             int r2, int r3)
+                             int r2, int r3, int flags = 0)
 {
   std::cerr << "Testing: " << libname << std::endl;
   kwsys::DynamicLoader::LibraryHandle l =
-    kwsys::DynamicLoader::OpenLibrary(libname);
+    kwsys::DynamicLoader::OpenLibrary(libname, flags);
   // If result is incompatible with expectation just fails (xor):
   if ((r1 && !l) || (!r1 && l)) {
-    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError()
+              << std::endl;
     return 1;
   }
   kwsys::DynamicLoader::SymbolPointer f =
     kwsys::DynamicLoader::GetSymbolAddress(l, symbol);
   if ((r2 && !f) || (!r2 && f)) {
-    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError()
+              << std::endl;
     return 1;
   }
 #ifndef __APPLE__
   int s = kwsys::DynamicLoader::CloseLibrary(l);
   if ((r3 && !s) || (!r3 && s)) {
-    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError()
+              << std::endl;
     return 1;
   }
 #else
@@ -113,5 +120,14 @@
   res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1);
   res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1);
 
+#ifdef _WIN32
+  libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir");
+  res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0);
+  res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1,
+                           kwsys::DynamicLoader::SearchBesideLibrary);
+  res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1,
+                           kwsys::DynamicLoader::SearchBesideLibrary);
+#endif
+
   return res;
 }
diff --git a/Source/kwsys/testDynloadImpl.c b/Source/kwsys/testDynloadImpl.c
new file mode 100644
index 0000000..2b9069b
--- /dev/null
+++ b/Source/kwsys/testDynloadImpl.c
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+
+#include "testDynloadImpl.h"
+
+int TestDynamicLoaderImplData = 0;
+
+void TestDynamicLoaderImplSymbolPointer()
+{
+}
diff --git a/Source/kwsys/testDynloadImpl.h b/Source/kwsys/testDynloadImpl.h
new file mode 100644
index 0000000..d0c9dfb
--- /dev/null
+++ b/Source/kwsys/testDynloadImpl.h
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef _WIN32
+#  ifdef BUILDING_TestDynloadImpl
+#    define DLIMPL_EXPORT __declspec(dllexport)
+#  else
+#    define DLIMPL_EXPORT __declspec(dllimport)
+#  endif
+#else
+#  define DLIMPL_EXPORT
+#endif
+
+DLIMPL_EXPORT int TestDynamicLoaderImplData;
+
+DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer();
diff --git a/Source/kwsys/testDynloadUse.c b/Source/kwsys/testDynloadUse.c
new file mode 100644
index 0000000..5402add
--- /dev/null
+++ b/Source/kwsys/testDynloadUse.c
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "testDynloadImpl.h"
+
+#ifdef _WIN32
+#  define DL_EXPORT __declspec(dllexport)
+#else
+#  define DL_EXPORT
+#endif
+
+DL_EXPORT int TestLoad()
+{
+  TestDynamicLoaderImplSymbolPointer();
+  return TestDynamicLoaderImplData;
+}
diff --git a/Tests/BundleTest/BundleSubDir/CMakeLists.txt b/Tests/BundleTest/BundleSubDir/CMakeLists.txt
index 43c366a..2f7f2c4 100644
--- a/Tests/BundleTest/BundleSubDir/CMakeLists.txt
+++ b/Tests/BundleTest/BundleSubDir/CMakeLists.txt
@@ -1,3 +1,5 @@
+project(BundleSubDir)
+
 add_custom_command(
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
   COMMAND /bin/cp
@@ -34,3 +36,8 @@
 # bundle does not respect the name.  Also the executable will not be found by
 # the test driver if this does not work.
 set_target_properties(SecondBundle PROPERTIES OUTPUT_NAME SecondBundleExe)
+
+# Express one app bundle in terms of another's SOURCES to verify that
+# the generators do not expose the Info.plist of one to the other.
+add_executable(SubdirBundle1 MACOSX_BUNDLE EXCLUDE_FROM_ALL ../BundleTest.cxx)
+add_executable(SubdirBundle2 MACOSX_BUNDLE EXCLUDE_FROM_ALL $<TARGET_PROPERTY:SubdirBundle1,SOURCES>)
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index f6a9153..031ab01 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -5,8 +5,10 @@
   )
 
 set(CMakeLib_TESTS
+  testArgumentParser.cxx
   testGeneratedFileStream.cxx
   testRST.cxx
+  testRange.cxx
   testString.cxx
   testSystemTools.cxx
   testUTF8.cxx
diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx
new file mode 100644
index 0000000..788fece
--- /dev/null
+++ b/Tests/CMakeLib/testArgumentParser.cxx
@@ -0,0 +1,148 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmArgumentParser.h"
+
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
+
+#include <initializer_list>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace {
+
+struct Result
+{
+  bool Option1 = false;
+  bool Option2 = false;
+
+  std::string String1;
+  std::string String2;
+
+  std::vector<std::string> List1;
+  std::vector<std::string> List2;
+  std::vector<std::string> List3;
+
+  std::vector<std::vector<std::string>> Multi1;
+  std::vector<std::vector<std::string>> Multi2;
+  std::vector<std::vector<std::string>> Multi3;
+};
+
+std::initializer_list<cm::string_view> const args = {
+  /* clang-format off */
+  "OPTION_1",                // option
+  "STRING_1",                // string arg missing value
+  "STRING_2", "foo", "bar",  // string arg + unparsed value
+  "LIST_1",                  // list arg missing values
+  "LIST_2", "foo", "bar",    // list arg with 2 elems
+  "LIST_3", "bar",           // list arg ...
+  "LIST_3", "foo",           // ... with continuation
+  "MULTI_2",                 // multi list with 0 lists
+  "MULTI_3", "foo", "bar",   // multi list with first list with two elems
+  "MULTI_3", "bar", "foo",   // multi list with second list with two elems
+  /* clang-format on */
+};
+
+bool verifyResult(Result const& result,
+                  std::vector<std::string> const& unparsedArguments,
+                  std::vector<std::string> const& keywordsMissingValue)
+{
+  static std::vector<std::string> const foobar = { "foo", "bar" };
+  static std::vector<std::string> const barfoo = { "bar", "foo" };
+  static std::vector<std::string> const missing = { "STRING_1", "LIST_1" };
+
+#define ASSERT_TRUE(x)                                                        \
+  do {                                                                        \
+    if (!(x)) {                                                               \
+      std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+      return false;                                                           \
+    }                                                                         \
+  } while (false)
+
+  ASSERT_TRUE(result.Option1);
+  ASSERT_TRUE(!result.Option2);
+
+  ASSERT_TRUE(result.String1.empty());
+  ASSERT_TRUE(result.String2 == "foo");
+
+  ASSERT_TRUE(result.List1.empty());
+  ASSERT_TRUE(result.List2 == foobar);
+  ASSERT_TRUE(result.List3 == barfoo);
+
+  ASSERT_TRUE(result.Multi1.empty());
+  ASSERT_TRUE(result.Multi2.size() == 1);
+  ASSERT_TRUE(result.Multi2[0].empty());
+  ASSERT_TRUE(result.Multi3.size() == 2);
+  ASSERT_TRUE(result.Multi3[0] == foobar);
+  ASSERT_TRUE(result.Multi3[1] == barfoo);
+
+  ASSERT_TRUE(unparsedArguments.size() == 1);
+  ASSERT_TRUE(unparsedArguments[0] == "bar");
+  ASSERT_TRUE(keywordsMissingValue == missing);
+
+  return true;
+}
+
+bool testArgumentParserDynamic()
+{
+  Result result;
+  std::vector<std::string> unparsedArguments;
+  std::vector<std::string> keywordsMissingValue;
+
+  cmArgumentParser<void>{}
+    .Bind("OPTION_1"_s, result.Option1)
+    .Bind("OPTION_2"_s, result.Option2)
+    .Bind("STRING_1"_s, result.String1)
+    .Bind("STRING_2"_s, result.String2)
+    .Bind("LIST_1"_s, result.List1)
+    .Bind("LIST_2"_s, result.List2)
+    .Bind("LIST_3"_s, result.List3)
+    .Bind("MULTI_1"_s, result.Multi1)
+    .Bind("MULTI_2"_s, result.Multi2)
+    .Bind("MULTI_3"_s, result.Multi3)
+    .Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+  return verifyResult(result, unparsedArguments, keywordsMissingValue);
+}
+
+bool testArgumentParserStatic()
+{
+  static auto const parser = //
+    cmArgumentParser<Result>{}
+      .Bind("OPTION_1"_s, &Result::Option1)
+      .Bind("OPTION_2"_s, &Result::Option2)
+      .Bind("STRING_1"_s, &Result::String1)
+      .Bind("STRING_2"_s, &Result::String2)
+      .Bind("LIST_1"_s, &Result::List1)
+      .Bind("LIST_2"_s, &Result::List2)
+      .Bind("LIST_3"_s, &Result::List3)
+      .Bind("MULTI_1"_s, &Result::Multi1)
+      .Bind("MULTI_2"_s, &Result::Multi2)
+      .Bind("MULTI_3"_s, &Result::Multi3);
+
+  std::vector<std::string> unparsedArguments;
+  std::vector<std::string> keywordsMissingValue;
+  Result const result =
+    parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+  return verifyResult(result, unparsedArguments, keywordsMissingValue);
+}
+
+} // namespace
+
+int testArgumentParser(int /*unused*/, char* /*unused*/ [])
+{
+  if (!testArgumentParserDynamic()) {
+    std::cout << "While executing testArgumentParserDynamic().\n";
+    return -1;
+  }
+
+  if (!testArgumentParserStatic()) {
+    std::cout << "While executing testArgumentParserStatic().\n";
+    return -1;
+  }
+
+  return 0;
+}
diff --git a/Tests/CMakeLib/testRST.expect b/Tests/CMakeLib/testRST.expect
index d7b91d1..c19ee94 100644
--- a/Tests/CMakeLib/testRST.expect
+++ b/Tests/CMakeLib/testRST.expect
@@ -83,6 +83,10 @@
 but not after a line ending in two colons::
 in the middle of a paragraph.
 
+A literal block can be empty::
+
+
+
 .. productionlist::
  grammar: `production`
  production: "content rendered"
diff --git a/Tests/CMakeLib/testRST.rst b/Tests/CMakeLib/testRST.rst
index 633219f..d2d1140 100644
--- a/Tests/CMakeLib/testRST.rst
+++ b/Tests/CMakeLib/testRST.rst
@@ -90,6 +90,10 @@
 but not after a line ending in two colons::
 in the middle of a paragraph.
 
+A literal block can be empty::
+
+
+
 .. productionlist::
  grammar: `production`
  production: "content rendered"
diff --git a/Tests/CMakeLib/testRange.cxx b/Tests/CMakeLib/testRange.cxx
new file mode 100644
index 0000000..b26b07b
--- /dev/null
+++ b/Tests/CMakeLib/testRange.cxx
@@ -0,0 +1,45 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmRange.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#define ASSERT_TRUE(x)                                                        \
+  do {                                                                        \
+    if (!(x)) {                                                               \
+      std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+      return -1;                                                              \
+    }                                                                         \
+  } while (false)
+
+int testRange(int /*unused*/, char* /*unused*/ [])
+{
+  std::vector<int> const testData = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+  ASSERT_TRUE(!cmMakeRange(testData).empty());
+  ASSERT_TRUE(cmMakeRange(testData).size() == 10);
+
+  ASSERT_TRUE(!cmMakeRange(testData).advance(5).empty());
+  ASSERT_TRUE(cmMakeRange(testData).advance(5).size() == 5);
+
+  ASSERT_TRUE(cmMakeRange(testData).advance(5).retreat(5).empty());
+  ASSERT_TRUE(cmMakeRange(testData).advance(5).retreat(5).size() == 0);
+
+  ASSERT_TRUE(cmMakeRange(testData).any_of([](int n) { return n % 3 == 0; }));
+  ASSERT_TRUE(cmMakeRange(testData).all_of([](int n) { return n < 11; }));
+  ASSERT_TRUE(cmMakeRange(testData).none_of([](int n) { return n > 11; }));
+
+  std::vector<int> const evenData = { 2, 4, 6, 8, 10 };
+  ASSERT_TRUE(cmMakeRange(testData).filter([](int n) { return n % 2 == 0; }) ==
+              cmMakeRange(evenData));
+
+  std::vector<std::string> const stringRange = { "1", "2", "3", "4", "5" };
+  ASSERT_TRUE(cmMakeRange(testData)
+                .transform([](int n) { return std::to_string(n); })
+                .retreat(5) == cmMakeRange(stringRange));
+
+  return 0;
+}
diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx
index 96a4819..121e639 100644
--- a/Tests/CMakeLib/testSystemTools.cxx
+++ b/Tests/CMakeLib/testSystemTools.cxx
@@ -93,5 +93,22 @@
   if (!failed) {
     cmPassed("cmSystemTools::strverscmp working");
   }
+
+  // ----------------------------------------------------------------------
+  // Test cmSystemTools::StringToULong
+  {
+    unsigned long value;
+    cmAssert(cmSystemTools::StringToULong("1", &value) && value == 1,
+             "StringToULong parses a decimal integer.");
+    cmAssert(cmSystemTools::StringToULong(" 1", &value) && value == 1,
+             "StringToULong parses a decimal integer after whitespace.");
+    cmAssert(!cmSystemTools::StringToULong("-1", &value),
+             "StringToULong rejects a negative number.");
+    cmAssert(!cmSystemTools::StringToULong(" -1", &value),
+             "StringToULong rejects a negative number after whitespace.");
+    cmAssert(!cmSystemTools::StringToULong("1x", &value),
+             "StringToULong rejects trailing content.");
+  }
+
   return failed;
 }
diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx
index c99c46d..a0bb5cd 100644
--- a/Tests/CMakeLib/testUTF8.cxx
+++ b/Tests/CMakeLib/testUTF8.cxx
@@ -13,6 +13,21 @@
          static_cast<int>(d[3]));
 }
 
+static void byte_array_print(char const* s)
+{
+  unsigned char const* d = reinterpret_cast<unsigned char const*>(s);
+  bool started = false;
+  printf("[");
+  for (; *d; ++d) {
+    if (started) {
+      printf(",");
+    }
+    started = true;
+    printf("0x%02X", static_cast<int>(*d));
+  }
+  printf("]");
+}
+
 struct test_utf8_entry
 {
   int n;
@@ -21,17 +36,36 @@
 };
 
 static test_utf8_entry const good_entry[] = {
-  { 1, "\x20\x00\x00\x00", 0x0020 },  /* Space.  */
-  { 2, "\xC2\xA9\x00\x00", 0x00A9 },  /* Copyright.  */
-  { 3, "\xE2\x80\x98\x00", 0x2018 },  /* Open-single-quote.  */
-  { 3, "\xE2\x80\x99\x00", 0x2019 },  /* Close-single-quote.  */
-  { 4, "\xF0\xA3\x8E\xB4", 0x233B4 }, /* Example from RFC 3629.  */
+  { 1, "\x20\x00\x00\x00", 0x0020 },   /* Space.  */
+  { 2, "\xC2\xA9\x00\x00", 0x00A9 },   /* Copyright.  */
+  { 3, "\xE2\x80\x98\x00", 0x2018 },   /* Open-single-quote.  */
+  { 3, "\xE2\x80\x99\x00", 0x2019 },   /* Close-single-quote.  */
+  { 4, "\xF0\xA3\x8E\xB4", 0x233B4 },  /* Example from RFC 3629.  */
+  { 3, "\xED\x80\x80\x00", 0xD000 },   /* Valid 0xED prefixed codepoint.  */
+  { 4, "\xF4\x8F\xBF\xBF", 0x10FFFF }, /* Highest valid RFC codepoint. */
   { 0, { 0, 0, 0, 0, 0 }, 0 }
 };
 
 static test_utf8_char const bad_chars[] = {
-  "\x80\x00\x00\x00", "\xC0\x00\x00\x00", "\xE0\x00\x00\x00",
-  "\xE0\x80\x80\x00", "\xF0\x80\x80\x80", { 0, 0, 0, 0, 0 }
+  "\x80\x00\x00\x00", /* Leading continuation byte. */
+  "\xC0\x80\x00\x00", /* Overlong encoding. */
+  "\xC1\x80\x00\x00", /* Overlong encoding. */
+  "\xC2\x00\x00\x00", /* Missing continuation byte. */
+  "\xE0\x00\x00\x00", /* Missing continuation bytes. */
+  "\xE0\x80\x80\x00", /* Overlong encoding. */
+  "\xF0\x80\x80\x80", /* Overlong encoding. */
+  "\xED\xA0\x80\x00", /* UTF-16 surrogate half. */
+  "\xED\xBF\xBF\x00", /* UTF-16 surrogate half. */
+  "\xF4\x90\x80\x80", /* Lowest out-of-range codepoint. */
+  "\xF5\x80\x80\x80", /* Prefix forces out-of-range codepoints. */
+  { 0, 0, 0, 0, 0 }
+};
+
+static char const* good_strings[] = { "", "ASCII", "\xC2\xA9 Kitware", 0 };
+
+static char const* bad_strings[] = {
+  "\xC0\x80", /* Modified UTF-8 for embedded 0-byte. */
+  0
 };
 
 static void report_good(bool passed, test_utf8_char const c)
@@ -87,6 +121,46 @@
   return true;
 }
 
+static void report_valid(bool passed, char const* s)
+{
+  printf("%s: validity good ", passed ? "pass" : "FAIL");
+  byte_array_print(s);
+  printf(" (%s) ", s);
+}
+
+static void report_invalid(bool passed, char const* s)
+{
+  printf("%s: validity bad  ", passed ? "pass" : "FAIL");
+  byte_array_print(s);
+  printf(" ");
+}
+
+static bool is_valid(const char* s)
+{
+  bool valid = cm_utf8_is_valid(s) != 0;
+  if (!valid) {
+    report_valid(false, s);
+    printf("expected valid, reported as invalid\n");
+    return false;
+  }
+  report_valid(true, s);
+  printf("valid as expected\n");
+  return true;
+}
+
+static bool is_invalid(const char* s)
+{
+  bool valid = cm_utf8_is_valid(s) != 0;
+  if (valid) {
+    report_invalid(false, s);
+    printf("expected invalid, reported as valid\n");
+    return false;
+  }
+  report_invalid(true, s);
+  printf("invalid as expected\n");
+  return true;
+}
+
 int testUTF8(int /*unused*/, char* /*unused*/ [])
 {
   int result = 0;
@@ -94,11 +168,27 @@
     if (!decode_good(*e)) {
       result = 1;
     }
+    if (!is_valid(e->str)) {
+      result = 1;
+    }
   }
   for (test_utf8_char const* c = bad_chars; (*c)[0]; ++c) {
     if (!decode_bad(*c)) {
       result = 1;
     }
+    if (!is_invalid(*c)) {
+      result = 1;
+    }
+  }
+  for (char const** s = good_strings; *s; ++s) {
+    if (!is_valid(*s)) {
+      result = 1;
+    }
+  }
+  for (char const** s = bad_strings; *s; ++s) {
+    if (!is_invalid(*s)) {
+      result = 1;
+    }
   }
   return result;
 }
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 431a492..2e0902c 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -459,7 +459,7 @@
     set(runCxxDialectTest 1)
   endif()
   if(CMAKE_CXX_COMPILER_ID STREQUAL Clang
-        AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
+        AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4 AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
     if(NOT APPLE OR POLICY CMP0025)
       set(runCxxDialectTest 1)
     endif()
@@ -1413,10 +1413,18 @@
     add_subdirectory(FindCURL)
   endif()
 
+  if(CMake_TEST_FindCups)
+    add_subdirectory(FindCups)
+  endif()
+
   if(CMake_TEST_FindDoxygen)
     add_subdirectory(FindDoxygen)
   endif()
 
+  if(CMake_TEST_FindEnvModules)
+    add_subdirectory(FindEnvModules)
+  endif()
+
   if(CMake_TEST_FindEXPAT)
     add_subdirectory(FindEXPAT)
   endif()
@@ -1441,6 +1449,10 @@
     add_subdirectory(FindGit)
   endif()
 
+  if(CMake_TEST_FindGLEW)
+    add_subdirectory(FindGLEW)
+  endif()
+
   if(CMake_TEST_FindGSL)
     add_subdirectory(FindGSL)
   endif()
@@ -1450,6 +1462,10 @@
     add_subdirectory(GoogleTest)
   endif()
 
+  if(CMake_TEST_FindGTK2)
+    add_subdirectory(FindGTK2)
+  endif()
+
   if(CMake_TEST_FindIconv)
     add_subdirectory(FindIconv)
   endif()
@@ -1593,11 +1609,6 @@
     ADD_TEST_MACRO(FindMatlab.r2018a_check   ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
   endif()
 
-  find_package(GTK2 QUIET)
-  if(GTK2_FOUND)
-    add_subdirectory(FindGTK2)
-  endif()
-
   add_test(ExternalProject ${CMAKE_CTEST_COMMAND}
     --build-and-test
     "${CMake_SOURCE_DIR}/Tests/ExternalProject"
@@ -2313,6 +2324,7 @@
         --build-generator "Green Hills MULTI"
         --build-project test
         --build-config $<CONFIGURATION>
+        --force-new-ctest-process
         --build-options ${ghs_target_arch} ${ghs_toolset_name} ${ghs_toolset_root} ${ghs_target_platform}
           ${ghs_os_root} ${ghs_os_dir} ${ghs_bsp_name} ${_ghs_build_opts} ${_ghs_toolset_extra}
           ${_ghs_test_command}
@@ -2324,7 +2336,7 @@
     endmacro()
     macro(add_test_GhsMulti_rename_install test_name)
       add_test_GhsMulti( ${test_name} GhsMultiRenameInstall ${test_name}
-        "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} -P ./cmake_install.cmake)
+        "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} --build . --target install)
     endmacro()
     #unset ghs config variables
     unset(ghs_config_name)
@@ -2379,6 +2391,9 @@
       add_test_GhsMulti(compiler_options_kernel GhsMultiCompilerOptions Kernel "-DRUN_TEST=KERNEL_FLAGS -DRUN_TEST_BUILD_TYPE=DEBUG")
       add_test_GhsMulti(try_compile_copy GhsMultiCopyFile "" "")
       add_test_GhsMulti(ghs_platform GhsMultiPlatform "" "")
+      add_test_GhsMulti(custom_target GhsMultiCustomTarget "" "")
+      add_test_GhsMulti(dep_order GhsMultiDepOrder "" "")
+      add_test_GhsMulti(external_project GhsMultiExternalProject "" "")
       list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}")
       #unset ghs config variables
       unset(ghs_config_name)
@@ -3264,12 +3279,14 @@
       --output-log "${CMake_BINARY_DIR}/Tests/CTestTest/testOutput.log"
       )
 
-    configure_file("${CMake_SOURCE_DIR}/Tests/CTestTest2/test.cmake.in"
-      "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" @ONLY ESCAPE_QUOTES)
-    add_test(CTestTest2 ${CMAKE_CTEST_COMMAND}
-      -S "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" -V
-      --output-log "${CMake_BINARY_DIR}/Tests/CTestTest2/testOutput.log"
-      )
+    if(NOT CMake_TEST_EXTERNAL_CMAKE)
+      configure_file("${CMake_SOURCE_DIR}/Tests/CTestTest2/test.cmake.in"
+        "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" @ONLY ESCAPE_QUOTES)
+      add_test(CTestTest2 ${CMAKE_CTEST_COMMAND}
+        -S "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" -V
+        --output-log "${CMake_BINARY_DIR}/Tests/CTestTest2/testOutput.log"
+        )
+    endif()
 
     if("${CMAKE_GENERATOR}" MATCHES "Makefiles" OR "${CMAKE_GENERATOR}" MATCHES "Ninja")
       configure_file("${CMake_SOURCE_DIR}/Tests/CTestTestLaunchers/test.cmake.in"
@@ -3301,11 +3318,13 @@
         PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
     endif ()
 
-    get_test_property(CTestTest2 TIMEOUT PREVIOUS_TIMEOUT)
-    if ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
-      set_tests_properties ( CTestTest2
-        PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
-    endif ()
+    if(NOT CMake_TEST_EXTERNAL_CMAKE)
+      get_test_property(CTestTest2 TIMEOUT PREVIOUS_TIMEOUT)
+      if("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
+        set_tests_properties ( CTestTest2
+          PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+      endif()
+    endif()
   endif ()
 
   if(CMake_TEST_EXTERNAL_CMAKE)
@@ -3369,6 +3388,7 @@
         --build-options ${build_options}
           -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
           -DCMake_TEST_Fortran_SUBMODULES:BOOL=${CMake_TEST_Fortran_SUBMODULES}
+          ${CMake_TEST_FortranModules_BUILD_OPTIONS}
         )
       list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/FortranModules")
     endif()
diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt
index f40524f..1aeab8b 100644
--- a/Tests/CMakeOnly/CMakeLists.txt
+++ b/Tests/CMakeOnly/CMakeLists.txt
@@ -56,6 +56,18 @@
   -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
   )
 
+add_test(CMakeOnly.ProjectIncludeAny ${CMAKE_CMAKE_COMMAND}
+  -DTEST=ProjectIncludeAny
+  -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectInclude/include.cmake
+  -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+  )
+
+add_test(CMakeOnly.ProjectIncludeBefore ${CMAKE_CMAKE_COMMAND}
+  -DTEST=ProjectIncludeBefore
+  -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE_BEFORE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectIncludeBefore/include.cmake
+  -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+  )
+
 include(CMakeParseArguments)
 
 function(add_major_test module)
diff --git a/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
index 9be69f1..1f9d3ac 100644
--- a/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
@@ -57,7 +57,7 @@
   message("Unhandled Platform")
 endif()
 
-if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
   check_cxx_compiler_flag("-x c++" HAVE_X_CXX)
   if(NOT HAVE_X_CXX)
     message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} compiler flag '-x c++' check failed")
diff --git a/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt b/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
index a9abb4a..ffce488 100644
--- a/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
+++ b/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
@@ -1,4 +1,4 @@
-project(ProjectInclude)
+project(ProjectInclude LANGUAGES NONE)
 if(NOT AUTO_INCLUDE)
   message(FATAL_ERROR "include file not found")
 endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt
new file mode 100644
index 0000000..ffce488
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+  message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt
new file mode 100644
index 0000000..5cd9cba
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(FOO TRUE)
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+  message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake b/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake
new file mode 100644
index 0000000..0a4799d
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake
@@ -0,0 +1,9 @@
+if(NOT FOO)
+  message(FATAL_ERROR "FOO is not set")
+endif()
+
+if(NOT "${PROJECT_NAME}" STREQUAL "")
+  message(FATAL_ERROR "PROJECT_NAME should be empty")
+endif()
+
+set(AUTO_INCLUDE TRUE)
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
index b0bc656..2dd8917 100644
--- a/Tests/CompileFeatures/CMakeLists.txt
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -15,17 +15,21 @@
   endif()
 endmacro()
 
-get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
-list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
-foreach(feature ${c_features})
-  run_test(${feature} C)
-endforeach()
+if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+  get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
+  list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+  foreach(feature ${c_features})
+    run_test(${feature} C)
+  endforeach()
+endif()
 
-get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
-list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
-foreach(feature ${cxx_features})
-  run_test(${feature} CXX)
-endforeach()
+if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+  get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
+  list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+  foreach(feature ${cxx_features})
+    run_test(${feature} CXX)
+  endforeach()
+endif()
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
     AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
@@ -338,11 +342,11 @@
 
   add_executable(CompileFeaturesGenex2 genex_test.cpp)
   target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_std_11)
-  target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs})
+  target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
 
   add_library(std_11_iface INTERFACE)
   target_compile_features(std_11_iface INTERFACE cxx_std_11)
   add_executable(CompileFeaturesGenex3 genex_test.cpp)
   target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
-  target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs})
+  target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
 endif()
diff --git a/Tests/CompileFeatures/genex_test.cpp b/Tests/CompileFeatures/genex_test.cpp
index 59f9006..53dce62 100644
--- a/Tests/CompileFeatures/genex_test.cpp
+++ b/Tests/CompileFeatures/genex_test.cpp
@@ -15,10 +15,10 @@
 #  if !HAVE_CXX_STD_11
 #    error HAVE_CXX_STD_11 is false with CXX_STANDARD == 11
 #  endif
-#  if HAVE_CXX_STD_14
+#  if HAVE_CXX_STD_14 && !defined(ALLOW_LATER_STANDARDS)
 #    error HAVE_CXX_STD_14 is true with CXX_STANDARD == 11
 #  endif
-#  if HAVE_CXX_STD_17
+#  if HAVE_CXX_STD_17 && !defined(ALLOW_LATER_STANDARDS)
 #    error HAVE_CXX_STD_17 is true with CXX_STANDARD == 11
 #  endif
 #endif
@@ -31,17 +31,6 @@
 #  if !EXPECT_OVERRIDE_CONTROL
 #    error "Expect no override control feature"
 #  endif
-
-struct A
-{
-  virtual int getA() { return 7; }
-};
-
-struct B final : A
-{
-  int getA() override { return 42; }
-};
-
 #endif
 
 #if !HAVE_AUTO_TYPE
diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt
index e58204d..00fd7d2 100644
--- a/Tests/CudaOnly/WithDefs/CMakeLists.txt
+++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt
@@ -37,6 +37,8 @@
     $<$<CONFIG:RELEASE>:$<BUILD_INTERFACE:${release_compile_defs}>>
     -DDEF_COMPILE_LANG_$<COMPILE_LANGUAGE>
     -DDEF_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
+    -DDEF_CUDA_COMPILER=$<CUDA_COMPILER_ID>
+    -DDEF_CUDA_COMPILER_VERSION=$<CUDA_COMPILER_VERSION>
   )
 
 target_include_directories(CudaOnlyWithDefs
diff --git a/Tests/CudaOnly/WithDefs/main.notcu b/Tests/CudaOnly/WithDefs/main.notcu
index 98f73ce..68a296b 100644
--- a/Tests/CudaOnly/WithDefs/main.notcu
+++ b/Tests/CudaOnly/WithDefs/main.notcu
@@ -39,6 +39,14 @@
 #  error "Expected DEF_LANG_IS_CUDA"
 #endif
 
+#ifndef DEF_CUDA_COMPILER
+#  error "DEF_CUDA_COMPILER not defined!"
+#endif
+
+#ifndef DEF_CUDA_COMPILER_VERSION
+#  error "DEF_CUDA_COMPILER_VERSION not defined!"
+#endif
+
 static __global__ void DetermineIfValidCudaDevice()
 {
 }
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 811fff3..b5df961 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -407,7 +407,7 @@
 unset(_configs)
 
 if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
-    OR CMAKE_C_COMPILER_ID STREQUAL Clang)
+    OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))
     AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL "Ninja"))
   include(CheckCXXCompilerFlag)
   check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
diff --git a/Tests/FindBoost/CMakeLists.txt b/Tests/FindBoost/CMakeLists.txt
index 17a8ec7..58d795b 100644
--- a/Tests/FindBoost/CMakeLists.txt
+++ b/Tests/FindBoost/CMakeLists.txt
@@ -33,3 +33,16 @@
   --build-options ${build_options}
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
+
+if (CMake_TEST_FindBoost_Python)
+  add_test(NAME FindBoost.TestPython COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindBoost/TestPython"
+    "${CMake_BINARY_DIR}/Tests/FindBoost/TestPython"
+    ${build_generator_args}
+    --build-project TestFindBoostPython
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endif ()
diff --git a/Tests/FindBoost/TestPython/CMakeLists.txt b/Tests/FindBoost/TestPython/CMakeLists.txt
new file mode 100644
index 0000000..4d137ca
--- /dev/null
+++ b/Tests/FindBoost/TestPython/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.14)
+project(TestFindBoostPython CXX)
+include(CTest)
+
+find_package(Boost OPTIONAL_COMPONENTS python27 python34 python35 python36 python37)
+
+set(FAILTEST TRUE)
+foreach (v IN ITEMS 27 34 35 36 37)
+  if (Boost_PYTHON${v}_FOUND)
+    set(FAILTEST FALSE)
+    break()
+  endif ()
+endforeach ()
+
+if (FAILTEST)
+  message(FATAL_ERROR "No Boost Python module found")
+endif ()
diff --git a/Tests/FindCups/CMakeLists.txt b/Tests/FindCups/CMakeLists.txt
new file mode 100644
index 0000000..5be1ac1
--- /dev/null
+++ b/Tests/FindCups/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindCups.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindCups/Test"
+  "${CMake_BINARY_DIR}/Tests/FindCups/Test"
+  ${build_generator_args}
+  --build-project FindCups
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindCups/Test/CMakeLists.txt b/Tests/FindCups/Test/CMakeLists.txt
new file mode 100644
index 0000000..9e90553
--- /dev/null
+++ b/Tests/FindCups/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindCups C)
+include(CTest)
+
+find_package(Cups REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_CUPS_VERSION="${CUPS_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt Cups::Cups)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${CUPS_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${CUPS_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindCups/Test/main.c b/Tests/FindCups/Test/main.c
new file mode 100644
index 0000000..b69d621
--- /dev/null
+++ b/Tests/FindCups/Test/main.c
@@ -0,0 +1,12 @@
+#include <cups/cups.h>
+
+int main()
+{
+  int num_options = 0;
+  cups_option_t* options = NULL;
+
+  num_options = cupsAddOption(CUPS_COPIES, "1", num_options, &options);
+  cupsFreeOptions(num_options, options);
+
+  return 0;
+}
diff --git a/Tests/FindEnvModules/CMakeLists.txt b/Tests/FindEnvModules/CMakeLists.txt
new file mode 100644
index 0000000..95b7d1d
--- /dev/null
+++ b/Tests/FindEnvModules/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_test(FindEnvModules.Test ${CMAKE_CMAKE_COMMAND}
+  -P ${CMAKE_CURRENT_LIST_DIR}/EnvModules.cmake
+)
diff --git a/Tests/FindEnvModules/EnvModules.cmake b/Tests/FindEnvModules/EnvModules.cmake
new file mode 100644
index 0000000..0c81bf2
--- /dev/null
+++ b/Tests/FindEnvModules/EnvModules.cmake
@@ -0,0 +1,35 @@
+find_package(EnvModules REQUIRED)
+message("module purge")
+env_module(COMMAND purge RESULT_VARIABLE ret_var)
+if(NOT ret_var EQUAL 0)
+  message(FATAL_ERROR "module(purge) returned ${ret_var}")
+endif()
+
+message("module avail")
+env_module_avail(avail_mods)
+foreach(mod IN LISTS avail_mods)
+  message("  ${mod}")
+endforeach()
+
+if(avail_mods)
+  list(GET avail_mods 0 mod0)
+  message("module load ${mod0}")
+  env_module(load ${mod0})
+
+  message("module list")
+  env_module_list(loaded_mods)
+  foreach(mod IN LISTS loaded_mods)
+    message("  ${mod}")
+  endforeach()
+
+  list(LENGTH loaded_mods num_loaded_mods)
+  message("Number of modules loaded: ${num_loaded_mods}")
+  if(NOT num_loaded_mods EQUAL 1)
+    message(FATAL_ERROR "Exactly 1 module should be loaded.  Found ${num_loaded_mods}")
+  endif()
+
+  list(GET loaded_mods 0 mod0_actual)
+  if(NOT (mod0_actual MATCHES "^${mod0}"))
+    message(FATAL_ERROR "Loaded module does not match ${mod0}.  Actual: ${mod0_actual}")
+  endif()
+endif()
diff --git a/Tests/FindGLEW/CMakeLists.txt b/Tests/FindGLEW/CMakeLists.txt
new file mode 100644
index 0000000..ff42bce
--- /dev/null
+++ b/Tests/FindGLEW/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGLEW.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindGLEW/Test"
+  "${CMake_BINARY_DIR}/Tests/FindGLEW/Test"
+  ${build_generator_args}
+  --build-project TestFindGLEW
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindGLEW/Test/CMakeLists.txt b/Tests/FindGLEW/Test/CMakeLists.txt
new file mode 100644
index 0000000..954ee10
--- /dev/null
+++ b/Tests/FindGLEW/Test/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindGLEW LANGUAGES CXX)
+include(CTest)
+
+find_package(GLEW REQUIRED)
+
+add_executable(test_glew_shared_tgt main.cpp)
+target_link_libraries(test_glew_shared_tgt GLEW::GLEW)
+add_test(NAME test_glew_shared_tgt COMMAND test_glew_shared_tgt)
+
+add_executable(test_glew_generic_tgt main.cpp)
+target_link_libraries(test_glew_generic_tgt GLEW::glew)
+add_test(NAME test_glew_generic_tgt COMMAND test_glew_generic_tgt)
+
+add_executable(test_glew_var main.cpp)
+target_include_directories(test_glew_var PRIVATE ${GLEW_INCLUDE_DIRS})
+target_link_libraries(test_glew_var PRIVATE ${GLEW_LIBRARIES})
+add_test(NAME test_glew_var COMMAND test_glew_var)
diff --git a/Tests/FindGLEW/Test/main.cpp b/Tests/FindGLEW/Test/main.cpp
new file mode 100644
index 0000000..4a108ad
--- /dev/null
+++ b/Tests/FindGLEW/Test/main.cpp
@@ -0,0 +1,8 @@
+#include <GL/glew.h>
+
+int main()
+{
+  GLenum init_return = glewInit();
+
+  return (init_return == GLEW_OK);
+}
diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt
index f8b36c5..972580c 100644
--- a/Tests/FindPackageTest/CMakeLists.txt
+++ b/Tests/FindPackageTest/CMakeLists.txt
@@ -380,6 +380,7 @@
   ${FindPackageTest_SOURCE_DIR}/Exporter
   CMakeTestExportPackage dummy
   CMAKE_FLAGS "-UCMAKE_EXPORT_NO_PACKAGE_REGISTRY"
+    "-DCMAKE_POLICY_DEFAULT_CMP0090:STRING=OLD"
     -Dversion=${version}
   OUTPUT_VARIABLE output)
 message(STATUS "Searching for export(PACKAGE) test project")
@@ -417,6 +418,25 @@
   message(SEND_ERROR "CMakeTestExportPackage should not be FOUND!")
 endif()
 
+message(STATUS "Remove export(PACKAGE) test project")
+file(REMOVE_RECURSE ${FindPackageTest_BINARY_DIR}/Exporter-build)
+
+message(STATUS "Preparing export(PACKAGE) test project with POLICY CMP0090=NEW")
+try_compile(EXPORTER_COMPILED
+  ${FindPackageTest_BINARY_DIR}/Exporter-build
+  ${FindPackageTest_SOURCE_DIR}/Exporter
+  CMakeTestExportPackage dummy
+  CMAKE_FLAGS
+   "-DCMAKE_POLICY_DEFAULT_CMP0090:STRING=NEW"
+    -Dversion=${version}
+  OUTPUT_VARIABLE output)
+message(STATUS "Searching for export(PACKAGE) test project")
+find_package(CMakeTestExportPackage 1.${version} EXACT QUIET)
+if(CMakeTestExportPackage_FOUND)
+  message(SEND_ERROR "CMakeTestExportPackage should not be FOUND!")
+endif()
+
+
 #-----------------------------------------------------------------------------
 # Test configure_package_config_file().
 
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index 38211a4..d6f50e7 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -68,6 +68,17 @@
     --build-options ${build_options}
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
+
+  add_test(NAME FindPython.VirtualEnv COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/VirtualEnv"
+    "${CMake_BINARY_DIR}/Tests/FindPython/VirtualEnv"
+    ${build_generator_args}
+    --build-project TestVirtualEnv
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
 endif()
 
 if(CMake_TEST_FindPython_NumPy)
diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt
new file mode 100644
index 0000000..64ba201
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestVirtualEnv LANGUAGES NONE)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+if (NOT Python3_FOUND)
+  message (FATAL_ERROR "Fail to found Python 3")
+endif()
+
+set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
+
+execute_process (COMMAND "${Python3_EXECUTABLE}" -m venv "${Python3_VIRTUAL_ENV}"
+                 RESULT_VARIABLE result
+                 OUTPUT_VARIABLE outputs
+                 ERROR_VARIABLE outputs)
+if (result)
+  message (FATAL_ERROR "Fail to create virtual environment: ${outputs}")
+endif()
+
+add_test(NAME FindPython3.VirtualEnvDefault
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
+
+add_test(NAME FindPython3.VirtualEnvOnly
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+add_test(NAME FindPython3.UnsetVirtualEnvOnly
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=VIRTUAL_ENV
+                 "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+
+add_test(NAME FindPython3.VirtualEnvStandard
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
new file mode 100644
index 0000000..020ecac
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
@@ -0,0 +1,6 @@
+
+find_package (Python3 REQUIRED)
+
+if (NOT Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+  message (FATAL_ERROR "Fail to use virtual environment")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
new file mode 100644
index 0000000..29a4924
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
@@ -0,0 +1,16 @@
+
+#
+# Virtual environment is defined for python3
+# Trying to find a python2 using only virtual environment
+# It is expecting to fail if a virtual environment is active and to success otherwise.
+#
+set (Python2_FIND_VIRTUALENV ONLY)
+find_package (Python2 QUIET)
+
+if (PYTHON3_VIRTUAL_ENV AND Python2_FOUND)
+  message (FATAL_ERROR "Python2 unexpectedly found.")
+endif()
+
+if (NOT PYTHON3_VIRTUAL_ENV AND NOT Python2_FOUND)
+  message (FATAL_ERROR "Fail to find Python2.")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
new file mode 100644
index 0000000..89f27d8
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
@@ -0,0 +1,7 @@
+
+set (Python3_FIND_VIRTUALENV STANDARD)
+find_package (Python3 REQUIRED)
+
+if (Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+  message (FATAL_ERROR "Python3 virtual env unexpectedly found.")
+endif()
diff --git a/Tests/Fortran/CMakeLists.txt b/Tests/Fortran/CMakeLists.txt
index 7023615..929fa4d 100644
--- a/Tests/Fortran/CMakeLists.txt
+++ b/Tests/Fortran/CMakeLists.txt
@@ -46,7 +46,7 @@
   FortranCInterface_VERIFY()
   FortranCInterface_VERIFY(CXX)
   if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
-    if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|MIPSpro|PathScale|Absoft")
+    if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|PathScale|Absoft")
       set(module_expected 1)
     endif()
     if(FortranCInterface_MODULE_FOUND OR module_expected)
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index 3d08704..df0c78d 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -3,11 +3,26 @@
 
 include(CTest)
 
+# Real projects normally want the MSYS shell path conversion, but for this test
+# we need to verify that the command line is constructed with the proper string.
+set(msys1_prefix "")
+set(msys2_no_conv "")
+if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
+  execute_process(COMMAND "uname" OUTPUT_VARIABLE uname)
+  if("${uname}" MATCHES "^MINGW32")
+    # MinGW.org MSYS 1.0 does not support generic path conversion suppression
+    set(msys1_prefix MSYS1_PREFIX)
+  else()
+    # msys2 supports generic path conversion suppression
+    set(msys2_no_conv env MSYS2_ARG_CONV_EXCL=-D)
+  endif()
+endif()
+
 # This test is split into multiple parts as needed to avoid NMake command
 # length limits.
 
 add_custom_target(check-part1 ALL
-  COMMAND ${CMAKE_COMMAND}
+  COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
     -Dtest_0=$<0:nothing>
     -Dtest_0_with_comma=$<0:-Wl,--no-undefined>
     -Dtest_1=$<1:content>
@@ -97,7 +112,7 @@
 target_include_directories(empty5 PRIVATE /empty5/private1 /empty5/private2)
 
 add_custom_target(check-part2 ALL
-  COMMAND ${CMAKE_COMMAND}
+  COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
     -Dtest_incomplete_1=$<
     -Dtest_incomplete_2=$<something
     -Dtest_incomplete_3=$<something:
@@ -188,7 +203,7 @@
 set_property(TARGET importedFallback PROPERTY MAP_IMPORTED_CONFIG_RELEASE "")
 
 add_custom_target(check-part3 ALL
-  COMMAND ${CMAKE_COMMAND}
+  COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
     -Dtest_version_greater_1=$<VERSION_GREATER:1.0,1.1.1>
     -Dtest_version_greater_2=$<VERSION_GREATER:1.1.1,1.0>
     -Dtest_version_less_1=$<VERSION_LESS:1.1.1,1.0>
@@ -241,17 +256,19 @@
 
 if(WIN32)
   set(test_shell_path c:/shell/path)
+  set(test_shell_path2 c:/shell/path d:/another/path)
 else()
   set(test_shell_path /shell/path)
+  set(test_shell_path2 /shell/path /another/path)
 endif()
-set(path_prefix BYPASS_FURTHER_CONVERSION)
 
 add_custom_target(check-part4 ALL
-  COMMAND ${CMAKE_COMMAND}
+  COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
     # Prefix path to bypass its further conversion when being processed by
     # CMake as command-line argument
-    -Dtest_shell_path=${path_prefix}$<SHELL_PATH:${test_shell_path}>
-    -Dpath_prefix=${path_prefix}
+    -Dmsys1_prefix=${msys1_prefix}
+    -Dtest_shell_path=${msys1_prefix}$<SHELL_PATH:${test_shell_path}>
+    "-Dtest_shell_path2=$<SHELL_PATH:${test_shell_path2}>"
     -Dif_1=$<IF:1,a,b>
     -Dif_2=$<IF:0,a,b>
     -Dif_3=$<IF:$<EQUAL:10,30>,a,b>
diff --git a/Tests/GeneratorExpression/check-part4.cmake b/Tests/GeneratorExpression/check-part4.cmake
index f5d14dd..a7e0944 100644
--- a/Tests/GeneratorExpression/check-part4.cmake
+++ b/Tests/GeneratorExpression/check-part4.cmake
@@ -1,6 +1,8 @@
 include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
 
-string(REPLACE ${path_prefix} "" test_shell_path ${test_shell_path})
+if(msys1_prefix)
+  string(REPLACE "${msys1_prefix}" "" test_shell_path ${test_shell_path})
+endif()
 
 if(WIN32)
   if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
@@ -13,6 +15,17 @@
 else()
   check(test_shell_path [[/shell/path]])
 endif()
+if(WIN32)
+  if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles" AND NOT msys1_prefix)
+    check(test_shell_path2 [[/c/shell/path:/d/another/path]])
+  elseif(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+    check(test_shell_path2 [[c:/shell/path;d:/another/path]])
+  else()
+    check(test_shell_path2 [[c:\shell\path;d:\another\path]])
+  endif()
+else()
+  check(test_shell_path2 [[/shell/path:/another/path]])
+endif()
 
 check(if_1 "a")
 check(if_2 "b")
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
new file mode 100644
index 0000000..93d668b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
@@ -0,0 +1,110 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+# Tests assume no previous builds in the build directory
+file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/build)
+
+macro (test_output)
+  if (BUILD_OUTPUT STREQUAL EXPECTED_LINES )
+    message("Build OK")
+  else()
+    message("BUILD_OUTPUT")
+    foreach(Line IN LISTS BUILD_OUTPUT)
+      message("${Line}")
+    endforeach()
+    message("EXPECTED_LINES")
+    foreach(Line IN LISTS EXPECTED_LINES)
+      message("${Line}")
+    endforeach()
+    message(SEND_ERROR "Build KO")
+  endif()
+endmacro()
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+  ${CMAKE_CURRENT_BINARY_DIR}/src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/exe1.c
+          ${CMAKE_CURRENT_SOURCE_DIR}/lib1.c
+  DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src
+)
+
+message("Building ALL target")
+try_compile(RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/build
+  ${CMAKE_CURRENT_BINARY_DIR}/src
+  test
+  CMAKE_FLAGS
+    -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+  OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_postbuild")
+
+test_output()
+
+message("Building target_update_files target")
+try_compile(RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/build
+  ${CMAKE_CURRENT_BINARY_DIR}/src
+  test target_update_files
+  CMAKE_FLAGS
+    -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+  OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate C file another_file")
+list(APPEND EXPECTED_LINES "CT: generate text file dependsA")
+list(APPEND EXPECTED_LINES "CT: generate text file out_of_order_dep")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
+
+message("Rerun target_update_files target")
+try_compile(RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/build
+  ${CMAKE_CURRENT_BINARY_DIR}/src
+  test target_update_files
+  CMAKE_FLAGS
+    -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+  OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
new file mode 100644
index 0000000..fed946c
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
@@ -0,0 +1,108 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+
+set(TEST_MISSING_TARGET_SRC 0)
+set(TEST_MISSING_TARGET_DEP 0)
+set(TEST_MISSING_DEP 0)
+set(TEST_DEP_CYCLE 0)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+add_custom_target(target_cmd ALL
+  COMMAND ${CMAKE_COMMAND} -E echo "target_cmd" > target_cmd
+  COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_extra" > target_cmd_extra.txt
+  BYPRODUCTS target_cmd target_cmd_extra.txt
+  COMMENT "CT: Processing target_cmd")
+
+add_custom_command(TARGET target_cmd PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prebuild" > target_cmd_prebuild.txt
+  BYPRODUCTS target_cmd_prebuild.txt
+  COMMENT "CT: Processing target_cmd_prebuild")
+#event does not run for custom targets
+add_custom_command(TARGET target_cmd PRE_LINK
+  COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_prelink commands"
+  COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prelink" > target_cmd_prelink.txt
+  BYPRODUCTS target_cmd_prelink.txt
+  COMMENT "CT: Processing target_cmd_prelink")
+add_custom_command(TARGET target_cmd POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_postbuild commands"
+  COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_postbuild" > target_cmd_postbuild.txt
+  BYPRODUCTS target_cmd_postbuild.txt
+  COMMENT "CT: Processing target_cmd_postbuild")
+
+add_custom_target(target_empty ALL
+  COMMENT "CT: Processing target_empty")
+
+add_custom_command(TARGET target_empty PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo "target_empty_prebuild" > target_empty_prebuild.txt
+  BYPRODUCTS target_empty_prebuild.txt
+  COMMENT "CT: Processing target_empty_prebuild")
+add_custom_command(TARGET target_empty POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo "target_empty_postbuild" > target_empty_postbuild.txt
+  BYPRODUCTS target_empty_postbuild.txt
+  COMMENT "CT: Processing target_empty_postbuild")
+
+add_dependencies(target_cmd target_empty)
+
+add_custom_command(
+  OUTPUT out_of_order_dep.txt
+  COMMAND ${CMAKE_COMMAND} -E echo "out_of_order_dep" > out_of_order_dep.txt
+  COMMENT "CT: generate text file out_of_order_dep"
+  DEPENDS dependsA.txt
+)
+
+if(TEST_MISSING_TARGET_SRC)
+  set(SRC_FILE does_not_exist)
+endif()
+if(TEST_MISSING_TARGET_DEP)
+  set(DEP_FILE does_not_exist)
+endif()
+
+add_custom_target(target_update_files
+  DEPENDS genc_do_not_list.txt ${DEP_FILE}
+  SOURCES gena.txt genb.txt another_file.c ${SRC_FILE}
+  BYPRODUCTS junkit.txt
+  COMMAND ${CMAKE_COMMAND} -E copy another_file.c junkit.txt
+  COMMENT "CT: Processing target_update_files")
+
+add_custom_command(
+  OUTPUT force_rebuild gena.txt genb.txt genc_do_not_list.txt
+  COMMAND ${CMAKE_COMMAND} -E copy dependsA.txt gena.txt
+  COMMAND ${CMAKE_COMMAND} -E echo "genb" > genb.txt
+  COMMAND ${CMAKE_COMMAND} -E echo "genc" > genc_do_not_list.txt
+  DEPENDS out_of_order_dep.txt dependsA.txt
+  COMMENT "CT: generate text files A, B, and C"
+)
+
+if(TEST_MISSING_DEP)
+  set(MISSING_DEP MISSING_DEP)
+endif()
+if(TEST_DEP_CYCLE)
+  set(DEP_CYCLE out_of_order_dep.txt)
+endif()
+
+add_custom_command(
+  OUTPUT dependsA.txt
+  COMMAND ${CMAKE_COMMAND} -E echo "dependsA" > dependsA.txt
+  DEPENDS ${MISSING_DEP} ${DEP_CYCLE} another_file.c
+  COMMENT "CT: generate text file dependsA"
+)
+
+add_custom_command(
+  OUTPUT another_file.c
+  COMMAND ${CMAKE_COMMAND} -E echo "//auto-gen file" > another_file.c
+  COMMENT "CT: generate C file another_file"
+)
+
+add_dependencies(target_update_files target_empty)
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
new file mode 100644
index 0000000..29ad70a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+  return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+  return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
new file mode 100644
index 0000000..2e2871b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+#set_property( GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
+add_subdirectory(exec)
+add_subdirectory(lib)
+add_subdirectory(protolib)
+add_dependencies(lib1 proto)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
new file mode 100644
index 0000000..85ee805
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+target_include_directories(exe1 PRIVATE "${test_BINARY_DIR}")
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  target_link_options(exe1 PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
new file mode 100644
index 0000000..fbf4ed4
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
@@ -0,0 +1,8 @@
+#include "lib1.h"
+#include "p.h"
+
+int main(void)
+{
+  return func1() + func2() + func3() + func1p() + func2p() + func3p() +
+    PROTO1 + PROTO2 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
new file mode 100644
index 0000000..ae30fa2
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+add_library(lib1 STATIC
+  func1.c lib1.h
+  "${test_BINARY_DIR}/protolib/proto1.c"
+  "${test_BINARY_DIR}/protolib/proto1.h")
+set_source_files_properties(
+  "${test_BINARY_DIR}/protolib/proto1.c"
+  "${test_BINARY_DIR}/protolib/proto1.h"
+  PROPERTIES GENERATED 1)
+target_include_directories(lib1 PRIVATE "${test_BINARY_DIR}/protolib"
+  PUBLIC .)
+add_custom_command( TARGET lib1 POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${test_BINARY_DIR}/protolib/proto1.h" "${test_BINARY_DIR}/p.h"
+  COMMENT "Copy ${test_BINARY_DIR}/protolib/proto1.h ${test_BINARY_DIR}/p.h"
+  BYPRODUCTS "${test_BINARY_DIR}/p.h")
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
new file mode 100644
index 0000000..53334fe
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
@@ -0,0 +1,17 @@
+#include "lib1.h"
+#include "proto1.h"
+
+int func1(void)
+{
+  return 1 + PROTO1;
+}
+
+int func2(void)
+{
+  return 2 + PROTO2;
+}
+
+int func3(void)
+{
+  return 3 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
new file mode 100644
index 0000000..5e99f02
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
@@ -0,0 +1,3 @@
+extern int func1(void);
+extern int func2(void);
+extern int func3(void);
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
new file mode 100644
index 0000000..8cb6869
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_custom_target(proto ALL
+  DEPENDS proto1.c
+          proto1.h
+  SOURCES
+          ${test_SOURCE_DIR}/protolib/proto1.c.in
+          ${test_SOURCE_DIR}/protolib/proto1.h.in
+  COMMENT "Creating proto files")
+
+add_custom_command(
+  OUTPUT proto1.c
+  COMMAND ${CMAKE_COMMAND} -E copy
+    ${test_SOURCE_DIR}/protolib/proto1.c.in proto1.c
+  DEPENDS ${test_SOURCE_DIR}/protolib/proto1.c.in
+  COMMENT "generate proto C files"
+)
+
+add_custom_command(
+  OUTPUT proto1.h
+  COMMAND ${CMAKE_COMMAND} -E copy
+    ${test_SOURCE_DIR}/protolib/proto1.h.in proto1.h
+  DEPENDS ${test_SOURCE_DIR}/protolib/proto1.h.in
+  COMMENT "generate proto H files"
+)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
new file mode 100644
index 0000000..0efb1bd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
@@ -0,0 +1,16 @@
+#include "proto1.h"
+
+int func1p(void)
+{
+  return 1;
+}
+
+int func2p(void)
+{
+  return 2;
+}
+
+int func3p(void)
+{
+  return 3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
new file mode 100644
index 0000000..f2f93af
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
@@ -0,0 +1,7 @@
+extern int func1p(void);
+extern int func2p(void);
+extern int func3p(void);
+
+#define PROTO1 0x1
+#define PROTO2 0x2
+#define PROTO3 0x3
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
new file mode 100644
index 0000000..24126c8
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+include(ExternalProject)
+
+ExternalProject_Add(another_project
+  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/empty
+  BINARY_DIR empty_build
+  INSTALL_COMMAND ""
+  TEST_COMMAND ""
+  )
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
new file mode 100644
index 0000000..6846a98
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(empty NONE)
+
+message("EMPTY PROJECT")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
index e431217..3837b5a 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
@@ -1,4 +1,3 @@
 add_executable(App Main.c)
-target_include_directories(App PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../Lib)
 target_link_libraries(App Lib)
 target_compile_options(App PUBLIC "-non_shared")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
index 00e0f59..bb9849a 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
@@ -1 +1,2 @@
 add_library(Lib HelperFun.c HelperFun.h)
+target_include_directories(Lib PUBLIC .)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
index c5db155..3f2f0eb 100644
--- a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
@@ -18,3 +18,4 @@
 
 # create monolith INTEGRITY application
 add_executable(monolith test.int)
+add_dependencies(monolith vas)
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt b/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
index a025814..98668e5 100644
--- a/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
@@ -5,7 +5,7 @@
 
 project(test C)
 
-add_library(obj1 OBJECT testObj.c testObj.h sub/testObj.c testObj2.c)
+add_library(obj1 OBJECT testOBJ.c testOBJ.h sub/testOBJ.c testOBJ2.c)
 
 add_executable(exe1 exe.c $<TARGET_OBJECTS:obj1>)
 if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
diff --git a/Tests/GhsMulti/GhsMultiPlatform/file1.c b/Tests/GhsMulti/GhsMultiPlatform/file1.c
deleted file mode 100644
index 4132aa4..0000000
--- a/Tests/GhsMulti/GhsMultiPlatform/file1.c
+++ /dev/null
@@ -1,4 +0,0 @@
-int main(void)
-{
-  return -42;
-}
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
index f5792b4..b2540d9 100644
--- a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
@@ -13,7 +13,7 @@
 
 if(RUN_TEST STREQUAL "SINGLE_EXEC")
   add_executable(exe1 exe.c)
-  set(targets_to_install ${targets_to_install} exe1)
+  set(targets_to_install exe1)
 endif()
 
 if(RUN_TEST STREQUAL "SINGLE_EXEC_RENAMED")
@@ -22,7 +22,7 @@
   set_property(TARGET exe1 PROPERTY RUNTIME_OUTPUT_DIRECTORY ${name}_bin_$<CONFIG>)
   set_property(TARGET exe1 PROPERTY OUTPUT_NAME ${name}_$<CONFIG>)
   set_property(TARGET exe1 PROPERTY SUFFIX .bin)
-  set(targets_to_install ${targets_to_install} exe1)
+  set(targets_to_install exe1)
 endif()
 
 if(RUN_TEST STREQUAL "EXEC_AND_LIB")
@@ -33,7 +33,7 @@
 
  add_executable(exe1 exe1.c)
  target_link_libraries(exe1 lib1)
- set(targets_to_install ${targets_to_install} exe1 lib1)
+ set(targets_to_install exe1 lib1)
 endif()
 
 install(TARGETS ${targets_to_install}
diff --git a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
index ed3094b..f5f3c55 100644
--- a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
+++ b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
@@ -5,8 +5,6 @@
 
 project(test C)
 
-add_custom_target(testTarget ALL echo this is a test)
-
 add_library(sharedLib SHARED file.c)
 
 add_library(moduleLib MODULE file.c)
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index b7b8320..761c405 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -2,7 +2,7 @@
 project(IncludeDirectories)
 
 if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
-    OR CMAKE_C_COMPILER_ID STREQUAL Clang OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
+    OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
     AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles"
       OR CMAKE_GENERATOR STREQUAL "Ninja"
       OR (CMAKE_GENERATOR STREQUAL "Xcode" AND NOT XCODE_VERSION VERSION_LESS 6.0)))
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
index 5b99ea7..a9edf9a 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
@@ -17,7 +17,8 @@
 create_header(bung)
 create_header(arguments)
 create_header(list)
-create_header(target)
+create_header(target1)
+create_header(target2)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
@@ -69,14 +70,23 @@
 set_property(TARGET lib4 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foh;$<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>")
 
 add_library(somelib::withcolons UNKNOWN IMPORTED)
-set_property(TARGET somelib::withcolons PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/target")
-set_property(TARGET somelib::withcolons PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target")
+set_property(TARGET somelib::withcolons PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/target1")
+set_property(TARGET somelib::withcolons PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target1")
 
 set_property(TARGET TargetIncludeDirectories
   APPEND PROPERTY INCLUDE_DIRECTORIES
   "$<TARGET_PROPERTY:somelib::withcolons,INTERFACE_INCLUDE_DIRECTORIES>"
 )
 
+add_library(somelib_aliased UNKNOWN IMPORTED GLOBAL)
+set_property(TARGET somelib_aliased PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target2")
+add_library(somelib::withcolons2 ALIAS somelib_aliased)
+
+set_property(TARGET TargetIncludeDirectories
+  APPEND PROPERTY INCLUDE_DIRECTORIES
+  "$<TARGET_PROPERTY:somelib::withcolons2,INTERFACE_INCLUDE_DIRECTORIES>"
+)
+
 add_custom_target(test_custom_target
         "some_bogus_custom_tool"
         $<TARGET_PROPERTY:TargetIncludeDirectories,COMPILE_DEFINITIONS>
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
index 2ee05e2..541ef92 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
@@ -10,7 +10,8 @@
 #include "foo.h"
 #include "list.h"
 #include "prefix_foo_bar_bat.h"
-#include "target.h"
+#include "target1.h"
+#include "target2.h"
 #include "ting.h"
 
 int main(int, char**)
diff --git a/Tests/Module/FindDependency/CMakeLists.txt b/Tests/Module/FindDependency/CMakeLists.txt
index dcb998a..06d7dce 100644
--- a/Tests/Module/FindDependency/CMakeLists.txt
+++ b/Tests/Module/FindDependency/CMakeLists.txt
@@ -6,6 +6,8 @@
 
 find_package(Pack1 REQUIRED)
 find_package(Pack4 4.3 EXACT REQUIRED)
+find_package(Pack7 REQUIRED)
+find_package(Pack8 REQUIRED)
 
 add_executable(FindDependency main.cpp)
-target_link_libraries(FindDependency Pack1::Lib Pack4::Lib)
+target_link_libraries(FindDependency Pack1::Lib Pack4::Lib Pack8::Lib)
diff --git a/Tests/Module/FindDependency/main.cpp b/Tests/Module/FindDependency/main.cpp
index 1df4cb5..4ee460f 100644
--- a/Tests/Module/FindDependency/main.cpp
+++ b/Tests/Module/FindDependency/main.cpp
@@ -23,6 +23,18 @@
 #  error Expected HAVE_PACK6
 #endif
 
+#ifndef HAVE_PACK7
+#  error Expected HAVE_PACK7
+#endif
+
+#ifndef HAVE_PACK7_COMP1
+#  error Expected HAVE_PACK7_COMP1
+#endif
+
+#ifndef HAVE_PACK8
+#  error Expected HAVE_PACK8
+#endif
+
 int main(int argc, char** argv)
 {
   return 0;
diff --git a/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake b/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake
new file mode 100644
index 0000000..9df1345
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake
@@ -0,0 +1,14 @@
+if(NOT Pack7_FOUND)
+  set(Pack7_FOUND 1)
+  add_library(Pack7::Pack7 INTERFACE IMPORTED)
+  set_property(TARGET Pack7::Pack7 PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK7)
+endif()
+
+foreach(module ${Pack7_FIND_COMPONENTS})
+  if(module STREQUAL "Comp1")
+    add_library(Pack7::Comp1 INTERFACE IMPORTED)
+    set_property(TARGET Pack7::Comp1 PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK7_COMP1)
+    set_property(TARGET Pack7::Comp1 PROPERTY INTERFACE_LINK_LIBRARIES Pack7::Pack7)
+    set(Pack7_Comp1_FOUND 1)
+  endif()
+endforeach()
diff --git a/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake b/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake
new file mode 100644
index 0000000..d7ca054
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake
@@ -0,0 +1,7 @@
+include(CMakeFindDependencyMacro)
+
+find_dependency(Pack7 REQUIRED COMPONENTS Comp1)
+
+add_library(Pack8::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack8::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK8)
+set_property(TARGET Pack8::Lib PROPERTY INTERFACE_LINK_LIBRARIES Pack7::Comp1)
diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
index 45bb229..cffef5a 100644
--- a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
+++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
@@ -52,8 +52,10 @@
 # detailed features tables, not just meta-features
 
 if (CMAKE_C_COMPILE_FEATURES)
-  set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
-  list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+  if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+    set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
+    list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+  endif()
 endif()
 if (C_expected_features)
   string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" COMPILER_VERSION_MAJOR "${CMAKE_C_COMPILER_VERSION}")
@@ -61,7 +63,7 @@
   string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" COMPILER_VERSION_PATCH "${CMAKE_C_COMPILER_VERSION}")
 
   if (CMAKE_C_COMPILER_ID STREQUAL "GNU"
-      OR CMAKE_C_COMPILER_ID STREQUAL "Clang"
+      OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
       OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
       OR CMAKE_C_COMPILER_ID STREQUAL "Intel")
     add_executable(WriteCompilerDetectionHeader_C11 main.c)
@@ -93,8 +95,10 @@
 endif()
 
 if (CMAKE_CXX_COMPILE_FEATURES)
-  set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
-  list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+  if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+    set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
+    list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+  endif()
 endif()
 if (NOT CXX_expected_features)
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
@@ -118,7 +122,7 @@
 string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" COMPILER_VERSION_PATCH "${CMAKE_CXX_COMPILER_VERSION}")
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
-    OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+    OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
     OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
     OR CMAKE_CXX_COMPILER_ID STREQUAL "SunPro"
     OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
@@ -128,7 +132,8 @@
 endif()
 
 # for msvc the compiler version determines which c++11 features are available.
-if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
+    OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))
   if(";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_delegating_constructors;")
     list(APPEND true_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
     list(APPEND true_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
diff --git a/Tests/Plugin/CMakeLists.txt b/Tests/Plugin/CMakeLists.txt
index 227d990..8e8fa07 100644
--- a/Tests/Plugin/CMakeLists.txt
+++ b/Tests/Plugin/CMakeLists.txt
@@ -15,6 +15,7 @@
 set(KWSYS_NAMESPACE kwsys)
 set(KWSYS_HEADER_ROOT ${Plugin_BINARY_DIR}/include)
 set(KWSYS_USE_DynamicLoader 1)
+set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_UTF8)
 add_subdirectory(${Plugin_SOURCE_DIR}/../../Source/kwsys src/kwsys)
 
 # Configure the location of plugins.
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
index cff7022..81fd8db 100644
--- a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
+++ b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
@@ -69,6 +69,9 @@
 message("___ Configuring GAT project ___")
 execute_process(
     COMMAND "${CMAKE_COMMAND}" "${GAT_SDIR}"
+        -G "${CMAKE_GENERATOR}"
+        -A "${CMAKE_GENERATOR_PLATFORM}"
+        -T "${CMAKE_GENERATOR_TOOLSET}"
         "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
         "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
         "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
diff --git a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
index f4b726f..9b32e59 100644
--- a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
@@ -5,10 +5,48 @@
 # Dummy executable to generate a clean target
 add_executable(dummy dummy.cpp)
 
-set(timeformat "%Y%j%H%M%S")
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
 set(mocBasicSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/MocBasic")
 set(mocBasicBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocBasic")
 
+# Utility macros
+macro(sleep)
+  message(STATUS "Sleeping for a few seconds.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamp When)
+  file(TIMESTAMP "${mocBasicBin}" time${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+  message(STATUS "Starting build ${buildName}.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result)
+  if (result)
+    message(FATAL_ERROR "Build ${buildName} failed.")
+  else()
+    message(STATUS "Build ${buildName} finished.")
+  endif()
+endmacro()
+
+macro(require_change)
+  if (timeAfter VERSION_GREATER timeBefore)
+    message(STATUS "As expected the file ${mocBasicBin} changed.")
+  else()
+    message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} did not change!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+  endif()
+endmacro()
+
+macro(require_change_not)
+  if (timeAfter VERSION_GREATER timeBefore)
+    message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} changed!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+  else()
+    message(STATUS "As expected the file ${mocBasicBin} did not change.")
+  endif()
+endmacro()
+
+
 # Initial build
 configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
 try_compile(MOC_RERUN
@@ -21,46 +59,44 @@
   OUTPUT_VARIABLE output
 )
 if (NOT MOC_RERUN)
-  message(SEND_ERROR "Initial build of mocBasic failed. Output: ${output}")
+  message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}")
 endif()
+
 # Get name of the output binary
 file(STRINGS "${mocBasicBinDir}/mocBasic.txt" mocBasicList ENCODING UTF-8)
 list(GET mocBasicList 0 mocBasicBin)
 
-message("Changing the header content for a MOC rerun")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${mocBasicBin}" timeBefore "${timeformat}")
+# To avoid a race condition where the binary has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - touch binary to ensure it has a new timestamp
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Touching binary file to ensure a new timestamps")
+file(TOUCH_NOCREATE "${mocBasicBin}")
+acquire_timestamp(After)
+require_change()
+
+
 # - Ensure that the timestamp will change
-# - Change header file content and rebuild
+# - Change header file content
 # - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Changing the header content for a MOC re-run")
 configure_file("${mocBasicSrcDir}/test1b.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result )
-if (result)
-  message(SEND_ERROR "Second build of mocBasic failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${mocBasicBin}" timeAfter "${timeformat}")
-# - Test if timestamps changed
-if (NOT timeAfter GREATER timeBefore)
-  message(SEND_ERROR "File (${mocBasicBin}) should have changed!")
-endif()
+sleep()
+rebuild(2)
+acquire_timestamp(After)
+require_change()
 
 
-message("Changing nothing for a MOC rerun")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${mocBasicBin}" timeBefore "${timeformat}")
 # - Ensure that the timestamp would change
 # - Change nothing
 # - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result )
-if (result)
-  message(SEND_ERROR "Third build of mocBasic failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${mocBasicBin}" timeAfter "${timeformat}")
-# - Test if timestamps changed
-if (timeAfter GREATER timeBefore)
-  message(SEND_ERROR "File (${mocBasicBin}) should not have changed!")
-endif()
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Changing nothing for no MOC re-run")
+rebuild(3)
+acquire_timestamp(After)
+require_change_not()
diff --git a/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt b/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
index b83e994..e1951f1 100644
--- a/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
@@ -9,10 +9,53 @@
 add_executable(dummy dummy.cpp)
 
 # Utility variables
-set(timeformat "%Y%j%H%M%S")
+set(timeformat "%Y.%j.%H.%M%S")
 set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/MocPlugin")
 set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocPlugin")
 
+# Utility macros
+macro(sleep)
+  message(STATUS "Sleeping for a few seconds.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(rebuild buildName)
+  message(STATUS "Starting build ${buildName}.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}" RESULT_VARIABLE result)
+  if (result)
+    message(FATAL_ERROR "Build ${buildName} failed.")
+  else()
+    message(STATUS "Build ${buildName} finished.")
+  endif()
+endmacro()
+
+macro(require_change PLG)
+  if (pl${PLG}After VERSION_GREATER pl${PLG}Before)
+    message(STATUS "As expected the file ${pl${PLG}File} changed.")
+  else()
+    message(SEND_ERROR
+      "Unexpectedly the file ${pl${PLG}File} did not change!\nTimestamp pre: ${pl${PLG}Before}\nTimestamp aft: ${pl${PLG}After}\n")
+  endif()
+endmacro()
+
+macro(require_change_not PLG)
+  if (pl${PLG}After VERSION_GREATER pl${PLG}Before)
+    message(SEND_ERROR
+      "Unexpectedly the file ${pl${PLG}File} changed!\nTimestamp pre: ${pl${PLG}Before}\nTimestamp aft: ${pl${PLG}After}\n")
+  else()
+    message(STATUS "As expected the file ${pl${PLG}File} did not change.")
+  endif()
+endmacro()
+
+macro(acquire_timestamps When)
+  file(TIMESTAMP "${plAFile}" plA${When} "${timeformat}")
+  file(TIMESTAMP "${plBFile}" plB${When} "${timeformat}")
+  file(TIMESTAMP "${plCFile}" plC${When} "${timeformat}")
+  file(TIMESTAMP "${plDFile}" plD${When} "${timeformat}")
+  file(TIMESTAMP "${plEFile}" plE${When} "${timeformat}")
+endmacro()
+
+
 # Initial build
 try_compile(MOC_PLUGIN
   "${mocPlugBinDir}"
@@ -24,83 +67,68 @@
   OUTPUT_VARIABLE output
 )
 if (NOT MOC_PLUGIN)
-  message(SEND_ERROR "Initial build of mocPlugin failed. Output: ${output}")
+  message(FATAL_ERROR "Initial build of mocPlugin failed. Output: ${output}")
 endif()
 
+# Get names of the output binaries
 find_library(plAFile "PlugA" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
 find_library(plBFile "PlugB" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
 find_library(plCFile "PlugC" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
 find_library(plDFile "PlugD" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
 find_library(plEFile "PlugE" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
 
+# To avoid a race condition where the library has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - rebuild library to ensure it has a new timestamp
+sleep()
+message(STATUS "Rebuilding library files to ensure new timestamps")
+rebuild(1)
+
+
 # - Ensure that the timestamp will change.
 # - Change the json files referenced by Q_PLUGIN_METADATA
 # - Rebuild
-file(TIMESTAMP "${plAFile}" plABefore "${timeformat}")
-file(TIMESTAMP "${plBFile}" plBBefore "${timeformat}")
-file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}")
-
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing json files.")
 configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC.json")
 configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json")
 configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/StyleE.json")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}")
+sleep()
+rebuild(2)
+acquire_timestamps(After)
+# Test changes
+require_change_not(A)
+require_change_not(B)
+require_change(C)
+require_change(D)
+# There's a bug in Ninja on Windows:
+# https://gitlab.kitware.com/cmake/cmake/issues/16776
+if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
+  require_change(E)
+endif()
 
-file(TIMESTAMP "${plAFile}" plAAfter "${timeformat}")
-file(TIMESTAMP "${plBFile}" plBAfter "${timeformat}")
-file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}")
-
-if (plAAfter GREATER plABefore)
-  message(SEND_ERROR "file (${plAFile}) should not have changed!")
-endif()
-if (plBAfter GREATER plBBefore)
-  message(SEND_ERROR "file (${plBFile}) should not have changed!")
-endif()
-if (NOT plCAfter GREATER plCBefore)
-  message(SEND_ERROR "file (${plCFile}) should have changed!")
-endif()
-if (NOT plDAfter GREATER plDBefore)
-  message(SEND_ERROR "file (${plDFile}) should have changed!")
-endif()
-if (NOT plEAfter GREATER plEBefore)
-  # There's a bug in Ninja on Windows
-  # https://gitlab.kitware.com/cmake/cmake/issues/16776
-  if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
-    message(SEND_ERROR "file (${plEFile}) should have changed!")
-  endif()
-endif()
 
 # - Ensure that the timestamp will change.
 # - Change the json files referenced by A_CUSTOM_MACRO
 # - Rebuild
-file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}")
-
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing json files")
 configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json")
 configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD_Custom.json")
 configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleE_Custom.json")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}")
-
-file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}")
-file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}")
-file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}")
-
-if (NOT plCAfter GREATER plCBefore)
-  message(SEND_ERROR "file (${plCFile}) should have changed!")
-endif()
-if (NOT plDAfter GREATER plDBefore)
-  message(SEND_ERROR "file (${plDFile}) should have changed!")
-endif()
-if (NOT plEAfter GREATER plEBefore)
-  # There's a bug in Ninja on Windows
-  # https://gitlab.kitware.com/cmake/cmake/issues/16776
-  if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
-    message(SEND_ERROR "file (${plEFile}) should have changed!")
-  endif()
+sleep()
+rebuild(3)
+acquire_timestamps(After)
+# Test changes
+require_change_not(A)
+require_change_not(B)
+require_change(C)
+require_change(D)
+# There's a bug in Ninja on Windows
+# https://gitlab.kitware.com/cmake/cmake/issues/16776
+if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
+  require_change(E)
 endif()
diff --git a/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt b/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
index dcb7a79..33c01ac 100644
--- a/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
@@ -9,10 +9,23 @@
 
 # When a .qrc or a file listed in a .qrc file changes,
 # the target must be rebuilt
-set(timeformat "%Y%j%H%M%S")
 set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/RccConfigChange")
 set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/RccConfigChange")
 
+# Rebuild macro
+macro(rebuild CFG)
+  message(STATUS "Rebuilding rccConfigChange in ${CFG} configuration.")
+  execute_process(
+    COMMAND "${CMAKE_COMMAND}" --build . --config "${CFG}"
+    WORKING_DIRECTORY "${rccDepBD}"
+    RESULT_VARIABLE result)
+  if (result)
+    message(FATAL_ERROR "${CFG} build of rccConfigChange failed.")
+  else()
+    message(STATUS "${CFG} build of rccConfigChange finished.")
+  endif()
+endmacro()
+
 # Initial build
 try_compile(RCC_DEPENDS
   "${rccDepBD}"
@@ -24,19 +37,11 @@
   OUTPUT_VARIABLE output
 )
 if (NOT RCC_DEPENDS)
-  message(SEND_ERROR "Initial build of rccConfigChange failed. Output: ${output}")
+  message(FATAL_ERROR "Initial build of rccConfigChange failed. Output: ${output}")
 endif()
 
-# - Rebuild Release
-message("Rebuilding rccConfigChange in Release configuration")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . --config Release WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
-  message(SEND_ERROR "Release build of rccConfigChange failed.")
-endif()
+# Rebuild: Release
+rebuild(Release)
 
-# - Rebuild Debug
-message("Rebuilding rccConfigChange in Debug configuration")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . --config Debug WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
-  message(SEND_ERROR "Debug build of rccConfigChange failed.")
-endif()
+# Rebuild: Debug
+rebuild(Debug)
diff --git a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
index 80c5cf0..1301550 100644
--- a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
@@ -3,19 +3,63 @@
 include("../AutogenCoreTest.cmake")
 
 # Tests rcc rebuilding when a resource file changes
+# When a .qrc or a file listed in a .qrc file changes,
+# the target must be rebuilt
 
 # Dummy executable to generate a clean target
 add_executable(dummy dummy.cpp)
 
-# When a .qrc or a file listed in a .qrc file changes,
-# the target must be rebuilt
-set(timeformat "%Y%j%H%M%S")
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
 set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/RccDepends")
 set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/RccDepends")
 
-# Initial build
+# Utility macros
+macro(sleep)
+  message(STATUS "Sleeping for a few seconds.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamps When)
+  file(TIMESTAMP "${rccDepBinPlain}" rdPlain${When} "${timeformat}")
+  file(TIMESTAMP "${rccDepBinGenerated}" rdGenerated${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+  message(STATUS "Starting build ${buildName} of rccDepends.")
+  execute_process(
+    COMMAND "${CMAKE_COMMAND}" --build .
+    WORKING_DIRECTORY "${rccDepBD}"
+    RESULT_VARIABLE result)
+  if (result)
+    message(FATAL_ERROR "Build ${buildName} of rccDepends failed.")
+  else()
+    message(STATUS "Build ${buildName} of rccDepends finished.")
+  endif()
+endmacro()
+
+macro(require_change type)
+  if (rd${type}After VERSION_GREATER rd${type}Before)
+    message(STATUS "As expected the ${type} .qrc file ${rccDepBin${type}} changed.")
+  else()
+    message(SEND_ERROR "Unexpectedly the ${type} .qrc file ${rccDepBin${type}} did not change!\nTimestamp pre: ${rd${type}Before}\nTimestamp aft: ${rd${type}After}\n")
+  endif()
+endmacro()
+
+macro(require_change_not type)
+  if (rd${type}After VERSION_GREATER rd${type}Before)
+    message(SEND_ERROR "Unexpectedly the ${type} .qrc file ${rccDepBin${type}} changed!\nTimestamp pre: ${rd${type}Before}\nTimestamp aft: ${rd${type}After}\n")
+  else()
+    message(STATUS "As expected the ${type} .qrc file ${rccDepBin${type}} did not change.")
+  endif()
+endmacro()
+
+
+# Initial configuration
 configure_file(${rccDepSD}/resPlainA.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY)
 configure_file(${rccDepSD}/resGenA.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY)
+
+# Initial build
 try_compile(RCC_DEPENDS
   "${rccDepBD}"
   "${rccDepSD}"
@@ -26,113 +70,84 @@
   OUTPUT_VARIABLE output
 )
 if (NOT RCC_DEPENDS)
-  message(SEND_ERROR "Initial build of rccDepends failed. Output: ${output}")
+  message(FATAL_ERROR "Initial build of rccDepends failed. Output: ${output}")
 endif()
 
 # Get name of the output binaries
 file(STRINGS "${rccDepBD}/targetPlain.txt" targetListPlain ENCODING UTF-8)
 file(STRINGS "${rccDepBD}/targetGen.txt" targetListGen ENCODING UTF-8)
 list(GET targetListPlain 0 rccDepBinPlain)
-list(GET targetListGen 0 rccDepBinGen)
-message("Target that uses a plain .qrc file is:\n  ${rccDepBinPlain}")
-message("Target that uses a GENERATED .qrc file is:\n  ${rccDepBinGen}")
+list(GET targetListGen 0 rccDepBinGenerated)
+message(STATUS "Target that uses a plain .qrc file is:\n  ${rccDepBinPlain}")
+message(STATUS "Target that uses a GENERATED .qrc file is:\n  ${rccDepBinGenerated}")
+
+# To avoid a race condition where the binary has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - touch binary to ensure it has a new timestamp
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Touching binary files to ensure new timestamps")
+file(TOUCH_NOCREATE "${rccDepBinPlain}" "${rccDepBinGenerated}")
+acquire_timestamps(After)
+require_change(Plain)
+require_change(Generated)
 
 
-message("Changing a resource files listed in the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
 # - Ensure that the timestamp will change
 # - Change a resource files listed in the .qrc file
 # - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing a resource file listed in the .qrc file")
 file(TOUCH "${rccDepBD}/resPlain/input.txt" "${rccDepBD}/resGen/input.txt")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
-  message(SEND_ERROR "Second build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+sleep()
+rebuild(2)
+acquire_timestamps(After)
 # - Test if timestamps changed
-if (NOT rdPlainAfter GREATER rdPlainBefore)
-  message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!")
-endif()
-if (NOT rdGenAfter GREATER rdGenBefore)
-  message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!")
-endif()
+require_change(Plain)
+require_change(Generated)
 
 
-message("Changing the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
 # - Ensure that the timestamp will change
 # - Change the .qrc file
 # - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing the .qrc file")
 configure_file(${rccDepSD}/resPlainB.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY)
 configure_file(${rccDepSD}/resGenB.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
-  message(SEND_ERROR "Third build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+sleep()
+rebuild(3)
+acquire_timestamps(After)
 # - Test if timestamps changed
-if (NOT rdPlainAfter GREATER rdPlainBefore)
-  message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!")
-endif()
-if (NOT rdGenAfter GREATER rdGenBefore)
-  message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!")
-endif()
+require_change(Plain)
+require_change(Generated)
 
 
-message("Changing a newly added resource files listed in the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
 # - Ensure that the timestamp will change
 # - Change a newly added resource files listed in the .qrc file
 # - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing a newly added resource file listed in the .qrc file")
 file(TOUCH "${rccDepBD}/resPlain/inputAdded.txt" "${rccDepBD}/resGen/inputAdded.txt")
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
-  message(SEND_ERROR "Fourth build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+sleep()
+rebuild(4)
+acquire_timestamps(After)
 # - Test if timestamps changed
-if (NOT rdPlainAfter GREATER rdPlainBefore)
-  message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!")
-endif()
-if (NOT rdGenAfter GREATER rdGenBefore)
-  message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!")
-endif()
+require_change(Plain)
+require_change(Generated)
 
 
-message("Changing nothing in the .qrc file")
-# - Acquire binary timestamps before the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}")
 # - Ensure that the timestamp will change
 # - Change nothing
 # - Rebuild
-execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
-execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result)
-if (result)
-  message(SEND_ERROR "Fifth build of rccDepends failed.")
-endif()
-# - Acquire binary timestamps after the build
-file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}")
-file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}")
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing nothing in the .qrc file")
+rebuild(5)
+acquire_timestamps(After)
 # - Test if timestamps changed
-if (rdPlainAfter GREATER rdPlainBefore)
-  message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should NOT have changed!")
-endif()
-if (rdGenAfter GREATER rdGenBefore)
-  message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should NOT have changed!")
-endif()
+require_change_not(Plain)
+require_change_not(Generated)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index f2b7ff1..68411d6 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -192,6 +192,9 @@
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(LinkStatic)
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+  add_RunCMake_test(MetaCompileFeatures)
+endif()
 add_RunCMake_test(ObjectLibrary)
 add_RunCMake_test(ParseImplicitIncludeInfo)
 if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
@@ -339,8 +342,7 @@
   add_RunCMake_test(FindPkgConfig)
 endif()
 
-find_package(GTK2 QUIET)
-if (GTK2_FOUND)
+if(CMake_TEST_FindGTK2)
   add_RunCMake_test(FindGTK2)
 endif()
 
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-stderr.txt
deleted file mode 100644
index f2cbaa6..0000000
--- a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-stderr.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-^'--target' may not be specified more than once\.
-+
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt
new file mode 100644
index 0000000..40d9bec
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt
@@ -0,0 +1,2 @@
+^Error: Building 'clean' and other targets together is not supported\.
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt
new file mode 100644
index 0000000..40d9bec
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt
@@ -0,0 +1,2 @@
+^Error: Building 'clean' and other targets together is not supported\.
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt b/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt
index 0ca5a0a..fc62914 100644
--- a/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt
+++ b/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt
@@ -1,4 +1,5 @@
-cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.14)
+project(ExplicitDirs NONE)
 add_custom_command(
   OUTPUT output.txt
   COMMAND ${CMAKE_COMMAND} -E echo CustomCommand > output.txt
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 23fb9ef..ea749ea 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -54,6 +54,14 @@
 run_cmake_command(build-bad-generator
   ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-generator)
 
+run_cmake_command(install-no-dir
+  ${CMAKE_COMMAND} --install)
+run_cmake_command(install-bad-dir
+  ${CMAKE_COMMAND} --install dir-does-not-exist)
+run_cmake_command(install-options-to-vars
+  ${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
+  --strip --prefix /var/test --config sample --component pack)
+
 run_cmake_command(cache-bad-entry
   ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-entry/)
 run_cmake_command(cache-empty-entry
@@ -74,23 +82,27 @@
   set(source_dir ${RunCMake_SOURCE_DIR}/ExplicitDirs)
   set(binary_dir ${RunCMake_BINARY_DIR}/ExplicitDirs-build)
 
+  set(RunCMake_TEST_SOURCE_DIR "${source_dir}")
+  set(RunCMake_TEST_BINARY_DIR "${binary_dir}")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_NO_SOURCE_DIR 1)
+
   file(REMOVE_RECURSE "${binary_dir}")
-  file(MAKE_DIRECTORY "${binary_dir}")
-  run_cmake_command(S-arg ${CMAKE_COMMAND} -S ${source_dir} ${binary_dir})
-  run_cmake_command(S-arg-reverse-order ${CMAKE_COMMAND} ${binary_dir} -S${source_dir} )
-  run_cmake_command(S-no-arg ${CMAKE_COMMAND} -S )
-  run_cmake_command(S-no-arg2 ${CMAKE_COMMAND} -S -T)
-  run_cmake_command(S-B ${CMAKE_COMMAND} -S ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-arg -S ${source_dir} ${binary_dir})
+  run_cmake_with_options(S-arg-reverse-order ${binary_dir} -S${source_dir} )
+  run_cmake_with_options(S-no-arg -S )
+  run_cmake_with_options(S-no-arg2 -S -T)
+  run_cmake_with_options(S-B -S ${source_dir} -B ${binary_dir})
 
   # make sure that -B can explicitly construct build directories
   file(REMOVE_RECURSE "${binary_dir}")
-  run_cmake_command(B-arg ${CMAKE_COMMAND} -B ${binary_dir} ${source_dir})
+  run_cmake_with_options(B-arg -B ${binary_dir} ${source_dir})
   file(REMOVE_RECURSE "${binary_dir}")
-  run_cmake_command(B-arg-reverse-order ${CMAKE_COMMAND} ${source_dir} -B${binary_dir})
-  run_cmake_command(B-no-arg ${CMAKE_COMMAND} -B )
-  run_cmake_command(B-no-arg2 ${CMAKE_COMMAND} -B -T)
+  run_cmake_with_options(B-arg-reverse-order ${source_dir} -B${binary_dir})
+  run_cmake_with_options(B-no-arg -B )
+  run_cmake_with_options(B-no-arg2 -B -T)
   file(REMOVE_RECURSE "${binary_dir}")
-  run_cmake_command(B-S ${CMAKE_COMMAND} -B${binary_dir} -S${source_dir})
+  run_cmake_with_options(B-S -B${binary_dir} -S${source_dir})
 
 endfunction()
 run_ExplicitDirs()
@@ -106,7 +118,13 @@
   run_cmake_command(BuildDir--build ${CMAKE_COMMAND} -E chdir ..
     ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget)
   run_cmake_command(BuildDir--build-multiple-targets ${CMAKE_COMMAND} -E chdir ..
-    ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget2 --target CustomTarget3)
+    ${CMAKE_COMMAND} --build BuildDir-build -t CustomTarget2 --target CustomTarget3)
+  run_cmake_command(BuildDir--build-multiple-targets-jobs ${CMAKE_COMMAND} -E chdir ..
+    ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget CustomTarget2 -j2 --target CustomTarget3)
+  run_cmake_command(BuildDir--build-multiple-targets-with-clean-first ${CMAKE_COMMAND} -E chdir ..
+    ${CMAKE_COMMAND} --build BuildDir-build --target clean CustomTarget)
+  run_cmake_command(BuildDir--build-multiple-targets-with-clean-second ${CMAKE_COMMAND} -E chdir ..
+    ${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget clean)
   run_cmake_command(BuildDir--build-jobs-bad-number ${CMAKE_COMMAND} -E chdir ..
     ${CMAKE_COMMAND} --build BuildDir-build -j 12ab)
   run_cmake_command(BuildDir--build-jobs-good-number ${CMAKE_COMMAND} -E chdir ..
diff --git a/Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake b/Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake
new file mode 100644
index 0000000..fd4e67d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake
@@ -0,0 +1,15 @@
+if(CMAKE_INSTALL_PREFIX)
+  message("CMAKE_INSTALL_PREFIX is ${CMAKE_INSTALL_PREFIX}")
+endif()
+
+if(CMAKE_INSTALL_COMPONENT)
+  message("CMAKE_INSTALL_COMPONENT is ${CMAKE_INSTALL_COMPONENT}")
+endif()
+
+if(CMAKE_INSTALL_CONFIG_NAME)
+  message("CMAKE_INSTALL_CONFIG_NAME is ${CMAKE_INSTALL_CONFIG_NAME}")
+endif()
+
+if(CMAKE_INSTALL_DO_STRIP)
+  message("CMAKE_INSTALL_DO_STRIP is ${CMAKE_INSTALL_DO_STRIP}")
+endif()
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLine/install-bad-dir-result.txt
similarity index 100%
rename from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
rename to Tests/RunCMake/CommandLine/install-bad-dir-result.txt
diff --git a/Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt b/Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt
new file mode 100644
index 0000000..320aecc
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Error processing file:
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLine/install-no-dir-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/CommandLine/install-no-dir-result.txt
diff --git a/Tests/RunCMake/CommandLine/install-no-dir-stderr.txt b/Tests/RunCMake/CommandLine/install-no-dir-stderr.txt
new file mode 100644
index 0000000..d64f638
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-no-dir-stderr.txt
@@ -0,0 +1 @@
+^Usage: cmake --install <dir> \[options\]
diff --git a/Tests/RunCMake/CommandLine/install-options-to-vars-result.txt b/Tests/RunCMake/CommandLine/install-options-to-vars-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-options-to-vars-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt b/Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt
new file mode 100644
index 0000000..f7b1583
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt
@@ -0,0 +1,4 @@
+CMAKE_INSTALL_PREFIX is /var/test
+CMAKE_INSTALL_COMPONENT is pack
+CMAKE_INSTALL_CONFIG_NAME is sample
+CMAKE_INSTALL_DO_STRIP is 1
diff --git a/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake b/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake
index 12635db..5deb110 100644
--- a/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake
@@ -4,19 +4,23 @@
   run_cmake_command(${NAME} ${CMAKE_COMMAND} -E ${ARGN})
 endfunction()
 
-external_command_test(bad-opt1   tar cvf bad.tar --bad)
-external_command_test(bad-mtime1 tar cvf bad.tar --mtime=bad .)
-external_command_test(bad-from1  tar cvf bad.tar --files-from=bad)
-external_command_test(bad-from2  tar cvf bad.tar --files-from=.)
-external_command_test(bad-from3  tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from3.txt)
-external_command_test(bad-from4  tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from4.txt)
-external_command_test(bad-from5  tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from5.txt)
-external_command_test(end-opt1   tar cvf bad.tar -- --bad)
-external_command_test(end-opt2   tar cvf bad.tar --)
-external_command_test(mtime      tar cvf bad.tar "--mtime=1970-01-01 00:00:00 UTC")
-external_command_test(bad-format tar cvf bad.tar "--format=bad-format")
-external_command_test(zip-bz2    tar cvjf bad.tar "--format=zip")
-external_command_test(7zip-gz    tar cvzf bad.tar "--format=7zip")
+external_command_test(without-files      tar cvf bad.tar)
+external_command_test(bad-opt1           tar cvf bad.tar --bad)
+external_command_test(bad-mtime1         tar cvf bad.tar --mtime=bad .)
+external_command_test(bad-from1          tar cvf bad.tar --files-from=bad)
+external_command_test(bad-from2          tar cvf bad.tar --files-from=.)
+external_command_test(bad-from3          tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from3.txt)
+external_command_test(bad-from4          tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from4.txt)
+external_command_test(bad-from5          tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/bad-from5.txt)
+external_command_test(bad-file           tar cf  bad.tar badfile.txt ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(bad-without-action tar f bad.tar ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(bad-wrong-flag     tar cvfq bad.tar ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(end-opt1           tar cvf bad.tar -- --bad)
+external_command_test(end-opt2           tar cvf bad.tar --)
+external_command_test(mtime              tar cvf bad.tar "--mtime=1970-01-01 00:00:00 UTC" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(bad-format         tar cvf bad.tar "--format=bad-format" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(zip-bz2            tar cvjf bad.tar "--format=zip" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
+external_command_test(7zip-gz            tar cvzf bad.tar "--format=7zip" ${CMAKE_CURRENT_LIST_DIR}/test-file.txt)
 
 run_cmake(7zip)
 run_cmake(gnutar)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLineTar/bad-file-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/CommandLineTar/bad-file-result.txt
diff --git a/Tests/RunCMake/CommandLineTar/bad-file-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-file-stderr.txt
new file mode 100644
index 0000000..1f9f748
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-file-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Unable to read from file 'badfile.txt': .*
+CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt
index 1417d4d..fb0702a 100644
--- a/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt
+++ b/Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt
@@ -1,2 +1,2 @@
-^CMake Error: archive_read_disk_entry_from_file 'does-not-exist':.*
+^CMake Error: Unable to read from file 'does-not-exist':.*
 CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt
index 1417d4d..fb0702a 100644
--- a/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt
+++ b/Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt
@@ -1,2 +1,2 @@
-^CMake Error: archive_read_disk_entry_from_file 'does-not-exist':.*
+^CMake Error: Unable to read from file 'does-not-exist':.*
 CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/CommandLineTar/bad-without-action-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/CommandLineTar/bad-without-action-result.txt
diff --git a/Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt
new file mode 100644
index 0000000..2fec254
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: tar: No action specified. Please choose: 't' \(list\), 'c' \(create\) or 'x' \(extract\)$
diff --git a/Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt
new file mode 100644
index 0000000..d5c1e01
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt
@@ -0,0 +1 @@
+^tar: Unknown argument: q
diff --git a/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt b/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt
index 1fddf6d..1342dc8 100644
--- a/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt
+++ b/Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt
@@ -1,2 +1,2 @@
-^CMake Error: archive_read_disk_entry_from_file '--bad':.*
+^CMake Error: Unable to read from file '--bad':.*
 CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt b/Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt
new file mode 100644
index 0000000..70166f5
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt
@@ -0,0 +1 @@
+^tar: No files or directories specified
diff --git a/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake b/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake
index 5f2674a..53ee961 100644
--- a/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake
+++ b/Tests/RunCMake/CommandLineTar/gnutar-gz.cmake
@@ -1,9 +1,9 @@
 set(OUTPUT_NAME "test.tar.gz")
 
-set(COMPRESSION_FLAGS cvzf)
+set(COMPRESSION_FLAGS -cvzf)
 set(COMPRESSION_OPTIONS --format=gnutar)
 
-set(DECOMPRESSION_FLAGS xvzf)
+set(DECOMPRESSION_FLAGS -xvzf)
 
 include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
 
diff --git a/Tests/RunCMake/CommandLineTar/pax.cmake b/Tests/RunCMake/CommandLineTar/pax.cmake
index 60ed238..77f74d1 100644
--- a/Tests/RunCMake/CommandLineTar/pax.cmake
+++ b/Tests/RunCMake/CommandLineTar/pax.cmake
@@ -1,9 +1,9 @@
 set(OUTPUT_NAME "test.tar")
 
-set(COMPRESSION_FLAGS cvf)
+set(COMPRESSION_FLAGS -cvf)
 set(COMPRESSION_OPTIONS --format=pax)
 
-set(DECOMPRESSION_FLAGS xvf)
+set(DECOMPRESSION_FLAGS -xvf)
 
 include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
 
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output b/Tests/RunCMake/CommandLineTar/test-file.txt
similarity index 100%
copy from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output
copy to Tests/RunCMake/CommandLineTar/test-file.txt
diff --git a/Tests/RunCMake/CommandLineTar/without-files-stderr.txt b/Tests/RunCMake/CommandLineTar/without-files-stderr.txt
new file mode 100644
index 0000000..70166f5
--- /dev/null
+++ b/Tests/RunCMake/CommandLineTar/without-files-stderr.txt
@@ -0,0 +1 @@
+^tar: No files or directories specified
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake
new file mode 100644
index 0000000..f5f5c8c
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake
@@ -0,0 +1,21 @@
+# Prepare environment and variables
+set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH FALSE)
+if(WIN32)
+    set(ENV{CMAKE_PREFIX_PATH} "C:\\baz")
+    set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}\\pc-bletch\\lib\\pkgconfig;X:\\this\\directory\\should\\not\\exist\\in\\the\\filesystem")
+else()
+    set(ENV{CMAKE_PREFIX_PATH} "/baz")
+    set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/pc-bletch/lib/pkgconfig:/this/directory/should/not/exist/in/the/filesystem")
+endif()
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(BLETCH QUIET bletch)
+
+if (NOT BLETCH_FOUND)
+  message(FATAL_ERROR "Failed to find embedded package bletch via PKG_CONFIG_PATH")
+endif ()
+
+pkg_get_variable(bletchvar bletch jackpot)
+if (NOT bletchvar STREQUAL "bletch-lives")
+  message(FATAL_ERROR "Failed to fetch variable jackpot from embedded package bletch via PKG_CONFIG_PATH")
+endif ()
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake
new file mode 100644
index 0000000..cfc0760
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake
@@ -0,0 +1,21 @@
+# Prepare environment and variables
+set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH TRUE)
+if(WIN32)
+    set(ENV{CMAKE_PREFIX_PATH} "${CMAKE_CURRENT_SOURCE_DIR}\\pc-bletch;X:\\this\\directory\\should\\not\\exist\\in\\the\\filesystem")
+    set(ENV{PKG_CONFIG_PATH} "C:\\baz")
+else()
+    set(ENV{CMAKE_PREFIX_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/pc-bletch:/this/directory/should/not/exist/in/the/filesystem")
+    set(ENV{PKG_CONFIG_PATH} "/baz")
+endif()
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(BLETCH QUIET bletch)
+
+if (NOT BLETCH_FOUND)
+  message(FATAL_ERROR "Failed to find embedded package bletch via CMAKE_PREFIX_PATH")
+endif ()
+
+pkg_get_variable(bletchvar bletch jackpot)
+if (NOT bletchvar STREQUAL "bletch-lives")
+  message(FATAL_ERROR "Failed to fetch variable jackpot from embedded package bletch via CMAKE_PREFIX_PATH")
+endif ()
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
index 24e7202..e82b05f 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
@@ -109,3 +109,24 @@
 if (NOT FakePackage2_LINK_LIBRARIES STREQUAL "${fakePkgDir}/lib/libcmakeinternalfakepackage2.a")
   message(FATAL_ERROR "FakePackage2_LINK_LIBRARIES has bad content on second run: ${FakePackage2_LINK_LIBRARIES}")
 endif()
+
+set(pname fakelinkoptionspackage)
+file(WRITE ${fakePkgDir}/lib/pkgconfig/${pname}.pc
+"Name: FakeLinkOptionsPackage
+Description: Dummy package for FindPkgConfig IMPORTED_TARGET INTERFACE_LINK_OPTIONS test
+Version: 1.2.3
+Libs: -e dummy_main
+")
+
+set(expected_link_options -e dummy_main)
+pkg_check_modules(FakeLinkOptionsPackage REQUIRED QUIET IMPORTED_TARGET fakelinkoptionspackage)
+if (NOT TARGET PkgConfig::FakeLinkOptionsPackage)
+  message(FATAL_ERROR "No import target for fake link options package")
+endif()
+get_target_property(link_options PkgConfig::FakeLinkOptionsPackage INTERFACE_LINK_OPTIONS)
+if (NOT link_options STREQUAL expected_link_options)
+  message(FATAL_ERROR
+    "Additional link options not present in INTERFACE_LINK_OPTIONS property"
+    "expected: \"${expected_link_options}\", but got \"${link_options}\""
+  )
+endif()
diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
index 671ff51..414d9b6 100644
--- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
@@ -14,6 +14,8 @@
 find_package(PkgConfig)
 if (PKG_CONFIG_FOUND)
   run_cmake(FindPkgConfig_GET_VARIABLE)
+  run_cmake(FindPkgConfig_GET_VARIABLE_PREFIX_PATH)
+  run_cmake(FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH)
   run_cmake(FindPkgConfig_cache_variables)
   run_cmake(FindPkgConfig_IMPORTED_TARGET)
   run_cmake(FindPkgConfig_VERSION_OPERATORS)
diff --git a/Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc b/Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc
new file mode 100644
index 0000000..04d2c1b
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc
@@ -0,0 +1,12 @@
+prefix=/opt/bletch
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+jackpot=bletch-lives
+
+Name: Bletch
+Description: Dummy packaget to test variable support
+Version: 1.0
+Libs: -L${libdir} -lbletch
+Cflags: -Dbletch_version=1
diff --git a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt
index 8d3c4cc..a08e7b2 100644
--- a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt
@@ -15,3 +15,12 @@
   "Relative/Path" is not an absolute path.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
++
+CMake Error at BadSHELL_PATH.cmake:[0-9]+ \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<SHELL_PATH:;>
+
+  "" is not an absolute path.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake
index 5eff7bc..0e7c342 100644
--- a/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake
+++ b/Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake
@@ -1,4 +1,5 @@
 add_custom_target(check ALL COMMAND check
   $<SHELL_PATH:>
   $<SHELL_PATH:Relative/Path>
+  "$<SHELL_PATH:;>"
   VERBATIM)
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake
new file mode 100644
index 0000000..605ae4d
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content)
+
+set(expected "DO_NOT_FILTER_THIS;thisisanitem")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake
new file mode 100644
index 0000000..b879be2
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake
@@ -0,0 +1,4 @@
+cmake_policy(VERSION 3.11)
+
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:${mylist},EXCLUDE,^FILTER_THIS_.+>")
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake
new file mode 100644
index 0000000..9d48d98
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content)
+
+set(expected "FILTER_THIS_BIT;FILTER_THIS_THING")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake
new file mode 100644
index 0000000..5e0260a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake
@@ -0,0 +1,4 @@
+cmake_policy(VERSION 3.11)
+
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:${mylist},INCLUDE,^FILTER_THIS_.+>")
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt
new file mode 100644
index 0000000..dd10925
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at FILTER-InvalidOperator.cmake:3 \(file\):
+  Error evaluating generator expression:
+
+    \$<FILTER:,RM,>
+
+  \$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake
new file mode 100644
index 0000000..26f3917
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,RM,>")
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake
new file mode 100644
index 0000000..2844484
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content)
+
+set(expected "")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake
new file mode 100644
index 0000000..e0fc671
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,INCLUDE,>")
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME-stderr.txt b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME-stderr.txt
new file mode 100644
index 0000000..783bfb3
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at ImportedTarget-TARGET_PDB_OUTPUT_NAME.cmake:2 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<TARGET_PDB_OUTPUT_NAME:empty>
+
+  TARGET_PDB_OUTPUT_NAME not allowed for IMPORTED targets.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME.cmake b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME.cmake
new file mode 100644
index 0000000..010b38e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_OUTPUT_NAME.cmake
@@ -0,0 +1,2 @@
+add_library(empty UNKNOWN IMPORTED)
+add_custom_target(custom COMMAND echo $<TARGET_PDB_OUTPUT_NAME:empty>)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME-stderr.txt
new file mode 100644
index 0000000..00ec496
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at NonValidCompiler-TARGET_PDB_OUTPUT_NAME.cmake:6 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_PDB_OUTPUT_NAME:empty>
+
+  TARGET_PDB_OUTPUT_NAME is not supported by the target linker.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME.cmake b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME.cmake
new file mode 100644
index 0000000..07951de
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_OUTPUT_NAME.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(empty STATIC empty.c)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_PDB_OUTPUT_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME-stderr.txt
new file mode 100644
index 0000000..8ac349e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-TARGET_PDB_OUTPUT_NAME.cmake:6 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_PDB_OUTPUT_NAME:empty>
+
+  TARGET_PDB_OUTPUT_NAME is allowed only for targets with linker created
+  artifacts.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME.cmake b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME.cmake
new file mode 100644
index 0000000..07951de
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_OUTPUT_NAME.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(empty STATIC empty.c)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_PDB_OUTPUT_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
index bf592e7..013c4f2 100644
--- a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
@@ -1,4 +1,10 @@
 CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\):
-  Target 'empty1' OUTPUT_NAME depends on itself.
+  Target 'empty2' OUTPUT_NAME depends on itself.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\):
+  Target 'empty2' OUTPUT_NAME depends on itself.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
index 5cb8050..775f68a 100644
--- a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
@@ -1,3 +1,6 @@
 enable_language(C)
 add_executable(empty1 empty.c)
 set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>)
+
+add_executable(empty2 empty.c)
+set_property(TARGET empty2 PROPERTY OUTPUT_NAME $<TARGET_OUTPUT_NAME:empty2>)
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake
new file mode 100644
index 0000000..e127711
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "1")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake
new file mode 100644
index 0000000..53934af
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:1>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake
new file mode 100644
index 0000000..e127711
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "1")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake
new file mode 100644
index 0000000..a8aca6e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:1$<SEMICOLON>1>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake
new file mode 100644
index 0000000..e3055ce
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "2;1")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake
new file mode 100644
index 0000000..ee2dd3e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:2$<SEMICOLON>1>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake
new file mode 100644
index 0000000..e3055ce
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "2;1")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake
new file mode 100644
index 0000000..557bc28
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:2$<SEMICOLON>1$<SEMICOLON>2>")
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake
new file mode 100644
index 0000000..f779d48
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake
@@ -0,0 +1,6 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/REMOVE_DUPLICATES-generated.txt" content)
+
+set(expected "")
+if(NOT content STREQUAL expected)
+  set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake
new file mode 100644
index 0000000..3b9d674
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake
@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "REMOVE_DUPLICATES-generated.txt" CONTENT "$<REMOVE_DUPLICATES:>")
diff --git a/Tests/RunCMake/GeneratorExpression/ResultValidator.cmake b/Tests/RunCMake/GeneratorExpression/ResultValidator.cmake
new file mode 100644
index 0000000..722ae05
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ResultValidator.cmake
@@ -0,0 +1,6 @@
+
+function (CHECK_VALUE test_msg value expected)
+  if (NOT value STREQUAL expected)
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [[${value}]]\nbut expected:\n [[${expected}]]\n")
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 8a5604c..0b0fb78 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -33,6 +33,18 @@
 run_cmake(COMPILE_LANGUAGE-unknown-lang)
 run_cmake(TARGET_FILE-recursion)
 run_cmake(OUTPUT_NAME-recursion)
+run_cmake(TARGET_FILE_PREFIX)
+run_cmake(TARGET_FILE_PREFIX-imported-target)
+run_cmake(TARGET_FILE_PREFIX-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_PREFIX-non-valid-target)
+run_cmake(TARGET_FILE_SUFFIX)
+run_cmake(TARGET_FILE_SUFFIX-imported-target)
+run_cmake(TARGET_FILE_SUFFIX-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_SUFFIX-non-valid-target)
+run_cmake(TARGET_OUTPUT_NAME)
+run_cmake(TARGET_OUTPUT_NAME-imported-target)
+run_cmake(TARGET_OUTPUT_NAME-non-valid-target)
+run_cmake(TARGET_LINKER_OUTPUT_NAME-non-valid-target)
 run_cmake(TARGET_PROPERTY-LOCATION)
 run_cmake(TARGET_PROPERTY-SOURCES)
 run_cmake(LINK_ONLY-not-linking)
@@ -53,15 +65,28 @@
 run_cmake(GENEX_EVAL-recursion1)
 run_cmake(GENEX_EVAL-recursion2)
 run_cmake(GENEX_EVAL)
+run_cmake(REMOVE_DUPLICATES-empty)
+run_cmake(REMOVE_DUPLICATES-1)
+run_cmake(REMOVE_DUPLICATES-2)
+run_cmake(REMOVE_DUPLICATES-3)
+run_cmake(REMOVE_DUPLICATES-4)
+run_cmake(FILTER-empty)
+run_cmake(FILTER-InvalidOperator)
+run_cmake(FILTER-Exclude)
+run_cmake(FILTER-Include)
 
 run_cmake(ImportedTarget-TARGET_BUNDLE_DIR)
 run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR)
 run_cmake(ImportedTarget-TARGET_PDB_FILE)
+run_cmake(ImportedTarget-TARGET_PDB_OUTPUT_NAME)
 if(LINKER_SUPPORTS_PDB)
   run_cmake(NonValidTarget-TARGET_PDB_FILE)
   run_cmake(ValidTarget-TARGET_PDB_FILE)
+  run_cmake(NonValidTarget-TARGET_PDB_OUTPUT_NAME)
+  run_cmake(ValidTarget-TARGET_PDB_OUTPUT_NAME)
 else()
   run_cmake(NonValidCompiler-TARGET_PDB_FILE)
+  run_cmake(NonValidCompiler-TARGET_PDB_OUTPUT_NAME)
 endif()
 
 set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=OLD)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake
new file mode 100644
index 0000000..676ad4b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake
new file mode 100644
index 0000000..676ad4b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake
new file mode 100644
index 0000000..34e500a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable(exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable default\" \"$<TARGET_FILE_PREFIX:exec1>\" \"\")
+check_value (\"TARGET_FILE_PREFIX shared default\" \"$<TARGET_FILE_PREFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker default\" \"$<TARGET_LINKER_FILE_PREFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_PREFIX},${CMAKE_SHARED_LIBRARY_PREFIX}>\")
+check_value (\"TARGET_FILE_PREFIX static default\" \"$<TARGET_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker default\" \"$<TARGET_LINKER_FILE_PREFIX:static1>\"  \"${CMAKE_STATIC_LIBRARY_PREFIX}\")\n")
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY PREFIX exec2_prefix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_PREFIX exec2_import_prefix)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY PREFIX shared2_prefix)
+set_property (TARGET shared2 PROPERTY IMPORT_PREFIX shared2_import_prefix)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY PREFIX static2_prefix)
+set_property (TARGET static2 PROPERTY IMPORT_PREFIX static2_import_prefix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable custom\" \"$<TARGET_FILE_PREFIX:exec2>\" \"exec2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX executable linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_prefix,exec2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX shared custom\" \"$<TARGET_FILE_PREFIX:shared2>\" \"shared2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_prefix,shared2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX static custom\" \"$<TARGET_FILE_PREFIX:static2>\" \"static2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:static2>\" \"static2_prefix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..81362ef
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_PREFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_FILE_PREFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake
new file mode 100644
index 0000000..d1095fa
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_FILE_PREFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake
new file mode 100644
index 0000000..6bb1e44
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable default\" \"$<TARGET_FILE_PREFIX:exec1>\" \"\")
+check_value (\"TARGET_FILE_PREFIX shared default\" \"$<TARGET_FILE_PREFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker default\" \"$<TARGET_LINKER_FILE_PREFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_PREFIX},${CMAKE_SHARED_LIBRARY_PREFIX}>\")
+check_value (\"TARGET_FILE_PREFIX static default\" \"$<TARGET_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker default\" \"$<TARGET_LINKER_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")\n")
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY PREFIX exec2_prefix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_PREFIX exec2_import_prefix)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY PREFIX shared2_prefix)
+set_property (TARGET shared2 PROPERTY IMPORT_PREFIX shared2_import_prefix)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY PREFIX static2_prefix)
+set_property (TARGET static2 PROPERTY IMPORT_PREFIX static2_import_prefix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable custom\" \"$<TARGET_FILE_PREFIX:exec2>\" \"exec2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX executable linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_prefix,exec2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX shared custom\" \"$<TARGET_FILE_PREFIX:shared2>\" \"shared2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_prefix,shared2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX static custom\" \"$<TARGET_FILE_PREFIX:static2>\" \"static2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:static2>\" \"static2_prefix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake
new file mode 100644
index 0000000..f159370
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake
new file mode 100644
index 0000000..f159370
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake
new file mode 100644
index 0000000..e1b7654
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable default\" \"$<TARGET_FILE_SUFFIX:exec1>\" \"${CMAKE_EXECUTABLE_SUFFIX}\")
+check_value (\"TARGET_FILE_SUFFIX shared default\" \"$<TARGET_FILE_SUFFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_SUFFIX},${CMAKE_SHARED_LIBRARY_SUFFIX}>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n")
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY SUFFIX exec2_suffix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_SUFFIX exec2_import_suffix)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY SUFFIX shared2_suffix)
+set_property (TARGET shared2 PROPERTY IMPORT_SUFFIX shared2_import_suffix)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY SUFFIX static2_suffix)
+set_property (TARGET static2 PROPERTY IMPORT_SUFFIX static2_import_suffix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable custom\" \"$<TARGET_FILE_SUFFIX:exec2>\" \"exec2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX executable linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_suffix,exec2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX shared custom\" \"$<TARGET_FILE_SUFFIX:shared2>\" \"shared2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_suffix,shared2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX static custom\" \"$<TARGET_FILE_SUFFIX:static2>\" \"static2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:static2>\" \"static2_suffix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..9ea09d1
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_SUFFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_FILE_SUFFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake
new file mode 100644
index 0000000..f7089f9
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_FILE_SUFFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake
new file mode 100644
index 0000000..78afecd
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable default\" \"$<TARGET_FILE_SUFFIX:exec1>\" \"${CMAKE_EXECUTABLE_SUFFIX}\")
+check_value (\"TARGET_FILE_SUFFIX shared default\" \"$<TARGET_FILE_SUFFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_SUFFIX},${CMAKE_SHARED_LIBRARY_SUFFIX}>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n")
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY SUFFIX exec2_suffix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_SUFFIX exec2_import_suffix)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY SUFFIX shared2_suffix)
+set_property (TARGET shared2 PROPERTY IMPORT_SUFFIX shared2_import_suffix)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY SUFFIX static2_suffix)
+set_property (TARGET static2 PROPERTY IMPORT_SUFFIX static2_import_suffix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable custom\" \"$<TARGET_FILE_SUFFIX:exec2>\" \"exec2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX executable linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_suffix,exec2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX shared custom\" \"$<TARGET_FILE_SUFFIX:shared2>\" \"shared2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_suffix,shared2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX static custom\" \"$<TARGET_FILE_SUFFIX:static2>\" \"static2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:static2>\" \"static2_suffix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..7a36cef
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_LINKER_FILE_PREFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake
new file mode 100644
index 0000000..8dad4da
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_LINKER_FILE_PREFIX:empty>]"
+)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..cc5217a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_LINKER_FILE_SUFFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake
new file mode 100644
index 0000000..82c2f3a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_LINKER_FILE_SUFFIX:empty>]"
+)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt
new file mode 100644
index 0000000..0e09469
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_LINKER_OUTPUT_NAME:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake
new file mode 100644
index 0000000..c439535
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_LINKER_OUTPUT_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-check.cmake
new file mode 100644
index 0000000..fa4f2b9
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_OUTPUT_NAME-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-imported-target-check.cmake
new file mode 100644
index 0000000..fa4f2b9
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_OUTPUT_NAME-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-imported-target.cmake
new file mode 100644
index 0000000..548a2d7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-imported-target.cmake
@@ -0,0 +1,79 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable(exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_OUTPUT_NAME executable default" "$<TARGET_OUTPUT_NAME:exec1>" "exec1")
+check_value ("TARGET_OUTPUT_NAME shared default" "$<TARGET_OUTPUT_NAME:shared1>" "shared1")
+check_value ("TARGET_LINKER_OUTPUT_NAME shared linker default" "$<TARGET_LINKER_OUTPUT_NAME:shared1>" "shared1")
+check_value ("TARGET_OUTPUT_NAME static default" "$<TARGET_OUTPUT_NAME:static1>" "static1")
+check_value ("TARGET_LINKER_OUTPUT_NAME static linker default" "$<TARGET_LINKER_OUTPUT_NAME:static1>" "static1")
+]])
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY OUTPUT_NAME exec2_custom)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY OUTPUT_NAME shared2_custom)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY OUTPUT_NAME static2_custom)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_OUTPUT_NAME executable custom" "$<TARGET_OUTPUT_NAME:exec2>" "exec2_custom")
+check_value ("TARGET_OUTPUT_NAME shared custom" "$<TARGET_OUTPUT_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_LINKER_OUTPUT_NAME shared linker custom" "$<TARGET_LINKER_OUTPUT_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_OUTPUT_NAME static custom" "$<TARGET_OUTPUT_NAME:static2>" "static2_custom")
+check_value ("TARGET_LINKER_OUTPUT_NAME static linker custom" "$<TARGET_LINKER_OUTPUT_NAME:static2>" "static2_custom")
+]])
+
+
+add_executable (exec3 IMPORTED)
+set_property (TARGET exec3 PROPERTY RUNTIME_OUTPUT_NAME exec3_runtime)
+set_property (TARGET exec3 PROPERTY LIBRARY_OUTPUT_NAME exec3_library)
+set_property (TARGET exec3 PROPERTY ARCHIVE_OUTPUT_NAME exec3_archive)
+set_property (TARGET exec3 PROPERTY PDB_NAME exec3_pdb)
+add_library (shared3 SHARED IMPORTED)
+set_property (TARGET shared3 PROPERTY RUNTIME_OUTPUT_NAME shared3_runtime)
+set_property (TARGET shared3 PROPERTY LIBRARY_OUTPUT_NAME shared3_library)
+set_property (TARGET shared3 PROPERTY ARCHIVE_OUTPUT_NAME shared3_archive)
+set_property (TARGET shared3 PROPERTY PDB_NAME shared3_pdb)
+add_library (static3 STATIC IMPORTED)
+set_property (TARGET static3 PROPERTY RUNTIME_OUTPUT_NAME static3_runtime)
+set_property (TARGET static3 PROPERTY LIBRARY_OUTPUT_NAME static3_library)
+set_property (TARGET static3 PROPERTY ARCHIVE_OUTPUT_NAME static3_archive)
+set_property (TARGET static3 PROPERTY PDB_NAME static3_pdb)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_OUTPUT_NAME executable all properties" "$<TARGET_OUTPUT_NAME:exec3>" "exec3_runtime")
+check_value ("TARGET_OUTPUT_NAME shared all properties" "$<TARGET_OUTPUT_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_runtime,shared3_library>")
+check_value ("TARGET_LINKER_OUTPUT_NAME shared linker all properties" "$<TARGET_LINKER_OUTPUT_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_archive,shared3_library>")
+check_value ("TARGET_OUTPUT_NAME static all properties" "$<TARGET_OUTPUT_NAME:static3>" "static3_archive")
+check_value ("TARGET_LINKER_OUTPUT_NAME static linker all properties" "$<TARGET_LINKER_OUTPUT_NAME:static3>" "static3_archive")
+]])
+
+
+unset(GENERATE_CONDITION)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG)
+  set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>)
+endif()
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_OUTPUT_NAME-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}" ${GENERATE_CONDITION})
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-result.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt
new file mode 100644
index 0000000..9672a99
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_OUTPUT_NAME-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_OUTPUT_NAME:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake
new file mode 100644
index 0000000..5248dfa
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_OUTPUT_NAME:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME.cmake
new file mode 100644
index 0000000..b7bae15
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME.cmake
@@ -0,0 +1,96 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_OUTPUT_NAME executable default" "$<TARGET_OUTPUT_NAME:exec1>" "exec1")
+check_value ("TARGET_OUTPUT_NAME shared default" "$<TARGET_OUTPUT_NAME:shared1>" "shared1")
+check_value ("TARGET_LINKER_OUTPUT_NAME shared linker default" "$<TARGET_LINKER_OUTPUT_NAME:shared1>" "shared1")
+check_value ("TARGET_OUTPUT_NAME static default" "$<TARGET_OUTPUT_NAME:static1>" "static1")
+check_value ("TARGET_LINKER_OUTPUT_NAME static linker default" "$<TARGET_LINKER_OUTPUT_NAME:static1>" "static1")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+  string(APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_OUTPUT_NAME executable PDB default" "$<TARGET_PDB_OUTPUT_NAME:exec1>" "exec1")
+check_value ("TARGET_PDB_OUTPUT_NAME shared PDB default" "$<TARGET_PDB_OUTPUT_NAME:shared1>" "shared1")
+]])
+endif()
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY OUTPUT_NAME exec2_custom)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY OUTPUT_NAME shared2_custom)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY OUTPUT_NAME static2_custom)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_OUTPUT_NAME executable custom" "$<TARGET_OUTPUT_NAME:exec2>" "exec2_custom")
+check_value ("TARGET_OUTPUT_NAME shared custom" "$<TARGET_OUTPUT_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_LINKER_OUTPUT_NAME shared linker custom" "$<TARGET_LINKER_OUTPUT_NAME:shared2>" "shared2_custom")
+check_value ("TARGET_OUTPUT_NAME static custom" "$<TARGET_OUTPUT_NAME:static2>" "static2_custom")
+check_value ("TARGET_LINKER_OUTPUT_NAME static linker custom" "$<TARGET_LINKER_OUTPUT_NAME:static2>" "static2_custom")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+  string (APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_OUTPUT_NAME executable PDB custom" "$<TARGET_PDB_OUTPUT_NAME:exec2>" "exec2_custom")
+check_value ("TARGET_PDB_OUTPUT_NAME shared PDB custom" "$<TARGET_PDB_OUTPUT_NAME:shared2>" "shared2_custom")
+  ]])
+endif()
+
+add_executable (exec3 empty.c)
+set_property (TARGET exec3 PROPERTY RUNTIME_OUTPUT_NAME exec3_runtime)
+set_property (TARGET exec3 PROPERTY LIBRARY_OUTPUT_NAME exec3_library)
+set_property (TARGET exec3 PROPERTY ARCHIVE_OUTPUT_NAME exec3_archive)
+set_property (TARGET exec3 PROPERTY PDB_NAME exec3_pdb)
+add_library (shared3 SHARED empty.c)
+set_property (TARGET shared3 PROPERTY RUNTIME_OUTPUT_NAME shared3_runtime)
+set_property (TARGET shared3 PROPERTY LIBRARY_OUTPUT_NAME shared3_library)
+set_property (TARGET shared3 PROPERTY ARCHIVE_OUTPUT_NAME shared3_archive)
+set_property (TARGET shared3 PROPERTY PDB_NAME shared3_pdb)
+add_library (static3 STATIC empty.c)
+set_property (TARGET static3 PROPERTY RUNTIME_OUTPUT_NAME static3_runtime)
+set_property (TARGET static3 PROPERTY LIBRARY_OUTPUT_NAME static3_library)
+set_property (TARGET static3 PROPERTY ARCHIVE_OUTPUT_NAME static3_archive)
+set_property (TARGET static3 PROPERTY PDB_NAME static3_pdb)
+
+string (APPEND GENERATE_CONTENT [[
+
+check_value ("TARGET_OUTPUT_NAME executable all properties" "$<TARGET_OUTPUT_NAME:exec3>" "exec3_runtime")
+check_value ("TARGET_OUTPUT_NAME shared all properties" "$<TARGET_OUTPUT_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_runtime,shared3_library>")
+check_value ("TARGET_LINKER_OUTPUT_NAME shared linker all properties" "$<TARGET_LINKER_OUTPUT_NAME:shared3>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared3_archive,shared3_library>")
+check_value ("TARGET_OUTPUT_NAME static all properties" "$<TARGET_OUTPUT_NAME:static3>" "static3_archive")
+check_value ("TARGET_LINKER_OUTPUT_NAME static linker all properties" "$<TARGET_LINKER_OUTPUT_NAME:static3>" "static3_archive")
+]])
+if (CMAKE_C_LINKER_SUPPORTS_PDB)
+  string (APPEND GENERATE_CONTENT [[
+check_value ("TARGET_PDB_OUTPUT_NAME executable PDB all properties" "$<TARGET_PDB_OUTPUT_NAME:exec3>" "exec3_pdb")
+check_value ("TARGET_PDB_OUTPUT_NAME shared PDB all properties" "$<TARGET_PDB_OUTPUT_NAME:shared3>" "shared3_pdb")
+]])
+endif()
+
+
+unset(GENERATE_CONDITION)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG)
+  set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>)
+endif()
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_OUTPUT_NAME-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}" ${GENERATE_CONDITION})
diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_OUTPUT_NAME-check.cmake b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_OUTPUT_NAME-check.cmake
new file mode 100644
index 0000000..8d1103e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_OUTPUT_NAME-check.cmake
@@ -0,0 +1,7 @@
+file(STRINGS ${RunCMake_TEST_BINARY_DIR}/test.txt TEST_TXT ENCODING UTF-8)
+
+list(GET TEST_TXT 0 PDB_OUTPUT_NAME)
+
+if(NOT PDB_OUTPUT_NAME MATCHES "empty")
+  set(RunCMake_TEST_FAILED "unexpected PDB_OUTPUT_NAME [${PDB_OUTPUT_NAME}]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_OUTPUT_NAME.cmake b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_OUTPUT_NAME.cmake
new file mode 100644
index 0000000..ba70b43
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_OUTPUT_NAME.cmake
@@ -0,0 +1,16 @@
+
+enable_language(C)
+
+add_library(empty SHARED empty.c)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG)
+  set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>)
+endif()
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "$<TARGET_PDB_OUTPUT_NAME:empty>"
+  ${GENERATE_CONDITION}
+)
diff --git a/Tests/RunCMake/MetaCompileFeatures/C.cmake b/Tests/RunCMake/MetaCompileFeatures/C.cmake
new file mode 100644
index 0000000..3bb6181
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/C.cmake
@@ -0,0 +1,27 @@
+
+enable_language(C)
+
+function(check_language_feature_flags lang level)
+  if(CMAKE_${lang}${level}_STANDARD_COMPILE_OPTION)
+    #this property is an internal implementation detail of CMake
+    get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+    list(LENGTH known_features len)
+    if(len LESS 1)
+      message(FATAL_ERROR "unable to find known features of ${lang}${level}")
+    endif()
+
+    string(TOLOWER ${lang} lang_lower)
+    set(known_name ${lang_lower}${level}_known_features)
+    set(meta_name  ${lang_lower}${level}_meta_feature)
+
+    add_library(${known_name} STATIC a.c)
+    target_compile_features(${known_name} PUBLIC ${known_features})
+    add_library(${meta_name} STATIC a.c)
+    target_compile_features(${meta_name} PUBLIC ${lang_lower}_std_${level})
+  endif()
+endfunction()
+
+
+check_language_feature_flags(C 90)
+check_language_feature_flags(C 99)
+check_language_feature_flags(C 11)
diff --git a/Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt b/Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt
new file mode 100644
index 0000000..3e470a2
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MetaCompileFeatures/CXX.cmake b/Tests/RunCMake/MetaCompileFeatures/CXX.cmake
new file mode 100644
index 0000000..ef3b9d4
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/CXX.cmake
@@ -0,0 +1,27 @@
+
+enable_language(CXX)
+
+function(check_language_feature_flags lang level)
+  if(CMAKE_${lang}${level}_STANDARD_COMPILE_OPTION)
+    #this property is an internal implementation detail of CMake
+    get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+    list(LENGTH known_features len)
+    if(len LESS 1)
+      message(FATAL_ERROR "unable to find known features of ${lang}${level}")
+    endif()
+
+    string(TOLOWER ${lang} lang_lower)
+    set(known_name ${lang_lower}${level}_known_features)
+    set(meta_name  ${lang_lower}${level}_meta_feature)
+
+    add_library(${known_name} STATIC a.cxx)
+    target_compile_features(${known_name} PUBLIC ${known_features})
+    add_library(${meta_name} STATIC a.cxx)
+    target_compile_features(${meta_name} PUBLIC ${lang_lower}_std_${level})
+  endif()
+endfunction()
+
+
+check_language_feature_flags(CXX 98)
+check_language_feature_flags(CXX 11)
+check_language_feature_flags(CXX 14)
diff --git a/Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake
new file mode 100644
index 0000000..009cde4
--- /dev/null
+++ b/Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(RunCMake)
+
+run_cmake(C)
+run_cmake(CXX)
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output b/Tests/RunCMake/MetaCompileFeatures/a.c
similarity index 100%
copy from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output
copy to Tests/RunCMake/MetaCompileFeatures/a.c
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output b/Tests/RunCMake/MetaCompileFeatures/a.cxx
similarity index 100%
copy from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output
copy to Tests/RunCMake/MetaCompileFeatures/a.cxx
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake b/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake
index a39a529..b495d98 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake
@@ -10,6 +10,7 @@
 #
 set(targets
   aix-C-XL-13.1.3 aix-CXX-XL-13.1.3
+  aix-C-XLClang-16.1.0.1 aix-CXX-XLClang-16.1.0.1
   craype-C-Cray-8.7 craype-CXX-Cray-8.7 craype-Fortran-Cray-8.7
   craype-C-GNU-7.3.0 craype-CXX-GNU-7.3.0 craype-Fortran-GNU-7.3.0
   craype-C-Intel-18.0.2.20180210 craype-CXX-Intel-18.0.2.20180210
@@ -17,8 +18,9 @@
   darwin-C-AppleClang-8.0.0.8000042 darwin-CXX-AppleClang-8.0.0.8000042
     darwin_nostdinc-C-AppleClang-8.0.0.8000042
     darwin_nostdinc-CXX-AppleClang-8.0.0.8000042
-  empty-C empty-CXX
   freebsd-C-Clang-3.3.0 freebsd-CXX-Clang-3.3.0 freebsd-Fortran-GNU-4.6.4
+  hand-C-empty hand-CXX-empty
+  hand-C-relative hand-CXX-relative
   linux-C-GNU-7.3.0 linux-CXX-GNU-7.3.0 linux-Fortran-GNU-7.3.0
   linux-C-Intel-18.0.0.20170811 linux-CXX-Intel-18.0.0.20170811
   linux-C-PGI-18.10.1 linux-CXX-PGI-18.10.1
@@ -104,12 +106,12 @@
   file(READ ${outfile} output)
   string(STRIP "${output}" output)
   cmake_parse_implicit_include_info("${input}" "${lang}" idirs log state)
-  if(t MATCHES "^empty-")          # empty isn't supposed to parse
+  if(t MATCHES "-empty$")          # empty isn't supposed to parse
     if("${state}" STREQUAL "done")
       message("empty parse failed: ${idirs}, log=${log}")
     endif()
-  elseif(NOT "${state}" STREQUAL "done" OR NOT "${output}" STREQUAL "${idirs}")
-    message("parse failed: state=${state}, ${output} != ${idirs}, log=${log}")
+  elseif(NOT "${state}" STREQUAL "done" OR NOT "${idirs}" MATCHES "^${output}$")
+    message("parse failed: state=${state}, '${idirs}' does not match '^${output}$', log=${log}")
   endif()
   unload_compiler_info("${cmvars}")
 endforeach(t)
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt b/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt
index b854e2e..bffe819 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/CMakeLists.txt
@@ -12,6 +12,9 @@
 #
 
 cmake_minimum_required(VERSION 3.3)
+if(POLICY CMP0089)
+  cmake_policy(SET CMP0089 NEW)
+endif()
 
 set(lngs C CXX)
 set(LANGUAGES "${lngs}" CACHE STRING "List of languages to generate inputs for")
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input
new file mode 100644
index 0000000..2f018e6
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.input
@@ -0,0 +1,40 @@
+CMAKE_LANG=C
+CMAKE_C_COMPILER_ABI=
+CMAKE_C_COMPILER_AR=
+CMAKE_C_COMPILER_ARCHITECTURE_ID=
+CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=
+CMAKE_C_COMPILER_ID=XLClang
+CMAKE_C_COMPILER_LAUNCHER=
+CMAKE_C_COMPILER_LOADED=1
+CMAKE_C_COMPILER_RANLIB=
+CMAKE_C_COMPILER_TARGET=
+CMAKE_C_COMPILER_VERSION=16.1.0.1
+CMAKE_C_COMPILER_VERSION_INTERAL=
+Change Dir: /tmp/ii/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/gmake cmTC_fcf21/fast
+/usr/bin/gmake -f CMakeFiles/cmTC_fcf21.dir/build.make CMakeFiles/cmTC_fcf21.dir/build
+gmake[1]: Entering directory '/tmp/ii/CMakeFiles/CMakeTmp'
+Building C object CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o
+/opt/IBM/xlC/16.1.0/bin/xlclang   -V -o CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o   -c /tmp/CMake/Modules/CMakeCCompilerABI.c
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang
+export XL_ASMOBJFILES=/tmp/xlcASuz87id
+export "XL_DIS=/opt/IBM/xlc/16.1.0/exe/dis -o "CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o" "CMakeCCompilerABI.o""
+/opt/IBM/xlC/16.1.0/exe/xlC2entry -qosvar=aix.7.2 -qalias=ansi -qthreaded -D_THREAD_SAFE -Wno-parentheses -Wno-unused-value -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX50 -D_AIX51 -D_AIX52 -D_AIX53 -D_AIX61 -D_AIX71 -D_AIX72 -D_IBMR2 -D_POWER -xc -qasm_as=/bin/as -qc_stdinc=/opt/IBM/xlC/16.1.0/include2:/opt/IBM/xlC/16.1.0/include2/aix:/opt/IBM/xlmass/9.1.0/include:/usr/include -qvac_include_path=/opt/IBM/xlc/16.1.0/include -oCMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o /tmp/CMake/Modules/CMakeCCompilerABI.c /tmp/xlcW0tZ87ia /tmp/xlcW1ub87ib /dev/null /tmp/xlcLu487ieF.lst /dev/null /tmp/xlcW2uj87ic
+export XL_BACKEND=/opt/IBM/xlc/16.1.0/exe/xlCcode
+export XL_LINKER=/bin/ld
+/opt/IBM/xlc/16.1.0/exe/xlCcode -qalias=ansi -qthreaded /tmp/xlcW0tZ87ia /tmp/xlcW1ub87ib CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o /tmp/xlcLu487ieB.lst /tmp/xlcW2uj87ic
+rm /tmp/xlcASuz87id
+rm /tmp/xlcLu487ie
+rm /tmp/xlcW0tZ87ia
+rm /tmp/xlcW1ub87ib
+rm /tmp/xlcW2uj87ic
+Linking C executable cmTC_fcf21
+/tmp/CMake/bin/cmake -E cmake_link_script CMakeFiles/cmTC_fcf21.dir/link.txt --verbose=1
+/opt/IBM/xlC/16.1.0/bin/xlclang   -Wl,-bnoipath -Wl,-brtl -V -Wl,-bexpall CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o  -o cmTC_fcf21 -Wl,-blibpath:/usr/lib:/lib
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang
+/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 -bnoipath -brtl -bexpall CMakeFiles/cmTC_fcf21.dir/CMakeCCompilerABI.c.o -o cmTC_fcf21 -blibpath:/usr/lib:/lib -L/opt/IBM/xlmass/9.1.0/lib/aix61 -L/opt/IBM/xlc/16.1.0/lib -lxlopt -lxlipa -lxl -lc -lpthreads
+rm /tmp/xlcW0vJG7ia
+rm /tmp/xlcW1vNG7ib
+rm /tmp/xlcW2vRG7ic
+gmake[1]: Leaving directory '/tmp/ii/CMakeFiles/CMakeTmp'
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output
new file mode 100644
index 0000000..85399b7
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-C-XLClang-16.1.0.1.output
@@ -0,0 +1 @@
+/opt/IBM/xlC/16.1.0/include2;/opt/IBM/xlC/16.1.0/include2/aix;/opt/IBM/xlmass/9.1.0/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input
new file mode 100644
index 0000000..da16db3
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.input
@@ -0,0 +1,44 @@
+CMAKE_LANG=CXX
+CMAKE_CXX_COMPILER_ABI=
+CMAKE_CXX_COMPILER_AR=
+CMAKE_CXX_COMPILER_ARCHITECTURE_ID=
+CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=
+CMAKE_CXX_COMPILER_ID=XLClang
+CMAKE_CXX_COMPILER_LAUNCHER=
+CMAKE_CXX_COMPILER_LOADED=1
+CMAKE_CXX_COMPILER_RANLIB=
+CMAKE_CXX_COMPILER_TARGET=
+CMAKE_CXX_COMPILER_VERSION=16.1.0.1
+CMAKE_CXX_COMPILER_VERSION_INTERAL=
+Change Dir: /tmp/ii/CMakeFiles/CMakeTmp
+
+Run Build Command(s):/usr/bin/gmake cmTC_b8490/fast
+/usr/bin/gmake -f CMakeFiles/cmTC_b8490.dir/build.make CMakeFiles/cmTC_b8490.dir/build
+gmake[1]: Entering directory '/tmp/ii/CMakeFiles/CMakeTmp'
+Building CXX object CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o
+/opt/IBM/xlC/16.1.0/bin/xlclang++ -x c++   -V -o CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o -c /tmp/CMake/Modules/CMakeCXXCompilerABI.cpp
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang++
+export XL_XLCMP_PATH=/opt/IBM/xlc/16.1.0:/opt/IBM/xlC/16.1.0
+export XL_COMPILER=xlc++
+export XL_ASMOBJFILES=/tmp/xlcAS3IXqid
+export "XL_DIS=/opt/IBM/xlc/16.1.0/exe/dis -o "CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o" "CMakeCXXCompilerABI.o""
+/opt/IBM/xlC/16.1.0/exe/xlC2entry -qosvar=aix.7.2 -qalias=ansi -qthreaded -D_THREAD_SAFE -Wno-parentheses -Wno-unused-value -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX50 -D_AIX51 -D_AIX52 -D_AIX53 -D_AIX61 -D_AIX71 -D_AIX72 -D_IBMR2 -D_POWER -xc++ -qasm_as=/bin/as -qcpp_stdinc=/opt/IBM/xlC/16.1.0/include2/c++:/opt/IBM/xlC/16.1.0/include2:/opt/IBM/xlC/16.1.0/include2/aix:/opt/IBM/xlmass/9.1.0/include:/usr/include -qc_stdinc=/opt/IBM/xlC/16.1.0/include2:/opt/IBM/xlC/16.1.0/include2/aix:/opt/IBM/xlmass/9.1.0/include:/usr/include -oCMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o /tmp/CMake/Modules/CMakeCXXCompilerABI.cpp /tmp/xlcW03uXqia /tmp/xlcW137Xqib /dev/null /tmp/xlcL3QXqieF.lst /dev/null /tmp/xlcW23AXqic
+export XL_BACKEND=/opt/IBM/xlc/16.1.0/exe/xlCcode
+export XL_LINKER=/bin/ld
+/opt/IBM/xlc/16.1.0/exe/xlCcode -qalias=ansi -qthreaded /tmp/xlcW03uXqia /tmp/xlcW137Xqib CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o /tmp/xlcL3QXqieB.lst /tmp/xlcW23AXqic
+rm /tmp/xlcAS3IXqid
+rm /tmp/xlcL3QXqie
+rm /tmp/xlcW03uXqia
+rm /tmp/xlcW137Xqib
+rm /tmp/xlcW23AXqic
+Linking CXX executable cmTC_b8490
+/tmp/CMake/bin/cmake -E cmake_link_script CMakeFiles/cmTC_b8490.dir/link.txt --verbose=1
+/opt/IBM/xlC/16.1.0/bin/xlclang++    -Wl,-bnoipath -Wl,-brtl -V -Wl,-bexpall CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o  -o cmTC_b8490 -Wl,-blibpath:/usr/lib:/lib
+export XL_CONFIG=/opt/IBM/xlc/16.1.0/etc/xlc.cfg.72:xlclang++
+/bin/ld -b32 /lib/crt0.o /lib/crti.o -bpT:0x10000000 -bpD:0x20000000 -bnoipath -brtl -bexpall CMakeFiles/cmTC_b8490.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b8490 -blibpath:/usr/lib:/lib -bcdtors:all:0:s -btmplrename -L/opt/IBM/xlmass/9.1.0/lib/aix61 -L/opt/IBM/xlc/16.1.0/lib -lxlopt -lxlipa -lxl -L/opt/IBM/xlC/16.1.0/lib -lc++ -lCcore -lpthreads -lm -lc  |
+/opt/IBM/xlC/16.1.0/bin/c++filt -S |
+/bin/sed '/317.*::virtual-fn-table-ptr$/ s/^\(.*: \)*{*\([^}]*\)\(}*.*\)::virtual-fn-table-ptr$/\1Virtual table for class "\2": Some possible causes are: first non-inline virtual function in "\2" is not defined or the class is a template instantiation and an explicit instantiation definition of the class is missing./'
+rm /tmp/xlcW05fS7ia
+rm /tmp/xlcW15rS7ib
+rm /tmp/xlcW25vS7ic
+gmake[1]: Leaving directory '/tmp/ii/CMakeFiles/CMakeTmp'
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output
new file mode 100644
index 0000000..7666f7e
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/aix-CXX-XLClang-16.1.0.1.output
@@ -0,0 +1 @@
+/opt/IBM/xlC/16.1.0/include2/c\+\+;/opt/IBM/xlC/16.1.0/include2;/opt/IBM/xlC/16.1.0/include2/aix;/opt/IBM/xlmass/9.1.0/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Cray-8.7.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Cray-8.7.output
index 259c42a..263f8cb 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Cray-8.7.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Cray-8.7.output
@@ -1 +1 @@
-/opt/cray/pe/cce/8.7.4/cce/x86_64/include/craylibs;/opt/gcc/6.1.0/snos/include/g++;/opt/gcc/6.1.0/snos/include/g++/x86_64-suse-linux;/opt/gcc/6.1.0/snos/include/g++/backward;/opt/gcc/6.1.0/snos/lib/gcc/x86_64-suse-linux/6.1.0/include;/opt/gcc/6.1.0/snos/lib/gcc/x86_64-suse-linux/6.1.0/include-fixed;/opt/cray/pe/cce/8.7.4/cce/x86_64/include/c++;/opt/cray/pe/cce/8.7.4/cce/x86_64/include/basic;/opt/gcc/6.1.0/snos/include;/usr/include;/opt/cray/pe/libsci/18.07.1/CRAY/8.6/x86_64/include;/opt/cray/pe/mpt/7.7.3/gni/mpich-cray/8.6/include;/opt/cray/rca/2.2.16-6.0.5.0_15.34__g5e09e6d.ari/include;/opt/cray/alps/6.5.28-6.0.5.0_18.6__g13a91b6.ari/include;/opt/cray/xpmem/2.2.4-6.0.5.1_8.26__g35d5e73.ari/include;/opt/cray/gni-headers/5.0.12-6.0.5.0_2.15__g2ef1ebc.ari/include;/opt/cray/dmapp/7.1.1-6.0.5.0_49.8__g1125556.ari/include;/opt/cray/pe/pmi/5.0.14/include;/opt/cray/ugni/6.0.14-6.0.5.0_16.9__g19583bb.ari/include;/opt/cray/udreg/2.3.2-6.0.5.0_13.12__ga14955a.ari/include;/opt/cray/wlm_detect/1.3.2-6.0.5.0_3.1__g388ccd5.ari/include;/opt/cray/krca/2.2.2-6.0.5.1_13.47__g4614cf3.ari/include;/opt/cray-hss-devel/8.0.0/include
+/opt/cray/pe/cce/8.7.4/cce/x86_64/include/craylibs;/opt/gcc/6.1.0/snos/include/g\+\+;/opt/gcc/6.1.0/snos/include/g\+\+/x86_64-suse-linux;/opt/gcc/6.1.0/snos/include/g\+\+/backward;/opt/gcc/6.1.0/snos/lib/gcc/x86_64-suse-linux/6.1.0/include;/opt/gcc/6.1.0/snos/lib/gcc/x86_64-suse-linux/6.1.0/include-fixed;/opt/cray/pe/cce/8.7.4/cce/x86_64/include/c\+\+;/opt/cray/pe/cce/8.7.4/cce/x86_64/include/basic;/opt/gcc/6.1.0/snos/include;/usr/include;/opt/cray/pe/libsci/18.07.1/CRAY/8.6/x86_64/include;/opt/cray/pe/mpt/7.7.3/gni/mpich-cray/8.6/include;/opt/cray/rca/2.2.16-6.0.5.0_15.34__g5e09e6d.ari/include;/opt/cray/alps/6.5.28-6.0.5.0_18.6__g13a91b6.ari/include;/opt/cray/xpmem/2.2.4-6.0.5.1_8.26__g35d5e73.ari/include;/opt/cray/gni-headers/5.0.12-6.0.5.0_2.15__g2ef1ebc.ari/include;/opt/cray/dmapp/7.1.1-6.0.5.0_49.8__g1125556.ari/include;/opt/cray/pe/pmi/5.0.14/include;/opt/cray/ugni/6.0.14-6.0.5.0_16.9__g19583bb.ari/include;/opt/cray/udreg/2.3.2-6.0.5.0_13.12__ga14955a.ari/include;/opt/cray/wlm_detect/1.3.2-6.0.5.0_3.1__g388ccd5.ari/include;/opt/cray/krca/2.2.2-6.0.5.1_13.47__g4614cf3.ari/include;/opt/cray-hss-devel/8.0.0/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-GNU-7.3.0.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-GNU-7.3.0.output
index d9095f7..b76c5db 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-GNU-7.3.0.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-GNU-7.3.0.output
@@ -1 +1 @@
-/opt/cray/pe/libsci/18.07.1/GNU/7.1/x86_64/include;/opt/cray/pe/mpt/7.7.3/gni/mpich-gnu/7.1/include;/opt/cray/rca/2.2.16-6.0.5.0_15.34__g5e09e6d.ari/include;/opt/cray/alps/6.5.28-6.0.5.0_18.6__g13a91b6.ari/include;/opt/cray/xpmem/2.2.4-6.0.5.1_8.26__g35d5e73.ari/include;/opt/cray/gni-headers/5.0.12-6.0.5.0_2.15__g2ef1ebc.ari/include;/opt/cray/pe/pmi/5.0.14/include;/opt/cray/ugni/6.0.14-6.0.5.0_16.9__g19583bb.ari/include;/opt/cray/udreg/2.3.2-6.0.5.0_13.12__ga14955a.ari/include;/opt/cray/wlm_detect/1.3.2-6.0.5.0_3.1__g388ccd5.ari/include;/opt/cray/krca/2.2.2-6.0.5.1_13.47__g4614cf3.ari/include;/opt/cray-hss-devel/8.0.0/include;/opt/gcc/7.3.0/snos/include/g++;/opt/gcc/7.3.0/snos/include/g++/x86_64-suse-linux;/opt/gcc/7.3.0/snos/include/g++/backward;/opt/gcc/7.3.0/snos/lib/gcc/x86_64-suse-linux/7.3.0/include;/usr/local/include;/opt/gcc/7.3.0/snos/include;/opt/gcc/7.3.0/snos/lib/gcc/x86_64-suse-linux/7.3.0/include-fixed;/usr/include
+/opt/cray/pe/libsci/18.07.1/GNU/7.1/x86_64/include;/opt/cray/pe/mpt/7.7.3/gni/mpich-gnu/7.1/include;/opt/cray/rca/2.2.16-6.0.5.0_15.34__g5e09e6d.ari/include;/opt/cray/alps/6.5.28-6.0.5.0_18.6__g13a91b6.ari/include;/opt/cray/xpmem/2.2.4-6.0.5.1_8.26__g35d5e73.ari/include;/opt/cray/gni-headers/5.0.12-6.0.5.0_2.15__g2ef1ebc.ari/include;/opt/cray/pe/pmi/5.0.14/include;/opt/cray/ugni/6.0.14-6.0.5.0_16.9__g19583bb.ari/include;/opt/cray/udreg/2.3.2-6.0.5.0_13.12__ga14955a.ari/include;/opt/cray/wlm_detect/1.3.2-6.0.5.0_3.1__g388ccd5.ari/include;/opt/cray/krca/2.2.2-6.0.5.1_13.47__g4614cf3.ari/include;/opt/cray-hss-devel/8.0.0/include;/opt/gcc/7.3.0/snos/include/g\+\+;/opt/gcc/7.3.0/snos/include/g\+\+/x86_64-suse-linux;/opt/gcc/7.3.0/snos/include/g\+\+/backward;/opt/gcc/7.3.0/snos/lib/gcc/x86_64-suse-linux/7.3.0/include;/usr/local/include;/opt/gcc/7.3.0/snos/include;/opt/gcc/7.3.0/snos/lib/gcc/x86_64-suse-linux/7.3.0/include-fixed;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Intel-18.0.2.20180210.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Intel-18.0.2.20180210.output
index 31f8a11..031c324 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Intel-18.0.2.20180210.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/craype-CXX-Intel-18.0.2.20180210.output
@@ -1 +1 @@
-/opt/intel/2018.2.199/compilers_and_libraries_2018/linux/mkl/include;/opt/intel/2018.2.199/compilers_and_libraries_2018.2.199/linux/compiler/include/intel64;/opt/intel/2018.2.199/compilers_and_libraries_2018.2.199/linux/compiler/include/icc;/opt/intel/2018.2.199/compilers_and_libraries_2018.2.199/linux/compiler/include;/opt/gcc/6.3.0/snos/include/g++;/opt/gcc/6.3.0/snos/include/g++/x86_64-suse-linux;/opt/gcc/6.3.0/snos/include/g++/backward;/usr/local/include;/opt/gcc/6.3.0/snos/lib/gcc/x86_64-suse-linux/6.3.0/include;/opt/gcc/6.3.0/snos/lib/gcc/x86_64-suse-linux/6.3.0/include-fixed;/opt/gcc/6.3.0/snos/include;/usr/include
+/opt/intel/2018.2.199/compilers_and_libraries_2018/linux/mkl/include;/opt/intel/2018.2.199/compilers_and_libraries_2018.2.199/linux/compiler/include/intel64;/opt/intel/2018.2.199/compilers_and_libraries_2018.2.199/linux/compiler/include/icc;/opt/intel/2018.2.199/compilers_and_libraries_2018.2.199/linux/compiler/include;/opt/gcc/6.3.0/snos/include/g\+\+;/opt/gcc/6.3.0/snos/include/g\+\+/x86_64-suse-linux;/opt/gcc/6.3.0/snos/include/g\+\+/backward;/usr/local/include;/opt/gcc/6.3.0/snos/lib/gcc/x86_64-suse-linux/6.3.0/include;/opt/gcc/6.3.0/snos/lib/gcc/x86_64-suse-linux/6.3.0/include-fixed;/opt/gcc/6.3.0/snos/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/darwin-CXX-AppleClang-8.0.0.8000042.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/darwin-CXX-AppleClang-8.0.0.8000042.output
index b10b2af..de0f91f 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/darwin-CXX-AppleClang-8.0.0.8000042.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/darwin-CXX-AppleClang-8.0.0.8000042.output
@@ -1 +1 @@
-/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1;/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/include;/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include;/usr/include
+/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c\+\+/v1;/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/include;/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-CXX.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-CXX.output
deleted file mode 100644
index e69de29..0000000
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-CXX.output
+++ /dev/null
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/freebsd-CXX-Clang-3.3.0.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/freebsd-CXX-Clang-3.3.0.output
index cd64264..97410f2 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/freebsd-CXX-Clang-3.3.0.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/freebsd-CXX-Clang-3.3.0.output
@@ -1 +1 @@
-/usr/include/c++/v1;/usr/include/c++/4.2;/usr/include/c++/4.2/backward;/usr/include/clang/3.3;/usr/include
+/usr/include/c\+\+/v1;/usr/include/c\+\+/4.2;/usr/include/c\+\+/4.2/backward;/usr/include/clang/3.3;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-empty.input
similarity index 100%
rename from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.input
rename to Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-empty.input
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-empty.output
similarity index 100%
rename from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output
rename to Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-empty.output
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-relative.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-relative.input
new file mode 100644
index 0000000..dd846e3
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-relative.input
@@ -0,0 +1,21 @@
+CMAKE_LANG=C
+CMAKE_C_COMPILER_ABI=ELF
+CMAKE_C_COMPILER_AR=/usr/bin/gcc-ar-7
+CMAKE_C_COMPILER_ARCHITECTURE_ID=
+CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=
+CMAKE_C_COMPILER_ID=GNU
+CMAKE_C_COMPILER_LAUNCHER=
+CMAKE_C_COMPILER_LOADED=1
+CMAKE_C_COMPILER_RANLIB=/usr/bin/gcc-ranlib-7
+CMAKE_C_COMPILER_TARGET=
+CMAKE_C_COMPILER_VERSION=7.3.0
+CMAKE_C_COMPILER_VERSION_INTERAL=
+
+This is a hand-written test case.
+
+#include "..." search starts here:
+#include <...> search starts here:
+ /usr/local/include
+ ../../../adaptive/relative/include
+ /usr/include
+End of search list.
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-relative.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-relative.output
new file mode 100644
index 0000000..e43139b
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-C-relative.output
@@ -0,0 +1 @@
+ /usr/local/include;[^;]*/Tests/RunCMake/ParseImplicitIncludeInfo/adaptive/relative/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-CXX.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-empty.input
similarity index 100%
rename from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-CXX.input
rename to Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-empty.input
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-empty.output
similarity index 100%
copy from Tests/RunCMake/ParseImplicitIncludeInfo/data/empty-C.output
copy to Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-empty.output
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-relative.input b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-relative.input
new file mode 100644
index 0000000..54cc4db
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-relative.input
@@ -0,0 +1,21 @@
+CMAKE_LANG=CXX
+CMAKE_CXX_COMPILER_ABI=ELF
+CMAKE_CXX_COMPILER_AR=/usr/bin/gcc-ar-7
+CMAKE_CXX_COMPILER_ARCHITECTURE_ID=
+CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=
+CMAKE_CXX_COMPILER_ID=GNU
+CMAKE_CXX_COMPILER_LAUNCHER=
+CMAKE_CXX_COMPILER_LOADED=1
+CMAKE_CXX_COMPILER_RANLIB=/usr/bin/gcc-ranlib-7
+CMAKE_CXX_COMPILER_TARGET=
+CMAKE_CXX_COMPILER_VERSION=7.3.0
+CMAKE_CXX_COMPILER_VERSION_INTERAL=
+
+This is a hand-written test case.
+
+#include "..." search starts here:
+#include <...> search starts here:
+ /usr/local/include
+ ../../../adaptive/relative/include
+ /usr/include
+End of search list.
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-relative.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-relative.output
new file mode 100644
index 0000000..e43139b
--- /dev/null
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/hand-CXX-relative.output
@@ -0,0 +1 @@
+ /usr/local/include;[^;]*/Tests/RunCMake/ParseImplicitIncludeInfo/adaptive/relative/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CUDA-NVIDIA-9.2.148.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CUDA-NVIDIA-9.2.148.output
index 4f49cd1..497fb88 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CUDA-NVIDIA-9.2.148.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CUDA-NVIDIA-9.2.148.output
@@ -1 +1 @@
-/usr/include/c++/5;/usr/include/x86_64-linux-gnu/c++/5;/usr/include/c++/5/backward;/usr/lib/gcc/x86_64-linux-gnu/5/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
+/usr/include/c\+\+/5;/usr/include/x86_64-linux-gnu/c\+\+/5;/usr/include/c\+\+/5/backward;/usr/lib/gcc/x86_64-linux-gnu/5/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-GNU-7.3.0.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-GNU-7.3.0.output
index 6f5d071..af33ba8 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-GNU-7.3.0.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-GNU-7.3.0.output
@@ -1 +1 @@
-/usr/include/c++/7;/usr/include/x86_64-linux-gnu/c++/7;/usr/include/c++/7/backward;/usr/lib/gcc/x86_64-linux-gnu/7/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
+/usr/include/c\+\+/7;/usr/include/x86_64-linux-gnu/c\+\+/7;/usr/include/c\+\+/7/backward;/usr/lib/gcc/x86_64-linux-gnu/7/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-Intel-18.0.0.20170811.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-Intel-18.0.0.20170811.output
index 1bf5711..95bdf99 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-Intel-18.0.0.20170811.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-Intel-18.0.0.20170811.output
@@ -1 +1 @@
-/opt/intel/compilers_and_libraries_2018.0.128/linux/ipp/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/mkl/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/pstl/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/tbb/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/include/intel64;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/include/icc;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/include;/usr/include/c++/4.8.5;/usr/include/c++/4.8.5/x86_64-redhat-linux;/usr/include/c++/4.8.5/backward;/usr/local/include;/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include;/usr/include
+/opt/intel/compilers_and_libraries_2018.0.128/linux/ipp/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/mkl/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/pstl/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/tbb/include;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/include/intel64;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/include/icc;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/include;/usr/include/c\+\+/4.8.5;/usr/include/c\+\+/4.8.5/x86_64-redhat-linux;/usr/include/c\+\+/4.8.5/backward;/usr/local/include;/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-PGI-18.10.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-PGI-18.10.1.output
index 8c9d24a..8eb97c8 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-PGI-18.10.1.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-PGI-18.10.1.output
@@ -1 +1 @@
-/mnt/pgi/linux86-64/18.10/include-gcc70;/mnt/pgi/linux86-64/18.10/include;/usr/include/c++/7;/usr/include/x86_64-linux-gnu/c++/7;/usr/include/c++/7/backward;/usr/lib/gcc/x86_64-linux-gnu/7/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
+/mnt/pgi/linux86-64/18.10/include-gcc70;/mnt/pgi/linux86-64/18.10/include;/usr/include/c\+\+/7;/usr/include/x86_64-linux-gnu/c\+\+/7;/usr/include/c\+\+/7/backward;/usr/lib/gcc/x86_64-linux-gnu/7/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-12.1.0.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-12.1.0.output
index a2d8c26..d6d3e58 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-12.1.0.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-12.1.0.output
@@ -1 +1 @@
-/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/include;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/include;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/include;/usr/include/c++/4.4.7;/usr/include/c++/4.4.7/ppc64-redhat-linux;/usr/include/c++/4.4.7/backward;/usr/local/include;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/crt/include;/usr/include
+/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/include;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/include;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/include;/usr/include/c\+\+/4.4.7;/usr/include/c\+\+/4.4.7/ppc64-redhat-linux;/usr/include/c\+\+/4.4.7/backward;/usr/local/include;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/crt/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-16.1.0.0.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-16.1.0.0.output
index 6994f3c..9e118fc 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-16.1.0.0.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux-CXX-XL-16.1.0.0.output
@@ -1 +1 @@
-/opt/ibm/xlsmp/5.1.0/include;/opt/ibm/xlmass/9.1.0/include;/opt/ibm/xlC/16.1.0/include;/usr/include/c++/4.8.5;/usr/include/c++/4.8.5/ppc64le-redhat-linux;/usr/include/c++/4.8.5/backward;/usr/local/include;/usr/include
+/opt/ibm/xlsmp/5.1.0/include;/opt/ibm/xlmass/9.1.0/include;/opt/ibm/xlC/16.1.0/include;/usr/include/c\+\+/4.8.5;/usr/include/c\+\+/4.8.5/ppc64le-redhat-linux;/usr/include/c\+\+/4.8.5/backward;/usr/local/include;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux_nostdinc-CXX-PGI-18.10.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux_nostdinc-CXX-PGI-18.10.1.output
index 8c9d24a..8eb97c8 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux_nostdinc-CXX-PGI-18.10.1.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/linux_nostdinc-CXX-PGI-18.10.1.output
@@ -1 +1 @@
-/mnt/pgi/linux86-64/18.10/include-gcc70;/mnt/pgi/linux86-64/18.10/include;/usr/include/c++/7;/usr/include/x86_64-linux-gnu/c++/7;/usr/include/c++/7/backward;/usr/lib/gcc/x86_64-linux-gnu/7/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
+/mnt/pgi/linux86-64/18.10/include-gcc70;/mnt/pgi/linux86-64/18.10/include;/usr/include/c\+\+/7;/usr/include/x86_64-linux-gnu/c\+\+/7;/usr/include/c\+\+/7/backward;/usr/lib/gcc/x86_64-linux-gnu/7/include;/usr/local/include;/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed;/usr/include/x86_64-linux-gnu;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/mingw.org-CXX-GNU-4.9.3.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/mingw.org-CXX-GNU-4.9.3.output
index 7a5e447..9996940 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/mingw.org-CXX-GNU-4.9.3.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/mingw.org-CXX-GNU-4.9.3.output
@@ -1 +1 @@
-C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include/c++;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include/c++/mingw32;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include/c++/backward;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include;C:/DoesNotExist/mingw/include;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include-fixed
+C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include/c\+\+;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include/c\+\+/mingw32;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include/c\+\+/backward;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include;C:/DoesNotExist/mingw/include;C:/DoesNotExist/mingw/lib/gcc/mingw32/4.9.3/include-fixed
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/netbsd-CXX-GNU-4.8.5.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/netbsd-CXX-GNU-4.8.5.output
index 7b1e11e..d2289eb 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/netbsd-CXX-GNU-4.8.5.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/netbsd-CXX-GNU-4.8.5.output
@@ -1 +1 @@
-/usr/include/g++;/usr/include/g++/backward;/usr/include/gcc-4.8;/usr/include
+/usr/include/g\+\+;/usr/include/g\+\+/backward;/usr/include/gcc-4.8;/usr/include
diff --git a/Tests/RunCMake/ParseImplicitIncludeInfo/data/openbsd-CXX-Clang-5.0.1.output b/Tests/RunCMake/ParseImplicitIncludeInfo/data/openbsd-CXX-Clang-5.0.1.output
index 6da1398..d77687b 100644
--- a/Tests/RunCMake/ParseImplicitIncludeInfo/data/openbsd-CXX-Clang-5.0.1.output
+++ b/Tests/RunCMake/ParseImplicitIncludeInfo/data/openbsd-CXX-Clang-5.0.1.output
@@ -1 +1 @@
-/usr/include/c++/v1;/usr/lib/clang/5.0.1/include;/usr/include
+/usr/include/c\+\+/v1;/usr/lib/clang/5.0.1/include;/usr/include
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index ce71677..ad3f8f6 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -98,8 +98,14 @@
     else()
       set(_D_CMAKE_GENERATOR_INSTANCE "")
     endif()
+    if(NOT RunCMake_TEST_NO_SOURCE_DIR)
+      set(maybe_source_dir "${RunCMake_TEST_SOURCE_DIR}")
+    else()
+      set(maybe_source_dir "")
+    endif()
     execute_process(
-      COMMAND ${CMAKE_COMMAND} "${RunCMake_TEST_SOURCE_DIR}"
+      COMMAND ${CMAKE_COMMAND}
+                ${maybe_source_dir}
                 -G "${RunCMake_GENERATOR}"
                 -A "${RunCMake_GENERATOR_PLATFORM}"
                 -T "${RunCMake_GENERATOR_TOOLSET}"
@@ -182,5 +188,10 @@
   run_cmake(${test})
 endfunction()
 
+function(run_cmake_with_options test)
+  set(RunCMake_TEST_OPTIONS "${ARGN}")
+  run_cmake(${test})
+endfunction()
+
 # Protect RunCMake tests from calling environment.
 unset(ENV{MAKEFLAGS})
diff --git a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake
index 6ab3833..dab1c33 100644
--- a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake
+++ b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake
@@ -40,3 +40,62 @@
   set(RunCMake_TEST_FAILED "Failed to find correct ToolsVersion=\"4.0\" .")
   return()
 endif()
+
+#
+# Test solution file deployment items.
+#
+
+set(vcSlnFile "${RunCMake_TEST_BINARY_DIR}/VsCEDebuggerDeploy.sln")
+if(NOT EXISTS "${vcSlnFile}")
+  set(RunCMake_TEST_FAILED "Solution file ${vcSlnFile} does not exist.")
+  return()
+endif()
+
+
+if( NOT ${CMAKE_SYSTEM_NAME} STREQUAL "WindowsCE" )
+  set(RunCMake_TEST_FAILED "Test only valid for WindowsCE")
+  return()
+endif()
+
+
+set(FooProjGUID "")
+set(FoundFooProj FALSE)
+set(InFooProj FALSE)
+set(FoundReleaseDeploy FALSE)
+set(DeployConfigs Debug MinSizeRel RelWithDebInfo )
+
+file(STRINGS "${vcSlnFile}" lines)
+foreach(line IN LISTS lines)
+#message(STATUS "${line}")
+  if( (NOT InFooProj ) AND (line MATCHES "^[ \\t]*Project\\(\"{[A-F0-9-]+}\"\\) = \"foo\", \"foo.vcxproj\", \"({[A-F0-9-]+})\"[ \\t]*$"))
+    # First, identify the GUID for the foo project, and record it.
+    set(FoundFooProj TRUE)
+    set(InFooProj TRUE)
+    set(FooProjGUID ${CMAKE_MATCH_1})
+  elseif(InFooProj AND line MATCHES "EndProject")
+    set(InFooProj FALSE)
+  elseif((NOT InFooProj) AND line MATCHES "${FooProjGUID}\\.Release.*\\.Deploy\\.0")
+    # If foo's Release configuration is set to deploy, this is the error.
+    set(FoundReleaseDeploy TRUE)
+  endif()
+  if( line MATCHES "{[A-F0-9-]+}\\.([^\\|]+).*\\.Deploy\\.0" )
+    # Check that the other configurations ARE set to deploy.
+    list( REMOVE_ITEM DeployConfigs ${CMAKE_MATCH_1})
+  endif()
+endforeach()
+
+if(FoundReleaseDeploy)
+  set(RunCMake_TEST_FAILED "Release deployment not inhibited by VS_NO_SOLUTION_DEPLOY_Release.")
+  return()
+endif()
+
+if(NOT FoundFooProj)
+  set(RunCMake_TEST_FAILED "Failed to find foo project in the solution.")
+  return()
+endif()
+
+list(LENGTH DeployConfigs length)
+if(  length GREATER 0 )
+  set(RunCMake_TEST_FAILED "Failed to find Deploy lines for non-Release configurations. (${length})")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake
index 948f14c..611db0a 100644
--- a/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake
+++ b/Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake
@@ -4,10 +4,11 @@
    "temp\\foodir"
 )
 
-add_library(foo foo.cpp)
+add_library(foo SHARED foo.cpp)
 
 set_target_properties(foo
  PROPERTIES
   DEPLOYMENT_ADDITIONAL_FILES "foo.dll|\\foo\\src\\dir\\on\\host|$(RemoteDirectory)|0;bar.dll|\\bar\\src\\dir|$(RemoteDirectory)bardir|0"
   DEPLOYMENT_REMOTE_DIRECTORY ${DEPLOY_DIR}
+  VS_NO_SOLUTION_DEPLOY $<CONFIG:Release>
 )
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
index f675d81..88077b3 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
@@ -7,6 +7,13 @@
   endif()
 endfunction()
 
+function(expect_no_schema target)
+  set(schema "${RunCMake_TEST_BINARY_DIR}/XcodeSchemaProperty.xcodeproj/xcshareddata/xcschemes/${target}.xcscheme")
+  if(EXISTS ${schema})
+    message(SEND_ERROR "Found unexpected schema ${schema}")
+  endif()
+endfunction()
+
 check_property("ADDRESS_SANITIZER" "enableAddressSanitizer")
 check_property("ADDRESS_SANITIZER_USE_AFTER_RETURN" "enableASanStackUseAfterReturn")
 check_property("THREAD_SANITIZER" "enableThreadSanitizer")
@@ -31,3 +38,5 @@
 check_property("ENVIRONMENT" [=[value="foo"]=])
 check_property("ENVIRONMENT" [=[key="BAR"]=])
 check_property("ENVIRONMENT" [=[value="bar"]=])
+
+expect_no_schema("NoSchema")
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
index 2b72a64..73ef5ca 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
@@ -35,3 +35,6 @@
 create_scheme_for_property(EXECUTABLE myExecutable)
 create_scheme_for_property(ARGUMENTS "--foo;--bar=baz")
 create_scheme_for_property(ENVIRONMENT "FOO=foo;BAR=bar")
+
+add_executable(NoSchema main.cpp)
+set_target_properties(NoSchema PROPERTIES XCODE_GENERATE_SCHEME OFF)
diff --git a/Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake b/Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake
new file mode 100644
index 0000000..561f9c0
--- /dev/null
+++ b/Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake
@@ -0,0 +1,133 @@
+include(${CMAKE_CURRENT_LIST_DIR}/test_utils.cmake)
+
+# No keywords that miss any values, _KEYWORDS_MISSING_VALUES should not be defined
+cmake_parse_arguments(PREF "" "P1" "P2" P1 p1 P2 p2_a p2_b)
+
+TEST(PREF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+
+# Keyword should even be deleted from the actual scope
+set(PREF_KEYWORDS_MISSING_VALUES "What ever")
+cmake_parse_arguments(PREF "" "" "")
+
+TEST(PREF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+
+# Given missing keywords as only option
+cmake_parse_arguments(PREF "" "P1" "P2" P1)
+
+TEST(PREF_KEYWORDS_MISSING_VALUES "P1")
+TEST(PREF_P1 "UNDEFINED")
+TEST(PREF_UNPARSED_ARGUMENTS "UNDEFINED")
+
+# Mixed with unparsed arguments
+cmake_parse_arguments(UPREF "" "P1" "P2" A B P2 C P1)
+TEST(UPREF_KEYWORDS_MISSING_VALUES "P1")
+TEST(UPREF_UNPARSED_ARGUMENTS A B)
+
+# one_value_keyword followed by option
+cmake_parse_arguments(REF "OP" "P1" "" P1 OP)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_OP "TRUE")
+
+# Counter Test
+cmake_parse_arguments(REF "OP" "P1" "" P1 p1 OP)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_OP "TRUE")
+
+# one_value_keyword followed by a one_value_keyword
+cmake_parse_arguments(REF "" "P1;P2" "" P1 P2 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "p2")
+
+# Counter Test
+cmake_parse_arguments(REF "" "P1;P2" "" P1 p1 P2 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "p2")
+
+# one_value_keyword followed by a multi_value_keywords
+cmake_parse_arguments(REF "" "P1" "P2" P1 P2 p1 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 p1 p2)
+
+# Counter Examples
+cmake_parse_arguments(REF "" "P1" "P2" P1 p1 P2 p1 p2)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 p1 p2)
+
+# multi_value_keywords as only option
+cmake_parse_arguments(REF "" "P1" "P2" P2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P2")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# multi_value_keywords followed by option
+cmake_parse_arguments(REF "O1" "" "P1" P1 O1)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_O1 "TRUE")
+
+# counter test
+cmake_parse_arguments(REF "O1" "" "P1" P1 p1 p2 O1)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1;p2")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_O1 "TRUE")
+
+# multi_value_keywords followed by one_value_keyword
+cmake_parse_arguments(REF "" "P1" "P2" P2 P1 p1)
+TEST(REF_KEYWORDS_MISSING_VALUES "P2")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# counter test
+cmake_parse_arguments(REF "" "P1" "P2" P2 p2 P1 p1)
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_P1 "p1")
+TEST(REF_UNPARSED_ARGUMENTS "UNDEFINED")
+TEST(REF_P2 "p2")
+
+# one_value_keyword as last argument
+cmake_parse_arguments(REF "" "P1" "P2" A P2 p2 P1)
+TEST(REF_KEYWORDS_MISSING_VALUES "P1")
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_UNPARSED_ARGUMENTS "A")
+TEST(REF_P2 "p2")
+
+# multi_value_keywords as last argument
+cmake_parse_arguments(REF "" "P1" "P2" P1 p1 P2)
+TEST(REF_KEYWORDS_MISSING_VALUES "P2")
+TEST(REF_P1 "p1")
+TEST(REF_P2 "UNDEFINED")
+
+# Multiple one_value_keyword and multi_value_keywords at different places
+cmake_parse_arguments(REF "O1;O2" "P1" "P2" P1 O1 P2 O2)
+TEST(REF_KEYWORDS_MISSING_VALUES P1 P2)
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# Duplicated missing keywords
+cmake_parse_arguments(REF "O1;O2" "P1" "P2" P1 O1 P2 O2 P1 P2)
+TEST(REF_KEYWORDS_MISSING_VALUES P1 P2)
+TEST(REF_P1 "UNDEFINED")
+TEST(REF_P2 "UNDEFINED")
+
+# make sure keywords that are never used, don't get added to KEYWORDS_MISSING_VALUES
+cmake_parse_arguments(REF "O1;O2" "P1" "P2")
+TEST(REF_KEYWORDS_MISSING_VALUES "UNDEFINED")
+TEST(REF_O1 FALSE)
+TEST(REF_O2 FALSE)
+TEST(REF_P1 UNDEFINED)
+TEST(REF_P2 UNDEFINED)
diff --git a/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake b/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake
index 1e15b3b..505840d 100644
--- a/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake
+++ b/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake
@@ -11,3 +11,4 @@
 run_cmake(BadArgvN3)
 run_cmake(BadArgvN4)
 run_cmake(CornerCasesArgvN)
+run_cmake(KeyWordsMissingValues)
diff --git a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake
index 4d7d29b..78856b4 100644
--- a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake
@@ -31,7 +31,7 @@
 run_ctest_submit(CDashUploadMissingFile CDASH_UPLOAD bad-upload)
 run_ctest_submit(CDashUploadRetry CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo RETRY_COUNT 2 RETRY_DELAY 1 INTERNAL_TEST_CHECKSUM)
 run_ctest_submit(CDashSubmitQuiet QUIET)
-run_ctest_submit_debug(CDashSubmitVerbose)
+run_ctest_submit_debug(CDashSubmitVerbose BUILD_ID my_build_id)
 run_ctest_submit_debug(FILESNoBuildId FILES ${CMAKE_CURRENT_LIST_FILE})
 run_ctest_submit_debug(CDashSubmitHeaders HTTPHEADER "Authorization: Bearer asdf")
 run_ctest_submit_debug(CDashUploadHeaders CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo HTTPHEADER "Authorization: Bearer asdf")
diff --git a/Tests/RunCMake/export/AppendExport-stderr.txt b/Tests/RunCMake/export/AppendExport-stderr.txt
index d71620e..d12124c 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 EXPORT signature does not recognise the APPEND option.
+  export Unknown argument: "APPEND".
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/export/OldIface-stderr.txt b/Tests/RunCMake/export/OldIface-stderr.txt
index 818c2cb..3cc1033 100644
--- a/Tests/RunCMake/export/OldIface-stderr.txt
+++ b/Tests/RunCMake/export/OldIface-stderr.txt
@@ -1,5 +1,4 @@
 CMake Error at OldIface.cmake:[0-9]+ \(export\):
-  export EXPORT signature does not recognise the
-  EXPORT_LINK_INTERFACE_LIBRARIES option.
+  export Unknown argument: "EXPORT_LINK_INTERFACE_LIBRARIES".
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake b/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
index c41cb2a..15335b2 100644
--- a/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
+++ b/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
@@ -4,6 +4,8 @@
     [[bin/exe\.exe]]
     [[bin/(lib)?lib1\.dll]]
     [[include]]
+    [[include/obj1\.h]]
+    [[include/obj2\.h]]
     [[include/obj4\.h]]
     [[include/obj5\.h]]
     [[lib]]
@@ -20,6 +22,8 @@
     [[bin/cyglib1\.dll]]
     [[bin/exe\.exe]]
     [[include]]
+    [[include/obj1\.h]]
+    [[include/obj2\.h]]
     [[include/obj4\.h]]
     [[include/obj5\.h]]
     [[lib]]
@@ -35,6 +39,8 @@
     [[bin]]
     [[bin/exe]]
     [[include]]
+    [[include/obj1\.h]]
+    [[include/obj2\.h]]
     [[include/obj4\.h]]
     [[include/obj5\.h]]
     [[lib]]
diff --git a/Tests/RunCMake/install/TARGETS-Defaults.cmake b/Tests/RunCMake/install/TARGETS-Defaults.cmake
index bfd8c2c..324aa11 100644
--- a/Tests/RunCMake/install/TARGETS-Defaults.cmake
+++ b/Tests/RunCMake/install/TARGETS-Defaults.cmake
@@ -8,6 +8,11 @@
 add_library(lib4 SHARED obj5.c)
 set_property(TARGET lib4 PROPERTY PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj5.h)
 
+add_library(iface INTERFACE)
+set_target_properties(iface PROPERTIES
+  PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj1.h
+  PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj2.h)
+
 install(TARGETS exe lib1 lib2)
 install(TARGETS lib3
   LIBRARY DESTINATION lib3
@@ -17,3 +22,6 @@
   LIBRARY DESTINATION lib4
   RUNTIME DESTINATION lib4
   )
+install(TARGETS iface
+  PUBLIC_HEADER DESTINATION include
+  PRIVATE_HEADER DESTINATION include)
diff --git a/Tests/RunCMake/install/obj2.h b/Tests/RunCMake/install/obj2.h
new file mode 100644
index 0000000..90bcd34
--- /dev/null
+++ b/Tests/RunCMake/install/obj2.h
@@ -0,0 +1,6 @@
+#ifndef OBJ2_H
+#define OBJ2_H
+
+int obj2(void);
+
+#endif /* OBJ2_H */
diff --git a/Tests/RunCMake/interface_library/whitelist.cmake b/Tests/RunCMake/interface_library/whitelist.cmake
index bf64f01..0db6375 100644
--- a/Tests/RunCMake/interface_library/whitelist.cmake
+++ b/Tests/RunCMake/interface_library/whitelist.cmake
@@ -14,3 +14,12 @@
 set_property(TARGET iface PROPERTY "custom_property" output)
 set_property(TARGET iface APPEND PROPERTY "custom_property" append)
 get_target_property(outname iface "custom_property")
+
+# PUBLIC_HEADER / PRIVATE_HEADER properties are allowed
+set_property(TARGET iface PROPERTY PUBLIC_HEADER foo.h)
+set_property(TARGET iface APPEND PROPERTY PUBLIC_HEADER bar.h)
+get_target_property(outname iface PUBLIC_HEADER)
+
+set_property(TARGET iface PROPERTY PRIVATE_HEADER foo.h)
+set_property(TARGET iface APPEND PROPERTY PRIVATE_HEADER bar.h)
+get_target_property(outname iface PRIVATE_HEADER)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/list/POP_BACK-NoArgs-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/list/POP_BACK-NoArgs-result.txt
diff --git a/Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt b/Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt
new file mode 100644
index 0000000..83060b4
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt
@@ -0,0 +1 @@
+list must be called with at least two arguments
diff --git a/Tests/RunCMake/list/POP_BACK-NoArgs.cmake b/Tests/RunCMake/list/POP_BACK-NoArgs.cmake
new file mode 100644
index 0000000..518924d
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK-NoArgs.cmake
@@ -0,0 +1 @@
+list(POP_FRONT)
diff --git a/Tests/RunCMake/list/POP_BACK.cmake b/Tests/RunCMake/list/POP_BACK.cmake
new file mode 100644
index 0000000..4794796
--- /dev/null
+++ b/Tests/RunCMake/list/POP_BACK.cmake
@@ -0,0 +1,79 @@
+cmake_policy(SET CMP0054 NEW)
+
+function(assert_expected_list_len list_var expected_size)
+    list(LENGTH ${list_var} _size)
+    if(NOT _size EQUAL ${expected_size})
+        message(FATAL_ERROR "list size expected to be `${expected_size}`, got `${_size}` instead")
+    endif()
+endfunction()
+
+# Pop from undefined list
+list(POP_BACK test)
+if(DEFINED test)
+    message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Pop from empty list
+set(test)
+list(POP_BACK test)
+if(DEFINED test)
+    message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Default pop from 1-item list
+list(APPEND test one)
+list(POP_BACK test)
+assert_expected_list_len(test 0)
+
+# Pop from 1-item list to var
+list(APPEND test one)
+list(POP_BACK test one)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+    message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+    message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+
+unset(one)
+unset(two)
+
+# Pop from 1-item list to vars
+list(APPEND test one)
+list(POP_BACK test one two)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+    message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+    message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+if(DEFINED two)
+    message(FATAL_ERROR "`two` expected to be undefined")
+endif()
+
+unset(one)
+unset(two)
+
+# Default pop from 2-item list
+list(APPEND test one two)
+list(POP_BACK test)
+assert_expected_list_len(test 1)
+if(NOT test STREQUAL "one")
+    message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
+
+# Pop from 2-item list
+list(APPEND test two)
+list(POP_BACK test two)
+assert_expected_list_len(test 1)
+if(NOT DEFINED two)
+    message(FATAL_ERROR "`two` expected to be defined")
+endif()
+if(NOT two STREQUAL "two")
+    message(FATAL_ERROR "`two` has unexpected value `${two}`")
+endif()
+if(NOT test STREQUAL "one")
+    message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt
diff --git a/Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt b/Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt
new file mode 100644
index 0000000..83060b4
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt
@@ -0,0 +1 @@
+list must be called with at least two arguments
diff --git a/Tests/RunCMake/list/POP_FRONT-NoArgs.cmake b/Tests/RunCMake/list/POP_FRONT-NoArgs.cmake
new file mode 100644
index 0000000..c5cf837
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT-NoArgs.cmake
@@ -0,0 +1 @@
+list(POP_BACK)
diff --git a/Tests/RunCMake/list/POP_FRONT.cmake b/Tests/RunCMake/list/POP_FRONT.cmake
new file mode 100644
index 0000000..a2f8f3c
--- /dev/null
+++ b/Tests/RunCMake/list/POP_FRONT.cmake
@@ -0,0 +1,79 @@
+cmake_policy(SET CMP0054 NEW)
+
+function(assert_expected_list_len list_var expected_size)
+    list(LENGTH ${list_var} _size)
+    if(NOT _size EQUAL ${expected_size})
+        message(FATAL_ERROR "list size expected to be `${expected_size}`, got `${_size}` instead")
+    endif()
+endfunction()
+
+# Pop from undefined list
+list(POP_FRONT test)
+if(DEFINED test)
+    message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Pop from empty list
+set(test)
+list(POP_FRONT test)
+if(DEFINED test)
+    message(FATAL_ERROR "`test` expected to be undefined")
+endif()
+
+# Default pop from 1-item list
+list(APPEND test one)
+list(POP_FRONT test)
+assert_expected_list_len(test 0)
+
+# Pop from 1-item list to var
+list(APPEND test one)
+list(POP_FRONT test one)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+    message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+    message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+
+unset(one)
+unset(two)
+
+# Pop from 1-item list to vars
+list(APPEND test one)
+list(POP_FRONT test one two)
+assert_expected_list_len(test 0)
+if(NOT DEFINED one)
+    message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+    message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+if(DEFINED two)
+    message(FATAL_ERROR "`two` expected to be undefined")
+endif()
+
+unset(one)
+unset(two)
+
+# Default pop from 2-item list
+list(APPEND test one two)
+list(POP_FRONT test)
+assert_expected_list_len(test 1)
+if(NOT test STREQUAL "two")
+    message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
+
+# Pop from 2-item list
+list(PREPEND test one)
+list(POP_FRONT test one)
+assert_expected_list_len(test 1)
+if(NOT DEFINED one)
+    message(FATAL_ERROR "`one` expected to be defined")
+endif()
+if(NOT one STREQUAL "one")
+    message(FATAL_ERROR "`one` has unexpected value `${one}`")
+endif()
+if(NOT test STREQUAL "two")
+    message(FATAL_ERROR "`test` has unexpected value `${test}`")
+endif()
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt b/Tests/RunCMake/list/PREPEND-NoArgs-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-result.txt
copy to Tests/RunCMake/list/PREPEND-NoArgs-result.txt
diff --git a/Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt b/Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt
new file mode 100644
index 0000000..83060b4
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt
@@ -0,0 +1 @@
+list must be called with at least two arguments
diff --git a/Tests/RunCMake/list/PREPEND-NoArgs.cmake b/Tests/RunCMake/list/PREPEND-NoArgs.cmake
new file mode 100644
index 0000000..8935fa9
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND-NoArgs.cmake
@@ -0,0 +1 @@
+list(PREPEND)
diff --git a/Tests/RunCMake/list/PREPEND.cmake b/Tests/RunCMake/list/PREPEND.cmake
new file mode 100644
index 0000000..17b2921
--- /dev/null
+++ b/Tests/RunCMake/list/PREPEND.cmake
@@ -0,0 +1,33 @@
+list(PREPEND test)
+if(test)
+    message(FATAL_ERROR "failed")
+endif()
+
+list(PREPEND test satu)
+if(NOT test STREQUAL "satu")
+    message(FATAL_ERROR "failed")
+endif()
+
+list(PREPEND test dua)
+if(NOT test STREQUAL "dua;satu")
+    message(FATAL_ERROR "failed")
+endif()
+
+list(PREPEND test tiga)
+if(NOT test STREQUAL "tiga;dua;satu")
+    message(FATAL_ERROR "failed")
+endif()
+
+# Scope test
+function(foo)
+    list(PREPEND test empat)
+    if(NOT test STREQUAL "empat;tiga;dua;satu")
+        message(FATAL_ERROR "failed")
+    endif()
+endfunction()
+
+foo()
+
+if(NOT test STREQUAL "tiga;dua;satu")
+    message(FATAL_ERROR "failed")
+endif()
diff --git a/Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake b/Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake
new file mode 100644
index 0000000..91abbd6
--- /dev/null
+++ b/Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake
@@ -0,0 +1,5 @@
+set(mylist "b;c;b;a;a;c;b;a;c;b")
+list(REMOVE_DUPLICATES mylist)
+if(NOT mylist STREQUAL "b;c;a")
+  message(SEND_ERROR "Expected b;c;a, got ${mylist}")
+endif()
diff --git a/Tests/RunCMake/list/RunCMakeTest.cmake b/Tests/RunCMake/list/RunCMakeTest.cmake
index bf3d22d..b4a91bc 100644
--- a/Tests/RunCMake/list/RunCMakeTest.cmake
+++ b/Tests/RunCMake/list/RunCMakeTest.cmake
@@ -24,6 +24,8 @@
 
 run_cmake(REMOVE_AT-EmptyList)
 
+run_cmake(REMOVE_DUPLICATES-PreserveOrder)
+
 run_cmake(FILTER-NotList)
 run_cmake(REMOVE_AT-NotList)
 run_cmake(REMOVE_DUPLICATES-NotList)
@@ -98,3 +100,15 @@
 
 # Successful tests
 run_cmake(SORT)
+
+# argument tests
+run_cmake(PREPEND-NoArgs)
+# Successful tests
+run_cmake(PREPEND)
+
+# argument tests
+run_cmake(POP_BACK-NoArgs)
+run_cmake(POP_FRONT-NoArgs)
+# Successful tests
+run_cmake(POP_BACK)
+run_cmake(POP_FRONT)
diff --git a/Tests/RunCMake/try_compile/CMP0066-stderr.txt b/Tests/RunCMake/try_compile/CMP0066-stderr.txt
index b14e290..0b92dcf 100644
--- a/Tests/RunCMake/try_compile/CMP0066-stderr.txt
+++ b/Tests/RunCMake/try_compile/CMP0066-stderr.txt
@@ -12,4 +12,15 @@
   test project.
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)
-This warning is for project developers.  Use -Wno-dev to suppress it.$
+This warning is for project developers.  Use -Wno-dev to suppress it.
+*
+CMake Deprecation Warning at CMP0066.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0066 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.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/try_compile/LinkOptions.cmake b/Tests/RunCMake/try_compile/LinkOptions.cmake
index 9b246c4..488cab1 100644
--- a/Tests/RunCMake/try_compile/LinkOptions.cmake
+++ b/Tests/RunCMake/try_compile/LinkOptions.cmake
@@ -5,7 +5,7 @@
 
 set (lib_name "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}lib${CMAKE_STATIC_LIBRARY_SUFFIX}")
 if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
-  if (RunCMake_C_COMPILER_ID STREQUAL "MSVC")
+  if (RunCMake_C_COMPILER_ID STREQUAL "MSVC" OR "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
     if (CMAKE_SIZEOF_VOID_P EQUAL 4)
       set (undef_flag /INCLUDE:_func)
     else()
diff --git a/Tests/RunCMake/try_run/LinkOptions.cmake b/Tests/RunCMake/try_run/LinkOptions.cmake
index 17af2f7..9939a42 100644
--- a/Tests/RunCMake/try_run/LinkOptions.cmake
+++ b/Tests/RunCMake/try_run/LinkOptions.cmake
@@ -5,7 +5,7 @@
 
 set (lib_name "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}lib${CMAKE_STATIC_LIBRARY_SUFFIX}")
 if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
-  if (RunCMake_C_COMPILER_ID STREQUAL "MSVC")
+  if (RunCMake_C_COMPILER_ID STREQUAL "MSVC" OR "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
     if (CMAKE_SIZEOF_VOID_P EQUAL 4)
       set (undef_flag /INCLUDE:_func)
     else()
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 482a08d..0393ff1 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -68,6 +68,7 @@
   { symbol: [ "std::__decay_and_strip<cmGeneratorTarget *&>::__type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::__decay_and_strip<cmFindCommon::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::__decay_and_strip<cmSearchPath>::__type", private, "\"cmConfigure.h\"", public ] },
+  { symbol: [ "std::__decay_and_strip<cm::string_view>::__type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::__decay_and_strip<std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::__decay_and_strip<const std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::__decay_and_strip<cmFindPackageCommand::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
diff --git a/Utilities/Release/win32_release.cmake b/Utilities/Release/win32_release.cmake
index c03c665..974c402 100644
--- a/Utilities/Release/win32_release.cmake
+++ b/Utilities/Release/win32_release.cmake
@@ -8,12 +8,17 @@
 set(CPACK_SOURCE_GENERATORS "ZIP")
 set(MAKE_PROGRAM "ninja")
 set(MAKE "${MAKE_PROGRAM} -j16")
-set(qt_prefix "c:/Qt/5.6.3/msvc2017-32-xp-mt")
+set(qt_prefix "c:/Qt/5.12.1/msvc2017-32-w7-mt")
 set(qt_win_libs
   ${qt_prefix}/plugins/platforms/qwindows.lib
-  ${qt_prefix}/lib/Qt5PlatformSupport.lib
+  ${qt_prefix}/plugins/styles/qwindowsvistastyle.lib
+  ${qt_prefix}/lib/Qt5EventDispatcherSupport.lib
+  ${qt_prefix}/lib/Qt5FontDatabaseSupport.lib
+  ${qt_prefix}/lib/Qt5ThemeSupport.lib
   ${qt_prefix}/lib/qtfreetype.lib
+  ${qt_prefix}/lib/qtlibpng.lib
   imm32.lib
+  wtsapi32.lib
   )
 set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
 CMAKE_DOC_DIR:STRING=doc/cmake
@@ -31,7 +36,7 @@
 CMake_TEST_Qt4:BOOL=OFF
 CMake_TEST_Qt5:BOOL=OFF
 ")
-set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000 -D_USING_V110_SDK71_")
+set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000")
 set(CFLAGS "${ppflags}")
 set(CXXFLAGS "${ppflags}")
 set(ENV ". ~/rel/env32")
diff --git a/Utilities/Release/win64_release.cmake b/Utilities/Release/win64_release.cmake
index 8417206..20529f0 100644
--- a/Utilities/Release/win64_release.cmake
+++ b/Utilities/Release/win64_release.cmake
@@ -8,12 +8,17 @@
 set(CPACK_SOURCE_GENERATORS "")
 set(MAKE_PROGRAM "ninja")
 set(MAKE "${MAKE_PROGRAM} -j16")
-set(qt_prefix "c:/Qt/5.6.3/msvc2017-64-xp-mt")
+set(qt_prefix "c:/Qt/5.12.1/msvc2017-64-w7-mt")
 set(qt_win_libs
   ${qt_prefix}/plugins/platforms/qwindows.lib
-  ${qt_prefix}/lib/Qt5PlatformSupport.lib
+  ${qt_prefix}/plugins/styles/qwindowsvistastyle.lib
+  ${qt_prefix}/lib/Qt5EventDispatcherSupport.lib
+  ${qt_prefix}/lib/Qt5FontDatabaseSupport.lib
+  ${qt_prefix}/lib/Qt5ThemeSupport.lib
   ${qt_prefix}/lib/qtfreetype.lib
+  ${qt_prefix}/lib/qtlibpng.lib
   imm32.lib
+  wtsapi32.lib
   )
 set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
 CMAKE_DOC_DIR:STRING=doc/cmake
@@ -31,7 +36,7 @@
 CMake_TEST_Qt4:BOOL=OFF
 CMake_TEST_Qt5:BOOL=OFF
 ")
-set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000 -D_USING_V110_SDK71_")
+set(ppflags "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000")
 set(CFLAGS "${ppflags}")
 set(CXXFLAGS "${ppflags}")
 set(ENV ". ~/rel/env64")
diff --git a/Utilities/Scripts/update-third-party.bash b/Utilities/Scripts/update-third-party.bash
index 670946e..fcab871 100644
--- a/Utilities/Scripts/update-third-party.bash
+++ b/Utilities/Scripts/update-third-party.bash
@@ -71,8 +71,6 @@
 
 readonly regex_date='20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
 readonly basehash_regex="$name $regex_date ([0-9a-f]*)"
-readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
-readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
 
 ########################################################################
 # Sanity checking
@@ -87,6 +85,18 @@
     die "'repo' is empty"
 [ -n "$tag" ] || \
     die "'tag' is empty"
+
+# Check for an empty destination directory on disk.  By checking on disk and
+# not in the repo it allows a library to be freshly re-inialized in a single
+# commit rather than first deleting the old copy in one commit and adding the
+# new copy in a seperate commit.
+if [ ! -d "$(git rev-parse --show-toplevel)/$subtree" ]; then
+    readonly basehash=""
+else
+    readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
+fi
+readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
+
 [ -n "$basehash" ] || \
     warn "'basehash' is empty; performing initial import"
 readonly do_shortlog="${shortlog-false}"
@@ -104,6 +114,8 @@
 git clone "$repo" "$upstreamdir"
 
 if [ -n "$basehash" ]; then
+    # Remove old worktrees
+    git worktree prune
     # Use the existing package's history
     git worktree add "$extractdir" "$basehash"
     # Clear out the working tree
@@ -163,13 +175,17 @@
 if [ -n "$basehash" ]; then
     git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name"
 else
+    # Note: on Windows 'git merge --help' will open a browser, and the check
+    # will fail, so use the flag by default.
     unrelated_histories_flag=""
-    if git merge --help | grep -q -e allow-unrelated-histories; then
+    if git --version | grep -q windows; then
+        unrelated_histories_flag="--allow-unrelated-histories "
+    elif git merge --help | grep -q -e allow-unrelated-histories; then
         unrelated_histories_flag="--allow-unrelated-histories "
     fi
     readonly unrelated_histories_flag
 
-    git fetch "$extractdir" "upstream-$name:upstream-$name"
+    git fetch "$extractdir" "+upstream-$name:upstream-$name"
     git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name"
     git read-tree -u --prefix="$subtree/" "upstream-$name"
 fi
diff --git a/Utilities/Scripts/update-zstd.bash b/Utilities/Scripts/update-zstd.bash
new file mode 100755
index 0000000..ce2c66b
--- /dev/null
+++ b/Utilities/Scripts/update-zstd.bash
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="zstd"
+readonly ownership="zstd upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmzstd"
+readonly repo="https://github.com/facebook/zstd.git"
+readonly tag="v1.3.8"
+readonly shortlog=false
+readonly paths="
+  LICENSE
+  README.md
+  lib/common/*.c
+  lib/common/*.h
+  lib/compress/*.c
+  lib/compress/*.h
+  lib/decompress/*.c
+  lib/decompress/*.h
+  lib/deprecated/*.c
+  lib/deprecated/*.h
+  lib/dictBuilder/*.c
+  lib/dictBuilder/*.h
+  lib/zstd.h
+"
+
+extract_source () {
+    git_archive
+    pushd "${extractdir}/${name}-reduced"
+    echo "* -whitespace" > .gitattributes
+    popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/cmThirdParty.h.in b/Utilities/cmThirdParty.h.in
index 46e0490..1456e34 100644
--- a/Utilities/cmThirdParty.h.in
+++ b/Utilities/cmThirdParty.h.in
@@ -15,5 +15,6 @@
 #cmakedefine CMAKE_USE_SYSTEM_JSONCPP
 #cmakedefine CMAKE_USE_SYSTEM_LIBRHASH
 #cmakedefine CMAKE_USE_SYSTEM_LIBUV
+#cmakedefine CMAKE_USE_SYSTEM_ZSTD
 
 #endif
diff --git a/Utilities/cm_zstd.h b/Utilities/cm_zstd.h
new file mode 100644
index 0000000..4bda996
--- /dev/null
+++ b/Utilities/cm_zstd.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_zstd_h
+#define cm_zstd_h
+
+/* Use the libzstd configured for CMake.  */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_ZSTD
+#  include <zstd.h>
+#else
+#  include <cmzstd/lib/zstd.h>
+#endif
+
+#endif
diff --git a/Utilities/cmcompress/CMakeLists.txt b/Utilities/cmcompress/CMakeLists.txt
deleted file mode 100644
index 8063573..0000000
--- a/Utilities/cmcompress/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-PROJECT(CMCompress)
-
-ADD_LIBRARY(cmcompress cmcompress.c)
-
-INSTALL(FILES Copyright.txt DESTINATION ${CMAKE_DOC_DIR}/cmcompress)
diff --git a/Utilities/cmcompress/Copyright.txt b/Utilities/cmcompress/Copyright.txt
deleted file mode 100644
index 162332f..0000000
--- a/Utilities/cmcompress/Copyright.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-Copyright (c) 1985, 1986 The Regents of the University of California.
-All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-James A. Woods, derived from original work by Spencer Thomas
-and Joseph Orost.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-     This product includes software developed by the University of
-     California, Berkeley and its contributors.
-4. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
diff --git a/Utilities/cmcompress/cmcompress.c b/Utilities/cmcompress/cmcompress.c
deleted file mode 100644
index ea845ed..0000000
--- a/Utilities/cmcompress/cmcompress.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *  This product includes software developed by the University of
- *  California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "cmcompress.h"
-
-#include <errno.h>
-#include <string.h>
-
-static const char_type magic_header[] = { "\037\235" };  /* 1F 9D */
-
-/* Defines for third byte of header */
-#define BIT_MASK  0x1f
-#define BLOCK_MASK  0x80
-#define CHECK_GAP 10000  /* ratio check interval */
-/* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
-   a fourth header byte (for expansion).
-   */
-#define INIT_BITS 9      /* initial number of bits/code */
-
-#ifdef COMPATIBLE    /* But wrong! */
-# define MAXCODE(n_bits)  (1 << (n_bits) - 1)
-#else
-# define MAXCODE(n_bits)  ((1 << (n_bits)) - 1)
-#endif /* COMPATIBLE */
-
-#define htabof(i)  cdata->htab[i]
-#define codetabof(i)  cdata->codetab[i]
-
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define FIRST  257  /* first free entry */
-#define  CLEAR  256  /* table clear output code */
-
-#ifdef DEBUG
-static void prratio( FILE *stream, long int num, long int den);
-#endif
-
-int cmcompress_compress_initialize(struct cmcompress_stream* cdata)
-{
-  cdata->maxbits = BITS;      /* user settable max # bits/code */
-  cdata->maxmaxcode = 1 << BITS;  /* should NEVER generate this code */
-  cdata->hsize = HSIZE;      /* for dynamic table sizing */
-  cdata->free_ent = 0;      /* first unused entry */
-  cdata->nomagic = 0;  /* Use a 3-byte magic number header, unless old file */
-  cdata->block_compress = BLOCK_MASK;
-  cdata->clear_flg = 0;
-  cdata->ratio = 0;
-  cdata->checkpoint = CHECK_GAP;
-
-  cdata->input_stream = 0;
-  cdata->output_stream = 0;
-  cdata->client_data = 0;
-  return 1;
-}
-
-static void cl_hash(struct cmcompress_stream* cdata, count_int hsize)    /* reset code table */
-{
-  register count_int *htab_p = cdata->htab+hsize;
-  register long i;
-  register long m1 = -1;
-
-  i = hsize - 16;
-  do
-    {        /* might use Sys V memset(3) here */
-    *(htab_p-16) = m1;
-    *(htab_p-15) = m1;
-    *(htab_p-14) = m1;
-    *(htab_p-13) = m1;
-    *(htab_p-12) = m1;
-    *(htab_p-11) = m1;
-    *(htab_p-10) = m1;
-    *(htab_p-9) = m1;
-    *(htab_p-8) = m1;
-    *(htab_p-7) = m1;
-    *(htab_p-6) = m1;
-    *(htab_p-5) = m1;
-    *(htab_p-4) = m1;
-    *(htab_p-3) = m1;
-    *(htab_p-2) = m1;
-    *(htab_p-1) = m1;
-    htab_p -= 16;
-    }
-  while ((i -= 16) >= 0);
-  for ( i += 16; i > 0; i-- )
-    {
-    *--htab_p = m1;
-    }
-}
-
-/*-
- * Output the given code.
- * Inputs:
- *   code:  A n_bits-bit integer.  If == -1, then EOF.  This assumes
- *    that n_bits =< (long)wordsize - 1.
- * Outputs:
- *   Outputs code to the file.
- * Assumptions:
- *  Chars are 8 bits long.
- * Algorithm:
- *   Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly).  Use the VAX insv instruction to insert each
- * code in turn.  When the buffer fills up empty it and start over.
- */
-
-static char buf[BITS];
-
-#ifndef vax
-char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
-char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-#endif /* vax */
-
-static int output(struct cmcompress_stream* cdata, code_int  code)
-{
-#ifdef DEBUG
-  static int col = 0;
-#endif /* DEBUG */
-
-  /*
-   * On the VAX, it is important to have the register declarations
-   * in exactly the order given, or the asm will break.
-   */
-  register int r_off = cdata->offset, bits= cdata->n_bits;
-  register char * bp = buf;
-
-#ifdef DEBUG
-  if ( verbose )
-    {
-    fprintf( stderr, "%5d%c", code,
-      (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
-    }
-#endif /* DEBUG */
-  if ( code >= 0 )
-    {
-#if defined(vax) && !defined(__GNUC__)
-    /*
-     * VAX and PCC DEPENDENT!! Implementation on other machines is
-     * below.
-     *
-     * Translation: Insert BITS bits from the argument starting at
-     * cdata->offset bits from the beginning of buf.
-     */
-    0;  /* Work around for pcc -O bug with asm and if stmt */
-    asm( "insv  4(ap),r11,r10,(r9)" );
-#else
-    /*
-     * byte/bit numbering on the VAX is simulated by the following code
-     */
-    /*
-     * Get to the first byte.
-     */
-    bp += (r_off >> 3);
-    r_off &= 7;
-    /*
-     * Since code is always >= 8 bits, only need to mask the first
-     * hunk on the left.
-     */
-    *bp = (char)((*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]));
-    bp++;
-    bits -= (8 - r_off);
-    code >>= 8 - r_off;
-    /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
-    if ( bits >= 8 )
-      {
-      *bp++ = (char)(code);
-      code >>= 8;
-      bits -= 8;
-      }
-    /* Last bits. */
-    if(bits)
-      {
-      *bp = (char)(code);
-      }
-#endif /* vax */
-    cdata->offset += cdata->n_bits;
-    if ( cdata->offset == (cdata->n_bits << 3) )
-      {
-      bp = buf;
-      bits = cdata->n_bits;
-      cdata->bytes_out += bits;
-      do
-        {
-        if ( cdata->output_stream(cdata, bp, 1) != 1 )
-          {
-          return 0;
-          }
-        bp++;
-        }
-      while(--bits);
-      cdata->offset = 0;
-      }
-
-    /*
-     * If the next entry is going to be too big for the code size,
-     * then increase it, if possible.
-     */
-    if ( cdata->free_ent > cdata->maxcode || (cdata->clear_flg > 0))
-      {
-      /*
-       * Write the whole buffer, because the input side won't
-       * discover the size increase until after it has read it.
-       */
-      if ( cdata->offset > 0 )
-        {
-        if ( cdata->output_stream(cdata, buf, cdata->n_bits) != cdata->n_bits )
-          {
-          return 0;
-          }
-        cdata->bytes_out += cdata->n_bits;
-        }
-      cdata->offset = 0;
-
-      if ( cdata->clear_flg )
-        {
-        cdata->maxcode = MAXCODE (cdata->n_bits = INIT_BITS);
-        cdata->clear_flg = 0;
-        }
-      else
-        {
-        cdata->n_bits++;
-        if ( cdata->n_bits == cdata->maxbits )
-          {
-          cdata->maxcode = cdata->maxmaxcode;
-          }
-        else
-          {
-          cdata->maxcode = MAXCODE(cdata->n_bits);
-          }
-        }
-#ifdef DEBUG
-      if ( debug )
-        {
-        fprintf( stderr, "\nChange to %d bits\n", cdata->n_bits );
-        col = 0;
-        }
-#endif /* DEBUG */
-      }
-    }
-  else
-    {
-    /*
-     * At EOF, write the rest of the buffer.
-     */
-    if ( cdata->offset > 0 )
-      {
-      cdata->offset = (cdata->offset + 7) / 8;
-      if ( cdata->output_stream(cdata, buf, cdata->offset ) != cdata->offset )
-        {
-        return 0;
-        }
-      cdata->bytes_out += cdata->offset;
-      }
-    cdata->offset = 0;
-    (void)fflush( stdout );
-    if( ferror( stdout ) )
-      {
-      return 0;
-      }
-#ifdef DEBUG
-    if ( verbose )
-      {
-      fprintf( stderr, "\n" );
-      }
-#endif
-    }
-  return 1;
-}
-
-/*
- * compress stdin to stdout
- *
- * Algorithm:  use open addressing double hashing (no chaining) on the
- * prefix code / next character combination.  We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe.  Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation.  Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills.  The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor.  Late addition:  construct the table according to
- * file size for noticeable speed improvement on small files.  Please direct
- * questions about this implementation to ames!jaw.
- */
-
-int cmcompress_compress_start(struct cmcompress_stream* cdata)
-{
-#ifndef COMPATIBLE
-  if (cdata->nomagic == 0)
-    {
-    char headLast = (char)(cdata->maxbits | cdata->block_compress);
-    cdata->output_stream(cdata, (const char*)magic_header, 2);
-    cdata->output_stream(cdata, &headLast, 1);
-    if(ferror(stdout))
-      {
-      printf("Error...\n");
-      }
-    }
-#endif /* COMPATIBLE */
-
-  cdata->offset = 0;
-  cdata->bytes_out = 3;    /* includes 3-byte header mojo */
-  cdata->out_count = 0;
-  cdata->clear_flg = 0;
-  cdata->ratio = 0;
-  cdata->in_count = 1;
-  cdata->checkpoint = CHECK_GAP;
-  cdata->maxcode = MAXCODE(cdata->n_bits = INIT_BITS);
-  cdata->free_ent = ((cdata->block_compress) ? FIRST : 256 );
-
-  cdata->first_pass = 1;
-
-  cdata->hshift = 0;
-  for ( cdata->fcode = (long) cdata->hsize;  cdata->fcode < 65536L; cdata->fcode *= 2L )
-    {
-    cdata->hshift++;
-    }
-  cdata->hshift = 8 - cdata->hshift;    /* set hash code range bound */
-
-  cdata->hsize_reg = cdata->hsize;
-  cl_hash(cdata, (count_int) cdata->hsize_reg);    /* clear hash table */
-
-  return 1;
-}
-
-static int cl_block (struct cmcompress_stream* cdata)    /* table clear for block compress */
-{
-  register long int rat;
-
-  cdata->checkpoint = cdata->in_count + CHECK_GAP;
-#ifdef DEBUG
-  if ( cdata->debug )
-    {
-    fprintf ( stderr, "count: %ld, ratio: ", cdata->in_count );
-    prratio ( stderr, cdata->in_count, cdata->bytes_out );
-    fprintf ( stderr, "\n");
-    }
-#endif /* DEBUG */
-
-  if(cdata->in_count > 0x007fffff)
-    {  /* shift will overflow */
-    rat = cdata->bytes_out >> 8;
-    if(rat == 0)
-      {    /* Don't divide by zero */
-      rat = 0x7fffffff;
-      }
-    else
-      {
-      rat = cdata->in_count / rat;
-      }
-    }
-  else
-    {
-    rat = (cdata->in_count << 8) / cdata->bytes_out;  /* 8 fractional bits */
-    }
-  if ( rat > cdata->ratio )
-    {
-    cdata->ratio = rat;
-    }
-  else
-    {
-    cdata->ratio = 0;
-#ifdef DEBUG
-    if(cdata->verbose)
-      {
-      dump_tab();  /* dump string table */
-      }
-#endif
-    cl_hash (cdata, (count_int) cdata->hsize );
-    cdata->free_ent = FIRST;
-    cdata->clear_flg = 1;
-    if ( !output (cdata, (code_int) CLEAR ) )
-      {
-      return 0;
-      }
-#ifdef DEBUG
-    if(cdata->debug)
-      {
-      fprintf ( stderr, "clear\n" );
-      }
-#endif /* DEBUG */
-    }
-  return 1;
-}
-
-
-int cmcompress_compress(struct cmcompress_stream* cdata, void* buff, size_t n)
-{
-  register code_int i;
-  register int c;
-  register int disp;
-
-  unsigned char* input_buffer = (unsigned char*)buff;
-
-  size_t cc;
-
-  /*printf("cmcompress_compress(%p, %p, %d)\n", cdata, buff, n);*/
-
-  if ( cdata->first_pass )
-    {
-    cdata->ent = input_buffer[0];
-    ++ input_buffer;
-    -- n;
-    cdata->first_pass = 0;
-    }
-
-  for ( cc = 0; cc < n; ++ cc )
-    {
-    c = input_buffer[cc];
-    cdata->in_count++;
-    cdata->fcode = (long) (((long) c << cdata->maxbits) + cdata->ent);
-    i = ((c << cdata->hshift) ^ cdata->ent);  /* xor hashing */
-
-    if ( htabof (i) == cdata->fcode )
-      {
-      cdata->ent = codetabof (i);
-      continue;
-      }
-    else if ( (long)htabof (i) < 0 )  /* empty slot */
-      {
-      goto nomatch;
-      }
-    disp = (int)(cdata->hsize_reg - i);    /* secondary hash (after G. Knott) */
-    if ( i == 0 )
-      {
-      disp = 1;
-      }
-probe:
-    if ( (i -= disp) < 0 )
-      {
-      i += cdata->hsize_reg;
-      }
-
-    if ( htabof (i) == cdata->fcode )
-      {
-      cdata->ent = codetabof (i);
-      continue;
-      }
-    if ( (long)htabof (i) > 0 )
-      {
-      goto probe;
-      }
-nomatch:
-    if ( !output(cdata, (code_int) cdata->ent ) )
-      {
-      return 0;
-      }
-    cdata->out_count++;
-    cdata->ent = c;
-    if (
-#ifdef SIGNED_COMPARE_SLOW
-      (unsigned) cdata->free_ent < (unsigned) cdata->maxmaxcode
-#else
-      cdata->free_ent < cdata->maxmaxcode
-#endif
-    )
-      {
-      codetabof (i) = (unsigned short)(cdata->free_ent++);  /* code -> hashtable */
-      htabof (i) = cdata->fcode;
-      }
-    else if ( (count_int)cdata->in_count >= cdata->checkpoint && cdata->block_compress )
-      {
-      if ( !cl_block (cdata) )
-        {
-        return 0;
-        }
-      }
-    }
-
-  return 1;
-}
-
-int cmcompress_compress_finalize(struct cmcompress_stream* cdata)
-{
-  /*
-   * Put out the final code.
-   */
-  if ( !output(cdata, (code_int)cdata->ent ) )
-    {
-    return 0;
-    }
-  cdata->out_count++;
-  if ( !output(cdata, (code_int)-1 ) )
-    {
-    return 0;
-    }
-
-  if(cdata->bytes_out > cdata->in_count)  /* exit(2) if no savings */
-    {
-    return 0;
-    }
-  return 1;
-}
-
-
-#if defined(DEBUG)
-static void prratio(FILE *stream, long int num, long int den)
-{
-  register int q;      /* Doesn't need to be long */
-
-  if(num > 214748L)
-    {    /* 2147483647/10000 */
-    q = num / (den / 10000L);
-    }
-  else
-    {
-    q = 10000L * num / den;    /* Long calculations, though */
-    }
-  if (q < 0)
-    {
-    putc('-', stream);
-    q = -q;
-    }
-  fprintf(stream, "%d.%02d%%", q / 100, q % 100);
-}
-#endif
-
diff --git a/Utilities/cmcompress/cmcompress.h b/Utilities/cmcompress/cmcompress.h
deleted file mode 100644
index 4cd3a1c..0000000
--- a/Utilities/cmcompress/cmcompress.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *  This product includes software developed by the University of
- *  California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef cmcompress__h_
-#define cmcompress__h_
-
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-  /*
-   * Set USERMEM to the maximum amount of physical user memory available
-   * in bytes.  USERMEM is used to determine the maximum BITS that can be used
-   * for compression.
-   *
-   * SACREDMEM is the amount of physical memory saved for others; compress
-   * will hog the rest.
-   */
-#ifndef SACREDMEM
-#define SACREDMEM  0
-#endif
-
-#ifndef USERMEM
-# define USERMEM   450000  /* default user memory */
-#endif
-
-#ifdef pdp11
-# define BITS   12  /* max bits/code for 16-bit machine */
-# define NO_UCHAR  /* also if "unsigned char" functions as signed char */
-# undef USERMEM
-#endif /* pdp11 */  /* don't forget to compile with -i */
-
-#ifdef USERMEM
-# if USERMEM >= (433484+SACREDMEM)
-#  define PBITS  16
-# else
-#  if USERMEM >= (229600+SACREDMEM)
-#   define PBITS  15
-#  else
-#   if USERMEM >= (127536+SACREDMEM)
-#    define PBITS  14
-#   else
-#    if USERMEM >= (73464+SACREDMEM)
-#     define PBITS  13
-#    else
-#     define PBITS  12
-#    endif
-#   endif
-#  endif
-# endif
-# undef USERMEM
-#endif /* USERMEM */
-
-#ifdef PBITS    /* Preferred BITS for this memory size */
-# ifndef BITS
-#  define BITS PBITS
-# endif /* BITS */
-#endif /* PBITS */
-
-#if BITS == 16
-# define HSIZE  69001    /* 95% occupancy */
-#endif
-#if BITS == 15
-# define HSIZE  35023    /* 94% occupancy */
-#endif
-#if BITS == 14
-# define HSIZE  18013    /* 91% occupancy */
-#endif
-#if BITS == 13
-# define HSIZE  9001    /* 91% occupancy */
-#endif
-#if BITS <= 12
-# define HSIZE  5003    /* 80% occupancy */
-#endif
-
-  /*
-   * a code_int must be able to hold 2**BITS values of type int, and also -1
-   */
-#if BITS > 15
-  typedef long int  code_int;
-#else
-  typedef int    code_int;
-#endif
-
-#ifdef SIGNED_COMPARE_SLOW
-  typedef unsigned long int count_int;
-  typedef unsigned short int count_short;
-#else
-  typedef long int    count_int;
-#endif
-
-#ifdef NO_UCHAR
-  typedef char  char_type;
-#else
-  typedef  unsigned char  char_type;
-#endif /* UCHAR */
-
-
-
-  struct cmcompress_stream
-    {
-    int n_bits;        /* number of bits/code */
-    int maxbits;      /* user settable max # bits/code */
-    code_int maxcode;      /* maximum code, given n_bits */
-    code_int maxmaxcode;  /* should NEVER generate this code */
-
-    count_int htab [HSIZE];
-    unsigned short codetab [HSIZE];
-
-    code_int hsize;      /* for dynamic table sizing */
-    code_int free_ent;      /* first unused entry */
-    int nomagic;  /* Use a 3-byte magic number header, unless old file */
-
-    /*
-     * block compression parameters -- after all codes are used up,
-     * and compression rate changes, start over.
-     */
-    int block_compress;
-    int clear_flg;
-    long int ratio;
-    count_int checkpoint;
-
-#ifdef DEBUG
-    int debug;
-    int verbose;
-#endif
-
-    /* compress internals */
-    int offset;
-    long int in_count;      /* length of input */
-    long int bytes_out;      /* length of compressed output */
-    long int out_count;      /* # of codes output (for debugging) */
-
-    /* internals */
-    code_int ent;
-    code_int hsize_reg;
-    int hshift;
-
-    long fcode;
-    int first_pass;
-
-    /* For input and output */
-    int (*input_stream)(void*);
-    int (*output_stream)(void*, const char*,int);
-    void* client_data;
-    };
-
-  int cmcompress_compress_initialize(struct cmcompress_stream* cdata);
-  int cmcompress_compress_start(struct cmcompress_stream* cdata);
-  int cmcompress_compress(struct cmcompress_stream* cdata, void* buff, size_t n);
-  int cmcompress_compress_finalize(struct cmcompress_stream* cdata);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* cmcompress__h_ */
diff --git a/Utilities/cmcompress/compress.c.original b/Utilities/cmcompress/compress.c.original
deleted file mode 100644
index 5062bda..0000000
--- a/Utilities/cmcompress/compress.c.original
+++ /dev/null
@@ -1,1308 +0,0 @@
-/*
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1985, 1986 The Regents of the University of California.\n\
- All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)compress.c	5.19 (Berkeley) 3/18/91";
-#endif /* not lint */
-
-/*
- * compress.c - File compression ala IEEE Computer, June 1984.
- *
- * Authors:	Spencer W. Thomas	(decvax!utah-cs!thomas)
- *		Jim McKie		(decvax!mcvax!jim)
- *		Steve Davies		(decvax!vax135!petsd!peora!srd)
- *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
- *		James A. Woods		(decvax!ihnp4!ames!jaw)
- *		Joe Orost		(decvax!vax135!petsd!joe)
- */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <utime.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Set USERMEM to the maximum amount of physical user memory available
- * in bytes.  USERMEM is used to determine the maximum BITS that can be used
- * for compression.
- *
- * SACREDMEM is the amount of physical memory saved for others; compress
- * will hog the rest.
- */
-#ifndef SACREDMEM
-#define SACREDMEM	0
-#endif
-
-#ifndef USERMEM
-# define USERMEM 	450000	/* default user memory */
-#endif
-
-#ifdef pdp11
-# define BITS 	12	/* max bits/code for 16-bit machine */
-# define NO_UCHAR	/* also if "unsigned char" functions as signed char */
-# undef USERMEM 
-#endif /* pdp11 */	/* don't forget to compile with -i */
-
-#ifdef USERMEM
-# if USERMEM >= (433484+SACREDMEM)
-#  define PBITS	16
-# else
-#  if USERMEM >= (229600+SACREDMEM)
-#   define PBITS	15
-#  else
-#   if USERMEM >= (127536+SACREDMEM)
-#    define PBITS	14
-#   else
-#    if USERMEM >= (73464+SACREDMEM)
-#     define PBITS	13
-#    else
-#     define PBITS	12
-#    endif
-#   endif
-#  endif
-# endif
-# undef USERMEM
-#endif /* USERMEM */
-
-#ifdef PBITS		/* Preferred BITS for this memory size */
-# ifndef BITS
-#  define BITS PBITS
-# endif BITS
-#endif /* PBITS */
-
-#if BITS == 16
-# define HSIZE	69001		/* 95% occupancy */
-#endif
-#if BITS == 15
-# define HSIZE	35023		/* 94% occupancy */
-#endif
-#if BITS == 14
-# define HSIZE	18013		/* 91% occupancy */
-#endif
-#if BITS == 13
-# define HSIZE	9001		/* 91% occupancy */
-#endif
-#if BITS <= 12
-# define HSIZE	5003		/* 80% occupancy */
-#endif
-
-/*
- * a code_int must be able to hold 2**BITS values of type int, and also -1
- */
-#if BITS > 15
-typedef long int	code_int;
-#else
-typedef int		code_int;
-#endif
-
-#ifdef SIGNED_COMPARE_SLOW
-typedef unsigned long int count_int;
-typedef unsigned short int count_short;
-#else
-typedef long int	  count_int;
-#endif
-
-#ifdef NO_UCHAR
- typedef char	char_type;
-#else
- typedef	unsigned char	char_type;
-#endif /* UCHAR */
-char_type magic_header[] = { "\037\235" };	/* 1F 9D */
-
-/* Defines for third byte of header */
-#define BIT_MASK	0x1f
-#define BLOCK_MASK	0x80
-/* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
-   a fourth header byte (for expansion).
-*/
-#define INIT_BITS 9			/* initial number of bits/code */
-
-int n_bits;				/* number of bits/code */
-int maxbits = BITS;			/* user settable max # bits/code */
-code_int maxcode;			/* maximum code, given n_bits */
-code_int maxmaxcode = 1 << BITS;	/* should NEVER generate this code */
-#ifdef COMPATIBLE		/* But wrong! */
-# define MAXCODE(n_bits)	(1 << (n_bits) - 1)
-#else
-# define MAXCODE(n_bits)	((1 << (n_bits)) - 1)
-#endif /* COMPATIBLE */
-
-count_int htab [HSIZE];
-unsigned short codetab [HSIZE];
-
-#define htabof(i)	htab[i]
-#define codetabof(i)	codetab[i]
-code_int hsize = HSIZE;			/* for dynamic table sizing */
-count_int fsize;
-
-/*
- * To save much memory, we overlay the table used by compress() with those
- * used by decompress().  The tab_prefix table is the same size and type
- * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
- * get this from the beginning of htab.  The output stack uses the rest
- * of htab, and contains characters.  There is plenty of room for any
- * possible stack (stack used to be 8000 characters).
- */
-
-#define tab_prefixof(i)	codetabof(i)
-# define tab_suffixof(i)	((char_type *)(htab))[i]
-# define de_stack		((char_type *)&tab_suffixof(1<<BITS))
-
-code_int free_ent = 0;			/* first unused entry */
-int exit_stat = 0;			/* per-file status */
-int perm_stat = 0;			/* permanent status */
-
-code_int getcode();
-
-int nomagic = 0;	/* Use a 3-byte magic number header, unless old file */
-int zcat_flg = 0;	/* Write output on stdout, suppress messages */
-int precious = 1;	/* Don't unlink output file on interrupt */
-int quiet = 1;		/* don't tell me about compression */
-
-/*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
-int block_compress = BLOCK_MASK;
-int clear_flg = 0;
-long int ratio = 0;
-#define CHECK_GAP 10000	/* ratio check interval */
-count_int checkpoint = CHECK_GAP;
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */ 
-#define FIRST	257	/* first free entry */
-#define	CLEAR	256	/* table clear output code */
-
-int force = 0;
-char ofname [100];
-#ifdef DEBUG
-int debug, verbose;
-#endif
-sig_t oldint;
-int bgnd_flag;
-
-int do_decomp = 0;
-
-/*-
- * Algorithm from "A Technique for High Performance Data Compression",
- * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
- *
- * Usage: compress [-dfvc] [-b bits] [file ...]
- * Inputs:
- *	-d:	    If given, decompression is done instead.
- *
- *      -c:         Write output on stdout, don't remove original.
- *
- *      -b:         Parameter limits the max number of bits/code.
- *
- *	-f:	    Forces output file to be generated, even if one already
- *		    exists, and even if no space is saved by compressing.
- *		    If -f is not used, the user will be prompted if stdin is
- *		    a tty, otherwise, the output file will not be overwritten.
- *
- *      -v:	    Write compression statistics
- *
- * 	file ...:   Files to be compressed.  If none specified, stdin
- *		    is used.
- * Outputs:
- *	file.Z:	    Compressed form of file with same mode, owner, and utimes
- * 	or stdout   (if stdin used as input)
- *
- * Assumptions:
- *	When filenames are given, replaces with the compressed version
- *	(.Z suffix) only if the file decreases in size.
- * Algorithm:
- * 	Modified Lempel-Ziv method (LZW).  Basically finds common
- * substrings and replaces them with a variable size code.  This is
- * deterministic, and can be done on the fly.  Thus, the decompression
- * procedure needs no input table, but tracks the way the table was built.
- */
-
-main(argc, argv)
-	int argc;
-	char **argv;
-{
-	extern int optind;
-	extern char *optarg;
-	struct stat statbuf;
-	int ch, overwrite;
-	char **filelist, **fileptr, *cp, tempname[MAXPATHLEN];
-	void onintr(), oops();
-
-	/* This bg check only works for sh. */
-	if ((oldint = signal(SIGINT, SIG_IGN)) != SIG_IGN) {
-		(void)signal(SIGINT, onintr);
-		(void)signal(SIGSEGV, oops);		/* XXX */
-	}
-	bgnd_flag = oldint != SIG_DFL;
-    
-#ifdef COMPATIBLE
-	nomagic = 1;		/* Original didn't have a magic number */
-#endif
-
-	if (cp = rindex(argv[0], '/'))
-		++cp;
-	else
-		cp = argv[0];
-	if (strcmp(cp, "uncompress") == 0)
-		do_decomp = 1;
-	else if(strcmp(cp, "zcat") == 0) {
-		do_decomp = 1;
-		zcat_flg = 1;
-	}
-
-	/*
-	 * -b maxbits => maxbits.
-	 * -C => generate output compatible with compress 2.0.
-	 * -c => cat all output to stdout
-	 * -D => debug
-	 * -d => do_decomp
-	 * -f => force overwrite of output file
-	 * -n => no header: useful to uncompress old files
-	 * -V => print Version; debug verbose
-	 * -v => unquiet
-	 */
-	
-	overwrite = 0;
-#ifdef DEBUG
-	while ((ch = getopt(argc, argv, "b:CcDdfnVv")) != EOF)
-#else
-	while ((ch = getopt(argc, argv, "b:Ccdfnv")) != EOF)
-#endif
-		switch(ch) {
-		case 'b':
-			maxbits = atoi(optarg);
-			break;
-		case 'C':
-			block_compress = 0;
-			break;
-		case 'c':
-			zcat_flg = 1;
-			break;
-#ifdef DEBUG
-		case 'D':
-			debug = 1;
-			break;
-#endif
-		case 'd':
-			do_decomp = 1;
-			break;
-		case 'f':
-			overwrite = 1;
-			force = 1;
-			break;
-		case 'n':
-			nomagic = 1;
-			break;
-		case 'q':
-			quiet = 1;
-			break;
-#ifdef DEBUG
-		case 'V':
-			verbose = 1;
-			break;
-#endif
-		case 'v':
-			quiet = 0;
-			break;
-		case '?':
-		default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (maxbits < INIT_BITS)
-		maxbits = INIT_BITS;
-	if (maxbits > BITS)
-		maxbits = BITS;
-	maxmaxcode = 1 << maxbits;
-
-	/* Build useless input file list. */
-	filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
-	while (*argv)
-		*fileptr++ = *argv++;
-	*fileptr = NULL;
-
-    if (*filelist != NULL) {
-	for (fileptr = filelist; *fileptr; fileptr++) {
-	    exit_stat = 0;
-	    if (do_decomp) {			/* DECOMPRESSION */
-		/* Check for .Z suffix */
-		if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
-		    /* No .Z: tack one on */
-		    strcpy(tempname, *fileptr);
-		    strcat(tempname, ".Z");
-		    *fileptr = tempname;
-		}
-		/* Open input file */
-		if ((freopen(*fileptr, "r", stdin)) == NULL) {
-		    perror(*fileptr);
-		    perm_stat = 1;
-		    continue;
-		}
-		/* Check the magic number */
-		if (nomagic == 0) {
-		    if ((getchar() != (magic_header[0] & 0xFF))
-		     || (getchar() != (magic_header[1] & 0xFF))) {
-			fprintf(stderr, "%s: not in compressed format\n",
-			    *fileptr);
-		    continue;
-		    }
-		    maxbits = getchar();	/* set -b from file */
-		    block_compress = maxbits & BLOCK_MASK;
-		    maxbits &= BIT_MASK;
-		    maxmaxcode = 1 << maxbits;
-		    if(maxbits > BITS) {
-			fprintf(stderr,
-			"%s: compressed with %d bits, can only handle %d bits\n",
-			*fileptr, maxbits, BITS);
-			continue;
-		    }
-		}
-		/* Generate output filename */
-		strcpy(ofname, *fileptr);
-		ofname[strlen(*fileptr) - 2] = '\0';  /* Strip off .Z */
-	    } else {					/* COMPRESSION */
-		if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
-		    	fprintf(stderr, "%s: already has .Z suffix -- no change\n",
-			    *fileptr);
-		    continue;
-		}
-		/* Open input file */
-		if ((freopen(*fileptr, "r", stdin)) == NULL) {
-		    perror(*fileptr);
-		    perm_stat = 1;
-		    continue;
-		}
-		stat ( *fileptr, &statbuf );
-		fsize = (long) statbuf.st_size;
-		/*
-		 * tune hash table size for small files -- ad hoc,
-		 * but the sizes match earlier #defines, which
-		 * serve as upper bounds on the number of output codes. 
-		 */
-		hsize = HSIZE;
-		if ( fsize < (1 << 12) )
-		    hsize = MIN ( 5003, HSIZE );
-		else if ( fsize < (1 << 13) )
-		    hsize = MIN ( 9001, HSIZE );
-		else if ( fsize < (1 << 14) )
-		    hsize = MIN ( 18013, HSIZE );
-		else if ( fsize < (1 << 15) )
-		    hsize = MIN ( 35023, HSIZE );
-		else if ( fsize < 47000 )
-		    hsize = MIN ( 50021, HSIZE );
-
-		/* Generate output filename */
-		strcpy(ofname, *fileptr);
-		strcat(ofname, ".Z");
-	    }
-	    /* Check for overwrite of existing file */
-	    if (overwrite == 0 && zcat_flg == 0) {
-		if (stat(ofname, &statbuf) == 0) {
-		    char response[2];
-		    response[0] = 'n';
-		    fprintf(stderr, "%s already exists;", ofname);
-		    if (bgnd_flag == 0 && isatty(2)) {
-			fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
-			ofname);
-			fflush(stderr);
-			read(2, response, 2);
-			while (response[1] != '\n') {
-			    if (read(2, response+1, 1) < 0) {	/* Ack! */
-				perror("stderr"); break;
-			    }
-			}
-		    }
-		    if (response[0] != 'y') {
-			fprintf(stderr, "\tnot overwritten\n");
-			continue;
-		    }
-		}
-	    }
-	    if(zcat_flg == 0) {		/* Open output file */
-		if (freopen(ofname, "w", stdout) == NULL) {
-		    perror(ofname);
-		    perm_stat = 1;
-		    continue;
-		}
-		precious = 0;
-		if(!quiet)
-			fprintf(stderr, "%s: ", *fileptr);
-	    }
-
-	    /* Actually do the compression/decompression */
-	    if (do_decomp == 0)	compress();
-#ifndef DEBUG
-	    else			decompress();
-#else
-	    else if (debug == 0)	decompress();
-	    else			printcodes();
-	    if (verbose)		dump_tab();
-#endif /* DEBUG */
-	    if(zcat_flg == 0) {
-		copystat(*fileptr, ofname);	/* Copy stats */
-		precious = 1;
-		if((exit_stat == 1) || (!quiet))
-			putc('\n', stderr);
-	    }
-	}
-    } else {		/* Standard input */
-	if (do_decomp == 0) {
-		compress();
-#ifdef DEBUG
-		if(verbose)		dump_tab();
-#endif /* DEBUG */
-		if(!quiet)
-			putc('\n', stderr);
-	} else {
-	    /* Check the magic number */
-	    if (nomagic == 0) {
-		if ((getchar()!=(magic_header[0] & 0xFF))
-		 || (getchar()!=(magic_header[1] & 0xFF))) {
-		    fprintf(stderr, "stdin: not in compressed format\n");
-		    exit(1);
-		}
-		maxbits = getchar();	/* set -b from file */
-		block_compress = maxbits & BLOCK_MASK;
-		maxbits &= BIT_MASK;
-		maxmaxcode = 1 << maxbits;
-		fsize = 100000;		/* assume stdin large for USERMEM */
-		if(maxbits > BITS) {
-			fprintf(stderr,
-			"stdin: compressed with %d bits, can only handle %d bits\n",
-			maxbits, BITS);
-			exit(1);
-		}
-	    }
-#ifndef DEBUG
-	    decompress();
-#else
-	    if (debug == 0)	decompress();
-	    else		printcodes();
-	    if (verbose)	dump_tab();
-#endif /* DEBUG */
-	}
-    }
-    exit(perm_stat ? perm_stat : exit_stat);
-}
-
-static int offset;
-long int in_count = 1;			/* length of input */
-long int bytes_out;			/* length of compressed output */
-long int out_count = 0;			/* # of codes output (for debugging) */
-
-/*
- * compress stdin to stdout
- *
- * Algorithm:  use open addressing double hashing (no chaining) on the 
- * prefix code / next character combination.  We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe.  Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation.  Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills.  The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor.  Late addition:  construct the table according to
- * file size for noticeable speed improvement on small files.  Please direct
- * questions about this implementation to ames!jaw.
- */
-
-compress()
-{
-    register long fcode;
-    register code_int i = 0;
-    register int c;
-    register code_int ent;
-    register int disp;
-    register code_int hsize_reg;
-    register int hshift;
-
-#ifndef COMPATIBLE
-    if (nomagic == 0) {
-	putchar(magic_header[0]);
-	putchar(magic_header[1]);
-	putchar((char)(maxbits | block_compress));
-	if(ferror(stdout))
-		writeerr();
-    }
-#endif /* COMPATIBLE */
-
-    offset = 0;
-    bytes_out = 3;		/* includes 3-byte header mojo */
-    out_count = 0;
-    clear_flg = 0;
-    ratio = 0;
-    in_count = 1;
-    checkpoint = CHECK_GAP;
-    maxcode = MAXCODE(n_bits = INIT_BITS);
-    free_ent = ((block_compress) ? FIRST : 256 );
-
-    ent = getchar ();
-
-    hshift = 0;
-    for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
-    	hshift++;
-    hshift = 8 - hshift;		/* set hash code range bound */
-
-    hsize_reg = hsize;
-    cl_hash( (count_int) hsize_reg);		/* clear hash table */
-
-#ifdef SIGNED_COMPARE_SLOW
-    while ( (c = getchar()) != (unsigned) EOF ) {
-#else
-    while ( (c = getchar()) != EOF ) {
-#endif
-	in_count++;
-	fcode = (long) (((long) c << maxbits) + ent);
- 	i = ((c << hshift) ^ ent);	/* xor hashing */
-
-	if ( htabof (i) == fcode ) {
-	    ent = codetabof (i);
-	    continue;
-	} else if ( (long)htabof (i) < 0 )	/* empty slot */
-	    goto nomatch;
- 	disp = hsize_reg - i;		/* secondary hash (after G. Knott) */
-	if ( i == 0 )
-	    disp = 1;
-probe:
-	if ( (i -= disp) < 0 )
-	    i += hsize_reg;
-
-	if ( htabof (i) == fcode ) {
-	    ent = codetabof (i);
-	    continue;
-	}
-	if ( (long)htabof (i) > 0 ) 
-	    goto probe;
-nomatch:
-	output ( (code_int) ent );
-	out_count++;
- 	ent = c;
-#ifdef SIGNED_COMPARE_SLOW
-	if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
-#else
-	if ( free_ent < maxmaxcode ) {
-#endif
- 	    codetabof (i) = free_ent++;	/* code -> hashtable */
-	    htabof (i) = fcode;
-	}
-	else if ( (count_int)in_count >= checkpoint && block_compress )
-	    cl_block ();
-    }
-    /*
-     * Put out the final code.
-     */
-    output( (code_int)ent );
-    out_count++;
-    output( (code_int)-1 );
-
-    /*
-     * Print out stats on stderr
-     */
-    if(zcat_flg == 0 && !quiet) {
-#ifdef DEBUG
-	fprintf( stderr,
-		"%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
-		in_count, out_count, bytes_out );
-	prratio( stderr, in_count, bytes_out );
-	fprintf( stderr, "\n");
-	fprintf( stderr, "\tCompression as in compact: " );
-	prratio( stderr, in_count-bytes_out, in_count );
-	fprintf( stderr, "\n");
-	fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
-		free_ent - 1, n_bits );
-#else /* !DEBUG */
-	fprintf( stderr, "Compression: " );
-	prratio( stderr, in_count-bytes_out, in_count );
-#endif /* DEBUG */
-    }
-    if(bytes_out > in_count)	/* exit(2) if no savings */
-	exit_stat = 2;
-    return;
-}
-
-/*-
- * Output the given code.
- * Inputs:
- * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
- *		that n_bits =< (long)wordsize - 1.
- * Outputs:
- * 	Outputs code to the file.
- * Assumptions:
- *	Chars are 8 bits long.
- * Algorithm:
- * 	Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly).  Use the VAX insv instruction to insert each
- * code in turn.  When the buffer fills up empty it and start over.
- */
-
-static char buf[BITS];
-
-#ifndef vax
-char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
-char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-#endif /* vax */
-
-output( code )
-code_int  code;
-{
-#ifdef DEBUG
-    static int col = 0;
-#endif /* DEBUG */
-
-    /*
-     * On the VAX, it is important to have the register declarations
-     * in exactly the order given, or the asm will break.
-     */
-    register int r_off = offset, bits= n_bits;
-    register char * bp = buf;
-
-#ifdef DEBUG
-	if ( verbose )
-	    fprintf( stderr, "%5d%c", code,
-		    (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
-#endif /* DEBUG */
-    if ( code >= 0 ) {
-#if defined(vax) && !defined(__GNUC__)
-	/*
-	 * VAX and PCC DEPENDENT!! Implementation on other machines is
-	 * below.
-	 *
-	 * Translation: Insert BITS bits from the argument starting at
-	 * offset bits from the beginning of buf.
-	 */
-	0;	/* Work around for pcc -O bug with asm and if stmt */
-	asm( "insv	4(ap),r11,r10,(r9)" );
-#else
-/* 
- * byte/bit numbering on the VAX is simulated by the following code
- */
-	/*
-	 * Get to the first byte.
-	 */
-	bp += (r_off >> 3);
-	r_off &= 7;
-	/*
-	 * Since code is always >= 8 bits, only need to mask the first
-	 * hunk on the left.
-	 */
-	*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
-	bp++;
-	bits -= (8 - r_off);
-	code >>= 8 - r_off;
-	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
-	if ( bits >= 8 ) {
-	    *bp++ = code;
-	    code >>= 8;
-	    bits -= 8;
-	}
-	/* Last bits. */
-	if(bits)
-	    *bp = code;
-#endif /* vax */
-	offset += n_bits;
-	if ( offset == (n_bits << 3) ) {
-	    bp = buf;
-	    bits = n_bits;
-	    bytes_out += bits;
-	    do {
-		putchar(*bp++);
-		if (ferror(stdout))
-			writeerr();
-	    } while(--bits);
-	    offset = 0;
-	}
-
-	/*
-	 * If the next entry is going to be too big for the code size,
-	 * then increase it, if possible.
-	 */
-	if ( free_ent > maxcode || (clear_flg > 0))
-	{
-	    /*
-	     * Write the whole buffer, because the input side won't
-	     * discover the size increase until after it has read it.
-	     */
-	    if ( offset > 0 ) {
-		if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
-			writeerr();
-		bytes_out += n_bits;
-	    }
-	    offset = 0;
-
-	    if ( clear_flg ) {
-    	        maxcode = MAXCODE (n_bits = INIT_BITS);
-	        clear_flg = 0;
-	    }
-	    else {
-	    	n_bits++;
-	    	if ( n_bits == maxbits )
-		    maxcode = maxmaxcode;
-	    	else
-		    maxcode = MAXCODE(n_bits);
-	    }
-#ifdef DEBUG
-	    if ( debug ) {
-		fprintf( stderr, "\nChange to %d bits\n", n_bits );
-		col = 0;
-	    }
-#endif /* DEBUG */
-	}
-    } else {
-	/*
-	 * At EOF, write the rest of the buffer.
-	 */
-	if ( offset > 0 ) {
-		offset = (offset + 7) / 8;
-		if( fwrite( buf, 1, offset, stdout ) != offset )
-			writeerr();
-		bytes_out += offset;
-	}
-	offset = 0;
-	(void)fflush( stdout );
-	if( ferror( stdout ) )
-		writeerr();
-#ifdef DEBUG
-	if ( verbose )
-	    fprintf( stderr, "\n" );
-#endif
-    }
-}
-
-/*
- * Decompress stdin to stdout.  This routine adapts to the codes in the
- * file building the "string" table on-the-fly; requiring no table to
- * be stored in the compressed file.  The tables used herein are shared
- * with those of the compress() routine.  See the definitions above.
- */
-
-decompress() {
-    register char_type *stackp;
-    register int finchar;
-    register code_int code, oldcode, incode;
-    int    n, nwritten, offset;		/* Variables for buffered write */
-    char buff[BUFSIZ];			/* Buffer for buffered write */
-
-
-    /*
-     * As above, initialize the first 256 entries in the table.
-     */
-    maxcode = MAXCODE(n_bits = INIT_BITS);
-    for ( code = 255; code >= 0; code-- ) {
-	tab_prefixof(code) = 0;
-	tab_suffixof(code) = (char_type)code;
-    }
-    free_ent = ((block_compress) ? FIRST : 256 );
-
-    finchar = oldcode = getcode();
-    if(oldcode == -1)	/* EOF already? */
-	return;			/* Get out of here */
-
-    /* first code must be 8 bits = char */
-    n=0;
-    buff[n++] = (char)finchar;
-
-    stackp = de_stack;
-
-    while ( (code = getcode()) > -1 ) {
-
-	if ( (code == CLEAR) && block_compress ) {
-	    for ( code = 255; code >= 0; code-- )
-		tab_prefixof(code) = 0;
-	    clear_flg = 1;
-	    free_ent = FIRST - 1;
-	    if ( (code = getcode ()) == -1 )	/* O, untimely death! */
-		break;
-	}
-	incode = code;
-	/*
-	 * Special case for KwKwK string.
-	 */
-	if ( code >= free_ent ) {
-            *stackp++ = finchar;
-	    code = oldcode;
-	}
-
-	/*
-	 * Generate output characters in reverse order
-	 */
-#ifdef SIGNED_COMPARE_SLOW
-	while ( ((unsigned long)code) >= ((unsigned long)256) ) {
-#else
-	while ( code >= 256 ) {
-#endif
-	    *stackp++ = tab_suffixof(code);
-	    code = tab_prefixof(code);
-	}
-	*stackp++ = finchar = tab_suffixof(code);
-
-	/*
-	 * And put them out in forward order
-	 */
-	do {
-	    /*
-	     * About 60% of the time is spent in the putchar() call
-	     * that appeared here.  It was originally
-	     *		putchar ( *--stackp );
-	     * If we buffer the writes ourselves, we can go faster (about
-	     * 30%).
-	     *
-	     * At this point, the next line is the next *big* time
-	     * sink in the code.  It takes up about 10% of the time.
-	     */
-	     buff[n++] = *--stackp;
-	     if (n == BUFSIZ) {
-		 offset = 0;
-		 do {
-		     nwritten = write(fileno(stdout), &buff[offset], n);
-		     if (nwritten < 0)
-			 writeerr();
-		     offset += nwritten;
-		 } while ((n -= nwritten) > 0);
-	      }
-	} while ( stackp > de_stack );
-
-	/*
-	 * Generate the new entry.
-	 */
-	if ( (code=free_ent) < maxmaxcode ) {
-	    tab_prefixof(code) = (unsigned short)oldcode;
-	    tab_suffixof(code) = finchar;
-	    free_ent = code+1;
-	} 
-	/*
-	 * Remember previous code.
-	 */
-	oldcode = incode;
-    }
-    /*
-     * Flush the stuff remaining in our buffer...
-     */
-    offset = 0;
-    while (n > 0) {
-	nwritten = write(fileno(stdout), &buff[offset], n);
-	if (nwritten < 0)
-	    writeerr();
-	offset += nwritten;
-	n -= nwritten;
-    }
-}
-
-/*-
- * Read one code from the standard input.  If EOF, return -1.
- * Inputs:
- * 	stdin
- * Outputs:
- * 	code or -1 is returned.
- */
-code_int
-getcode() {
-    /*
-     * On the VAX, it is important to have the register declarations
-     * in exactly the order given, or the asm will break.
-     */
-    register code_int code;
-    static int offset = 0, size = 0;
-    static char_type buf[BITS];
-    register int r_off, bits;
-    register char_type *bp = buf;
-
-    if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
-	/*
-	 * If the next entry will be too big for the current code
-	 * size, then we must increase the size.  This implies reading
-	 * a new buffer full, too.
-	 */
-	if ( free_ent > maxcode ) {
-	    n_bits++;
-	    if ( n_bits == maxbits )
-		maxcode = maxmaxcode;	/* won't get any bigger now */
-	    else
-		maxcode = MAXCODE(n_bits);
-	}
-	if ( clear_flg > 0) {
-    	    maxcode = MAXCODE (n_bits = INIT_BITS);
-	    clear_flg = 0;
-	}
-	size = fread( buf, 1, n_bits, stdin );
-	if ( size <= 0 )
-	    return -1;			/* end of file */
-	offset = 0;
-	/* Round size down to integral number of codes */
-	size = (size << 3) - (n_bits - 1);
-    }
-    r_off = offset;
-    bits = n_bits;
-#ifdef vax
-    asm( "extzv   r10,r9,(r8),r11" );
-#else /* not a vax */
-	/*
-	 * Get to the first byte.
-	 */
-	bp += (r_off >> 3);
-	r_off &= 7;
-	/* Get first part (low order bits) */
-#ifdef NO_UCHAR
-	code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
-#else
-	code = (*bp++ >> r_off);
-#endif /* NO_UCHAR */
-	bits -= (8 - r_off);
-	r_off = 8 - r_off;		/* now, offset into code word */
-	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
-	if ( bits >= 8 ) {
-#ifdef NO_UCHAR
-	    code |= (*bp++ & 0xff) << r_off;
-#else
-	    code |= *bp++ << r_off;
-#endif /* NO_UCHAR */
-	    r_off += 8;
-	    bits -= 8;
-	}
-	/* high order bits. */
-	code |= (*bp & rmask[bits]) << r_off;
-#endif /* vax */
-    offset += n_bits;
-
-    return code;
-}
-
-#ifdef DEBUG
-printcodes()
-{
-    /*
-     * Just print out codes from input file.  For debugging.
-     */
-    code_int code;
-    int col = 0, bits;
-
-    bits = n_bits = INIT_BITS;
-    maxcode = MAXCODE(n_bits);
-    free_ent = ((block_compress) ? FIRST : 256 );
-    while ( ( code = getcode() ) >= 0 ) {
-	if ( (code == CLEAR) && block_compress ) {
-   	    free_ent = FIRST - 1;
-   	    clear_flg = 1;
-	}
-	else if ( free_ent < maxmaxcode )
-	    free_ent++;
-	if ( bits != n_bits ) {
-	    fprintf(stderr, "\nChange to %d bits\n", n_bits );
-	    bits = n_bits;
-	    col = 0;
-	}
-	fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
-    }
-    putc( '\n', stderr );
-    exit( 0 );
-}
-
-code_int sorttab[1<<BITS];	/* sorted pointers into htab */
-
-dump_tab()	/* dump string table */
-{
-    register int i, first;
-    register ent;
-#define STACK_SIZE	15000
-    int stack_top = STACK_SIZE;
-    register c;
-
-    if(do_decomp == 0) {	/* compressing */
-	register int flag = 1;
-
-	for(i=0; i<hsize; i++) {	/* build sort pointers */
-		if((long)htabof(i) >= 0) {
-			sorttab[codetabof(i)] = i;
-		}
-	}
-	first = block_compress ? FIRST : 256;
-	for(i = first; i < free_ent; i++) {
-		fprintf(stderr, "%5d: \"", i);
-		de_stack[--stack_top] = '\n';
-		de_stack[--stack_top] = '"';
-		stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff, 
-                                     stack_top);
-		for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
-		    ent > 256;
-		    ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
-			stack_top = in_stack(htabof(sorttab[ent]) >> maxbits,
-						stack_top);
-		}
-		stack_top = in_stack(ent, stack_top);
-		fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
-	   	stack_top = STACK_SIZE;
-	}
-   } else if(!debug) {	/* decompressing */
-
-       for ( i = 0; i < free_ent; i++ ) {
-	   ent = i;
-	   c = tab_suffixof(ent);
-	   if ( isascii(c) && isprint(c) )
-	       fprintf( stderr, "%5d: %5d/'%c'  \"",
-			   ent, tab_prefixof(ent), c );
-	   else
-	       fprintf( stderr, "%5d: %5d/\\%03o \"",
-			   ent, tab_prefixof(ent), c );
-	   de_stack[--stack_top] = '\n';
-	   de_stack[--stack_top] = '"';
-	   for ( ; ent != NULL;
-		   ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
-	       stack_top = in_stack(tab_suffixof(ent), stack_top);
-	   }
-	   fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
-	   stack_top = STACK_SIZE;
-       }
-    }
-}
-
-int
-in_stack(c, stack_top)
-	register c, stack_top;
-{
-	if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
-	    de_stack[--stack_top] = c;
-	} else {
-	    switch( c ) {
-	    case '\n': de_stack[--stack_top] = 'n'; break;
-	    case '\t': de_stack[--stack_top] = 't'; break;
-	    case '\b': de_stack[--stack_top] = 'b'; break;
-	    case '\f': de_stack[--stack_top] = 'f'; break;
-	    case '\r': de_stack[--stack_top] = 'r'; break;
-	    case '\\': de_stack[--stack_top] = '\\'; break;
-	    default:
-	 	de_stack[--stack_top] = '0' + c % 8;
-	 	de_stack[--stack_top] = '0' + (c / 8) % 8;
-	 	de_stack[--stack_top] = '0' + c / 64;
-	 	break;
-	    }
-	    de_stack[--stack_top] = '\\';
-	}
-	return stack_top;
-}
-#endif /* DEBUG */
-
-writeerr()
-{
-	(void)fprintf(stderr, "compress: %s: %s\n",
-	    ofname[0] ? ofname : "stdout", strerror(errno));
-	(void)unlink(ofname);
-	exit(1);
-}
-
-copystat(ifname, ofname)
-char *ifname, *ofname;
-{
-    struct stat statbuf;
-    int mode;
-    struct utimbuf tp;
-
-    fclose(stdout);
-    if (stat(ifname, &statbuf)) {		/* Get stat on input file */
-	perror(ifname);
-	return;
-    }
-    if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) {
-	if(quiet)
-	    	fprintf(stderr, "%s: ", ifname);
-	fprintf(stderr, " -- not a regular file: unchanged");
-	exit_stat = 1;
-	perm_stat = 1;
-    } else if (statbuf.st_nlink > 1) {
-	if(quiet)
-	    	fprintf(stderr, "%s: ", ifname);
-	fprintf(stderr, " -- has %d other links: unchanged",
-		statbuf.st_nlink - 1);
-	exit_stat = 1;
-	perm_stat = 1;
-    } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
-	if(!quiet)
-		fprintf(stderr, " -- file unchanged");
-    } else {			/* ***** Successful Compression ***** */
-	exit_stat = 0;
-	mode = statbuf.st_mode & 07777;
-	if (chmod(ofname, mode))		/* Copy modes */
-	    perror(ofname);
-	chown(ofname, statbuf.st_uid, statbuf.st_gid);	/* Copy ownership */
-	tp.actime = statbuf.st_atime;
-	tp.modtime = statbuf.st_mtime;
-	utime(ofname, &tp);	/* Update last accessed and modified times */
-	if (unlink(ifname))	/* Remove input file */
-	    perror(ifname);
-	if(!quiet)
-		fprintf(stderr, " -- replaced with %s", ofname);
-	return;		/* Successful return */
-    }
-
-    /* Unsuccessful return -- one of the tests failed */
-    if (unlink(ofname))
-	perror(ofname);
-}
-
-void
-onintr ( )
-{
-    if (!precious)
-	unlink ( ofname );
-    exit ( 1 );
-}
-
-void
-oops ( )	/* wild pointer -- assume bad input */
-{
-    if ( do_decomp ) 
-    	fprintf ( stderr, "uncompress: corrupt input\n" );
-    unlink ( ofname );
-    exit ( 1 );
-}
-
-cl_block ()		/* table clear for block compress */
-{
-    register long int rat;
-
-    checkpoint = in_count + CHECK_GAP;
-#ifdef DEBUG
-	if ( debug ) {
-    		fprintf ( stderr, "count: %ld, ratio: ", in_count );
-     		prratio ( stderr, in_count, bytes_out );
-		fprintf ( stderr, "\n");
-	}
-#endif /* DEBUG */
-
-    if(in_count > 0x007fffff) {	/* shift will overflow */
-	rat = bytes_out >> 8;
-	if(rat == 0) {		/* Don't divide by zero */
-	    rat = 0x7fffffff;
-	} else {
-	    rat = in_count / rat;
-	}
-    } else {
-	rat = (in_count << 8) / bytes_out;	/* 8 fractional bits */
-    }
-    if ( rat > ratio ) {
-	ratio = rat;
-    } else {
-	ratio = 0;
-#ifdef DEBUG
-	if(verbose)
-		dump_tab();	/* dump string table */
-#endif
- 	cl_hash ( (count_int) hsize );
-	free_ent = FIRST;
-	clear_flg = 1;
-	output ( (code_int) CLEAR );
-#ifdef DEBUG
-	if(debug)
-    		fprintf ( stderr, "clear\n" );
-#endif /* DEBUG */
-    }
-}
-
-cl_hash(hsize)		/* reset code table */
-	register count_int hsize;
-{
-	register count_int *htab_p = htab+hsize;
-	register long i;
-	register long m1 = -1;
-
-	i = hsize - 16;
- 	do {				/* might use Sys V memset(3) here */
-		*(htab_p-16) = m1;
-		*(htab_p-15) = m1;
-		*(htab_p-14) = m1;
-		*(htab_p-13) = m1;
-		*(htab_p-12) = m1;
-		*(htab_p-11) = m1;
-		*(htab_p-10) = m1;
-		*(htab_p-9) = m1;
-		*(htab_p-8) = m1;
-		*(htab_p-7) = m1;
-		*(htab_p-6) = m1;
-		*(htab_p-5) = m1;
-		*(htab_p-4) = m1;
-		*(htab_p-3) = m1;
-		*(htab_p-2) = m1;
-		*(htab_p-1) = m1;
-		htab_p -= 16;
-	} while ((i -= 16) >= 0);
-    	for ( i += 16; i > 0; i-- )
-		*--htab_p = m1;
-}
-
-prratio(stream, num, den)
-FILE *stream;
-long int num, den;
-{
-	register int q;			/* Doesn't need to be long */
-
-	if(num > 214748L) {		/* 2147483647/10000 */
-		q = num / (den / 10000L);
-	} else {
-		q = 10000L * num / den;		/* Long calculations, though */
-	}
-	if (q < 0) {
-		putc('-', stream);
-		q = -q;
-	}
-	fprintf(stream, "%d.%02d%%", q / 100, q % 100);
-}
-
-usage()
-{
-	(void)fprintf(stderr,
-#ifdef DEBUG
-	    "compress [-CDVcdfnv] [-b maxbits] [file ...]\n");
-#else
-	    "compress [-Ccdfnv] [-b maxbits] [file ...]\n");
-#endif
-	exit(1);
-}
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index 1c96497..8dc3b2c 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -77,7 +77,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmexpat/CMakeLists.txt b/Utilities/cmexpat/CMakeLists.txt
index 470fcba..13eb56d 100644
--- a/Utilities/cmexpat/CMakeLists.txt
+++ b/Utilities/cmexpat/CMakeLists.txt
@@ -1,6 +1,6 @@
 # Disable warnings to avoid changing 3rd party code.
 IF(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmjsoncpp/CMakeLists.txt b/Utilities/cmjsoncpp/CMakeLists.txt
index ef370cc..764be8d 100644
--- a/Utilities/cmjsoncpp/CMakeLists.txt
+++ b/Utilities/cmjsoncpp/CMakeLists.txt
@@ -2,7 +2,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_CXX_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
 elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall")
diff --git a/Utilities/cmjsoncpp/include/json/config.h b/Utilities/cmjsoncpp/include/json/config.h
index eb52e71..34f7314 100644
--- a/Utilities/cmjsoncpp/include/json/config.h
+++ b/Utilities/cmjsoncpp/include/json/config.h
@@ -5,13 +5,14 @@
 
 #ifndef JSON_CONFIG_H_INCLUDED
 #define JSON_CONFIG_H_INCLUDED
-#include <stddef.h>
-#include <string> //typedef String
-#include <stdint.h> //typedef int64_t, uint64_t
 
 // Include KWSys Large File Support configuration.
 #include <cmsys/Configure.h>
 
+#include <stddef.h>
+#include <string> //typedef String
+#include <stdint.h> //typedef int64_t, uint64_t
+
 #if defined(_MSC_VER)
 # pragma warning(push,1)
 #endif
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index d7af6e2..60c8316 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -60,7 +60,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 IF(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -376,6 +376,7 @@
 ENDIF(LZ4_FOUND)
 MARK_AS_ADVANCED(CLEAR LZ4_INCLUDE_DIR)
 MARK_AS_ADVANCED(CLEAR LZ4_LIBRARY)
+ENDIF()
 #
 # Find Zstd
 #
@@ -392,16 +393,13 @@
   SET(HAVE_ZSTD_H 1)
   INCLUDE_DIRECTORIES(${ZSTD_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${ZSTD_LIBRARY})
-  SET(CMAKE_REQUIRED_LIBRARIES ${ZSTD_LIBRARY})
-  SET(CMAKE_REQUIRED_INCLUDES ${ZSTD_INCLUDE_DIR})
-  CHECK_FUNCTION_EXISTS(ZSTD_compressStream HAVE_LIBZSTD)
+  SET(HAVE_LIBZSTD 1)
   #
   # TODO: test for static library.
   #
 ENDIF(ZSTD_FOUND)
 MARK_AS_ADVANCED(CLEAR ZSTD_INCLUDE_DIR)
 MARK_AS_ADVANCED(CLEAR ZSTD_LIBRARY)
-ENDIF()
 
 #
 # Check headers
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
index c8bb36b..4513706 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
@@ -45,7 +45,7 @@
 #include <unistd.h>
 #endif
 #if HAVE_ZSTD_H
-#include <zstd.h>
+#include <cm_zstd.h>
 #endif
 
 #include "archive.h"
diff --git a/Utilities/cmlibarchive/libarchive/archive_version_details.c b/Utilities/cmlibarchive/libarchive/archive_version_details.c
index e773e5e..b9af6d7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_version_details.c
+++ b/Utilities/cmlibarchive/libarchive/archive_version_details.c
@@ -46,7 +46,7 @@
 #include <lz4.h>
 #endif
 #ifdef HAVE_ZSTD_H
-#include <zstd.h>
+#include <cm_zstd.h>
 #endif
 
 #include "archive.h"
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
index 671fc6a..251b17d 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
@@ -38,7 +38,7 @@
 #include <string.h>
 #endif
 #ifdef HAVE_ZSTD_H
-#include <zstd.h>
+#include <cm_zstd.h>
 #endif
 
 #include "archive.h"
diff --git a/Utilities/cmliblzma/CMakeLists.txt b/Utilities/cmliblzma/CMakeLists.txt
index e9f8826..b443fd6 100644
--- a/Utilities/cmliblzma/CMakeLists.txt
+++ b/Utilities/cmliblzma/CMakeLists.txt
@@ -183,7 +183,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 IF(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibrhash/CMakeLists.txt b/Utilities/cmlibrhash/CMakeLists.txt
index aa28055..6067b7d 100644
--- a/Utilities/cmlibrhash/CMakeLists.txt
+++ b/Utilities/cmlibrhash/CMakeLists.txt
@@ -2,7 +2,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index a62c516..2e781f1 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -2,7 +2,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibuv/src/unix/atomic-ops.h b/Utilities/cmlibuv/src/unix/atomic-ops.h
index 7cac1f9..be741dc 100644
--- a/Utilities/cmlibuv/src/unix/atomic-ops.h
+++ b/Utilities/cmlibuv/src/unix/atomic-ops.h
@@ -37,7 +37,7 @@
                         : "r" (newval), "0" (oldval)
                         : "memory");
   return out;
-#elif defined(_AIX) && defined(__xlC__)
+#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__))
   const int out = (*(volatile int*) ptr);
   __compare_and_swap(ptr, &oldval, newval);
   return out;
@@ -63,7 +63,7 @@
                         : "r" (newval), "0" (oldval)
                         : "memory");
   return out;
-#elif defined(_AIX) && defined(__xlC__)
+#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__))
   const long out = (*(volatile int*) ptr);
 # if defined(__64BIT__)
   __compare_and_swaplp(ptr, &oldval, newval);
diff --git a/Utilities/cmzlib/CMakeLists.txt b/Utilities/cmzlib/CMakeLists.txt
index 0be48f1..888c3ff 100644
--- a/Utilities/cmzlib/CMakeLists.txt
+++ b/Utilities/cmzlib/CMakeLists.txt
@@ -2,7 +2,7 @@
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmzstd/.gitattributes b/Utilities/cmzstd/.gitattributes
new file mode 100644
index 0000000..562b12e
--- /dev/null
+++ b/Utilities/cmzstd/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmzstd/CMakeLists.txt b/Utilities/cmzstd/CMakeLists.txt
new file mode 100644
index 0000000..8ed04d8
--- /dev/null
+++ b/Utilities/cmzstd/CMakeLists.txt
@@ -0,0 +1,47 @@
+project(zstd C)
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+include_directories(lib lib/common)
+
+add_library(cmzstd STATIC
+  lib/common/entropy_common.c
+  lib/common/error_private.c
+  lib/common/fse_decompress.c
+  lib/common/pool.c
+  lib/common/threading.c
+  lib/common/xxhash.c
+  lib/common/zstd_common.c
+  lib/compress/fse_compress.c
+  lib/compress/hist.c
+  lib/compress/huf_compress.c
+  lib/compress/zstd_compress.c
+  lib/compress/zstd_double_fast.c
+  lib/compress/zstd_fast.c
+  lib/compress/zstd_lazy.c
+  lib/compress/zstd_ldm.c
+  lib/compress/zstdmt_compress.c
+  lib/compress/zstd_opt.c
+  lib/decompress/huf_decompress.c
+  lib/decompress/zstd_ddict.c
+  lib/decompress/zstd_decompress_block.c
+  lib/decompress/zstd_decompress.c
+  lib/deprecated/zbuff_common.c
+  lib/deprecated/zbuff_compress.c
+  lib/deprecated/zbuff_decompress.c
+  lib/dictBuilder/cover.c
+  lib/dictBuilder/divsufsort.c
+  lib/dictBuilder/fastcover.c
+  lib/dictBuilder/zdict.c
+  )
+
+# BMI2 instructions are not supported in older environments.
+set_property(TARGET cmzstd PROPERTY COMPILE_DEFINITIONS DYNAMIC_BMI2=0)
+
+install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmzstd)
diff --git a/Utilities/cmzstd/LICENSE b/Utilities/cmzstd/LICENSE
new file mode 100644
index 0000000..a793a80
--- /dev/null
+++ b/Utilities/cmzstd/LICENSE
@@ -0,0 +1,30 @@
+BSD License
+
+For Zstandard software
+
+Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Utilities/cmzstd/README.md b/Utilities/cmzstd/README.md
new file mode 100644
index 0000000..4b6d19e
--- /dev/null
+++ b/Utilities/cmzstd/README.md
@@ -0,0 +1,167 @@
+<p align="center"><img src="https://raw.githubusercontent.com/facebook/zstd/dev/doc/images/zstd_logo86.png" alt="Zstandard"></p>
+
+__Zstandard__, or `zstd` as short version, is a fast lossless compression algorithm,
+targeting real-time compression scenarios at zlib-level and better compression ratios.
+It's backed by a very fast entropy stage, provided by [Huff0 and FSE library](https://github.com/Cyan4973/FiniteStateEntropy).
+
+The project is provided as an open-source dual [BSD](LICENSE) and [GPLv2](COPYING) licensed **C** library,
+and a command line utility producing and decoding `.zst`, `.gz`, `.xz` and `.lz4` files.
+Should your project require another programming language,
+a list of known ports and bindings is provided on [Zstandard homepage](http://www.zstd.net/#other-languages).
+
+**Development branch status:**
+
+[![Build Status][travisDevBadge]][travisLink]
+[![Build status][AppveyorDevBadge]][AppveyorLink]
+[![Build status][CircleDevBadge]][CircleLink]
+
+[travisDevBadge]: https://travis-ci.org/facebook/zstd.svg?branch=dev "Continuous Integration test suite"
+[travisLink]: https://travis-ci.org/facebook/zstd
+[AppveyorDevBadge]: https://ci.appveyor.com/api/projects/status/xt38wbdxjk5mrbem/branch/dev?svg=true "Windows test suite"
+[AppveyorLink]: https://ci.appveyor.com/project/YannCollet/zstd-p0yf0
+[CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite"
+[CircleLink]: https://circleci.com/gh/facebook/zstd
+
+## Benchmarks
+
+For reference, several fast compression algorithms were tested and compared
+on a server running Linux Debian (`Linux version 4.14.0-3-amd64`),
+with a Core i7-6700K CPU @ 4.0GHz,
+using [lzbench], an open-source in-memory benchmark by @inikep
+compiled with [gcc] 7.3.0,
+on the [Silesia compression corpus].
+
+[lzbench]: https://github.com/inikep/lzbench
+[Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
+[gcc]: https://gcc.gnu.org/
+
+| Compressor name         | Ratio | Compression| Decompress.|
+| ---------------         | ------| -----------| ---------- |
+| **zstd 1.3.4 -1**       | 2.877 |   470 MB/s |  1380 MB/s |
+| zlib 1.2.11 -1          | 2.743 |   110 MB/s |   400 MB/s |
+| brotli 1.0.2 -0         | 2.701 |   410 MB/s |   430 MB/s |
+| quicklz 1.5.0 -1        | 2.238 |   550 MB/s |   710 MB/s |
+| lzo1x 2.09 -1           | 2.108 |   650 MB/s |   830 MB/s |
+| lz4 1.8.1               | 2.101 |   750 MB/s |  3700 MB/s |
+| snappy 1.1.4            | 2.091 |   530 MB/s |  1800 MB/s |
+| lzf 3.6 -1              | 2.077 |   400 MB/s |   860 MB/s |
+
+[zlib]: http://www.zlib.net/
+[LZ4]: http://www.lz4.org/
+
+Zstd can also offer stronger compression ratios at the cost of compression speed.
+Speed vs Compression trade-off is configurable by small increments.
+Decompression speed is preserved and remains roughly the same at all settings,
+a property shared by most LZ compression algorithms, such as [zlib] or lzma.
+
+The following tests were run
+on a server running Linux Debian (`Linux version 4.14.0-3-amd64`)
+with a Core i7-6700K CPU @ 4.0GHz,
+using [lzbench], an open-source in-memory benchmark by @inikep
+compiled with [gcc] 7.3.0,
+on the [Silesia compression corpus].
+
+Compression Speed vs Ratio | Decompression Speed
+---------------------------|--------------------
+![Compression Speed vs Ratio](doc/images/CSpeed2.png "Compression Speed vs Ratio") | ![Decompression Speed](doc/images/DSpeed3.png "Decompression Speed")
+
+A few other algorithms can produce higher compression ratios at slower speeds, falling outside of the graph.
+For a larger picture including slow modes, [click on this link](doc/images/DCspeed5.png).
+
+
+## The case for Small Data compression
+
+Previous charts provide results applicable to typical file and stream scenarios (several MB). Small data comes with different perspectives.
+
+The smaller the amount of data to compress, the more difficult it is to compress. This problem is common to all compression algorithms, and reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new data set, there is no "past" to build upon.
+
+To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data.
+Training Zstandard is achieved by providing it with a few samples (one file per sample). The result of this training is stored in a file called "dictionary", which must be loaded before compression and decompression.
+Using this dictionary, the compression ratio achievable on small data improves dramatically.
+
+The following example uses the `github-users` [sample set](https://github.com/facebook/zstd/releases/tag/v1.1.3), created from [github public API](https://developer.github.com/v3/users/#get-all-users).
+It consists of roughly 10K records weighing about 1KB each.
+
+Compression Ratio | Compression Speed | Decompression Speed
+------------------|-------------------|--------------------
+![Compression Ratio](doc/images/dict-cr.png "Compression Ratio") | ![Compression Speed](doc/images/dict-cs.png "Compression Speed") | ![Decompression Speed](doc/images/dict-ds.png "Decompression Speed")
+
+
+These compression gains are achieved while simultaneously providing _faster_ compression and decompression speeds.
+
+Training works if there is some correlation in a family of small data samples. The more data-specific a dictionary is, the more efficient it is (there is no _universal dictionary_).
+Hence, deploying one dictionary per type of data will provide the greatest benefits.
+Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will gradually use previously decoded content to better compress the rest of the file.
+
+### Dictionary compression How To:
+
+1. Create the dictionary
+
+   `zstd --train FullPathToTrainingSet/* -o dictionaryName`
+
+2. Compress with dictionary
+
+   `zstd -D dictionaryName FILE`
+
+3. Decompress with dictionary
+
+   `zstd -D dictionaryName --decompress FILE.zst`
+
+
+## Build instructions
+
+### Makefile
+
+If your system is compatible with standard `make` (or `gmake`),
+invoking `make` in root directory will generate `zstd` cli in root directory.
+
+Other available options include:
+- `make install` : create and install zstd cli, library and man pages
+- `make check` : create and run `zstd`, tests its behavior on local platform
+
+### cmake
+
+A `cmake` project generator is provided within `build/cmake`.
+It can generate Makefiles or other build scripts
+to create `zstd` binary, and `libzstd` dynamic and static libraries.
+
+By default, `CMAKE_BUILD_TYPE` is set to `Release`.
+
+### Meson
+
+A Meson project is provided within [`build/meson`](build/meson). Follow
+build instructions in that directory.
+
+You can also take a look at [`.travis.yml`](.travis.yml) file for an
+example about how Meson is used to build this project.
+
+Note that default build type is **release**.
+
+### Visual Studio (Windows)
+
+Going into `build` directory, you will find additional possibilities:
+- Projects for Visual Studio 2005, 2008 and 2010.
+  + VS2010 project is compatible with VS2012, VS2013, VS2015 and VS2017.
+- Automated build scripts for Visual compiler by [@KrzysFR](https://github.com/KrzysFR), in `build/VS_scripts`,
+  which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution.
+
+### Buck
+
+You can build the zstd binary via buck by executing: `buck build programs:zstd` from the root of the repo.
+The output binary will be in `buck-out/gen/programs/`.
+
+## Status
+
+Zstandard is currently deployed within Facebook. It is used continuously to compress large amounts of data in multiple formats and use cases.
+Zstandard is considered safe for production environments.
+
+## License
+
+Zstandard is dual-licensed under [BSD](LICENSE) and [GPLv2](COPYING).
+
+## Contributing
+
+The "dev" branch is the one where all contributions are merged before reaching "master".
+If you plan to propose a patch, please commit into the "dev" branch, or its own feature branch.
+Direct commit to "master" are not permitted.
+For more information, please read [CONTRIBUTING](CONTRIBUTING.md).
diff --git a/Utilities/cmzstd/lib/common/bitstream.h b/Utilities/cmzstd/lib/common/bitstream.h
new file mode 100644
index 0000000..d955bd6
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/bitstream.h
@@ -0,0 +1,455 @@
+/* ******************************************************************
+   bitstream
+   Part of FSE library
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+#ifndef BITSTREAM_H_MODULE
+#define BITSTREAM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+*  This API consists of small unitary functions, which must be inlined for best performance.
+*  Since link-time-optimization is not available for all compilers,
+*  these functions are defined into a .h to be included.
+*/
+
+/*-****************************************
+*  Dependencies
+******************************************/
+#include "mem.h"            /* unaligned access routines */
+#include "debug.h"          /* assert(), DEBUGLOG(), RAWLOG() */
+#include "error_private.h"  /* error codes and messages */
+
+
+/*=========================================
+*  Target specific
+=========================================*/
+#if defined(__BMI__) && defined(__GNUC__)
+#  include <immintrin.h>   /* support for bextr (experimental) */
+#endif
+
+#define STREAM_ACCUMULATOR_MIN_32  25
+#define STREAM_ACCUMULATOR_MIN_64  57
+#define STREAM_ACCUMULATOR_MIN    ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
+
+
+/*-******************************************
+*  bitStream encoding API (write forward)
+********************************************/
+/* bitStream can mix input from multiple sources.
+ * A critical property of these streams is that they encode and decode in **reverse** direction.
+ * So the first bit sequence you add will be the last to be read, like a LIFO stack.
+ */
+typedef struct {
+    size_t bitContainer;
+    unsigned bitPos;
+    char*  startPtr;
+    char*  ptr;
+    char*  endPtr;
+} BIT_CStream_t;
+
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
+MEM_STATIC void   BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+MEM_STATIC void   BIT_flushBits(BIT_CStream_t* bitC);
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
+
+/* Start with initCStream, providing the size of buffer to write into.
+*  bitStream will never write outside of this buffer.
+*  `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
+*
+*  bits are first added to a local register.
+*  Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
+*  Writing data into memory is an explicit operation, performed by the flushBits function.
+*  Hence keep track how many bits are potentially stored into local register to avoid register overflow.
+*  After a flushBits, a maximum of 7 bits might still be stored into local register.
+*
+*  Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
+*
+*  Last operation is to close the bitStream.
+*  The function returns the final size of CStream in bytes.
+*  If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
+*/
+
+
+/*-********************************************
+*  bitStream decoding API (read backward)
+**********************************************/
+typedef struct {
+    size_t   bitContainer;
+    unsigned bitsConsumed;
+    const char* ptr;
+    const char* start;
+    const char* limitPtr;
+} BIT_DStream_t;
+
+typedef enum { BIT_DStream_unfinished = 0,
+               BIT_DStream_endOfBuffer = 1,
+               BIT_DStream_completed = 2,
+               BIT_DStream_overflow = 3 } BIT_DStream_status;  /* result of BIT_reloadDStream() */
+               /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
+
+MEM_STATIC size_t   BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
+MEM_STATIC size_t   BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
+
+
+/* Start by invoking BIT_initDStream().
+*  A chunk of the bitStream is then stored into a local register.
+*  Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+*  You can then retrieve bitFields stored into the local register, **in reverse order**.
+*  Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
+*  A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
+*  Otherwise, it can be less than that, so proceed accordingly.
+*  Checking if DStream has reached its end can be performed with BIT_endOfDStream().
+*/
+
+
+/*-****************************************
+*  unsafe API
+******************************************/
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
+
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
+/* unsafe version; does not check buffer overflow */
+
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
+/* faster, but works only if nbBits >= 1 */
+
+
+
+/*-**************************************************************
+*  Internal functions
+****************************************************************/
+MEM_STATIC unsigned BIT_highbit32 (U32 val)
+{
+    assert(val != 0);
+    {
+#   if defined(_MSC_VER)   /* Visual */
+        unsigned long r=0;
+        _BitScanReverse ( &r, val );
+        return (unsigned) r;
+#   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* Use GCC Intrinsic */
+        return 31 - __builtin_clz (val);
+#   else   /* Software version */
+        static const unsigned DeBruijnClz[32] = { 0,  9,  1, 10, 13, 21,  2, 29,
+                                                 11, 14, 16, 18, 22, 25,  3, 30,
+                                                  8, 12, 20, 28, 15, 17, 24,  7,
+                                                 19, 27, 23,  6, 26,  5,  4, 31 };
+        U32 v = val;
+        v |= v >> 1;
+        v |= v >> 2;
+        v |= v >> 4;
+        v |= v >> 8;
+        v |= v >> 16;
+        return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
+#   endif
+    }
+}
+
+/*=====    Local Constants   =====*/
+static const unsigned BIT_mask[] = {
+    0,          1,         3,         7,         0xF,       0x1F,
+    0x3F,       0x7F,      0xFF,      0x1FF,     0x3FF,     0x7FF,
+    0xFFF,      0x1FFF,    0x3FFF,    0x7FFF,    0xFFFF,    0x1FFFF,
+    0x3FFFF,    0x7FFFF,   0xFFFFF,   0x1FFFFF,  0x3FFFFF,  0x7FFFFF,
+    0xFFFFFF,   0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
+    0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
+#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
+
+/*-**************************************************************
+*  bitStream encoding
+****************************************************************/
+/*! BIT_initCStream() :
+ *  `dstCapacity` must be > sizeof(size_t)
+ *  @return : 0 if success,
+ *            otherwise an error code (can be tested using ERR_isError()) */
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
+                                  void* startPtr, size_t dstCapacity)
+{
+    bitC->bitContainer = 0;
+    bitC->bitPos = 0;
+    bitC->startPtr = (char*)startPtr;
+    bitC->ptr = bitC->startPtr;
+    bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
+    if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
+    return 0;
+}
+
+/*! BIT_addBits() :
+ *  can add up to 31 bits into `bitC`.
+ *  Note : does not check for register overflow ! */
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
+                            size_t value, unsigned nbBits)
+{
+    MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
+    assert(nbBits < BIT_MASK_SIZE);
+    assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+    bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
+    bitC->bitPos += nbBits;
+}
+
+/*! BIT_addBitsFast() :
+ *  works only if `value` is _clean_,
+ *  meaning all high bits above nbBits are 0 */
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
+                                size_t value, unsigned nbBits)
+{
+    assert((value>>nbBits) == 0);
+    assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+    bitC->bitContainer |= value << bitC->bitPos;
+    bitC->bitPos += nbBits;
+}
+
+/*! BIT_flushBitsFast() :
+ *  assumption : bitContainer has not overflowed
+ *  unsafe version; does not check buffer overflow */
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
+{
+    size_t const nbBytes = bitC->bitPos >> 3;
+    assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+    MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+    bitC->ptr += nbBytes;
+    assert(bitC->ptr <= bitC->endPtr);
+    bitC->bitPos &= 7;
+    bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_flushBits() :
+ *  assumption : bitContainer has not overflowed
+ *  safe version; check for buffer overflow, and prevents it.
+ *  note : does not signal buffer overflow.
+ *  overflow will be revealed later on using BIT_closeCStream() */
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
+{
+    size_t const nbBytes = bitC->bitPos >> 3;
+    assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+    MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+    bitC->ptr += nbBytes;
+    if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
+    bitC->bitPos &= 7;
+    bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_closeCStream() :
+ *  @return : size of CStream, in bytes,
+ *            or 0 if it could not fit into dstBuffer */
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
+{
+    BIT_addBitsFast(bitC, 1, 1);   /* endMark */
+    BIT_flushBits(bitC);
+    if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
+    return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
+}
+
+
+/*-********************************************************
+*  bitStream decoding
+**********************************************************/
+/*! BIT_initDStream() :
+ *  Initialize a BIT_DStream_t.
+ * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
+ * `srcSize` must be the *exact* size of the bitStream, in bytes.
+ * @return : size of stream (== srcSize), or an errorCode if a problem is detected
+ */
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
+{
+    if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
+
+    bitD->start = (const char*)srcBuffer;
+    bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
+
+    if (srcSize >=  sizeof(bitD->bitContainer)) {  /* normal case */
+        bitD->ptr   = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
+        bitD->bitContainer = MEM_readLEST(bitD->ptr);
+        { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+          bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;  /* ensures bitsConsumed is always set */
+          if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
+    } else {
+        bitD->ptr   = bitD->start;
+        bitD->bitContainer = *(const BYTE*)(bitD->start);
+        switch(srcSize)
+        {
+        case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
+                /* fall-through */
+
+        case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
+                /* fall-through */
+
+        case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
+                /* fall-through */
+
+        case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
+                /* fall-through */
+
+        case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
+                /* fall-through */
+
+        case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) <<  8;
+                /* fall-through */
+
+        default: break;
+        }
+        {   BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+            bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
+            if (lastByte == 0) return ERROR(corruption_detected);  /* endMark not present */
+        }
+        bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
+    }
+
+    return srcSize;
+}
+
+MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
+{
+    return bitContainer >> start;
+}
+
+MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
+{
+    U32 const regMask = sizeof(bitContainer)*8 - 1;
+    /* if start > regMask, bitstream is corrupted, and result is undefined */
+    assert(nbBits < BIT_MASK_SIZE);
+    return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
+}
+
+MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
+{
+    assert(nbBits < BIT_MASK_SIZE);
+    return bitContainer & BIT_mask[nbBits];
+}
+
+/*! BIT_lookBits() :
+ *  Provides next n bits from local register.
+ *  local register is not modified.
+ *  On 32-bits, maxNbBits==24.
+ *  On 64-bits, maxNbBits==56.
+ * @return : value extracted */
+MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
+{
+    /* arbitrate between double-shift and shift+mask */
+#if 1
+    /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
+     * bitstream is likely corrupted, and result is undefined */
+    return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
+#else
+    /* this code path is slower on my os-x laptop */
+    U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
+    return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
+#endif
+}
+
+/*! BIT_lookBitsFast() :
+ *  unsafe version; only works if nbBits >= 1 */
+MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
+{
+    U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
+    assert(nbBits >= 1);
+    return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
+}
+
+MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
+{
+    bitD->bitsConsumed += nbBits;
+}
+
+/*! BIT_readBits() :
+ *  Read (consume) next n bits from local register and update.
+ *  Pay attention to not read more than nbBits contained into local register.
+ * @return : extracted value. */
+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
+{
+    size_t const value = BIT_lookBits(bitD, nbBits);
+    BIT_skipBits(bitD, nbBits);
+    return value;
+}
+
+/*! BIT_readBitsFast() :
+ *  unsafe version; only works only if nbBits >= 1 */
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
+{
+    size_t const value = BIT_lookBitsFast(bitD, nbBits);
+    assert(nbBits >= 1);
+    BIT_skipBits(bitD, nbBits);
+    return value;
+}
+
+/*! BIT_reloadDStream() :
+ *  Refill `bitD` from buffer previously set in BIT_initDStream() .
+ *  This function is safe, it guarantees it will not read beyond src buffer.
+ * @return : status of `BIT_DStream_t` internal register.
+ *           when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
+{
+    if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))  /* overflow detected, like end of stream */
+        return BIT_DStream_overflow;
+
+    if (bitD->ptr >= bitD->limitPtr) {
+        bitD->ptr -= bitD->bitsConsumed >> 3;
+        bitD->bitsConsumed &= 7;
+        bitD->bitContainer = MEM_readLEST(bitD->ptr);
+        return BIT_DStream_unfinished;
+    }
+    if (bitD->ptr == bitD->start) {
+        if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
+        return BIT_DStream_completed;
+    }
+    /* start < ptr < limitPtr */
+    {   U32 nbBytes = bitD->bitsConsumed >> 3;
+        BIT_DStream_status result = BIT_DStream_unfinished;
+        if (bitD->ptr - nbBytes < bitD->start) {
+            nbBytes = (U32)(bitD->ptr - bitD->start);  /* ptr > start */
+            result = BIT_DStream_endOfBuffer;
+        }
+        bitD->ptr -= nbBytes;
+        bitD->bitsConsumed -= nbBytes*8;
+        bitD->bitContainer = MEM_readLEST(bitD->ptr);   /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
+        return result;
+    }
+}
+
+/*! BIT_endOfDStream() :
+ * @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
+ */
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
+{
+    return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* BITSTREAM_H_MODULE */
diff --git a/Utilities/cmzstd/lib/common/compiler.h b/Utilities/cmzstd/lib/common/compiler.h
new file mode 100644
index 0000000..7f56128
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/compiler.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMPILER_H
+#define ZSTD_COMPILER_H
+
+/*-*******************************************************
+*  Compiler specifics
+*********************************************************/
+/* force inlining */
+
+#if !defined(ZSTD_NO_INLINE)
+#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */
+#  define INLINE_KEYWORD inline
+#else
+#  define INLINE_KEYWORD
+#endif
+
+#if defined(__GNUC__)
+#  define FORCE_INLINE_ATTR __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#  define FORCE_INLINE_ATTR __forceinline
+#else
+#  define FORCE_INLINE_ATTR
+#endif
+
+#else
+
+#define INLINE_KEYWORD
+#define FORCE_INLINE_ATTR
+
+#endif
+
+/**
+ * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
+ * parameters. They must be inlined for the compiler to elimininate the constant
+ * branches.
+ */
+#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
+/**
+ * HINT_INLINE is used to help the compiler generate better code. It is *not*
+ * used for "templates", so it can be tweaked based on the compilers
+ * performance.
+ *
+ * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
+ * always_inline attribute.
+ *
+ * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
+ * attribute.
+ */
+#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
+#  define HINT_INLINE static INLINE_KEYWORD
+#else
+#  define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
+#endif
+
+/* force no inlining */
+#ifdef _MSC_VER
+#  define FORCE_NOINLINE static __declspec(noinline)
+#else
+#  ifdef __GNUC__
+#    define FORCE_NOINLINE static __attribute__((__noinline__))
+#  else
+#    define FORCE_NOINLINE static
+#  endif
+#endif
+
+/* target attribute */
+#ifndef __has_attribute
+  #define __has_attribute(x) 0  /* Compatibility with non-clang compilers. */
+#endif
+#if defined(__GNUC__)
+#  define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
+#else
+#  define TARGET_ATTRIBUTE(target)
+#endif
+
+/* Enable runtime BMI2 dispatch based on the CPU.
+ * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
+ */
+#ifndef DYNAMIC_BMI2
+  #if ((defined(__clang__) && __has_attribute(__target__)) \
+      || (defined(__GNUC__) \
+          && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
+      && (defined(__x86_64__) || defined(_M_X86)) \
+      && !defined(__BMI2__)
+  #  define DYNAMIC_BMI2 1
+  #else
+  #  define DYNAMIC_BMI2 0
+  #endif
+#endif
+
+/* prefetch
+ * can be disabled, by declaring NO_PREFETCH build macro */
+#if defined(NO_PREFETCH)
+#  define PREFETCH_L1(ptr)  (void)(ptr)  /* disabled */
+#  define PREFETCH_L2(ptr)  (void)(ptr)  /* disabled */
+#else
+#  if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86))  /* _mm_prefetch() is not defined outside of x86/x64 */
+#    include <mmintrin.h>   /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
+#    define PREFETCH_L1(ptr)  _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
+#    define PREFETCH_L2(ptr)  _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
+#  elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
+#    define PREFETCH_L1(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
+#    define PREFETCH_L2(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
+#  else
+#    define PREFETCH_L1(ptr) (void)(ptr)  /* disabled */
+#    define PREFETCH_L2(ptr) (void)(ptr)  /* disabled */
+#  endif
+#endif  /* NO_PREFETCH */
+
+#define CACHELINE_SIZE 64
+
+#define PREFETCH_AREA(p, s)  {            \
+    const char* const _ptr = (const char*)(p);  \
+    size_t const _size = (size_t)(s);     \
+    size_t _pos;                          \
+    for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) {  \
+        PREFETCH_L2(_ptr + _pos);         \
+    }                                     \
+}
+
+/* disable warnings */
+#ifdef _MSC_VER    /* Visual Studio */
+#  include <intrin.h>                    /* For Visual 2005 */
+#  pragma warning(disable : 4100)        /* disable: C4100: unreferenced formal parameter */
+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
+#  pragma warning(disable : 4204)        /* disable: C4204: non-constant aggregate initializer */
+#  pragma warning(disable : 4214)        /* disable: C4214: non-int bitfields */
+#  pragma warning(disable : 4324)        /* disable: C4324: padded structure */
+#endif
+
+#endif /* ZSTD_COMPILER_H */
diff --git a/Utilities/cmzstd/lib/common/cpu.h b/Utilities/cmzstd/lib/common/cpu.h
new file mode 100644
index 0000000..5f0923f
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/cpu.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMMON_CPU_H
+#define ZSTD_COMMON_CPU_H
+
+/**
+ * Implementation taken from folly/CpuId.h
+ * https://github.com/facebook/folly/blob/master/folly/CpuId.h
+ */
+
+#include <string.h>
+
+#include "mem.h"
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+typedef struct {
+    U32 f1c;
+    U32 f1d;
+    U32 f7b;
+    U32 f7c;
+} ZSTD_cpuid_t;
+
+MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
+    U32 f1c = 0;
+    U32 f1d = 0;
+    U32 f7b = 0;
+    U32 f7c = 0;
+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+    int reg[4];
+    __cpuid((int*)reg, 0);
+    {
+        int const n = reg[0];
+        if (n >= 1) {
+            __cpuid((int*)reg, 1);
+            f1c = (U32)reg[2];
+            f1d = (U32)reg[3];
+        }
+        if (n >= 7) {
+            __cpuidex((int*)reg, 7, 0);
+            f7b = (U32)reg[1];
+            f7c = (U32)reg[2];
+        }
+    }
+#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
+    /* The following block like the normal cpuid branch below, but gcc
+     * reserves ebx for use of its pic register so we must specially
+     * handle the save and restore to avoid clobbering the register
+     */
+    U32 n;
+    __asm__(
+        "pushl %%ebx\n\t"
+        "cpuid\n\t"
+        "popl %%ebx\n\t"
+        : "=a"(n)
+        : "a"(0)
+        : "ecx", "edx");
+    if (n >= 1) {
+      U32 f1a;
+      __asm__(
+          "pushl %%ebx\n\t"
+          "cpuid\n\t"
+          "popl %%ebx\n\t"
+          : "=a"(f1a), "=c"(f1c), "=d"(f1d)
+          : "a"(1));
+    }
+    if (n >= 7) {
+      __asm__(
+          "pushl %%ebx\n\t"
+          "cpuid\n\t"
+          "movl %%ebx, %%eax\n\t"
+          "popl %%ebx"
+          : "=a"(f7b), "=c"(f7c)
+          : "a"(7), "c"(0)
+          : "edx");
+    }
+#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
+    U32 n;
+    __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
+    if (n >= 1) {
+      U32 f1a;
+      __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
+    }
+    if (n >= 7) {
+      U32 f7a;
+      __asm__("cpuid"
+              : "=a"(f7a), "=b"(f7b), "=c"(f7c)
+              : "a"(7), "c"(0)
+              : "edx");
+    }
+#endif
+    {
+        ZSTD_cpuid_t cpuid;
+        cpuid.f1c = f1c;
+        cpuid.f1d = f1d;
+        cpuid.f7b = f7b;
+        cpuid.f7c = f7c;
+        return cpuid;
+    }
+}
+
+#define X(name, r, bit)                                                        \
+  MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) {                 \
+    return ((cpuid.r) & (1U << bit)) != 0;                                     \
+  }
+
+/* cpuid(1): Processor Info and Feature Bits. */
+#define C(name, bit) X(name, f1c, bit)
+  C(sse3, 0)
+  C(pclmuldq, 1)
+  C(dtes64, 2)
+  C(monitor, 3)
+  C(dscpl, 4)
+  C(vmx, 5)
+  C(smx, 6)
+  C(eist, 7)
+  C(tm2, 8)
+  C(ssse3, 9)
+  C(cnxtid, 10)
+  C(fma, 12)
+  C(cx16, 13)
+  C(xtpr, 14)
+  C(pdcm, 15)
+  C(pcid, 17)
+  C(dca, 18)
+  C(sse41, 19)
+  C(sse42, 20)
+  C(x2apic, 21)
+  C(movbe, 22)
+  C(popcnt, 23)
+  C(tscdeadline, 24)
+  C(aes, 25)
+  C(xsave, 26)
+  C(osxsave, 27)
+  C(avx, 28)
+  C(f16c, 29)
+  C(rdrand, 30)
+#undef C
+#define D(name, bit) X(name, f1d, bit)
+  D(fpu, 0)
+  D(vme, 1)
+  D(de, 2)
+  D(pse, 3)
+  D(tsc, 4)
+  D(msr, 5)
+  D(pae, 6)
+  D(mce, 7)
+  D(cx8, 8)
+  D(apic, 9)
+  D(sep, 11)
+  D(mtrr, 12)
+  D(pge, 13)
+  D(mca, 14)
+  D(cmov, 15)
+  D(pat, 16)
+  D(pse36, 17)
+  D(psn, 18)
+  D(clfsh, 19)
+  D(ds, 21)
+  D(acpi, 22)
+  D(mmx, 23)
+  D(fxsr, 24)
+  D(sse, 25)
+  D(sse2, 26)
+  D(ss, 27)
+  D(htt, 28)
+  D(tm, 29)
+  D(pbe, 31)
+#undef D
+
+/* cpuid(7): Extended Features. */
+#define B(name, bit) X(name, f7b, bit)
+  B(bmi1, 3)
+  B(hle, 4)
+  B(avx2, 5)
+  B(smep, 7)
+  B(bmi2, 8)
+  B(erms, 9)
+  B(invpcid, 10)
+  B(rtm, 11)
+  B(mpx, 14)
+  B(avx512f, 16)
+  B(avx512dq, 17)
+  B(rdseed, 18)
+  B(adx, 19)
+  B(smap, 20)
+  B(avx512ifma, 21)
+  B(pcommit, 22)
+  B(clflushopt, 23)
+  B(clwb, 24)
+  B(avx512pf, 26)
+  B(avx512er, 27)
+  B(avx512cd, 28)
+  B(sha, 29)
+  B(avx512bw, 30)
+  B(avx512vl, 31)
+#undef B
+#define C(name, bit) X(name, f7c, bit)
+  C(prefetchwt1, 0)
+  C(avx512vbmi, 1)
+#undef C
+
+#undef X
+
+#endif /* ZSTD_COMMON_CPU_H */
diff --git a/Utilities/cmzstd/lib/common/debug.c b/Utilities/cmzstd/lib/common/debug.c
new file mode 100644
index 0000000..3ebdd1c
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/debug.c
@@ -0,0 +1,44 @@
+/* ******************************************************************
+   debug
+   Part of FSE library
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+
+/*
+ * This module only hosts one global variable
+ * which can be used to dynamically influence the verbosity of traces,
+ * such as DEBUGLOG and RAWLOG
+ */
+
+#include "debug.h"
+
+int g_debuglevel = DEBUGLEVEL;
diff --git a/Utilities/cmzstd/lib/common/debug.h b/Utilities/cmzstd/lib/common/debug.h
new file mode 100644
index 0000000..b4fc89d
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/debug.h
@@ -0,0 +1,134 @@
+/* ******************************************************************
+   debug
+   Part of FSE library
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+
+/*
+ * The purpose of this header is to enable debug functions.
+ * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
+ * and DEBUG_STATIC_ASSERT() for compile-time.
+ *
+ * By default, DEBUGLEVEL==0, which means run-time debug is disabled.
+ *
+ * Level 1 enables assert() only.
+ * Starting level 2, traces can be generated and pushed to stderr.
+ * The higher the level, the more verbose the traces.
+ *
+ * It's possible to dynamically adjust level using variable g_debug_level,
+ * which is only declared if DEBUGLEVEL>=2,
+ * and is a global variable, not multi-thread protected (use with care)
+ */
+
+#ifndef DEBUG_H_12987983217
+#define DEBUG_H_12987983217
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* static assert is triggered at compile time, leaving no runtime artefact.
+ * static assert only works with compile-time constants.
+ * Also, this variant can only be used inside a function. */
+#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
+
+
+/* DEBUGLEVEL is expected to be defined externally,
+ * typically through compiler command line.
+ * Value must be a number. */
+#ifndef DEBUGLEVEL
+#  define DEBUGLEVEL 0
+#endif
+
+
+/* DEBUGFILE can be defined externally,
+ * typically through compiler command line.
+ * note : currently useless.
+ * Value must be stderr or stdout */
+#ifndef DEBUGFILE
+#  define DEBUGFILE stderr
+#endif
+
+
+/* recommended values for DEBUGLEVEL :
+ * 0 : release mode, no debug, all run-time checks disabled
+ * 1 : enables assert() only, no display
+ * 2 : reserved, for currently active debug path
+ * 3 : events once per object lifetime (CCtx, CDict, etc.)
+ * 4 : events once per frame
+ * 5 : events once per block
+ * 6 : events once per sequence (verbose)
+ * 7+: events at every position (*very* verbose)
+ *
+ * It's generally inconvenient to output traces > 5.
+ * In which case, it's possible to selectively trigger high verbosity levels
+ * by modifying g_debug_level.
+ */
+
+#if (DEBUGLEVEL>=1)
+#  include <assert.h>
+#else
+#  ifndef assert   /* assert may be already defined, due to prior #include <assert.h> */
+#    define assert(condition) ((void)0)   /* disable assert (default) */
+#  endif
+#endif
+
+#if (DEBUGLEVEL>=2)
+#  include <stdio.h>
+extern int g_debuglevel; /* the variable is only declared,
+                            it actually lives in debug.c,
+                            and is shared by the whole process.
+                            It's not thread-safe.
+                            It's useful when enabling very verbose levels
+                            on selective conditions (such as position in src) */
+
+#  define RAWLOG(l, ...) {                                      \
+                if (l<=g_debuglevel) {                          \
+                    fprintf(stderr, __VA_ARGS__);               \
+            }   }
+#  define DEBUGLOG(l, ...) {                                    \
+                if (l<=g_debuglevel) {                          \
+                    fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
+                    fprintf(stderr, " \n");                     \
+            }   }
+#else
+#  define RAWLOG(l, ...)      {}    /* disabled */
+#  define DEBUGLOG(l, ...)    {}    /* disabled */
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* DEBUG_H_12987983217 */
diff --git a/Utilities/cmzstd/lib/common/entropy_common.c b/Utilities/cmzstd/lib/common/entropy_common.c
new file mode 100644
index 0000000..b12944e
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/entropy_common.c
@@ -0,0 +1,236 @@
+/*
+   Common functions of New Generation Entropy library
+   Copyright (C) 2016, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+    - Public forum : https://groups.google.com/forum/#!forum/lz4c
+*************************************************************************** */
+
+/* *************************************
+*  Dependencies
+***************************************/
+#include "mem.h"
+#include "error_private.h"       /* ERR_*, ERROR */
+#define FSE_STATIC_LINKING_ONLY  /* FSE_MIN_TABLELOG */
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY  /* HUF_TABLELOG_ABSOLUTEMAX */
+#include "huf.h"
+
+
+/*===   Version   ===*/
+unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
+
+
+/*===   Error Management   ===*/
+unsigned FSE_isError(size_t code) { return ERR_isError(code); }
+const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+unsigned HUF_isError(size_t code) { return ERR_isError(code); }
+const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+
+/*-**************************************************************
+*  FSE NCount encoding-decoding
+****************************************************************/
+size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+                 const void* headerBuffer, size_t hbSize)
+{
+    const BYTE* const istart = (const BYTE*) headerBuffer;
+    const BYTE* const iend = istart + hbSize;
+    const BYTE* ip = istart;
+    int nbBits;
+    int remaining;
+    int threshold;
+    U32 bitStream;
+    int bitCount;
+    unsigned charnum = 0;
+    int previous0 = 0;
+
+    if (hbSize < 4) {
+        /* This function only works when hbSize >= 4 */
+        char buffer[4];
+        memset(buffer, 0, sizeof(buffer));
+        memcpy(buffer, headerBuffer, hbSize);
+        {   size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
+                                                    buffer, sizeof(buffer));
+            if (FSE_isError(countSize)) return countSize;
+            if (countSize > hbSize) return ERROR(corruption_detected);
+            return countSize;
+    }   }
+    assert(hbSize >= 4);
+
+    /* init */
+    memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0]));   /* all symbols not present in NCount have a frequency of 0 */
+    bitStream = MEM_readLE32(ip);
+    nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG;   /* extract tableLog */
+    if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
+    bitStream >>= 4;
+    bitCount = 4;
+    *tableLogPtr = nbBits;
+    remaining = (1<<nbBits)+1;
+    threshold = 1<<nbBits;
+    nbBits++;
+
+    while ((remaining>1) & (charnum<=*maxSVPtr)) {
+        if (previous0) {
+            unsigned n0 = charnum;
+            while ((bitStream & 0xFFFF) == 0xFFFF) {
+                n0 += 24;
+                if (ip < iend-5) {
+                    ip += 2;
+                    bitStream = MEM_readLE32(ip) >> bitCount;
+                } else {
+                    bitStream >>= 16;
+                    bitCount   += 16;
+            }   }
+            while ((bitStream & 3) == 3) {
+                n0 += 3;
+                bitStream >>= 2;
+                bitCount += 2;
+            }
+            n0 += bitStream & 3;
+            bitCount += 2;
+            if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
+            while (charnum < n0) normalizedCounter[charnum++] = 0;
+            if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+                assert((bitCount >> 3) <= 3); /* For first condition to work */
+                ip += bitCount>>3;
+                bitCount &= 7;
+                bitStream = MEM_readLE32(ip) >> bitCount;
+            } else {
+                bitStream >>= 2;
+        }   }
+        {   int const max = (2*threshold-1) - remaining;
+            int count;
+
+            if ((bitStream & (threshold-1)) < (U32)max) {
+                count = bitStream & (threshold-1);
+                bitCount += nbBits-1;
+            } else {
+                count = bitStream & (2*threshold-1);
+                if (count >= threshold) count -= max;
+                bitCount += nbBits;
+            }
+
+            count--;   /* extra accuracy */
+            remaining -= count < 0 ? -count : count;   /* -1 means +1 */
+            normalizedCounter[charnum++] = (short)count;
+            previous0 = !count;
+            while (remaining < threshold) {
+                nbBits--;
+                threshold >>= 1;
+            }
+
+            if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+                ip += bitCount>>3;
+                bitCount &= 7;
+            } else {
+                bitCount -= (int)(8 * (iend - 4 - ip));
+                ip = iend - 4;
+            }
+            bitStream = MEM_readLE32(ip) >> (bitCount & 31);
+    }   }   /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
+    if (remaining != 1) return ERROR(corruption_detected);
+    if (bitCount > 32) return ERROR(corruption_detected);
+    *maxSVPtr = charnum-1;
+
+    ip += (bitCount+7)>>3;
+    return ip-istart;
+}
+
+
+/*! HUF_readStats() :
+    Read compact Huffman tree, saved by HUF_writeCTable().
+    `huffWeight` is destination buffer.
+    `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
+    @return : size read from `src` , or an error Code .
+    Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
+*/
+size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+                     U32* nbSymbolsPtr, U32* tableLogPtr,
+                     const void* src, size_t srcSize)
+{
+    U32 weightTotal;
+    const BYTE* ip = (const BYTE*) src;
+    size_t iSize;
+    size_t oSize;
+
+    if (!srcSize) return ERROR(srcSize_wrong);
+    iSize = ip[0];
+    /* memset(huffWeight, 0, hwSize);   *//* is not necessary, even though some analyzer complain ... */
+
+    if (iSize >= 128) {  /* special header */
+        oSize = iSize - 127;
+        iSize = ((oSize+1)/2);
+        if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
+        if (oSize >= hwSize) return ERROR(corruption_detected);
+        ip += 1;
+        {   U32 n;
+            for (n=0; n<oSize; n+=2) {
+                huffWeight[n]   = ip[n/2] >> 4;
+                huffWeight[n+1] = ip[n/2] & 15;
+    }   }   }
+    else  {   /* header compressed with FSE (normal case) */
+        FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)];  /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
+        if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
+        oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6);   /* max (hwSize-1) values decoded, as last one is implied */
+        if (FSE_isError(oSize)) return oSize;
+    }
+
+    /* collect weight stats */
+    memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
+    weightTotal = 0;
+    {   U32 n; for (n=0; n<oSize; n++) {
+            if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+            rankStats[huffWeight[n]]++;
+            weightTotal += (1 << huffWeight[n]) >> 1;
+    }   }
+    if (weightTotal == 0) return ERROR(corruption_detected);
+
+    /* get last non-null symbol weight (implied, total must be 2^n) */
+    {   U32 const tableLog = BIT_highbit32(weightTotal) + 1;
+        if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+        *tableLogPtr = tableLog;
+        /* determine last weight */
+        {   U32 const total = 1 << tableLog;
+            U32 const rest = total - weightTotal;
+            U32 const verif = 1 << BIT_highbit32(rest);
+            U32 const lastWeight = BIT_highbit32(rest) + 1;
+            if (verif != rest) return ERROR(corruption_detected);    /* last value must be a clean power of 2 */
+            huffWeight[oSize] = (BYTE)lastWeight;
+            rankStats[lastWeight]++;
+    }   }
+
+    /* check tree construction validity */
+    if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected);   /* by construction : at least 2 elts of rank 1, must be even */
+
+    /* results */
+    *nbSymbolsPtr = (U32)(oSize+1);
+    return iSize+1;
+}
diff --git a/Utilities/cmzstd/lib/common/error_private.c b/Utilities/cmzstd/lib/common/error_private.c
new file mode 100644
index 0000000..7c1bb67
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/error_private.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* The purpose of this file is to have a single list of error strings embedded in binary */
+
+#include "error_private.h"
+
+const char* ERR_getErrorString(ERR_enum code)
+{
+#ifdef ZSTD_STRIP_ERROR_STRINGS
+    (void)code;
+    return "Error strings stripped";
+#else
+    static const char* const notErrorCode = "Unspecified error code";
+    switch( code )
+    {
+    case PREFIX(no_error): return "No error detected";
+    case PREFIX(GENERIC):  return "Error (generic)";
+    case PREFIX(prefix_unknown): return "Unknown frame descriptor";
+    case PREFIX(version_unsupported): return "Version not supported";
+    case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
+    case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
+    case PREFIX(corruption_detected): return "Corrupted block detected";
+    case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
+    case PREFIX(parameter_unsupported): return "Unsupported parameter";
+    case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
+    case PREFIX(init_missing): return "Context should be init first";
+    case PREFIX(memory_allocation): return "Allocation error : not enough memory";
+    case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
+    case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
+    case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
+    case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
+    case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
+    case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
+    case PREFIX(dictionary_wrong): return "Dictionary mismatch";
+    case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
+    case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
+    case PREFIX(srcSize_wrong): return "Src size is incorrect";
+    case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
+        /* following error codes are not stable and may be removed or changed in a future version */
+    case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
+    case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
+    case PREFIX(maxCode):
+    default: return notErrorCode;
+    }
+#endif
+}
diff --git a/Utilities/cmzstd/lib/common/error_private.h b/Utilities/cmzstd/lib/common/error_private.h
new file mode 100644
index 0000000..0d2fa7e
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/error_private.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* Note : this module is expected to remain private, do not expose it */
+
+#ifndef ERROR_H_MODULE
+#define ERROR_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* ****************************************
+*  Dependencies
+******************************************/
+#include <stddef.h>        /* size_t */
+#include "zstd_errors.h"  /* enum list */
+
+
+/* ****************************************
+*  Compiler-specific
+******************************************/
+#if defined(__GNUC__)
+#  define ERR_STATIC static __attribute__((unused))
+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+#  define ERR_STATIC static inline
+#elif defined(_MSC_VER)
+#  define ERR_STATIC static __inline
+#else
+#  define ERR_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
+#endif
+
+
+/*-****************************************
+*  Customization (error_public.h)
+******************************************/
+typedef ZSTD_ErrorCode ERR_enum;
+#define PREFIX(name) ZSTD_error_##name
+
+
+/*-****************************************
+*  Error codes handling
+******************************************/
+#undef ERROR   /* reported already defined on VS 2015 (Rich Geldreich) */
+#define ERROR(name) ZSTD_ERROR(name)
+#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
+
+ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
+
+ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
+
+
+/*-****************************************
+*  Error Strings
+******************************************/
+
+const char* ERR_getErrorString(ERR_enum code);   /* error_private.c */
+
+ERR_STATIC const char* ERR_getErrorName(size_t code)
+{
+    return ERR_getErrorString(ERR_getErrorCode(code));
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ERROR_H_MODULE */
diff --git a/Utilities/cmzstd/lib/common/fse.h b/Utilities/cmzstd/lib/common/fse.h
new file mode 100644
index 0000000..f72c519
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/fse.h
@@ -0,0 +1,708 @@
+/* ******************************************************************
+   FSE : Finite State Entropy codec
+   Public Prototypes declaration
+   Copyright (C) 2013-2016, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef FSE_H
+#define FSE_H
+
+
+/*-*****************************************
+*  Dependencies
+******************************************/
+#include <stddef.h>    /* size_t, ptrdiff_t */
+
+
+/*-*****************************************
+*  FSE_PUBLIC_API : control library symbols visibility
+******************************************/
+#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
+#  define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
+#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1)   /* Visual expected */
+#  define FSE_PUBLIC_API __declspec(dllexport)
+#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
+#  define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+#  define FSE_PUBLIC_API
+#endif
+
+/*------   Version   ------*/
+#define FSE_VERSION_MAJOR    0
+#define FSE_VERSION_MINOR    9
+#define FSE_VERSION_RELEASE  0
+
+#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
+#define FSE_QUOTE(str) #str
+#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
+#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
+
+#define FSE_VERSION_NUMBER  (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
+FSE_PUBLIC_API unsigned FSE_versionNumber(void);   /**< library version number; to be used when checking dll version */
+
+
+/*-****************************************
+*  FSE simple functions
+******************************************/
+/*! FSE_compress() :
+    Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
+    'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
+    @return : size of compressed data (<= dstCapacity).
+    Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
+                     if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
+                     if FSE_isError(return), compression failed (more details using FSE_getErrorName())
+*/
+FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
+                             const void* src, size_t srcSize);
+
+/*! FSE_decompress():
+    Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
+    into already allocated destination buffer 'dst', of size 'dstCapacity'.
+    @return : size of regenerated data (<= maxDstSize),
+              or an error code, which can be tested using FSE_isError() .
+
+    ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
+    Why ? : making this distinction requires a header.
+    Header management is intentionally delegated to the user layer, which can better manage special cases.
+*/
+FSE_PUBLIC_API size_t FSE_decompress(void* dst,  size_t dstCapacity,
+                               const void* cSrc, size_t cSrcSize);
+
+
+/*-*****************************************
+*  Tool functions
+******************************************/
+FSE_PUBLIC_API size_t FSE_compressBound(size_t size);       /* maximum compressed size */
+
+/* Error Management */
+FSE_PUBLIC_API unsigned    FSE_isError(size_t code);        /* tells if a return value is an error code */
+FSE_PUBLIC_API const char* FSE_getErrorName(size_t code);   /* provides error code string (useful for debugging) */
+
+
+/*-*****************************************
+*  FSE advanced functions
+******************************************/
+/*! FSE_compress2() :
+    Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
+    Both parameters can be defined as '0' to mean : use default value
+    @return : size of compressed data
+    Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
+                     if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
+                     if FSE_isError(return), it's an error code.
+*/
+FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
+
+
+/*-*****************************************
+*  FSE detailed API
+******************************************/
+/*!
+FSE_compress() does the following:
+1. count symbol occurrence from source[] into table count[] (see hist.h)
+2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
+3. save normalized counters to memory buffer using writeNCount()
+4. build encoding table 'CTable' from normalized counters
+5. encode the data stream using encoding table 'CTable'
+
+FSE_decompress() does the following:
+1. read normalized counters with readNCount()
+2. build decoding table 'DTable' from normalized counters
+3. decode the data stream using decoding table 'DTable'
+
+The following API allows targeting specific sub-functions for advanced tasks.
+For example, it's possible to compress several blocks using the same 'CTable',
+or to save and provide normalized distribution using external method.
+*/
+
+/* *** COMPRESSION *** */
+
+/*! FSE_optimalTableLog():
+    dynamically downsize 'tableLog' when conditions are met.
+    It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
+    @return : recommended tableLog (necessarily <= 'maxTableLog') */
+FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
+
+/*! FSE_normalizeCount():
+    normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
+    'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
+    @return : tableLog,
+              or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
+                    const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
+
+/*! FSE_NCountWriteBound():
+    Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
+    Typically useful for allocation purpose. */
+FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_writeNCount():
+    Compactly save 'normalizedCounter' into 'buffer'.
+    @return : size of the compressed table,
+              or an errorCode, which can be tested using FSE_isError(). */
+FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
+                                 const short* normalizedCounter,
+                                 unsigned maxSymbolValue, unsigned tableLog);
+
+/*! Constructor and Destructor of FSE_CTable.
+    Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
+typedef unsigned FSE_CTable;   /* don't allocate that. It's only meant to be more restrictive than void* */
+FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
+FSE_PUBLIC_API void        FSE_freeCTable (FSE_CTable* ct);
+
+/*! FSE_buildCTable():
+    Builds `ct`, which must be already allocated, using FSE_createCTable().
+    @return : 0, or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_compress_usingCTable():
+    Compress `src` using `ct` into `dst` which must be already allocated.
+    @return : size of compressed data (<= `dstCapacity`),
+              or 0 if compressed data could not fit into `dst`,
+              or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
+
+/*!
+Tutorial :
+----------
+The first step is to count all symbols. FSE_count() does this job very fast.
+Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
+'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
+maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
+FSE_count() will return the number of occurrence of the most frequent symbol.
+This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
+
+The next step is to normalize the frequencies.
+FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
+It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
+You can use 'tableLog'==0 to mean "use default tableLog value".
+If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
+which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
+
+The result of FSE_normalizeCount() will be saved into a table,
+called 'normalizedCounter', which is a table of signed short.
+'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
+The return value is tableLog if everything proceeded as expected.
+It is 0 if there is a single symbol within distribution.
+If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
+
+'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
+'buffer' must be already allocated.
+For guaranteed success, buffer size must be at least FSE_headerBound().
+The result of the function is the number of bytes written into 'buffer'.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
+
+'normalizedCounter' can then be used to create the compression table 'CTable'.
+The space required by 'CTable' must be already allocated, using FSE_createCTable().
+You can then use FSE_buildCTable() to fill 'CTable'.
+If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
+
+'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
+Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
+The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
+If it returns '0', compressed data could not fit into 'dst'.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
+*/
+
+
+/* *** DECOMPRESSION *** */
+
+/*! FSE_readNCount():
+    Read compactly saved 'normalizedCounter' from 'rBuffer'.
+    @return : size read from 'rBuffer',
+              or an errorCode, which can be tested using FSE_isError().
+              maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
+FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
+                           unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
+                           const void* rBuffer, size_t rBuffSize);
+
+/*! Constructor and Destructor of FSE_DTable.
+    Note that its size depends on 'tableLog' */
+typedef unsigned FSE_DTable;   /* don't allocate that. It's just a way to be more restrictive than void* */
+FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
+FSE_PUBLIC_API void        FSE_freeDTable(FSE_DTable* dt);
+
+/*! FSE_buildDTable():
+    Builds 'dt', which must be already allocated, using FSE_createDTable().
+    return : 0, or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_decompress_usingDTable():
+    Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
+    into `dst` which must be already allocated.
+    @return : size of regenerated data (necessarily <= `dstCapacity`),
+              or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
+
+/*!
+Tutorial :
+----------
+(Note : these functions only decompress FSE-compressed blocks.
+ If block is uncompressed, use memcpy() instead
+ If block is a single repeated byte, use memset() instead )
+
+The first step is to obtain the normalized frequencies of symbols.
+This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
+'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
+In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
+or size the table to handle worst case situations (typically 256).
+FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
+The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
+Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
+If there is an error, the function will return an error code, which can be tested using FSE_isError().
+
+The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
+This is performed by the function FSE_buildDTable().
+The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
+If there is an error, the function will return an error code, which can be tested using FSE_isError().
+
+`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
+`cSrcSize` must be strictly correct, otherwise decompression will fail.
+FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
+If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
+*/
+
+#endif  /* FSE_H */
+
+#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
+#define FSE_H_FSE_STATIC_LINKING_ONLY
+
+/* *** Dependency *** */
+#include "bitstream.h"
+
+
+/* *****************************************
+*  Static allocation
+*******************************************/
+/* FSE buffer bounds */
+#define FSE_NCOUNTBOUND 512
+#define FSE_BLOCKBOUND(size) (size + (size>>7))
+#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size))   /* Macro version, useful for static allocation */
+
+/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
+#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue)   (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
+#define FSE_DTABLE_SIZE_U32(maxTableLog)                   (1 + (1<<maxTableLog))
+
+/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
+#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue)   (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
+#define FSE_DTABLE_SIZE(maxTableLog)                   (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
+
+
+/* *****************************************
+ *  FSE advanced API
+ ***************************************** */
+
+unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
+/**< same as FSE_optimalTableLog(), which used `minus==2` */
+
+/* FSE_compress_wksp() :
+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
+ * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
+ */
+#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue)   ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+
+size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
+/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
+
+size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
+/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
+
+/* FSE_buildCTable_wksp() :
+ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
+ * `wkspSize` must be >= `(1<<tableLog)`.
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+
+size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
+/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
+
+size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
+/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
+
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
+/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
+
+typedef enum {
+   FSE_repeat_none,  /**< Cannot use the previous table */
+   FSE_repeat_check, /**< Can use the previous table but it must be checked */
+   FSE_repeat_valid  /**< Can use the previous table and it is asumed to be valid */
+ } FSE_repeat;
+
+/* *****************************************
+*  FSE symbol compression API
+*******************************************/
+/*!
+   This API consists of small unitary functions, which highly benefit from being inlined.
+   Hence their body are included in next section.
+*/
+typedef struct {
+    ptrdiff_t   value;
+    const void* stateTable;
+    const void* symbolTT;
+    unsigned    stateLog;
+} FSE_CState_t;
+
+static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
+
+static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
+
+static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
+
+/**<
+These functions are inner components of FSE_compress_usingCTable().
+They allow the creation of custom streams, mixing multiple tables and bit sources.
+
+A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
+So the first symbol you will encode is the last you will decode, like a LIFO stack.
+
+You will need a few variables to track your CStream. They are :
+
+FSE_CTable    ct;         // Provided by FSE_buildCTable()
+BIT_CStream_t bitStream;  // bitStream tracking structure
+FSE_CState_t  state;      // State tracking structure (can have several)
+
+
+The first thing to do is to init bitStream and state.
+    size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
+    FSE_initCState(&state, ct);
+
+Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
+You can then encode your input data, byte after byte.
+FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
+Remember decoding will be done in reverse direction.
+    FSE_encodeByte(&bitStream, &state, symbol);
+
+At any time, you can also add any bit sequence.
+Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
+    BIT_addBits(&bitStream, bitField, nbBits);
+
+The above methods don't commit data to memory, they just store it into local register, for speed.
+Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+Writing data to memory is a manual operation, performed by the flushBits function.
+    BIT_flushBits(&bitStream);
+
+Your last FSE encoding operation shall be to flush your last state value(s).
+    FSE_flushState(&bitStream, &state);
+
+Finally, you must close the bitStream.
+The function returns the size of CStream in bytes.
+If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
+If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
+    size_t size = BIT_closeCStream(&bitStream);
+*/
+
+
+/* *****************************************
+*  FSE symbol decompression API
+*******************************************/
+typedef struct {
+    size_t      state;
+    const void* table;   /* precise table may vary, depending on U16 */
+} FSE_DState_t;
+
+
+static void     FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
+
+static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
+
+static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
+
+/**<
+Let's now decompose FSE_decompress_usingDTable() into its unitary components.
+You will decode FSE-encoded symbols from the bitStream,
+and also any other bitFields you put in, **in reverse order**.
+
+You will need a few variables to track your bitStream. They are :
+
+BIT_DStream_t DStream;    // Stream context
+FSE_DState_t  DState;     // State context. Multiple ones are possible
+FSE_DTable*   DTablePtr;  // Decoding table, provided by FSE_buildDTable()
+
+The first thing to do is to init the bitStream.
+    errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
+
+You should then retrieve your initial state(s)
+(in reverse flushing order if you have several ones) :
+    errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
+
+You can then decode your data, symbol after symbol.
+For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
+Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
+    unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
+
+You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
+Note : maximum allowed nbBits is 25, for 32-bits compatibility
+    size_t bitField = BIT_readBits(&DStream, nbBits);
+
+All above operations only read from local register (which size depends on size_t).
+Refueling the register from memory is manually performed by the reload method.
+    endSignal = FSE_reloadDStream(&DStream);
+
+BIT_reloadDStream() result tells if there is still some more data to read from DStream.
+BIT_DStream_unfinished : there is still some data left into the DStream.
+BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
+BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
+BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
+
+When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
+to properly detect the exact end of stream.
+After each decoded symbol, check if DStream is fully consumed using this simple test :
+    BIT_reloadDStream(&DStream) >= BIT_DStream_completed
+
+When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
+Checking if DStream has reached its end is performed by :
+    BIT_endOfDStream(&DStream);
+Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
+    FSE_endOfDState(&DState);
+*/
+
+
+/* *****************************************
+*  FSE unsafe API
+*******************************************/
+static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
+/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
+
+
+/* *****************************************
+*  Implementation of inlined functions
+*******************************************/
+typedef struct {
+    int deltaFindState;
+    U32 deltaNbBits;
+} FSE_symbolCompressionTransform; /* total 8 bytes */
+
+MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
+{
+    const void* ptr = ct;
+    const U16* u16ptr = (const U16*) ptr;
+    const U32 tableLog = MEM_read16(ptr);
+    statePtr->value = (ptrdiff_t)1<<tableLog;
+    statePtr->stateTable = u16ptr+2;
+    statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
+    statePtr->stateLog = tableLog;
+}
+
+
+/*! FSE_initCState2() :
+*   Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
+*   uses the smallest state value possible, saving the cost of this symbol */
+MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
+{
+    FSE_initCState(statePtr, ct);
+    {   const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
+        const U16* stateTable = (const U16*)(statePtr->stateTable);
+        U32 nbBitsOut  = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
+        statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
+        statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+    }
+}
+
+MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
+{
+    FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
+    const U16* const stateTable = (const U16*)(statePtr->stateTable);
+    U32 const nbBitsOut  = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
+    BIT_addBits(bitC, statePtr->value, nbBitsOut);
+    statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+}
+
+MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
+{
+    BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
+    BIT_flushBits(bitC);
+}
+
+
+/* FSE_getMaxNbBits() :
+ * Approximate maximum cost of a symbol, in bits.
+ * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
+ * note 1 : assume symbolValue is valid (<= maxSymbolValue)
+ * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
+MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
+{
+    const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
+    return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
+}
+
+/* FSE_bitCost() :
+ * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
+ * note 1 : assume symbolValue is valid (<= maxSymbolValue)
+ * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
+MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
+{
+    const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
+    U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
+    U32 const threshold = (minNbBits+1) << 16;
+    assert(tableLog < 16);
+    assert(accuracyLog < 31-tableLog);  /* ensure enough room for renormalization double shift */
+    {   U32 const tableSize = 1 << tableLog;
+        U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
+        U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog;   /* linear interpolation (very approximate) */
+        U32 const bitMultiplier = 1 << accuracyLog;
+        assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
+        assert(normalizedDeltaFromThreshold <= bitMultiplier);
+        return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
+    }
+}
+
+
+/* ======    Decompression    ====== */
+
+typedef struct {
+    U16 tableLog;
+    U16 fastMode;
+} FSE_DTableHeader;   /* sizeof U32 */
+
+typedef struct
+{
+    unsigned short newState;
+    unsigned char  symbol;
+    unsigned char  nbBits;
+} FSE_decode_t;   /* size == U32 */
+
+MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
+{
+    const void* ptr = dt;
+    const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
+    DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
+    BIT_reloadDStream(bitD);
+    DStatePtr->table = dt + 1;
+}
+
+MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
+{
+    FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+    return DInfo.symbol;
+}
+
+MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+    FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+    U32 const nbBits = DInfo.nbBits;
+    size_t const lowBits = BIT_readBits(bitD, nbBits);
+    DStatePtr->state = DInfo.newState + lowBits;
+}
+
+MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+    FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+    U32 const nbBits = DInfo.nbBits;
+    BYTE const symbol = DInfo.symbol;
+    size_t const lowBits = BIT_readBits(bitD, nbBits);
+
+    DStatePtr->state = DInfo.newState + lowBits;
+    return symbol;
+}
+
+/*! FSE_decodeSymbolFast() :
+    unsafe, only works if no symbol has a probability > 50% */
+MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+    FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+    U32 const nbBits = DInfo.nbBits;
+    BYTE const symbol = DInfo.symbol;
+    size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
+
+    DStatePtr->state = DInfo.newState + lowBits;
+    return symbol;
+}
+
+MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
+{
+    return DStatePtr->state == 0;
+}
+
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+/* **************************************************************
+*  Tuning parameters
+****************************************************************/
+/*!MEMORY_USAGE :
+*  Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+*  Increasing memory usage improves compression ratio
+*  Reduced memory usage can improve speed, due to cache effect
+*  Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+#ifndef FSE_MAX_MEMORY_USAGE
+#  define FSE_MAX_MEMORY_USAGE 14
+#endif
+#ifndef FSE_DEFAULT_MEMORY_USAGE
+#  define FSE_DEFAULT_MEMORY_USAGE 13
+#endif
+
+/*!FSE_MAX_SYMBOL_VALUE :
+*  Maximum symbol value authorized.
+*  Required for proper stack allocation */
+#ifndef FSE_MAX_SYMBOL_VALUE
+#  define FSE_MAX_SYMBOL_VALUE 255
+#endif
+
+/* **************************************************************
+*  template functions type & suffix
+****************************************************************/
+#define FSE_FUNCTION_TYPE BYTE
+#define FSE_FUNCTION_EXTENSION
+#define FSE_DECODE_TYPE FSE_decode_t
+
+
+#endif   /* !FSE_COMMONDEFS_ONLY */
+
+
+/* ***************************************************************
+*  Constants
+*****************************************************************/
+#define FSE_MAX_TABLELOG  (FSE_MAX_MEMORY_USAGE-2)
+#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
+#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
+#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
+#define FSE_MIN_TABLELOG 5
+
+#define FSE_TABLELOG_ABSOLUTE_MAX 15
+#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
+#  error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
+#endif
+
+#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
+
+
+#endif /* FSE_STATIC_LINKING_ONLY */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/common/fse_decompress.c b/Utilities/cmzstd/lib/common/fse_decompress.c
new file mode 100644
index 0000000..72bbead
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/fse_decompress.c
@@ -0,0 +1,309 @@
+/* ******************************************************************
+   FSE : Finite State Entropy decoder
+   Copyright (C) 2013-2015, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+    - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+
+/* **************************************************************
+*  Includes
+****************************************************************/
+#include <stdlib.h>     /* malloc, free, qsort */
+#include <string.h>     /* memcpy, memset */
+#include "bitstream.h"
+#include "compiler.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+*  Error Management
+****************************************************************/
+#define FSE_isError ERR_isError
+#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)   /* use only *after* variable declarations */
+
+/* check and forward error code */
+#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; }
+
+
+/* **************************************************************
+*  Templates
+****************************************************************/
+/*
+  designed to be included
+  for type-specific functions (template emulation in C)
+  Objective is to write these functions only once, for improved maintenance
+*/
+
+/* safety checks */
+#ifndef FSE_FUNCTION_EXTENSION
+#  error "FSE_FUNCTION_EXTENSION must be defined"
+#endif
+#ifndef FSE_FUNCTION_TYPE
+#  error "FSE_FUNCTION_TYPE must be defined"
+#endif
+
+/* Function names */
+#define FSE_CAT(X,Y) X##Y
+#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
+#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
+
+
+/* Function templates */
+FSE_DTable* FSE_createDTable (unsigned tableLog)
+{
+    if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
+    return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
+}
+
+void FSE_freeDTable (FSE_DTable* dt)
+{
+    free(dt);
+}
+
+size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+    void* const tdPtr = dt+1;   /* because *dt is unsigned, 32-bits aligned on 32-bits */
+    FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
+    U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
+
+    U32 const maxSV1 = maxSymbolValue + 1;
+    U32 const tableSize = 1 << tableLog;
+    U32 highThreshold = tableSize-1;
+
+    /* Sanity Checks */
+    if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
+    if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+
+    /* Init, lay down lowprob symbols */
+    {   FSE_DTableHeader DTableH;
+        DTableH.tableLog = (U16)tableLog;
+        DTableH.fastMode = 1;
+        {   S16 const largeLimit= (S16)(1 << (tableLog-1));
+            U32 s;
+            for (s=0; s<maxSV1; s++) {
+                if (normalizedCounter[s]==-1) {
+                    tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
+                    symbolNext[s] = 1;
+                } else {
+                    if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
+                    symbolNext[s] = normalizedCounter[s];
+        }   }   }
+        memcpy(dt, &DTableH, sizeof(DTableH));
+    }
+
+    /* Spread symbols */
+    {   U32 const tableMask = tableSize-1;
+        U32 const step = FSE_TABLESTEP(tableSize);
+        U32 s, position = 0;
+        for (s=0; s<maxSV1; s++) {
+            int i;
+            for (i=0; i<normalizedCounter[s]; i++) {
+                tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
+                position = (position + step) & tableMask;
+                while (position > highThreshold) position = (position + step) & tableMask;   /* lowprob area */
+        }   }
+        if (position!=0) return ERROR(GENERIC);   /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+    }
+
+    /* Build Decoding table */
+    {   U32 u;
+        for (u=0; u<tableSize; u++) {
+            FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
+            U32 const nextState = symbolNext[symbol]++;
+            tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
+            tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
+    }   }
+
+    return 0;
+}
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+/*-*******************************************************
+*  Decompression (Byte symbols)
+*********************************************************/
+size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
+{
+    void* ptr = dt;
+    FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
+    void* dPtr = dt + 1;
+    FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
+
+    DTableH->tableLog = 0;
+    DTableH->fastMode = 0;
+
+    cell->newState = 0;
+    cell->symbol = symbolValue;
+    cell->nbBits = 0;
+
+    return 0;
+}
+
+
+size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
+{
+    void* ptr = dt;
+    FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
+    void* dPtr = dt + 1;
+    FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
+    const unsigned tableSize = 1 << nbBits;
+    const unsigned tableMask = tableSize - 1;
+    const unsigned maxSV1 = tableMask+1;
+    unsigned s;
+
+    /* Sanity checks */
+    if (nbBits < 1) return ERROR(GENERIC);         /* min size */
+
+    /* Build Decoding Table */
+    DTableH->tableLog = (U16)nbBits;
+    DTableH->fastMode = 1;
+    for (s=0; s<maxSV1; s++) {
+        dinfo[s].newState = 0;
+        dinfo[s].symbol = (BYTE)s;
+        dinfo[s].nbBits = (BYTE)nbBits;
+    }
+
+    return 0;
+}
+
+FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
+          void* dst, size_t maxDstSize,
+    const void* cSrc, size_t cSrcSize,
+    const FSE_DTable* dt, const unsigned fast)
+{
+    BYTE* const ostart = (BYTE*) dst;
+    BYTE* op = ostart;
+    BYTE* const omax = op + maxDstSize;
+    BYTE* const olimit = omax-3;
+
+    BIT_DStream_t bitD;
+    FSE_DState_t state1;
+    FSE_DState_t state2;
+
+    /* Init */
+    CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
+
+    FSE_initDState(&state1, &bitD, dt);
+    FSE_initDState(&state2, &bitD, dt);
+
+#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
+
+    /* 4 symbols per loop */
+    for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
+        op[0] = FSE_GETSYMBOL(&state1);
+
+        if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
+            BIT_reloadDStream(&bitD);
+
+        op[1] = FSE_GETSYMBOL(&state2);
+
+        if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
+            { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
+
+        op[2] = FSE_GETSYMBOL(&state1);
+
+        if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
+            BIT_reloadDStream(&bitD);
+
+        op[3] = FSE_GETSYMBOL(&state2);
+    }
+
+    /* tail */
+    /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
+    while (1) {
+        if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+        *op++ = FSE_GETSYMBOL(&state1);
+        if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+            *op++ = FSE_GETSYMBOL(&state2);
+            break;
+        }
+
+        if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+        *op++ = FSE_GETSYMBOL(&state2);
+        if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+            *op++ = FSE_GETSYMBOL(&state1);
+            break;
+    }   }
+
+    return op-ostart;
+}
+
+
+size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
+                            const void* cSrc, size_t cSrcSize,
+                            const FSE_DTable* dt)
+{
+    const void* ptr = dt;
+    const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
+    const U32 fastMode = DTableH->fastMode;
+
+    /* select fast mode (static) */
+    if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
+    return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
+}
+
+
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
+{
+    const BYTE* const istart = (const BYTE*)cSrc;
+    const BYTE* ip = istart;
+    short counting[FSE_MAX_SYMBOL_VALUE+1];
+    unsigned tableLog;
+    unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+
+    /* normal FSE decoding mode */
+    size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
+    if (FSE_isError(NCountLength)) return NCountLength;
+    //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong);   /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
+    if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
+    ip += NCountLength;
+    cSrcSize -= NCountLength;
+
+    CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
+
+    return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace);   /* always return, even if it is an error code */
+}
+
+
+typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
+
+size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
+{
+    DTable_max_t dt;   /* Static analyzer seems unable to understand this table will be properly initialized later */
+    return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);
+}
+
+
+
+#endif   /* FSE_COMMONDEFS_ONLY */
diff --git a/Utilities/cmzstd/lib/common/huf.h b/Utilities/cmzstd/lib/common/huf.h
new file mode 100644
index 0000000..6b572c4
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/huf.h
@@ -0,0 +1,358 @@
+/* ******************************************************************
+   huff0 huffman codec,
+   part of Finite State Entropy library
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef HUF_H_298734234
+#define HUF_H_298734234
+
+/* *** Dependencies *** */
+#include <stddef.h>    /* size_t */
+
+
+/* *** library symbols visibility *** */
+/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
+ *        HUF symbols remain "private" (internal symbols for library only).
+ *        Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
+#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
+#  define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
+#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1)   /* Visual expected */
+#  define HUF_PUBLIC_API __declspec(dllexport)
+#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
+#  define HUF_PUBLIC_API __declspec(dllimport)  /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
+#else
+#  define HUF_PUBLIC_API
+#endif
+
+
+/* ========================== */
+/* ***  simple functions  *** */
+/* ========================== */
+
+/** HUF_compress() :
+ *  Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
+ * 'dst' buffer must be already allocated.
+ *  Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
+ * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
+ * @return : size of compressed data (<= `dstCapacity`).
+ *  Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
+ *                   if HUF_isError(return), compression failed (more details using HUF_getErrorName())
+ */
+HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
+                             const void* src, size_t srcSize);
+
+/** HUF_decompress() :
+ *  Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
+ *  into already allocated buffer 'dst', of minimum size 'dstSize'.
+ * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
+ *  Note : in contrast with FSE, HUF_decompress can regenerate
+ *         RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
+ *         because it knows size to regenerate (originalSize).
+ * @return : size of regenerated data (== originalSize),
+ *           or an error code, which can be tested using HUF_isError()
+ */
+HUF_PUBLIC_API size_t HUF_decompress(void* dst,  size_t originalSize,
+                               const void* cSrc, size_t cSrcSize);
+
+
+/* ***   Tool functions *** */
+#define HUF_BLOCKSIZE_MAX (128 * 1024)                  /**< maximum input size for a single block compressed with HUF_compress */
+HUF_PUBLIC_API size_t HUF_compressBound(size_t size);   /**< maximum compressed size (worst case) */
+
+/* Error Management */
+HUF_PUBLIC_API unsigned    HUF_isError(size_t code);       /**< tells if a return value is an error code */
+HUF_PUBLIC_API const char* HUF_getErrorName(size_t code);  /**< provides error code string (useful for debugging) */
+
+
+/* ***   Advanced function   *** */
+
+/** HUF_compress2() :
+ *  Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
+ * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
+ * `tableLog` must be `<= HUF_TABLELOG_MAX` . */
+HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
+                               const void* src, size_t srcSize,
+                               unsigned maxSymbolValue, unsigned tableLog);
+
+/** HUF_compress4X_wksp() :
+ *  Same as HUF_compress2(), but uses externally allocated `workSpace`.
+ * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */
+#define HUF_WORKSPACE_SIZE (6 << 10)
+#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
+HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
+                                     const void* src, size_t srcSize,
+                                     unsigned maxSymbolValue, unsigned tableLog,
+                                     void* workSpace, size_t wkspSize);
+
+#endif   /* HUF_H_298734234 */
+
+/* ******************************************************************
+ *  WARNING !!
+ *  The following section contains advanced and experimental definitions
+ *  which shall never be used in the context of a dynamic library,
+ *  because they are not guaranteed to remain stable in the future.
+ *  Only consider them in association with static linking.
+ * *****************************************************************/
+#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
+#define HUF_H_HUF_STATIC_LINKING_ONLY
+
+/* *** Dependencies *** */
+#include "mem.h"   /* U32 */
+
+
+/* *** Constants *** */
+#define HUF_TABLELOG_MAX      12      /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
+#define HUF_TABLELOG_DEFAULT  11      /* default tableLog value when none specified */
+#define HUF_SYMBOLVALUE_MAX  255
+
+#define HUF_TABLELOG_ABSOLUTEMAX  15  /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
+#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
+#  error "HUF_TABLELOG_MAX is too large !"
+#endif
+
+
+/* ****************************************
+*  Static allocation
+******************************************/
+/* HUF buffer bounds */
+#define HUF_CTABLEBOUND 129
+#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8)   /* only true when incompressible is pre-filtered with fast heuristic */
+#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size))   /* Macro version, useful for static allocation */
+
+/* static allocation of HUF's Compression Table */
+#define HUF_CTABLE_SIZE_U32(maxSymbolValue)   ((maxSymbolValue)+1)   /* Use tables of U32, for proper alignment */
+#define HUF_CTABLE_SIZE(maxSymbolValue)       (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32))
+#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
+    U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \
+    void* name##hv = &(name##hb); \
+    HUF_CElt* name = (HUF_CElt*)(name##hv)   /* no final ; */
+
+/* static allocation of HUF's DTable */
+typedef U32 HUF_DTable;
+#define HUF_DTABLE_SIZE(maxTableLog)   (1 + (1<<(maxTableLog)))
+#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
+        HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
+#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
+        HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
+
+
+/* ****************************************
+*  Advanced decompression functions
+******************************************/
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */
+#endif
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< decodes RLE and uncompressed */
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */
+size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);   /**< single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);   /**< double-symbols decoder */
+#endif
+
+
+/* ****************************************
+ *  HUF detailed API
+ * ****************************************/
+
+/*! HUF_compress() does the following:
+ *  1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
+ *  2. (optional) refine tableLog using HUF_optimalTableLog()
+ *  3. build Huffman table from count using HUF_buildCTable()
+ *  4. save Huffman table to memory buffer using HUF_writeCTable()
+ *  5. encode the data stream using HUF_compress4X_usingCTable()
+ *
+ *  The following API allows targeting specific sub-functions for advanced tasks.
+ *  For example, it's possible to compress several blocks using the same 'CTable',
+ *  or to save and regenerate 'CTable' using external methods.
+ */
+unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
+typedef struct HUF_CElt_s HUF_CElt;   /* incomplete type */
+size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits);   /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+
+typedef enum {
+   HUF_repeat_none,  /**< Cannot use the previous table */
+   HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
+   HUF_repeat_valid  /**< Can use the previous table and it is assumed to be valid */
+ } HUF_repeat;
+/** HUF_compress4X_repeat() :
+ *  Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
+ *  If it uses hufTable it does not modify hufTable or repeat.
+ *  If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
+ *  If preferRepeat then the old table will always be used if valid. */
+size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
+                       const void* src, size_t srcSize,
+                       unsigned maxSymbolValue, unsigned tableLog,
+                       void* workSpace, size_t wkspSize,    /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
+                       HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
+
+/** HUF_buildCTable_wksp() :
+ *  Same as HUF_buildCTable(), but using externally allocated scratch buffer.
+ * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
+ */
+#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
+#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
+size_t HUF_buildCTable_wksp (HUF_CElt* tree,
+                       const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
+                             void* workSpace, size_t wkspSize);
+
+/*! HUF_readStats() :
+ *  Read compact Huffman tree, saved by HUF_writeCTable().
+ * `huffWeight` is destination buffer.
+ * @return : size read from `src` , or an error Code .
+ *  Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
+size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
+                     U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
+                     const void* src, size_t srcSize);
+
+/** HUF_readCTable() :
+ *  Loading a CTable saved with HUF_writeCTable() */
+size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
+
+/** HUF_getNbBits() :
+ *  Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
+ *  Note 1 : is not inlined, as HUF_CElt definition is private
+ *  Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */
+U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue);
+
+/*
+ * HUF_decompress() does the following:
+ * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
+ * 2. build Huffman table from save, using HUF_readDTableX?()
+ * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
+ */
+
+/** HUF_selectDecoder() :
+ *  Tells which decoder is likely to decode faster,
+ *  based on a set of pre-computed metrics.
+ * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
+ *  Assumption : 0 < dstSize <= 128 KB */
+U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
+
+/**
+ *  The minimum workspace size for the `workSpace` used in
+ *  HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp().
+ *
+ *  The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
+ *  HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
+ *  Buffer overflow errors may potentially occur if code modifications result in
+ *  a required workspace size greater than that specified in the following
+ *  macro.
+ */
+#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
+#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
+size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
+size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
+#endif
+
+size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+
+
+/* ====================== */
+/* single stream variants */
+/* ====================== */
+
+size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
+size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);  /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+/** HUF_compress1X_repeat() :
+ *  Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
+ *  If it uses hufTable it does not modify hufTable or repeat.
+ *  If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
+ *  If preferRepeat then the old table will always be used if valid. */
+size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
+                       const void* src, size_t srcSize,
+                       unsigned maxSymbolValue, unsigned tableLog,
+                       void* workSpace, size_t wkspSize,   /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
+                       HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* double-symbol decoder */
+#endif
+
+size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */
+size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);   /**< single-symbol decoder */
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);   /**< double-symbols decoder */
+#endif
+
+size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);   /**< automatic selection of sing or double symbol decoder, based on DTable */
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+
+/* BMI2 variants.
+ * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
+ */
+size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+#endif
+size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
+size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+
+#endif /* HUF_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/common/mem.h b/Utilities/cmzstd/lib/common/mem.h
new file mode 100644
index 0000000..5da2487
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/mem.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef MEM_H_MODULE
+#define MEM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*-****************************************
+*  Dependencies
+******************************************/
+#include <stddef.h>     /* size_t, ptrdiff_t */
+#include <string.h>     /* memcpy */
+
+
+/*-****************************************
+*  Compiler specifics
+******************************************/
+#if defined(_MSC_VER)   /* Visual Studio */
+#   include <stdlib.h>  /* _byteswap_ulong */
+#   include <intrin.h>  /* _byteswap_* */
+#endif
+#if defined(__GNUC__)
+#  define MEM_STATIC static __inline __attribute__((unused))
+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+#  define MEM_STATIC static inline
+#elif defined(_MSC_VER)
+#  define MEM_STATIC static __inline
+#else
+#  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
+#endif
+
+#ifndef __has_builtin
+#  define __has_builtin(x) 0  /* compat. with non-clang compilers */
+#endif
+
+/* code only tested on 32 and 64 bits systems */
+#define MEM_STATIC_ASSERT(c)   { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
+MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
+
+
+/*-**************************************************************
+*  Basic Types
+*****************************************************************/
+#if  !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+  typedef   uint8_t BYTE;
+  typedef  uint16_t U16;
+  typedef   int16_t S16;
+  typedef  uint32_t U32;
+  typedef   int32_t S32;
+  typedef  uint64_t U64;
+  typedef   int64_t S64;
+#else
+# include <limits.h>
+#if CHAR_BIT != 8
+#  error "this implementation requires char to be exactly 8-bit type"
+#endif
+  typedef unsigned char      BYTE;
+#if USHRT_MAX != 65535
+#  error "this implementation requires short to be exactly 16-bit type"
+#endif
+  typedef unsigned short      U16;
+  typedef   signed short      S16;
+#if UINT_MAX != 4294967295
+#  error "this implementation requires int to be exactly 32-bit type"
+#endif
+  typedef unsigned int        U32;
+  typedef   signed int        S32;
+/* note : there are no limits defined for long long type in C90.
+ * limits exist in C99, however, in such case, <stdint.h> is preferred */
+  typedef unsigned long long  U64;
+  typedef   signed long long  S64;
+#endif
+
+
+/*-**************************************************************
+*  Memory I/O
+*****************************************************************/
+/* MEM_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).
+ *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method is portable but violate C standard.
+ *            It can generate buggy code on targets depending on alignment.
+ *            In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)
+ * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef MEM_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
+#  if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+#    define MEM_FORCE_MEMORY_ACCESS 2
+#  elif defined(__INTEL_COMPILER) || defined(__GNUC__)
+#    define MEM_FORCE_MEMORY_ACCESS 1
+#  endif
+#endif
+
+MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
+MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
+
+MEM_STATIC unsigned MEM_isLittleEndian(void)
+{
+    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */
+    return one.c[0];
+}
+
+#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
+
+/* violates C standard, by lying on structure alignment.
+Only use if no other choice to achieve best performance on target platform */
+MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
+MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
+MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
+MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
+
+#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
+    __pragma( pack(push, 1) )
+    typedef struct { U16 v; } unalign16;
+    typedef struct { U32 v; } unalign32;
+    typedef struct { U64 v; } unalign64;
+    typedef struct { size_t v; } unalignArch;
+    __pragma( pack(pop) )
+#else
+    typedef struct { U16 v; } __attribute__((packed)) unalign16;
+    typedef struct { U32 v; } __attribute__((packed)) unalign32;
+    typedef struct { U64 v; } __attribute__((packed)) unalign64;
+    typedef struct { size_t v; } __attribute__((packed)) unalignArch;
+#endif
+
+MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }
+MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }
+MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }
+MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }
+
+#else
+
+/* default method, safe and standard.
+   can sometimes prove slower */
+
+MEM_STATIC U16 MEM_read16(const void* memPtr)
+{
+    U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC U32 MEM_read32(const void* memPtr)
+{
+    U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC U64 MEM_read64(const void* memPtr)
+{
+    U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC size_t MEM_readST(const void* memPtr)
+{
+    size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value)
+{
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+MEM_STATIC void MEM_write32(void* memPtr, U32 value)
+{
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+MEM_STATIC void MEM_write64(void* memPtr, U64 value)
+{
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+#endif /* MEM_FORCE_MEMORY_ACCESS */
+
+MEM_STATIC U32 MEM_swap32(U32 in)
+{
+#if defined(_MSC_VER)     /* Visual Studio */
+    return _byteswap_ulong(in);
+#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
+  || (defined(__clang__) && __has_builtin(__builtin_bswap32))
+    return __builtin_bswap32(in);
+#else
+    return  ((in << 24) & 0xff000000 ) |
+            ((in <<  8) & 0x00ff0000 ) |
+            ((in >>  8) & 0x0000ff00 ) |
+            ((in >> 24) & 0x000000ff );
+#endif
+}
+
+MEM_STATIC U64 MEM_swap64(U64 in)
+{
+#if defined(_MSC_VER)     /* Visual Studio */
+    return _byteswap_uint64(in);
+#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
+  || (defined(__clang__) && __has_builtin(__builtin_bswap64))
+    return __builtin_bswap64(in);
+#else
+    return  ((in << 56) & 0xff00000000000000ULL) |
+            ((in << 40) & 0x00ff000000000000ULL) |
+            ((in << 24) & 0x0000ff0000000000ULL) |
+            ((in << 8)  & 0x000000ff00000000ULL) |
+            ((in >> 8)  & 0x00000000ff000000ULL) |
+            ((in >> 24) & 0x0000000000ff0000ULL) |
+            ((in >> 40) & 0x000000000000ff00ULL) |
+            ((in >> 56) & 0x00000000000000ffULL);
+#endif
+}
+
+MEM_STATIC size_t MEM_swapST(size_t in)
+{
+    if (MEM_32bits())
+        return (size_t)MEM_swap32((U32)in);
+    else
+        return (size_t)MEM_swap64((U64)in);
+}
+
+/*=== Little endian r/w ===*/
+
+MEM_STATIC U16 MEM_readLE16(const void* memPtr)
+{
+    if (MEM_isLittleEndian())
+        return MEM_read16(memPtr);
+    else {
+        const BYTE* p = (const BYTE*)memPtr;
+        return (U16)(p[0] + (p[1]<<8));
+    }
+}
+
+MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
+{
+    if (MEM_isLittleEndian()) {
+        MEM_write16(memPtr, val);
+    } else {
+        BYTE* p = (BYTE*)memPtr;
+        p[0] = (BYTE)val;
+        p[1] = (BYTE)(val>>8);
+    }
+}
+
+MEM_STATIC U32 MEM_readLE24(const void* memPtr)
+{
+    return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
+}
+
+MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
+{
+    MEM_writeLE16(memPtr, (U16)val);
+    ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
+}
+
+MEM_STATIC U32 MEM_readLE32(const void* memPtr)
+{
+    if (MEM_isLittleEndian())
+        return MEM_read32(memPtr);
+    else
+        return MEM_swap32(MEM_read32(memPtr));
+}
+
+MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
+{
+    if (MEM_isLittleEndian())
+        MEM_write32(memPtr, val32);
+    else
+        MEM_write32(memPtr, MEM_swap32(val32));
+}
+
+MEM_STATIC U64 MEM_readLE64(const void* memPtr)
+{
+    if (MEM_isLittleEndian())
+        return MEM_read64(memPtr);
+    else
+        return MEM_swap64(MEM_read64(memPtr));
+}
+
+MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
+{
+    if (MEM_isLittleEndian())
+        MEM_write64(memPtr, val64);
+    else
+        MEM_write64(memPtr, MEM_swap64(val64));
+}
+
+MEM_STATIC size_t MEM_readLEST(const void* memPtr)
+{
+    if (MEM_32bits())
+        return (size_t)MEM_readLE32(memPtr);
+    else
+        return (size_t)MEM_readLE64(memPtr);
+}
+
+MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
+{
+    if (MEM_32bits())
+        MEM_writeLE32(memPtr, (U32)val);
+    else
+        MEM_writeLE64(memPtr, (U64)val);
+}
+
+/*=== Big endian r/w ===*/
+
+MEM_STATIC U32 MEM_readBE32(const void* memPtr)
+{
+    if (MEM_isLittleEndian())
+        return MEM_swap32(MEM_read32(memPtr));
+    else
+        return MEM_read32(memPtr);
+}
+
+MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
+{
+    if (MEM_isLittleEndian())
+        MEM_write32(memPtr, MEM_swap32(val32));
+    else
+        MEM_write32(memPtr, val32);
+}
+
+MEM_STATIC U64 MEM_readBE64(const void* memPtr)
+{
+    if (MEM_isLittleEndian())
+        return MEM_swap64(MEM_read64(memPtr));
+    else
+        return MEM_read64(memPtr);
+}
+
+MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
+{
+    if (MEM_isLittleEndian())
+        MEM_write64(memPtr, MEM_swap64(val64));
+    else
+        MEM_write64(memPtr, val64);
+}
+
+MEM_STATIC size_t MEM_readBEST(const void* memPtr)
+{
+    if (MEM_32bits())
+        return (size_t)MEM_readBE32(memPtr);
+    else
+        return (size_t)MEM_readBE64(memPtr);
+}
+
+MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
+{
+    if (MEM_32bits())
+        MEM_writeBE32(memPtr, (U32)val);
+    else
+        MEM_writeBE64(memPtr, (U64)val);
+}
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* MEM_H_MODULE */
diff --git a/Utilities/cmzstd/lib/common/pool.c b/Utilities/cmzstd/lib/common/pool.c
new file mode 100644
index 0000000..7a82945
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/pool.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ======   Dependencies   ======= */
+#include <stddef.h>    /* size_t */
+#include "debug.h"     /* assert */
+#include "zstd_internal.h"  /* ZSTD_malloc, ZSTD_free */
+#include "pool.h"
+
+/* ======   Compiler specifics   ====== */
+#if defined(_MSC_VER)
+#  pragma warning(disable : 4204)        /* disable: C4204: non-constant aggregate initializer */
+#endif
+
+
+#ifdef ZSTD_MULTITHREAD
+
+#include "threading.h"   /* pthread adaptation */
+
+/* A job is a function and an opaque argument */
+typedef struct POOL_job_s {
+    POOL_function function;
+    void *opaque;
+} POOL_job;
+
+struct POOL_ctx_s {
+    ZSTD_customMem customMem;
+    /* Keep track of the threads */
+    ZSTD_pthread_t* threads;
+    size_t threadCapacity;
+    size_t threadLimit;
+
+    /* The queue is a circular buffer */
+    POOL_job *queue;
+    size_t queueHead;
+    size_t queueTail;
+    size_t queueSize;
+
+    /* The number of threads working on jobs */
+    size_t numThreadsBusy;
+    /* Indicates if the queue is empty */
+    int queueEmpty;
+
+    /* The mutex protects the queue */
+    ZSTD_pthread_mutex_t queueMutex;
+    /* Condition variable for pushers to wait on when the queue is full */
+    ZSTD_pthread_cond_t queuePushCond;
+    /* Condition variables for poppers to wait on when the queue is empty */
+    ZSTD_pthread_cond_t queuePopCond;
+    /* Indicates if the queue is shutting down */
+    int shutdown;
+};
+
+/* POOL_thread() :
+ * Work thread for the thread pool.
+ * Waits for jobs and executes them.
+ * @returns : NULL on failure else non-null.
+ */
+static void* POOL_thread(void* opaque) {
+    POOL_ctx* const ctx = (POOL_ctx*)opaque;
+    if (!ctx) { return NULL; }
+    for (;;) {
+        /* Lock the mutex and wait for a non-empty queue or until shutdown */
+        ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+
+        while ( ctx->queueEmpty
+            || (ctx->numThreadsBusy >= ctx->threadLimit) ) {
+            if (ctx->shutdown) {
+                /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
+                 * a few threads will be shutdown while !queueEmpty,
+                 * but enough threads will remain active to finish the queue */
+                ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+                return opaque;
+            }
+            ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
+        }
+        /* Pop a job off the queue */
+        {   POOL_job const job = ctx->queue[ctx->queueHead];
+            ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
+            ctx->numThreadsBusy++;
+            ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
+            /* Unlock the mutex, signal a pusher, and run the job */
+            ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+            ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+
+            job.function(job.opaque);
+
+            /* If the intended queue size was 0, signal after finishing job */
+            ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+            ctx->numThreadsBusy--;
+            if (ctx->queueSize == 1) {
+                ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+            }
+            ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+        }
+    }  /* for (;;) */
+    assert(0);  /* Unreachable */
+}
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+    return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
+}
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
+                               ZSTD_customMem customMem) {
+    POOL_ctx* ctx;
+    /* Check parameters */
+    if (!numThreads) { return NULL; }
+    /* Allocate the context and zero initialize */
+    ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
+    if (!ctx) { return NULL; }
+    /* Initialize the job queue.
+     * It needs one extra space since one space is wasted to differentiate
+     * empty and full queues.
+     */
+    ctx->queueSize = queueSize + 1;
+    ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
+    ctx->queueHead = 0;
+    ctx->queueTail = 0;
+    ctx->numThreadsBusy = 0;
+    ctx->queueEmpty = 1;
+    (void)ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
+    (void)ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
+    (void)ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
+    ctx->shutdown = 0;
+    /* Allocate space for the thread handles */
+    ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
+    ctx->threadCapacity = 0;
+    ctx->customMem = customMem;
+    /* Check for errors */
+    if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
+    /* Initialize the threads */
+    {   size_t i;
+        for (i = 0; i < numThreads; ++i) {
+            if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
+                ctx->threadCapacity = i;
+                POOL_free(ctx);
+                return NULL;
+        }   }
+        ctx->threadCapacity = numThreads;
+        ctx->threadLimit = numThreads;
+    }
+    return ctx;
+}
+
+/*! POOL_join() :
+    Shutdown the queue, wake any sleeping threads, and join all of the threads.
+*/
+static void POOL_join(POOL_ctx* ctx) {
+    /* Shut down the queue */
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    ctx->shutdown = 1;
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+    /* Wake up sleeping threads */
+    ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
+    ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+    /* Join all of the threads */
+    {   size_t i;
+        for (i = 0; i < ctx->threadCapacity; ++i) {
+            ZSTD_pthread_join(ctx->threads[i], NULL);  /* note : could fail */
+    }   }
+}
+
+void POOL_free(POOL_ctx *ctx) {
+    if (!ctx) { return; }
+    POOL_join(ctx);
+    ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
+    ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
+    ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
+    ZSTD_free(ctx->queue, ctx->customMem);
+    ZSTD_free(ctx->threads, ctx->customMem);
+    ZSTD_free(ctx, ctx->customMem);
+}
+
+
+
+size_t POOL_sizeof(POOL_ctx *ctx) {
+    if (ctx==NULL) return 0;  /* supports sizeof NULL */
+    return sizeof(*ctx)
+        + ctx->queueSize * sizeof(POOL_job)
+        + ctx->threadCapacity * sizeof(ZSTD_pthread_t);
+}
+
+
+/* @return : 0 on success, 1 on error */
+static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
+{
+    if (numThreads <= ctx->threadCapacity) {
+        if (!numThreads) return 1;
+        ctx->threadLimit = numThreads;
+        return 0;
+    }
+    /* numThreads > threadCapacity */
+    {   ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
+        if (!threadPool) return 1;
+        /* replace existing thread pool */
+        memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
+        ZSTD_free(ctx->threads, ctx->customMem);
+        ctx->threads = threadPool;
+        /* Initialize additional threads */
+        {   size_t threadId;
+            for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
+                if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
+                    ctx->threadCapacity = threadId;
+                    return 1;
+            }   }
+    }   }
+    /* successfully expanded */
+    ctx->threadCapacity = numThreads;
+    ctx->threadLimit = numThreads;
+    return 0;
+}
+
+/* @return : 0 on success, 1 on error */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads)
+{
+    int result;
+    if (ctx==NULL) return 1;
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    result = POOL_resize_internal(ctx, numThreads);
+    ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+    return result;
+}
+
+/**
+ * Returns 1 if the queue is full and 0 otherwise.
+ *
+ * When queueSize is 1 (pool was created with an intended queueSize of 0),
+ * then a queue is empty if there is a thread free _and_ no job is waiting.
+ */
+static int isQueueFull(POOL_ctx const* ctx) {
+    if (ctx->queueSize > 1) {
+        return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
+    } else {
+        return (ctx->numThreadsBusy == ctx->threadLimit) ||
+               !ctx->queueEmpty;
+    }
+}
+
+
+static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
+{
+    POOL_job const job = {function, opaque};
+    assert(ctx != NULL);
+    if (ctx->shutdown) return;
+
+    ctx->queueEmpty = 0;
+    ctx->queue[ctx->queueTail] = job;
+    ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
+    ZSTD_pthread_cond_signal(&ctx->queuePopCond);
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+    assert(ctx != NULL);
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    /* Wait until there is space in the queue for the new job */
+    while (isQueueFull(ctx) && (!ctx->shutdown)) {
+        ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
+    }
+    POOL_add_internal(ctx, function, opaque);
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+}
+
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+    assert(ctx != NULL);
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    if (isQueueFull(ctx)) {
+        ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+        return 0;
+    }
+    POOL_add_internal(ctx, function, opaque);
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+    return 1;
+}
+
+
+#else  /* ZSTD_MULTITHREAD  not defined */
+
+/* ========================== */
+/* No multi-threading support */
+/* ========================== */
+
+
+/* We don't need any data, but if it is empty, malloc() might return NULL. */
+struct POOL_ctx_s {
+    int dummy;
+};
+static POOL_ctx g_ctx;
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+    return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
+}
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
+    (void)numThreads;
+    (void)queueSize;
+    (void)customMem;
+    return &g_ctx;
+}
+
+void POOL_free(POOL_ctx* ctx) {
+    assert(!ctx || ctx == &g_ctx);
+    (void)ctx;
+}
+
+int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
+    (void)ctx; (void)numThreads;
+    return 0;
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
+    (void)ctx;
+    function(opaque);
+}
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
+    (void)ctx;
+    function(opaque);
+    return 1;
+}
+
+size_t POOL_sizeof(POOL_ctx* ctx) {
+    if (ctx==NULL) return 0;  /* supports sizeof NULL */
+    assert(ctx == &g_ctx);
+    return sizeof(*ctx);
+}
+
+#endif  /* ZSTD_MULTITHREAD */
diff --git a/Utilities/cmzstd/lib/common/pool.h b/Utilities/cmzstd/lib/common/pool.h
new file mode 100644
index 0000000..458d37f
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/pool.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef POOL_H
+#define POOL_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#include <stddef.h>   /* size_t */
+#define ZSTD_STATIC_LINKING_ONLY   /* ZSTD_customMem */
+#include "zstd.h"
+
+typedef struct POOL_ctx_s POOL_ctx;
+
+/*! POOL_create() :
+ *  Create a thread pool with at most `numThreads` threads.
+ * `numThreads` must be at least 1.
+ *  The maximum number of queued jobs before blocking is `queueSize`.
+ * @return : POOL_ctx pointer on success, else NULL.
+*/
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
+                               ZSTD_customMem customMem);
+
+/*! POOL_free() :
+ *  Free a thread pool returned by POOL_create().
+ */
+void POOL_free(POOL_ctx* ctx);
+
+/*! POOL_resize() :
+ *  Expands or shrinks pool's number of threads.
+ *  This is more efficient than releasing + creating a new context,
+ *  since it tries to preserve and re-use existing threads.
+ * `numThreads` must be at least 1.
+ * @return : 0 when resize was successful,
+ *           !0 (typically 1) if there is an error.
+ *    note : only numThreads can be resized, queueSize remains unchanged.
+ */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads);
+
+/*! POOL_sizeof() :
+ * @return threadpool memory usage
+ *  note : compatible with NULL (returns 0 in this case)
+ */
+size_t POOL_sizeof(POOL_ctx* ctx);
+
+/*! POOL_function :
+ *  The function type that can be added to a thread pool.
+ */
+typedef void (*POOL_function)(void*);
+
+/*! POOL_add() :
+ *  Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
+ *  Possibly blocks until there is room in the queue.
+ *  Note : The function may be executed asynchronously,
+ *         therefore, `opaque` must live until function has been completed.
+ */
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+/*! POOL_tryAdd() :
+ *  Add the job `function(opaque)` to thread pool _if_ a worker is available.
+ *  Returns immediately even if not (does not block).
+ * @return : 1 if successful, 0 if not.
+ */
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
diff --git a/Utilities/cmzstd/lib/common/threading.c b/Utilities/cmzstd/lib/common/threading.c
new file mode 100644
index 0000000..8be8c8d
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/threading.c
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2016 Tino Reichardt
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ *
+ * You can contact the author at:
+ * - zstdmt source repository: https://github.com/mcmilk/zstdmt
+ */
+
+/**
+ * This file will hold wrapper for systems, which do not support pthreads
+ */
+
+/* create fake symbol to avoid empty trnaslation unit warning */
+int g_ZSTD_threading_useles_symbol;
+
+#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
+
+/**
+ * Windows minimalist Pthread Wrapper, based on :
+ * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
+ */
+
+
+/* ===  Dependencies  === */
+#include <process.h>
+#include <errno.h>
+#include "threading.h"
+
+
+/* ===  Implementation  === */
+
+static unsigned __stdcall worker(void *arg)
+{
+    ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg;
+    thread->arg = thread->start_routine(thread->arg);
+    return 0;
+}
+
+int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
+            void* (*start_routine) (void*), void* arg)
+{
+    (void)unused;
+    thread->arg = arg;
+    thread->start_routine = start_routine;
+    thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL);
+
+    if (!thread->handle)
+        return errno;
+    else
+        return 0;
+}
+
+int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr)
+{
+    DWORD result;
+
+    if (!thread.handle) return 0;
+
+    result = WaitForSingleObject(thread.handle, INFINITE);
+    switch (result) {
+    case WAIT_OBJECT_0:
+        if (value_ptr) *value_ptr = thread.arg;
+        return 0;
+    case WAIT_ABANDONED:
+        return EINVAL;
+    default:
+        return GetLastError();
+    }
+}
+
+#endif   /* ZSTD_MULTITHREAD */
diff --git a/Utilities/cmzstd/lib/common/threading.h b/Utilities/cmzstd/lib/common/threading.h
new file mode 100644
index 0000000..d806c89
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/threading.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2016 Tino Reichardt
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ *
+ * You can contact the author at:
+ * - zstdmt source repository: https://github.com/mcmilk/zstdmt
+ */
+
+#ifndef THREADING_H_938743
+#define THREADING_H_938743
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
+
+/**
+ * Windows minimalist Pthread Wrapper, based on :
+ * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
+ */
+#ifdef WINVER
+#  undef WINVER
+#endif
+#define WINVER       0x0600
+
+#ifdef _WIN32_WINNT
+#  undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0600
+
+#ifndef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#endif
+
+#undef ERROR   /* reported already defined on VS 2015 (Rich Geldreich) */
+#include <windows.h>
+#undef ERROR
+#define ERROR(name) ZSTD_ERROR(name)
+
+
+/* mutex */
+#define ZSTD_pthread_mutex_t           CRITICAL_SECTION
+#define ZSTD_pthread_mutex_init(a, b)  ((void)(b), InitializeCriticalSection((a)), 0)
+#define ZSTD_pthread_mutex_destroy(a)  DeleteCriticalSection((a))
+#define ZSTD_pthread_mutex_lock(a)     EnterCriticalSection((a))
+#define ZSTD_pthread_mutex_unlock(a)   LeaveCriticalSection((a))
+
+/* condition variable */
+#define ZSTD_pthread_cond_t             CONDITION_VARIABLE
+#define ZSTD_pthread_cond_init(a, b)    ((void)(b), InitializeConditionVariable((a)), 0)
+#define ZSTD_pthread_cond_destroy(a)    ((void)(a))
+#define ZSTD_pthread_cond_wait(a, b)    SleepConditionVariableCS((a), (b), INFINITE)
+#define ZSTD_pthread_cond_signal(a)     WakeConditionVariable((a))
+#define ZSTD_pthread_cond_broadcast(a)  WakeAllConditionVariable((a))
+
+/* ZSTD_pthread_create() and ZSTD_pthread_join() */
+typedef struct {
+    HANDLE handle;
+    void* (*start_routine)(void*);
+    void* arg;
+} ZSTD_pthread_t;
+
+int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
+                   void* (*start_routine) (void*), void* arg);
+
+int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
+
+/**
+ * add here more wrappers as required
+ */
+
+
+#elif defined(ZSTD_MULTITHREAD)   /* posix assumed ; need a better detection method */
+/* ===   POSIX Systems   === */
+#  include <pthread.h>
+
+#define ZSTD_pthread_mutex_t            pthread_mutex_t
+#define ZSTD_pthread_mutex_init(a, b)   pthread_mutex_init((a), (b))
+#define ZSTD_pthread_mutex_destroy(a)   pthread_mutex_destroy((a))
+#define ZSTD_pthread_mutex_lock(a)      pthread_mutex_lock((a))
+#define ZSTD_pthread_mutex_unlock(a)    pthread_mutex_unlock((a))
+
+#define ZSTD_pthread_cond_t             pthread_cond_t
+#define ZSTD_pthread_cond_init(a, b)    pthread_cond_init((a), (b))
+#define ZSTD_pthread_cond_destroy(a)    pthread_cond_destroy((a))
+#define ZSTD_pthread_cond_wait(a, b)    pthread_cond_wait((a), (b))
+#define ZSTD_pthread_cond_signal(a)     pthread_cond_signal((a))
+#define ZSTD_pthread_cond_broadcast(a)  pthread_cond_broadcast((a))
+
+#define ZSTD_pthread_t                  pthread_t
+#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
+#define ZSTD_pthread_join(a, b)         pthread_join((a),(b))
+
+#else  /* ZSTD_MULTITHREAD not defined */
+/* No multithreading support */
+
+typedef int ZSTD_pthread_mutex_t;
+#define ZSTD_pthread_mutex_init(a, b)   ((void)(a), (void)(b), 0)
+#define ZSTD_pthread_mutex_destroy(a)   ((void)(a))
+#define ZSTD_pthread_mutex_lock(a)      ((void)(a))
+#define ZSTD_pthread_mutex_unlock(a)    ((void)(a))
+
+typedef int ZSTD_pthread_cond_t;
+#define ZSTD_pthread_cond_init(a, b)    ((void)(a), (void)(b), 0)
+#define ZSTD_pthread_cond_destroy(a)    ((void)(a))
+#define ZSTD_pthread_cond_wait(a, b)    ((void)(a), (void)(b))
+#define ZSTD_pthread_cond_signal(a)     ((void)(a))
+#define ZSTD_pthread_cond_broadcast(a)  ((void)(a))
+
+/* do not use ZSTD_pthread_t */
+
+#endif /* ZSTD_MULTITHREAD */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* THREADING_H_938743 */
diff --git a/Utilities/cmzstd/lib/common/xxhash.c b/Utilities/cmzstd/lib/common/xxhash.c
new file mode 100644
index 0000000..532b816
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/xxhash.c
@@ -0,0 +1,876 @@
+/*
+*  xxHash - Fast Hash algorithm
+*  Copyright (C) 2012-2016, Yann Collet
+*
+*  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+*
+*  Redistribution and use in source and binary forms, with or without
+*  modification, are permitted provided that the following conditions are
+*  met:
+*
+*  * Redistributions of source code must retain the above copyright
+*  notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*  copyright notice, this list of conditions and the following disclaimer
+*  in the documentation and/or other materials provided with the
+*  distribution.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*  You can contact the author at :
+*  - xxHash homepage: http://www.xxhash.com
+*  - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+
+/* *************************************
+*  Tuning parameters
+***************************************/
+/*!XXH_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
+ *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
+ *            It can generate buggy code on targets which do not support unaligned memory accesses.
+ *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
+ * See http://stackoverflow.com/a/32095106/646947 for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef XXH_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
+#  if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+#    define XXH_FORCE_MEMORY_ACCESS 2
+#  elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
+  (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
+#    define XXH_FORCE_MEMORY_ACCESS 1
+#  endif
+#endif
+
+/*!XXH_ACCEPT_NULL_INPUT_POINTER :
+ * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
+ * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
+ * By default, this option is disabled. To enable it, uncomment below define :
+ */
+/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
+
+/*!XXH_FORCE_NATIVE_FORMAT :
+ * By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
+ * Results are therefore identical for little-endian and big-endian CPU.
+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
+ * Should endian-independance be of no importance for your application, you may set the #define below to 1,
+ * to improve speed for Big-endian CPU.
+ * This option has no impact on Little_Endian CPU.
+ */
+#ifndef XXH_FORCE_NATIVE_FORMAT   /* can be defined externally */
+#  define XXH_FORCE_NATIVE_FORMAT 0
+#endif
+
+/*!XXH_FORCE_ALIGN_CHECK :
+ * This is a minor performance trick, only useful with lots of very small keys.
+ * It means : check for aligned/unaligned input.
+ * The check costs one initial branch per hash; set to 0 when the input data
+ * is guaranteed to be aligned.
+ */
+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
+#  if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+#    define XXH_FORCE_ALIGN_CHECK 0
+#  else
+#    define XXH_FORCE_ALIGN_CHECK 1
+#  endif
+#endif
+
+
+/* *************************************
+*  Includes & Memory related functions
+***************************************/
+/* Modify the local functions below should you wish to use some other memory routines */
+/* for malloc(), free() */
+#include <stdlib.h>
+#include <stddef.h>     /* size_t */
+static void* XXH_malloc(size_t s) { return malloc(s); }
+static void  XXH_free  (void* p)  { free(p); }
+/* for memcpy() */
+#include <string.h>
+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
+
+#ifndef XXH_STATIC_LINKING_ONLY
+#  define XXH_STATIC_LINKING_ONLY
+#endif
+#include "xxhash.h"
+
+
+/* *************************************
+*  Compiler Specific Options
+***************************************/
+#if defined (__GNUC__) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */
+#  define INLINE_KEYWORD inline
+#else
+#  define INLINE_KEYWORD
+#endif
+
+#if defined(__GNUC__)
+#  define FORCE_INLINE_ATTR __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#  define FORCE_INLINE_ATTR __forceinline
+#else
+#  define FORCE_INLINE_ATTR
+#endif
+
+#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
+
+
+#ifdef _MSC_VER
+#  pragma warning(disable : 4127)      /* disable: C4127: conditional expression is constant */
+#endif
+
+
+/* *************************************
+*  Basic Types
+***************************************/
+#ifndef MEM_MODULE
+# define MEM_MODULE
+# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+#   include <stdint.h>
+    typedef uint8_t  BYTE;
+    typedef uint16_t U16;
+    typedef uint32_t U32;
+    typedef  int32_t S32;
+    typedef uint64_t U64;
+#  else
+    typedef unsigned char      BYTE;
+    typedef unsigned short     U16;
+    typedef unsigned int       U32;
+    typedef   signed int       S32;
+    typedef unsigned long long U64;   /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
+#  endif
+#endif
+
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign;
+
+static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
+static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
+
+#else
+
+/* portable and safe solution. Generally efficient.
+ * see : http://stackoverflow.com/a/32095106/646947
+ */
+
+static U32 XXH_read32(const void* memPtr)
+{
+    U32 val;
+    memcpy(&val, memPtr, sizeof(val));
+    return val;
+}
+
+static U64 XXH_read64(const void* memPtr)
+{
+    U64 val;
+    memcpy(&val, memPtr, sizeof(val));
+    return val;
+}
+
+#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+
+/* ****************************************
+*  Compiler-specific Functions and Macros
+******************************************/
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
+#if defined(_MSC_VER)
+#  define XXH_rotl32(x,r) _rotl(x,r)
+#  define XXH_rotl64(x,r) _rotl64(x,r)
+#else
+#  define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
+#  define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
+#endif
+
+#if defined(_MSC_VER)     /* Visual Studio */
+#  define XXH_swap32 _byteswap_ulong
+#  define XXH_swap64 _byteswap_uint64
+#elif GCC_VERSION >= 403
+#  define XXH_swap32 __builtin_bswap32
+#  define XXH_swap64 __builtin_bswap64
+#else
+static U32 XXH_swap32 (U32 x)
+{
+    return  ((x << 24) & 0xff000000 ) |
+            ((x <<  8) & 0x00ff0000 ) |
+            ((x >>  8) & 0x0000ff00 ) |
+            ((x >> 24) & 0x000000ff );
+}
+static U64 XXH_swap64 (U64 x)
+{
+    return  ((x << 56) & 0xff00000000000000ULL) |
+            ((x << 40) & 0x00ff000000000000ULL) |
+            ((x << 24) & 0x0000ff0000000000ULL) |
+            ((x << 8)  & 0x000000ff00000000ULL) |
+            ((x >> 8)  & 0x00000000ff000000ULL) |
+            ((x >> 24) & 0x0000000000ff0000ULL) |
+            ((x >> 40) & 0x000000000000ff00ULL) |
+            ((x >> 56) & 0x00000000000000ffULL);
+}
+#endif
+
+
+/* *************************************
+*  Architecture Macros
+***************************************/
+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+
+/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
+#ifndef XXH_CPU_LITTLE_ENDIAN
+    static const int g_one = 1;
+#   define XXH_CPU_LITTLE_ENDIAN   (*(const char*)(&g_one))
+#endif
+
+
+/* ***************************
+*  Memory reads
+*****************************/
+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
+
+FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+    if (align==XXH_unaligned)
+        return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
+    else
+        return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
+}
+
+FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
+{
+    return XXH_readLE32_align(ptr, endian, XXH_unaligned);
+}
+
+static U32 XXH_readBE32(const void* ptr)
+{
+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+    if (align==XXH_unaligned)
+        return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
+    else
+        return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
+{
+    return XXH_readLE64_align(ptr, endian, XXH_unaligned);
+}
+
+static U64 XXH_readBE64(const void* ptr)
+{
+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
+}
+
+
+/* *************************************
+*  Macros
+***************************************/
+#define XXH_STATIC_ASSERT(c)   { enum { XXH_static_assert = 1/(int)(!!(c)) }; }    /* use only *after* variable declarations */
+
+
+/* *************************************
+*  Constants
+***************************************/
+static const U32 PRIME32_1 = 2654435761U;
+static const U32 PRIME32_2 = 2246822519U;
+static const U32 PRIME32_3 = 3266489917U;
+static const U32 PRIME32_4 =  668265263U;
+static const U32 PRIME32_5 =  374761393U;
+
+static const U64 PRIME64_1 = 11400714785074694791ULL;
+static const U64 PRIME64_2 = 14029467366897019727ULL;
+static const U64 PRIME64_3 =  1609587929392839161ULL;
+static const U64 PRIME64_4 =  9650029242287828579ULL;
+static const U64 PRIME64_5 =  2870177450012600261ULL;
+
+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
+
+
+/* **************************
+*  Utils
+****************************/
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState)
+{
+    memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState)
+{
+    memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+
+/* ***************************
+*  Simple Hash Functions
+*****************************/
+
+static U32 XXH32_round(U32 seed, U32 input)
+{
+    seed += input * PRIME32_2;
+    seed  = XXH_rotl32(seed, 13);
+    seed *= PRIME32_1;
+    return seed;
+}
+
+FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
+{
+    const BYTE* p = (const BYTE*)input;
+    const BYTE* bEnd = p + len;
+    U32 h32;
+#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+    if (p==NULL) {
+        len=0;
+        bEnd=p=(const BYTE*)(size_t)16;
+    }
+#endif
+
+    if (len>=16) {
+        const BYTE* const limit = bEnd - 16;
+        U32 v1 = seed + PRIME32_1 + PRIME32_2;
+        U32 v2 = seed + PRIME32_2;
+        U32 v3 = seed + 0;
+        U32 v4 = seed - PRIME32_1;
+
+        do {
+            v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
+            v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
+            v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
+            v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
+        } while (p<=limit);
+
+        h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+    } else {
+        h32  = seed + PRIME32_5;
+    }
+
+    h32 += (U32) len;
+
+    while (p+4<=bEnd) {
+        h32 += XXH_get32bits(p) * PRIME32_3;
+        h32  = XXH_rotl32(h32, 17) * PRIME32_4 ;
+        p+=4;
+    }
+
+    while (p<bEnd) {
+        h32 += (*p) * PRIME32_5;
+        h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
+        p++;
+    }
+
+    h32 ^= h32 >> 15;
+    h32 *= PRIME32_2;
+    h32 ^= h32 >> 13;
+    h32 *= PRIME32_3;
+    h32 ^= h32 >> 16;
+
+    return h32;
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
+{
+#if 0
+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+    XXH32_CREATESTATE_STATIC(state);
+    XXH32_reset(state, seed);
+    XXH32_update(state, input, len);
+    return XXH32_digest(state);
+#else
+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+    if (XXH_FORCE_ALIGN_CHECK) {
+        if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */
+            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+                return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+            else
+                return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+    }   }
+
+    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+        return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+    else
+        return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+static U64 XXH64_round(U64 acc, U64 input)
+{
+    acc += input * PRIME64_2;
+    acc  = XXH_rotl64(acc, 31);
+    acc *= PRIME64_1;
+    return acc;
+}
+
+static U64 XXH64_mergeRound(U64 acc, U64 val)
+{
+    val  = XXH64_round(0, val);
+    acc ^= val;
+    acc  = acc * PRIME64_1 + PRIME64_4;
+    return acc;
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
+{
+    const BYTE* p = (const BYTE*)input;
+    const BYTE* const bEnd = p + len;
+    U64 h64;
+#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+    if (p==NULL) {
+        len=0;
+        bEnd=p=(const BYTE*)(size_t)32;
+    }
+#endif
+
+    if (len>=32) {
+        const BYTE* const limit = bEnd - 32;
+        U64 v1 = seed + PRIME64_1 + PRIME64_2;
+        U64 v2 = seed + PRIME64_2;
+        U64 v3 = seed + 0;
+        U64 v4 = seed - PRIME64_1;
+
+        do {
+            v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
+            v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
+            v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
+            v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
+        } while (p<=limit);
+
+        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+        h64 = XXH64_mergeRound(h64, v1);
+        h64 = XXH64_mergeRound(h64, v2);
+        h64 = XXH64_mergeRound(h64, v3);
+        h64 = XXH64_mergeRound(h64, v4);
+
+    } else {
+        h64  = seed + PRIME64_5;
+    }
+
+    h64 += (U64) len;
+
+    while (p+8<=bEnd) {
+        U64 const k1 = XXH64_round(0, XXH_get64bits(p));
+        h64 ^= k1;
+        h64  = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
+        p+=8;
+    }
+
+    if (p+4<=bEnd) {
+        h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
+        h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+        p+=4;
+    }
+
+    while (p<bEnd) {
+        h64 ^= (*p) * PRIME64_5;
+        h64 = XXH_rotl64(h64, 11) * PRIME64_1;
+        p++;
+    }
+
+    h64 ^= h64 >> 33;
+    h64 *= PRIME64_2;
+    h64 ^= h64 >> 29;
+    h64 *= PRIME64_3;
+    h64 ^= h64 >> 32;
+
+    return h64;
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
+{
+#if 0
+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+    XXH64_CREATESTATE_STATIC(state);
+    XXH64_reset(state, seed);
+    XXH64_update(state, input, len);
+    return XXH64_digest(state);
+#else
+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+    if (XXH_FORCE_ALIGN_CHECK) {
+        if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */
+            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+                return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+            else
+                return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+    }   }
+
+    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+        return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+    else
+        return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+/* **************************************************
+*  Advanced Hash Functions
+****************************************************/
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
+{
+    return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
+{
+    XXH_free(statePtr);
+    return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
+{
+    return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
+{
+    XXH_free(statePtr);
+    return XXH_OK;
+}
+
+
+/*** Hash feed ***/
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
+{
+    XXH32_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+    memset(&state, 0, sizeof(state)-4);   /* do not write into reserved, for future removal */
+    state.v1 = seed + PRIME32_1 + PRIME32_2;
+    state.v2 = seed + PRIME32_2;
+    state.v3 = seed + 0;
+    state.v4 = seed - PRIME32_1;
+    memcpy(statePtr, &state, sizeof(state));
+    return XXH_OK;
+}
+
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
+{
+    XXH64_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+    memset(&state, 0, sizeof(state)-8);   /* do not write into reserved, for future removal */
+    state.v1 = seed + PRIME64_1 + PRIME64_2;
+    state.v2 = seed + PRIME64_2;
+    state.v3 = seed + 0;
+    state.v4 = seed - PRIME64_1;
+    memcpy(statePtr, &state, sizeof(state));
+    return XXH_OK;
+}
+
+
+FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+    const BYTE* p = (const BYTE*)input;
+    const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+    if (input==NULL) return XXH_ERROR;
+#endif
+
+    state->total_len_32 += (unsigned)len;
+    state->large_len |= (len>=16) | (state->total_len_32>=16);
+
+    if (state->memsize + len < 16)  {   /* fill in tmp buffer */
+        XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
+        state->memsize += (unsigned)len;
+        return XXH_OK;
+    }
+
+    if (state->memsize) {   /* some data left from previous update */
+        XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
+        {   const U32* p32 = state->mem32;
+            state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
+            state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
+            state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
+            state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
+        }
+        p += 16-state->memsize;
+        state->memsize = 0;
+    }
+
+    if (p <= bEnd-16) {
+        const BYTE* const limit = bEnd - 16;
+        U32 v1 = state->v1;
+        U32 v2 = state->v2;
+        U32 v3 = state->v3;
+        U32 v4 = state->v4;
+
+        do {
+            v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
+            v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
+            v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
+            v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
+        } while (p<=limit);
+
+        state->v1 = v1;
+        state->v2 = v2;
+        state->v3 = v3;
+        state->v4 = v4;
+    }
+
+    if (p < bEnd) {
+        XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
+        state->memsize = (unsigned)(bEnd-p);
+    }
+
+    return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
+{
+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+        return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
+    else
+        return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
+{
+    const BYTE * p = (const BYTE*)state->mem32;
+    const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
+    U32 h32;
+
+    if (state->large_len) {
+        h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
+    } else {
+        h32 = state->v3 /* == seed */ + PRIME32_5;
+    }
+
+    h32 += state->total_len_32;
+
+    while (p+4<=bEnd) {
+        h32 += XXH_readLE32(p, endian) * PRIME32_3;
+        h32  = XXH_rotl32(h32, 17) * PRIME32_4;
+        p+=4;
+    }
+
+    while (p<bEnd) {
+        h32 += (*p) * PRIME32_5;
+        h32  = XXH_rotl32(h32, 11) * PRIME32_1;
+        p++;
+    }
+
+    h32 ^= h32 >> 15;
+    h32 *= PRIME32_2;
+    h32 ^= h32 >> 13;
+    h32 *= PRIME32_3;
+    h32 ^= h32 >> 16;
+
+    return h32;
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
+{
+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+        return XXH32_digest_endian(state_in, XXH_littleEndian);
+    else
+        return XXH32_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+
+/* **** XXH64 **** */
+
+FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+    const BYTE* p = (const BYTE*)input;
+    const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+    if (input==NULL) return XXH_ERROR;
+#endif
+
+    state->total_len += len;
+
+    if (state->memsize + len < 32) {  /* fill in tmp buffer */
+        XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
+        state->memsize += (U32)len;
+        return XXH_OK;
+    }
+
+    if (state->memsize) {   /* tmp buffer is full */
+        XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
+        state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
+        state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
+        state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
+        state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
+        p += 32-state->memsize;
+        state->memsize = 0;
+    }
+
+    if (p+32 <= bEnd) {
+        const BYTE* const limit = bEnd - 32;
+        U64 v1 = state->v1;
+        U64 v2 = state->v2;
+        U64 v3 = state->v3;
+        U64 v4 = state->v4;
+
+        do {
+            v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
+            v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
+            v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
+            v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
+        } while (p<=limit);
+
+        state->v1 = v1;
+        state->v2 = v2;
+        state->v3 = v3;
+        state->v4 = v4;
+    }
+
+    if (p < bEnd) {
+        XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
+        state->memsize = (unsigned)(bEnd-p);
+    }
+
+    return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
+{
+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+        return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
+    else
+        return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
+{
+    const BYTE * p = (const BYTE*)state->mem64;
+    const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
+    U64 h64;
+
+    if (state->total_len >= 32) {
+        U64 const v1 = state->v1;
+        U64 const v2 = state->v2;
+        U64 const v3 = state->v3;
+        U64 const v4 = state->v4;
+
+        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+        h64 = XXH64_mergeRound(h64, v1);
+        h64 = XXH64_mergeRound(h64, v2);
+        h64 = XXH64_mergeRound(h64, v3);
+        h64 = XXH64_mergeRound(h64, v4);
+    } else {
+        h64  = state->v3 + PRIME64_5;
+    }
+
+    h64 += (U64) state->total_len;
+
+    while (p+8<=bEnd) {
+        U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
+        h64 ^= k1;
+        h64  = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
+        p+=8;
+    }
+
+    if (p+4<=bEnd) {
+        h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
+        h64  = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+        p+=4;
+    }
+
+    while (p<bEnd) {
+        h64 ^= (*p) * PRIME64_5;
+        h64  = XXH_rotl64(h64, 11) * PRIME64_1;
+        p++;
+    }
+
+    h64 ^= h64 >> 33;
+    h64 *= PRIME64_2;
+    h64 ^= h64 >> 29;
+    h64 *= PRIME64_3;
+    h64 ^= h64 >> 32;
+
+    return h64;
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
+{
+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+        return XXH64_digest_endian(state_in, XXH_littleEndian);
+    else
+        return XXH64_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+/* **************************
+*  Canonical representation
+****************************/
+
+/*! Default XXH result types are basic unsigned 32 and 64 bits.
+*   The canonical representation follows human-readable write convention, aka big-endian (large digits first).
+*   These functions allow transformation of hash result into and from its canonical format.
+*   This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
+*/
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
+{
+    XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
+    memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
+{
+    XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
+    memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
+{
+    return XXH_readBE32(src);
+}
+
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
+{
+    return XXH_readBE64(src);
+}
diff --git a/Utilities/cmzstd/lib/common/xxhash.h b/Utilities/cmzstd/lib/common/xxhash.h
new file mode 100644
index 0000000..9bad1f5
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/xxhash.h
@@ -0,0 +1,305 @@
+/*
+   xxHash - Extremely Fast Hash algorithm
+   Header File
+   Copyright (C) 2012-2016, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+/* Notice extracted from xxHash homepage :
+
+xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
+It also successfully passes all tests from the SMHasher suite.
+
+Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
+
+Name            Speed       Q.Score   Author
+xxHash          5.4 GB/s     10
+CrapWow         3.2 GB/s      2       Andrew
+MumurHash 3a    2.7 GB/s     10       Austin Appleby
+SpookyHash      2.0 GB/s     10       Bob Jenkins
+SBox            1.4 GB/s      9       Bret Mulvey
+Lookup3         1.2 GB/s      9       Bob Jenkins
+SuperFastHash   1.2 GB/s      1       Paul Hsieh
+CityHash64      1.05 GB/s    10       Pike & Alakuijala
+FNV             0.55 GB/s     5       Fowler, Noll, Vo
+CRC32           0.43 GB/s     9
+MD5-32          0.33 GB/s    10       Ronald L. Rivest
+SHA1-32         0.28 GB/s    10
+
+Q.Score is a measure of quality of the hash function.
+It depends on successfully passing SMHasher test set.
+10 is a perfect score.
+
+A 64-bits version, named XXH64, is available since r35.
+It offers much better speed, but for 64-bits applications only.
+Name     Speed on 64 bits    Speed on 32 bits
+XXH64       13.8 GB/s            1.9 GB/s
+XXH32        6.8 GB/s            6.0 GB/s
+*/
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef XXHASH_H_5627135585666179
+#define XXHASH_H_5627135585666179 1
+
+
+/* ****************************
+*  Definitions
+******************************/
+#include <stddef.h>   /* size_t */
+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+
+
+/* ****************************
+*  API modifier
+******************************/
+/** XXH_PRIVATE_API
+*   This is useful if you want to include xxhash functions in `static` mode
+*   in order to inline them, and remove their symbol from the public list.
+*   Methodology :
+*     #define XXH_PRIVATE_API
+*     #include "xxhash.h"
+*   `xxhash.c` is automatically included.
+*   It's not useful to compile and link it as a separate module anymore.
+*/
+#ifdef XXH_PRIVATE_API
+#  ifndef XXH_STATIC_LINKING_ONLY
+#    define XXH_STATIC_LINKING_ONLY
+#  endif
+#  if defined(__GNUC__)
+#    define XXH_PUBLIC_API static __inline __attribute__((unused))
+#  elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+#    define XXH_PUBLIC_API static inline
+#  elif defined(_MSC_VER)
+#    define XXH_PUBLIC_API static __inline
+#  else
+#    define XXH_PUBLIC_API static   /* this version may generate warnings for unused static functions; disable the relevant warning */
+#  endif
+#else
+#  define XXH_PUBLIC_API   /* do nothing */
+#endif /* XXH_PRIVATE_API */
+
+/*!XXH_NAMESPACE, aka Namespace Emulation :
+
+If you want to include _and expose_ xxHash functions from within your own library,
+but also want to avoid symbol collisions with another library which also includes xxHash,
+
+you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
+with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
+
+Note that no change is required within the calling program as long as it includes `xxhash.h` :
+regular symbol name will be automatically translated by this header.
+*/
+#ifdef XXH_NAMESPACE
+#  define XXH_CAT(A,B) A##B
+#  define XXH_NAME2(A,B) XXH_CAT(A,B)
+#  define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
+#  define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
+#  define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
+#  define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
+#  define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
+#  define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
+#  define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
+#  define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
+#  define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
+#  define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
+#  define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
+#  define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
+#  define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
+#  define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
+#  define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
+#  define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
+#  define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
+#  define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
+#  define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
+#endif
+
+
+/* *************************************
+*  Version
+***************************************/
+#define XXH_VERSION_MAJOR    0
+#define XXH_VERSION_MINOR    6
+#define XXH_VERSION_RELEASE  2
+#define XXH_VERSION_NUMBER  (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
+XXH_PUBLIC_API unsigned XXH_versionNumber (void);
+
+
+/* ****************************
+*  Simple Hash Functions
+******************************/
+typedef unsigned int       XXH32_hash_t;
+typedef unsigned long long XXH64_hash_t;
+
+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
+
+/*!
+XXH32() :
+    Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
+    The memory between input & input+length must be valid (allocated and read-accessible).
+    "seed" can be used to alter the result predictably.
+    Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
+XXH64() :
+    Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
+    "seed" can be used to alter the result predictably.
+    This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
+*/
+
+
+/* ****************************
+*  Streaming Hash Functions
+******************************/
+typedef struct XXH32_state_s XXH32_state_t;   /* incomplete type */
+typedef struct XXH64_state_s XXH64_state_t;   /* incomplete type */
+
+/*! State allocation, compatible with dynamic libraries */
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
+XXH_PUBLIC_API XXH_errorcode  XXH32_freeState(XXH32_state_t* statePtr);
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
+XXH_PUBLIC_API XXH_errorcode  XXH64_freeState(XXH64_state_t* statePtr);
+
+
+/* hash streaming */
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset  (XXH32_state_t* statePtr, unsigned int seed);
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH32_hash_t  XXH32_digest (const XXH32_state_t* statePtr);
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset  (XXH64_state_t* statePtr, unsigned long long seed);
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t  XXH64_digest (const XXH64_state_t* statePtr);
+
+/*
+These functions generate the xxHash of an input provided in multiple segments.
+Note that, for small input, they are slower than single-call functions, due to state management.
+For small input, prefer `XXH32()` and `XXH64()` .
+
+XXH state must first be allocated, using XXH*_createState() .
+
+Start a new hash by initializing state with a seed, using XXH*_reset().
+
+Then, feed the hash state by calling XXH*_update() as many times as necessary.
+Obviously, input must be allocated and read accessible.
+The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
+
+Finally, a hash value can be produced anytime, by using XXH*_digest().
+This function returns the nn-bits hash as an int or long long.
+
+It's still possible to continue inserting input into the hash state after a digest,
+and generate some new hashes later on, by calling again XXH*_digest().
+
+When done, free XXH state space if it was allocated dynamically.
+*/
+
+
+/* **************************
+*  Utils
+****************************/
+#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))   /* ! C99 */
+#  define restrict   /* disable restrict */
+#endif
+
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state);
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state);
+
+
+/* **************************
+*  Canonical representation
+****************************/
+/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
+*  The canonical representation uses human-readable write convention, aka big-endian (large digits first).
+*  These functions allow transformation of hash result into and from its canonical format.
+*  This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
+*/
+typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
+typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
+
+#endif /* XXHASH_H_5627135585666179 */
+
+
+
+/* ================================================================================================
+   This section contains definitions which are not guaranteed to remain stable.
+   They may change in future versions, becoming incompatible with a different version of the library.
+   They shall only be used with static linking.
+   Never use these definitions in association with dynamic linking !
+=================================================================================================== */
+#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345)
+#define XXH_STATIC_H_3543687687345
+
+/* These definitions are only meant to allow allocation of XXH state
+   statically, on stack, or in a struct for example.
+   Do not use members directly. */
+
+   struct XXH32_state_s {
+       unsigned total_len_32;
+       unsigned large_len;
+       unsigned v1;
+       unsigned v2;
+       unsigned v3;
+       unsigned v4;
+       unsigned mem32[4];   /* buffer defined as U32 for alignment */
+       unsigned memsize;
+       unsigned reserved;   /* never read nor write, will be removed in a future version */
+   };   /* typedef'd to XXH32_state_t */
+
+   struct XXH64_state_s {
+       unsigned long long total_len;
+       unsigned long long v1;
+       unsigned long long v2;
+       unsigned long long v3;
+       unsigned long long v4;
+       unsigned long long mem64[4];   /* buffer defined as U64 for alignment */
+       unsigned memsize;
+       unsigned reserved[2];          /* never read nor write, will be removed in a future version */
+   };   /* typedef'd to XXH64_state_t */
+
+
+#  ifdef XXH_PRIVATE_API
+#    include "xxhash.c"   /* include xxhash functions as `static`, for inlining */
+#  endif
+
+#endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/common/zstd_common.c b/Utilities/cmzstd/lib/common/zstd_common.c
new file mode 100644
index 0000000..667f4a2
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/zstd_common.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include <stdlib.h>      /* malloc, calloc, free */
+#include <string.h>      /* memset */
+#include "error_private.h"
+#include "zstd_internal.h"
+
+
+/*-****************************************
+*  Version
+******************************************/
+unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; }
+
+const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
+
+
+/*-****************************************
+*  ZSTD Error Management
+******************************************/
+#undef ZSTD_isError   /* defined within zstd_internal.h */
+/*! ZSTD_isError() :
+ *  tells if a return value is an error code
+ *  symbol is required for external callers */
+unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
+
+/*! ZSTD_getErrorName() :
+ *  provides error code string from function result (useful for debugging) */
+const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+/*! ZSTD_getError() :
+ *  convert a `size_t` function result into a proper ZSTD_errorCode enum */
+ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
+
+/*! ZSTD_getErrorString() :
+ *  provides error code string from enum */
+const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
+
+
+
+/*=**************************************************************
+*  Custom allocator
+****************************************************************/
+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
+{
+    if (customMem.customAlloc)
+        return customMem.customAlloc(customMem.opaque, size);
+    return malloc(size);
+}
+
+void* ZSTD_calloc(size_t size, ZSTD_customMem customMem)
+{
+    if (customMem.customAlloc) {
+        /* calloc implemented as malloc+memset;
+         * not as efficient as calloc, but next best guess for custom malloc */
+        void* const ptr = customMem.customAlloc(customMem.opaque, size);
+        memset(ptr, 0, size);
+        return ptr;
+    }
+    return calloc(1, size);
+}
+
+void ZSTD_free(void* ptr, ZSTD_customMem customMem)
+{
+    if (ptr!=NULL) {
+        if (customMem.customFree)
+            customMem.customFree(customMem.opaque, ptr);
+        else
+            free(ptr);
+    }
+}
diff --git a/Utilities/cmzstd/lib/common/zstd_errors.h b/Utilities/cmzstd/lib/common/zstd_errors.h
new file mode 100644
index 0000000..92a3433
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/zstd_errors.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_ERRORS_H_398273423
+#define ZSTD_ERRORS_H_398273423
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*===== dependency =====*/
+#include <stddef.h>   /* size_t */
+
+
+/* =====   ZSTDERRORLIB_API : control library symbols visibility   ===== */
+#ifndef ZSTDERRORLIB_VISIBILITY
+#  if defined(__GNUC__) && (__GNUC__ >= 4)
+#    define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default")))
+#  else
+#    define ZSTDERRORLIB_VISIBILITY
+#  endif
+#endif
+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
+#  define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY
+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
+#  define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+#  define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
+#endif
+
+/*-*********************************************
+ *  Error codes list
+ *-*********************************************
+ *  Error codes _values_ are pinned down since v1.3.1 only.
+ *  Therefore, don't rely on values if you may link to any version < v1.3.1.
+ *
+ *  Only values < 100 are considered stable.
+ *
+ *  note 1 : this API shall be used with static linking only.
+ *           dynamic linking is not yet officially supported.
+ *  note 2 : Prefer relying on the enum than on its value whenever possible
+ *           This is the only supported way to use the error list < v1.3.1
+ *  note 3 : ZSTD_isError() is always correct, whatever the library version.
+ **********************************************/
+typedef enum {
+  ZSTD_error_no_error = 0,
+  ZSTD_error_GENERIC  = 1,
+  ZSTD_error_prefix_unknown                = 10,
+  ZSTD_error_version_unsupported           = 12,
+  ZSTD_error_frameParameter_unsupported    = 14,
+  ZSTD_error_frameParameter_windowTooLarge = 16,
+  ZSTD_error_corruption_detected = 20,
+  ZSTD_error_checksum_wrong      = 22,
+  ZSTD_error_dictionary_corrupted      = 30,
+  ZSTD_error_dictionary_wrong          = 32,
+  ZSTD_error_dictionaryCreation_failed = 34,
+  ZSTD_error_parameter_unsupported   = 40,
+  ZSTD_error_parameter_outOfBound    = 42,
+  ZSTD_error_tableLog_tooLarge       = 44,
+  ZSTD_error_maxSymbolValue_tooLarge = 46,
+  ZSTD_error_maxSymbolValue_tooSmall = 48,
+  ZSTD_error_stage_wrong       = 60,
+  ZSTD_error_init_missing      = 62,
+  ZSTD_error_memory_allocation = 64,
+  ZSTD_error_workSpace_tooSmall= 66,
+  ZSTD_error_dstSize_tooSmall = 70,
+  ZSTD_error_srcSize_wrong    = 72,
+  ZSTD_error_dstBuffer_null   = 74,
+  /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
+  ZSTD_error_frameIndex_tooLarge = 100,
+  ZSTD_error_seekableIO          = 102,
+  ZSTD_error_maxCode = 120  /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
+} ZSTD_ErrorCode;
+
+/*! ZSTD_getErrorCode() :
+    convert a `size_t` function result into a `ZSTD_ErrorCode` enum type,
+    which can be used to compare with enum list published above */
+ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult);
+ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code);   /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_ERRORS_H_398273423 */
diff --git a/Utilities/cmzstd/lib/common/zstd_internal.h b/Utilities/cmzstd/lib/common/zstd_internal.h
new file mode 100644
index 0000000..edeb74b
--- /dev/null
+++ b/Utilities/cmzstd/lib/common/zstd_internal.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_CCOMMON_H_MODULE
+#define ZSTD_CCOMMON_H_MODULE
+
+/* this module contains definitions which must be identical
+ * across compression, decompression and dictBuilder.
+ * It also contains a few functions useful to at least 2 of them
+ * and which benefit from being inlined */
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include "compiler.h"
+#include "mem.h"
+#include "debug.h"                 /* assert, DEBUGLOG, RAWLOG, g_debuglevel */
+#include "error_private.h"
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#ifndef XXH_STATIC_LINKING_ONLY
+#  define XXH_STATIC_LINKING_ONLY  /* XXH64_state_t */
+#endif
+#include "xxhash.h"                /* XXH_reset, update, digest */
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* ---- static assert (debug) --- */
+#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
+#define ZSTD_isError ERR_isError   /* for inlining */
+#define FSE_isError  ERR_isError
+#define HUF_isError  ERR_isError
+
+
+/*-*************************************
+*  shared macros
+***************************************/
+#undef MIN
+#undef MAX
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; }  /* check and Forward error code */
+#define CHECK_E(f, e) { size_t const errcod = f; if (ERR_isError(errcod)) return ERROR(e); }  /* check and send Error code */
+
+
+/*-*************************************
+*  Common constants
+***************************************/
+#define ZSTD_OPT_NUM    (1<<12)
+
+#define ZSTD_REP_NUM      3                 /* number of repcodes */
+#define ZSTD_REP_MOVE     (ZSTD_REP_NUM-1)
+static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define BIT7 128
+#define BIT6  64
+#define BIT5  32
+#define BIT4  16
+#define BIT1   2
+#define BIT0   1
+
+#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
+static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
+static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
+
+#define ZSTD_FRAMEIDSIZE 4   /* magic number size */
+
+#define ZSTD_BLOCKHEADERSIZE 3   /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
+static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
+typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
+
+#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
+#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */)   /* for a non-null block */
+
+#define HufLog 12
+typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
+
+#define LONGNBSEQ 0x7F00
+
+#define MINMATCH 3
+
+#define Litbits  8
+#define MaxLit ((1<<Litbits) - 1)
+#define MaxML   52
+#define MaxLL   35
+#define DefaultMaxOff 28
+#define MaxOff  31
+#define MaxSeq MAX(MaxLL, MaxML)   /* Assumption : MaxOff < MaxLL,MaxML */
+#define MLFSELog    9
+#define LLFSELog    9
+#define OffFSELog   8
+#define MaxFSELog  MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
+
+static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
+                                      0, 0, 0, 0, 0, 0, 0, 0,
+                                      1, 1, 1, 1, 2, 2, 3, 3,
+                                      4, 6, 7, 8, 9,10,11,12,
+                                     13,14,15,16 };
+static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2,
+                                             2, 2, 2, 2, 2, 1, 1, 1,
+                                             2, 2, 2, 2, 2, 2, 2, 2,
+                                             2, 3, 2, 1, 1, 1, 1, 1,
+                                            -1,-1,-1,-1 };
+#define LL_DEFAULTNORMLOG 6  /* for static allocation */
+static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
+
+static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
+                                      0, 0, 0, 0, 0, 0, 0, 0,
+                                      0, 0, 0, 0, 0, 0, 0, 0,
+                                      0, 0, 0, 0, 0, 0, 0, 0,
+                                      1, 1, 1, 1, 2, 2, 3, 3,
+                                      4, 4, 5, 7, 8, 9,10,11,
+                                     12,13,14,15,16 };
+static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2,
+                                             2, 1, 1, 1, 1, 1, 1, 1,
+                                             1, 1, 1, 1, 1, 1, 1, 1,
+                                             1, 1, 1, 1, 1, 1, 1, 1,
+                                             1, 1, 1, 1, 1, 1, 1, 1,
+                                             1, 1, 1, 1, 1, 1,-1,-1,
+                                            -1,-1,-1,-1,-1 };
+#define ML_DEFAULTNORMLOG 6  /* for static allocation */
+static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
+
+static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2,
+                                                     2, 1, 1, 1, 1, 1, 1, 1,
+                                                     1, 1, 1, 1, 1, 1, 1, 1,
+                                                    -1,-1,-1,-1,-1 };
+#define OF_DEFAULTNORMLOG 5  /* for static allocation */
+static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
+
+
+/*-*******************************************
+*  Shared functions to include for inlining
+*********************************************/
+static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
+#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
+
+/*! ZSTD_wildcopy() :
+ *  custom version of memcpy(), can overwrite up to WILDCOPY_OVERLENGTH bytes (if length==0) */
+#define WILDCOPY_OVERLENGTH 8
+MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
+{
+    const BYTE* ip = (const BYTE*)src;
+    BYTE* op = (BYTE*)dst;
+    BYTE* const oend = op + length;
+    do
+        COPY8(op, ip)
+    while (op < oend);
+}
+
+MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd)   /* should be faster for decoding, but strangely, not verified on all platform */
+{
+    const BYTE* ip = (const BYTE*)src;
+    BYTE* op = (BYTE*)dst;
+    BYTE* const oend = (BYTE*)dstEnd;
+    do
+        COPY8(op, ip)
+    while (op < oend);
+}
+
+
+/*-*******************************************
+*  Private declarations
+*********************************************/
+typedef struct seqDef_s {
+    U32 offset;
+    U16 litLength;
+    U16 matchLength;
+} seqDef;
+
+typedef struct {
+    seqDef* sequencesStart;
+    seqDef* sequences;
+    BYTE* litStart;
+    BYTE* lit;
+    BYTE* llCode;
+    BYTE* mlCode;
+    BYTE* ofCode;
+    size_t maxNbSeq;
+    size_t maxNbLit;
+    U32   longLengthID;   /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
+    U32   longLengthPos;
+} seqStore_t;
+
+const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);   /* compress & dictBuilder */
+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);   /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
+
+/* custom memory allocation functions */
+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
+void* ZSTD_calloc(size_t size, ZSTD_customMem customMem);
+void ZSTD_free(void* ptr, ZSTD_customMem customMem);
+
+
+MEM_STATIC U32 ZSTD_highbit32(U32 val)   /* compress, dictBuilder, decodeCorpus */
+{
+    assert(val != 0);
+    {
+#   if defined(_MSC_VER)   /* Visual */
+        unsigned long r=0;
+        _BitScanReverse(&r, val);
+        return (unsigned)r;
+#   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* GCC Intrinsic */
+        return 31 - __builtin_clz(val);
+#   else   /* Software version */
+        static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
+        U32 v = val;
+        v |= v >> 1;
+        v |= v >> 2;
+        v |= v >> 4;
+        v |= v >> 8;
+        v |= v >> 16;
+        return DeBruijnClz[(v * 0x07C4ACDDU) >> 27];
+#   endif
+    }
+}
+
+
+/* ZSTD_invalidateRepCodes() :
+ * ensures next compression will not use repcodes from previous block.
+ * Note : only works with regular variant;
+ *        do not use with extDict variant ! */
+void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx);   /* zstdmt, adaptive_compression (shouldn't get this definition from here) */
+
+
+typedef struct {
+    blockType_e blockType;
+    U32 lastBlock;
+    U32 origSize;
+} blockProperties_t;   /* declared here for decompress and fullbench */
+
+/*! ZSTD_getcBlockSize() :
+ *  Provides the size of compressed block from block header `src` */
+/* Used by: decompress, fullbench (does not get its definition from here) */
+size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
+                          blockProperties_t* bpPtr);
+
+/*! ZSTD_decodeSeqHeaders() :
+ *  decode sequence header from src */
+/* Used by: decompress, fullbench (does not get its definition from here) */
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
+                       const void* src, size_t srcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif   /* ZSTD_CCOMMON_H_MODULE */
diff --git a/Utilities/cmzstd/lib/compress/fse_compress.c b/Utilities/cmzstd/lib/compress/fse_compress.c
new file mode 100644
index 0000000..60f357b
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/fse_compress.c
@@ -0,0 +1,721 @@
+/* ******************************************************************
+   FSE : Finite State Entropy encoder
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+    - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* **************************************************************
+*  Includes
+****************************************************************/
+#include <stdlib.h>     /* malloc, free, qsort */
+#include <string.h>     /* memcpy, memset */
+#include "compiler.h"
+#include "mem.h"        /* U32, U16, etc. */
+#include "debug.h"      /* assert, DEBUGLOG */
+#include "hist.h"       /* HIST_count_wksp */
+#include "bitstream.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+*  Error Management
+****************************************************************/
+#define FSE_isError ERR_isError
+
+
+/* **************************************************************
+*  Templates
+****************************************************************/
+/*
+  designed to be included
+  for type-specific functions (template emulation in C)
+  Objective is to write these functions only once, for improved maintenance
+*/
+
+/* safety checks */
+#ifndef FSE_FUNCTION_EXTENSION
+#  error "FSE_FUNCTION_EXTENSION must be defined"
+#endif
+#ifndef FSE_FUNCTION_TYPE
+#  error "FSE_FUNCTION_TYPE must be defined"
+#endif
+
+/* Function names */
+#define FSE_CAT(X,Y) X##Y
+#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
+#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
+
+
+/* Function templates */
+
+/* FSE_buildCTable_wksp() :
+ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
+ * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
+ * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable* ct,
+                      const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+                            void* workSpace, size_t wkspSize)
+{
+    U32 const tableSize = 1 << tableLog;
+    U32 const tableMask = tableSize - 1;
+    void* const ptr = ct;
+    U16* const tableU16 = ( (U16*) ptr) + 2;
+    void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
+    FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+    U32 const step = FSE_TABLESTEP(tableSize);
+    U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
+
+    FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
+    U32 highThreshold = tableSize-1;
+
+    /* CTable header */
+    if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
+    tableU16[-2] = (U16) tableLog;
+    tableU16[-1] = (U16) maxSymbolValue;
+    assert(tableLog < 16);   /* required for threshold strategy to work */
+
+    /* For explanations on how to distribute symbol values over the table :
+     * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
+
+     #ifdef __clang_analyzer__
+     memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize);   /* useless initialization, just to keep scan-build happy */
+     #endif
+
+    /* symbol start positions */
+    {   U32 u;
+        cumul[0] = 0;
+        for (u=1; u <= maxSymbolValue+1; u++) {
+            if (normalizedCounter[u-1]==-1) {  /* Low proba symbol */
+                cumul[u] = cumul[u-1] + 1;
+                tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
+            } else {
+                cumul[u] = cumul[u-1] + normalizedCounter[u-1];
+        }   }
+        cumul[maxSymbolValue+1] = tableSize+1;
+    }
+
+    /* Spread symbols */
+    {   U32 position = 0;
+        U32 symbol;
+        for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+            int nbOccurences;
+            int const freq = normalizedCounter[symbol];
+            for (nbOccurences=0; nbOccurences<freq; nbOccurences++) {
+                tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
+                position = (position + step) & tableMask;
+                while (position > highThreshold)
+                    position = (position + step) & tableMask;   /* Low proba area */
+        }   }
+
+        assert(position==0);  /* Must have initialized all positions */
+    }
+
+    /* Build table */
+    {   U32 u; for (u=0; u<tableSize; u++) {
+        FSE_FUNCTION_TYPE s = tableSymbol[u];   /* note : static analyzer may not understand tableSymbol is properly initialized */
+        tableU16[cumul[s]++] = (U16) (tableSize+u);   /* TableU16 : sorted by symbol order; gives next state value */
+    }   }
+
+    /* Build Symbol Transformation Table */
+    {   unsigned total = 0;
+        unsigned s;
+        for (s=0; s<=maxSymbolValue; s++) {
+            switch (normalizedCounter[s])
+            {
+            case  0:
+                /* filling nonetheless, for compatibility with FSE_getMaxNbBits() */
+                symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);
+                break;
+
+            case -1:
+            case  1:
+                symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
+                symbolTT[s].deltaFindState = total - 1;
+                total ++;
+                break;
+            default :
+                {
+                    U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
+                    U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
+                    symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
+                    symbolTT[s].deltaFindState = total - normalizedCounter[s];
+                    total +=  normalizedCounter[s];
+    }   }   }   }
+
+#if 0  /* debug : symbol costs */
+    DEBUGLOG(5, "\n --- table statistics : ");
+    {   U32 symbol;
+        for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+            DEBUGLOG(5, "%3u: w=%3i,   maxBits=%u, fracBits=%.2f",
+                symbol, normalizedCounter[symbol],
+                FSE_getMaxNbBits(symbolTT, symbol),
+                (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);
+        }
+    }
+#endif
+
+    return 0;
+}
+
+
+size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+    FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE];   /* memset() is not necessary, even if static analyzer complain about it */
+    return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
+}
+
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+
+/*-**************************************************************
+*  FSE NCount encoding
+****************************************************************/
+size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
+{
+    size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
+    return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND;  /* maxSymbolValue==0 ? use default */
+}
+
+static size_t
+FSE_writeNCount_generic (void* header, size_t headerBufferSize,
+                   const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+                         unsigned writeIsSafe)
+{
+    BYTE* const ostart = (BYTE*) header;
+    BYTE* out = ostart;
+    BYTE* const oend = ostart + headerBufferSize;
+    int nbBits;
+    const int tableSize = 1 << tableLog;
+    int remaining;
+    int threshold;
+    U32 bitStream = 0;
+    int bitCount = 0;
+    unsigned symbol = 0;
+    unsigned const alphabetSize = maxSymbolValue + 1;
+    int previousIs0 = 0;
+
+    /* Table Size */
+    bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
+    bitCount  += 4;
+
+    /* Init */
+    remaining = tableSize+1;   /* +1 for extra accuracy */
+    threshold = tableSize;
+    nbBits = tableLog+1;
+
+    while ((symbol < alphabetSize) && (remaining>1)) {  /* stops at 1 */
+        if (previousIs0) {
+            unsigned start = symbol;
+            while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++;
+            if (symbol == alphabetSize) break;   /* incorrect distribution */
+            while (symbol >= start+24) {
+                start+=24;
+                bitStream += 0xFFFFU << bitCount;
+                if ((!writeIsSafe) && (out > oend-2))
+                    return ERROR(dstSize_tooSmall);   /* Buffer overflow */
+                out[0] = (BYTE) bitStream;
+                out[1] = (BYTE)(bitStream>>8);
+                out+=2;
+                bitStream>>=16;
+            }
+            while (symbol >= start+3) {
+                start+=3;
+                bitStream += 3 << bitCount;
+                bitCount += 2;
+            }
+            bitStream += (symbol-start) << bitCount;
+            bitCount += 2;
+            if (bitCount>16) {
+                if ((!writeIsSafe) && (out > oend - 2))
+                    return ERROR(dstSize_tooSmall);   /* Buffer overflow */
+                out[0] = (BYTE)bitStream;
+                out[1] = (BYTE)(bitStream>>8);
+                out += 2;
+                bitStream >>= 16;
+                bitCount -= 16;
+        }   }
+        {   int count = normalizedCounter[symbol++];
+            int const max = (2*threshold-1) - remaining;
+            remaining -= count < 0 ? -count : count;
+            count++;   /* +1 for extra accuracy */
+            if (count>=threshold)
+                count += max;   /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
+            bitStream += count << bitCount;
+            bitCount  += nbBits;
+            bitCount  -= (count<max);
+            previousIs0  = (count==1);
+            if (remaining<1) return ERROR(GENERIC);
+            while (remaining<threshold) { nbBits--; threshold>>=1; }
+        }
+        if (bitCount>16) {
+            if ((!writeIsSafe) && (out > oend - 2))
+                return ERROR(dstSize_tooSmall);   /* Buffer overflow */
+            out[0] = (BYTE)bitStream;
+            out[1] = (BYTE)(bitStream>>8);
+            out += 2;
+            bitStream >>= 16;
+            bitCount -= 16;
+    }   }
+
+    if (remaining != 1)
+        return ERROR(GENERIC);  /* incorrect normalized distribution */
+    assert(symbol <= alphabetSize);
+
+    /* flush remaining bitStream */
+    if ((!writeIsSafe) && (out > oend - 2))
+        return ERROR(dstSize_tooSmall);   /* Buffer overflow */
+    out[0] = (BYTE)bitStream;
+    out[1] = (BYTE)(bitStream>>8);
+    out+= (bitCount+7) /8;
+
+    return (out-ostart);
+}
+
+
+size_t FSE_writeNCount (void* buffer, size_t bufferSize,
+                  const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+    if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);   /* Unsupported */
+    if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC);   /* Unsupported */
+
+    if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
+        return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
+
+    return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */);
+}
+
+
+/*-**************************************************************
+*  FSE Compression Code
+****************************************************************/
+
+FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
+{
+    size_t size;
+    if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
+    size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
+    return (FSE_CTable*)malloc(size);
+}
+
+void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
+
+/* provides the minimum logSize to safely represent a distribution */
+static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
+{
+    U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;
+    U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
+    U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
+    assert(srcSize > 1); /* Not supported, RLE should be used instead */
+    return minBits;
+}
+
+unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
+{
+    U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
+    U32 tableLog = maxTableLog;
+    U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
+    assert(srcSize > 1); /* Not supported, RLE should be used instead */
+    if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
+    if (maxBitsSrc < tableLog) tableLog = maxBitsSrc;   /* Accuracy can be reduced */
+    if (minBits > tableLog) tableLog = minBits;   /* Need a minimum to safely represent all symbol values */
+    if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
+    if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
+    return tableLog;
+}
+
+unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
+{
+    return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
+}
+
+
+/* Secondary normalization method.
+   To be used when primary method fails. */
+
+static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
+{
+    short const NOT_YET_ASSIGNED = -2;
+    U32 s;
+    U32 distributed = 0;
+    U32 ToDistribute;
+
+    /* Init */
+    U32 const lowThreshold = (U32)(total >> tableLog);
+    U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
+
+    for (s=0; s<=maxSymbolValue; s++) {
+        if (count[s] == 0) {
+            norm[s]=0;
+            continue;
+        }
+        if (count[s] <= lowThreshold) {
+            norm[s] = -1;
+            distributed++;
+            total -= count[s];
+            continue;
+        }
+        if (count[s] <= lowOne) {
+            norm[s] = 1;
+            distributed++;
+            total -= count[s];
+            continue;
+        }
+
+        norm[s]=NOT_YET_ASSIGNED;
+    }
+    ToDistribute = (1 << tableLog) - distributed;
+
+    if (ToDistribute == 0)
+        return 0;
+
+    if ((total / ToDistribute) > lowOne) {
+        /* risk of rounding to zero */
+        lowOne = (U32)((total * 3) / (ToDistribute * 2));
+        for (s=0; s<=maxSymbolValue; s++) {
+            if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
+                norm[s] = 1;
+                distributed++;
+                total -= count[s];
+                continue;
+        }   }
+        ToDistribute = (1 << tableLog) - distributed;
+    }
+
+    if (distributed == maxSymbolValue+1) {
+        /* all values are pretty poor;
+           probably incompressible data (should have already been detected);
+           find max, then give all remaining points to max */
+        U32 maxV = 0, maxC = 0;
+        for (s=0; s<=maxSymbolValue; s++)
+            if (count[s] > maxC) { maxV=s; maxC=count[s]; }
+        norm[maxV] += (short)ToDistribute;
+        return 0;
+    }
+
+    if (total == 0) {
+        /* all of the symbols were low enough for the lowOne or lowThreshold */
+        for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
+            if (norm[s] > 0) { ToDistribute--; norm[s]++; }
+        return 0;
+    }
+
+    {   U64 const vStepLog = 62 - tableLog;
+        U64 const mid = (1ULL << (vStepLog-1)) - 1;
+        U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total;   /* scale on remaining */
+        U64 tmpTotal = mid;
+        for (s=0; s<=maxSymbolValue; s++) {
+            if (norm[s]==NOT_YET_ASSIGNED) {
+                U64 const end = tmpTotal + (count[s] * rStep);
+                U32 const sStart = (U32)(tmpTotal >> vStepLog);
+                U32 const sEnd = (U32)(end >> vStepLog);
+                U32 const weight = sEnd - sStart;
+                if (weight < 1)
+                    return ERROR(GENERIC);
+                norm[s] = (short)weight;
+                tmpTotal = end;
+    }   }   }
+
+    return 0;
+}
+
+
+size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
+                           const unsigned* count, size_t total,
+                           unsigned maxSymbolValue)
+{
+    /* Sanity checks */
+    if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
+    if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC);   /* Unsupported size */
+    if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);   /* Unsupported size */
+    if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC);   /* Too small tableLog, compression potentially impossible */
+
+    {   static U32 const rtbTable[] = {     0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
+        U64 const scale = 62 - tableLog;
+        U64 const step = ((U64)1<<62) / total;   /* <== here, one division ! */
+        U64 const vStep = 1ULL<<(scale-20);
+        int stillToDistribute = 1<<tableLog;
+        unsigned s;
+        unsigned largest=0;
+        short largestP=0;
+        U32 lowThreshold = (U32)(total >> tableLog);
+
+        for (s=0; s<=maxSymbolValue; s++) {
+            if (count[s] == total) return 0;   /* rle special case */
+            if (count[s] == 0) { normalizedCounter[s]=0; continue; }
+            if (count[s] <= lowThreshold) {
+                normalizedCounter[s] = -1;
+                stillToDistribute--;
+            } else {
+                short proba = (short)((count[s]*step) >> scale);
+                if (proba<8) {
+                    U64 restToBeat = vStep * rtbTable[proba];
+                    proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
+                }
+                if (proba > largestP) { largestP=proba; largest=s; }
+                normalizedCounter[s] = proba;
+                stillToDistribute -= proba;
+        }   }
+        if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
+            /* corner case, need another normalization method */
+            size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
+            if (FSE_isError(errorCode)) return errorCode;
+        }
+        else normalizedCounter[largest] += (short)stillToDistribute;
+    }
+
+#if 0
+    {   /* Print Table (debug) */
+        U32 s;
+        U32 nTotal = 0;
+        for (s=0; s<=maxSymbolValue; s++)
+            RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);
+        for (s=0; s<=maxSymbolValue; s++)
+            nTotal += abs(normalizedCounter[s]);
+        if (nTotal != (1U<<tableLog))
+            RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
+        getchar();
+    }
+#endif
+
+    return tableLog;
+}
+
+
+/* fake FSE_CTable, for raw (uncompressed) input */
+size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
+{
+    const unsigned tableSize = 1 << nbBits;
+    const unsigned tableMask = tableSize - 1;
+    const unsigned maxSymbolValue = tableMask;
+    void* const ptr = ct;
+    U16* const tableU16 = ( (U16*) ptr) + 2;
+    void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1);   /* assumption : tableLog >= 1 */
+    FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+    unsigned s;
+
+    /* Sanity checks */
+    if (nbBits < 1) return ERROR(GENERIC);             /* min size */
+
+    /* header */
+    tableU16[-2] = (U16) nbBits;
+    tableU16[-1] = (U16) maxSymbolValue;
+
+    /* Build table */
+    for (s=0; s<tableSize; s++)
+        tableU16[s] = (U16)(tableSize + s);
+
+    /* Build Symbol Transformation Table */
+    {   const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
+        for (s=0; s<=maxSymbolValue; s++) {
+            symbolTT[s].deltaNbBits = deltaNbBits;
+            symbolTT[s].deltaFindState = s-1;
+    }   }
+
+    return 0;
+}
+
+/* fake FSE_CTable, for rle input (always same symbol) */
+size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
+{
+    void* ptr = ct;
+    U16* tableU16 = ( (U16*) ptr) + 2;
+    void* FSCTptr = (U32*)ptr + 2;
+    FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
+
+    /* header */
+    tableU16[-2] = (U16) 0;
+    tableU16[-1] = (U16) symbolValue;
+
+    /* Build table */
+    tableU16[0] = 0;
+    tableU16[1] = 0;   /* just in case */
+
+    /* Build Symbol Transformation Table */
+    symbolTT[symbolValue].deltaNbBits = 0;
+    symbolTT[symbolValue].deltaFindState = 0;
+
+    return 0;
+}
+
+
+static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
+                           const void* src, size_t srcSize,
+                           const FSE_CTable* ct, const unsigned fast)
+{
+    const BYTE* const istart = (const BYTE*) src;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* ip=iend;
+
+    BIT_CStream_t bitC;
+    FSE_CState_t CState1, CState2;
+
+    /* init */
+    if (srcSize <= 2) return 0;
+    { size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
+      if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
+
+#define FSE_FLUSHBITS(s)  (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
+
+    if (srcSize & 1) {
+        FSE_initCState2(&CState1, ct, *--ip);
+        FSE_initCState2(&CState2, ct, *--ip);
+        FSE_encodeSymbol(&bitC, &CState1, *--ip);
+        FSE_FLUSHBITS(&bitC);
+    } else {
+        FSE_initCState2(&CState2, ct, *--ip);
+        FSE_initCState2(&CState1, ct, *--ip);
+    }
+
+    /* join to mod 4 */
+    srcSize -= 2;
+    if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) {  /* test bit 2 */
+        FSE_encodeSymbol(&bitC, &CState2, *--ip);
+        FSE_encodeSymbol(&bitC, &CState1, *--ip);
+        FSE_FLUSHBITS(&bitC);
+    }
+
+    /* 2 or 4 encoding per loop */
+    while ( ip>istart ) {
+
+        FSE_encodeSymbol(&bitC, &CState2, *--ip);
+
+        if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 )   /* this test must be static */
+            FSE_FLUSHBITS(&bitC);
+
+        FSE_encodeSymbol(&bitC, &CState1, *--ip);
+
+        if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) {  /* this test must be static */
+            FSE_encodeSymbol(&bitC, &CState2, *--ip);
+            FSE_encodeSymbol(&bitC, &CState1, *--ip);
+        }
+
+        FSE_FLUSHBITS(&bitC);
+    }
+
+    FSE_flushCState(&bitC, &CState2);
+    FSE_flushCState(&bitC, &CState1);
+    return BIT_closeCStream(&bitC);
+}
+
+size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
+                           const void* src, size_t srcSize,
+                           const FSE_CTable* ct)
+{
+    unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
+
+    if (fast)
+        return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
+    else
+        return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
+}
+
+
+size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
+
+#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
+#define CHECK_F(f)   { CHECK_V_F(_var_err__, f); }
+
+/* FSE_compress_wksp() :
+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
+ * `wkspSize` size must be `(1<<tableLog)`.
+ */
+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
+{
+    BYTE* const ostart = (BYTE*) dst;
+    BYTE* op = ostart;
+    BYTE* const oend = ostart + dstSize;
+
+    unsigned count[FSE_MAX_SYMBOL_VALUE+1];
+    S16   norm[FSE_MAX_SYMBOL_VALUE+1];
+    FSE_CTable* CTable = (FSE_CTable*)workSpace;
+    size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
+    void* scratchBuffer = (void*)(CTable + CTableSize);
+    size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
+
+    /* init conditions */
+    if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
+    if (srcSize <= 1) return 0;  /* Not compressible */
+    if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+    if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
+
+    /* Scan input and build symbol stats */
+    {   CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, scratchBuffer, scratchBufferSize) );
+        if (maxCount == srcSize) return 1;   /* only a single symbol in src : rle */
+        if (maxCount == 1) return 0;         /* each symbol present maximum once => not compressible */
+        if (maxCount < (srcSize >> 7)) return 0;   /* Heuristic : not compressible enough */
+    }
+
+    tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
+    CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
+
+    /* Write table description header */
+    {   CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
+        op += nc_err;
+    }
+
+    /* Compress */
+    CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
+    {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
+        if (cSize == 0) return 0;   /* not enough space for compressed data */
+        op += cSize;
+    }
+
+    /* check compressibility */
+    if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
+
+    return op-ostart;
+}
+
+typedef struct {
+    FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
+    BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
+} fseWkspMax_t;
+
+size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
+{
+    fseWkspMax_t scratchBuffer;
+    DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE));   /* compilation failures here means scratchBuffer is not large enough */
+    if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+    return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
+}
+
+size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
+}
+
+
+#endif   /* FSE_COMMONDEFS_ONLY */
diff --git a/Utilities/cmzstd/lib/compress/hist.c b/Utilities/cmzstd/lib/compress/hist.c
new file mode 100644
index 0000000..45b7bab
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/hist.c
@@ -0,0 +1,203 @@
+/* ******************************************************************
+   hist : Histogram functions
+   part of Finite State Entropy project
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+    - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* --- dependencies --- */
+#include "mem.h"             /* U32, BYTE, etc. */
+#include "debug.h"           /* assert, DEBUGLOG */
+#include "error_private.h"   /* ERROR */
+#include "hist.h"
+
+
+/* --- Error management --- */
+unsigned HIST_isError(size_t code) { return ERR_isError(code); }
+
+/*-**************************************************************
+ *  Histogram functions
+ ****************************************************************/
+unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
+                           const void* src, size_t srcSize)
+{
+    const BYTE* ip = (const BYTE*)src;
+    const BYTE* const end = ip + srcSize;
+    unsigned maxSymbolValue = *maxSymbolValuePtr;
+    unsigned largestCount=0;
+
+    memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
+    if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
+
+    while (ip<end) {
+        assert(*ip <= maxSymbolValue);
+        count[*ip++]++;
+    }
+
+    while (!count[maxSymbolValue]) maxSymbolValue--;
+    *maxSymbolValuePtr = maxSymbolValue;
+
+    {   U32 s;
+        for (s=0; s<=maxSymbolValue; s++)
+            if (count[s] > largestCount) largestCount = count[s];
+    }
+
+    return largestCount;
+}
+
+typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e;
+
+/* HIST_count_parallel_wksp() :
+ * store histogram into 4 intermediate tables, recombined at the end.
+ * this design makes better use of OoO cpus,
+ * and is noticeably faster when some values are heavily repeated.
+ * But it needs some additional workspace for intermediate tables.
+ * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32.
+ * @return : largest histogram frequency,
+ *           or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
+static size_t HIST_count_parallel_wksp(
+                                unsigned* count, unsigned* maxSymbolValuePtr,
+                                const void* source, size_t sourceSize,
+                                HIST_checkInput_e check,
+                                U32* const workSpace)
+{
+    const BYTE* ip = (const BYTE*)source;
+    const BYTE* const iend = ip+sourceSize;
+    unsigned maxSymbolValue = *maxSymbolValuePtr;
+    unsigned max=0;
+    U32* const Counting1 = workSpace;
+    U32* const Counting2 = Counting1 + 256;
+    U32* const Counting3 = Counting2 + 256;
+    U32* const Counting4 = Counting3 + 256;
+
+    memset(workSpace, 0, 4*256*sizeof(unsigned));
+
+    /* safety checks */
+    if (!sourceSize) {
+        memset(count, 0, maxSymbolValue + 1);
+        *maxSymbolValuePtr = 0;
+        return 0;
+    }
+    if (!maxSymbolValue) maxSymbolValue = 255;            /* 0 == default */
+
+    /* by stripes of 16 bytes */
+    {   U32 cached = MEM_read32(ip); ip += 4;
+        while (ip < iend-15) {
+            U32 c = cached; cached = MEM_read32(ip); ip += 4;
+            Counting1[(BYTE) c     ]++;
+            Counting2[(BYTE)(c>>8) ]++;
+            Counting3[(BYTE)(c>>16)]++;
+            Counting4[       c>>24 ]++;
+            c = cached; cached = MEM_read32(ip); ip += 4;
+            Counting1[(BYTE) c     ]++;
+            Counting2[(BYTE)(c>>8) ]++;
+            Counting3[(BYTE)(c>>16)]++;
+            Counting4[       c>>24 ]++;
+            c = cached; cached = MEM_read32(ip); ip += 4;
+            Counting1[(BYTE) c     ]++;
+            Counting2[(BYTE)(c>>8) ]++;
+            Counting3[(BYTE)(c>>16)]++;
+            Counting4[       c>>24 ]++;
+            c = cached; cached = MEM_read32(ip); ip += 4;
+            Counting1[(BYTE) c     ]++;
+            Counting2[(BYTE)(c>>8) ]++;
+            Counting3[(BYTE)(c>>16)]++;
+            Counting4[       c>>24 ]++;
+        }
+        ip-=4;
+    }
+
+    /* finish last symbols */
+    while (ip<iend) Counting1[*ip++]++;
+
+    if (check) {   /* verify stats will fit into destination table */
+        U32 s; for (s=255; s>maxSymbolValue; s--) {
+            Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
+            if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
+    }   }
+
+    {   U32 s;
+        if (maxSymbolValue > 255) maxSymbolValue = 255;
+        for (s=0; s<=maxSymbolValue; s++) {
+            count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
+            if (count[s] > max) max = count[s];
+    }   }
+
+    while (!count[maxSymbolValue]) maxSymbolValue--;
+    *maxSymbolValuePtr = maxSymbolValue;
+    return (size_t)max;
+}
+
+/* HIST_countFast_wksp() :
+ * Same as HIST_countFast(), but using an externally provided scratch buffer.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+                          const void* source, size_t sourceSize,
+                          void* workSpace, size_t workSpaceSize)
+{
+    if (sourceSize < 1500) /* heuristic threshold */
+        return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize);
+    if ((size_t)workSpace & 3) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
+    if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
+    return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace);
+}
+
+/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+                     const void* source, size_t sourceSize)
+{
+    unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+    return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters));
+}
+
+/* HIST_count_wksp() :
+ * Same as HIST_count(), but using an externally provided scratch buffer.
+ * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
+size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+                       const void* source, size_t sourceSize,
+                       void* workSpace, size_t workSpaceSize)
+{
+    if ((size_t)workSpace & 3) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
+    if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
+    if (*maxSymbolValuePtr < 255)
+        return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace);
+    *maxSymbolValuePtr = 255;
+    return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize);
+}
+
+size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
+                 const void* src, size_t srcSize)
+{
+    unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+    return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters));
+}
diff --git a/Utilities/cmzstd/lib/compress/hist.h b/Utilities/cmzstd/lib/compress/hist.h
new file mode 100644
index 0000000..8b38935
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/hist.h
@@ -0,0 +1,95 @@
+/* ******************************************************************
+   hist : Histogram functions
+   part of Finite State Entropy project
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+    - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* --- dependencies --- */
+#include <stddef.h>   /* size_t */
+
+
+/* --- simple histogram functions --- */
+
+/*! HIST_count():
+ *  Provides the precise count of each byte within a table 'count'.
+ * 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
+ *  Updates *maxSymbolValuePtr with actual largest symbol value detected.
+ * @return : count of the most frequent symbol (which isn't identified).
+ *           or an error code, which can be tested using HIST_isError().
+ *           note : if return == srcSize, there is only one symbol.
+ */
+size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
+                  const void* src, size_t srcSize);
+
+unsigned HIST_isError(size_t code);  /**< tells if a return value is an error code */
+
+
+/* --- advanced histogram functions --- */
+
+#define HIST_WKSP_SIZE_U32 1024
+#define HIST_WKSP_SIZE    (HIST_WKSP_SIZE_U32 * sizeof(unsigned))
+/** HIST_count_wksp() :
+ *  Same as HIST_count(), but using an externally provided scratch buffer.
+ *  Benefit is this function will use very little stack space.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+                       const void* src, size_t srcSize,
+                       void* workSpace, size_t workSpaceSize);
+
+/** HIST_countFast() :
+ *  same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr.
+ *  This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr`
+ */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+                      const void* src, size_t srcSize);
+
+/** HIST_countFast_wksp() :
+ *  Same as HIST_countFast(), but using an externally provided scratch buffer.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+                           const void* src, size_t srcSize,
+                           void* workSpace, size_t workSpaceSize);
+
+/*! HIST_count_simple() :
+ *  Same as HIST_countFast(), this function is unsafe,
+ *  and will segfault if any value within `src` is `> *maxSymbolValuePtr`.
+ *  It is also a bit slower for large inputs.
+ *  However, it does not need any additional memory (not even on stack).
+ * @return : count of the most frequent symbol.
+ *  Note this function doesn't produce any error (i.e. it must succeed).
+ */
+unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
+                           const void* src, size_t srcSize);
diff --git a/Utilities/cmzstd/lib/compress/huf_compress.c b/Utilities/cmzstd/lib/compress/huf_compress.c
new file mode 100644
index 0000000..f074f1e
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/huf_compress.c
@@ -0,0 +1,798 @@
+/* ******************************************************************
+   Huffman encoder, part of New Generation Entropy library
+   Copyright (C) 2013-2016, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+    - Public forum : https://groups.google.com/forum/#!forum/lz4c
+****************************************************************** */
+
+/* **************************************************************
+*  Compiler specifics
+****************************************************************/
+#ifdef _MSC_VER    /* Visual Studio */
+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
+#endif
+
+
+/* **************************************************************
+*  Includes
+****************************************************************/
+#include <string.h>     /* memcpy, memset */
+#include <stdio.h>      /* printf (debug) */
+#include "compiler.h"
+#include "bitstream.h"
+#include "hist.h"
+#define FSE_STATIC_LINKING_ONLY   /* FSE_optimalTableLog_internal */
+#include "fse.h"        /* header compression */
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+*  Error Management
+****************************************************************/
+#define HUF_isError ERR_isError
+#define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)   /* use only *after* variable declarations */
+#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
+#define CHECK_F(f)   { CHECK_V_F(_var_err__, f); }
+
+
+/* **************************************************************
+*  Utils
+****************************************************************/
+unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
+{
+    return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
+}
+
+
+/* *******************************************************
+*  HUF : Huffman block compression
+*********************************************************/
+/* HUF_compressWeights() :
+ * Same as FSE_compress(), but dedicated to huff0's weights compression.
+ * The use case needs much less stack memory.
+ * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
+ */
+#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
+static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
+{
+    BYTE* const ostart = (BYTE*) dst;
+    BYTE* op = ostart;
+    BYTE* const oend = ostart + dstSize;
+
+    unsigned maxSymbolValue = HUF_TABLELOG_MAX;
+    U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
+
+    FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
+    BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
+
+    unsigned count[HUF_TABLELOG_MAX+1];
+    S16 norm[HUF_TABLELOG_MAX+1];
+
+    /* init conditions */
+    if (wtSize <= 1) return 0;  /* Not compressible */
+
+    /* Scan input and build symbol stats */
+    {   unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize);   /* never fails */
+        if (maxCount == wtSize) return 1;   /* only a single symbol in src : rle */
+        if (maxCount == 1) return 0;        /* each symbol present maximum once => not compressible */
+    }
+
+    tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
+    CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
+
+    /* Write table description header */
+    {   CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
+        op += hSize;
+    }
+
+    /* Compress */
+    CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
+    {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) );
+        if (cSize == 0) return 0;   /* not enough space for compressed data */
+        op += cSize;
+    }
+
+    return op-ostart;
+}
+
+
+struct HUF_CElt_s {
+  U16  val;
+  BYTE nbBits;
+};   /* typedef'd to HUF_CElt within "huf.h" */
+
+/*! HUF_writeCTable() :
+    `CTable` : Huffman tree to save, using huf representation.
+    @return : size of saved CTable */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize,
+                        const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
+{
+    BYTE bitsToWeight[HUF_TABLELOG_MAX + 1];   /* precomputed conversion table */
+    BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
+    BYTE* op = (BYTE*)dst;
+    U32 n;
+
+     /* check conditions */
+    if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+
+    /* convert to weight */
+    bitsToWeight[0] = 0;
+    for (n=1; n<huffLog+1; n++)
+        bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
+    for (n=0; n<maxSymbolValue; n++)
+        huffWeight[n] = bitsToWeight[CTable[n].nbBits];
+
+    /* attempt weights compression by FSE */
+    {   CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
+        if ((hSize>1) & (hSize < maxSymbolValue/2)) {   /* FSE compressed */
+            op[0] = (BYTE)hSize;
+            return hSize+1;
+    }   }
+
+    /* write raw values as 4-bits (max : 15) */
+    if (maxSymbolValue > (256-128)) return ERROR(GENERIC);   /* should not happen : likely means source cannot be compressed */
+    if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall);   /* not enough space within dst buffer */
+    op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
+    huffWeight[maxSymbolValue] = 0;   /* to be sure it doesn't cause msan issue in final combination */
+    for (n=0; n<maxSymbolValue; n+=2)
+        op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
+    return ((maxSymbolValue+1)/2) + 1;
+}
+
+
+size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize)
+{
+    BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];   /* init not required, even though some static analyzer may complain */
+    U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1];   /* large enough for values from 0 to 16 */
+    U32 tableLog = 0;
+    U32 nbSymbols = 0;
+
+    /* get symbol weights */
+    CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
+
+    /* check result */
+    if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+    if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
+
+    /* Prepare base value per rank */
+    {   U32 n, nextRankStart = 0;
+        for (n=1; n<=tableLog; n++) {
+            U32 current = nextRankStart;
+            nextRankStart += (rankVal[n] << (n-1));
+            rankVal[n] = current;
+    }   }
+
+    /* fill nbBits */
+    {   U32 n; for (n=0; n<nbSymbols; n++) {
+            const U32 w = huffWeight[n];
+            CTable[n].nbBits = (BYTE)(tableLog + 1 - w);
+    }   }
+
+    /* fill val */
+    {   U16 nbPerRank[HUF_TABLELOG_MAX+2]  = {0};  /* support w=0=>n=tableLog+1 */
+        U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
+        { U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; }
+        /* determine stating value per rank */
+        valPerRank[tableLog+1] = 0;   /* for w==0 */
+        {   U16 min = 0;
+            U32 n; for (n=tableLog; n>0; n--) {  /* start at n=tablelog <-> w=1 */
+                valPerRank[n] = min;     /* get starting value within each rank */
+                min += nbPerRank[n];
+                min >>= 1;
+        }   }
+        /* assign value within rank, symbol order */
+        { U32 n; for (n=0; n<nbSymbols; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
+    }
+
+    *maxSymbolValuePtr = nbSymbols - 1;
+    return readSize;
+}
+
+U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue)
+{
+    const HUF_CElt* table = (const HUF_CElt*)symbolTable;
+    assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
+    return table[symbolValue].nbBits;
+}
+
+
+typedef struct nodeElt_s {
+    U32 count;
+    U16 parent;
+    BYTE byte;
+    BYTE nbBits;
+} nodeElt;
+
+static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
+{
+    const U32 largestBits = huffNode[lastNonNull].nbBits;
+    if (largestBits <= maxNbBits) return largestBits;   /* early exit : no elt > maxNbBits */
+
+    /* there are several too large elements (at least >= 2) */
+    {   int totalCost = 0;
+        const U32 baseCost = 1 << (largestBits - maxNbBits);
+        U32 n = lastNonNull;
+
+        while (huffNode[n].nbBits > maxNbBits) {
+            totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
+            huffNode[n].nbBits = (BYTE)maxNbBits;
+            n --;
+        }  /* n stops at huffNode[n].nbBits <= maxNbBits */
+        while (huffNode[n].nbBits == maxNbBits) n--;   /* n end at index of smallest symbol using < maxNbBits */
+
+        /* renorm totalCost */
+        totalCost >>= (largestBits - maxNbBits);  /* note : totalCost is necessarily a multiple of baseCost */
+
+        /* repay normalized cost */
+        {   U32 const noSymbol = 0xF0F0F0F0;
+            U32 rankLast[HUF_TABLELOG_MAX+2];
+            int pos;
+
+            /* Get pos of last (smallest) symbol per rank */
+            memset(rankLast, 0xF0, sizeof(rankLast));
+            {   U32 currentNbBits = maxNbBits;
+                for (pos=n ; pos >= 0; pos--) {
+                    if (huffNode[pos].nbBits >= currentNbBits) continue;
+                    currentNbBits = huffNode[pos].nbBits;   /* < maxNbBits */
+                    rankLast[maxNbBits-currentNbBits] = pos;
+            }   }
+
+            while (totalCost > 0) {
+                U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1;
+                for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
+                    U32 highPos = rankLast[nBitsToDecrease];
+                    U32 lowPos = rankLast[nBitsToDecrease-1];
+                    if (highPos == noSymbol) continue;
+                    if (lowPos == noSymbol) break;
+                    {   U32 const highTotal = huffNode[highPos].count;
+                        U32 const lowTotal = 2 * huffNode[lowPos].count;
+                        if (highTotal <= lowTotal) break;
+                }   }
+                /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
+                /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
+                while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
+                    nBitsToDecrease ++;
+                totalCost -= 1 << (nBitsToDecrease-1);
+                if (rankLast[nBitsToDecrease-1] == noSymbol)
+                    rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease];   /* this rank is no longer empty */
+                huffNode[rankLast[nBitsToDecrease]].nbBits ++;
+                if (rankLast[nBitsToDecrease] == 0)    /* special case, reached largest symbol */
+                    rankLast[nBitsToDecrease] = noSymbol;
+                else {
+                    rankLast[nBitsToDecrease]--;
+                    if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
+                        rankLast[nBitsToDecrease] = noSymbol;   /* this rank is now empty */
+            }   }   /* while (totalCost > 0) */
+
+            while (totalCost < 0) {  /* Sometimes, cost correction overshoot */
+                if (rankLast[1] == noSymbol) {  /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
+                    while (huffNode[n].nbBits == maxNbBits) n--;
+                    huffNode[n+1].nbBits--;
+                    rankLast[1] = n+1;
+                    totalCost++;
+                    continue;
+                }
+                huffNode[ rankLast[1] + 1 ].nbBits--;
+                rankLast[1]++;
+                totalCost ++;
+    }   }   }   /* there are several too large elements (at least >= 2) */
+
+    return maxNbBits;
+}
+
+
+typedef struct {
+    U32 base;
+    U32 current;
+} rankPos;
+
+static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue)
+{
+    rankPos rank[32];
+    U32 n;
+
+    memset(rank, 0, sizeof(rank));
+    for (n=0; n<=maxSymbolValue; n++) {
+        U32 r = BIT_highbit32(count[n] + 1);
+        rank[r].base ++;
+    }
+    for (n=30; n>0; n--) rank[n-1].base += rank[n].base;
+    for (n=0; n<32; n++) rank[n].current = rank[n].base;
+    for (n=0; n<=maxSymbolValue; n++) {
+        U32 const c = count[n];
+        U32 const r = BIT_highbit32(c+1) + 1;
+        U32 pos = rank[r].current++;
+        while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) {
+            huffNode[pos] = huffNode[pos-1];
+            pos--;
+        }
+        huffNode[pos].count = c;
+        huffNode[pos].byte  = (BYTE)n;
+    }
+}
+
+
+/** HUF_buildCTable_wksp() :
+ *  Same as HUF_buildCTable(), but using externally allocated scratch buffer.
+ *  `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of HUF_CTABLE_WORKSPACE_SIZE_U32 unsigned.
+ */
+#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
+typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
+size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
+{
+    nodeElt* const huffNode0 = (nodeElt*)workSpace;
+    nodeElt* const huffNode = huffNode0+1;
+    U32 n, nonNullRank;
+    int lowS, lowN;
+    U16 nodeNb = STARTNODE;
+    U32 nodeRoot;
+
+    /* safety checks */
+    if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
+    if (wkspSize < sizeof(huffNodeTable)) return ERROR(workSpace_tooSmall);
+    if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
+    if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+    memset(huffNode0, 0, sizeof(huffNodeTable));
+
+    /* sort, decreasing order */
+    HUF_sort(huffNode, count, maxSymbolValue);
+
+    /* init for parents */
+    nonNullRank = maxSymbolValue;
+    while(huffNode[nonNullRank].count == 0) nonNullRank--;
+    lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
+    huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
+    huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb;
+    nodeNb++; lowS-=2;
+    for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
+    huffNode0[0].count = (U32)(1U<<31);  /* fake entry, strong barrier */
+
+    /* create parents */
+    while (nodeNb <= nodeRoot) {
+        U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
+        U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
+        huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
+        huffNode[n1].parent = huffNode[n2].parent = nodeNb;
+        nodeNb++;
+    }
+
+    /* distribute weights (unlimited tree height) */
+    huffNode[nodeRoot].nbBits = 0;
+    for (n=nodeRoot-1; n>=STARTNODE; n--)
+        huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+    for (n=0; n<=nonNullRank; n++)
+        huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+
+    /* enforce maxTableLog */
+    maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits);
+
+    /* fill result into tree (val, nbBits) */
+    {   U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
+        U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
+        if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC);   /* check fit into table */
+        for (n=0; n<=nonNullRank; n++)
+            nbPerRank[huffNode[n].nbBits]++;
+        /* determine stating value per rank */
+        {   U16 min = 0;
+            for (n=maxNbBits; n>0; n--) {
+                valPerRank[n] = min;      /* get starting value within each rank */
+                min += nbPerRank[n];
+                min >>= 1;
+        }   }
+        for (n=0; n<=maxSymbolValue; n++)
+            tree[huffNode[n].byte].nbBits = huffNode[n].nbBits;   /* push nbBits per symbol, symbol order */
+        for (n=0; n<=maxSymbolValue; n++)
+            tree[n].val = valPerRank[tree[n].nbBits]++;   /* assign value within rank, symbol order */
+    }
+
+    return maxNbBits;
+}
+
+/** HUF_buildCTable() :
+ * @return : maxNbBits
+ *  Note : count is used before tree is written, so they can safely overlap
+ */
+size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits)
+{
+    huffNodeTable nodeTable;
+    return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, nodeTable, sizeof(nodeTable));
+}
+
+static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
+{
+    size_t nbBits = 0;
+    int s;
+    for (s = 0; s <= (int)maxSymbolValue; ++s) {
+        nbBits += CTable[s].nbBits * count[s];
+    }
+    return nbBits >> 3;
+}
+
+static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
+  int bad = 0;
+  int s;
+  for (s = 0; s <= (int)maxSymbolValue; ++s) {
+    bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
+  }
+  return !bad;
+}
+
+size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
+
+FORCE_INLINE_TEMPLATE void
+HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
+{
+    BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
+}
+
+#define HUF_FLUSHBITS(s)  BIT_flushBits(s)
+
+#define HUF_FLUSHBITS_1(stream) \
+    if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
+
+#define HUF_FLUSHBITS_2(stream) \
+    if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
+                                   const void* src, size_t srcSize,
+                                   const HUF_CElt* CTable)
+{
+    const BYTE* ip = (const BYTE*) src;
+    BYTE* const ostart = (BYTE*)dst;
+    BYTE* const oend = ostart + dstSize;
+    BYTE* op = ostart;
+    size_t n;
+    BIT_CStream_t bitC;
+
+    /* init */
+    if (dstSize < 8) return 0;   /* not enough space to compress */
+    { size_t const initErr = BIT_initCStream(&bitC, op, oend-op);
+      if (HUF_isError(initErr)) return 0; }
+
+    n = srcSize & ~3;  /* join to mod 4 */
+    switch (srcSize & 3)
+    {
+        case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
+                 HUF_FLUSHBITS_2(&bitC);
+		 /* fall-through */
+        case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
+                 HUF_FLUSHBITS_1(&bitC);
+		 /* fall-through */
+        case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
+                 HUF_FLUSHBITS(&bitC);
+		 /* fall-through */
+        case 0 : /* fall-through */
+        default: break;
+    }
+
+    for (; n>0; n-=4) {  /* note : n&3==0 at this stage */
+        HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
+        HUF_FLUSHBITS_1(&bitC);
+        HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
+        HUF_FLUSHBITS_2(&bitC);
+        HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
+        HUF_FLUSHBITS_1(&bitC);
+        HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
+        HUF_FLUSHBITS(&bitC);
+    }
+
+    return BIT_closeCStream(&bitC);
+}
+
+#if DYNAMIC_BMI2
+
+static TARGET_ATTRIBUTE("bmi2") size_t
+HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize,
+                                   const void* src, size_t srcSize,
+                                   const HUF_CElt* CTable)
+{
+    return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+static size_t
+HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize,
+                                      const void* src, size_t srcSize,
+                                      const HUF_CElt* CTable)
+{
+    return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+static size_t
+HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
+                              const void* src, size_t srcSize,
+                              const HUF_CElt* CTable, const int bmi2)
+{
+    if (bmi2) {
+        return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
+    }
+    return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
+}
+
+#else
+
+static size_t
+HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
+                              const void* src, size_t srcSize,
+                              const HUF_CElt* CTable, const int bmi2)
+{
+    (void)bmi2;
+    return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+#endif
+
+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+{
+    return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
+}
+
+
+static size_t
+HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
+                              const void* src, size_t srcSize,
+                              const HUF_CElt* CTable, int bmi2)
+{
+    size_t const segmentSize = (srcSize+3)/4;   /* first 3 segments */
+    const BYTE* ip = (const BYTE*) src;
+    const BYTE* const iend = ip + srcSize;
+    BYTE* const ostart = (BYTE*) dst;
+    BYTE* const oend = ostart + dstSize;
+    BYTE* op = ostart;
+
+    if (dstSize < 6 + 1 + 1 + 1 + 8) return 0;   /* minimum space to compress successfully */
+    if (srcSize < 12) return 0;   /* no saving possible : too small input */
+    op += 6;   /* jumpTable */
+
+    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
+        if (cSize==0) return 0;
+        assert(cSize <= 65535);
+        MEM_writeLE16(ostart, (U16)cSize);
+        op += cSize;
+    }
+
+    ip += segmentSize;
+    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
+        if (cSize==0) return 0;
+        assert(cSize <= 65535);
+        MEM_writeLE16(ostart+2, (U16)cSize);
+        op += cSize;
+    }
+
+    ip += segmentSize;
+    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, segmentSize, CTable, bmi2) );
+        if (cSize==0) return 0;
+        assert(cSize <= 65535);
+        MEM_writeLE16(ostart+4, (U16)cSize);
+        op += cSize;
+    }
+
+    ip += segmentSize;
+    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, oend-op, ip, iend-ip, CTable, bmi2) );
+        if (cSize==0) return 0;
+        op += cSize;
+    }
+
+    return op-ostart;
+}
+
+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+{
+    return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
+}
+
+typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
+
+static size_t HUF_compressCTable_internal(
+                BYTE* const ostart, BYTE* op, BYTE* const oend,
+                const void* src, size_t srcSize,
+                HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2)
+{
+    size_t const cSize = (nbStreams==HUF_singleStream) ?
+                         HUF_compress1X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2) :
+                         HUF_compress4X_usingCTable_internal(op, oend - op, src, srcSize, CTable, bmi2);
+    if (HUF_isError(cSize)) { return cSize; }
+    if (cSize==0) { return 0; }   /* uncompressible */
+    op += cSize;
+    /* check compressibility */
+    if ((size_t)(op-ostart) >= srcSize-1) { return 0; }
+    return op-ostart;
+}
+
+typedef struct {
+    unsigned count[HUF_SYMBOLVALUE_MAX + 1];
+    HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
+    huffNodeTable nodeTable;
+} HUF_compress_tables_t;
+
+/* HUF_compress_internal() :
+ * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+static size_t
+HUF_compress_internal (void* dst, size_t dstSize,
+                 const void* src, size_t srcSize,
+                       unsigned maxSymbolValue, unsigned huffLog,
+                       HUF_nbStreams_e nbStreams,
+                       void* workSpace, size_t wkspSize,
+                       HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
+                 const int bmi2)
+{
+    HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace;
+    BYTE* const ostart = (BYTE*)dst;
+    BYTE* const oend = ostart + dstSize;
+    BYTE* op = ostart;
+
+    /* checks & inits */
+    if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
+    if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall);
+    if (!srcSize) return 0;  /* Uncompressed */
+    if (!dstSize) return 0;  /* cannot fit anything within dst budget */
+    if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);   /* current block size limit */
+    if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+    if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+    if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+    if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
+
+    /* Heuristic : If old table is valid, use it for small inputs */
+    if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
+        return HUF_compressCTable_internal(ostart, op, oend,
+                                           src, srcSize,
+                                           nbStreams, oldHufTable, bmi2);
+    }
+
+    /* Scan input and build symbol stats */
+    {   CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) );
+        if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; }   /* single symbol, rle */
+        if (largest <= (srcSize >> 7)+4) return 0;   /* heuristic : probably not compressible enough */
+    }
+
+    /* Check validity of previous table */
+    if ( repeat
+      && *repeat == HUF_repeat_check
+      && !HUF_validateCTable(oldHufTable, table->count, maxSymbolValue)) {
+        *repeat = HUF_repeat_none;
+    }
+    /* Heuristic : use existing table for small inputs */
+    if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
+        return HUF_compressCTable_internal(ostart, op, oend,
+                                           src, srcSize,
+                                           nbStreams, oldHufTable, bmi2);
+    }
+
+    /* Build Huffman Tree */
+    huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
+    {   size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
+                                            maxSymbolValue, huffLog,
+                                            table->nodeTable, sizeof(table->nodeTable));
+        CHECK_F(maxBits);
+        huffLog = (U32)maxBits;
+        /* Zero unused symbols in CTable, so we can check it for validity */
+        memset(table->CTable + (maxSymbolValue + 1), 0,
+               sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt)));
+    }
+
+    /* Write table description header */
+    {   CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
+        /* Check if using previous huffman table is beneficial */
+        if (repeat && *repeat != HUF_repeat_none) {
+            size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
+            size_t const newSize = HUF_estimateCompressedSize(table->CTable, table->count, maxSymbolValue);
+            if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
+                return HUF_compressCTable_internal(ostart, op, oend,
+                                                   src, srcSize,
+                                                   nbStreams, oldHufTable, bmi2);
+        }   }
+
+        /* Use the new huffman table */
+        if (hSize + 12ul >= srcSize) { return 0; }
+        op += hSize;
+        if (repeat) { *repeat = HUF_repeat_none; }
+        if (oldHufTable)
+            memcpy(oldHufTable, table->CTable, sizeof(table->CTable));  /* Save new table */
+    }
+    return HUF_compressCTable_internal(ostart, op, oend,
+                                       src, srcSize,
+                                       nbStreams, table->CTable, bmi2);
+}
+
+
+size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
+                      const void* src, size_t srcSize,
+                      unsigned maxSymbolValue, unsigned huffLog,
+                      void* workSpace, size_t wkspSize)
+{
+    return HUF_compress_internal(dst, dstSize, src, srcSize,
+                                 maxSymbolValue, huffLog, HUF_singleStream,
+                                 workSpace, wkspSize,
+                                 NULL, NULL, 0, 0 /*bmi2*/);
+}
+
+size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
+                      const void* src, size_t srcSize,
+                      unsigned maxSymbolValue, unsigned huffLog,
+                      void* workSpace, size_t wkspSize,
+                      HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
+{
+    return HUF_compress_internal(dst, dstSize, src, srcSize,
+                                 maxSymbolValue, huffLog, HUF_singleStream,
+                                 workSpace, wkspSize, hufTable,
+                                 repeat, preferRepeat, bmi2);
+}
+
+size_t HUF_compress1X (void* dst, size_t dstSize,
+                 const void* src, size_t srcSize,
+                 unsigned maxSymbolValue, unsigned huffLog)
+{
+    unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+    return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
+/* HUF_compress4X_repeat():
+ * compress input using 4 streams.
+ * provide workspace to generate compression tables */
+size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
+                      const void* src, size_t srcSize,
+                      unsigned maxSymbolValue, unsigned huffLog,
+                      void* workSpace, size_t wkspSize)
+{
+    return HUF_compress_internal(dst, dstSize, src, srcSize,
+                                 maxSymbolValue, huffLog, HUF_fourStreams,
+                                 workSpace, wkspSize,
+                                 NULL, NULL, 0, 0 /*bmi2*/);
+}
+
+/* HUF_compress4X_repeat():
+ * compress input using 4 streams.
+ * re-use an existing huffman compression table */
+size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
+                      const void* src, size_t srcSize,
+                      unsigned maxSymbolValue, unsigned huffLog,
+                      void* workSpace, size_t wkspSize,
+                      HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
+{
+    return HUF_compress_internal(dst, dstSize, src, srcSize,
+                                 maxSymbolValue, huffLog, HUF_fourStreams,
+                                 workSpace, wkspSize,
+                                 hufTable, repeat, preferRepeat, bmi2);
+}
+
+size_t HUF_compress2 (void* dst, size_t dstSize,
+                const void* src, size_t srcSize,
+                unsigned maxSymbolValue, unsigned huffLog)
+{
+    unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+    return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
+size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
+{
+    return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_compress.c b/Utilities/cmzstd/lib/compress/zstd_compress.c
new file mode 100644
index 0000000..c2c9d3b
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_compress.c
@@ -0,0 +1,4290 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include <limits.h>         /* INT_MAX */
+#include <string.h>         /* memset */
+#include "cpu.h"
+#include "mem.h"
+#include "hist.h"           /* HIST_countFast_wksp */
+#define FSE_STATIC_LINKING_ONLY   /* FSE_encodeSymbol */
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_compress_internal.h"
+#include "zstd_fast.h"
+#include "zstd_double_fast.h"
+#include "zstd_lazy.h"
+#include "zstd_opt.h"
+#include "zstd_ldm.h"
+
+
+/*-*************************************
+*  Helper functions
+***************************************/
+size_t ZSTD_compressBound(size_t srcSize) {
+    return ZSTD_COMPRESSBOUND(srcSize);
+}
+
+
+/*-*************************************
+*  Context memory management
+***************************************/
+struct ZSTD_CDict_s {
+    void* dictBuffer;
+    const void* dictContent;
+    size_t dictContentSize;
+    void* workspace;
+    size_t workspaceSize;
+    ZSTD_matchState_t matchState;
+    ZSTD_compressedBlockState_t cBlockState;
+    ZSTD_customMem customMem;
+    U32 dictID;
+};  /* typedef'd to ZSTD_CDict within "zstd.h" */
+
+ZSTD_CCtx* ZSTD_createCCtx(void)
+{
+    return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
+}
+
+static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
+{
+    assert(cctx != NULL);
+    memset(cctx, 0, sizeof(*cctx));
+    cctx->customMem = memManager;
+    cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+    {   size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
+        assert(!ZSTD_isError(err));
+        (void)err;
+    }
+}
+
+ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
+{
+    ZSTD_STATIC_ASSERT(zcss_init==0);
+    ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
+    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+    {   ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
+        if (!cctx) return NULL;
+        ZSTD_initCCtx(cctx, customMem);
+        return cctx;
+    }
+}
+
+ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
+{
+    ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace;
+    if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL;  /* minimum size */
+    if ((size_t)workspace & 7) return NULL;  /* must be 8-aligned */
+    memset(workspace, 0, workspaceSize);   /* may be a bit generous, could memset be smaller ? */
+    cctx->staticSize = workspaceSize;
+    cctx->workSpace = (void*)(cctx+1);
+    cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
+
+    /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
+    if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL;
+    assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0);   /* ensure correct alignment */
+    cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace;
+    cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1;
+    {
+        void* const ptr = cctx->blockState.nextCBlock + 1;
+        cctx->entropyWorkspace = (U32*)ptr;
+    }
+    cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+    return cctx;
+}
+
+static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
+{
+    assert(cctx != NULL);
+    assert(cctx->staticSize == 0);
+    ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
+    ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL;
+#ifdef ZSTD_MULTITHREAD
+    ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
+#endif
+}
+
+size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
+{
+    if (cctx==NULL) return 0;   /* support free on NULL */
+    if (cctx->staticSize) return ERROR(memory_allocation);   /* not compatible with static CCtx */
+    ZSTD_freeCCtxContent(cctx);
+    ZSTD_free(cctx, cctx->customMem);
+    return 0;
+}
+
+
+static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+    return ZSTDMT_sizeof_CCtx(cctx->mtctx);
+#else
+    (void)cctx;
+    return 0;
+#endif
+}
+
+
+size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
+{
+    if (cctx==NULL) return 0;   /* support sizeof on NULL */
+    return sizeof(*cctx) + cctx->workSpaceSize
+           + ZSTD_sizeof_CDict(cctx->cdictLocal)
+           + ZSTD_sizeof_mtctx(cctx);
+}
+
+size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
+{
+    return ZSTD_sizeof_CCtx(zcs);  /* same object */
+}
+
+/* private API call, for dictBuilder only */
+const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
+
+static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
+        ZSTD_compressionParameters cParams)
+{
+    ZSTD_CCtx_params cctxParams;
+    memset(&cctxParams, 0, sizeof(cctxParams));
+    cctxParams.cParams = cParams;
+    cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;  /* should not matter, as all cParams are presumed properly defined */
+    assert(!ZSTD_checkCParams(cParams));
+    cctxParams.fParams.contentSizeFlag = 1;
+    return cctxParams;
+}
+
+static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
+        ZSTD_customMem customMem)
+{
+    ZSTD_CCtx_params* params;
+    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+    params = (ZSTD_CCtx_params*)ZSTD_calloc(
+            sizeof(ZSTD_CCtx_params), customMem);
+    if (!params) { return NULL; }
+    params->customMem = customMem;
+    params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
+    params->fParams.contentSizeFlag = 1;
+    return params;
+}
+
+ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
+{
+    return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
+{
+    if (params == NULL) { return 0; }
+    ZSTD_free(params, params->customMem);
+    return 0;
+}
+
+size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
+{
+    return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
+}
+
+size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
+    if (!cctxParams) { return ERROR(GENERIC); }
+    memset(cctxParams, 0, sizeof(*cctxParams));
+    cctxParams->compressionLevel = compressionLevel;
+    cctxParams->fParams.contentSizeFlag = 1;
+    return 0;
+}
+
+size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
+{
+    if (!cctxParams) { return ERROR(GENERIC); }
+    CHECK_F( ZSTD_checkCParams(params.cParams) );
+    memset(cctxParams, 0, sizeof(*cctxParams));
+    cctxParams->cParams = params.cParams;
+    cctxParams->fParams = params.fParams;
+    cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT;   /* should not matter, as all cParams are presumed properly defined */
+    assert(!ZSTD_checkCParams(params.cParams));
+    return 0;
+}
+
+/* ZSTD_assignParamsToCCtxParams() :
+ * params is presumed valid at this stage */
+static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
+        ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
+{
+    ZSTD_CCtx_params ret = cctxParams;
+    ret.cParams = params.cParams;
+    ret.fParams = params.fParams;
+    ret.compressionLevel = ZSTD_CLEVEL_DEFAULT;   /* should not matter, as all cParams are presumed properly defined */
+    assert(!ZSTD_checkCParams(params.cParams));
+    return ret;
+}
+
+ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
+{
+    ZSTD_bounds bounds = { 0, 0, 0 };
+
+    switch(param)
+    {
+    case ZSTD_c_compressionLevel:
+        bounds.lowerBound = ZSTD_minCLevel();
+        bounds.upperBound = ZSTD_maxCLevel();
+        return bounds;
+
+    case ZSTD_c_windowLog:
+        bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
+        bounds.upperBound = ZSTD_WINDOWLOG_MAX;
+        return bounds;
+
+    case ZSTD_c_hashLog:
+        bounds.lowerBound = ZSTD_HASHLOG_MIN;
+        bounds.upperBound = ZSTD_HASHLOG_MAX;
+        return bounds;
+
+    case ZSTD_c_chainLog:
+        bounds.lowerBound = ZSTD_CHAINLOG_MIN;
+        bounds.upperBound = ZSTD_CHAINLOG_MAX;
+        return bounds;
+
+    case ZSTD_c_searchLog:
+        bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
+        bounds.upperBound = ZSTD_SEARCHLOG_MAX;
+        return bounds;
+
+    case ZSTD_c_minMatch:
+        bounds.lowerBound = ZSTD_MINMATCH_MIN;
+        bounds.upperBound = ZSTD_MINMATCH_MAX;
+        return bounds;
+
+    case ZSTD_c_targetLength:
+        bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
+        bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
+        return bounds;
+
+    case ZSTD_c_strategy:
+        bounds.lowerBound = ZSTD_STRATEGY_MIN;
+        bounds.upperBound = ZSTD_STRATEGY_MAX;
+        return bounds;
+
+    case ZSTD_c_contentSizeFlag:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_checksumFlag:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_dictIDFlag:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_nbWorkers:
+        bounds.lowerBound = 0;
+#ifdef ZSTD_MULTITHREAD
+        bounds.upperBound = ZSTDMT_NBWORKERS_MAX;
+#else
+        bounds.upperBound = 0;
+#endif
+        return bounds;
+
+    case ZSTD_c_jobSize:
+        bounds.lowerBound = 0;
+#ifdef ZSTD_MULTITHREAD
+        bounds.upperBound = ZSTDMT_JOBSIZE_MAX;
+#else
+        bounds.upperBound = 0;
+#endif
+        return bounds;
+
+    case ZSTD_c_overlapLog:
+        bounds.lowerBound = ZSTD_OVERLAPLOG_MIN;
+        bounds.upperBound = ZSTD_OVERLAPLOG_MAX;
+        return bounds;
+
+    case ZSTD_c_enableLongDistanceMatching:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_ldmHashLog:
+        bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
+        bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
+        return bounds;
+
+    case ZSTD_c_ldmMinMatch:
+        bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
+        bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
+        return bounds;
+
+    case ZSTD_c_ldmBucketSizeLog:
+        bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
+        bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
+        return bounds;
+
+    case ZSTD_c_ldmHashRateLog:
+        bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
+        bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
+        return bounds;
+
+    /* experimental parameters */
+    case ZSTD_c_rsyncable:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_forceMaxWindow :
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_format:
+        ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
+        bounds.lowerBound = ZSTD_f_zstd1;
+        bounds.upperBound = ZSTD_f_zstd1_magicless;   /* note : how to ensure at compile time that this is the highest value enum ? */
+        return bounds;
+
+    case ZSTD_c_forceAttachDict:
+        ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
+        bounds.lowerBound = ZSTD_dictDefaultAttach;
+        bounds.upperBound = ZSTD_dictForceCopy;       /* note : how to ensure at compile time that this is the highest value enum ? */
+        return bounds;
+
+    default:
+        {   ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 };
+            return boundError;
+        }
+    }
+}
+
+/* ZSTD_cParam_withinBounds:
+ * @return 1 if value is within cParam bounds,
+ * 0 otherwise */
+static int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
+{
+    ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
+    if (ZSTD_isError(bounds.error)) return 0;
+    if (value < bounds.lowerBound) return 0;
+    if (value > bounds.upperBound) return 0;
+    return 1;
+}
+
+#define BOUNDCHECK(cParam, val) {                  \
+    if (!ZSTD_cParam_withinBounds(cParam,val)) {   \
+        return ERROR(parameter_outOfBound);        \
+}   }
+
+
+static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
+{
+    switch(param)
+    {
+    case ZSTD_c_compressionLevel:
+    case ZSTD_c_hashLog:
+    case ZSTD_c_chainLog:
+    case ZSTD_c_searchLog:
+    case ZSTD_c_minMatch:
+    case ZSTD_c_targetLength:
+    case ZSTD_c_strategy:
+        return 1;
+
+    case ZSTD_c_format:
+    case ZSTD_c_windowLog:
+    case ZSTD_c_contentSizeFlag:
+    case ZSTD_c_checksumFlag:
+    case ZSTD_c_dictIDFlag:
+    case ZSTD_c_forceMaxWindow :
+    case ZSTD_c_nbWorkers:
+    case ZSTD_c_jobSize:
+    case ZSTD_c_overlapLog:
+    case ZSTD_c_rsyncable:
+    case ZSTD_c_enableLongDistanceMatching:
+    case ZSTD_c_ldmHashLog:
+    case ZSTD_c_ldmMinMatch:
+    case ZSTD_c_ldmBucketSizeLog:
+    case ZSTD_c_ldmHashRateLog:
+    case ZSTD_c_forceAttachDict:
+    default:
+        return 0;
+    }
+}
+
+size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
+{
+    DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
+    if (cctx->streamStage != zcss_init) {
+        if (ZSTD_isUpdateAuthorized(param)) {
+            cctx->cParamsChanged = 1;
+        } else {
+            return ERROR(stage_wrong);
+    }   }
+
+    switch(param)
+    {
+    case ZSTD_c_format :
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_compressionLevel:
+        if (cctx->cdict) return ERROR(stage_wrong);
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_windowLog:
+    case ZSTD_c_hashLog:
+    case ZSTD_c_chainLog:
+    case ZSTD_c_searchLog:
+    case ZSTD_c_minMatch:
+    case ZSTD_c_targetLength:
+    case ZSTD_c_strategy:
+        if (cctx->cdict) return ERROR(stage_wrong);
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_contentSizeFlag:
+    case ZSTD_c_checksumFlag:
+    case ZSTD_c_dictIDFlag:
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_forceMaxWindow :  /* Force back-references to remain < windowSize,
+                                   * even when referencing into Dictionary content.
+                                   * default : 0 when using a CDict, 1 when using a Prefix */
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_forceAttachDict:
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_nbWorkers:
+        if ((value!=0) && cctx->staticSize) {
+            return ERROR(parameter_unsupported);  /* MT not compatible with static alloc */
+        }
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_jobSize:
+    case ZSTD_c_overlapLog:
+    case ZSTD_c_rsyncable:
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    case ZSTD_c_enableLongDistanceMatching:
+    case ZSTD_c_ldmHashLog:
+    case ZSTD_c_ldmMinMatch:
+    case ZSTD_c_ldmBucketSizeLog:
+    case ZSTD_c_ldmHashRateLog:
+        if (cctx->cdict) return ERROR(stage_wrong);
+        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
+
+    default: return ERROR(parameter_unsupported);
+    }
+}
+
+size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* CCtxParams,
+                                   ZSTD_cParameter param, int value)
+{
+    DEBUGLOG(4, "ZSTD_CCtxParam_setParameter (%i, %i)", (int)param, value);
+    switch(param)
+    {
+    case ZSTD_c_format :
+        BOUNDCHECK(ZSTD_c_format, value);
+        CCtxParams->format = (ZSTD_format_e)value;
+        return (size_t)CCtxParams->format;
+
+    case ZSTD_c_compressionLevel : {
+        int cLevel = value;
+        if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
+        if (cLevel < ZSTD_minCLevel()) cLevel = ZSTD_minCLevel();
+        if (cLevel) {  /* 0 : does not change current level */
+            CCtxParams->compressionLevel = cLevel;
+        }
+        if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel;
+        return 0;  /* return type (size_t) cannot represent negative values */
+    }
+
+    case ZSTD_c_windowLog :
+        if (value!=0)   /* 0 => use default */
+            BOUNDCHECK(ZSTD_c_windowLog, value);
+        CCtxParams->cParams.windowLog = value;
+        return CCtxParams->cParams.windowLog;
+
+    case ZSTD_c_hashLog :
+        if (value!=0)   /* 0 => use default */
+            BOUNDCHECK(ZSTD_c_hashLog, value);
+        CCtxParams->cParams.hashLog = value;
+        return CCtxParams->cParams.hashLog;
+
+    case ZSTD_c_chainLog :
+        if (value!=0)   /* 0 => use default */
+            BOUNDCHECK(ZSTD_c_chainLog, value);
+        CCtxParams->cParams.chainLog = value;
+        return CCtxParams->cParams.chainLog;
+
+    case ZSTD_c_searchLog :
+        if (value!=0)   /* 0 => use default */
+            BOUNDCHECK(ZSTD_c_searchLog, value);
+        CCtxParams->cParams.searchLog = value;
+        return value;
+
+    case ZSTD_c_minMatch :
+        if (value!=0)   /* 0 => use default */
+            BOUNDCHECK(ZSTD_c_minMatch, value);
+        CCtxParams->cParams.minMatch = value;
+        return CCtxParams->cParams.minMatch;
+
+    case ZSTD_c_targetLength :
+        BOUNDCHECK(ZSTD_c_targetLength, value);
+        CCtxParams->cParams.targetLength = value;
+        return CCtxParams->cParams.targetLength;
+
+    case ZSTD_c_strategy :
+        if (value!=0)   /* 0 => use default */
+            BOUNDCHECK(ZSTD_c_strategy, value);
+        CCtxParams->cParams.strategy = (ZSTD_strategy)value;
+        return (size_t)CCtxParams->cParams.strategy;
+
+    case ZSTD_c_contentSizeFlag :
+        /* Content size written in frame header _when known_ (default:1) */
+        DEBUGLOG(4, "set content size flag = %u", (value!=0));
+        CCtxParams->fParams.contentSizeFlag = value != 0;
+        return CCtxParams->fParams.contentSizeFlag;
+
+    case ZSTD_c_checksumFlag :
+        /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
+        CCtxParams->fParams.checksumFlag = value != 0;
+        return CCtxParams->fParams.checksumFlag;
+
+    case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
+        DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
+        CCtxParams->fParams.noDictIDFlag = !value;
+        return !CCtxParams->fParams.noDictIDFlag;
+
+    case ZSTD_c_forceMaxWindow :
+        CCtxParams->forceWindow = (value != 0);
+        return CCtxParams->forceWindow;
+
+    case ZSTD_c_forceAttachDict : {
+        const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
+        BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
+        CCtxParams->attachDictPref = pref;
+        return CCtxParams->attachDictPref;
+    }
+
+    case ZSTD_c_nbWorkers :
+#ifndef ZSTD_MULTITHREAD
+        if (value!=0) return ERROR(parameter_unsupported);
+        return 0;
+#else
+        return ZSTDMT_CCtxParam_setNbWorkers(CCtxParams, value);
+#endif
+
+    case ZSTD_c_jobSize :
+#ifndef ZSTD_MULTITHREAD
+        return ERROR(parameter_unsupported);
+#else
+        return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value);
+#endif
+
+    case ZSTD_c_overlapLog :
+#ifndef ZSTD_MULTITHREAD
+        return ERROR(parameter_unsupported);
+#else
+        return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapLog, value);
+#endif
+
+    case ZSTD_c_rsyncable :
+#ifndef ZSTD_MULTITHREAD
+        return ERROR(parameter_unsupported);
+#else
+        return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_rsyncable, value);
+#endif
+
+    case ZSTD_c_enableLongDistanceMatching :
+        CCtxParams->ldmParams.enableLdm = (value!=0);
+        return CCtxParams->ldmParams.enableLdm;
+
+    case ZSTD_c_ldmHashLog :
+        if (value!=0)   /* 0 ==> auto */
+            BOUNDCHECK(ZSTD_c_ldmHashLog, value);
+        CCtxParams->ldmParams.hashLog = value;
+        return CCtxParams->ldmParams.hashLog;
+
+    case ZSTD_c_ldmMinMatch :
+        if (value!=0)   /* 0 ==> default */
+            BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
+        CCtxParams->ldmParams.minMatchLength = value;
+        return CCtxParams->ldmParams.minMatchLength;
+
+    case ZSTD_c_ldmBucketSizeLog :
+        if (value!=0)   /* 0 ==> default */
+            BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
+        CCtxParams->ldmParams.bucketSizeLog = value;
+        return CCtxParams->ldmParams.bucketSizeLog;
+
+    case ZSTD_c_ldmHashRateLog :
+        if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
+            return ERROR(parameter_outOfBound);
+        CCtxParams->ldmParams.hashRateLog = value;
+        return CCtxParams->ldmParams.hashRateLog;
+
+    default: return ERROR(parameter_unsupported);
+    }
+}
+
+size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
+{
+    return ZSTD_CCtxParam_getParameter(&cctx->requestedParams, param, value);
+}
+
+size_t ZSTD_CCtxParam_getParameter(
+        ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
+{
+    switch(param)
+    {
+    case ZSTD_c_format :
+        *value = CCtxParams->format;
+        break;
+    case ZSTD_c_compressionLevel :
+        *value = CCtxParams->compressionLevel;
+        break;
+    case ZSTD_c_windowLog :
+        *value = CCtxParams->cParams.windowLog;
+        break;
+    case ZSTD_c_hashLog :
+        *value = CCtxParams->cParams.hashLog;
+        break;
+    case ZSTD_c_chainLog :
+        *value = CCtxParams->cParams.chainLog;
+        break;
+    case ZSTD_c_searchLog :
+        *value = CCtxParams->cParams.searchLog;
+        break;
+    case ZSTD_c_minMatch :
+        *value = CCtxParams->cParams.minMatch;
+        break;
+    case ZSTD_c_targetLength :
+        *value = CCtxParams->cParams.targetLength;
+        break;
+    case ZSTD_c_strategy :
+        *value = (unsigned)CCtxParams->cParams.strategy;
+        break;
+    case ZSTD_c_contentSizeFlag :
+        *value = CCtxParams->fParams.contentSizeFlag;
+        break;
+    case ZSTD_c_checksumFlag :
+        *value = CCtxParams->fParams.checksumFlag;
+        break;
+    case ZSTD_c_dictIDFlag :
+        *value = !CCtxParams->fParams.noDictIDFlag;
+        break;
+    case ZSTD_c_forceMaxWindow :
+        *value = CCtxParams->forceWindow;
+        break;
+    case ZSTD_c_forceAttachDict :
+        *value = CCtxParams->attachDictPref;
+        break;
+    case ZSTD_c_nbWorkers :
+#ifndef ZSTD_MULTITHREAD
+        assert(CCtxParams->nbWorkers == 0);
+#endif
+        *value = CCtxParams->nbWorkers;
+        break;
+    case ZSTD_c_jobSize :
+#ifndef ZSTD_MULTITHREAD
+        return ERROR(parameter_unsupported);
+#else
+        assert(CCtxParams->jobSize <= INT_MAX);
+        *value = (int)CCtxParams->jobSize;
+        break;
+#endif
+    case ZSTD_c_overlapLog :
+#ifndef ZSTD_MULTITHREAD
+        return ERROR(parameter_unsupported);
+#else
+        *value = CCtxParams->overlapLog;
+        break;
+#endif
+    case ZSTD_c_rsyncable :
+#ifndef ZSTD_MULTITHREAD
+        return ERROR(parameter_unsupported);
+#else
+        *value = CCtxParams->rsyncable;
+        break;
+#endif
+    case ZSTD_c_enableLongDistanceMatching :
+        *value = CCtxParams->ldmParams.enableLdm;
+        break;
+    case ZSTD_c_ldmHashLog :
+        *value = CCtxParams->ldmParams.hashLog;
+        break;
+    case ZSTD_c_ldmMinMatch :
+        *value = CCtxParams->ldmParams.minMatchLength;
+        break;
+    case ZSTD_c_ldmBucketSizeLog :
+        *value = CCtxParams->ldmParams.bucketSizeLog;
+        break;
+    case ZSTD_c_ldmHashRateLog :
+        *value = CCtxParams->ldmParams.hashRateLog;
+        break;
+    default: return ERROR(parameter_unsupported);
+    }
+    return 0;
+}
+
+/** ZSTD_CCtx_setParametersUsingCCtxParams() :
+ *  just applies `params` into `cctx`
+ *  no action is performed, parameters are merely stored.
+ *  If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
+ *    This is possible even if a compression is ongoing.
+ *    In which case, new parameters will be applied on the fly, starting with next compression job.
+ */
+size_t ZSTD_CCtx_setParametersUsingCCtxParams(
+        ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
+{
+    DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
+    if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+    if (cctx->cdict) return ERROR(stage_wrong);
+
+    cctx->requestedParams = *params;
+    return 0;
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
+    if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+    cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+    return 0;
+}
+
+size_t ZSTD_CCtx_loadDictionary_advanced(
+        ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
+        ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
+{
+    if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+    if (cctx->staticSize) return ERROR(memory_allocation);  /* no malloc for static CCtx */
+    DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
+    ZSTD_freeCDict(cctx->cdictLocal);  /* in case one already exists */
+    if (dict==NULL || dictSize==0) {   /* no dictionary mode */
+        cctx->cdictLocal = NULL;
+        cctx->cdict = NULL;
+    } else {
+        ZSTD_compressionParameters const cParams =
+                ZSTD_getCParamsFromCCtxParams(&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize);
+        cctx->cdictLocal = ZSTD_createCDict_advanced(
+                                dict, dictSize,
+                                dictLoadMethod, dictContentType,
+                                cParams, cctx->customMem);
+        cctx->cdict = cctx->cdictLocal;
+        if (cctx->cdictLocal == NULL)
+            return ERROR(memory_allocation);
+    }
+    return 0;
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
+      ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+{
+    return ZSTD_CCtx_loadDictionary_advanced(
+            cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+{
+    return ZSTD_CCtx_loadDictionary_advanced(
+            cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
+}
+
+
+size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
+{
+    if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+    cctx->cdict = cdict;
+    memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));  /* exclusive */
+    return 0;
+}
+
+size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
+{
+    return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
+}
+
+size_t ZSTD_CCtx_refPrefix_advanced(
+        ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
+{
+    if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+    cctx->cdict = NULL;   /* prefix discards any prior cdict */
+    cctx->prefixDict.dict = prefix;
+    cctx->prefixDict.dictSize = prefixSize;
+    cctx->prefixDict.dictContentType = dictContentType;
+    return 0;
+}
+
+/*! ZSTD_CCtx_reset() :
+ *  Also dumps dictionary */
+size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
+{
+    if ( (reset == ZSTD_reset_session_only)
+      || (reset == ZSTD_reset_session_and_parameters) ) {
+        cctx->streamStage = zcss_init;
+        cctx->pledgedSrcSizePlusOne = 0;
+    }
+    if ( (reset == ZSTD_reset_parameters)
+      || (reset == ZSTD_reset_session_and_parameters) ) {
+        if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
+        cctx->cdict = NULL;
+        return ZSTD_CCtxParams_reset(&cctx->requestedParams);
+    }
+    return 0;
+}
+
+
+/** ZSTD_checkCParams() :
+    control CParam values remain within authorized range.
+    @return : 0, or an error code if one value is beyond authorized range */
+size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
+{
+    BOUNDCHECK(ZSTD_c_windowLog, cParams.windowLog);
+    BOUNDCHECK(ZSTD_c_chainLog,  cParams.chainLog);
+    BOUNDCHECK(ZSTD_c_hashLog,   cParams.hashLog);
+    BOUNDCHECK(ZSTD_c_searchLog, cParams.searchLog);
+    BOUNDCHECK(ZSTD_c_minMatch,  cParams.minMatch);
+    BOUNDCHECK(ZSTD_c_targetLength,cParams.targetLength);
+    BOUNDCHECK(ZSTD_c_strategy,  cParams.strategy);
+    return 0;
+}
+
+/** ZSTD_clampCParams() :
+ *  make CParam values within valid range.
+ *  @return : valid CParams */
+static ZSTD_compressionParameters
+ZSTD_clampCParams(ZSTD_compressionParameters cParams)
+{
+#   define CLAMP_TYPE(cParam, val, type) {                                \
+        ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);         \
+        if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound;      \
+        else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
+    }
+#   define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, int)
+    CLAMP(ZSTD_c_windowLog, cParams.windowLog);
+    CLAMP(ZSTD_c_chainLog,  cParams.chainLog);
+    CLAMP(ZSTD_c_hashLog,   cParams.hashLog);
+    CLAMP(ZSTD_c_searchLog, cParams.searchLog);
+    CLAMP(ZSTD_c_minMatch,  cParams.minMatch);
+    CLAMP(ZSTD_c_targetLength,cParams.targetLength);
+    CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
+    return cParams;
+}
+
+/** ZSTD_cycleLog() :
+ *  condition for correct operation : hashLog > 1 */
+static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
+{
+    U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
+    return hashLog - btScale;
+}
+
+/** ZSTD_adjustCParams_internal() :
+    optimize `cPar` for a given input (`srcSize` and `dictSize`).
+    mostly downsizing to reduce memory consumption and initialization latency.
+    Both `srcSize` and `dictSize` are optional (use 0 if unknown).
+    Note : cPar is assumed validated. Use ZSTD_checkCParams() to ensure this condition. */
+static ZSTD_compressionParameters
+ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
+                            unsigned long long srcSize,
+                            size_t dictSize)
+{
+    static const U64 minSrcSize = 513; /* (1<<9) + 1 */
+    static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
+    assert(ZSTD_checkCParams(cPar)==0);
+
+    if (dictSize && (srcSize+1<2) /* srcSize unknown */ )
+        srcSize = minSrcSize;  /* presumed small when there is a dictionary */
+    else if (srcSize == 0)
+        srcSize = ZSTD_CONTENTSIZE_UNKNOWN;  /* 0 == unknown : presumed large */
+
+    /* resize windowLog if input is small enough, to use less memory */
+    if ( (srcSize < maxWindowResize)
+      && (dictSize < maxWindowResize) )  {
+        U32 const tSize = (U32)(srcSize + dictSize);
+        static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
+        U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
+                            ZSTD_highbit32(tSize-1) + 1;
+        if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
+    }
+    if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
+    {   U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
+        if (cycleLog > cPar.windowLog)
+            cPar.chainLog -= (cycleLog - cPar.windowLog);
+    }
+
+    if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
+        cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN;  /* required for frame header */
+
+    return cPar;
+}
+
+ZSTD_compressionParameters
+ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
+                   unsigned long long srcSize,
+                   size_t dictSize)
+{
+    cPar = ZSTD_clampCParams(cPar);
+    return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
+}
+
+ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
+        const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
+{
+    ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
+    if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
+    if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
+    if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
+    if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
+    if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
+    if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
+    if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
+    if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
+    assert(!ZSTD_checkCParams(cParams));
+    return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
+}
+
+static size_t
+ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
+                       const U32 forCCtx)
+{
+    size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+    size_t const hSize = ((size_t)1) << cParams->hashLog;
+    U32    const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
+    size_t const h3Size = ((size_t)1) << hashLog3;
+    size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+    size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
+                          + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
+    size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
+                                ? optPotentialSpace
+                                : 0;
+    DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
+                (U32)chainSize, (U32)hSize, (U32)h3Size);
+    return tableSpace + optSpace;
+}
+
+size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
+{
+    /* Estimate CCtx size is supported for single-threaded compression only. */
+    if (params->nbWorkers > 0) { return ERROR(GENERIC); }
+    {   ZSTD_compressionParameters const cParams =
+                ZSTD_getCParamsFromCCtxParams(params, 0, 0);
+        size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
+        U32    const divider = (cParams.minMatch==3) ? 3 : 4;
+        size_t const maxNbSeq = blockSize / divider;
+        size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
+        size_t const entropySpace = HUF_WORKSPACE_SIZE;
+        size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
+        size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
+
+        size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
+        size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq);
+
+        size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
+                                   matchStateSize + ldmSpace + ldmSeqSpace;
+
+        DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
+        DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
+        return sizeof(ZSTD_CCtx) + neededSpace;
+    }
+}
+
+size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
+{
+    ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
+    return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
+}
+
+static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
+{
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
+    return ZSTD_estimateCCtxSize_usingCParams(cParams);
+}
+
+size_t ZSTD_estimateCCtxSize(int compressionLevel)
+{
+    int level;
+    size_t memBudget = 0;
+    for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+        size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
+        if (newMB > memBudget) memBudget = newMB;
+    }
+    return memBudget;
+}
+
+size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
+{
+    if (params->nbWorkers > 0) { return ERROR(GENERIC); }
+    {   size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
+        size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
+        size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
+        size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
+        size_t const streamingSize = inBuffSize + outBuffSize;
+
+        return CCtxSize + streamingSize;
+    }
+}
+
+size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
+{
+    ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
+    return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
+}
+
+static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
+{
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
+    return ZSTD_estimateCStreamSize_usingCParams(cParams);
+}
+
+size_t ZSTD_estimateCStreamSize(int compressionLevel)
+{
+    int level;
+    size_t memBudget = 0;
+    for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+        size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
+        if (newMB > memBudget) memBudget = newMB;
+    }
+    return memBudget;
+}
+
+/* ZSTD_getFrameProgression():
+ * tells how much data has been consumed (input) and produced (output) for current frame.
+ * able to count progression inside worker threads (non-blocking mode).
+ */
+ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+    if (cctx->appliedParams.nbWorkers > 0) {
+        return ZSTDMT_getFrameProgression(cctx->mtctx);
+    }
+#endif
+    {   ZSTD_frameProgression fp;
+        size_t const buffered = (cctx->inBuff == NULL) ? 0 :
+                                cctx->inBuffPos - cctx->inToCompress;
+        if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
+        assert(buffered <= ZSTD_BLOCKSIZE_MAX);
+        fp.ingested = cctx->consumedSrcSize + buffered;
+        fp.consumed = cctx->consumedSrcSize;
+        fp.produced = cctx->producedCSize;
+        fp.flushed  = cctx->producedCSize;   /* simplified; some data might still be left within streaming output buffer */
+        fp.currentJobID = 0;
+        fp.nbActiveWorkers = 0;
+        return fp;
+}   }
+
+/*! ZSTD_toFlushNow()
+ *  Only useful for multithreading scenarios currently (nbWorkers >= 1).
+ */
+size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+    if (cctx->appliedParams.nbWorkers > 0) {
+        return ZSTDMT_toFlushNow(cctx->mtctx);
+    }
+#endif
+    (void)cctx;
+    return 0;   /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */
+}
+
+
+
+static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
+                                  ZSTD_compressionParameters cParams2)
+{
+    return (cParams1.hashLog  == cParams2.hashLog)
+         & (cParams1.chainLog == cParams2.chainLog)
+         & (cParams1.strategy == cParams2.strategy)   /* opt parser space */
+         & ((cParams1.minMatch==3) == (cParams2.minMatch==3));  /* hashlog3 space */
+}
+
+static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
+                                    ZSTD_compressionParameters cParams2)
+{
+    (void)cParams1;
+    (void)cParams2;
+    assert(cParams1.windowLog    == cParams2.windowLog);
+    assert(cParams1.chainLog     == cParams2.chainLog);
+    assert(cParams1.hashLog      == cParams2.hashLog);
+    assert(cParams1.searchLog    == cParams2.searchLog);
+    assert(cParams1.minMatch     == cParams2.minMatch);
+    assert(cParams1.targetLength == cParams2.targetLength);
+    assert(cParams1.strategy     == cParams2.strategy);
+}
+
+/** The parameters are equivalent if ldm is not enabled in both sets or
+ *  all the parameters are equivalent. */
+static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
+                                    ldmParams_t ldmParams2)
+{
+    return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
+           (ldmParams1.enableLdm == ldmParams2.enableLdm &&
+            ldmParams1.hashLog == ldmParams2.hashLog &&
+            ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
+            ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
+            ldmParams1.hashRateLog == ldmParams2.hashRateLog);
+}
+
+typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
+
+/* ZSTD_sufficientBuff() :
+ * check internal buffers exist for streaming if buffPol == ZSTDb_buffered .
+ * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */
+static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1,
+                            size_t maxNbLit1,
+                            ZSTD_buffered_policy_e buffPol2,
+                            ZSTD_compressionParameters cParams2,
+                            U64 pledgedSrcSize)
+{
+    size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
+    size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
+    size_t const maxNbSeq2 = blockSize2 / ((cParams2.minMatch == 3) ? 3 : 4);
+    size_t const maxNbLit2 = blockSize2;
+    size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
+    DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u",
+                (U32)neededBufferSize2, (U32)bufferSize1);
+    DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u",
+                (U32)maxNbSeq2, (U32)maxNbSeq1);
+    DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u",
+                (U32)maxNbLit2, (U32)maxNbLit1);
+    return (maxNbLit2 <= maxNbLit1)
+         & (maxNbSeq2 <= maxNbSeq1)
+         & (neededBufferSize2 <= bufferSize1);
+}
+
+/** Equivalence for resetCCtx purposes */
+static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
+                                 ZSTD_CCtx_params params2,
+                                 size_t buffSize1,
+                                 size_t maxNbSeq1, size_t maxNbLit1,
+                                 ZSTD_buffered_policy_e buffPol2,
+                                 U64 pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize);
+    if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) {
+      DEBUGLOG(4, "ZSTD_equivalentCParams() == 0");
+      return 0;
+    }
+    if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) {
+      DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0");
+      return 0;
+    }
+    if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2,
+                             params2.cParams, pledgedSrcSize)) {
+      DEBUGLOG(4, "ZSTD_sufficientBuff() == 0");
+      return 0;
+    }
+    return 1;
+}
+
+static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
+{
+    int i;
+    for (i = 0; i < ZSTD_REP_NUM; ++i)
+        bs->rep[i] = repStartValue[i];
+    bs->entropy.huf.repeatMode = HUF_repeat_none;
+    bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
+    bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
+    bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
+}
+
+/*! ZSTD_invalidateMatchState()
+ * Invalidate all the matches in the match finder tables.
+ * Requires nextSrc and base to be set (can be NULL).
+ */
+static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
+{
+    ZSTD_window_clear(&ms->window);
+
+    ms->nextToUpdate = ms->window.dictLimit;
+    ms->nextToUpdate3 = ms->window.dictLimit;
+    ms->loadedDictEnd = 0;
+    ms->opt.litLengthSum = 0;  /* force reset of btopt stats */
+    ms->dictMatchState = NULL;
+}
+
+/*! ZSTD_continueCCtx() :
+ *  reuse CCtx without reset (note : requires no dictionary) */
+static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
+{
+    size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+    size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
+    DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
+
+    cctx->blockSize = blockSize;   /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
+    cctx->appliedParams = params;
+    cctx->blockState.matchState.cParams = params.cParams;
+    cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+    cctx->consumedSrcSize = 0;
+    cctx->producedCSize = 0;
+    if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+        cctx->appliedParams.fParams.contentSizeFlag = 0;
+    DEBUGLOG(4, "pledged content size : %u ; flag : %u",
+        (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
+    cctx->stage = ZSTDcs_init;
+    cctx->dictID = 0;
+    if (params.ldmParams.enableLdm)
+        ZSTD_window_clear(&cctx->ldmState.window);
+    ZSTD_referenceExternalSequences(cctx, NULL, 0);
+    ZSTD_invalidateMatchState(&cctx->blockState.matchState);
+    ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock);
+    XXH64_reset(&cctx->xxhState, 0);
+    return 0;
+}
+
+typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
+
+static void*
+ZSTD_reset_matchState(ZSTD_matchState_t* ms,
+                      void* ptr,
+                const ZSTD_compressionParameters* cParams,
+                      ZSTD_compResetPolicy_e const crp, U32 const forCCtx)
+{
+    size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+    size_t const hSize = ((size_t)1) << cParams->hashLog;
+    U32    const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
+    size_t const h3Size = ((size_t)1) << hashLog3;
+    size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+
+    assert(((size_t)ptr & 3) == 0);
+
+    ms->hashLog3 = hashLog3;
+    memset(&ms->window, 0, sizeof(ms->window));
+    ms->window.dictLimit = 1;    /* start from 1, so that 1st position is valid */
+    ms->window.lowLimit = 1;     /* it ensures first and later CCtx usages compress the same */
+    ms->window.nextSrc = ms->window.base + 1;   /* see issue #1241 */
+    ZSTD_invalidateMatchState(ms);
+
+    /* opt parser space */
+    if (forCCtx && (cParams->strategy >= ZSTD_btopt)) {
+        DEBUGLOG(4, "reserving optimal parser space");
+        ms->opt.litFreq = (unsigned*)ptr;
+        ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits);
+        ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1);
+        ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1);
+        ptr = ms->opt.offCodeFreq + (MaxOff+1);
+        ms->opt.matchTable = (ZSTD_match_t*)ptr;
+        ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1;
+        ms->opt.priceTable = (ZSTD_optimal_t*)ptr;
+        ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1;
+    }
+
+    /* table Space */
+    DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
+    assert(((size_t)ptr & 3) == 0);  /* ensure ptr is properly aligned */
+    if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace);   /* reset tables only */
+    ms->hashTable = (U32*)(ptr);
+    ms->chainTable = ms->hashTable + hSize;
+    ms->hashTable3 = ms->chainTable + chainSize;
+    ptr = ms->hashTable3 + h3Size;
+
+    ms->cParams = *cParams;
+
+    assert(((size_t)ptr & 3) == 0);
+    return ptr;
+}
+
+#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */
+#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128  /* when workspace is continuously too large
+                                         * during at least this number of times,
+                                         * context's memory usage is considered wasteful,
+                                         * because it's sized to handle a worst case scenario which rarely happens.
+                                         * In which case, resize it down to free some memory */
+
+/*! ZSTD_resetCCtx_internal() :
+    note : `params` are assumed fully validated at this stage */
+static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
+                                      ZSTD_CCtx_params params,
+                                      U64 pledgedSrcSize,
+                                      ZSTD_compResetPolicy_e const crp,
+                                      ZSTD_buffered_policy_e const zbuff)
+{
+    DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
+                (U32)pledgedSrcSize, params.cParams.windowLog);
+    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+
+    if (crp == ZSTDcrp_continue) {
+        if (ZSTD_equivalentParams(zc->appliedParams, params,
+                                  zc->inBuffSize,
+                                  zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit,
+                                  zbuff, pledgedSrcSize)) {
+            DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)",
+                        zc->appliedParams.cParams.windowLog, zc->blockSize);
+            zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0);   /* if it was too large, it still is */
+            if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION)
+                return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
+    }   }
+    DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
+
+    if (params.ldmParams.enableLdm) {
+        /* Adjust long distance matching parameters */
+        ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
+        assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
+        assert(params.ldmParams.hashRateLog < 32);
+        zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+    }
+
+    {   size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+        size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
+        U32    const divider = (params.cParams.minMatch==3) ? 3 : 4;
+        size_t const maxNbSeq = blockSize / divider;
+        size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
+        size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
+        size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
+        size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
+        size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
+        void* ptr;   /* used to partition workSpace */
+
+        /* Check if workSpace is large enough, alloc a new one if needed */
+        {   size_t const entropySpace = HUF_WORKSPACE_SIZE;
+            size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
+            size_t const bufferSpace = buffInSize + buffOutSize;
+            size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
+            size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq);
+
+            size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
+                                       ldmSeqSpace + matchStateSize + tokenSpace +
+                                       bufferSpace;
+
+            int const workSpaceTooSmall = zc->workSpaceSize < neededSpace;
+            int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace;
+            int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION);
+            zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0;
+
+            DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
+                        neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
+            DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
+
+            if (workSpaceTooSmall || workSpaceWasteful) {
+                DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB",
+                            zc->workSpaceSize >> 10,
+                            neededSpace >> 10);
+                /* static cctx : no resize, error out */
+                if (zc->staticSize) return ERROR(memory_allocation);
+
+                zc->workSpaceSize = 0;
+                ZSTD_free(zc->workSpace, zc->customMem);
+                zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
+                if (zc->workSpace == NULL) return ERROR(memory_allocation);
+                zc->workSpaceSize = neededSpace;
+                zc->workSpaceOversizedDuration = 0;
+
+                /* Statically sized space.
+                 * entropyWorkspace never moves,
+                 * though prev/next block swap places */
+                assert(((size_t)zc->workSpace & 3) == 0);   /* ensure correct alignment */
+                assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
+                zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
+                zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1;
+                ptr = zc->blockState.nextCBlock + 1;
+                zc->entropyWorkspace = (U32*)ptr;
+        }   }
+
+        /* init params */
+        zc->appliedParams = params;
+        zc->blockState.matchState.cParams = params.cParams;
+        zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+        zc->consumedSrcSize = 0;
+        zc->producedCSize = 0;
+        if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+            zc->appliedParams.fParams.contentSizeFlag = 0;
+        DEBUGLOG(4, "pledged content size : %u ; flag : %u",
+            (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
+        zc->blockSize = blockSize;
+
+        XXH64_reset(&zc->xxhState, 0);
+        zc->stage = ZSTDcs_init;
+        zc->dictID = 0;
+
+        ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
+
+        ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
+
+        /* ldm hash table */
+        /* initialize bucketOffsets table later for pointer alignment */
+        if (params.ldmParams.enableLdm) {
+            size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
+            memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
+            assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
+            zc->ldmState.hashTable = (ldmEntry_t*)ptr;
+            ptr = zc->ldmState.hashTable + ldmHSize;
+            zc->ldmSequences = (rawSeq*)ptr;
+            ptr = zc->ldmSequences + maxNbLdmSeq;
+            zc->maxNbLdmSequences = maxNbLdmSeq;
+
+            memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window));
+        }
+        assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
+
+        ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, &params.cParams, crp, /* forCCtx */ 1);
+
+        /* sequences storage */
+        zc->seqStore.maxNbSeq = maxNbSeq;
+        zc->seqStore.sequencesStart = (seqDef*)ptr;
+        ptr = zc->seqStore.sequencesStart + maxNbSeq;
+        zc->seqStore.llCode = (BYTE*) ptr;
+        zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
+        zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
+        zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
+        /* ZSTD_wildcopy() is used to copy into the literals buffer,
+         * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
+         */
+        zc->seqStore.maxNbLit = blockSize;
+        ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH;
+
+        /* ldm bucketOffsets table */
+        if (params.ldmParams.enableLdm) {
+            size_t const ldmBucketSize =
+                  ((size_t)1) << (params.ldmParams.hashLog -
+                                  params.ldmParams.bucketSizeLog);
+            memset(ptr, 0, ldmBucketSize);
+            zc->ldmState.bucketOffsets = (BYTE*)ptr;
+            ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
+            ZSTD_window_clear(&zc->ldmState.window);
+        }
+        ZSTD_referenceExternalSequences(zc, NULL, 0);
+
+        /* buffers */
+        zc->inBuffSize = buffInSize;
+        zc->inBuff = (char*)ptr;
+        zc->outBuffSize = buffOutSize;
+        zc->outBuff = zc->inBuff + buffInSize;
+
+        return 0;
+    }
+}
+
+/* ZSTD_invalidateRepCodes() :
+ * ensures next compression will not use repcodes from previous block.
+ * Note : only works with regular variant;
+ *        do not use with extDict variant ! */
+void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
+    int i;
+    for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
+    assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
+}
+
+/* These are the approximate sizes for each strategy past which copying the
+ * dictionary tables into the working context is faster than using them
+ * in-place.
+ */
+static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
+    8 KB,  /* unused */
+    8 KB,  /* ZSTD_fast */
+    16 KB, /* ZSTD_dfast */
+    32 KB, /* ZSTD_greedy */
+    32 KB, /* ZSTD_lazy */
+    32 KB, /* ZSTD_lazy2 */
+    32 KB, /* ZSTD_btlazy2 */
+    32 KB, /* ZSTD_btopt */
+    8 KB,  /* ZSTD_btultra */
+    8 KB   /* ZSTD_btultra2 */
+};
+
+static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
+                                 ZSTD_CCtx_params params,
+                                 U64 pledgedSrcSize)
+{
+    size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
+    return ( pledgedSrcSize <= cutoff
+          || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
+          || params.attachDictPref == ZSTD_dictForceAttach )
+        && params.attachDictPref != ZSTD_dictForceCopy
+        && !params.forceWindow; /* dictMatchState isn't correctly
+                                 * handled in _enforceMaxDist */
+}
+
+static size_t ZSTD_resetCCtx_byAttachingCDict(
+    ZSTD_CCtx* cctx,
+    const ZSTD_CDict* cdict,
+    ZSTD_CCtx_params params,
+    U64 pledgedSrcSize,
+    ZSTD_buffered_policy_e zbuff)
+{
+    {
+        const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
+        unsigned const windowLog = params.cParams.windowLog;
+        assert(windowLog != 0);
+        /* Resize working context table params for input only, since the dict
+         * has its own tables. */
+        params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
+        params.cParams.windowLog = windowLog;
+        ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+                                ZSTDcrp_continue, zbuff);
+        assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+    }
+
+    {
+        const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
+                                  - cdict->matchState.window.base);
+        const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
+        if (cdictLen == 0) {
+            /* don't even attach dictionaries with no contents */
+            DEBUGLOG(4, "skipping attaching empty dictionary");
+        } else {
+            DEBUGLOG(4, "attaching dictionary into context");
+            cctx->blockState.matchState.dictMatchState = &cdict->matchState;
+
+            /* prep working match state so dict matches never have negative indices
+             * when they are translated to the working context's index space. */
+            if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
+                cctx->blockState.matchState.window.nextSrc =
+                    cctx->blockState.matchState.window.base + cdictEnd;
+                ZSTD_window_clear(&cctx->blockState.matchState.window);
+            }
+            cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
+        }
+    }
+
+    cctx->dictID = cdict->dictID;
+
+    /* copy block state */
+    memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+    return 0;
+}
+
+static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
+                            const ZSTD_CDict* cdict,
+                            ZSTD_CCtx_params params,
+                            U64 pledgedSrcSize,
+                            ZSTD_buffered_policy_e zbuff)
+{
+    const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
+
+    DEBUGLOG(4, "copying dictionary into context");
+
+    {   unsigned const windowLog = params.cParams.windowLog;
+        assert(windowLog != 0);
+        /* Copy only compression parameters related to tables. */
+        params.cParams = *cdict_cParams;
+        params.cParams.windowLog = windowLog;
+        ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+                                ZSTDcrp_noMemset, zbuff);
+        assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+        assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
+        assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
+    }
+
+    /* copy tables */
+    {   size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
+        size_t const hSize =  (size_t)1 << cdict_cParams->hashLog;
+        size_t const tableSpace = (chainSize + hSize) * sizeof(U32);
+        assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize);  /* chainTable must follow hashTable */
+        assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize);
+        assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize);  /* chainTable must follow hashTable */
+        assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize);
+        memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace);   /* presumes all tables follow each other */
+    }
+
+    /* Zero the hashTable3, since the cdict never fills it */
+    {   size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3;
+        assert(cdict->matchState.hashLog3 == 0);
+        memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
+    }
+
+    /* copy dictionary offsets */
+    {   ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
+        ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
+        dstMatchState->window       = srcMatchState->window;
+        dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+        dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
+        dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+    }
+
+    cctx->dictID = cdict->dictID;
+
+    /* copy block state */
+    memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+    return 0;
+}
+
+/* We have a choice between copying the dictionary context into the working
+ * context, or referencing the dictionary context from the working context
+ * in-place. We decide here which strategy to use. */
+static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
+                            const ZSTD_CDict* cdict,
+                            ZSTD_CCtx_params params,
+                            U64 pledgedSrcSize,
+                            ZSTD_buffered_policy_e zbuff)
+{
+
+    DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
+                (unsigned)pledgedSrcSize);
+
+    if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
+        return ZSTD_resetCCtx_byAttachingCDict(
+            cctx, cdict, params, pledgedSrcSize, zbuff);
+    } else {
+        return ZSTD_resetCCtx_byCopyingCDict(
+            cctx, cdict, params, pledgedSrcSize, zbuff);
+    }
+}
+
+/*! ZSTD_copyCCtx_internal() :
+ *  Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
+ *  Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
+ *  The "context", in this case, refers to the hash and chain tables,
+ *  entropy tables, and dictionary references.
+ * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
+ * @return : 0, or an error code */
+static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
+                            const ZSTD_CCtx* srcCCtx,
+                            ZSTD_frameParameters fParams,
+                            U64 pledgedSrcSize,
+                            ZSTD_buffered_policy_e zbuff)
+{
+    DEBUGLOG(5, "ZSTD_copyCCtx_internal");
+    if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
+
+    memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
+    {   ZSTD_CCtx_params params = dstCCtx->requestedParams;
+        /* Copy only compression parameters related to tables. */
+        params.cParams = srcCCtx->appliedParams.cParams;
+        params.fParams = fParams;
+        ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
+                                ZSTDcrp_noMemset, zbuff);
+        assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
+        assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
+        assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
+        assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
+        assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
+    }
+
+    /* copy tables */
+    {   size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
+        size_t const hSize =  (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
+        size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3;
+        size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
+        assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize);  /* chainTable must follow hashTable */
+        assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
+        memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace);   /* presumes all tables follow each other */
+    }
+
+    /* copy dictionary offsets */
+    {
+        const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
+        ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
+        dstMatchState->window       = srcMatchState->window;
+        dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+        dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
+        dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+    }
+    dstCCtx->dictID = srcCCtx->dictID;
+
+    /* copy block state */
+    memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
+
+    return 0;
+}
+
+/*! ZSTD_copyCCtx() :
+ *  Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
+ *  Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
+ *  pledgedSrcSize==0 means "unknown".
+*   @return : 0, or an error code */
+size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
+{
+    ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+    ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
+    ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
+    if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+    fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
+
+    return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
+                                fParams, pledgedSrcSize,
+                                zbuff);
+}
+
+
+#define ZSTD_ROWSIZE 16
+/*! ZSTD_reduceTable() :
+ *  reduce table indexes by `reducerValue`, or squash to zero.
+ *  PreserveMark preserves "unsorted mark" for btlazy2 strategy.
+ *  It must be set to a clear 0/1 value, to remove branch during inlining.
+ *  Presume table size is a multiple of ZSTD_ROWSIZE
+ *  to help auto-vectorization */
+FORCE_INLINE_TEMPLATE void
+ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
+{
+    int const nbRows = (int)size / ZSTD_ROWSIZE;
+    int cellNb = 0;
+    int rowNb;
+    assert((size & (ZSTD_ROWSIZE-1)) == 0);  /* multiple of ZSTD_ROWSIZE */
+    assert(size < (1U<<31));   /* can be casted to int */
+    for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
+        int column;
+        for (column=0; column<ZSTD_ROWSIZE; column++) {
+            if (preserveMark) {
+                U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
+                table[cellNb] += adder;
+            }
+            if (table[cellNb] < reducerValue) table[cellNb] = 0;
+            else table[cellNb] -= reducerValue;
+            cellNb++;
+    }   }
+}
+
+static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
+{
+    ZSTD_reduceTable_internal(table, size, reducerValue, 0);
+}
+
+static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
+{
+    ZSTD_reduceTable_internal(table, size, reducerValue, 1);
+}
+
+/*! ZSTD_reduceIndex() :
+*   rescale all indexes to avoid future overflow (indexes are U32) */
+static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
+{
+    ZSTD_matchState_t* const ms = &zc->blockState.matchState;
+    {   U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
+        ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
+    }
+
+    if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
+        U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
+        if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
+            ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
+        else
+            ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
+    }
+
+    if (ms->hashLog3) {
+        U32 const h3Size = (U32)1 << ms->hashLog3;
+        ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
+    }
+}
+
+
+/*-*******************************************************
+*  Block entropic compression
+*********************************************************/
+
+/* See doc/zstd_compression_format.md for detailed format description */
+
+static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock)
+{
+    U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3);
+    if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
+    MEM_writeLE24(dst, cBlockHeader24);
+    memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
+    return ZSTD_blockHeaderSize + srcSize;
+}
+
+static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    BYTE* const ostart = (BYTE* const)dst;
+    U32   const flSize = 1 + (srcSize>31) + (srcSize>4095);
+
+    if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
+
+    switch(flSize)
+    {
+        case 1: /* 2 - 1 - 5 */
+            ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
+            break;
+        case 2: /* 2 - 2 - 12 */
+            MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
+            break;
+        case 3: /* 2 - 2 - 20 */
+            MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
+            break;
+        default:   /* not necessary : flSize is {1,2,3} */
+            assert(0);
+    }
+
+    memcpy(ostart + flSize, src, srcSize);
+    return srcSize + flSize;
+}
+
+static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    BYTE* const ostart = (BYTE* const)dst;
+    U32   const flSize = 1 + (srcSize>31) + (srcSize>4095);
+
+    (void)dstCapacity;  /* dstCapacity already guaranteed to be >=4, hence large enough */
+
+    switch(flSize)
+    {
+        case 1: /* 2 - 1 - 5 */
+            ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
+            break;
+        case 2: /* 2 - 2 - 12 */
+            MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
+            break;
+        case 3: /* 2 - 2 - 20 */
+            MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
+            break;
+        default:   /* not necessary : flSize is {1,2,3} */
+            assert(0);
+    }
+
+    ostart[flSize] = *(const BYTE*)src;
+    return flSize+1;
+}
+
+
+/* ZSTD_minGain() :
+ * minimum compression required
+ * to generate a compress block or a compressed literals section.
+ * note : use same formula for both situations */
+static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
+{
+    U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
+    ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
+    assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
+    return (srcSize >> minlog) + 2;
+}
+
+static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
+                                     ZSTD_hufCTables_t* nextHuf,
+                                     ZSTD_strategy strategy, int disableLiteralCompression,
+                                     void* dst, size_t dstCapacity,
+                               const void* src, size_t srcSize,
+                                     void* workspace, size_t wkspSize,
+                               const int bmi2)
+{
+    size_t const minGain = ZSTD_minGain(srcSize, strategy);
+    size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
+    BYTE*  const ostart = (BYTE*)dst;
+    U32 singleStream = srcSize < 256;
+    symbolEncodingType_e hType = set_compressed;
+    size_t cLitSize;
+
+    DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
+                disableLiteralCompression);
+
+    /* Prepare nextEntropy assuming reusing the existing table */
+    memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+
+    if (disableLiteralCompression)
+        return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+
+    /* small ? don't even attempt compression (speed opt) */
+#   define COMPRESS_LITERALS_SIZE_MIN 63
+    {   size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
+        if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+    }
+
+    if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall);   /* not enough space for compression */
+    {   HUF_repeat repeat = prevHuf->repeatMode;
+        int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
+        if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
+        cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
+                                      workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2)
+                                : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
+                                      workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
+        if (repeat != HUF_repeat_none) {
+            /* reused the existing table */
+            hType = set_repeat;
+        }
+    }
+
+    if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
+        memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+        return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+    }
+    if (cLitSize==1) {
+        memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+        return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
+    }
+
+    if (hType == set_compressed) {
+        /* using a newly constructed table */
+        nextHuf->repeatMode = HUF_repeat_check;
+    }
+
+    /* Build header */
+    switch(lhSize)
+    {
+    case 3: /* 2 - 2 - 10 - 10 */
+        {   U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
+            MEM_writeLE24(ostart, lhc);
+            break;
+        }
+    case 4: /* 2 - 2 - 14 - 14 */
+        {   U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
+            MEM_writeLE32(ostart, lhc);
+            break;
+        }
+    case 5: /* 2 - 2 - 18 - 18 */
+        {   U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
+            MEM_writeLE32(ostart, lhc);
+            ostart[4] = (BYTE)(cLitSize >> 10);
+            break;
+        }
+    default:  /* not possible : lhSize is {3,4,5} */
+        assert(0);
+    }
+    return lhSize+cLitSize;
+}
+
+
+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
+{
+    const seqDef* const sequences = seqStorePtr->sequencesStart;
+    BYTE* const llCodeTable = seqStorePtr->llCode;
+    BYTE* const ofCodeTable = seqStorePtr->ofCode;
+    BYTE* const mlCodeTable = seqStorePtr->mlCode;
+    U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+    U32 u;
+    assert(nbSeq <= seqStorePtr->maxNbSeq);
+    for (u=0; u<nbSeq; u++) {
+        U32 const llv = sequences[u].litLength;
+        U32 const mlv = sequences[u].matchLength;
+        llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
+        ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
+        mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
+    }
+    if (seqStorePtr->longLengthID==1)
+        llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
+    if (seqStorePtr->longLengthID==2)
+        mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
+}
+
+
+/**
+ * -log2(x / 256) lookup table for x in [0, 256).
+ * If x == 0: Return 0
+ * Else: Return floor(-log2(x / 256) * 256)
+ */
+static unsigned const kInverseProbabiltyLog256[256] = {
+    0,    2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
+    1130, 1100, 1073, 1047, 1024, 1001, 980,  960,  941,  923,  906,  889,
+    874,  859,  844,  830,  817,  804,  791,  779,  768,  756,  745,  734,
+    724,  714,  704,  694,  685,  676,  667,  658,  650,  642,  633,  626,
+    618,  610,  603,  595,  588,  581,  574,  567,  561,  554,  548,  542,
+    535,  529,  523,  517,  512,  506,  500,  495,  489,  484,  478,  473,
+    468,  463,  458,  453,  448,  443,  438,  434,  429,  424,  420,  415,
+    411,  407,  402,  398,  394,  390,  386,  382,  377,  373,  370,  366,
+    362,  358,  354,  350,  347,  343,  339,  336,  332,  329,  325,  322,
+    318,  315,  311,  308,  305,  302,  298,  295,  292,  289,  286,  282,
+    279,  276,  273,  270,  267,  264,  261,  258,  256,  253,  250,  247,
+    244,  241,  239,  236,  233,  230,  228,  225,  222,  220,  217,  215,
+    212,  209,  207,  204,  202,  199,  197,  194,  192,  190,  187,  185,
+    182,  180,  178,  175,  173,  171,  168,  166,  164,  162,  159,  157,
+    155,  153,  151,  149,  146,  144,  142,  140,  138,  136,  134,  132,
+    130,  128,  126,  123,  121,  119,  117,  115,  114,  112,  110,  108,
+    106,  104,  102,  100,  98,   96,   94,   93,   91,   89,   87,   85,
+    83,   82,   80,   78,   76,   74,   73,   71,   69,   67,   66,   64,
+    62,   61,   59,   57,   55,   54,   52,   50,   49,   47,   46,   44,
+    42,   41,   39,   37,   36,   34,   33,   31,   30,   28,   26,   25,
+    23,   22,   20,   19,   17,   16,   14,   13,   11,   10,   8,    7,
+    5,    4,    2,    1,
+};
+
+
+/**
+ * Returns the cost in bits of encoding the distribution described by count
+ * using the entropy bound.
+ */
+static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
+{
+    unsigned cost = 0;
+    unsigned s;
+    for (s = 0; s <= max; ++s) {
+        unsigned norm = (unsigned)((256 * count[s]) / total);
+        if (count[s] != 0 && norm == 0)
+            norm = 1;
+        assert(count[s] < total);
+        cost += count[s] * kInverseProbabiltyLog256[norm];
+    }
+    return cost >> 8;
+}
+
+
+/**
+ * Returns the cost in bits of encoding the distribution in count using the
+ * table described by norm. The max symbol support by norm is assumed >= max.
+ * norm must be valid for every symbol with non-zero probability in count.
+ */
+static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
+                                    unsigned const* count, unsigned const max)
+{
+    unsigned const shift = 8 - accuracyLog;
+    size_t cost = 0;
+    unsigned s;
+    assert(accuracyLog <= 8);
+    for (s = 0; s <= max; ++s) {
+        unsigned const normAcc = norm[s] != -1 ? norm[s] : 1;
+        unsigned const norm256 = normAcc << shift;
+        assert(norm256 > 0);
+        assert(norm256 < 256);
+        cost += count[s] * kInverseProbabiltyLog256[norm256];
+    }
+    return cost >> 8;
+}
+
+
+static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
+  void const* ptr = ctable;
+  U16 const* u16ptr = (U16 const*)ptr;
+  U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
+  return maxSymbolValue;
+}
+
+
+/**
+ * Returns the cost in bits of encoding the distribution in count using ctable.
+ * Returns an error if ctable cannot represent all the symbols in count.
+ */
+static size_t ZSTD_fseBitCost(
+    FSE_CTable const* ctable,
+    unsigned const* count,
+    unsigned const max)
+{
+    unsigned const kAccuracyLog = 8;
+    size_t cost = 0;
+    unsigned s;
+    FSE_CState_t cstate;
+    FSE_initCState(&cstate, ctable);
+    if (ZSTD_getFSEMaxSymbolValue(ctable) < max) {
+        DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u",
+                    ZSTD_getFSEMaxSymbolValue(ctable), max);
+        return ERROR(GENERIC);
+    }
+    for (s = 0; s <= max; ++s) {
+        unsigned const tableLog = cstate.stateLog;
+        unsigned const badCost = (tableLog + 1) << kAccuracyLog;
+        unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
+        if (count[s] == 0)
+            continue;
+        if (bitCost >= badCost) {
+            DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s);
+            return ERROR(GENERIC);
+        }
+        cost += count[s] * bitCost;
+    }
+    return cost >> kAccuracyLog;
+}
+
+/**
+ * Returns the cost in bytes of encoding the normalized count header.
+ * Returns an error if any of the helper functions return an error.
+ */
+static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
+                              size_t const nbSeq, unsigned const FSELog)
+{
+    BYTE wksp[FSE_NCOUNTBOUND];
+    S16 norm[MaxSeq + 1];
+    const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
+    CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq, max));
+    return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
+}
+
+
+typedef enum {
+    ZSTD_defaultDisallowed = 0,
+    ZSTD_defaultAllowed = 1
+} ZSTD_defaultPolicy_e;
+
+MEM_STATIC symbolEncodingType_e
+ZSTD_selectEncodingType(
+        FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
+        size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
+        FSE_CTable const* prevCTable,
+        short const* defaultNorm, U32 defaultNormLog,
+        ZSTD_defaultPolicy_e const isDefaultAllowed,
+        ZSTD_strategy const strategy)
+{
+    ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
+    if (mostFrequent == nbSeq) {
+        *repeatMode = FSE_repeat_none;
+        if (isDefaultAllowed && nbSeq <= 2) {
+            /* Prefer set_basic over set_rle when there are 2 or less symbols,
+             * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
+             * If basic encoding isn't possible, always choose RLE.
+             */
+            DEBUGLOG(5, "Selected set_basic");
+            return set_basic;
+        }
+        DEBUGLOG(5, "Selected set_rle");
+        return set_rle;
+    }
+    if (strategy < ZSTD_lazy) {
+        if (isDefaultAllowed) {
+            size_t const staticFse_nbSeq_max = 1000;
+            size_t const mult = 10 - strategy;
+            size_t const baseLog = 3;
+            size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog;  /* 28-36 for offset, 56-72 for lengths */
+            assert(defaultNormLog >= 5 && defaultNormLog <= 6);  /* xx_DEFAULTNORMLOG */
+            assert(mult <= 9 && mult >= 7);
+            if ( (*repeatMode == FSE_repeat_valid)
+              && (nbSeq < staticFse_nbSeq_max) ) {
+                DEBUGLOG(5, "Selected set_repeat");
+                return set_repeat;
+            }
+            if ( (nbSeq < dynamicFse_nbSeq_min)
+              || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
+                DEBUGLOG(5, "Selected set_basic");
+                /* The format allows default tables to be repeated, but it isn't useful.
+                 * When using simple heuristics to select encoding type, we don't want
+                 * to confuse these tables with dictionaries. When running more careful
+                 * analysis, we don't need to waste time checking both repeating tables
+                 * and default tables.
+                 */
+                *repeatMode = FSE_repeat_none;
+                return set_basic;
+            }
+        }
+    } else {
+        size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
+        size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
+        size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
+        size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
+
+        if (isDefaultAllowed) {
+            assert(!ZSTD_isError(basicCost));
+            assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
+        }
+        assert(!ZSTD_isError(NCountCost));
+        assert(compressedCost < ERROR(maxCode));
+        DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
+                    (unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost);
+        if (basicCost <= repeatCost && basicCost <= compressedCost) {
+            DEBUGLOG(5, "Selected set_basic");
+            assert(isDefaultAllowed);
+            *repeatMode = FSE_repeat_none;
+            return set_basic;
+        }
+        if (repeatCost <= compressedCost) {
+            DEBUGLOG(5, "Selected set_repeat");
+            assert(!ZSTD_isError(repeatCost));
+            return set_repeat;
+        }
+        assert(compressedCost < basicCost && compressedCost < repeatCost);
+    }
+    DEBUGLOG(5, "Selected set_compressed");
+    *repeatMode = FSE_repeat_check;
+    return set_compressed;
+}
+
+MEM_STATIC size_t
+ZSTD_buildCTable(void* dst, size_t dstCapacity,
+                FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
+                unsigned* count, U32 max,
+                const BYTE* codeTable, size_t nbSeq,
+                const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+                const FSE_CTable* prevCTable, size_t prevCTableSize,
+                void* workspace, size_t workspaceSize)
+{
+    BYTE* op = (BYTE*)dst;
+    const BYTE* const oend = op + dstCapacity;
+    DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity);
+
+    switch (type) {
+    case set_rle:
+        CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max));
+        if (dstCapacity==0) return ERROR(dstSize_tooSmall);
+        *op = codeTable[0];
+        return 1;
+    case set_repeat:
+        memcpy(nextCTable, prevCTable, prevCTableSize);
+        return 0;
+    case set_basic:
+        CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize));  /* note : could be pre-calculated */
+        return 0;
+    case set_compressed: {
+        S16 norm[MaxSeq + 1];
+        size_t nbSeq_1 = nbSeq;
+        const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
+        if (count[codeTable[nbSeq-1]] > 1) {
+            count[codeTable[nbSeq-1]]--;
+            nbSeq_1--;
+        }
+        assert(nbSeq_1 > 1);
+        CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
+        {   size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog);   /* overflow protected */
+            if (FSE_isError(NCountSize)) return NCountSize;
+            CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
+            return NCountSize;
+        }
+    }
+    default: return assert(0), ERROR(GENERIC);
+    }
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_encodeSequences_body(
+            void* dst, size_t dstCapacity,
+            FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+            FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+            FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+            seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+    BIT_CStream_t blockStream;
+    FSE_CState_t  stateMatchLength;
+    FSE_CState_t  stateOffsetBits;
+    FSE_CState_t  stateLitLength;
+
+    CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */
+    DEBUGLOG(6, "available space for bitstream : %i  (dstCapacity=%u)",
+                (int)(blockStream.endPtr - blockStream.startPtr),
+                (unsigned)dstCapacity);
+
+    /* first symbols */
+    FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
+    FSE_initCState2(&stateOffsetBits,  CTable_OffsetBits,  ofCodeTable[nbSeq-1]);
+    FSE_initCState2(&stateLitLength,   CTable_LitLength,   llCodeTable[nbSeq-1]);
+    BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
+    if (MEM_32bits()) BIT_flushBits(&blockStream);
+    BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
+    if (MEM_32bits()) BIT_flushBits(&blockStream);
+    if (longOffsets) {
+        U32 const ofBits = ofCodeTable[nbSeq-1];
+        int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+        if (extraBits) {
+            BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
+            BIT_flushBits(&blockStream);
+        }
+        BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
+                    ofBits - extraBits);
+    } else {
+        BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
+    }
+    BIT_flushBits(&blockStream);
+
+    {   size_t n;
+        for (n=nbSeq-2 ; n<nbSeq ; n--) {      /* intentional underflow */
+            BYTE const llCode = llCodeTable[n];
+            BYTE const ofCode = ofCodeTable[n];
+            BYTE const mlCode = mlCodeTable[n];
+            U32  const llBits = LL_bits[llCode];
+            U32  const ofBits = ofCode;
+            U32  const mlBits = ML_bits[mlCode];
+            DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
+                        (unsigned)sequences[n].litLength,
+                        (unsigned)sequences[n].matchLength + MINMATCH,
+                        (unsigned)sequences[n].offset);
+                                                                            /* 32b*/  /* 64b*/
+                                                                            /* (7)*/  /* (7)*/
+            FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode);       /* 15 */  /* 15 */
+            FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode);      /* 24 */  /* 24 */
+            if (MEM_32bits()) BIT_flushBits(&blockStream);                  /* (7)*/
+            FSE_encodeSymbol(&blockStream, &stateLitLength, llCode);        /* 16 */  /* 33 */
+            if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
+                BIT_flushBits(&blockStream);                                /* (7)*/
+            BIT_addBits(&blockStream, sequences[n].litLength, llBits);
+            if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
+            BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
+            if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
+            if (longOffsets) {
+                int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+                if (extraBits) {
+                    BIT_addBits(&blockStream, sequences[n].offset, extraBits);
+                    BIT_flushBits(&blockStream);                            /* (7)*/
+                }
+                BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
+                            ofBits - extraBits);                            /* 31 */
+            } else {
+                BIT_addBits(&blockStream, sequences[n].offset, ofBits);     /* 31 */
+            }
+            BIT_flushBits(&blockStream);                                    /* (7)*/
+            DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr));
+    }   }
+
+    DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
+    FSE_flushCState(&blockStream, &stateMatchLength);
+    DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
+    FSE_flushCState(&blockStream, &stateOffsetBits);
+    DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
+    FSE_flushCState(&blockStream, &stateLitLength);
+
+    {   size_t const streamSize = BIT_closeCStream(&blockStream);
+        if (streamSize==0) return ERROR(dstSize_tooSmall);   /* not enough space */
+        return streamSize;
+    }
+}
+
+static size_t
+ZSTD_encodeSequences_default(
+            void* dst, size_t dstCapacity,
+            FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+            FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+            FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+            seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+    return ZSTD_encodeSequences_body(dst, dstCapacity,
+                                    CTable_MatchLength, mlCodeTable,
+                                    CTable_OffsetBits, ofCodeTable,
+                                    CTable_LitLength, llCodeTable,
+                                    sequences, nbSeq, longOffsets);
+}
+
+
+#if DYNAMIC_BMI2
+
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_encodeSequences_bmi2(
+            void* dst, size_t dstCapacity,
+            FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+            FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+            FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+            seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+    return ZSTD_encodeSequences_body(dst, dstCapacity,
+                                    CTable_MatchLength, mlCodeTable,
+                                    CTable_OffsetBits, ofCodeTable,
+                                    CTable_LitLength, llCodeTable,
+                                    sequences, nbSeq, longOffsets);
+}
+
+#endif
+
+static size_t ZSTD_encodeSequences(
+            void* dst, size_t dstCapacity,
+            FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+            FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+            FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+            seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
+{
+    DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
+#if DYNAMIC_BMI2
+    if (bmi2) {
+        return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
+                                         CTable_MatchLength, mlCodeTable,
+                                         CTable_OffsetBits, ofCodeTable,
+                                         CTable_LitLength, llCodeTable,
+                                         sequences, nbSeq, longOffsets);
+    }
+#endif
+    (void)bmi2;
+    return ZSTD_encodeSequences_default(dst, dstCapacity,
+                                        CTable_MatchLength, mlCodeTable,
+                                        CTable_OffsetBits, ofCodeTable,
+                                        CTable_LitLength, llCodeTable,
+                                        sequences, nbSeq, longOffsets);
+}
+
+/* ZSTD_compressSequences_internal():
+ * actually compresses both literals and sequences */
+MEM_STATIC size_t
+ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
+                          const ZSTD_entropyCTables_t* prevEntropy,
+                                ZSTD_entropyCTables_t* nextEntropy,
+                          const ZSTD_CCtx_params* cctxParams,
+                                void* dst, size_t dstCapacity,
+                                void* workspace, size_t wkspSize,
+                          const int bmi2)
+{
+    const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
+    ZSTD_strategy const strategy = cctxParams->cParams.strategy;
+    unsigned count[MaxSeq+1];
+    FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
+    FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
+    FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
+    U32 LLtype, Offtype, MLtype;   /* compressed, raw or rle */
+    const seqDef* const sequences = seqStorePtr->sequencesStart;
+    const BYTE* const ofCodeTable = seqStorePtr->ofCode;
+    const BYTE* const llCodeTable = seqStorePtr->llCode;
+    const BYTE* const mlCodeTable = seqStorePtr->mlCode;
+    BYTE* const ostart = (BYTE*)dst;
+    BYTE* const oend = ostart + dstCapacity;
+    BYTE* op = ostart;
+    size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
+    BYTE* seqHead;
+    BYTE* lastNCount = NULL;
+
+    ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+    DEBUGLOG(5, "ZSTD_compressSequences_internal");
+
+    /* Compress literals */
+    {   const BYTE* const literals = seqStorePtr->litStart;
+        size_t const litSize = seqStorePtr->lit - literals;
+        int const disableLiteralCompression = (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0);
+        size_t const cSize = ZSTD_compressLiterals(
+                                    &prevEntropy->huf, &nextEntropy->huf,
+                                    cctxParams->cParams.strategy, disableLiteralCompression,
+                                    op, dstCapacity,
+                                    literals, litSize,
+                                    workspace, wkspSize,
+                                    bmi2);
+        if (ZSTD_isError(cSize))
+          return cSize;
+        assert(cSize <= dstCapacity);
+        op += cSize;
+    }
+
+    /* Sequences Header */
+    if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall);
+    if (nbSeq < 0x7F)
+        *op++ = (BYTE)nbSeq;
+    else if (nbSeq < LONGNBSEQ)
+        op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
+    else
+        op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
+    if (nbSeq==0) {
+        /* Copy the old tables over as if we repeated them */
+        memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
+        return op - ostart;
+    }
+
+    /* seqHead : flags for FSE encoding type */
+    seqHead = op++;
+
+    /* convert length/distances into codes */
+    ZSTD_seqToCodes(seqStorePtr);
+    /* build CTable for Literal Lengths */
+    {   unsigned max = MaxLL;
+        size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace, wkspSize);   /* can't fail */
+        DEBUGLOG(5, "Building LL table");
+        nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
+        LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
+                                        count, max, mostFrequent, nbSeq,
+                                        LLFSELog, prevEntropy->fse.litlengthCTable,
+                                        LL_defaultNorm, LL_defaultNormLog,
+                                        ZSTD_defaultAllowed, strategy);
+        assert(set_basic < set_compressed && set_rle < set_compressed);
+        assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+        {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
+                                                    count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
+                                                    prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable),
+                                                    workspace, wkspSize);
+            if (ZSTD_isError(countSize)) return countSize;
+            if (LLtype == set_compressed)
+                lastNCount = op;
+            op += countSize;
+    }   }
+    /* build CTable for Offsets */
+    {   unsigned max = MaxOff;
+        size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace, wkspSize);  /* can't fail */
+        /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
+        ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
+        DEBUGLOG(5, "Building OF table");
+        nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
+        Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
+                                        count, max, mostFrequent, nbSeq,
+                                        OffFSELog, prevEntropy->fse.offcodeCTable,
+                                        OF_defaultNorm, OF_defaultNormLog,
+                                        defaultPolicy, strategy);
+        assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+        {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
+                                                    count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+                                                    prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable),
+                                                    workspace, wkspSize);
+            if (ZSTD_isError(countSize)) return countSize;
+            if (Offtype == set_compressed)
+                lastNCount = op;
+            op += countSize;
+    }   }
+    /* build CTable for MatchLengths */
+    {   unsigned max = MaxML;
+        size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace, wkspSize);   /* can't fail */
+        DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
+        nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
+        MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
+                                        count, max, mostFrequent, nbSeq,
+                                        MLFSELog, prevEntropy->fse.matchlengthCTable,
+                                        ML_defaultNorm, ML_defaultNormLog,
+                                        ZSTD_defaultAllowed, strategy);
+        assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+        {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
+                                                    count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
+                                                    prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable),
+                                                    workspace, wkspSize);
+            if (ZSTD_isError(countSize)) return countSize;
+            if (MLtype == set_compressed)
+                lastNCount = op;
+            op += countSize;
+    }   }
+
+    *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
+
+    {   size_t const bitstreamSize = ZSTD_encodeSequences(
+                                        op, oend - op,
+                                        CTable_MatchLength, mlCodeTable,
+                                        CTable_OffsetBits, ofCodeTable,
+                                        CTable_LitLength, llCodeTable,
+                                        sequences, nbSeq,
+                                        longOffsets, bmi2);
+        if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
+        op += bitstreamSize;
+        /* zstd versions <= 1.3.4 mistakenly report corruption when
+         * FSE_readNCount() recieves a buffer < 4 bytes.
+         * Fixed by https://github.com/facebook/zstd/pull/1146.
+         * This can happen when the last set_compressed table present is 2
+         * bytes and the bitstream is only one byte.
+         * In this exceedingly rare case, we will simply emit an uncompressed
+         * block, since it isn't worth optimizing.
+         */
+        if (lastNCount && (op - lastNCount) < 4) {
+            /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
+            assert(op - lastNCount == 3);
+            DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
+                        "emitting an uncompressed block.");
+            return 0;
+        }
+    }
+
+    DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
+    return op - ostart;
+}
+
+MEM_STATIC size_t
+ZSTD_compressSequences(seqStore_t* seqStorePtr,
+                       const ZSTD_entropyCTables_t* prevEntropy,
+                             ZSTD_entropyCTables_t* nextEntropy,
+                       const ZSTD_CCtx_params* cctxParams,
+                             void* dst, size_t dstCapacity,
+                             size_t srcSize,
+                             void* workspace, size_t wkspSize,
+                             int bmi2)
+{
+    size_t const cSize = ZSTD_compressSequences_internal(
+                            seqStorePtr, prevEntropy, nextEntropy, cctxParams,
+                            dst, dstCapacity,
+                            workspace, wkspSize, bmi2);
+    if (cSize == 0) return 0;
+    /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
+     * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
+     */
+    if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
+        return 0;  /* block not compressed */
+    if (ZSTD_isError(cSize)) return cSize;
+
+    /* Check compressibility */
+    {   size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
+        if (cSize >= maxCSize) return 0;  /* block not compressed */
+    }
+
+    return cSize;
+}
+
+/* ZSTD_selectBlockCompressor() :
+ * Not static, but internal use only (used by long distance matcher)
+ * assumption : strat is a valid strategy */
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
+{
+    static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
+        { ZSTD_compressBlock_fast  /* default for 0 */,
+          ZSTD_compressBlock_fast,
+          ZSTD_compressBlock_doubleFast,
+          ZSTD_compressBlock_greedy,
+          ZSTD_compressBlock_lazy,
+          ZSTD_compressBlock_lazy2,
+          ZSTD_compressBlock_btlazy2,
+          ZSTD_compressBlock_btopt,
+          ZSTD_compressBlock_btultra,
+          ZSTD_compressBlock_btultra2 },
+        { ZSTD_compressBlock_fast_extDict  /* default for 0 */,
+          ZSTD_compressBlock_fast_extDict,
+          ZSTD_compressBlock_doubleFast_extDict,
+          ZSTD_compressBlock_greedy_extDict,
+          ZSTD_compressBlock_lazy_extDict,
+          ZSTD_compressBlock_lazy2_extDict,
+          ZSTD_compressBlock_btlazy2_extDict,
+          ZSTD_compressBlock_btopt_extDict,
+          ZSTD_compressBlock_btultra_extDict,
+          ZSTD_compressBlock_btultra_extDict },
+        { ZSTD_compressBlock_fast_dictMatchState  /* default for 0 */,
+          ZSTD_compressBlock_fast_dictMatchState,
+          ZSTD_compressBlock_doubleFast_dictMatchState,
+          ZSTD_compressBlock_greedy_dictMatchState,
+          ZSTD_compressBlock_lazy_dictMatchState,
+          ZSTD_compressBlock_lazy2_dictMatchState,
+          ZSTD_compressBlock_btlazy2_dictMatchState,
+          ZSTD_compressBlock_btopt_dictMatchState,
+          ZSTD_compressBlock_btultra_dictMatchState,
+          ZSTD_compressBlock_btultra_dictMatchState }
+    };
+    ZSTD_blockCompressor selectedCompressor;
+    ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
+
+    assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
+    selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+    assert(selectedCompressor != NULL);
+    return selectedCompressor;
+}
+
+static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
+                                   const BYTE* anchor, size_t lastLLSize)
+{
+    memcpy(seqStorePtr->lit, anchor, lastLLSize);
+    seqStorePtr->lit += lastLLSize;
+}
+
+void ZSTD_resetSeqStore(seqStore_t* ssPtr)
+{
+    ssPtr->lit = ssPtr->litStart;
+    ssPtr->sequences = ssPtr->sequencesStart;
+    ssPtr->longLengthID = 0;
+}
+
+static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
+                                        void* dst, size_t dstCapacity,
+                                        const void* src, size_t srcSize)
+{
+    ZSTD_matchState_t* const ms = &zc->blockState.matchState;
+    size_t cSize;
+    DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
+                (unsigned)dstCapacity, (unsigned)ms->window.dictLimit, (unsigned)ms->nextToUpdate);
+    assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
+
+    /* Assert that we have correctly flushed the ctx params into the ms's copy */
+    ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
+
+    if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
+        ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
+        cSize = 0;
+        goto out;  /* don't even attempt compression below a certain srcSize */
+    }
+    ZSTD_resetSeqStore(&(zc->seqStore));
+    ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy;   /* required for optimal parser to read stats from dictionary */
+
+    /* a gap between an attached dict and the current window is not safe,
+     * they must remain adjacent,
+     * and when that stops being the case, the dict must be unset */
+    assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
+
+    /* limited update after a very long match */
+    {   const BYTE* const base = ms->window.base;
+        const BYTE* const istart = (const BYTE*)src;
+        const U32 current = (U32)(istart-base);
+        if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1));   /* ensure no overflow */
+        if (current > ms->nextToUpdate + 384)
+            ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
+    }
+
+    /* select and store sequences */
+    {   ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
+        size_t lastLLSize;
+        {   int i;
+            for (i = 0; i < ZSTD_REP_NUM; ++i)
+                zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
+        }
+        if (zc->externSeqStore.pos < zc->externSeqStore.size) {
+            assert(!zc->appliedParams.ldmParams.enableLdm);
+            /* Updates ldmSeqStore.pos */
+            lastLLSize =
+                ZSTD_ldm_blockCompress(&zc->externSeqStore,
+                                       ms, &zc->seqStore,
+                                       zc->blockState.nextCBlock->rep,
+                                       src, srcSize);
+            assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
+        } else if (zc->appliedParams.ldmParams.enableLdm) {
+            rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
+
+            ldmSeqStore.seq = zc->ldmSequences;
+            ldmSeqStore.capacity = zc->maxNbLdmSequences;
+            /* Updates ldmSeqStore.size */
+            CHECK_F(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
+                                               &zc->appliedParams.ldmParams,
+                                               src, srcSize));
+            /* Updates ldmSeqStore.pos */
+            lastLLSize =
+                ZSTD_ldm_blockCompress(&ldmSeqStore,
+                                       ms, &zc->seqStore,
+                                       zc->blockState.nextCBlock->rep,
+                                       src, srcSize);
+            assert(ldmSeqStore.pos == ldmSeqStore.size);
+        } else {   /* not long range mode */
+            ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
+            lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
+        }
+        {   const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
+            ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
+    }   }
+
+    /* encode sequences and literals */
+    cSize = ZSTD_compressSequences(&zc->seqStore,
+            &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
+            &zc->appliedParams,
+            dst, dstCapacity,
+            srcSize,
+            zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+            zc->bmi2);
+
+out:
+    if (!ZSTD_isError(cSize) && cSize != 0) {
+        /* confirm repcodes and entropy tables when emitting a compressed block */
+        ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
+        zc->blockState.prevCBlock = zc->blockState.nextCBlock;
+        zc->blockState.nextCBlock = tmp;
+    }
+    /* We check that dictionaries have offset codes available for the first
+     * block. After the first block, the offcode table might not have large
+     * enough codes to represent the offsets in the data.
+     */
+    if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+        zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+    return cSize;
+}
+
+
+/*! ZSTD_compress_frameChunk() :
+*   Compress a chunk of data into one or multiple blocks.
+*   All blocks will be terminated, all input will be consumed.
+*   Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
+*   Frame is supposed already started (header already produced)
+*   @return : compressed size, or an error code
+*/
+static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
+                                     void* dst, size_t dstCapacity,
+                               const void* src, size_t srcSize,
+                                     U32 lastFrameChunk)
+{
+    size_t blockSize = cctx->blockSize;
+    size_t remaining = srcSize;
+    const BYTE* ip = (const BYTE*)src;
+    BYTE* const ostart = (BYTE*)dst;
+    BYTE* op = ostart;
+    U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
+    assert(cctx->appliedParams.cParams.windowLog <= 31);
+
+    DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
+    if (cctx->appliedParams.fParams.checksumFlag && srcSize)
+        XXH64_update(&cctx->xxhState, src, srcSize);
+
+    while (remaining) {
+        ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
+        U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
+
+        if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
+            return ERROR(dstSize_tooSmall);   /* not enough space to store compressed block */
+        if (remaining < blockSize) blockSize = remaining;
+
+        if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) {
+            U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy);
+            U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
+            ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
+            ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
+            ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
+            ZSTD_reduceIndex(cctx, correction);
+            if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
+            else ms->nextToUpdate -= correction;
+            ms->loadedDictEnd = 0;
+            ms->dictMatchState = NULL;
+        }
+        ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
+        if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
+
+        {   size_t cSize = ZSTD_compressBlock_internal(cctx,
+                                op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
+                                ip, blockSize);
+            if (ZSTD_isError(cSize)) return cSize;
+
+            if (cSize == 0) {  /* block is not compressible */
+                cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
+                if (ZSTD_isError(cSize)) return cSize;
+            } else {
+                U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
+                MEM_writeLE24(op, cBlockHeader24);
+                cSize += ZSTD_blockHeaderSize;
+            }
+
+            ip += blockSize;
+            assert(remaining >= blockSize);
+            remaining -= blockSize;
+            op += cSize;
+            assert(dstCapacity >= cSize);
+            dstCapacity -= cSize;
+            DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
+                        (unsigned)cSize);
+    }   }
+
+    if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
+    return op-ostart;
+}
+
+
+static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
+                                    ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID)
+{   BYTE* const op = (BYTE*)dst;
+    U32   const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536);   /* 0-3 */
+    U32   const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength;   /* 0-3 */
+    U32   const checksumFlag = params.fParams.checksumFlag>0;
+    U32   const windowSize = (U32)1 << params.cParams.windowLog;
+    U32   const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
+    BYTE  const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
+    U32   const fcsCode = params.fParams.contentSizeFlag ?
+                     (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0;  /* 0-3 */
+    BYTE  const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
+    size_t pos=0;
+
+    assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
+    if (dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX) return ERROR(dstSize_tooSmall);
+    DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
+                !params.fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
+
+    if (params.format == ZSTD_f_zstd1) {
+        MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
+        pos = 4;
+    }
+    op[pos++] = frameHeaderDecriptionByte;
+    if (!singleSegment) op[pos++] = windowLogByte;
+    switch(dictIDSizeCode)
+    {
+        default:  assert(0); /* impossible */
+        case 0 : break;
+        case 1 : op[pos] = (BYTE)(dictID); pos++; break;
+        case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
+        case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
+    }
+    switch(fcsCode)
+    {
+        default:  assert(0); /* impossible */
+        case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
+        case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
+        case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
+        case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
+    }
+    return pos;
+}
+
+/* ZSTD_writeLastEmptyBlock() :
+ * output an empty Block with end-of-frame mark to complete a frame
+ * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
+ *           or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
+ */
+size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
+{
+    if (dstCapacity < ZSTD_blockHeaderSize) return ERROR(dstSize_tooSmall);
+    {   U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1);  /* 0 size */
+        MEM_writeLE24(dst, cBlockHeader24);
+        return ZSTD_blockHeaderSize;
+    }
+}
+
+size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
+{
+    if (cctx->stage != ZSTDcs_init)
+        return ERROR(stage_wrong);
+    if (cctx->appliedParams.ldmParams.enableLdm)
+        return ERROR(parameter_unsupported);
+    cctx->externSeqStore.seq = seq;
+    cctx->externSeqStore.size = nbSeq;
+    cctx->externSeqStore.capacity = nbSeq;
+    cctx->externSeqStore.pos = 0;
+    return 0;
+}
+
+
+static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
+                              void* dst, size_t dstCapacity,
+                        const void* src, size_t srcSize,
+                               U32 frame, U32 lastFrameChunk)
+{
+    ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
+    size_t fhSize = 0;
+
+    DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
+                cctx->stage, (unsigned)srcSize);
+    if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong);   /* missing init (ZSTD_compressBegin) */
+
+    if (frame && (cctx->stage==ZSTDcs_init)) {
+        fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
+                                       cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
+        if (ZSTD_isError(fhSize)) return fhSize;
+        dstCapacity -= fhSize;
+        dst = (char*)dst + fhSize;
+        cctx->stage = ZSTDcs_ongoing;
+    }
+
+    if (!srcSize) return fhSize;  /* do not generate an empty block if no input */
+
+    if (!ZSTD_window_update(&ms->window, src, srcSize)) {
+        ms->nextToUpdate = ms->window.dictLimit;
+    }
+    if (cctx->appliedParams.ldmParams.enableLdm) {
+        ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
+    }
+
+    if (!frame) {
+        /* overflow check and correction for block mode */
+        if (ZSTD_window_needOverflowCorrection(ms->window, (const char*)src + srcSize)) {
+            U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy);
+            U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, 1 << cctx->appliedParams.cParams.windowLog, src);
+            ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
+            ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
+            ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
+            ZSTD_reduceIndex(cctx, correction);
+            if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
+            else ms->nextToUpdate -= correction;
+            ms->loadedDictEnd = 0;
+            ms->dictMatchState = NULL;
+        }
+    }
+
+    DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize);
+    {   size_t const cSize = frame ?
+                             ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
+                             ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
+        if (ZSTD_isError(cSize)) return cSize;
+        cctx->consumedSrcSize += srcSize;
+        cctx->producedCSize += (cSize + fhSize);
+        assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
+        if (cctx->pledgedSrcSizePlusOne != 0) {  /* control src size */
+            ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
+            if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) {
+                DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u",
+                    (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize);
+                return ERROR(srcSize_wrong);
+            }
+        }
+        return cSize + fhSize;
+    }
+}
+
+size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
+                              void* dst, size_t dstCapacity,
+                        const void* src, size_t srcSize)
+{
+    DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize);
+    return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
+}
+
+
+size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
+{
+    ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
+    assert(!ZSTD_checkCParams(cParams));
+    return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
+}
+
+size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
+    if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
+
+    return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
+}
+
+/*! ZSTD_loadDictionaryContent() :
+ *  @return : 0, or an error code
+ */
+static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
+                                         ZSTD_CCtx_params const* params,
+                                         const void* src, size_t srcSize,
+                                         ZSTD_dictTableLoadMethod_e dtlm)
+{
+    const BYTE* const ip = (const BYTE*) src;
+    const BYTE* const iend = ip + srcSize;
+
+    ZSTD_window_update(&ms->window, src, srcSize);
+    ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
+
+    /* Assert that we the ms params match the params we're being given */
+    ZSTD_assertEqualCParams(params->cParams, ms->cParams);
+
+    if (srcSize <= HASH_READ_SIZE) return 0;
+
+    switch(params->cParams.strategy)
+    {
+    case ZSTD_fast:
+        ZSTD_fillHashTable(ms, iend, dtlm);
+        break;
+    case ZSTD_dfast:
+        ZSTD_fillDoubleHashTable(ms, iend, dtlm);
+        break;
+
+    case ZSTD_greedy:
+    case ZSTD_lazy:
+    case ZSTD_lazy2:
+        if (srcSize >= HASH_READ_SIZE)
+            ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE);
+        break;
+
+    case ZSTD_btlazy2:   /* we want the dictionary table fully sorted */
+    case ZSTD_btopt:
+    case ZSTD_btultra:
+    case ZSTD_btultra2:
+        if (srcSize >= HASH_READ_SIZE)
+            ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend);
+        break;
+
+    default:
+        assert(0);  /* not possible : not a valid strategy id */
+    }
+
+    ms->nextToUpdate = (U32)(iend - ms->window.base);
+    return 0;
+}
+
+
+/* Dictionaries that assign zero probability to symbols that show up causes problems
+   when FSE encoding.  Refuse dictionaries that assign zero probability to symbols
+   that we may encounter during compression.
+   NOTE: This behavior is not standard and could be improved in the future. */
+static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
+    U32 s;
+    if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
+    for (s = 0; s <= maxSymbolValue; ++s) {
+        if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
+    }
+    return 0;
+}
+
+
+/* Dictionary format :
+ * See :
+ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+ */
+/*! ZSTD_loadZstdDictionary() :
+ * @return : dictID, or an error code
+ *  assumptions : magic number supposed already checked
+ *                dictSize supposed > 8
+ */
+static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
+                                      ZSTD_matchState_t* ms,
+                                      ZSTD_CCtx_params const* params,
+                                      const void* dict, size_t dictSize,
+                                      ZSTD_dictTableLoadMethod_e dtlm,
+                                      void* workspace)
+{
+    const BYTE* dictPtr = (const BYTE*)dict;
+    const BYTE* const dictEnd = dictPtr + dictSize;
+    short offcodeNCount[MaxOff+1];
+    unsigned offcodeMaxValue = MaxOff;
+    size_t dictID;
+
+    ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+    assert(dictSize > 8);
+    assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
+
+    dictPtr += 4;   /* skip magic number */
+    dictID = params->fParams.noDictIDFlag ? 0 :  MEM_readLE32(dictPtr);
+    dictPtr += 4;
+
+    {   unsigned maxSymbolValue = 255;
+        size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
+        if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
+        if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
+        dictPtr += hufHeaderSize;
+    }
+
+    {   unsigned offcodeLog;
+        size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+        if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
+        if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
+        /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
+        /* fill all offset symbols to avoid garbage at end of table */
+        CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.offcodeCTable,
+                                    offcodeNCount, MaxOff, offcodeLog,
+                                    workspace, HUF_WORKSPACE_SIZE),
+                 dictionary_corrupted);
+        dictPtr += offcodeHeaderSize;
+    }
+
+    {   short matchlengthNCount[MaxML+1];
+        unsigned matchlengthMaxValue = MaxML, matchlengthLog;
+        size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+        if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
+        if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
+        /* Every match length code must have non-zero probability */
+        CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
+        CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.matchlengthCTable,
+                                    matchlengthNCount, matchlengthMaxValue, matchlengthLog,
+                                    workspace, HUF_WORKSPACE_SIZE),
+                 dictionary_corrupted);
+        dictPtr += matchlengthHeaderSize;
+    }
+
+    {   short litlengthNCount[MaxLL+1];
+        unsigned litlengthMaxValue = MaxLL, litlengthLog;
+        size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+        if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
+        if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
+        /* Every literal length code must have non-zero probability */
+        CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
+        CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.litlengthCTable,
+                                    litlengthNCount, litlengthMaxValue, litlengthLog,
+                                    workspace, HUF_WORKSPACE_SIZE),
+                 dictionary_corrupted);
+        dictPtr += litlengthHeaderSize;
+    }
+
+    if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
+    bs->rep[0] = MEM_readLE32(dictPtr+0);
+    bs->rep[1] = MEM_readLE32(dictPtr+4);
+    bs->rep[2] = MEM_readLE32(dictPtr+8);
+    dictPtr += 12;
+
+    {   size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
+        U32 offcodeMax = MaxOff;
+        if (dictContentSize <= ((U32)-1) - 128 KB) {
+            U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
+            offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
+        }
+        /* All offset values <= dictContentSize + 128 KB must be representable */
+        CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
+        /* All repCodes must be <= dictContentSize and != 0*/
+        {   U32 u;
+            for (u=0; u<3; u++) {
+                if (bs->rep[u] == 0) return ERROR(dictionary_corrupted);
+                if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
+        }   }
+
+        bs->entropy.huf.repeatMode = HUF_repeat_valid;
+        bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
+        bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
+        bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
+        CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm));
+        return dictID;
+    }
+}
+
+/** ZSTD_compress_insertDictionary() :
+*   @return : dictID, or an error code */
+static size_t
+ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
+                               ZSTD_matchState_t* ms,
+                         const ZSTD_CCtx_params* params,
+                         const void* dict, size_t dictSize,
+                               ZSTD_dictContentType_e dictContentType,
+                               ZSTD_dictTableLoadMethod_e dtlm,
+                               void* workspace)
+{
+    DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
+    if ((dict==NULL) || (dictSize<=8)) return 0;
+
+    ZSTD_reset_compressedBlockState(bs);
+
+    /* dict restricted modes */
+    if (dictContentType == ZSTD_dct_rawContent)
+        return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm);
+
+    if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
+        if (dictContentType == ZSTD_dct_auto) {
+            DEBUGLOG(4, "raw content dictionary detected");
+            return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm);
+        }
+        if (dictContentType == ZSTD_dct_fullDict)
+            return ERROR(dictionary_wrong);
+        assert(0);   /* impossible */
+    }
+
+    /* dict as full zstd dictionary */
+    return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace);
+}
+
+/*! ZSTD_compressBegin_internal() :
+ * @return : 0, or an error code */
+static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
+                                    const void* dict, size_t dictSize,
+                                    ZSTD_dictContentType_e dictContentType,
+                                    ZSTD_dictTableLoadMethod_e dtlm,
+                                    const ZSTD_CDict* cdict,
+                                    ZSTD_CCtx_params params, U64 pledgedSrcSize,
+                                    ZSTD_buffered_policy_e zbuff)
+{
+    DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog);
+    /* params are supposed to be fully validated at this point */
+    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+    assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
+
+    if (cdict && cdict->dictContentSize>0) {
+        return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
+    }
+
+    CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+                                     ZSTDcrp_continue, zbuff) );
+    {
+        size_t const dictID = ZSTD_compress_insertDictionary(
+                cctx->blockState.prevCBlock, &cctx->blockState.matchState,
+                &params, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace);
+        if (ZSTD_isError(dictID)) return dictID;
+        assert(dictID <= (size_t)(U32)-1);
+        cctx->dictID = (U32)dictID;
+    }
+    return 0;
+}
+
+size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
+                                    const void* dict, size_t dictSize,
+                                    ZSTD_dictContentType_e dictContentType,
+                                    ZSTD_dictTableLoadMethod_e dtlm,
+                                    const ZSTD_CDict* cdict,
+                                    ZSTD_CCtx_params params,
+                                    unsigned long long pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog);
+    /* compression parameters verification and optimization */
+    CHECK_F( ZSTD_checkCParams(params.cParams) );
+    return ZSTD_compressBegin_internal(cctx,
+                                       dict, dictSize, dictContentType, dtlm,
+                                       cdict,
+                                       params, pledgedSrcSize,
+                                       ZSTDb_not_buffered);
+}
+
+/*! ZSTD_compressBegin_advanced() :
+*   @return : 0, or an error code */
+size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
+                             const void* dict, size_t dictSize,
+                                   ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+    ZSTD_CCtx_params const cctxParams =
+            ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+    return ZSTD_compressBegin_advanced_internal(cctx,
+                                            dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
+                                            NULL /*cdict*/,
+                                            cctxParams, pledgedSrcSize);
+}
+
+size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
+{
+    ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+    ZSTD_CCtx_params const cctxParams =
+            ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+    DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
+    return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
+                                       cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
+}
+
+size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
+{
+    return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
+}
+
+
+/*! ZSTD_writeEpilogue() :
+*   Ends a frame.
+*   @return : nb of bytes written into dst (or an error code) */
+static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
+{
+    BYTE* const ostart = (BYTE*)dst;
+    BYTE* op = ostart;
+    size_t fhSize = 0;
+
+    DEBUGLOG(4, "ZSTD_writeEpilogue");
+    if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong);  /* init missing */
+
+    /* special case : empty frame */
+    if (cctx->stage == ZSTDcs_init) {
+        fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
+        if (ZSTD_isError(fhSize)) return fhSize;
+        dstCapacity -= fhSize;
+        op += fhSize;
+        cctx->stage = ZSTDcs_ongoing;
+    }
+
+    if (cctx->stage != ZSTDcs_ending) {
+        /* write one last empty block, make it the "last" block */
+        U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
+        if (dstCapacity<4) return ERROR(dstSize_tooSmall);
+        MEM_writeLE32(op, cBlockHeader24);
+        op += ZSTD_blockHeaderSize;
+        dstCapacity -= ZSTD_blockHeaderSize;
+    }
+
+    if (cctx->appliedParams.fParams.checksumFlag) {
+        U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
+        if (dstCapacity<4) return ERROR(dstSize_tooSmall);
+        DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
+        MEM_writeLE32(op, checksum);
+        op += 4;
+    }
+
+    cctx->stage = ZSTDcs_created;  /* return to "created but no init" status */
+    return op-ostart;
+}
+
+size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
+                         void* dst, size_t dstCapacity,
+                   const void* src, size_t srcSize)
+{
+    size_t endResult;
+    size_t const cSize = ZSTD_compressContinue_internal(cctx,
+                                dst, dstCapacity, src, srcSize,
+                                1 /* frame mode */, 1 /* last chunk */);
+    if (ZSTD_isError(cSize)) return cSize;
+    endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
+    if (ZSTD_isError(endResult)) return endResult;
+    assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
+    if (cctx->pledgedSrcSizePlusOne != 0) {  /* control src size */
+        ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
+        DEBUGLOG(4, "end of frame : controlling src size");
+        if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
+            DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u",
+                (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize);
+            return ERROR(srcSize_wrong);
+    }   }
+    return cSize + endResult;
+}
+
+
+static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
+                                      void* dst, size_t dstCapacity,
+                                const void* src, size_t srcSize,
+                                const void* dict,size_t dictSize,
+                                      ZSTD_parameters params)
+{
+    ZSTD_CCtx_params const cctxParams =
+            ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+    DEBUGLOG(4, "ZSTD_compress_internal");
+    return ZSTD_compress_advanced_internal(cctx,
+                                           dst, dstCapacity,
+                                           src, srcSize,
+                                           dict, dictSize,
+                                           cctxParams);
+}
+
+size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
+                               void* dst, size_t dstCapacity,
+                         const void* src, size_t srcSize,
+                         const void* dict,size_t dictSize,
+                               ZSTD_parameters params)
+{
+    DEBUGLOG(4, "ZSTD_compress_advanced");
+    CHECK_F(ZSTD_checkCParams(params.cParams));
+    return ZSTD_compress_internal(cctx,
+                                  dst, dstCapacity,
+                                  src, srcSize,
+                                  dict, dictSize,
+                                  params);
+}
+
+/* Internal */
+size_t ZSTD_compress_advanced_internal(
+        ZSTD_CCtx* cctx,
+        void* dst, size_t dstCapacity,
+        const void* src, size_t srcSize,
+        const void* dict,size_t dictSize,
+        ZSTD_CCtx_params params)
+{
+    DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize);
+    CHECK_F( ZSTD_compressBegin_internal(cctx,
+                         dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
+                         params, srcSize, ZSTDb_not_buffered) );
+    return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+}
+
+size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
+                               void* dst, size_t dstCapacity,
+                         const void* src, size_t srcSize,
+                         const void* dict, size_t dictSize,
+                               int compressionLevel)
+{
+    ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0);
+    ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+    assert(params.fParams.contentSizeFlag == 1);
+    return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams);
+}
+
+size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
+                         void* dst, size_t dstCapacity,
+                   const void* src, size_t srcSize,
+                         int compressionLevel)
+{
+    DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize);
+    assert(cctx != NULL);
+    return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
+}
+
+size_t ZSTD_compress(void* dst, size_t dstCapacity,
+               const void* src, size_t srcSize,
+                     int compressionLevel)
+{
+    size_t result;
+    ZSTD_CCtx ctxBody;
+    ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
+    result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
+    ZSTD_freeCCtxContent(&ctxBody);   /* can't free ctxBody itself, as it's on stack; free only heap content */
+    return result;
+}
+
+
+/* =====  Dictionary API  ===== */
+
+/*! ZSTD_estimateCDictSize_advanced() :
+ *  Estimate amount of memory that will be needed to create a dictionary with following arguments */
+size_t ZSTD_estimateCDictSize_advanced(
+        size_t dictSize, ZSTD_compressionParameters cParams,
+        ZSTD_dictLoadMethod_e dictLoadMethod)
+{
+    DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
+    return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
+           + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+}
+
+size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
+{
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
+    return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
+}
+
+size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
+{
+    if (cdict==NULL) return 0;   /* support sizeof on NULL */
+    DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict));
+    return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
+}
+
+static size_t ZSTD_initCDict_internal(
+                    ZSTD_CDict* cdict,
+              const void* dictBuffer, size_t dictSize,
+                    ZSTD_dictLoadMethod_e dictLoadMethod,
+                    ZSTD_dictContentType_e dictContentType,
+                    ZSTD_compressionParameters cParams)
+{
+    DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
+    assert(!ZSTD_checkCParams(cParams));
+    cdict->matchState.cParams = cParams;
+    if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
+        cdict->dictBuffer = NULL;
+        cdict->dictContent = dictBuffer;
+    } else {
+        void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem);
+        cdict->dictBuffer = internalBuffer;
+        cdict->dictContent = internalBuffer;
+        if (!internalBuffer) return ERROR(memory_allocation);
+        memcpy(internalBuffer, dictBuffer, dictSize);
+    }
+    cdict->dictContentSize = dictSize;
+
+    /* Reset the state to no dictionary */
+    ZSTD_reset_compressedBlockState(&cdict->cBlockState);
+    {   void* const end = ZSTD_reset_matchState(
+                &cdict->matchState,
+                (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32,
+                &cParams, ZSTDcrp_continue, /* forCCtx */ 0);
+        assert(end == (char*)cdict->workspace + cdict->workspaceSize);
+        (void)end;
+    }
+    /* (Maybe) load the dictionary
+     * Skips loading the dictionary if it is <= 8 bytes.
+     */
+    {   ZSTD_CCtx_params params;
+        memset(&params, 0, sizeof(params));
+        params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
+        params.fParams.contentSizeFlag = 1;
+        params.cParams = cParams;
+        {   size_t const dictID = ZSTD_compress_insertDictionary(
+                    &cdict->cBlockState, &cdict->matchState, &params,
+                    cdict->dictContent, cdict->dictContentSize,
+                    dictContentType, ZSTD_dtlm_full, cdict->workspace);
+            if (ZSTD_isError(dictID)) return dictID;
+            assert(dictID <= (size_t)(U32)-1);
+            cdict->dictID = (U32)dictID;
+        }
+    }
+
+    return 0;
+}
+
+ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
+                                      ZSTD_dictLoadMethod_e dictLoadMethod,
+                                      ZSTD_dictContentType_e dictContentType,
+                                      ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
+{
+    DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
+    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+    {   ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
+        size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+        void* const workspace = ZSTD_malloc(workspaceSize, customMem);
+
+        if (!cdict || !workspace) {
+            ZSTD_free(cdict, customMem);
+            ZSTD_free(workspace, customMem);
+            return NULL;
+        }
+        cdict->customMem = customMem;
+        cdict->workspace = workspace;
+        cdict->workspaceSize = workspaceSize;
+        if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+                                        dictBuffer, dictSize,
+                                        dictLoadMethod, dictContentType,
+                                        cParams) )) {
+            ZSTD_freeCDict(cdict);
+            return NULL;
+        }
+
+        return cdict;
+    }
+}
+
+ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
+{
+    ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
+    return ZSTD_createCDict_advanced(dict, dictSize,
+                                     ZSTD_dlm_byCopy, ZSTD_dct_auto,
+                                     cParams, ZSTD_defaultCMem);
+}
+
+ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
+{
+    ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
+    return ZSTD_createCDict_advanced(dict, dictSize,
+                                     ZSTD_dlm_byRef, ZSTD_dct_auto,
+                                     cParams, ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
+{
+    if (cdict==NULL) return 0;   /* support free on NULL */
+    {   ZSTD_customMem const cMem = cdict->customMem;
+        ZSTD_free(cdict->workspace, cMem);
+        ZSTD_free(cdict->dictBuffer, cMem);
+        ZSTD_free(cdict, cMem);
+        return 0;
+    }
+}
+
+/*! ZSTD_initStaticCDict_advanced() :
+ *  Generate a digested dictionary in provided memory area.
+ *  workspace: The memory area to emplace the dictionary into.
+ *             Provided pointer must 8-bytes aligned.
+ *             It must outlive dictionary usage.
+ *  workspaceSize: Use ZSTD_estimateCDictSize()
+ *                 to determine how large workspace must be.
+ *  cParams : use ZSTD_getCParams() to transform a compression level
+ *            into its relevants cParams.
+ * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
+ *  Note : there is no corresponding "free" function.
+ *         Since workspace was allocated externally, it must be freed externally.
+ */
+const ZSTD_CDict* ZSTD_initStaticCDict(
+                                 void* workspace, size_t workspaceSize,
+                           const void* dict, size_t dictSize,
+                                 ZSTD_dictLoadMethod_e dictLoadMethod,
+                                 ZSTD_dictContentType_e dictContentType,
+                                 ZSTD_compressionParameters cParams)
+{
+    size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+    size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
+                            + HUF_WORKSPACE_SIZE + matchStateSize;
+    ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
+    void* ptr;
+    if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
+    DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
+        (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
+    if (workspaceSize < neededSize) return NULL;
+
+    if (dictLoadMethod == ZSTD_dlm_byCopy) {
+        memcpy(cdict+1, dict, dictSize);
+        dict = cdict+1;
+        ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
+    } else {
+        ptr = cdict+1;
+    }
+    cdict->workspace = ptr;
+    cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize;
+
+    if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+                                              dict, dictSize,
+                                              ZSTD_dlm_byRef, dictContentType,
+                                              cParams) ))
+        return NULL;
+
+    return cdict;
+}
+
+ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
+{
+    assert(cdict != NULL);
+    return cdict->matchState.cParams;
+}
+
+/* ZSTD_compressBegin_usingCDict_advanced() :
+ * cdict must be != NULL */
+size_t ZSTD_compressBegin_usingCDict_advanced(
+    ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
+    ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
+    if (cdict==NULL) return ERROR(dictionary_wrong);
+    {   ZSTD_CCtx_params params = cctx->requestedParams;
+        params.cParams = ZSTD_getCParamsFromCDict(cdict);
+        /* Increase window log to fit the entire dictionary and source if the
+         * source size is known. Limit the increase to 19, which is the
+         * window log for compression level 1 with the largest source size.
+         */
+        if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+            U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
+            U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
+            params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
+        }
+        params.fParams = fParams;
+        return ZSTD_compressBegin_internal(cctx,
+                                           NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
+                                           cdict,
+                                           params, pledgedSrcSize,
+                                           ZSTDb_not_buffered);
+    }
+}
+
+/* ZSTD_compressBegin_usingCDict() :
+ * pledgedSrcSize=0 means "unknown"
+ * if pledgedSrcSize>0, it will enable contentSizeFlag */
+size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
+{
+    ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+    DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
+    return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+                                void* dst, size_t dstCapacity,
+                                const void* src, size_t srcSize,
+                                const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
+{
+    CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize));   /* will check if cdict != NULL */
+    return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+}
+
+/*! ZSTD_compress_usingCDict() :
+ *  Compression using a digested Dictionary.
+ *  Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
+ *  Note that compression parameters are decided at CDict creation time
+ *  while frame parameters are hardcoded */
+size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
+                                void* dst, size_t dstCapacity,
+                                const void* src, size_t srcSize,
+                                const ZSTD_CDict* cdict)
+{
+    ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+    return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+}
+
+
+
+/* ******************************************************************
+*  Streaming
+********************************************************************/
+
+ZSTD_CStream* ZSTD_createCStream(void)
+{
+    DEBUGLOG(3, "ZSTD_createCStream");
+    return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
+}
+
+ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
+{
+    return ZSTD_initStaticCCtx(workspace, workspaceSize);
+}
+
+ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
+{   /* CStream and CCtx are now same object */
+    return ZSTD_createCCtx_advanced(customMem);
+}
+
+size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
+{
+    return ZSTD_freeCCtx(zcs);   /* same object */
+}
+
+
+
+/*======   Initialization   ======*/
+
+size_t ZSTD_CStreamInSize(void)  { return ZSTD_BLOCKSIZE_MAX; }
+
+size_t ZSTD_CStreamOutSize(void)
+{
+    return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
+}
+
+static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
+                    const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
+                    const ZSTD_CDict* const cdict,
+                    ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_resetCStream_internal");
+    /* Finalize the compression parameters */
+    params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
+    /* params are supposed to be fully validated at this point */
+    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+    assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
+
+    CHECK_F( ZSTD_compressBegin_internal(cctx,
+                                         dict, dictSize, dictContentType, ZSTD_dtlm_fast,
+                                         cdict,
+                                         params, pledgedSrcSize,
+                                         ZSTDb_buffered) );
+
+    cctx->inToCompress = 0;
+    cctx->inBuffPos = 0;
+    cctx->inBuffTarget = cctx->blockSize
+                      + (cctx->blockSize == pledgedSrcSize);   /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
+    cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
+    cctx->streamStage = zcss_load;
+    cctx->frameEnded = 0;
+    return 0;   /* ready to go */
+}
+
+/* ZSTD_resetCStream():
+ * pledgedSrcSize == 0 means "unknown" */
+size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
+{
+    ZSTD_CCtx_params params = zcs->requestedParams;
+    DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize);
+    if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+    params.fParams.contentSizeFlag = 1;
+    return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
+}
+
+/*! ZSTD_initCStream_internal() :
+ *  Note : for lib/compress only. Used by zstdmt_compress.c.
+ *  Assumption 1 : params are valid
+ *  Assumption 2 : either dict, or cdict, is defined, not both */
+size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
+                    const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
+                    ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_initCStream_internal");
+    params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
+    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+    assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
+
+    if (dict && dictSize >= 8) {
+        DEBUGLOG(4, "loading dictionary of size %u", (unsigned)dictSize);
+        if (zcs->staticSize) {   /* static CCtx : never uses malloc */
+            /* incompatible with internal cdict creation */
+            return ERROR(memory_allocation);
+        }
+        ZSTD_freeCDict(zcs->cdictLocal);
+        zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
+                                            ZSTD_dlm_byCopy, ZSTD_dct_auto,
+                                            params.cParams, zcs->customMem);
+        zcs->cdict = zcs->cdictLocal;
+        if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
+    } else {
+        if (cdict) {
+            params.cParams = ZSTD_getCParamsFromCDict(cdict);  /* cParams are enforced from cdict; it includes windowLog */
+        }
+        ZSTD_freeCDict(zcs->cdictLocal);
+        zcs->cdictLocal = NULL;
+        zcs->cdict = cdict;
+    }
+
+    return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
+}
+
+/* ZSTD_initCStream_usingCDict_advanced() :
+ * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
+size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
+                                            const ZSTD_CDict* cdict,
+                                            ZSTD_frameParameters fParams,
+                                            unsigned long long pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
+    if (!cdict) return ERROR(dictionary_wrong); /* cannot handle NULL cdict (does not know what to do) */
+    {   ZSTD_CCtx_params params = zcs->requestedParams;
+        params.cParams = ZSTD_getCParamsFromCDict(cdict);
+        params.fParams = fParams;
+        return ZSTD_initCStream_internal(zcs,
+                                NULL, 0, cdict,
+                                params, pledgedSrcSize);
+    }
+}
+
+/* note : cdict must outlive compression session */
+size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
+{
+    ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksum */, 0 /* hideDictID */ };
+    DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
+    return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);  /* note : will check that cdict != NULL */
+}
+
+
+/* ZSTD_initCStream_advanced() :
+ * pledgedSrcSize must be exact.
+ * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
+ * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */
+size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
+                                 const void* dict, size_t dictSize,
+                                 ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u",
+                (unsigned)pledgedSrcSize, params.fParams.contentSizeFlag);
+    CHECK_F( ZSTD_checkCParams(params.cParams) );
+    if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;  /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */
+    zcs->requestedParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
+    return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, zcs->requestedParams, pledgedSrcSize);
+}
+
+size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
+{
+    ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel);
+    return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, zcs->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
+{
+    U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;  /* temporary : 0 interpreted as "unknown" during transition period. Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. `0` will be interpreted as "empty" in the future */
+    ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel);
+    return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, zcs->requestedParams, pledgedSrcSize);
+}
+
+size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
+{
+    DEBUGLOG(4, "ZSTD_initCStream");
+    return ZSTD_initCStream_srcSize(zcs, compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+/*======   Compression   ======*/
+
+static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx)
+{
+    size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos;
+    if (hintInSize==0) hintInSize = cctx->blockSize;
+    return hintInSize;
+}
+
+static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
+                       const void* src, size_t srcSize)
+{
+    size_t const length = MIN(dstCapacity, srcSize);
+    if (length) memcpy(dst, src, length);
+    return length;
+}
+
+/** ZSTD_compressStream_generic():
+ *  internal function for all *compressStream*() variants
+ *  non-static, because can be called from zstdmt_compress.c
+ * @return : hint size for next input */
+size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
+                                   ZSTD_outBuffer* output,
+                                   ZSTD_inBuffer* input,
+                                   ZSTD_EndDirective const flushMode)
+{
+    const char* const istart = (const char*)input->src;
+    const char* const iend = istart + input->size;
+    const char* ip = istart + input->pos;
+    char* const ostart = (char*)output->dst;
+    char* const oend = ostart + output->size;
+    char* op = ostart + output->pos;
+    U32 someMoreWork = 1;
+
+    /* check expectations */
+    DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
+    assert(zcs->inBuff != NULL);
+    assert(zcs->inBuffSize > 0);
+    assert(zcs->outBuff !=  NULL);
+    assert(zcs->outBuffSize > 0);
+    assert(output->pos <= output->size);
+    assert(input->pos <= input->size);
+
+    while (someMoreWork) {
+        switch(zcs->streamStage)
+        {
+        case zcss_init:
+            /* call ZSTD_initCStream() first ! */
+            return ERROR(init_missing);
+
+        case zcss_load:
+            if ( (flushMode == ZSTD_e_end)
+              && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip))  /* enough dstCapacity */
+              && (zcs->inBuffPos == 0) ) {
+                /* shortcut to compression pass directly into output buffer */
+                size_t const cSize = ZSTD_compressEnd(zcs,
+                                                op, oend-op, ip, iend-ip);
+                DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize);
+                if (ZSTD_isError(cSize)) return cSize;
+                ip = iend;
+                op += cSize;
+                zcs->frameEnded = 1;
+                ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+                someMoreWork = 0; break;
+            }
+            /* complete loading into inBuffer */
+            {   size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
+                size_t const loaded = ZSTD_limitCopy(
+                                        zcs->inBuff + zcs->inBuffPos, toLoad,
+                                        ip, iend-ip);
+                zcs->inBuffPos += loaded;
+                ip += loaded;
+                if ( (flushMode == ZSTD_e_continue)
+                  && (zcs->inBuffPos < zcs->inBuffTarget) ) {
+                    /* not enough input to fill full block : stop here */
+                    someMoreWork = 0; break;
+                }
+                if ( (flushMode == ZSTD_e_flush)
+                  && (zcs->inBuffPos == zcs->inToCompress) ) {
+                    /* empty */
+                    someMoreWork = 0; break;
+                }
+            }
+            /* compress current block (note : this stage cannot be stopped in the middle) */
+            DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
+            {   void* cDst;
+                size_t cSize;
+                size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
+                size_t oSize = oend-op;
+                unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
+                if (oSize >= ZSTD_compressBound(iSize))
+                    cDst = op;   /* compress into output buffer, to skip flush stage */
+                else
+                    cDst = zcs->outBuff, oSize = zcs->outBuffSize;
+                cSize = lastBlock ?
+                        ZSTD_compressEnd(zcs, cDst, oSize,
+                                    zcs->inBuff + zcs->inToCompress, iSize) :
+                        ZSTD_compressContinue(zcs, cDst, oSize,
+                                    zcs->inBuff + zcs->inToCompress, iSize);
+                if (ZSTD_isError(cSize)) return cSize;
+                zcs->frameEnded = lastBlock;
+                /* prepare next block */
+                zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
+                if (zcs->inBuffTarget > zcs->inBuffSize)
+                    zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
+                DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
+                         (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
+                if (!lastBlock)
+                    assert(zcs->inBuffTarget <= zcs->inBuffSize);
+                zcs->inToCompress = zcs->inBuffPos;
+                if (cDst == op) {  /* no need to flush */
+                    op += cSize;
+                    if (zcs->frameEnded) {
+                        DEBUGLOG(5, "Frame completed directly in outBuffer");
+                        someMoreWork = 0;
+                        ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+                    }
+                    break;
+                }
+                zcs->outBuffContentSize = cSize;
+                zcs->outBuffFlushedSize = 0;
+                zcs->streamStage = zcss_flush; /* pass-through to flush stage */
+            }
+	    /* fall-through */
+        case zcss_flush:
+            DEBUGLOG(5, "flush stage");
+            {   size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
+                size_t const flushed = ZSTD_limitCopy(op, oend-op,
+                            zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
+                DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
+                            (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
+                op += flushed;
+                zcs->outBuffFlushedSize += flushed;
+                if (toFlush!=flushed) {
+                    /* flush not fully completed, presumably because dst is too small */
+                    assert(op==oend);
+                    someMoreWork = 0;
+                    break;
+                }
+                zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
+                if (zcs->frameEnded) {
+                    DEBUGLOG(5, "Frame completed on flush");
+                    someMoreWork = 0;
+                    ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+                    break;
+                }
+                zcs->streamStage = zcss_load;
+                break;
+            }
+
+        default: /* impossible */
+            assert(0);
+        }
+    }
+
+    input->pos = ip - istart;
+    output->pos = op - ostart;
+    if (zcs->frameEnded) return 0;
+    return ZSTD_nextInputSizeHint(zcs);
+}
+
+static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+    if (cctx->appliedParams.nbWorkers >= 1) {
+        assert(cctx->mtctx != NULL);
+        return ZSTDMT_nextInputSizeHint(cctx->mtctx);
+    }
+#endif
+    return ZSTD_nextInputSizeHint(cctx);
+
+}
+
+size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+    CHECK_F( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) );
+    return ZSTD_nextInputSizeHint_MTorST(zcs);
+}
+
+
+size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
+                             ZSTD_outBuffer* output,
+                             ZSTD_inBuffer* input,
+                             ZSTD_EndDirective endOp)
+{
+    DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
+    /* check conditions */
+    if (output->pos > output->size) return ERROR(GENERIC);
+    if (input->pos  > input->size)  return ERROR(GENERIC);
+    assert(cctx!=NULL);
+
+    /* transparent initialization stage */
+    if (cctx->streamStage == zcss_init) {
+        ZSTD_CCtx_params params = cctx->requestedParams;
+        ZSTD_prefixDict const prefixDict = cctx->prefixDict;
+        memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));   /* single usage */
+        assert(prefixDict.dict==NULL || cctx->cdict==NULL);    /* only one can be set */
+        DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
+        if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1;  /* auto-fix pledgedSrcSize */
+        params.cParams = ZSTD_getCParamsFromCCtxParams(
+                &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
+
+
+#ifdef ZSTD_MULTITHREAD
+        if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
+            params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
+        }
+        if (params.nbWorkers > 0) {
+            /* mt context creation */
+            if (cctx->mtctx == NULL) {
+                DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
+                            params.nbWorkers);
+                cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem);
+                if (cctx->mtctx == NULL) return ERROR(memory_allocation);
+            }
+            /* mt compression */
+            DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
+            CHECK_F( ZSTDMT_initCStream_internal(
+                        cctx->mtctx,
+                        prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent,
+                        cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
+            cctx->streamStage = zcss_load;
+            cctx->appliedParams.nbWorkers = params.nbWorkers;
+        } else
+#endif
+        {   CHECK_F( ZSTD_resetCStream_internal(cctx,
+                            prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
+                            cctx->cdict,
+                            params, cctx->pledgedSrcSizePlusOne-1) );
+            assert(cctx->streamStage == zcss_load);
+            assert(cctx->appliedParams.nbWorkers == 0);
+    }   }
+    /* end of transparent initialization stage */
+
+    /* compression stage */
+#ifdef ZSTD_MULTITHREAD
+    if (cctx->appliedParams.nbWorkers > 0) {
+        if (cctx->cParamsChanged) {
+            ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
+            cctx->cParamsChanged = 0;
+        }
+        {   size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
+            if ( ZSTD_isError(flushMin)
+              || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
+                ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+            }
+            DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
+            return flushMin;
+    }   }
+#endif
+    CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
+    DEBUGLOG(5, "completed ZSTD_compressStream2");
+    return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
+}
+
+size_t ZSTD_compressStream2_simpleArgs (
+                            ZSTD_CCtx* cctx,
+                            void* dst, size_t dstCapacity, size_t* dstPos,
+                      const void* src, size_t srcSize, size_t* srcPos,
+                            ZSTD_EndDirective endOp)
+{
+    ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
+    ZSTD_inBuffer  input  = { src, srcSize, *srcPos };
+    /* ZSTD_compressStream2() will check validity of dstPos and srcPos */
+    size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp);
+    *dstPos = output.pos;
+    *srcPos = input.pos;
+    return cErr;
+}
+
+size_t ZSTD_compress2(ZSTD_CCtx* cctx,
+                      void* dst, size_t dstCapacity,
+                      const void* src, size_t srcSize)
+{
+    ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+    {   size_t oPos = 0;
+        size_t iPos = 0;
+        size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
+                                        dst, dstCapacity, &oPos,
+                                        src, srcSize, &iPos,
+                                        ZSTD_e_end);
+        if (ZSTD_isError(result)) return result;
+        if (result != 0) {  /* compression not completed, due to lack of output space */
+            assert(oPos == dstCapacity);
+            return ERROR(dstSize_tooSmall);
+        }
+        assert(iPos == srcSize);   /* all input is expected consumed */
+        return oPos;
+    }
+}
+
+/*======   Finalize   ======*/
+
+/*! ZSTD_flushStream() :
+ * @return : amount of data remaining to flush */
+size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+{
+    ZSTD_inBuffer input = { NULL, 0, 0 };
+    return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush);
+}
+
+
+size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+{
+    ZSTD_inBuffer input = { NULL, 0, 0 };
+    size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end);
+    CHECK_F( remainingToFlush );
+    if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush;   /* minimal estimation */
+    /* single thread mode : attempt to calculate remaining to flush more precisely */
+    {   size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
+        size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
+        size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize;
+        DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush);
+        return toFlush;
+    }
+}
+
+
+/*-=====  Pre-defined compression levels  =====-*/
+
+#define ZSTD_MAX_CLEVEL     22
+int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
+int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
+
+static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
+{   /* "default" - guarantees a monotonically increasing memory budget */
+    /* W,  C,  H,  S,  L, TL, strat */
+    { 19, 12, 13,  1,  6,  1, ZSTD_fast    },  /* base for negative levels */
+    { 19, 13, 14,  1,  7,  0, ZSTD_fast    },  /* level  1 */
+    { 20, 15, 16,  1,  6,  0, ZSTD_fast    },  /* level  2 */
+    { 21, 16, 17,  1,  5,  1, ZSTD_dfast   },  /* level  3 */
+    { 21, 18, 18,  1,  5,  1, ZSTD_dfast   },  /* level  4 */
+    { 21, 18, 19,  2,  5,  2, ZSTD_greedy  },  /* level  5 */
+    { 21, 19, 19,  3,  5,  4, ZSTD_greedy  },  /* level  6 */
+    { 21, 19, 19,  3,  5,  8, ZSTD_lazy    },  /* level  7 */
+    { 21, 19, 19,  3,  5, 16, ZSTD_lazy2   },  /* level  8 */
+    { 21, 19, 20,  4,  5, 16, ZSTD_lazy2   },  /* level  9 */
+    { 22, 20, 21,  4,  5, 16, ZSTD_lazy2   },  /* level 10 */
+    { 22, 21, 22,  4,  5, 16, ZSTD_lazy2   },  /* level 11 */
+    { 22, 21, 22,  5,  5, 16, ZSTD_lazy2   },  /* level 12 */
+    { 22, 21, 22,  5,  5, 32, ZSTD_btlazy2 },  /* level 13 */
+    { 22, 22, 23,  5,  5, 32, ZSTD_btlazy2 },  /* level 14 */
+    { 22, 23, 23,  6,  5, 32, ZSTD_btlazy2 },  /* level 15 */
+    { 22, 22, 22,  5,  5, 48, ZSTD_btopt   },  /* level 16 */
+    { 23, 23, 22,  5,  4, 64, ZSTD_btopt   },  /* level 17 */
+    { 23, 23, 22,  6,  3, 64, ZSTD_btultra },  /* level 18 */
+    { 23, 24, 22,  7,  3,256, ZSTD_btultra2},  /* level 19 */
+    { 25, 25, 23,  7,  3,256, ZSTD_btultra2},  /* level 20 */
+    { 26, 26, 24,  7,  3,512, ZSTD_btultra2},  /* level 21 */
+    { 27, 27, 25,  9,  3,999, ZSTD_btultra2},  /* level 22 */
+},
+{   /* for srcSize <= 256 KB */
+    /* W,  C,  H,  S,  L,  T, strat */
+    { 18, 12, 13,  1,  5,  1, ZSTD_fast    },  /* base for negative levels */
+    { 18, 13, 14,  1,  6,  0, ZSTD_fast    },  /* level  1 */
+    { 18, 14, 14,  1,  5,  1, ZSTD_dfast   },  /* level  2 */
+    { 18, 16, 16,  1,  4,  1, ZSTD_dfast   },  /* level  3 */
+    { 18, 16, 17,  2,  5,  2, ZSTD_greedy  },  /* level  4.*/
+    { 18, 18, 18,  3,  5,  2, ZSTD_greedy  },  /* level  5.*/
+    { 18, 18, 19,  3,  5,  4, ZSTD_lazy    },  /* level  6.*/
+    { 18, 18, 19,  4,  4,  4, ZSTD_lazy    },  /* level  7 */
+    { 18, 18, 19,  4,  4,  8, ZSTD_lazy2   },  /* level  8 */
+    { 18, 18, 19,  5,  4,  8, ZSTD_lazy2   },  /* level  9 */
+    { 18, 18, 19,  6,  4,  8, ZSTD_lazy2   },  /* level 10 */
+    { 18, 18, 19,  5,  4, 12, ZSTD_btlazy2 },  /* level 11.*/
+    { 18, 19, 19,  7,  4, 12, ZSTD_btlazy2 },  /* level 12.*/
+    { 18, 18, 19,  4,  4, 16, ZSTD_btopt   },  /* level 13 */
+    { 18, 18, 19,  4,  3, 32, ZSTD_btopt   },  /* level 14.*/
+    { 18, 18, 19,  6,  3,128, ZSTD_btopt   },  /* level 15.*/
+    { 18, 19, 19,  6,  3,128, ZSTD_btultra },  /* level 16.*/
+    { 18, 19, 19,  8,  3,256, ZSTD_btultra },  /* level 17.*/
+    { 18, 19, 19,  6,  3,128, ZSTD_btultra2},  /* level 18.*/
+    { 18, 19, 19,  8,  3,256, ZSTD_btultra2},  /* level 19.*/
+    { 18, 19, 19, 10,  3,512, ZSTD_btultra2},  /* level 20.*/
+    { 18, 19, 19, 12,  3,512, ZSTD_btultra2},  /* level 21.*/
+    { 18, 19, 19, 13,  3,999, ZSTD_btultra2},  /* level 22.*/
+},
+{   /* for srcSize <= 128 KB */
+    /* W,  C,  H,  S,  L,  T, strat */
+    { 17, 12, 12,  1,  5,  1, ZSTD_fast    },  /* base for negative levels */
+    { 17, 12, 13,  1,  6,  0, ZSTD_fast    },  /* level  1 */
+    { 17, 13, 15,  1,  5,  0, ZSTD_fast    },  /* level  2 */
+    { 17, 15, 16,  2,  5,  1, ZSTD_dfast   },  /* level  3 */
+    { 17, 17, 17,  2,  4,  1, ZSTD_dfast   },  /* level  4 */
+    { 17, 16, 17,  3,  4,  2, ZSTD_greedy  },  /* level  5 */
+    { 17, 17, 17,  3,  4,  4, ZSTD_lazy    },  /* level  6 */
+    { 17, 17, 17,  3,  4,  8, ZSTD_lazy2   },  /* level  7 */
+    { 17, 17, 17,  4,  4,  8, ZSTD_lazy2   },  /* level  8 */
+    { 17, 17, 17,  5,  4,  8, ZSTD_lazy2   },  /* level  9 */
+    { 17, 17, 17,  6,  4,  8, ZSTD_lazy2   },  /* level 10 */
+    { 17, 17, 17,  5,  4,  8, ZSTD_btlazy2 },  /* level 11 */
+    { 17, 18, 17,  7,  4, 12, ZSTD_btlazy2 },  /* level 12 */
+    { 17, 18, 17,  3,  4, 12, ZSTD_btopt   },  /* level 13.*/
+    { 17, 18, 17,  4,  3, 32, ZSTD_btopt   },  /* level 14.*/
+    { 17, 18, 17,  6,  3,256, ZSTD_btopt   },  /* level 15.*/
+    { 17, 18, 17,  6,  3,128, ZSTD_btultra },  /* level 16.*/
+    { 17, 18, 17,  8,  3,256, ZSTD_btultra },  /* level 17.*/
+    { 17, 18, 17, 10,  3,512, ZSTD_btultra },  /* level 18.*/
+    { 17, 18, 17,  5,  3,256, ZSTD_btultra2},  /* level 19.*/
+    { 17, 18, 17,  7,  3,512, ZSTD_btultra2},  /* level 20.*/
+    { 17, 18, 17,  9,  3,512, ZSTD_btultra2},  /* level 21.*/
+    { 17, 18, 17, 11,  3,999, ZSTD_btultra2},  /* level 22.*/
+},
+{   /* for srcSize <= 16 KB */
+    /* W,  C,  H,  S,  L,  T, strat */
+    { 14, 12, 13,  1,  5,  1, ZSTD_fast    },  /* base for negative levels */
+    { 14, 14, 15,  1,  5,  0, ZSTD_fast    },  /* level  1 */
+    { 14, 14, 15,  1,  4,  0, ZSTD_fast    },  /* level  2 */
+    { 14, 14, 15,  2,  4,  1, ZSTD_dfast   },  /* level  3 */
+    { 14, 14, 14,  4,  4,  2, ZSTD_greedy  },  /* level  4 */
+    { 14, 14, 14,  3,  4,  4, ZSTD_lazy    },  /* level  5.*/
+    { 14, 14, 14,  4,  4,  8, ZSTD_lazy2   },  /* level  6 */
+    { 14, 14, 14,  6,  4,  8, ZSTD_lazy2   },  /* level  7 */
+    { 14, 14, 14,  8,  4,  8, ZSTD_lazy2   },  /* level  8.*/
+    { 14, 15, 14,  5,  4,  8, ZSTD_btlazy2 },  /* level  9.*/
+    { 14, 15, 14,  9,  4,  8, ZSTD_btlazy2 },  /* level 10.*/
+    { 14, 15, 14,  3,  4, 12, ZSTD_btopt   },  /* level 11.*/
+    { 14, 15, 14,  4,  3, 24, ZSTD_btopt   },  /* level 12.*/
+    { 14, 15, 14,  5,  3, 32, ZSTD_btultra },  /* level 13.*/
+    { 14, 15, 15,  6,  3, 64, ZSTD_btultra },  /* level 14.*/
+    { 14, 15, 15,  7,  3,256, ZSTD_btultra },  /* level 15.*/
+    { 14, 15, 15,  5,  3, 48, ZSTD_btultra2},  /* level 16.*/
+    { 14, 15, 15,  6,  3,128, ZSTD_btultra2},  /* level 17.*/
+    { 14, 15, 15,  7,  3,256, ZSTD_btultra2},  /* level 18.*/
+    { 14, 15, 15,  8,  3,256, ZSTD_btultra2},  /* level 19.*/
+    { 14, 15, 15,  8,  3,512, ZSTD_btultra2},  /* level 20.*/
+    { 14, 15, 15,  9,  3,512, ZSTD_btultra2},  /* level 21.*/
+    { 14, 15, 15, 10,  3,999, ZSTD_btultra2},  /* level 22.*/
+},
+};
+
+/*! ZSTD_getCParams() :
+*  @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
+*   Size values are optional, provide 0 if not known or unused */
+ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
+{
+    size_t const addedSize = srcSizeHint ? 0 : 500;
+    U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
+    U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);   /* intentional underflow for srcSizeHint == 0 */
+    int row = compressionLevel;
+    DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel);
+    if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT;   /* 0 == default */
+    if (compressionLevel < 0) row = 0;   /* entry 0 is baseline for fast mode */
+    if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
+    {   ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
+        if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel);   /* acceleration factor */
+        return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
+    }
+}
+
+/*! ZSTD_getParams() :
+*   same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
+*   All fields of `ZSTD_frameParameters` are set to default (0) */
+ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
+    ZSTD_parameters params;
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
+    DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
+    memset(&params, 0, sizeof(params));
+    params.cParams = cParams;
+    params.fParams.contentSizeFlag = 1;
+    return params;
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_compress_internal.h b/Utilities/cmzstd/lib/compress/zstd_compress_internal.h
new file mode 100644
index 0000000..29bca59
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_compress_internal.h
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* This header contains definitions
+ * that shall **only** be used by modules within lib/compress.
+ */
+
+#ifndef ZSTD_COMPRESS_H
+#define ZSTD_COMPRESS_H
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include "zstd_internal.h"
+#ifdef ZSTD_MULTITHREAD
+#  include "zstdmt_compress.h"
+#endif
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/*-*************************************
+*  Constants
+***************************************/
+#define kSearchStrength      8
+#define HASH_READ_SIZE       8
+#define ZSTD_DUBT_UNSORTED_MARK 1   /* For btlazy2 strategy, index 1 now means "unsorted".
+                                       It could be confused for a real successor at index "1", if sorted as larger than its predecessor.
+                                       It's not a big deal though : candidate will just be sorted again.
+                                       Additionnally, candidate position 1 will be lost.
+                                       But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
+                                       The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy
+                                       Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
+
+
+/*-*************************************
+*  Context memory management
+***************************************/
+typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
+typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
+
+typedef struct ZSTD_prefixDict_s {
+    const void* dict;
+    size_t dictSize;
+    ZSTD_dictContentType_e dictContentType;
+} ZSTD_prefixDict;
+
+typedef struct {
+    U32 CTable[HUF_CTABLE_SIZE_U32(255)];
+    HUF_repeat repeatMode;
+} ZSTD_hufCTables_t;
+
+typedef struct {
+    FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
+    FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
+    FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
+    FSE_repeat offcode_repeatMode;
+    FSE_repeat matchlength_repeatMode;
+    FSE_repeat litlength_repeatMode;
+} ZSTD_fseCTables_t;
+
+typedef struct {
+    ZSTD_hufCTables_t huf;
+    ZSTD_fseCTables_t fse;
+} ZSTD_entropyCTables_t;
+
+typedef struct {
+    U32 off;
+    U32 len;
+} ZSTD_match_t;
+
+typedef struct {
+    int price;
+    U32 off;
+    U32 mlen;
+    U32 litlen;
+    U32 rep[ZSTD_REP_NUM];
+} ZSTD_optimal_t;
+
+typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
+
+typedef struct {
+    /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
+    unsigned* litFreq;           /* table of literals statistics, of size 256 */
+    unsigned* litLengthFreq;     /* table of litLength statistics, of size (MaxLL+1) */
+    unsigned* matchLengthFreq;   /* table of matchLength statistics, of size (MaxML+1) */
+    unsigned* offCodeFreq;       /* table of offCode statistics, of size (MaxOff+1) */
+    ZSTD_match_t* matchTable;    /* list of found matches, of size ZSTD_OPT_NUM+1 */
+    ZSTD_optimal_t* priceTable;  /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
+
+    U32  litSum;                 /* nb of literals */
+    U32  litLengthSum;           /* nb of litLength codes */
+    U32  matchLengthSum;         /* nb of matchLength codes */
+    U32  offCodeSum;             /* nb of offset codes */
+    U32  litSumBasePrice;        /* to compare to log2(litfreq) */
+    U32  litLengthSumBasePrice;  /* to compare to log2(llfreq)  */
+    U32  matchLengthSumBasePrice;/* to compare to log2(mlfreq)  */
+    U32  offCodeSumBasePrice;    /* to compare to log2(offreq)  */
+    ZSTD_OptPrice_e priceType;   /* prices can be determined dynamically, or follow a pre-defined cost structure */
+    const ZSTD_entropyCTables_t* symbolCosts;  /* pre-calculated dictionary statistics */
+} optState_t;
+
+typedef struct {
+  ZSTD_entropyCTables_t entropy;
+  U32 rep[ZSTD_REP_NUM];
+} ZSTD_compressedBlockState_t;
+
+typedef struct {
+    BYTE const* nextSrc;    /* next block here to continue on current prefix */
+    BYTE const* base;       /* All regular indexes relative to this position */
+    BYTE const* dictBase;   /* extDict indexes relative to this position */
+    U32 dictLimit;          /* below that point, need extDict */
+    U32 lowLimit;           /* below that point, no more data */
+} ZSTD_window_t;
+
+typedef struct ZSTD_matchState_t ZSTD_matchState_t;
+struct ZSTD_matchState_t {
+    ZSTD_window_t window;   /* State for window round buffer management */
+    U32 loadedDictEnd;      /* index of end of dictionary */
+    U32 nextToUpdate;       /* index from which to continue table update */
+    U32 nextToUpdate3;      /* index from which to continue table update */
+    U32 hashLog3;           /* dispatch table : larger == faster, more memory */
+    U32* hashTable;
+    U32* hashTable3;
+    U32* chainTable;
+    optState_t opt;         /* optimal parser state */
+    const ZSTD_matchState_t * dictMatchState;
+    ZSTD_compressionParameters cParams;
+};
+
+typedef struct {
+    ZSTD_compressedBlockState_t* prevCBlock;
+    ZSTD_compressedBlockState_t* nextCBlock;
+    ZSTD_matchState_t matchState;
+} ZSTD_blockState_t;
+
+typedef struct {
+    U32 offset;
+    U32 checksum;
+} ldmEntry_t;
+
+typedef struct {
+    ZSTD_window_t window;   /* State for the window round buffer management */
+    ldmEntry_t* hashTable;
+    BYTE* bucketOffsets;    /* Next position in bucket to insert entry */
+    U64 hashPower;          /* Used to compute the rolling hash.
+                             * Depends on ldmParams.minMatchLength */
+} ldmState_t;
+
+typedef struct {
+    U32 enableLdm;          /* 1 if enable long distance matching */
+    U32 hashLog;            /* Log size of hashTable */
+    U32 bucketSizeLog;      /* Log bucket size for collision resolution, at most 8 */
+    U32 minMatchLength;     /* Minimum match length */
+    U32 hashRateLog;       /* Log number of entries to skip */
+    U32 windowLog;          /* Window log for the LDM */
+} ldmParams_t;
+
+typedef struct {
+    U32 offset;
+    U32 litLength;
+    U32 matchLength;
+} rawSeq;
+
+typedef struct {
+  rawSeq* seq;     /* The start of the sequences */
+  size_t pos;      /* The position where reading stopped. <= size. */
+  size_t size;     /* The number of sequences. <= capacity. */
+  size_t capacity; /* The capacity starting from `seq` pointer */
+} rawSeqStore_t;
+
+struct ZSTD_CCtx_params_s {
+    ZSTD_format_e format;
+    ZSTD_compressionParameters cParams;
+    ZSTD_frameParameters fParams;
+
+    int compressionLevel;
+    int forceWindow;           /* force back-references to respect limit of
+                                * 1<<wLog, even for dictionary */
+
+    ZSTD_dictAttachPref_e attachDictPref;
+
+    /* Multithreading: used to pass parameters to mtctx */
+    int nbWorkers;
+    size_t jobSize;
+    int overlapLog;
+    int rsyncable;
+
+    /* Long distance matching parameters */
+    ldmParams_t ldmParams;
+
+    /* Internal use, for createCCtxParams() and freeCCtxParams() only */
+    ZSTD_customMem customMem;
+};  /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
+
+struct ZSTD_CCtx_s {
+    ZSTD_compressionStage_e stage;
+    int cParamsChanged;                  /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
+    int bmi2;                            /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
+    ZSTD_CCtx_params requestedParams;
+    ZSTD_CCtx_params appliedParams;
+    U32   dictID;
+
+    int workSpaceOversizedDuration;
+    void* workSpace;
+    size_t workSpaceSize;
+    size_t blockSize;
+    unsigned long long pledgedSrcSizePlusOne;  /* this way, 0 (default) == unknown */
+    unsigned long long consumedSrcSize;
+    unsigned long long producedCSize;
+    XXH64_state_t xxhState;
+    ZSTD_customMem customMem;
+    size_t staticSize;
+
+    seqStore_t seqStore;      /* sequences storage ptrs */
+    ldmState_t ldmState;      /* long distance matching state */
+    rawSeq* ldmSequences;     /* Storage for the ldm output sequences */
+    size_t maxNbLdmSequences;
+    rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */
+    ZSTD_blockState_t blockState;
+    U32* entropyWorkspace;  /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
+
+    /* streaming */
+    char*  inBuff;
+    size_t inBuffSize;
+    size_t inToCompress;
+    size_t inBuffPos;
+    size_t inBuffTarget;
+    char*  outBuff;
+    size_t outBuffSize;
+    size_t outBuffContentSize;
+    size_t outBuffFlushedSize;
+    ZSTD_cStreamStage streamStage;
+    U32    frameEnded;
+
+    /* Dictionary */
+    ZSTD_CDict* cdictLocal;
+    const ZSTD_CDict* cdict;
+    ZSTD_prefixDict prefixDict;   /* single-usage dictionary */
+
+    /* Multi-threading */
+#ifdef ZSTD_MULTITHREAD
+    ZSTDMT_CCtx* mtctx;
+#endif
+};
+
+typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
+
+typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
+
+
+typedef size_t (*ZSTD_blockCompressor) (
+        ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
+
+
+MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
+{
+    static const BYTE LL_Code[64] = {  0,  1,  2,  3,  4,  5,  6,  7,
+                                       8,  9, 10, 11, 12, 13, 14, 15,
+                                      16, 16, 17, 17, 18, 18, 19, 19,
+                                      20, 20, 20, 20, 21, 21, 21, 21,
+                                      22, 22, 22, 22, 22, 22, 22, 22,
+                                      23, 23, 23, 23, 23, 23, 23, 23,
+                                      24, 24, 24, 24, 24, 24, 24, 24,
+                                      24, 24, 24, 24, 24, 24, 24, 24 };
+    static const U32 LL_deltaCode = 19;
+    return (litLength > 63) ? ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
+}
+
+/* ZSTD_MLcode() :
+ * note : mlBase = matchLength - MINMATCH;
+ *        because it's the format it's stored in seqStore->sequences */
+MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
+{
+    static const BYTE ML_Code[128] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+                                      16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+                                      32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
+                                      38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
+                                      40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+                                      41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+                                      42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+                                      42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
+    static const U32 ML_deltaCode = 36;
+    return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
+}
+
+/*! ZSTD_storeSeq() :
+ *  Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
+ *  `offsetCode` : distance to match + 3 (values 1-3 are repCodes).
+ *  `mlBase` : matchLength - MINMATCH
+*/
+MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase)
+{
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
+    static const BYTE* g_start = NULL;
+    if (g_start==NULL) g_start = (const BYTE*)literals;  /* note : index only works for compression within a single segment */
+    {   U32 const pos = (U32)((const BYTE*)literals - g_start);
+        DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
+               pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode);
+    }
+#endif
+    assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq);
+    /* copy Literals */
+    assert(seqStorePtr->maxNbLit <= 128 KB);
+    assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
+    ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
+    seqStorePtr->lit += litLength;
+
+    /* literal Length */
+    if (litLength>0xFFFF) {
+        assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
+        seqStorePtr->longLengthID = 1;
+        seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+    }
+    seqStorePtr->sequences[0].litLength = (U16)litLength;
+
+    /* match offset */
+    seqStorePtr->sequences[0].offset = offsetCode + 1;
+
+    /* match Length */
+    if (mlBase>0xFFFF) {
+        assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
+        seqStorePtr->longLengthID = 2;
+        seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+    }
+    seqStorePtr->sequences[0].matchLength = (U16)mlBase;
+
+    seqStorePtr->sequences++;
+}
+
+
+/*-*************************************
+*  Match length counter
+***************************************/
+static unsigned ZSTD_NbCommonBytes (size_t val)
+{
+    if (MEM_isLittleEndian()) {
+        if (MEM_64bits()) {
+#       if defined(_MSC_VER) && defined(_WIN64)
+            unsigned long r = 0;
+            _BitScanForward64( &r, (U64)val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 4)
+            return (__builtin_ctzll((U64)val) >> 3);
+#       else
+            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
+                                                     0, 3, 1, 3, 1, 4, 2, 7,
+                                                     0, 2, 3, 6, 1, 5, 3, 5,
+                                                     1, 3, 4, 4, 2, 5, 6, 7,
+                                                     7, 0, 1, 2, 3, 3, 4, 6,
+                                                     2, 6, 5, 5, 3, 4, 5, 6,
+                                                     7, 1, 2, 4, 6, 4, 4, 5,
+                                                     7, 2, 6, 5, 7, 6, 7, 7 };
+            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+#       endif
+        } else { /* 32 bits */
+#       if defined(_MSC_VER)
+            unsigned long r=0;
+            _BitScanForward( &r, (U32)val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 3)
+            return (__builtin_ctz((U32)val) >> 3);
+#       else
+            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
+                                                     3, 2, 2, 1, 3, 2, 0, 1,
+                                                     3, 3, 1, 2, 2, 2, 2, 0,
+                                                     3, 1, 2, 0, 1, 0, 1, 1 };
+            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+#       endif
+        }
+    } else {  /* Big Endian CPU */
+        if (MEM_64bits()) {
+#       if defined(_MSC_VER) && defined(_WIN64)
+            unsigned long r = 0;
+            _BitScanReverse64( &r, val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 4)
+            return (__builtin_clzll(val) >> 3);
+#       else
+            unsigned r;
+            const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */
+            if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
+            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+            r += (!val);
+            return r;
+#       endif
+        } else { /* 32 bits */
+#       if defined(_MSC_VER)
+            unsigned long r = 0;
+            _BitScanReverse( &r, (unsigned long)val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 3)
+            return (__builtin_clz((U32)val) >> 3);
+#       else
+            unsigned r;
+            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+            r += (!val);
+            return r;
+#       endif
+    }   }
+}
+
+
+MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
+{
+    const BYTE* const pStart = pIn;
+    const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
+
+    if (pIn < pInLoopLimit) {
+        { size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+          if (diff) return ZSTD_NbCommonBytes(diff); }
+        pIn+=sizeof(size_t); pMatch+=sizeof(size_t);
+        while (pIn < pInLoopLimit) {
+            size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+            if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
+            pIn += ZSTD_NbCommonBytes(diff);
+            return (size_t)(pIn - pStart);
+    }   }
+    if (MEM_64bits() && (pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
+    if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
+    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
+    return (size_t)(pIn - pStart);
+}
+
+/** ZSTD_count_2segments() :
+ *  can count match length with `ip` & `match` in 2 different segments.
+ *  convention : on reaching mEnd, match count continue starting from iStart
+ */
+MEM_STATIC size_t
+ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
+                     const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
+{
+    const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
+    size_t const matchLength = ZSTD_count(ip, match, vEnd);
+    if (match + matchLength != mEnd) return matchLength;
+    DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
+    DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
+    DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
+    DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
+    DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
+    return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
+}
+
+
+/*-*************************************
+ *  Hashes
+ ***************************************/
+static const U32 prime3bytes = 506832829U;
+static U32    ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes)  >> (32-h) ; }
+MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
+
+static const U32 prime4bytes = 2654435761U;
+static U32    ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
+static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
+
+static const U64 prime5bytes = 889523592379ULL;
+static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u  << (64-40)) * prime5bytes) >> (64-h)) ; }
+static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
+
+static const U64 prime6bytes = 227718039650203ULL;
+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; }
+static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
+
+static const U64 prime7bytes = 58295818150454627ULL;
+static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u  << (64-56)) * prime7bytes) >> (64-h)) ; }
+static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
+
+static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
+static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
+
+MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
+{
+    switch(mls)
+    {
+    default:
+    case 4: return ZSTD_hash4Ptr(p, hBits);
+    case 5: return ZSTD_hash5Ptr(p, hBits);
+    case 6: return ZSTD_hash6Ptr(p, hBits);
+    case 7: return ZSTD_hash7Ptr(p, hBits);
+    case 8: return ZSTD_hash8Ptr(p, hBits);
+    }
+}
+
+/** ZSTD_ipow() :
+ * Return base^exponent.
+ */
+static U64 ZSTD_ipow(U64 base, U64 exponent)
+{
+    U64 power = 1;
+    while (exponent) {
+      if (exponent & 1) power *= base;
+      exponent >>= 1;
+      base *= base;
+    }
+    return power;
+}
+
+#define ZSTD_ROLL_HASH_CHAR_OFFSET 10
+
+/** ZSTD_rollingHash_append() :
+ * Add the buffer to the hash value.
+ */
+static U64 ZSTD_rollingHash_append(U64 hash, void const* buf, size_t size)
+{
+    BYTE const* istart = (BYTE const*)buf;
+    size_t pos;
+    for (pos = 0; pos < size; ++pos) {
+        hash *= prime8bytes;
+        hash += istart[pos] + ZSTD_ROLL_HASH_CHAR_OFFSET;
+    }
+    return hash;
+}
+
+/** ZSTD_rollingHash_compute() :
+ * Compute the rolling hash value of the buffer.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_compute(void const* buf, size_t size)
+{
+    return ZSTD_rollingHash_append(0, buf, size);
+}
+
+/** ZSTD_rollingHash_primePower() :
+ * Compute the primePower to be passed to ZSTD_rollingHash_rotate() for a hash
+ * over a window of length bytes.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_primePower(U32 length)
+{
+    return ZSTD_ipow(prime8bytes, length - 1);
+}
+
+/** ZSTD_rollingHash_rotate() :
+ * Rotate the rolling hash by one byte.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64 primePower)
+{
+    hash -= (toRemove + ZSTD_ROLL_HASH_CHAR_OFFSET) * primePower;
+    hash *= prime8bytes;
+    hash += toAdd + ZSTD_ROLL_HASH_CHAR_OFFSET;
+    return hash;
+}
+
+/*-*************************************
+*  Round buffer management
+***************************************/
+/* Max current allowed */
+#define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX))
+/* Maximum chunk size before overflow correction needs to be called again */
+#define ZSTD_CHUNKSIZE_MAX                                                     \
+    ( ((U32)-1)                  /* Maximum ending current index */            \
+    - ZSTD_CURRENT_MAX)          /* Maximum beginning lowLimit */
+
+/**
+ * ZSTD_window_clear():
+ * Clears the window containing the history by simply setting it to empty.
+ */
+MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
+{
+    size_t const endT = (size_t)(window->nextSrc - window->base);
+    U32 const end = (U32)endT;
+
+    window->lowLimit = end;
+    window->dictLimit = end;
+}
+
+/**
+ * ZSTD_window_hasExtDict():
+ * Returns non-zero if the window has a non-empty extDict.
+ */
+MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
+{
+    return window.lowLimit < window.dictLimit;
+}
+
+/**
+ * ZSTD_matchState_dictMode():
+ * Inspects the provided matchState and figures out what dictMode should be
+ * passed to the compressor.
+ */
+MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
+{
+    return ZSTD_window_hasExtDict(ms->window) ?
+        ZSTD_extDict :
+        ms->dictMatchState != NULL ?
+            ZSTD_dictMatchState :
+            ZSTD_noDict;
+}
+
+/**
+ * ZSTD_window_needOverflowCorrection():
+ * Returns non-zero if the indices are getting too large and need overflow
+ * protection.
+ */
+MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
+                                                  void const* srcEnd)
+{
+    U32 const current = (U32)((BYTE const*)srcEnd - window.base);
+    return current > ZSTD_CURRENT_MAX;
+}
+
+/**
+ * ZSTD_window_correctOverflow():
+ * Reduces the indices to protect from index overflow.
+ * Returns the correction made to the indices, which must be applied to every
+ * stored index.
+ *
+ * The least significant cycleLog bits of the indices must remain the same,
+ * which may be 0. Every index up to maxDist in the past must be valid.
+ * NOTE: (maxDist & cycleMask) must be zero.
+ */
+MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
+                                           U32 maxDist, void const* src)
+{
+    /* preemptive overflow correction:
+     * 1. correction is large enough:
+     *    lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog
+     *    1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
+     *
+     *    current - newCurrent
+     *    > (3<<29 + 1<<windowLog) - (1<<windowLog + 1<<chainLog)
+     *    > (3<<29) - (1<<chainLog)
+     *    > (3<<29) - (1<<30)             (NOTE: chainLog <= 30)
+     *    > 1<<29
+     *
+     * 2. (ip+ZSTD_CHUNKSIZE_MAX - cctx->base) doesn't overflow:
+     *    After correction, current is less than (1<<chainLog + 1<<windowLog).
+     *    In 64-bit mode we are safe, because we have 64-bit ptrdiff_t.
+     *    In 32-bit mode we are safe, because (chainLog <= 29), so
+     *    ip+ZSTD_CHUNKSIZE_MAX - cctx->base < 1<<32.
+     * 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
+     *    windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
+     */
+    U32 const cycleMask = (1U << cycleLog) - 1;
+    U32 const current = (U32)((BYTE const*)src - window->base);
+    U32 const newCurrent = (current & cycleMask) + maxDist;
+    U32 const correction = current - newCurrent;
+    assert((maxDist & cycleMask) == 0);
+    assert(current > newCurrent);
+    /* Loose bound, should be around 1<<29 (see above) */
+    assert(correction > 1<<28);
+
+    window->base += correction;
+    window->dictBase += correction;
+    window->lowLimit -= correction;
+    window->dictLimit -= correction;
+
+    DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
+             window->lowLimit);
+    return correction;
+}
+
+/**
+ * ZSTD_window_enforceMaxDist():
+ * Updates lowLimit so that:
+ *    (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
+ *
+ * This allows a simple check that index >= lowLimit to see if index is valid.
+ * This must be called before a block compression call, with srcEnd as the block
+ * source end.
+ *
+ * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit.
+ * This is because dictionaries are allowed to be referenced as long as the last
+ * byte of the dictionary is in the window, but once they are out of range,
+ * they cannot be referenced. If loadedDictEndPtr is NULL, we use
+ * loadedDictEnd == 0.
+ *
+ * In normal dict mode, the dict is between lowLimit and dictLimit. In
+ * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary
+ * is below them. forceWindow and dictMatchState are therefore incompatible.
+ */
+MEM_STATIC void
+ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
+                           void const* srcEnd,
+                           U32 maxDist,
+                           U32* loadedDictEndPtr,
+                     const ZSTD_matchState_t** dictMatchStatePtr)
+{
+    U32 const blockEndIdx = (U32)((BYTE const*)srcEnd - window->base);
+    U32 loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
+    DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u",
+                (unsigned)blockEndIdx, (unsigned)maxDist);
+    if (blockEndIdx > maxDist + loadedDictEnd) {
+        U32 const newLowLimit = blockEndIdx - maxDist;
+        if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
+        if (window->dictLimit < window->lowLimit) {
+            DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
+                        (unsigned)window->dictLimit, (unsigned)window->lowLimit);
+            window->dictLimit = window->lowLimit;
+        }
+        if (loadedDictEndPtr)
+            *loadedDictEndPtr = 0;
+        if (dictMatchStatePtr)
+            *dictMatchStatePtr = NULL;
+    }
+}
+
+/**
+ * ZSTD_window_update():
+ * Updates the window by appending [src, src + srcSize) to the window.
+ * If it is not contiguous, the current prefix becomes the extDict, and we
+ * forget about the extDict. Handles overlap of the prefix and extDict.
+ * Returns non-zero if the segment is contiguous.
+ */
+MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
+                                  void const* src, size_t srcSize)
+{
+    BYTE const* const ip = (BYTE const*)src;
+    U32 contiguous = 1;
+    DEBUGLOG(5, "ZSTD_window_update");
+    /* Check if blocks follow each other */
+    if (src != window->nextSrc) {
+        /* not contiguous */
+        size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
+        DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
+        window->lowLimit = window->dictLimit;
+        assert(distanceFromBase == (size_t)(U32)distanceFromBase);  /* should never overflow */
+        window->dictLimit = (U32)distanceFromBase;
+        window->dictBase = window->base;
+        window->base = ip - distanceFromBase;
+        // ms->nextToUpdate = window->dictLimit;
+        if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit;   /* too small extDict */
+        contiguous = 0;
+    }
+    window->nextSrc = ip + srcSize;
+    /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
+    if ( (ip+srcSize > window->dictBase + window->lowLimit)
+       & (ip < window->dictBase + window->dictLimit)) {
+        ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
+        U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
+        window->lowLimit = lowLimitMax;
+        DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
+    }
+    return contiguous;
+}
+
+
+/* debug functions */
+#if (DEBUGLEVEL>=2)
+
+MEM_STATIC double ZSTD_fWeight(U32 rawStat)
+{
+    U32 const fp_accuracy = 8;
+    U32 const fp_multiplier = (1 << fp_accuracy);
+    U32 const newStat = rawStat + 1;
+    U32 const hb = ZSTD_highbit32(newStat);
+    U32 const BWeight = hb * fp_multiplier;
+    U32 const FWeight = (newStat << fp_accuracy) >> hb;
+    U32 const weight = BWeight + FWeight;
+    assert(hb + fp_accuracy < 31);
+    return (double)weight / fp_multiplier;
+}
+
+/* display a table content,
+ * listing each element, its frequency, and its predicted bit cost */
+MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
+{
+    unsigned u, sum;
+    for (u=0, sum=0; u<=max; u++) sum += table[u];
+    DEBUGLOG(2, "total nb elts: %u", sum);
+    for (u=0; u<=max; u++) {
+        DEBUGLOG(2, "%2u: %5u  (%.2f)",
+                u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
+    }
+}
+
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* ==============================================================
+ * Private declarations
+ * These prototypes shall only be called from within lib/compress
+ * ============================================================== */
+
+/* ZSTD_getCParamsFromCCtxParams() :
+ * cParams are built depending on compressionLevel, src size hints,
+ * LDM and manually set compression parameters.
+ */
+ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
+        const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize);
+
+/*! ZSTD_initCStream_internal() :
+ *  Private use only. Init streaming operation.
+ *  expects params to be valid.
+ *  must receive dict, or cdict, or none, but not both.
+ *  @return : 0, or an error code */
+size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
+                     const void* dict, size_t dictSize,
+                     const ZSTD_CDict* cdict,
+                     ZSTD_CCtx_params  params, unsigned long long pledgedSrcSize);
+
+void ZSTD_resetSeqStore(seqStore_t* ssPtr);
+
+/*! ZSTD_compressStream_generic() :
+ *  Private use only. To be called from zstdmt_compress.c in single-thread mode. */
+size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
+                                   ZSTD_outBuffer* output,
+                                   ZSTD_inBuffer* input,
+                                   ZSTD_EndDirective const flushMode);
+
+/*! ZSTD_getCParamsFromCDict() :
+ *  as the name implies */
+ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
+
+/* ZSTD_compressBegin_advanced_internal() :
+ * Private use only. To be called from zstdmt_compress.c. */
+size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
+                                    const void* dict, size_t dictSize,
+                                    ZSTD_dictContentType_e dictContentType,
+                                    ZSTD_dictTableLoadMethod_e dtlm,
+                                    const ZSTD_CDict* cdict,
+                                    ZSTD_CCtx_params params,
+                                    unsigned long long pledgedSrcSize);
+
+/* ZSTD_compress_advanced_internal() :
+ * Private use only. To be called from zstdmt_compress.c. */
+size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
+                                       void* dst, size_t dstCapacity,
+                                 const void* src, size_t srcSize,
+                                 const void* dict,size_t dictSize,
+                                 ZSTD_CCtx_params params);
+
+
+/* ZSTD_writeLastEmptyBlock() :
+ * output an empty Block with end-of-frame mark to complete a frame
+ * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
+ *           or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
+ */
+size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity);
+
+
+/* ZSTD_referenceExternalSequences() :
+ * Must be called before starting a compression operation.
+ * seqs must parse a prefix of the source.
+ * This cannot be used when long range matching is enabled.
+ * Zstd will use these sequences, and pass the literals to a secondary block
+ * compressor.
+ * @return : An error code on failure.
+ * NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory
+ * access and data corruption.
+ */
+size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
+
+
+#endif /* ZSTD_COMPRESS_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_double_fast.c b/Utilities/cmzstd/lib/compress/zstd_double_fast.c
new file mode 100644
index 0000000..47faf6d
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_double_fast.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_double_fast.h"
+
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+                              void const* end, ZSTD_dictTableLoadMethod_e dtlm)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const hashLarge = ms->hashTable;
+    U32  const hBitsL = cParams->hashLog;
+    U32  const mls = cParams->minMatch;
+    U32* const hashSmall = ms->chainTable;
+    U32  const hBitsS = cParams->chainLog;
+    const BYTE* const base = ms->window.base;
+    const BYTE* ip = base + ms->nextToUpdate;
+    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+    const U32 fastHashFillStep = 3;
+
+    /* Always insert every fastHashFillStep position into the hash tables.
+     * Insert the other positions into the large hash table if their entry
+     * is empty.
+     */
+    for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
+        U32 const current = (U32)(ip - base);
+        U32 i;
+        for (i = 0; i < fastHashFillStep; ++i) {
+            size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls);
+            size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8);
+            if (i == 0)
+                hashSmall[smHash] = current + i;
+            if (i == 0 || hashLarge[lgHash] == 0)
+                hashLarge[lgHash] = current + i;
+            /* Only load extra positions for ZSTD_dtlm_full */
+            if (dtlm == ZSTD_dtlm_fast)
+                break;
+        }
+    }
+}
+
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_doubleFast_generic(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize,
+        U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
+{
+    ZSTD_compressionParameters const* cParams = &ms->cParams;
+    U32* const hashLong = ms->hashTable;
+    const U32 hBitsL = cParams->hashLog;
+    U32* const hashSmall = ms->chainTable;
+    const U32 hBitsS = cParams->chainLog;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const U32 prefixLowestIndex = ms->window.dictLimit;
+    const BYTE* const prefixLowest = base + prefixLowestIndex;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - HASH_READ_SIZE;
+    U32 offset_1=rep[0], offset_2=rep[1];
+    U32 offsetSaved = 0;
+
+    const ZSTD_matchState_t* const dms = ms->dictMatchState;
+    const ZSTD_compressionParameters* const dictCParams =
+                                     dictMode == ZSTD_dictMatchState ?
+                                     &dms->cParams : NULL;
+    const U32* const dictHashLong  = dictMode == ZSTD_dictMatchState ?
+                                     dms->hashTable : NULL;
+    const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
+                                     dms->chainTable : NULL;
+    const U32 dictStartIndex       = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.dictLimit : 0;
+    const BYTE* const dictBase     = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.base : NULL;
+    const BYTE* const dictStart    = dictMode == ZSTD_dictMatchState ?
+                                     dictBase + dictStartIndex : NULL;
+    const BYTE* const dictEnd      = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.nextSrc : NULL;
+    const U32 dictIndexDelta       = dictMode == ZSTD_dictMatchState ?
+                                     prefixLowestIndex - (U32)(dictEnd - dictBase) :
+                                     0;
+    const U32 dictHBitsL           = dictMode == ZSTD_dictMatchState ?
+                                     dictCParams->hashLog : hBitsL;
+    const U32 dictHBitsS           = dictMode == ZSTD_dictMatchState ?
+                                     dictCParams->chainLog : hBitsS;
+    const U32 dictAndPrefixLength  = (U32)(ip - prefixLowest + dictEnd - dictStart);
+
+    assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
+
+    /* init */
+    ip += (dictAndPrefixLength == 0);
+    if (dictMode == ZSTD_noDict) {
+        U32 const maxRep = (U32)(ip - prefixLowest);
+        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
+        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+    }
+    if (dictMode == ZSTD_dictMatchState) {
+        /* dictMatchState repCode checks don't currently handle repCode == 0
+         * disabling. */
+        assert(offset_1 <= dictAndPrefixLength);
+        assert(offset_2 <= dictAndPrefixLength);
+    }
+
+    /* Main Search Loop */
+    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
+        size_t mLength;
+        U32 offset;
+        size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
+        size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
+        size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
+        size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
+        U32 const current = (U32)(ip-base);
+        U32 const matchIndexL = hashLong[h2];
+        U32 matchIndexS = hashSmall[h];
+        const BYTE* matchLong = base + matchIndexL;
+        const BYTE* match = base + matchIndexS;
+        const U32 repIndex = current + 1 - offset_1;
+        const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+                            && repIndex < prefixLowestIndex) ?
+                               dictBase + (repIndex - dictIndexDelta) :
+                               base + repIndex;
+        hashLong[h2] = hashSmall[h] = current;   /* update hash tables */
+
+        /* check dictMatchState repcode */
+        if (dictMode == ZSTD_dictMatchState
+            && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+            && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+            const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+            ip++;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+            goto _match_stored;
+        }
+
+        /* check noDict repcode */
+        if ( dictMode == ZSTD_noDict
+          && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+            ip++;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+            goto _match_stored;
+        }
+
+        if (matchIndexL > prefixLowestIndex) {
+            /* check prefix long match */
+            if (MEM_read64(matchLong) == MEM_read64(ip)) {
+                mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
+                offset = (U32)(ip-matchLong);
+                while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
+                goto _match_found;
+            }
+        } else if (dictMode == ZSTD_dictMatchState) {
+            /* check dictMatchState long match */
+            U32 const dictMatchIndexL = dictHashLong[dictHL];
+            const BYTE* dictMatchL = dictBase + dictMatchIndexL;
+            assert(dictMatchL < dictEnd);
+
+            if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
+                mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
+                offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
+                while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
+                goto _match_found;
+            }
+        }
+
+        if (matchIndexS > prefixLowestIndex) {
+            /* check prefix short match */
+            if (MEM_read32(match) == MEM_read32(ip)) {
+                goto _search_next_long;
+            }
+        } else if (dictMode == ZSTD_dictMatchState) {
+            /* check dictMatchState short match */
+            U32 const dictMatchIndexS = dictHashSmall[dictHS];
+            match = dictBase + dictMatchIndexS;
+            matchIndexS = dictMatchIndexS + dictIndexDelta;
+
+            if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
+                goto _search_next_long;
+            }
+        }
+
+        ip += ((ip-anchor) >> kSearchStrength) + 1;
+        continue;
+
+_search_next_long:
+
+        {
+            size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+            size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
+            U32 const matchIndexL3 = hashLong[hl3];
+            const BYTE* matchL3 = base + matchIndexL3;
+            hashLong[hl3] = current + 1;
+
+            /* check prefix long +1 match */
+            if (matchIndexL3 > prefixLowestIndex) {
+                if (MEM_read64(matchL3) == MEM_read64(ip+1)) {
+                    mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
+                    ip++;
+                    offset = (U32)(ip-matchL3);
+                    while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
+                    goto _match_found;
+                }
+            } else if (dictMode == ZSTD_dictMatchState) {
+                /* check dict long +1 match */
+                U32 const dictMatchIndexL3 = dictHashLong[dictHLNext];
+                const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
+                assert(dictMatchL3 < dictEnd);
+                if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
+                    mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
+                    ip++;
+                    offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
+                    while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
+                    goto _match_found;
+                }
+            }
+        }
+
+        /* if no long +1 match, explore the short match we found */
+        if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
+            mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
+            offset = (U32)(current - matchIndexS);
+            while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+        } else {
+            mLength = ZSTD_count(ip+4, match+4, iend) + 4;
+            offset = (U32)(ip - match);
+            while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+        }
+
+        /* fall-through */
+
+_match_found:
+        offset_2 = offset_1;
+        offset_1 = offset;
+
+        ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+_match_stored:
+        /* match found */
+        ip += mLength;
+        anchor = ip;
+
+        if (ip <= ilimit) {
+            /* Fill Table */
+            hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
+                hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;  /* here because current+2 could be > iend-8 */
+            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
+                hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
+
+            /* check immediate repcode */
+            if (dictMode == ZSTD_dictMatchState) {
+                while (ip <= ilimit) {
+                    U32 const current2 = (U32)(ip-base);
+                    U32 const repIndex2 = current2 - offset_2;
+                    const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
+                        && repIndex2 < prefixLowestIndex ?
+                            dictBase - dictIndexDelta + repIndex2 :
+                            base + repIndex2;
+                    if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
+                       && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+                        const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
+                        size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
+                        U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
+                        ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+                        hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
+                        hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+                        ip += repLength2;
+                        anchor = ip;
+                        continue;
+                    }
+                    break;
+                }
+            }
+
+            if (dictMode == ZSTD_noDict) {
+                while ( (ip <= ilimit)
+                     && ( (offset_2>0)
+                        & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+                    /* store sequence */
+                    size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+                    U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff;  /* swap offset_2 <=> offset_1 */
+                    hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
+                    hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
+                    ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
+                    ip += rLength;
+                    anchor = ip;
+                    continue;   /* faster when present ... (?) */
+    }   }   }   }
+
+    /* save reps for next block */
+    rep[0] = offset_1 ? offset_1 : offsetSaved;
+    rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_doubleFast(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    const U32 mls = ms->cParams.minMatch;
+    switch(mls)
+    {
+    default: /* includes case 3 */
+    case 4 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
+    case 5 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
+    case 6 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
+    case 7 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
+    }
+}
+
+
+size_t ZSTD_compressBlock_doubleFast_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    const U32 mls = ms->cParams.minMatch;
+    switch(mls)
+    {
+    default: /* includes case 3 */
+    case 4 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
+    case 5 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
+    case 6 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
+    case 7 :
+        return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
+    }
+}
+
+
+static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize,
+        U32 const mls /* template */)
+{
+    ZSTD_compressionParameters const* cParams = &ms->cParams;
+    U32* const hashLong = ms->hashTable;
+    U32  const hBitsL = cParams->hashLog;
+    U32* const hashSmall = ms->chainTable;
+    U32  const hBitsS = cParams->chainLog;
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - 8;
+    const U32   prefixStartIndex = ms->window.dictLimit;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const prefixStart = base + prefixStartIndex;
+    const U32   dictStartIndex = ms->window.lowLimit;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const BYTE* const dictStart = dictBase + dictStartIndex;
+    const BYTE* const dictEnd = dictBase + prefixStartIndex;
+    U32 offset_1=rep[0], offset_2=rep[1];
+
+    DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
+
+    /* Search Loop */
+    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
+        const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
+        const U32 matchIndex = hashSmall[hSmall];
+        const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
+        const BYTE* match = matchBase + matchIndex;
+
+        const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
+        const U32 matchLongIndex = hashLong[hLong];
+        const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
+        const BYTE* matchLong = matchLongBase + matchLongIndex;
+
+        const U32 current = (U32)(ip-base);
+        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */
+        const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
+        const BYTE* const repMatch = repBase + repIndex;
+        size_t mLength;
+        hashSmall[hSmall] = hashLong[hLong] = current;   /* update hash table */
+
+        if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
+            & (repIndex > dictStartIndex))
+          && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+            const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+            ip++;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+        } else {
+            if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
+                const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
+                const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
+                U32 offset;
+                mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
+                offset = current - matchLongIndex;
+                while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; }   /* catch up */
+                offset_2 = offset_1;
+                offset_1 = offset;
+                ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+            } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
+                size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+                U32 const matchIndex3 = hashLong[h3];
+                const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
+                const BYTE* match3 = match3Base + matchIndex3;
+                U32 offset;
+                hashLong[h3] = current + 1;
+                if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
+                    const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
+                    const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
+                    mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
+                    ip++;
+                    offset = current+1 - matchIndex3;
+                    while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
+                } else {
+                    const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
+                    const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
+                    mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
+                    offset = current - matchIndex;
+                    while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
+                }
+                offset_2 = offset_1;
+                offset_1 = offset;
+                ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+            } else {
+                ip += ((ip-anchor) >> kSearchStrength) + 1;
+                continue;
+        }   }
+
+        /* found a match : store it */
+        ip += mLength;
+        anchor = ip;
+
+        if (ip <= ilimit) {
+            /* Fill Table */
+            hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
+            hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
+            hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
+            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
+            /* check immediate repcode */
+            while (ip <= ilimit) {
+                U32 const current2 = (U32)(ip-base);
+                U32 const repIndex2 = current2 - offset_2;
+                const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
+                if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3)   /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
+                    & (repIndex2 > dictStartIndex))
+                  && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+                    const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+                    U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
+                    ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+                    hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
+                    hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+                    ip += repLength2;
+                    anchor = ip;
+                    continue;
+                }
+                break;
+    }   }   }
+
+    /* save reps for next block */
+    rep[0] = offset_1;
+    rep[1] = offset_2;
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_doubleFast_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    U32 const mls = ms->cParams.minMatch;
+    switch(mls)
+    {
+    default: /* includes case 3 */
+    case 4 :
+        return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
+    case 5 :
+        return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
+    case 6 :
+        return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
+    case 7 :
+        return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
+    }
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_double_fast.h b/Utilities/cmzstd/lib/compress/zstd_double_fast.h
new file mode 100644
index 0000000..4fa31ac
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_double_fast.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_DOUBLE_FAST_H
+#define ZSTD_DOUBLE_FAST_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "mem.h"      /* U32 */
+#include "zstd_compress_internal.h"     /* ZSTD_CCtx, size_t */
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+                              void const* end, ZSTD_dictTableLoadMethod_e dtlm);
+size_t ZSTD_compressBlock_doubleFast(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_DOUBLE_FAST_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_fast.c b/Utilities/cmzstd/lib/compress/zstd_fast.c
new file mode 100644
index 0000000..40ba0f7
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_fast.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_fast.h"
+
+
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+                        void const* end, ZSTD_dictTableLoadMethod_e dtlm)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const hashTable = ms->hashTable;
+    U32  const hBits = cParams->hashLog;
+    U32  const mls = cParams->minMatch;
+    const BYTE* const base = ms->window.base;
+    const BYTE* ip = base + ms->nextToUpdate;
+    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+    const U32 fastHashFillStep = 3;
+
+    /* Always insert every fastHashFillStep position into the hash table.
+     * Insert the other positions if their hash entry is empty.
+     */
+    for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) {
+        U32 const current = (U32)(ip - base);
+        size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls);
+        hashTable[hash0] = current;
+        if (dtlm == ZSTD_dtlm_fast) continue;
+        /* Only load extra positions for ZSTD_dtlm_full */
+        {   U32 p;
+            for (p = 1; p < fastHashFillStep; ++p) {
+                size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls);
+                if (hashTable[hash] == 0) {  /* not yet filled */
+                    hashTable[hash] = current + p;
+    }   }   }   }
+}
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_fast_generic(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize,
+        U32 const mls, ZSTD_dictMode_e const dictMode)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const hashTable = ms->hashTable;
+    U32 const hlog = cParams->hashLog;
+    /* support stepSize of 0 */
+    U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
+    const BYTE* const base = ms->window.base;
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const U32   prefixStartIndex = ms->window.dictLimit;
+    const BYTE* const prefixStart = base + prefixStartIndex;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - HASH_READ_SIZE;
+    U32 offset_1=rep[0], offset_2=rep[1];
+    U32 offsetSaved = 0;
+
+    const ZSTD_matchState_t* const dms = ms->dictMatchState;
+    const ZSTD_compressionParameters* const dictCParams =
+                                     dictMode == ZSTD_dictMatchState ?
+                                     &dms->cParams : NULL;
+    const U32* const dictHashTable = dictMode == ZSTD_dictMatchState ?
+                                     dms->hashTable : NULL;
+    const U32 dictStartIndex       = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.dictLimit : 0;
+    const BYTE* const dictBase     = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.base : NULL;
+    const BYTE* const dictStart    = dictMode == ZSTD_dictMatchState ?
+                                     dictBase + dictStartIndex : NULL;
+    const BYTE* const dictEnd      = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.nextSrc : NULL;
+    const U32 dictIndexDelta       = dictMode == ZSTD_dictMatchState ?
+                                     prefixStartIndex - (U32)(dictEnd - dictBase) :
+                                     0;
+    const U32 dictAndPrefixLength  = (U32)(ip - prefixStart + dictEnd - dictStart);
+    const U32 dictHLog             = dictMode == ZSTD_dictMatchState ?
+                                     dictCParams->hashLog : hlog;
+
+    assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
+
+    /* otherwise, we would get index underflow when translating a dict index
+     * into a local index */
+    assert(dictMode != ZSTD_dictMatchState
+        || prefixStartIndex >= (U32)(dictEnd - dictBase));
+
+    /* init */
+    ip += (dictAndPrefixLength == 0);
+    if (dictMode == ZSTD_noDict) {
+        U32 const maxRep = (U32)(ip - prefixStart);
+        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
+        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+    }
+    if (dictMode == ZSTD_dictMatchState) {
+        /* dictMatchState repCode checks don't currently handle repCode == 0
+         * disabling. */
+        assert(offset_1 <= dictAndPrefixLength);
+        assert(offset_2 <= dictAndPrefixLength);
+    }
+
+    /* Main Search Loop */
+    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
+        size_t mLength;
+        size_t const h = ZSTD_hashPtr(ip, hlog, mls);
+        U32 const current = (U32)(ip-base);
+        U32 const matchIndex = hashTable[h];
+        const BYTE* match = base + matchIndex;
+        const U32 repIndex = current + 1 - offset_1;
+        const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+                            && repIndex < prefixStartIndex) ?
+                               dictBase + (repIndex - dictIndexDelta) :
+                               base + repIndex;
+        hashTable[h] = current;   /* update hash table */
+
+        if ( (dictMode == ZSTD_dictMatchState)
+          && ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
+          && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+            const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+            ip++;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+        } else if ( dictMode == ZSTD_noDict
+                 && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+            ip++;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+        } else if ( (matchIndex <= prefixStartIndex) ) {
+            if (dictMode == ZSTD_dictMatchState) {
+                size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls);
+                U32 const dictMatchIndex = dictHashTable[dictHash];
+                const BYTE* dictMatch = dictBase + dictMatchIndex;
+                if (dictMatchIndex <= dictStartIndex ||
+                    MEM_read32(dictMatch) != MEM_read32(ip)) {
+                    assert(stepSize >= 1);
+                    ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+                    continue;
+                } else {
+                    /* found a dict match */
+                    U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
+                    mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
+                    while (((ip>anchor) & (dictMatch>dictStart))
+                         && (ip[-1] == dictMatch[-1])) {
+                        ip--; dictMatch--; mLength++;
+                    } /* catch up */
+                    offset_2 = offset_1;
+                    offset_1 = offset;
+                    ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+                }
+            } else {
+                assert(stepSize >= 1);
+                ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+                continue;
+            }
+        } else if (MEM_read32(match) != MEM_read32(ip)) {
+            /* it's not a match, and we're not going to check the dictionary */
+            assert(stepSize >= 1);
+            ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+            continue;
+        } else {
+            /* found a regular match */
+            U32 const offset = (U32)(ip-match);
+            mLength = ZSTD_count(ip+4, match+4, iend) + 4;
+            while (((ip>anchor) & (match>prefixStart))
+                 && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+            offset_2 = offset_1;
+            offset_1 = offset;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+        }
+
+        /* match found */
+        ip += mLength;
+        anchor = ip;
+
+        if (ip <= ilimit) {
+            /* Fill Table */
+            assert(base+current+2 > istart);  /* check base overflow */
+            hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;  /* here because current+2 could be > iend-8 */
+            hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
+
+            /* check immediate repcode */
+            if (dictMode == ZSTD_dictMatchState) {
+                while (ip <= ilimit) {
+                    U32 const current2 = (U32)(ip-base);
+                    U32 const repIndex2 = current2 - offset_2;
+                    const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
+                            dictBase - dictIndexDelta + repIndex2 :
+                            base + repIndex2;
+                    if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
+                       && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+                        const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+                        size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+                        U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
+                        ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+                        hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
+                        ip += repLength2;
+                        anchor = ip;
+                        continue;
+                    }
+                    break;
+                }
+            }
+
+            if (dictMode == ZSTD_noDict) {
+                while ( (ip <= ilimit)
+                     && ( (offset_2>0)
+                        & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+                    /* store sequence */
+                    size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+                    U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff;  /* swap offset_2 <=> offset_1 */
+                    hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
+                    ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
+                    ip += rLength;
+                    anchor = ip;
+                    continue;   /* faster when present ... (?) */
+    }   }   }   }
+
+    /* save reps for next block */
+    rep[0] = offset_1 ? offset_1 : offsetSaved;
+    rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_fast(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    ZSTD_compressionParameters const* cParams = &ms->cParams;
+    U32 const mls = cParams->minMatch;
+    assert(ms->dictMatchState == NULL);
+    switch(mls)
+    {
+    default: /* includes case 3 */
+    case 4 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
+    case 5 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
+    case 6 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
+    case 7 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
+    }
+}
+
+size_t ZSTD_compressBlock_fast_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    ZSTD_compressionParameters const* cParams = &ms->cParams;
+    U32 const mls = cParams->minMatch;
+    assert(ms->dictMatchState != NULL);
+    switch(mls)
+    {
+    default: /* includes case 3 */
+    case 4 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
+    case 5 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
+    case 6 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
+    case 7 :
+        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
+    }
+}
+
+
+static size_t ZSTD_compressBlock_fast_extDict_generic(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize, U32 const mls)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const hashTable = ms->hashTable;
+    U32 const hlog = cParams->hashLog;
+    /* support stepSize of 0 */
+    U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
+    const BYTE* const base = ms->window.base;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const U32   dictStartIndex = ms->window.lowLimit;
+    const BYTE* const dictStart = dictBase + dictStartIndex;
+    const U32   prefixStartIndex = ms->window.dictLimit;
+    const BYTE* const prefixStart = base + prefixStartIndex;
+    const BYTE* const dictEnd = dictBase + prefixStartIndex;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - 8;
+    U32 offset_1=rep[0], offset_2=rep[1];
+
+    /* Search Loop */
+    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
+        const size_t h = ZSTD_hashPtr(ip, hlog, mls);
+        const U32    matchIndex = hashTable[h];
+        const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
+        const BYTE*  match = matchBase + matchIndex;
+        const U32    current = (U32)(ip-base);
+        const U32    repIndex = current + 1 - offset_1;
+        const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
+        const BYTE* const repMatch = repBase + repIndex;
+        size_t mLength;
+        hashTable[h] = current;   /* update hash table */
+        assert(offset_1 <= current +1);   /* check repIndex */
+
+        if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
+           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+            const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+            ip++;
+            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
+        } else {
+            if ( (matchIndex < dictStartIndex) ||
+                 (MEM_read32(match) != MEM_read32(ip)) ) {
+                assert(stepSize >= 1);
+                ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+                continue;
+            }
+            {   const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
+                const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
+                U32 offset;
+                mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
+                while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
+                offset = current - matchIndex;
+                offset_2 = offset_1;
+                offset_1 = offset;
+                ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+        }   }
+
+        /* found a match : store it */
+        ip += mLength;
+        anchor = ip;
+
+        if (ip <= ilimit) {
+            /* Fill Table */
+            hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
+            hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
+            /* check immediate repcode */
+            while (ip <= ilimit) {
+                U32 const current2 = (U32)(ip-base);
+                U32 const repIndex2 = current2 - offset_2;
+                const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
+                if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex))  /* intentional overflow */
+                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+                    const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
+                    ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
+                    hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
+                    ip += repLength2;
+                    anchor = ip;
+                    continue;
+                }
+                break;
+    }   }   }
+
+    /* save reps for next block */
+    rep[0] = offset_1;
+    rep[1] = offset_2;
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_fast_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    ZSTD_compressionParameters const* cParams = &ms->cParams;
+    U32 const mls = cParams->minMatch;
+    switch(mls)
+    {
+    default: /* includes case 3 */
+    case 4 :
+        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
+    case 5 :
+        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
+    case 6 :
+        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
+    case 7 :
+        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
+    }
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_fast.h b/Utilities/cmzstd/lib/compress/zstd_fast.h
new file mode 100644
index 0000000..b74a88c
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_fast.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_FAST_H
+#define ZSTD_FAST_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "mem.h"      /* U32 */
+#include "zstd_compress_internal.h"
+
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+                        void const* end, ZSTD_dictTableLoadMethod_e dtlm);
+size_t ZSTD_compressBlock_fast(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_FAST_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_lazy.c b/Utilities/cmzstd/lib/compress/zstd_lazy.c
new file mode 100644
index 0000000..53f998a
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_lazy.c
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_lazy.h"
+
+
+/*-*************************************
+*  Binary Tree search
+***************************************/
+
+static void
+ZSTD_updateDUBT(ZSTD_matchState_t* ms,
+                const BYTE* ip, const BYTE* iend,
+                U32 mls)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const hashTable = ms->hashTable;
+    U32  const hashLog = cParams->hashLog;
+
+    U32* const bt = ms->chainTable;
+    U32  const btLog  = cParams->chainLog - 1;
+    U32  const btMask = (1 << btLog) - 1;
+
+    const BYTE* const base = ms->window.base;
+    U32 const target = (U32)(ip - base);
+    U32 idx = ms->nextToUpdate;
+
+    if (idx != target)
+        DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
+                    idx, target, ms->window.dictLimit);
+    assert(ip + 8 <= iend);   /* condition for ZSTD_hashPtr */
+    (void)iend;
+
+    assert(idx >= ms->window.dictLimit);   /* condition for valid base+idx */
+    for ( ; idx < target ; idx++) {
+        size_t const h  = ZSTD_hashPtr(base + idx, hashLog, mls);   /* assumption : ip + 8 <= iend */
+        U32    const matchIndex = hashTable[h];
+
+        U32*   const nextCandidatePtr = bt + 2*(idx&btMask);
+        U32*   const sortMarkPtr  = nextCandidatePtr + 1;
+
+        DEBUGLOG(8, "ZSTD_updateDUBT: insert %u", idx);
+        hashTable[h] = idx;   /* Update Hash Table */
+        *nextCandidatePtr = matchIndex;   /* update BT like a chain */
+        *sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
+    }
+    ms->nextToUpdate = target;
+}
+
+
+/** ZSTD_insertDUBT1() :
+ *  sort one already inserted but unsorted position
+ *  assumption : current >= btlow == (current - btmask)
+ *  doesn't fail */
+static void
+ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
+                 U32 current, const BYTE* inputEnd,
+                 U32 nbCompares, U32 btLow,
+                 const ZSTD_dictMode_e dictMode)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const bt = ms->chainTable;
+    U32  const btLog  = cParams->chainLog - 1;
+    U32  const btMask = (1 << btLog) - 1;
+    size_t commonLengthSmaller=0, commonLengthLarger=0;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const U32 dictLimit = ms->window.dictLimit;
+    const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
+    const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
+    const BYTE* const dictEnd = dictBase + dictLimit;
+    const BYTE* const prefixStart = base + dictLimit;
+    const BYTE* match;
+    U32* smallerPtr = bt + 2*(current&btMask);
+    U32* largerPtr  = smallerPtr + 1;
+    U32 matchIndex = *smallerPtr;   /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */
+    U32 dummy32;   /* to be nullified at the end */
+    U32 const windowLow = ms->window.lowLimit;
+
+    DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
+                current, dictLimit, windowLow);
+    assert(current >= btLow);
+    assert(ip < iend);   /* condition for ZSTD_count */
+
+    while (nbCompares-- && (matchIndex > windowLow)) {
+        U32* const nextPtr = bt + 2*(matchIndex & btMask);
+        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+        assert(matchIndex < current);
+        /* note : all candidates are now supposed sorted,
+         * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK
+         * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */
+
+        if ( (dictMode != ZSTD_extDict)
+          || (matchIndex+matchLength >= dictLimit)  /* both in current segment*/
+          || (current < dictLimit) /* both in extDict */) {
+            const BYTE* const mBase = ( (dictMode != ZSTD_extDict)
+                                     || (matchIndex+matchLength >= dictLimit)) ?
+                                        base : dictBase;
+            assert( (matchIndex+matchLength >= dictLimit)   /* might be wrong if extDict is incorrectly set to 0 */
+                 || (current < dictLimit) );
+            match = mBase + matchIndex;
+            matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+        } else {
+            match = dictBase + matchIndex;
+            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+            if (matchIndex+matchLength >= dictLimit)
+                match = base + matchIndex;   /* preparation for next read of match[matchLength] */
+        }
+
+        DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
+                    current, matchIndex, (U32)matchLength);
+
+        if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
+            break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
+        }
+
+        if (match[matchLength] < ip[matchLength]) {  /* necessarily within buffer */
+            /* match is smaller than current */
+            *smallerPtr = matchIndex;             /* update smaller idx */
+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
+            DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is smaller : next => %u",
+                        matchIndex, btLow, nextPtr[1]);
+            smallerPtr = nextPtr+1;               /* new "candidate" => larger than match, which was smaller than target */
+            matchIndex = nextPtr[1];              /* new matchIndex, larger than previous and closer to current */
+        } else {
+            /* match is larger than current */
+            *largerPtr = matchIndex;
+            commonLengthLarger = matchLength;
+            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
+            DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u",
+                        matchIndex, btLow, nextPtr[0]);
+            largerPtr = nextPtr;
+            matchIndex = nextPtr[0];
+    }   }
+
+    *smallerPtr = *largerPtr = 0;
+}
+
+
+static size_t
+ZSTD_DUBT_findBetterDictMatch (
+        ZSTD_matchState_t* ms,
+        const BYTE* const ip, const BYTE* const iend,
+        size_t* offsetPtr,
+        size_t bestLength,
+        U32 nbCompares,
+        U32 const mls,
+        const ZSTD_dictMode_e dictMode)
+{
+    const ZSTD_matchState_t * const dms = ms->dictMatchState;
+    const ZSTD_compressionParameters* const dmsCParams = &dms->cParams;
+    const U32 * const dictHashTable = dms->hashTable;
+    U32         const hashLog = dmsCParams->hashLog;
+    size_t      const h  = ZSTD_hashPtr(ip, hashLog, mls);
+    U32               dictMatchIndex = dictHashTable[h];
+
+    const BYTE* const base = ms->window.base;
+    const BYTE* const prefixStart = base + ms->window.dictLimit;
+    U32         const current = (U32)(ip-base);
+    const BYTE* const dictBase = dms->window.base;
+    const BYTE* const dictEnd = dms->window.nextSrc;
+    U32         const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base);
+    U32         const dictLowLimit = dms->window.lowLimit;
+    U32         const dictIndexDelta = ms->window.lowLimit - dictHighLimit;
+
+    U32*        const dictBt = dms->chainTable;
+    U32         const btLog  = dmsCParams->chainLog - 1;
+    U32         const btMask = (1 << btLog) - 1;
+    U32         const btLow = (btMask >= dictHighLimit - dictLowLimit) ? dictLowLimit : dictHighLimit - btMask;
+
+    size_t commonLengthSmaller=0, commonLengthLarger=0;
+
+    (void)dictMode;
+    assert(dictMode == ZSTD_dictMatchState);
+
+    while (nbCompares-- && (dictMatchIndex > dictLowLimit)) {
+        U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask);
+        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+        const BYTE* match = dictBase + dictMatchIndex;
+        matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+        if (dictMatchIndex+matchLength >= dictHighLimit)
+            match = base + dictMatchIndex + dictIndexDelta;   /* to prepare for next usage of match[matchLength] */
+
+        if (matchLength > bestLength) {
+            U32 matchIndex = dictMatchIndex + dictIndexDelta;
+            if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
+                DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)",
+                    current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex);
+                bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+            }
+            if (ip+matchLength == iend) {   /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */
+                break;   /* drop, to guarantee consistency (miss a little bit of compression) */
+            }
+        }
+
+        if (match[matchLength] < ip[matchLength]) {
+            if (dictMatchIndex <= btLow) { break; }   /* beyond tree size, stop the search */
+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
+            dictMatchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
+        } else {
+            /* match is larger than current */
+            if (dictMatchIndex <= btLow) { break; }   /* beyond tree size, stop the search */
+            commonLengthLarger = matchLength;
+            dictMatchIndex = nextPtr[0];
+        }
+    }
+
+    if (bestLength >= MINMATCH) {
+        U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+        DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+                    current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+    }
+    return bestLength;
+
+}
+
+
+static size_t
+ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
+                        const BYTE* const ip, const BYTE* const iend,
+                        size_t* offsetPtr,
+                        U32 const mls,
+                        const ZSTD_dictMode_e dictMode)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32*   const hashTable = ms->hashTable;
+    U32    const hashLog = cParams->hashLog;
+    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
+    U32          matchIndex  = hashTable[h];
+
+    const BYTE* const base = ms->window.base;
+    U32    const current = (U32)(ip-base);
+    U32    const windowLow = ms->window.lowLimit;
+
+    U32*   const bt = ms->chainTable;
+    U32    const btLog  = cParams->chainLog - 1;
+    U32    const btMask = (1 << btLog) - 1;
+    U32    const btLow = (btMask >= current) ? 0 : current - btMask;
+    U32    const unsortLimit = MAX(btLow, windowLow);
+
+    U32*         nextCandidate = bt + 2*(matchIndex&btMask);
+    U32*         unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+    U32          nbCompares = 1U << cParams->searchLog;
+    U32          nbCandidates = nbCompares;
+    U32          previousCandidate = 0;
+
+    DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current);
+    assert(ip <= iend-8);   /* required for h calculation */
+
+    /* reach end of unsorted candidates list */
+    while ( (matchIndex > unsortLimit)
+         && (*unsortedMark == ZSTD_DUBT_UNSORTED_MARK)
+         && (nbCandidates > 1) ) {
+        DEBUGLOG(8, "ZSTD_DUBT_findBestMatch: candidate %u is unsorted",
+                    matchIndex);
+        *unsortedMark = previousCandidate;  /* the unsortedMark becomes a reversed chain, to move up back to original position */
+        previousCandidate = matchIndex;
+        matchIndex = *nextCandidate;
+        nextCandidate = bt + 2*(matchIndex&btMask);
+        unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+        nbCandidates --;
+    }
+
+    /* nullify last candidate if it's still unsorted
+     * simplification, detrimental to compression ratio, beneficial for speed */
+    if ( (matchIndex > unsortLimit)
+      && (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
+        DEBUGLOG(7, "ZSTD_DUBT_findBestMatch: nullify last unsorted candidate %u",
+                    matchIndex);
+        *nextCandidate = *unsortedMark = 0;
+    }
+
+    /* batch sort stacked candidates */
+    matchIndex = previousCandidate;
+    while (matchIndex) {  /* will end on matchIndex == 0 */
+        U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
+        U32 const nextCandidateIdx = *nextCandidateIdxPtr;
+        ZSTD_insertDUBT1(ms, matchIndex, iend,
+                         nbCandidates, unsortLimit, dictMode);
+        matchIndex = nextCandidateIdx;
+        nbCandidates++;
+    }
+
+    /* find longest match */
+    {   size_t commonLengthSmaller = 0, commonLengthLarger = 0;
+        const BYTE* const dictBase = ms->window.dictBase;
+        const U32 dictLimit = ms->window.dictLimit;
+        const BYTE* const dictEnd = dictBase + dictLimit;
+        const BYTE* const prefixStart = base + dictLimit;
+        U32* smallerPtr = bt + 2*(current&btMask);
+        U32* largerPtr  = bt + 2*(current&btMask) + 1;
+        U32 matchEndIdx = current + 8 + 1;
+        U32 dummy32;   /* to be nullified at the end */
+        size_t bestLength = 0;
+
+        matchIndex  = hashTable[h];
+        hashTable[h] = current;   /* Update Hash Table */
+
+        while (nbCompares-- && (matchIndex > windowLow)) {
+            U32* const nextPtr = bt + 2*(matchIndex & btMask);
+            size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+            const BYTE* match;
+
+            if ((dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) {
+                match = base + matchIndex;
+                matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+            } else {
+                match = dictBase + matchIndex;
+                matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+                if (matchIndex+matchLength >= dictLimit)
+                    match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
+            }
+
+            if (matchLength > bestLength) {
+                if (matchLength > matchEndIdx - matchIndex)
+                    matchEndIdx = matchIndex + (U32)matchLength;
+                if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
+                    bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+                if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
+                    if (dictMode == ZSTD_dictMatchState) {
+                        nbCompares = 0; /* in addition to avoiding checking any
+                                         * further in this loop, make sure we
+                                         * skip checking in the dictionary. */
+                    }
+                    break;   /* drop, to guarantee consistency (miss a little bit of compression) */
+                }
+            }
+
+            if (match[matchLength] < ip[matchLength]) {
+                /* match is smaller than current */
+                *smallerPtr = matchIndex;             /* update smaller idx */
+                commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
+                if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
+                smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
+                matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
+            } else {
+                /* match is larger than current */
+                *largerPtr = matchIndex;
+                commonLengthLarger = matchLength;
+                if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
+                largerPtr = nextPtr;
+                matchIndex = nextPtr[0];
+        }   }
+
+        *smallerPtr = *largerPtr = 0;
+
+        if (dictMode == ZSTD_dictMatchState && nbCompares) {
+            bestLength = ZSTD_DUBT_findBetterDictMatch(
+                    ms, ip, iend,
+                    offsetPtr, bestLength, nbCompares,
+                    mls, dictMode);
+        }
+
+        assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
+        ms->nextToUpdate = matchEndIdx - 8;   /* skip repetitive patterns */
+        if (bestLength >= MINMATCH) {
+            U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+            DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+                        current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+        }
+        return bestLength;
+    }
+}
+
+
+/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms,
+                const BYTE* const ip, const BYTE* const iLimit,
+                      size_t* offsetPtr,
+                const U32 mls /* template */,
+                const ZSTD_dictMode_e dictMode)
+{
+    DEBUGLOG(7, "ZSTD_BtFindBestMatch");
+    if (ip < ms->window.base + ms->nextToUpdate) return 0;   /* skipped area */
+    ZSTD_updateDUBT(ms, ip, iLimit, mls);
+    return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode);
+}
+
+
+static size_t
+ZSTD_BtFindBestMatch_selectMLS (  ZSTD_matchState_t* ms,
+                            const BYTE* ip, const BYTE* const iLimit,
+                                  size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
+    case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
+    case 7 :
+    case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
+    }
+}
+
+
+static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
+    case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
+    case 7 :
+    case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
+    }
+}
+
+
+static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
+    case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
+    case 7 :
+    case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
+    }
+}
+
+
+
+/* *********************************
+*  Hash Chain
+***********************************/
+#define NEXT_IN_CHAIN(d, mask)   chainTable[(d) & (mask)]
+
+/* Update chains up to ip (excluded)
+   Assumption : always within prefix (i.e. not within extDict) */
+static U32 ZSTD_insertAndFindFirstIndex_internal(
+                        ZSTD_matchState_t* ms,
+                        const ZSTD_compressionParameters* const cParams,
+                        const BYTE* ip, U32 const mls)
+{
+    U32* const hashTable  = ms->hashTable;
+    const U32 hashLog = cParams->hashLog;
+    U32* const chainTable = ms->chainTable;
+    const U32 chainMask = (1 << cParams->chainLog) - 1;
+    const BYTE* const base = ms->window.base;
+    const U32 target = (U32)(ip - base);
+    U32 idx = ms->nextToUpdate;
+
+    while(idx < target) { /* catch up */
+        size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
+        NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
+        hashTable[h] = idx;
+        idx++;
+    }
+
+    ms->nextToUpdate = target;
+    return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
+}
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
+}
+
+
+/* inlining is important to hardwire a hot branch (template emulation) */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_HcFindBestMatch_generic (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* const ip, const BYTE* const iLimit,
+                        size_t* offsetPtr,
+                        const U32 mls, const ZSTD_dictMode_e dictMode)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32* const chainTable = ms->chainTable;
+    const U32 chainSize = (1 << cParams->chainLog);
+    const U32 chainMask = chainSize-1;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const U32 dictLimit = ms->window.dictLimit;
+    const BYTE* const prefixStart = base + dictLimit;
+    const BYTE* const dictEnd = dictBase + dictLimit;
+    const U32 lowLimit = ms->window.lowLimit;
+    const U32 current = (U32)(ip-base);
+    const U32 minChain = current > chainSize ? current - chainSize : 0;
+    U32 nbAttempts = 1U << cParams->searchLog;
+    size_t ml=4-1;
+
+    /* HC4 match finder */
+    U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
+
+    for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
+        size_t currentMl=0;
+        if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+            const BYTE* const match = base + matchIndex;
+            assert(matchIndex >= dictLimit);   /* ensures this is true if dictMode != ZSTD_extDict */
+            if (match[ml] == ip[ml])   /* potentially better */
+                currentMl = ZSTD_count(ip, match, iLimit);
+        } else {
+            const BYTE* const match = dictBase + matchIndex;
+            assert(match+4 <= dictEnd);
+            if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+                currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
+        }
+
+        /* save best solution */
+        if (currentMl > ml) {
+            ml = currentMl;
+            *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
+            if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+        }
+
+        if (matchIndex <= minChain) break;
+        matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
+    }
+
+    if (dictMode == ZSTD_dictMatchState) {
+        const ZSTD_matchState_t* const dms = ms->dictMatchState;
+        const U32* const dmsChainTable = dms->chainTable;
+        const U32 dmsChainSize         = (1 << dms->cParams.chainLog);
+        const U32 dmsChainMask         = dmsChainSize - 1;
+        const U32 dmsLowestIndex       = dms->window.dictLimit;
+        const BYTE* const dmsBase      = dms->window.base;
+        const BYTE* const dmsEnd       = dms->window.nextSrc;
+        const U32 dmsSize              = (U32)(dmsEnd - dmsBase);
+        const U32 dmsIndexDelta        = dictLimit - dmsSize;
+        const U32 dmsMinChain = dmsSize > dmsChainSize ? dmsSize - dmsChainSize : 0;
+
+        matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)];
+
+        for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
+            size_t currentMl=0;
+            const BYTE* const match = dmsBase + matchIndex;
+            assert(match+4 <= dmsEnd);
+            if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+                currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
+
+            /* save best solution */
+            if (currentMl > ml) {
+                ml = currentMl;
+                *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
+                if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+            }
+
+            if (matchIndex <= dmsMinChain) break;
+            matchIndex = dmsChainTable[matchIndex & dmsChainMask];
+        }
+    }
+
+    return ml;
+}
+
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
+    case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
+    case 7 :
+    case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
+    }
+}
+
+
+static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
+    case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
+    case 7 :
+    case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
+    }
+}
+
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
+    case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
+    case 7 :
+    case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
+    }
+}
+
+
+/* *******************************
+*  Common parser - lazy strategy
+*********************************/
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_lazy_generic(
+                        ZSTD_matchState_t* ms, seqStore_t* seqStore,
+                        U32 rep[ZSTD_REP_NUM],
+                        const void* src, size_t srcSize,
+                        const U32 searchMethod, const U32 depth,
+                        ZSTD_dictMode_e const dictMode)
+{
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - 8;
+    const BYTE* const base = ms->window.base;
+    const U32 prefixLowestIndex = ms->window.dictLimit;
+    const BYTE* const prefixLowest = base + prefixLowestIndex;
+
+    typedef size_t (*searchMax_f)(
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
+    searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
+        (searchMethod ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
+        (searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS);
+    U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
+
+    const ZSTD_matchState_t* const dms = ms->dictMatchState;
+    const U32 dictLowestIndex      = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.dictLimit : 0;
+    const BYTE* const dictBase     = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.base : NULL;
+    const BYTE* const dictLowest   = dictMode == ZSTD_dictMatchState ?
+                                     dictBase + dictLowestIndex : NULL;
+    const BYTE* const dictEnd      = dictMode == ZSTD_dictMatchState ?
+                                     dms->window.nextSrc : NULL;
+    const U32 dictIndexDelta       = dictMode == ZSTD_dictMatchState ?
+                                     prefixLowestIndex - (U32)(dictEnd - dictBase) :
+                                     0;
+    const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest);
+
+    /* init */
+    ip += (dictAndPrefixLength == 0);
+    ms->nextToUpdate3 = ms->nextToUpdate;
+    if (dictMode == ZSTD_noDict) {
+        U32 const maxRep = (U32)(ip - prefixLowest);
+        if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
+        if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
+    }
+    if (dictMode == ZSTD_dictMatchState) {
+        /* dictMatchState repCode checks don't currently handle repCode == 0
+         * disabling. */
+        assert(offset_1 <= dictAndPrefixLength);
+        assert(offset_2 <= dictAndPrefixLength);
+    }
+
+    /* Match Loop */
+    while (ip < ilimit) {
+        size_t matchLength=0;
+        size_t offset=0;
+        const BYTE* start=ip+1;
+
+        /* check repCode */
+        if (dictMode == ZSTD_dictMatchState) {
+            const U32 repIndex = (U32)(ip - base) + 1 - offset_1;
+            const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+                                && repIndex < prefixLowestIndex) ?
+                                   dictBase + (repIndex - dictIndexDelta) :
+                                   base + repIndex;
+            if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+                && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+                const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+                matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+                if (depth==0) goto _storeSequence;
+            }
+        }
+        if ( dictMode == ZSTD_noDict
+          && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+            matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+            if (depth==0) goto _storeSequence;
+        }
+
+        /* first search (depth 0) */
+        {   size_t offsetFound = 999999999;
+            size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
+            if (ml2 > matchLength)
+                matchLength = ml2, start = ip, offset=offsetFound;
+        }
+
+        if (matchLength < 4) {
+            ip += ((ip-anchor) >> kSearchStrength) + 1;   /* jump faster over incompressible sections */
+            continue;
+        }
+
+        /* let's try to find a better solution */
+        if (depth>=1)
+        while (ip<ilimit) {
+            ip ++;
+            if ( (dictMode == ZSTD_noDict)
+              && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
+                size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
+                int const gain2 = (int)(mlRep * 3);
+                int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+                if ((mlRep >= 4) && (gain2 > gain1))
+                    matchLength = mlRep, offset = 0, start = ip;
+            }
+            if (dictMode == ZSTD_dictMatchState) {
+                const U32 repIndex = (U32)(ip - base) - offset_1;
+                const BYTE* repMatch = repIndex < prefixLowestIndex ?
+                               dictBase + (repIndex - dictIndexDelta) :
+                               base + repIndex;
+                if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+                    && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+                    const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+                    size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+                    int const gain2 = (int)(mlRep * 3);
+                    int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+                    if ((mlRep >= 4) && (gain2 > gain1))
+                        matchLength = mlRep, offset = 0, start = ip;
+                }
+            }
+            {   size_t offset2=999999999;
+                size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
+                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
+                if ((ml2 >= 4) && (gain2 > gain1)) {
+                    matchLength = ml2, offset = offset2, start = ip;
+                    continue;   /* search a better one */
+            }   }
+
+            /* let's find an even better one */
+            if ((depth==2) && (ip<ilimit)) {
+                ip ++;
+                if ( (dictMode == ZSTD_noDict)
+                  && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
+                    size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
+                    int const gain2 = (int)(mlRep * 4);
+                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+                    if ((mlRep >= 4) && (gain2 > gain1))
+                        matchLength = mlRep, offset = 0, start = ip;
+                }
+                if (dictMode == ZSTD_dictMatchState) {
+                    const U32 repIndex = (U32)(ip - base) - offset_1;
+                    const BYTE* repMatch = repIndex < prefixLowestIndex ?
+                                   dictBase + (repIndex - dictIndexDelta) :
+                                   base + repIndex;
+                    if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+                        && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+                        const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+                        size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+                        int const gain2 = (int)(mlRep * 4);
+                        int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+                        if ((mlRep >= 4) && (gain2 > gain1))
+                            matchLength = mlRep, offset = 0, start = ip;
+                    }
+                }
+                {   size_t offset2=999999999;
+                    size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+                    int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
+                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+                    if ((ml2 >= 4) && (gain2 > gain1)) {
+                        matchLength = ml2, offset = offset2, start = ip;
+                        continue;
+            }   }   }
+            break;  /* nothing found : store previous solution */
+        }
+
+        /* NOTE:
+         * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
+         * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
+         * overflows the pointer, which is undefined behavior.
+         */
+        /* catch up */
+        if (offset) {
+            if (dictMode == ZSTD_noDict) {
+                while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest))
+                     && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) )  /* only search for offset within prefix */
+                    { start--; matchLength++; }
+            }
+            if (dictMode == ZSTD_dictMatchState) {
+                U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
+                const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex;
+                const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest;
+                while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; }  /* catch up */
+            }
+            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+        }
+        /* store sequence */
+_storeSequence:
+        {   size_t const litLength = start - anchor;
+            ZSTD_storeSeq(seqStore, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+            anchor = ip = start + matchLength;
+        }
+
+        /* check immediate repcode */
+        if (dictMode == ZSTD_dictMatchState) {
+            while (ip <= ilimit) {
+                U32 const current2 = (U32)(ip-base);
+                U32 const repIndex = current2 - offset_2;
+                const BYTE* repMatch = dictMode == ZSTD_dictMatchState
+                    && repIndex < prefixLowestIndex ?
+                        dictBase - dictIndexDelta + repIndex :
+                        base + repIndex;
+                if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */)
+                   && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+                    const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend;
+                    matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4;
+                    offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset;   /* swap offset_2 <=> offset_1 */
+                    ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
+                    ip += matchLength;
+                    anchor = ip;
+                    continue;
+                }
+                break;
+            }
+        }
+
+        if (dictMode == ZSTD_noDict) {
+            while ( ((ip <= ilimit) & (offset_2>0))
+                 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
+                /* store sequence */
+                matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+                offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
+                ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
+                ip += matchLength;
+                anchor = ip;
+                continue;   /* faster when present ... (?) */
+    }   }   }
+
+    /* Save reps for next block */
+    rep[0] = offset_1 ? offset_1 : savedOffset;
+    rep[1] = offset_2 ? offset_2 : savedOffset;
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_btlazy2(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy2(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_greedy(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btlazy2_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy2_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_greedy_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_dictMatchState);
+}
+
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_lazy_extDict_generic(
+                        ZSTD_matchState_t* ms, seqStore_t* seqStore,
+                        U32 rep[ZSTD_REP_NUM],
+                        const void* src, size_t srcSize,
+                        const U32 searchMethod, const U32 depth)
+{
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - 8;
+    const BYTE* const base = ms->window.base;
+    const U32 dictLimit = ms->window.dictLimit;
+    const U32 lowestIndex = ms->window.lowLimit;
+    const BYTE* const prefixStart = base + dictLimit;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const BYTE* const dictEnd  = dictBase + dictLimit;
+    const BYTE* const dictStart  = dictBase + lowestIndex;
+
+    typedef size_t (*searchMax_f)(
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
+    searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
+
+    U32 offset_1 = rep[0], offset_2 = rep[1];
+
+    /* init */
+    ms->nextToUpdate3 = ms->nextToUpdate;
+    ip += (ip == prefixStart);
+
+    /* Match Loop */
+    while (ip < ilimit) {
+        size_t matchLength=0;
+        size_t offset=0;
+        const BYTE* start=ip+1;
+        U32 current = (U32)(ip-base);
+
+        /* check repCode */
+        {   const U32 repIndex = (U32)(current+1 - offset_1);
+            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+            const BYTE* const repMatch = repBase + repIndex;
+            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))   /* intentional overflow */
+            if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
+                /* repcode detected we should take it */
+                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+                matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+                if (depth==0) goto _storeSequence;
+        }   }
+
+        /* first search (depth 0) */
+        {   size_t offsetFound = 999999999;
+            size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
+            if (ml2 > matchLength)
+                matchLength = ml2, start = ip, offset=offsetFound;
+        }
+
+         if (matchLength < 4) {
+            ip += ((ip-anchor) >> kSearchStrength) + 1;   /* jump faster over incompressible sections */
+            continue;
+        }
+
+        /* let's try to find a better solution */
+        if (depth>=1)
+        while (ip<ilimit) {
+            ip ++;
+            current++;
+            /* check repCode */
+            if (offset) {
+                const U32 repIndex = (U32)(current - offset_1);
+                const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+                const BYTE* const repMatch = repBase + repIndex;
+                if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */
+                if (MEM_read32(ip) == MEM_read32(repMatch)) {
+                    /* repcode detected */
+                    const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+                    size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+                    int const gain2 = (int)(repLength * 3);
+                    int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+                    if ((repLength >= 4) && (gain2 > gain1))
+                        matchLength = repLength, offset = 0, start = ip;
+            }   }
+
+            /* search match, depth 1 */
+            {   size_t offset2=999999999;
+                size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
+                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
+                if ((ml2 >= 4) && (gain2 > gain1)) {
+                    matchLength = ml2, offset = offset2, start = ip;
+                    continue;   /* search a better one */
+            }   }
+
+            /* let's find an even better one */
+            if ((depth==2) && (ip<ilimit)) {
+                ip ++;
+                current++;
+                /* check repCode */
+                if (offset) {
+                    const U32 repIndex = (U32)(current - offset_1);
+                    const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+                    const BYTE* const repMatch = repBase + repIndex;
+                    if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */
+                    if (MEM_read32(ip) == MEM_read32(repMatch)) {
+                        /* repcode detected */
+                        const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+                        size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+                        int const gain2 = (int)(repLength * 4);
+                        int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+                        if ((repLength >= 4) && (gain2 > gain1))
+                            matchLength = repLength, offset = 0, start = ip;
+                }   }
+
+                /* search match, depth 2 */
+                {   size_t offset2=999999999;
+                    size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+                    int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
+                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+                    if ((ml2 >= 4) && (gain2 > gain1)) {
+                        matchLength = ml2, offset = offset2, start = ip;
+                        continue;
+            }   }   }
+            break;  /* nothing found : store previous solution */
+        }
+
+        /* catch up */
+        if (offset) {
+            U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
+            const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
+            const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
+            while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; }  /* catch up */
+            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+        }
+
+        /* store sequence */
+_storeSequence:
+        {   size_t const litLength = start - anchor;
+            ZSTD_storeSeq(seqStore, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+            anchor = ip = start + matchLength;
+        }
+
+        /* check immediate repcode */
+        while (ip <= ilimit) {
+            const U32 repIndex = (U32)((ip-base) - offset_2);
+            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+            const BYTE* const repMatch = repBase + repIndex;
+            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */
+            if (MEM_read32(ip) == MEM_read32(repMatch)) {
+                /* repcode detected we should take it */
+                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+                matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+                offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset;   /* swap offset history */
+                ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH);
+                ip += matchLength;
+                anchor = ip;
+                continue;   /* faster when present ... (?) */
+            }
+            break;
+    }   }
+
+    /* Save reps for next block */
+    rep[0] = offset_1;
+    rep[1] = offset_2;
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_greedy_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 0);
+}
+
+size_t ZSTD_compressBlock_lazy_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 1);
+}
+
+size_t ZSTD_compressBlock_lazy2_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 2);
+}
+
+size_t ZSTD_compressBlock_btlazy2_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 1, 2);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_lazy.h b/Utilities/cmzstd/lib/compress/zstd_lazy.h
new file mode 100644
index 0000000..ef85a6d
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_lazy.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_LAZY_H
+#define ZSTD_LAZY_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
+
+void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue);  /*! used in ZSTD_reduceIndex(). pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK */
+
+size_t ZSTD_compressBlock_btlazy2(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_btlazy2_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_greedy_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btlazy2_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_LAZY_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_ldm.c b/Utilities/cmzstd/lib/compress/zstd_ldm.c
new file mode 100644
index 0000000..58eb2ff
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_ldm.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#include "zstd_ldm.h"
+
+#include "debug.h"
+#include "zstd_fast.h"          /* ZSTD_fillHashTable() */
+#include "zstd_double_fast.h"   /* ZSTD_fillDoubleHashTable() */
+
+#define LDM_BUCKET_SIZE_LOG 3
+#define LDM_MIN_MATCH_LENGTH 64
+#define LDM_HASH_RLOG 7
+#define LDM_HASH_CHAR_OFFSET 10
+
+void ZSTD_ldm_adjustParameters(ldmParams_t* params,
+                               ZSTD_compressionParameters const* cParams)
+{
+    params->windowLog = cParams->windowLog;
+    ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
+    DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
+    if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
+    if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
+    if (cParams->strategy >= ZSTD_btopt) {
+      /* Get out of the way of the optimal parser */
+      U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
+      assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
+      assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
+      params->minMatchLength = minMatch;
+    }
+    if (params->hashLog == 0) {
+        params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
+        assert(params->hashLog <= ZSTD_HASHLOG_MAX);
+    }
+    if (params->hashRateLog == 0) {
+        params->hashRateLog = params->windowLog < params->hashLog
+                                   ? 0
+                                   : params->windowLog - params->hashLog;
+    }
+    params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
+}
+
+size_t ZSTD_ldm_getTableSize(ldmParams_t params)
+{
+    size_t const ldmHSize = ((size_t)1) << params.hashLog;
+    size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
+    size_t const ldmBucketSize =
+        ((size_t)1) << (params.hashLog - ldmBucketSizeLog);
+    size_t const totalSize = ldmBucketSize + ldmHSize * sizeof(ldmEntry_t);
+    return params.enableLdm ? totalSize : 0;
+}
+
+size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
+{
+    return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
+}
+
+/** ZSTD_ldm_getSmallHash() :
+ *  numBits should be <= 32
+ *  If numBits==0, returns 0.
+ *  @return : the most significant numBits of value. */
+static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
+{
+    assert(numBits <= 32);
+    return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
+}
+
+/** ZSTD_ldm_getChecksum() :
+ *  numBitsToDiscard should be <= 32
+ *  @return : the next most significant 32 bits after numBitsToDiscard */
+static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
+{
+    assert(numBitsToDiscard <= 32);
+    return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
+}
+
+/** ZSTD_ldm_getTag() ;
+ *  Given the hash, returns the most significant numTagBits bits
+ *  after (32 + hbits) bits.
+ *
+ *  If there are not enough bits remaining, return the last
+ *  numTagBits bits. */
+static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
+{
+    assert(numTagBits < 32 && hbits <= 32);
+    if (32 - hbits < numTagBits) {
+        return hash & (((U32)1 << numTagBits) - 1);
+    } else {
+        return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
+    }
+}
+
+/** ZSTD_ldm_getBucket() :
+ *  Returns a pointer to the start of the bucket associated with hash. */
+static ldmEntry_t* ZSTD_ldm_getBucket(
+        ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
+{
+    return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
+}
+
+/** ZSTD_ldm_insertEntry() :
+ *  Insert the entry with corresponding hash into the hash table */
+static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
+                                 size_t const hash, const ldmEntry_t entry,
+                                 ldmParams_t const ldmParams)
+{
+    BYTE* const bucketOffsets = ldmState->bucketOffsets;
+    *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
+    bucketOffsets[hash]++;
+    bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
+}
+
+/** ZSTD_ldm_makeEntryAndInsertByTag() :
+ *
+ *  Gets the small hash, checksum, and tag from the rollingHash.
+ *
+ *  If the tag matches (1 << ldmParams.hashRateLog)-1, then
+ *  creates an ldmEntry from the offset, and inserts it into the hash table.
+ *
+ *  hBits is the length of the small hash, which is the most significant hBits
+ *  of rollingHash. The checksum is the next 32 most significant bits, followed
+ *  by ldmParams.hashRateLog bits that make up the tag. */
+static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
+                                             U64 const rollingHash,
+                                             U32 const hBits,
+                                             U32 const offset,
+                                             ldmParams_t const ldmParams)
+{
+    U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
+    U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
+    if (tag == tagMask) {
+        U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
+        U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
+        ldmEntry_t entry;
+        entry.offset = offset;
+        entry.checksum = checksum;
+        ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
+    }
+}
+
+/** ZSTD_ldm_countBackwardsMatch() :
+ *  Returns the number of bytes that match backwards before pIn and pMatch.
+ *
+ *  We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
+static size_t ZSTD_ldm_countBackwardsMatch(
+            const BYTE* pIn, const BYTE* pAnchor,
+            const BYTE* pMatch, const BYTE* pBase)
+{
+    size_t matchLength = 0;
+    while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
+        pIn--;
+        pMatch--;
+        matchLength++;
+    }
+    return matchLength;
+}
+
+/** ZSTD_ldm_fillFastTables() :
+ *
+ *  Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
+ *  This is similar to ZSTD_loadDictionaryContent.
+ *
+ *  The tables for the other strategies are filled within their
+ *  block compressors. */
+static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
+                                      void const* end)
+{
+    const BYTE* const iend = (const BYTE*)end;
+
+    switch(ms->cParams.strategy)
+    {
+    case ZSTD_fast:
+        ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast);
+        break;
+
+    case ZSTD_dfast:
+        ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast);
+        break;
+
+    case ZSTD_greedy:
+    case ZSTD_lazy:
+    case ZSTD_lazy2:
+    case ZSTD_btlazy2:
+    case ZSTD_btopt:
+    case ZSTD_btultra:
+    case ZSTD_btultra2:
+        break;
+    default:
+        assert(0);  /* not possible : not a valid strategy id */
+    }
+
+    return 0;
+}
+
+/** ZSTD_ldm_fillLdmHashTable() :
+ *
+ *  Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
+ *  lastHash is the rolling hash that corresponds to lastHashed.
+ *
+ *  Returns the rolling hash corresponding to position iend-1. */
+static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
+                                     U64 lastHash, const BYTE* lastHashed,
+                                     const BYTE* iend, const BYTE* base,
+                                     U32 hBits, ldmParams_t const ldmParams)
+{
+    U64 rollingHash = lastHash;
+    const BYTE* cur = lastHashed + 1;
+
+    while (cur < iend) {
+        rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
+                                              cur[ldmParams.minMatchLength-1],
+                                              state->hashPower);
+        ZSTD_ldm_makeEntryAndInsertByTag(state,
+                                         rollingHash, hBits,
+                                         (U32)(cur - base), ldmParams);
+        ++cur;
+    }
+    return rollingHash;
+}
+
+
+/** ZSTD_ldm_limitTableUpdate() :
+ *
+ *  Sets cctx->nextToUpdate to a position corresponding closer to anchor
+ *  if it is far way
+ *  (after a long match, only update tables a limited amount). */
+static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
+{
+    U32 const current = (U32)(anchor - ms->window.base);
+    if (current > ms->nextToUpdate + 1024) {
+        ms->nextToUpdate =
+            current - MIN(512, current - ms->nextToUpdate - 1024);
+    }
+}
+
+static size_t ZSTD_ldm_generateSequences_internal(
+        ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
+        ldmParams_t const* params, void const* src, size_t srcSize)
+{
+    /* LDM parameters */
+    int const extDict = ZSTD_window_hasExtDict(ldmState->window);
+    U32 const minMatchLength = params->minMatchLength;
+    U64 const hashPower = ldmState->hashPower;
+    U32 const hBits = params->hashLog - params->bucketSizeLog;
+    U32 const ldmBucketSize = 1U << params->bucketSizeLog;
+    U32 const hashRateLog = params->hashRateLog;
+    U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
+    /* Prefix and extDict parameters */
+    U32 const dictLimit = ldmState->window.dictLimit;
+    U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
+    BYTE const* const base = ldmState->window.base;
+    BYTE const* const dictBase = extDict ? ldmState->window.dictBase : NULL;
+    BYTE const* const dictStart = extDict ? dictBase + lowestIndex : NULL;
+    BYTE const* const dictEnd = extDict ? dictBase + dictLimit : NULL;
+    BYTE const* const lowPrefixPtr = base + dictLimit;
+    /* Input bounds */
+    BYTE const* const istart = (BYTE const*)src;
+    BYTE const* const iend = istart + srcSize;
+    BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
+    /* Input positions */
+    BYTE const* anchor = istart;
+    BYTE const* ip = istart;
+    /* Rolling hash */
+    BYTE const* lastHashed = NULL;
+    U64 rollingHash = 0;
+
+    while (ip <= ilimit) {
+        size_t mLength;
+        U32 const current = (U32)(ip - base);
+        size_t forwardMatchLength = 0, backwardMatchLength = 0;
+        ldmEntry_t* bestEntry = NULL;
+        if (ip != istart) {
+            rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
+                                                  lastHashed[minMatchLength],
+                                                  hashPower);
+        } else {
+            rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
+        }
+        lastHashed = ip;
+
+        /* Do not insert and do not look for a match */
+        if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
+           ip++;
+           continue;
+        }
+
+        /* Get the best entry and compute the match lengths */
+        {
+            ldmEntry_t* const bucket =
+                ZSTD_ldm_getBucket(ldmState,
+                                   ZSTD_ldm_getSmallHash(rollingHash, hBits),
+                                   *params);
+            ldmEntry_t* cur;
+            size_t bestMatchLength = 0;
+            U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
+
+            for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
+                size_t curForwardMatchLength, curBackwardMatchLength,
+                       curTotalMatchLength;
+                if (cur->checksum != checksum || cur->offset <= lowestIndex) {
+                    continue;
+                }
+                if (extDict) {
+                    BYTE const* const curMatchBase =
+                        cur->offset < dictLimit ? dictBase : base;
+                    BYTE const* const pMatch = curMatchBase + cur->offset;
+                    BYTE const* const matchEnd =
+                        cur->offset < dictLimit ? dictEnd : iend;
+                    BYTE const* const lowMatchPtr =
+                        cur->offset < dictLimit ? dictStart : lowPrefixPtr;
+
+                    curForwardMatchLength = ZSTD_count_2segments(
+                                                ip, pMatch, iend,
+                                                matchEnd, lowPrefixPtr);
+                    if (curForwardMatchLength < minMatchLength) {
+                        continue;
+                    }
+                    curBackwardMatchLength =
+                        ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
+                                                     lowMatchPtr);
+                    curTotalMatchLength = curForwardMatchLength +
+                                          curBackwardMatchLength;
+                } else { /* !extDict */
+                    BYTE const* const pMatch = base + cur->offset;
+                    curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
+                    if (curForwardMatchLength < minMatchLength) {
+                        continue;
+                    }
+                    curBackwardMatchLength =
+                        ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
+                                                     lowPrefixPtr);
+                    curTotalMatchLength = curForwardMatchLength +
+                                          curBackwardMatchLength;
+                }
+
+                if (curTotalMatchLength > bestMatchLength) {
+                    bestMatchLength = curTotalMatchLength;
+                    forwardMatchLength = curForwardMatchLength;
+                    backwardMatchLength = curBackwardMatchLength;
+                    bestEntry = cur;
+                }
+            }
+        }
+
+        /* No match found -- continue searching */
+        if (bestEntry == NULL) {
+            ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
+                                             hBits, current,
+                                             *params);
+            ip++;
+            continue;
+        }
+
+        /* Match found */
+        mLength = forwardMatchLength + backwardMatchLength;
+        ip -= backwardMatchLength;
+
+        {
+            /* Store the sequence:
+             * ip = current - backwardMatchLength
+             * The match is at (bestEntry->offset - backwardMatchLength)
+             */
+            U32 const matchIndex = bestEntry->offset;
+            U32 const offset = current - matchIndex;
+            rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
+
+            /* Out of sequence storage */
+            if (rawSeqStore->size == rawSeqStore->capacity)
+                return ERROR(dstSize_tooSmall);
+            seq->litLength = (U32)(ip - anchor);
+            seq->matchLength = (U32)mLength;
+            seq->offset = offset;
+            rawSeqStore->size++;
+        }
+
+        /* Insert the current entry into the hash table */
+        ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
+                                         (U32)(lastHashed - base),
+                                         *params);
+
+        assert(ip + backwardMatchLength == lastHashed);
+
+        /* Fill the hash table from lastHashed+1 to ip+mLength*/
+        /* Heuristic: don't need to fill the entire table at end of block */
+        if (ip + mLength <= ilimit) {
+            rollingHash = ZSTD_ldm_fillLdmHashTable(
+                              ldmState, rollingHash, lastHashed,
+                              ip + mLength, base, hBits, *params);
+            lastHashed = ip + mLength - 1;
+        }
+        ip += mLength;
+        anchor = ip;
+    }
+    return iend - anchor;
+}
+
+/*! ZSTD_ldm_reduceTable() :
+ *  reduce table indexes by `reducerValue` */
+static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
+                                 U32 const reducerValue)
+{
+    U32 u;
+    for (u = 0; u < size; u++) {
+        if (table[u].offset < reducerValue) table[u].offset = 0;
+        else table[u].offset -= reducerValue;
+    }
+}
+
+size_t ZSTD_ldm_generateSequences(
+        ldmState_t* ldmState, rawSeqStore_t* sequences,
+        ldmParams_t const* params, void const* src, size_t srcSize)
+{
+    U32 const maxDist = 1U << params->windowLog;
+    BYTE const* const istart = (BYTE const*)src;
+    BYTE const* const iend = istart + srcSize;
+    size_t const kMaxChunkSize = 1 << 20;
+    size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
+    size_t chunk;
+    size_t leftoverSize = 0;
+
+    assert(ZSTD_CHUNKSIZE_MAX >= kMaxChunkSize);
+    /* Check that ZSTD_window_update() has been called for this chunk prior
+     * to passing it to this function.
+     */
+    assert(ldmState->window.nextSrc >= (BYTE const*)src + srcSize);
+    /* The input could be very large (in zstdmt), so it must be broken up into
+     * chunks to enforce the maximmum distance and handle overflow correction.
+     */
+    assert(sequences->pos <= sequences->size);
+    assert(sequences->size <= sequences->capacity);
+    for (chunk = 0; chunk < nbChunks && sequences->size < sequences->capacity; ++chunk) {
+        BYTE const* const chunkStart = istart + chunk * kMaxChunkSize;
+        size_t const remaining = (size_t)(iend - chunkStart);
+        BYTE const *const chunkEnd =
+            (remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
+        size_t const chunkSize = chunkEnd - chunkStart;
+        size_t newLeftoverSize;
+        size_t const prevSize = sequences->size;
+
+        assert(chunkStart < iend);
+        /* 1. Perform overflow correction if necessary. */
+        if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
+            U32 const ldmHSize = 1U << params->hashLog;
+            U32 const correction = ZSTD_window_correctOverflow(
+                &ldmState->window, /* cycleLog */ 0, maxDist, src);
+            ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction);
+        }
+        /* 2. We enforce the maximum offset allowed.
+         *
+         * kMaxChunkSize should be small enough that we don't lose too much of
+         * the window through early invalidation.
+         * TODO: * Test the chunk size.
+         *       * Try invalidation after the sequence generation and test the
+         *         the offset against maxDist directly.
+         */
+        ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL, NULL);
+        /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
+        newLeftoverSize = ZSTD_ldm_generateSequences_internal(
+            ldmState, sequences, params, chunkStart, chunkSize);
+        if (ZSTD_isError(newLeftoverSize))
+            return newLeftoverSize;
+        /* 4. We add the leftover literals from previous iterations to the first
+         *    newly generated sequence, or add the `newLeftoverSize` if none are
+         *    generated.
+         */
+        /* Prepend the leftover literals from the last call */
+        if (prevSize < sequences->size) {
+            sequences->seq[prevSize].litLength += (U32)leftoverSize;
+            leftoverSize = newLeftoverSize;
+        } else {
+            assert(newLeftoverSize == chunkSize);
+            leftoverSize += chunkSize;
+        }
+    }
+    return 0;
+}
+
+void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) {
+    while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
+        rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
+        if (srcSize <= seq->litLength) {
+            /* Skip past srcSize literals */
+            seq->litLength -= (U32)srcSize;
+            return;
+        }
+        srcSize -= seq->litLength;
+        seq->litLength = 0;
+        if (srcSize < seq->matchLength) {
+            /* Skip past the first srcSize of the match */
+            seq->matchLength -= (U32)srcSize;
+            if (seq->matchLength < minMatch) {
+                /* The match is too short, omit it */
+                if (rawSeqStore->pos + 1 < rawSeqStore->size) {
+                    seq[1].litLength += seq[0].matchLength;
+                }
+                rawSeqStore->pos++;
+            }
+            return;
+        }
+        srcSize -= seq->matchLength;
+        seq->matchLength = 0;
+        rawSeqStore->pos++;
+    }
+}
+
+/**
+ * If the sequence length is longer than remaining then the sequence is split
+ * between this block and the next.
+ *
+ * Returns the current sequence to handle, or if the rest of the block should
+ * be literals, it returns a sequence with offset == 0.
+ */
+static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
+                                 U32 const remaining, U32 const minMatch)
+{
+    rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
+    assert(sequence.offset > 0);
+    /* Likely: No partial sequence */
+    if (remaining >= sequence.litLength + sequence.matchLength) {
+        rawSeqStore->pos++;
+        return sequence;
+    }
+    /* Cut the sequence short (offset == 0 ==> rest is literals). */
+    if (remaining <= sequence.litLength) {
+        sequence.offset = 0;
+    } else if (remaining < sequence.litLength + sequence.matchLength) {
+        sequence.matchLength = remaining - sequence.litLength;
+        if (sequence.matchLength < minMatch) {
+            sequence.offset = 0;
+        }
+    }
+    /* Skip past `remaining` bytes for the future sequences. */
+    ZSTD_ldm_skipSequences(rawSeqStore, remaining, minMatch);
+    return sequence;
+}
+
+size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
+    ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+    void const* src, size_t srcSize)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    unsigned const minMatch = cParams->minMatch;
+    ZSTD_blockCompressor const blockCompressor =
+        ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
+    /* Input bounds */
+    BYTE const* const istart = (BYTE const*)src;
+    BYTE const* const iend = istart + srcSize;
+    /* Input positions */
+    BYTE const* ip = istart;
+
+    DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
+    assert(rawSeqStore->pos <= rawSeqStore->size);
+    assert(rawSeqStore->size <= rawSeqStore->capacity);
+    /* Loop through each sequence and apply the block compressor to the lits */
+    while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
+        /* maybeSplitSequence updates rawSeqStore->pos */
+        rawSeq const sequence = maybeSplitSequence(rawSeqStore,
+                                                   (U32)(iend - ip), minMatch);
+        int i;
+        /* End signal */
+        if (sequence.offset == 0)
+            break;
+
+        assert(sequence.offset <= (1U << cParams->windowLog));
+        assert(ip + sequence.litLength + sequence.matchLength <= iend);
+
+        /* Fill tables for block compressor */
+        ZSTD_ldm_limitTableUpdate(ms, ip);
+        ZSTD_ldm_fillFastTables(ms, ip);
+        /* Run the block compressor */
+        DEBUGLOG(5, "calling block compressor on segment of size %u", sequence.litLength);
+        {
+            size_t const newLitLength =
+                blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
+            ip += sequence.litLength;
+            /* Update the repcodes */
+            for (i = ZSTD_REP_NUM - 1; i > 0; i--)
+                rep[i] = rep[i-1];
+            rep[0] = sequence.offset;
+            /* Store the sequence */
+            ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength,
+                          sequence.offset + ZSTD_REP_MOVE,
+                          sequence.matchLength - MINMATCH);
+            ip += sequence.matchLength;
+        }
+    }
+    /* Fill the tables for the block compressor */
+    ZSTD_ldm_limitTableUpdate(ms, ip);
+    ZSTD_ldm_fillFastTables(ms, ip);
+    /* Compress the last literals */
+    return blockCompressor(ms, seqStore, rep, ip, iend - ip);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstd_ldm.h b/Utilities/cmzstd/lib/compress/zstd_ldm.h
new file mode 100644
index 0000000..a478461
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_ldm.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#ifndef ZSTD_LDM_H
+#define ZSTD_LDM_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"   /* ldmParams_t, U32 */
+#include "zstd.h"   /* ZSTD_CCtx, size_t */
+
+/*-*************************************
+*  Long distance matching
+***************************************/
+
+#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT
+
+/**
+ * ZSTD_ldm_generateSequences():
+ *
+ * Generates the sequences using the long distance match finder.
+ * Generates long range matching sequences in `sequences`, which parse a prefix
+ * of the source. `sequences` must be large enough to store every sequence,
+ * which can be checked with `ZSTD_ldm_getMaxNbSeq()`.
+ * @returns 0 or an error code.
+ *
+ * NOTE: The user must have called ZSTD_window_update() for all of the input
+ * they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks.
+ * NOTE: This function returns an error if it runs out of space to store
+ *       sequences.
+ */
+size_t ZSTD_ldm_generateSequences(
+            ldmState_t* ldms, rawSeqStore_t* sequences,
+            ldmParams_t const* params, void const* src, size_t srcSize);
+
+/**
+ * ZSTD_ldm_blockCompress():
+ *
+ * Compresses a block using the predefined sequences, along with a secondary
+ * block compressor. The literals section of every sequence is passed to the
+ * secondary block compressor, and those sequences are interspersed with the
+ * predefined sequences. Returns the length of the last literals.
+ * Updates `rawSeqStore.pos` to indicate how many sequences have been consumed.
+ * `rawSeqStore.seq` may also be updated to split the last sequence between two
+ * blocks.
+ * @return The length of the last literals.
+ *
+ * NOTE: The source must be at most the maximum block size, but the predefined
+ * sequences can be any size, and may be longer than the block. In the case that
+ * they are longer than the block, the last sequences may need to be split into
+ * two. We handle that case correctly, and update `rawSeqStore` appropriately.
+ * NOTE: This function does not return any errors.
+ */
+size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
+            ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+            void const* src, size_t srcSize);
+
+/**
+ * ZSTD_ldm_skipSequences():
+ *
+ * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
+ * Avoids emitting matches less than `minMatch` bytes.
+ * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
+ */
+void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
+    U32 const minMatch);
+
+
+/** ZSTD_ldm_getTableSize() :
+ *  Estimate the space needed for long distance matching tables or 0 if LDM is
+ *  disabled.
+ */
+size_t ZSTD_ldm_getTableSize(ldmParams_t params);
+
+/** ZSTD_ldm_getSeqSpace() :
+ *  Return an upper bound on the number of sequences that can be produced by
+ *  the long distance matcher, or 0 if LDM is disabled.
+ */
+size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
+
+/** ZSTD_ldm_adjustParameters() :
+ *  If the params->hashRateLog is not set, set it to its default value based on
+ *  windowLog and params->hashLog.
+ *
+ *  Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
+ *  params->hashLog if it is not).
+ *
+ *  Ensures that the minMatchLength >= targetLength during optimal parsing.
+ */
+void ZSTD_ldm_adjustParameters(ldmParams_t* params,
+                               ZSTD_compressionParameters const* cParams);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_FAST_H */
diff --git a/Utilities/cmzstd/lib/compress/zstd_opt.c b/Utilities/cmzstd/lib/compress/zstd_opt.c
new file mode 100644
index 0000000..44de6e9
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_opt.c
@@ -0,0 +1,1217 @@
+/*
+ * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "hist.h"
+#include "zstd_opt.h"
+
+
+#define ZSTD_LITFREQ_ADD    2   /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
+#define ZSTD_FREQ_DIV       4   /* log factor when using previous stats to init next stats */
+#define ZSTD_MAX_PRICE     (1<<30)
+
+#define ZSTD_PREDEF_THRESHOLD 1024   /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */
+
+
+/*-*************************************
+*  Price functions for optimal parser
+***************************************/
+
+#if 0    /* approximation at bit level */
+#  define BITCOST_ACCURACY 0
+#  define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+#  define WEIGHT(stat)  ((void)opt, ZSTD_bitWeight(stat))
+#elif 0  /* fractional bit accuracy */
+#  define BITCOST_ACCURACY 8
+#  define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+#  define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat))
+#else    /* opt==approx, ultra==accurate */
+#  define BITCOST_ACCURACY 8
+#  define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+#  define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
+#endif
+
+MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
+{
+    return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
+}
+
+MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
+{
+    U32 const stat = rawStat + 1;
+    U32 const hb = ZSTD_highbit32(stat);
+    U32 const BWeight = hb * BITCOST_MULTIPLIER;
+    U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
+    U32 const weight = BWeight + FWeight;
+    assert(hb + BITCOST_ACCURACY < 31);
+    return weight;
+}
+
+#if (DEBUGLEVEL>=2)
+/* debugging function,
+ * @return price in bytes as fractional value
+ * for debug messages only */
+MEM_STATIC double ZSTD_fCost(U32 price)
+{
+    return (double)price / (BITCOST_MULTIPLIER*8);
+}
+#endif
+
+static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
+{
+    optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
+    optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
+    optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
+    optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
+}
+
+
+/* ZSTD_downscaleStat() :
+ * reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus)
+ * return the resulting sum of elements */
+static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus)
+{
+    U32 s, sum=0;
+    DEBUGLOG(5, "ZSTD_downscaleStat (nbElts=%u)", (unsigned)lastEltIndex+1);
+    assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31);
+    for (s=0; s<lastEltIndex+1; s++) {
+        table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus));
+        sum += table[s];
+    }
+    return sum;
+}
+
+/* ZSTD_rescaleFreqs() :
+ * if first block (detected by optPtr->litLengthSum == 0) : init statistics
+ *    take hints from dictionary if there is one
+ *    or init from zero, using src for literals stats, or flat 1 for match symbols
+ * otherwise downscale existing stats, to be used as seed for next block.
+ */
+static void
+ZSTD_rescaleFreqs(optState_t* const optPtr,
+            const BYTE* const src, size_t const srcSize,
+                  int const optLevel)
+{
+    DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
+    optPtr->priceType = zop_dynamic;
+
+    if (optPtr->litLengthSum == 0) {  /* first block : init */
+        if (srcSize <= ZSTD_PREDEF_THRESHOLD) {  /* heuristic */
+            DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef");
+            optPtr->priceType = zop_predef;
+        }
+
+        assert(optPtr->symbolCosts != NULL);
+        if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
+            /* huffman table presumed generated by dictionary */
+            optPtr->priceType = zop_dynamic;
+
+            assert(optPtr->litFreq != NULL);
+            optPtr->litSum = 0;
+            {   unsigned lit;
+                for (lit=0; lit<=MaxLit; lit++) {
+                    U32 const scaleLog = 11;   /* scale to 2K */
+                    U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit);
+                    assert(bitCost <= scaleLog);
+                    optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+                    optPtr->litSum += optPtr->litFreq[lit];
+            }   }
+
+            {   unsigned ll;
+                FSE_CState_t llstate;
+                FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
+                optPtr->litLengthSum = 0;
+                for (ll=0; ll<=MaxLL; ll++) {
+                    U32 const scaleLog = 10;   /* scale to 1K */
+                    U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
+                    assert(bitCost < scaleLog);
+                    optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+                    optPtr->litLengthSum += optPtr->litLengthFreq[ll];
+            }   }
+
+            {   unsigned ml;
+                FSE_CState_t mlstate;
+                FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
+                optPtr->matchLengthSum = 0;
+                for (ml=0; ml<=MaxML; ml++) {
+                    U32 const scaleLog = 10;
+                    U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
+                    assert(bitCost < scaleLog);
+                    optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+                    optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
+            }   }
+
+            {   unsigned of;
+                FSE_CState_t ofstate;
+                FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
+                optPtr->offCodeSum = 0;
+                for (of=0; of<=MaxOff; of++) {
+                    U32 const scaleLog = 10;
+                    U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
+                    assert(bitCost < scaleLog);
+                    optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+                    optPtr->offCodeSum += optPtr->offCodeFreq[of];
+            }   }
+
+        } else {  /* not a dictionary */
+
+            assert(optPtr->litFreq != NULL);
+            {   unsigned lit = MaxLit;
+                HIST_count_simple(optPtr->litFreq, &lit, src, srcSize);   /* use raw first block to init statistics */
+            }
+            optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
+
+            {   unsigned ll;
+                for (ll=0; ll<=MaxLL; ll++)
+                    optPtr->litLengthFreq[ll] = 1;
+            }
+            optPtr->litLengthSum = MaxLL+1;
+
+            {   unsigned ml;
+                for (ml=0; ml<=MaxML; ml++)
+                    optPtr->matchLengthFreq[ml] = 1;
+            }
+            optPtr->matchLengthSum = MaxML+1;
+
+            {   unsigned of;
+                for (of=0; of<=MaxOff; of++)
+                    optPtr->offCodeFreq[of] = 1;
+            }
+            optPtr->offCodeSum = MaxOff+1;
+
+        }
+
+    } else {   /* new block : re-use previous statistics, scaled down */
+
+        optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
+        optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0);
+        optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0);
+        optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0);
+    }
+
+    ZSTD_setBasePrices(optPtr, optLevel);
+}
+
+/* ZSTD_rawLiteralsCost() :
+ * price of literals (only) in specified segment (which length can be 0).
+ * does not include price of literalLength symbol */
+static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
+                                const optState_t* const optPtr,
+                                int optLevel)
+{
+    if (litLength == 0) return 0;
+    if (optPtr->priceType == zop_predef)
+        return (litLength*6) * BITCOST_MULTIPLIER;  /* 6 bit per literal - no statistic used */
+
+    /* dynamic statistics */
+    {   U32 price = litLength * optPtr->litSumBasePrice;
+        U32 u;
+        for (u=0; u < litLength; u++) {
+            assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice);   /* literal cost should never be negative */
+            price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel);
+        }
+        return price;
+    }
+}
+
+/* ZSTD_litLengthPrice() :
+ * cost of literalLength symbol */
+static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
+{
+    if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
+
+    /* dynamic statistics */
+    {   U32 const llCode = ZSTD_LLcode(litLength);
+        return (LL_bits[llCode] * BITCOST_MULTIPLIER)
+             + optPtr->litLengthSumBasePrice
+             - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
+    }
+}
+
+/* ZSTD_litLengthContribution() :
+ * @return ( cost(litlength) - cost(0) )
+ * this value can then be added to rawLiteralsCost()
+ * to provide a cost which is directly comparable to a match ending at same position */
+static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel)
+{
+    if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel);
+
+    /* dynamic statistics */
+    {   U32 const llCode = ZSTD_LLcode(litLength);
+        int const contribution = (LL_bits[llCode] * BITCOST_MULTIPLIER)
+                               + WEIGHT(optPtr->litLengthFreq[0], optLevel)   /* note: log2litLengthSum cancel out */
+                               - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
+#if 1
+        return contribution;
+#else
+        return MAX(0, contribution); /* sometimes better, sometimes not ... */
+#endif
+    }
+}
+
+/* ZSTD_literalsContribution() :
+ * creates a fake cost for the literals part of a sequence
+ * which can be compared to the ending cost of a match
+ * should a new match start at this position */
+static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength,
+                                     const optState_t* const optPtr,
+                                     int optLevel)
+{
+    int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel)
+                           + ZSTD_litLengthContribution(litLength, optPtr, optLevel);
+    return contribution;
+}
+
+/* ZSTD_getMatchPrice() :
+ * Provides the cost of the match part (offset + matchLength) of a sequence
+ * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
+ * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
+FORCE_INLINE_TEMPLATE U32
+ZSTD_getMatchPrice(U32 const offset,
+                   U32 const matchLength,
+             const optState_t* const optPtr,
+                   int const optLevel)
+{
+    U32 price;
+    U32 const offCode = ZSTD_highbit32(offset+1);
+    U32 const mlBase = matchLength - MINMATCH;
+    assert(matchLength >= MINMATCH);
+
+    if (optPtr->priceType == zop_predef)  /* fixed scheme, do not use statistics */
+        return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
+
+    /* dynamic statistics */
+    price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
+    if ((optLevel<2) /*static*/ && offCode >= 20)
+        price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
+
+    /* match Length */
+    {   U32 const mlCode = ZSTD_MLcode(mlBase);
+        price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
+    }
+
+    price += BITCOST_MULTIPLIER / 5;   /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
+
+    DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
+    return price;
+}
+
+/* ZSTD_updateStats() :
+ * assumption : literals + litLengtn <= iend */
+static void ZSTD_updateStats(optState_t* const optPtr,
+                             U32 litLength, const BYTE* literals,
+                             U32 offsetCode, U32 matchLength)
+{
+    /* literals */
+    {   U32 u;
+        for (u=0; u < litLength; u++)
+            optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
+        optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
+    }
+
+    /* literal Length */
+    {   U32 const llCode = ZSTD_LLcode(litLength);
+        optPtr->litLengthFreq[llCode]++;
+        optPtr->litLengthSum++;
+    }
+
+    /* match offset code (0-2=>repCode; 3+=>offset+2) */
+    {   U32 const offCode = ZSTD_highbit32(offsetCode+1);
+        assert(offCode <= MaxOff);
+        optPtr->offCodeFreq[offCode]++;
+        optPtr->offCodeSum++;
+    }
+
+    /* match Length */
+    {   U32 const mlBase = matchLength - MINMATCH;
+        U32 const mlCode = ZSTD_MLcode(mlBase);
+        optPtr->matchLengthFreq[mlCode]++;
+        optPtr->matchLengthSum++;
+    }
+}
+
+
+/* ZSTD_readMINMATCH() :
+ * function safe only for comparisons
+ * assumption : memPtr must be at least 4 bytes before end of buffer */
+MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
+{
+    switch (length)
+    {
+    default :
+    case 4 : return MEM_read32(memPtr);
+    case 3 : if (MEM_isLittleEndian())
+                return MEM_read32(memPtr)<<8;
+             else
+                return MEM_read32(memPtr)>>8;
+    }
+}
+
+
+/* Update hashTable3 up to ip (excluded)
+   Assumption : always within prefix (i.e. not within extDict) */
+static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip)
+{
+    U32* const hashTable3 = ms->hashTable3;
+    U32 const hashLog3 = ms->hashLog3;
+    const BYTE* const base = ms->window.base;
+    U32 idx = ms->nextToUpdate3;
+    U32 const target = ms->nextToUpdate3 = (U32)(ip - base);
+    size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
+    assert(hashLog3 > 0);
+
+    while(idx < target) {
+        hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
+        idx++;
+    }
+
+    return hashTable3[hash3];
+}
+
+
+/*-*************************************
+*  Binary Tree search
+***************************************/
+/** ZSTD_insertBt1() : add one or multiple positions to tree.
+ *  ip : assumed <= iend-8 .
+ * @return : nb of positions added */
+static U32 ZSTD_insertBt1(
+                ZSTD_matchState_t* ms,
+                const BYTE* const ip, const BYTE* const iend,
+                U32 const mls, const int extDict)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32*   const hashTable = ms->hashTable;
+    U32    const hashLog = cParams->hashLog;
+    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
+    U32*   const bt = ms->chainTable;
+    U32    const btLog  = cParams->chainLog - 1;
+    U32    const btMask = (1 << btLog) - 1;
+    U32 matchIndex = hashTable[h];
+    size_t commonLengthSmaller=0, commonLengthLarger=0;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const U32 dictLimit = ms->window.dictLimit;
+    const BYTE* const dictEnd = dictBase + dictLimit;
+    const BYTE* const prefixStart = base + dictLimit;
+    const BYTE* match;
+    const U32 current = (U32)(ip-base);
+    const U32 btLow = btMask >= current ? 0 : current - btMask;
+    U32* smallerPtr = bt + 2*(current&btMask);
+    U32* largerPtr  = smallerPtr + 1;
+    U32 dummy32;   /* to be nullified at the end */
+    U32 const windowLow = ms->window.lowLimit;
+    U32 matchEndIdx = current+8+1;
+    size_t bestLength = 8;
+    U32 nbCompares = 1U << cParams->searchLog;
+#ifdef ZSTD_C_PREDICT
+    U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
+    U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
+    predictedSmall += (predictedSmall>0);
+    predictedLarge += (predictedLarge>0);
+#endif /* ZSTD_C_PREDICT */
+
+    DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
+
+    assert(ip <= iend-8);   /* required for h calculation */
+    hashTable[h] = current;   /* Update Hash Table */
+
+    assert(windowLow > 0);
+    while (nbCompares-- && (matchIndex >= windowLow)) {
+        U32* const nextPtr = bt + 2*(matchIndex & btMask);
+        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+        assert(matchIndex < current);
+
+#ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
+        const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
+        if (matchIndex == predictedSmall) {
+            /* no need to check length, result known */
+            *smallerPtr = matchIndex;
+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
+            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
+            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
+            predictedSmall = predictPtr[1] + (predictPtr[1]>0);
+            continue;
+        }
+        if (matchIndex == predictedLarge) {
+            *largerPtr = matchIndex;
+            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
+            largerPtr = nextPtr;
+            matchIndex = nextPtr[0];
+            predictedLarge = predictPtr[0] + (predictPtr[0]>0);
+            continue;
+        }
+#endif
+
+        if (!extDict || (matchIndex+matchLength >= dictLimit)) {
+            assert(matchIndex+matchLength >= dictLimit);   /* might be wrong if actually extDict */
+            match = base + matchIndex;
+            matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+        } else {
+            match = dictBase + matchIndex;
+            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+            if (matchIndex+matchLength >= dictLimit)
+                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
+        }
+
+        if (matchLength > bestLength) {
+            bestLength = matchLength;
+            if (matchLength > matchEndIdx - matchIndex)
+                matchEndIdx = matchIndex + (U32)matchLength;
+        }
+
+        if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
+            break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
+        }
+
+        if (match[matchLength] < ip[matchLength]) {  /* necessarily within buffer */
+            /* match is smaller than current */
+            *smallerPtr = matchIndex;             /* update smaller idx */
+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
+            smallerPtr = nextPtr+1;               /* new "candidate" => larger than match, which was smaller than target */
+            matchIndex = nextPtr[1];              /* new matchIndex, larger than previous and closer to current */
+        } else {
+            /* match is larger than current */
+            *largerPtr = matchIndex;
+            commonLengthLarger = matchLength;
+            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
+            largerPtr = nextPtr;
+            matchIndex = nextPtr[0];
+    }   }
+
+    *smallerPtr = *largerPtr = 0;
+    if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));   /* speed optimization */
+    assert(matchEndIdx > current + 8);
+    return matchEndIdx - (current + 8);
+}
+
+FORCE_INLINE_TEMPLATE
+void ZSTD_updateTree_internal(
+                ZSTD_matchState_t* ms,
+                const BYTE* const ip, const BYTE* const iend,
+                const U32 mls, const ZSTD_dictMode_e dictMode)
+{
+    const BYTE* const base = ms->window.base;
+    U32 const target = (U32)(ip - base);
+    U32 idx = ms->nextToUpdate;
+    DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u  (dictMode:%u)",
+                idx, target, dictMode);
+
+    while(idx < target)
+        idx += ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict);
+    ms->nextToUpdate = target;
+}
+
+void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) {
+    ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
+}
+
+FORCE_INLINE_TEMPLATE
+U32 ZSTD_insertBtAndGetAllMatches (
+                    ZSTD_matchState_t* ms,
+                    const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode,
+                    U32 rep[ZSTD_REP_NUM],
+                    U32 const ll0,   /* tells if associated literal length is 0 or not. This value must be 0 or 1 */
+                    ZSTD_match_t* matches,
+                    const U32 lengthToBeat,
+                    U32 const mls /* template */)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+    const BYTE* const base = ms->window.base;
+    U32 const current = (U32)(ip-base);
+    U32 const hashLog = cParams->hashLog;
+    U32 const minMatch = (mls==3) ? 3 : 4;
+    U32* const hashTable = ms->hashTable;
+    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
+    U32 matchIndex  = hashTable[h];
+    U32* const bt   = ms->chainTable;
+    U32 const btLog = cParams->chainLog - 1;
+    U32 const btMask= (1U << btLog) - 1;
+    size_t commonLengthSmaller=0, commonLengthLarger=0;
+    const BYTE* const dictBase = ms->window.dictBase;
+    U32 const dictLimit = ms->window.dictLimit;
+    const BYTE* const dictEnd = dictBase + dictLimit;
+    const BYTE* const prefixStart = base + dictLimit;
+    U32 const btLow = btMask >= current ? 0 : current - btMask;
+    U32 const windowLow = ms->window.lowLimit;
+    U32 const matchLow = windowLow ? windowLow : 1;
+    U32* smallerPtr = bt + 2*(current&btMask);
+    U32* largerPtr  = bt + 2*(current&btMask) + 1;
+    U32 matchEndIdx = current+8+1;   /* farthest referenced position of any match => detects repetitive patterns */
+    U32 dummy32;   /* to be nullified at the end */
+    U32 mnum = 0;
+    U32 nbCompares = 1U << cParams->searchLog;
+
+    const ZSTD_matchState_t* dms    = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
+    const ZSTD_compressionParameters* const dmsCParams =
+                                      dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL;
+    const BYTE* const dmsBase       = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
+    const BYTE* const dmsEnd        = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
+    U32         const dmsHighLimit  = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
+    U32         const dmsLowLimit   = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
+    U32         const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
+    U32         const dmsHashLog    = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog;
+    U32         const dmsBtLog      = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog;
+    U32         const dmsBtMask     = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0;
+    U32         const dmsBtLow      = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
+
+    size_t bestLength = lengthToBeat-1;
+    DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
+
+    /* check repCode */
+    assert(ll0 <= 1);   /* necessarily 1 or 0 */
+    {   U32 const lastR = ZSTD_REP_NUM + ll0;
+        U32 repCode;
+        for (repCode = ll0; repCode < lastR; repCode++) {
+            U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+            U32 const repIndex = current - repOffset;
+            U32 repLen = 0;
+            assert(current >= dictLimit);
+            if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) {  /* equivalent to `current > repIndex >= dictLimit` */
+                if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) {
+                    repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
+                }
+            } else {  /* repIndex < dictLimit || repIndex >= current */
+                const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
+                                             dmsBase + repIndex - dmsIndexDelta :
+                                             dictBase + repIndex;
+                assert(current >= windowLow);
+                if ( dictMode == ZSTD_extDict
+                  && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow)  /* equivalent to `current > repIndex >= windowLow` */
+                     & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
+                  && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
+                    repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
+                }
+                if (dictMode == ZSTD_dictMatchState
+                  && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta))  /* equivalent to `current > repIndex >= dmsLowLimit` */
+                     & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
+                  && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
+                    repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
+            }   }
+            /* save longer solution */
+            if (repLen > bestLength) {
+                DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
+                            repCode, ll0, repOffset, repLen);
+                bestLength = repLen;
+                matches[mnum].off = repCode - ll0;
+                matches[mnum].len = (U32)repLen;
+                mnum++;
+                if ( (repLen > sufficient_len)
+                   | (ip+repLen == iLimit) ) {  /* best possible */
+                    return mnum;
+    }   }   }   }
+
+    /* HC3 match finder */
+    if ((mls == 3) /*static*/ && (bestLength < mls)) {
+        U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
+        if ((matchIndex3 >= matchLow)
+          & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
+            size_t mlen;
+            if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
+                const BYTE* const match = base + matchIndex3;
+                mlen = ZSTD_count(ip, match, iLimit);
+            } else {
+                const BYTE* const match = dictBase + matchIndex3;
+                mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart);
+            }
+
+            /* save best solution */
+            if (mlen >= mls /* == 3 > bestLength */) {
+                DEBUGLOG(8, "found small match with hlog3, of length %u",
+                            (U32)mlen);
+                bestLength = mlen;
+                assert(current > matchIndex3);
+                assert(mnum==0);  /* no prior solution */
+                matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE;
+                matches[0].len = (U32)mlen;
+                mnum = 1;
+                if ( (mlen > sufficient_len) |
+                     (ip+mlen == iLimit) ) {  /* best possible length */
+                    ms->nextToUpdate = current+1;  /* skip insertion */
+                    return 1;
+                }
+            }
+        }
+        /* no dictMatchState lookup: dicts don't have a populated HC3 table */
+    }
+
+    hashTable[h] = current;   /* Update Hash Table */
+
+    while (nbCompares-- && (matchIndex >= matchLow)) {
+        U32* const nextPtr = bt + 2*(matchIndex & btMask);
+        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+        const BYTE* match;
+        assert(current > matchIndex);
+
+        if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
+            assert(matchIndex+matchLength >= dictLimit);  /* ensure the condition is correct when !extDict */
+            match = base + matchIndex;
+            matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
+        } else {
+            match = dictBase + matchIndex;
+            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
+            if (matchIndex+matchLength >= dictLimit)
+                match = base + matchIndex;   /* prepare for match[matchLength] */
+        }
+
+        if (matchLength > bestLength) {
+            DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
+                    (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+            assert(matchEndIdx > matchIndex);
+            if (matchLength > matchEndIdx - matchIndex)
+                matchEndIdx = matchIndex + (U32)matchLength;
+            bestLength = matchLength;
+            matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+            matches[mnum].len = (U32)matchLength;
+            mnum++;
+            if ( (matchLength > ZSTD_OPT_NUM)
+               | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
+                if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
+                break; /* drop, to preserve bt consistency (miss a little bit of compression) */
+            }
+        }
+
+        if (match[matchLength] < ip[matchLength]) {
+            /* match smaller than current */
+            *smallerPtr = matchIndex;             /* update smaller idx */
+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
+            smallerPtr = nextPtr+1;               /* new candidate => larger than match, which was smaller than current */
+            matchIndex = nextPtr[1];              /* new matchIndex, larger than previous, closer to current */
+        } else {
+            *largerPtr = matchIndex;
+            commonLengthLarger = matchLength;
+            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
+            largerPtr = nextPtr;
+            matchIndex = nextPtr[0];
+    }   }
+
+    *smallerPtr = *largerPtr = 0;
+
+    if (dictMode == ZSTD_dictMatchState && nbCompares) {
+        size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls);
+        U32 dictMatchIndex = dms->hashTable[dmsH];
+        const U32* const dmsBt = dms->chainTable;
+        commonLengthSmaller = commonLengthLarger = 0;
+        while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) {
+            const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask);
+            size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+            const BYTE* match = dmsBase + dictMatchIndex;
+            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
+            if (dictMatchIndex+matchLength >= dmsHighLimit)
+                match = base + dictMatchIndex + dmsIndexDelta;   /* to prepare for next usage of match[matchLength] */
+
+            if (matchLength > bestLength) {
+                matchIndex = dictMatchIndex + dmsIndexDelta;
+                DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
+                        (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+                if (matchLength > matchEndIdx - matchIndex)
+                    matchEndIdx = matchIndex + (U32)matchLength;
+                bestLength = matchLength;
+                matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+                matches[mnum].len = (U32)matchLength;
+                mnum++;
+                if ( (matchLength > ZSTD_OPT_NUM)
+                   | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
+                    break;   /* drop, to guarantee consistency (miss a little bit of compression) */
+                }
+            }
+
+            if (dictMatchIndex <= dmsBtLow) { break; }   /* beyond tree size, stop the search */
+            if (match[matchLength] < ip[matchLength]) {
+                commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
+                dictMatchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
+            } else {
+                /* match is larger than current */
+                commonLengthLarger = matchLength;
+                dictMatchIndex = nextPtr[0];
+            }
+        }
+    }
+
+    assert(matchEndIdx > current+8);
+    ms->nextToUpdate = matchEndIdx - 8;  /* skip repetitive patterns */
+    return mnum;
+}
+
+
+FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode,
+                        U32 rep[ZSTD_REP_NUM], U32 const ll0,
+                        ZSTD_match_t* matches, U32 const lengthToBeat)
+{
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    U32 const matchLengthSearch = cParams->minMatch;
+    DEBUGLOG(8, "ZSTD_BtGetAllMatches");
+    if (ip < ms->window.base + ms->nextToUpdate) return 0;   /* skipped area */
+    ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode);
+    switch(matchLengthSearch)
+    {
+    case 3 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3);
+    default :
+    case 4 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 4);
+    case 5 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 5);
+    case 7 :
+    case 6 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 6);
+    }
+}
+
+
+/*-*******************************
+*  Optimal parser
+*********************************/
+typedef struct repcodes_s {
+    U32 rep[3];
+} repcodes_t;
+
+static repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
+{
+    repcodes_t newReps;
+    if (offset >= ZSTD_REP_NUM) {  /* full offset */
+        newReps.rep[2] = rep[1];
+        newReps.rep[1] = rep[0];
+        newReps.rep[0] = offset - ZSTD_REP_MOVE;
+    } else {   /* repcode */
+        U32 const repCode = offset + ll0;
+        if (repCode > 0) {  /* note : if repCode==0, no change */
+            U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+            newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2];
+            newReps.rep[1] = rep[0];
+            newReps.rep[0] = currentOffset;
+        } else {   /* repCode == 0 */
+            memcpy(&newReps, rep, sizeof(newReps));
+        }
+    }
+    return newReps;
+}
+
+
+static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
+{
+    return sol.litlen + sol.mlen;
+}
+
+#if 0 /* debug */
+
+static void
+listStats(const U32* table, int lastEltID)
+{
+    int const nbElts = lastEltID + 1;
+    int enb;
+    for (enb=0; enb < nbElts; enb++) {
+        (void)table;
+        //RAWLOG(2, "%3i:%3i,  ", enb, table[enb]);
+        RAWLOG(2, "%4i,", table[enb]);
+    }
+    RAWLOG(2, " \n");
+}
+
+#endif
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
+                               seqStore_t* seqStore,
+                               U32 rep[ZSTD_REP_NUM],
+                         const void* src, size_t srcSize,
+                         const int optLevel,
+                         const ZSTD_dictMode_e dictMode)
+{
+    optState_t* const optStatePtr = &ms->opt;
+    const BYTE* const istart = (const BYTE*)src;
+    const BYTE* ip = istart;
+    const BYTE* anchor = istart;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* const ilimit = iend - 8;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const prefixStart = base + ms->window.dictLimit;
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+
+    U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+    U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4;
+
+    ZSTD_optimal_t* const opt = optStatePtr->priceTable;
+    ZSTD_match_t* const matches = optStatePtr->matchTable;
+    ZSTD_optimal_t lastSequence;
+
+    /* init */
+    DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
+                (U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate);
+    assert(optLevel <= 2);
+    ms->nextToUpdate3 = ms->nextToUpdate;
+    ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
+    ip += (ip==prefixStart);
+
+    /* Match Loop */
+    while (ip < ilimit) {
+        U32 cur, last_pos = 0;
+
+        /* find first match */
+        {   U32 const litlen = (U32)(ip - anchor);
+            U32 const ll0 = !litlen;
+            U32 const nbMatches = ZSTD_BtGetAllMatches(ms, ip, iend, dictMode, rep, ll0, matches, minMatch);
+            if (!nbMatches) { ip++; continue; }
+
+            /* initialize opt[0] */
+            { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
+            opt[0].mlen = 0;  /* means is_a_literal */
+            opt[0].litlen = litlen;
+            opt[0].price = ZSTD_literalsContribution(anchor, litlen, optStatePtr, optLevel);
+
+            /* large match -> immediate encoding */
+            {   U32 const maxML = matches[nbMatches-1].len;
+                U32 const maxOffset = matches[nbMatches-1].off;
+                DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new serie",
+                            nbMatches, maxML, maxOffset, (U32)(ip-prefixStart));
+
+                if (maxML > sufficient_len) {
+                    lastSequence.litlen = litlen;
+                    lastSequence.mlen = maxML;
+                    lastSequence.off = maxOffset;
+                    DEBUGLOG(6, "large match (%u>%u), immediate encoding",
+                                maxML, sufficient_len);
+                    cur = 0;
+                    last_pos = ZSTD_totalLen(lastSequence);
+                    goto _shortestPath;
+            }   }
+
+            /* set prices for first matches starting position == 0 */
+            {   U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
+                U32 pos;
+                U32 matchNb;
+                for (pos = 1; pos < minMatch; pos++) {
+                    opt[pos].price = ZSTD_MAX_PRICE;   /* mlen, litlen and price will be fixed during forward scanning */
+                }
+                for (matchNb = 0; matchNb < nbMatches; matchNb++) {
+                    U32 const offset = matches[matchNb].off;
+                    U32 const end = matches[matchNb].len;
+                    repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0);
+                    for ( ; pos <= end ; pos++ ) {
+                        U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
+                        U32 const sequencePrice = literalsPrice + matchPrice;
+                        DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
+                                    pos, ZSTD_fCost(sequencePrice));
+                        opt[pos].mlen = pos;
+                        opt[pos].off = offset;
+                        opt[pos].litlen = litlen;
+                        opt[pos].price = sequencePrice;
+                        ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
+                        memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
+                }   }
+                last_pos = pos-1;
+            }
+        }
+
+        /* check further positions */
+        for (cur = 1; cur <= last_pos; cur++) {
+            const BYTE* const inr = ip + cur;
+            assert(cur < ZSTD_OPT_NUM);
+            DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
+
+            /* Fix current position with one literal if cheaper */
+            {   U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
+                int const price = opt[cur-1].price
+                                + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
+                                + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
+                                - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
+                assert(price < 1000000000); /* overflow check */
+                if (price <= opt[cur].price) {
+                    DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
+                                inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
+                                opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
+                    opt[cur].mlen = 0;
+                    opt[cur].off = 0;
+                    opt[cur].litlen = litlen;
+                    opt[cur].price = price;
+                    memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep));
+                } else {
+                    DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
+                                inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
+                                opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
+                }
+            }
+
+            /* last match must start at a minimum distance of 8 from oend */
+            if (inr > ilimit) continue;
+
+            if (cur == last_pos) break;
+
+            if ( (optLevel==0) /*static_test*/
+              && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
+                DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
+                continue;  /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
+            }
+
+            {   U32 const ll0 = (opt[cur].mlen != 0);
+                U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
+                U32 const previousPrice = opt[cur].price;
+                U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
+                U32 const nbMatches = ZSTD_BtGetAllMatches(ms, inr, iend, dictMode, opt[cur].rep, ll0, matches, minMatch);
+                U32 matchNb;
+                if (!nbMatches) {
+                    DEBUGLOG(7, "rPos:%u : no match found", cur);
+                    continue;
+                }
+
+                {   U32 const maxML = matches[nbMatches-1].len;
+                    DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
+                                inr-istart, cur, nbMatches, maxML);
+
+                    if ( (maxML > sufficient_len)
+                      || (cur + maxML >= ZSTD_OPT_NUM) ) {
+                        lastSequence.mlen = maxML;
+                        lastSequence.off = matches[nbMatches-1].off;
+                        lastSequence.litlen = litlen;
+                        cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0;  /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
+                        last_pos = cur + ZSTD_totalLen(lastSequence);
+                        if (cur > ZSTD_OPT_NUM) cur = 0;   /* underflow => first match */
+                        goto _shortestPath;
+                }   }
+
+                /* set prices using matches found at position == cur */
+                for (matchNb = 0; matchNb < nbMatches; matchNb++) {
+                    U32 const offset = matches[matchNb].off;
+                    repcodes_t const repHistory = ZSTD_updateRep(opt[cur].rep, offset, ll0);
+                    U32 const lastML = matches[matchNb].len;
+                    U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
+                    U32 mlen;
+
+                    DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u",
+                                matchNb, matches[matchNb].off, lastML, litlen);
+
+                    for (mlen = lastML; mlen >= startML; mlen--) {  /* scan downward */
+                        U32 const pos = cur + mlen;
+                        int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
+
+                        if ((pos > last_pos) || (price < opt[pos].price)) {
+                            DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
+                                        pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
+                            while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; }   /* fill empty positions */
+                            opt[pos].mlen = mlen;
+                            opt[pos].off = offset;
+                            opt[pos].litlen = litlen;
+                            opt[pos].price = price;
+                            ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
+                            memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
+                        } else {
+                            DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
+                                        pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
+                            if (optLevel==0) break;  /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
+                        }
+            }   }   }
+        }  /* for (cur = 1; cur <= last_pos; cur++) */
+
+        lastSequence = opt[last_pos];
+        cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0;  /* single sequence, and it starts before `ip` */
+        assert(cur < ZSTD_OPT_NUM);  /* control overflow*/
+
+_shortestPath:   /* cur, last_pos, best_mlen, best_off have to be set */
+        assert(opt[0].mlen == 0);
+
+        {   U32 const storeEnd = cur + 1;
+            U32 storeStart = storeEnd;
+            U32 seqPos = cur;
+
+            DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
+                        last_pos, cur); (void)last_pos;
+            assert(storeEnd < ZSTD_OPT_NUM);
+            DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
+                        storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
+            opt[storeEnd] = lastSequence;
+            while (seqPos > 0) {
+                U32 const backDist = ZSTD_totalLen(opt[seqPos]);
+                storeStart--;
+                DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
+                            seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
+                opt[storeStart] = opt[seqPos];
+                seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
+            }
+
+            /* save sequences */
+            DEBUGLOG(6, "sending selected sequences into seqStore")
+            {   U32 storePos;
+                for (storePos=storeStart; storePos <= storeEnd; storePos++) {
+                    U32 const llen = opt[storePos].litlen;
+                    U32 const mlen = opt[storePos].mlen;
+                    U32 const offCode = opt[storePos].off;
+                    U32 const advance = llen + mlen;
+                    DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u",
+                                anchor - istart, (unsigned)llen, (unsigned)mlen);
+
+                    if (mlen==0) {  /* only literals => must be last "sequence", actually starting a new stream of sequences */
+                        assert(storePos == storeEnd);   /* must be last sequence */
+                        ip = anchor + llen;     /* last "sequence" is a bunch of literals => don't progress anchor */
+                        continue;   /* will finish */
+                    }
+
+                    /* repcodes update : like ZSTD_updateRep(), but update in place */
+                    if (offCode >= ZSTD_REP_NUM) {  /* full offset */
+                        rep[2] = rep[1];
+                        rep[1] = rep[0];
+                        rep[0] = offCode - ZSTD_REP_MOVE;
+                    } else {   /* repcode */
+                        U32 const repCode = offCode + (llen==0);
+                        if (repCode) {  /* note : if repCode==0, no change */
+                            U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+                            if (repCode >= 2) rep[2] = rep[1];
+                            rep[1] = rep[0];
+                            rep[0] = currentOffset;
+                    }   }
+
+                    assert(anchor + llen <= iend);
+                    ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen);
+                    ZSTD_storeSeq(seqStore, llen, anchor, offCode, mlen-MINMATCH);
+                    anchor += advance;
+                    ip = anchor;
+            }   }
+            ZSTD_setBasePrices(optStatePtr, optLevel);
+        }
+
+    }   /* while (ip < ilimit) */
+
+    /* Return the last literals size */
+    return iend - anchor;
+}
+
+
+size_t ZSTD_compressBlock_btopt(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    DEBUGLOG(5, "ZSTD_compressBlock_btopt");
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
+}
+
+
+/* used in 2-pass strategy */
+static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus)
+{
+    U32 s, sum=0;
+    assert(ZSTD_FREQ_DIV+bonus >= 0);
+    for (s=0; s<lastEltIndex+1; s++) {
+        table[s] <<= ZSTD_FREQ_DIV+bonus;
+        table[s]--;
+        sum += table[s];
+    }
+    return sum;
+}
+
+/* used in 2-pass strategy */
+MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
+{
+    optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0);
+    optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0);
+    optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0);
+    optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0);
+}
+
+/* ZSTD_initStats_ultra():
+ * make a first compression pass, just to seed stats with more accurate starting values.
+ * only works on first block, with no dictionary and no ldm.
+ * this function cannot error, hence its constract must be respected.
+ */
+static void
+ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
+                     seqStore_t* seqStore,
+                     U32 rep[ZSTD_REP_NUM],
+               const void* src, size_t srcSize)
+{
+    U32 tmpRep[ZSTD_REP_NUM];  /* updated rep codes will sink here */
+    memcpy(tmpRep, rep, sizeof(tmpRep));
+
+    DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
+    assert(ms->opt.litLengthSum == 0);    /* first block */
+    assert(seqStore->sequences == seqStore->sequencesStart);   /* no ldm */
+    assert(ms->window.dictLimit == ms->window.lowLimit);   /* no dictionary */
+    assert(ms->window.dictLimit - ms->nextToUpdate <= 1);  /* no prefix (note: intentional overflow, defined as 2-complement) */
+
+    ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);   /* generate stats into ms->opt*/
+
+    /* invalidate first scan from history */
+    ZSTD_resetSeqStore(seqStore);
+    ms->window.base -= srcSize;
+    ms->window.dictLimit += (U32)srcSize;
+    ms->window.lowLimit = ms->window.dictLimit;
+    ms->nextToUpdate = ms->window.dictLimit;
+    ms->nextToUpdate3 = ms->window.dictLimit;
+
+    /* re-inforce weight of collected statistics */
+    ZSTD_upscaleStats(&ms->opt);
+}
+
+size_t ZSTD_compressBlock_btultra(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btultra2(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    U32 const current = (U32)((const BYTE*)src - ms->window.base);
+    DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
+
+    /* 2-pass strategy:
+     * this strategy makes a first pass over first block to collect statistics
+     * and seed next round's statistics with it.
+     * After 1st pass, function forgets everything, and starts a new block.
+     * Consequently, this can only work if no data has been previously loaded in tables,
+     * aka, no dictionary, no prefix, no ldm preprocessing.
+     * The compression ratio gain is generally small (~0.5% on first block),
+     * the cost is 2x cpu time on first block. */
+    assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
+    if ( (ms->opt.litLengthSum==0)   /* first block */
+      && (seqStore->sequences == seqStore->sequencesStart)  /* no ldm */
+      && (ms->window.dictLimit == ms->window.lowLimit)   /* no dictionary */
+      && (current == ms->window.dictLimit)   /* start of frame, nothing already loaded nor skipped */
+      && (srcSize > ZSTD_PREDEF_THRESHOLD)
+      ) {
+        ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
+    }
+
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btopt_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_btultra_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_btopt_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict);
+}
+
+size_t ZSTD_compressBlock_btultra_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        const void* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict);
+}
+
+/* note : no btultra2 variant for extDict nor dictMatchState,
+ * because btultra2 is not meant to work with dictionaries
+ * and is only specific for the first block (no prefix) */
diff --git a/Utilities/cmzstd/lib/compress/zstd_opt.h b/Utilities/cmzstd/lib/compress/zstd_opt.h
new file mode 100644
index 0000000..094f747
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstd_opt.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_OPT_H
+#define ZSTD_OPT_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"
+
+/* used in ZSTD_loadDictionaryContent() */
+void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend);
+
+size_t ZSTD_compressBlock_btopt(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra2(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+
+size_t ZSTD_compressBlock_btopt_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_dictMatchState(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_btopt_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_extDict(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+        /* note : no btultra2 variant for extDict nor dictMatchState,
+         * because btultra2 is not meant to work with dictionaries
+         * and is only specific for the first block (no prefix) */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_OPT_H */
diff --git a/Utilities/cmzstd/lib/compress/zstdmt_compress.c b/Utilities/cmzstd/lib/compress/zstdmt_compress.c
new file mode 100644
index 0000000..2cbd6ff
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstdmt_compress.c
@@ -0,0 +1,2107 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ======   Compiler specifics   ====== */
+#if defined(_MSC_VER)
+#  pragma warning(disable : 4204)   /* disable: C4204: non-constant aggregate initializer */
+#endif
+
+
+/* ======   Constants   ====== */
+#define ZSTDMT_OVERLAPLOG_DEFAULT 0
+
+
+/* ======   Dependencies   ====== */
+#include <string.h>      /* memcpy, memset */
+#include <limits.h>      /* INT_MAX, UINT_MAX */
+#include "pool.h"        /* threadpool */
+#include "threading.h"   /* mutex */
+#include "zstd_compress_internal.h"  /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
+#include "zstd_ldm.h"
+#include "zstdmt_compress.h"
+
+/* Guards code to support resizing the SeqPool.
+ * We will want to resize the SeqPool to save memory in the future.
+ * Until then, comment the code out since it is unused.
+ */
+#define ZSTD_RESIZE_SEQPOOL 0
+
+/* ======   Debug   ====== */
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=2) \
+    && !defined(_MSC_VER) \
+    && !defined(__MINGW32__)
+
+#  include <stdio.h>
+#  include <unistd.h>
+#  include <sys/times.h>
+
+#  define DEBUG_PRINTHEX(l,p,n) {            \
+    unsigned debug_u;                        \
+    for (debug_u=0; debug_u<(n); debug_u++)  \
+        RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
+    RAWLOG(l, " \n");                        \
+}
+
+static unsigned long long GetCurrentClockTimeMicroseconds(void)
+{
+   static clock_t _ticksPerSecond = 0;
+   if (_ticksPerSecond <= 0) _ticksPerSecond = sysconf(_SC_CLK_TCK);
+
+   {   struct tms junk; clock_t newTicks = (clock_t) times(&junk);
+       return ((((unsigned long long)newTicks)*(1000000))/_ticksPerSecond);
+}  }
+
+#define MUTEX_WAIT_TIME_DLEVEL 6
+#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) {          \
+    if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) {   \
+        unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
+        ZSTD_pthread_mutex_lock(mutex);           \
+        {   unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
+            unsigned long long const elapsedTime = (afterTime-beforeTime); \
+            if (elapsedTime > 1000) {  /* or whatever threshold you like; I'm using 1 millisecond here */ \
+                DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \
+                   elapsedTime, #mutex);          \
+        }   }                                     \
+    } else {                                      \
+        ZSTD_pthread_mutex_lock(mutex);           \
+    }                                             \
+}
+
+#else
+
+#  define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m)
+#  define DEBUG_PRINTHEX(l,p,n) {}
+
+#endif
+
+
+/* =====   Buffer Pool   ===== */
+/* a single Buffer Pool can be invoked from multiple threads in parallel */
+
+typedef struct buffer_s {
+    void* start;
+    size_t capacity;
+} buffer_t;
+
+static const buffer_t g_nullBuffer = { NULL, 0 };
+
+typedef struct ZSTDMT_bufferPool_s {
+    ZSTD_pthread_mutex_t poolMutex;
+    size_t bufferSize;
+    unsigned totalBuffers;
+    unsigned nbBuffers;
+    ZSTD_customMem cMem;
+    buffer_t bTable[1];   /* variable size */
+} ZSTDMT_bufferPool;
+
+static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbWorkers, ZSTD_customMem cMem)
+{
+    unsigned const maxNbBuffers = 2*nbWorkers + 3;
+    ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
+        sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
+    if (bufPool==NULL) return NULL;
+    if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) {
+        ZSTD_free(bufPool, cMem);
+        return NULL;
+    }
+    bufPool->bufferSize = 64 KB;
+    bufPool->totalBuffers = maxNbBuffers;
+    bufPool->nbBuffers = 0;
+    bufPool->cMem = cMem;
+    return bufPool;
+}
+
+static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
+{
+    unsigned u;
+    DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
+    if (!bufPool) return;   /* compatibility with free on NULL */
+    for (u=0; u<bufPool->totalBuffers; u++) {
+        DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start);
+        ZSTD_free(bufPool->bTable[u].start, bufPool->cMem);
+    }
+    ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
+    ZSTD_free(bufPool, bufPool->cMem);
+}
+
+/* only works at initialization, not during compression */
+static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
+{
+    size_t const poolSize = sizeof(*bufPool)
+                          + (bufPool->totalBuffers - 1) * sizeof(buffer_t);
+    unsigned u;
+    size_t totalBufferSize = 0;
+    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+    for (u=0; u<bufPool->totalBuffers; u++)
+        totalBufferSize += bufPool->bTable[u].capacity;
+    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+
+    return poolSize + totalBufferSize;
+}
+
+/* ZSTDMT_setBufferSize() :
+ * all future buffers provided by this buffer pool will have _at least_ this size
+ * note : it's better for all buffers to have same size,
+ * as they become freely interchangeable, reducing malloc/free usages and memory fragmentation */
+static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize)
+{
+    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+    DEBUGLOG(4, "ZSTDMT_setBufferSize: bSize = %u", (U32)bSize);
+    bufPool->bufferSize = bSize;
+    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+}
+
+
+static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, U32 nbWorkers)
+{
+    unsigned const maxNbBuffers = 2*nbWorkers + 3;
+    if (srcBufPool==NULL) return NULL;
+    if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */
+        return srcBufPool;
+    /* need a larger buffer pool */
+    {   ZSTD_customMem const cMem = srcBufPool->cMem;
+        size_t const bSize = srcBufPool->bufferSize;   /* forward parameters */
+        ZSTDMT_bufferPool* newBufPool;
+        ZSTDMT_freeBufferPool(srcBufPool);
+        newBufPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
+        if (newBufPool==NULL) return newBufPool;
+        ZSTDMT_setBufferSize(newBufPool, bSize);
+        return newBufPool;
+    }
+}
+
+/** ZSTDMT_getBuffer() :
+ *  assumption : bufPool must be valid
+ * @return : a buffer, with start pointer and size
+ *  note: allocation may fail, in this case, start==NULL and size==0 */
+static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
+{
+    size_t const bSize = bufPool->bufferSize;
+    DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize);
+    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+    if (bufPool->nbBuffers) {   /* try to use an existing buffer */
+        buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
+        size_t const availBufferSize = buf.capacity;
+        bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
+        if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) {
+            /* large enough, but not too much */
+            DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
+                        bufPool->nbBuffers, (U32)buf.capacity);
+            ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+            return buf;
+        }
+        /* size conditions not respected : scratch this buffer, create new one */
+        DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing");
+        ZSTD_free(buf.start, bufPool->cMem);
+    }
+    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+    /* create new buffer */
+    DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer");
+    {   buffer_t buffer;
+        void* const start = ZSTD_malloc(bSize, bufPool->cMem);
+        buffer.start = start;   /* note : start can be NULL if malloc fails ! */
+        buffer.capacity = (start==NULL) ? 0 : bSize;
+        if (start==NULL) {
+            DEBUGLOG(5, "ZSTDMT_getBuffer: buffer allocation failure !!");
+        } else {
+            DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
+        }
+        return buffer;
+    }
+}
+
+#if ZSTD_RESIZE_SEQPOOL
+/** ZSTDMT_resizeBuffer() :
+ * assumption : bufPool must be valid
+ * @return : a buffer that is at least the buffer pool buffer size.
+ *           If a reallocation happens, the data in the input buffer is copied.
+ */
+static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer)
+{
+    size_t const bSize = bufPool->bufferSize;
+    if (buffer.capacity < bSize) {
+        void* const start = ZSTD_malloc(bSize, bufPool->cMem);
+        buffer_t newBuffer;
+        newBuffer.start = start;
+        newBuffer.capacity = start == NULL ? 0 : bSize;
+        if (start != NULL) {
+            assert(newBuffer.capacity >= buffer.capacity);
+            memcpy(newBuffer.start, buffer.start, buffer.capacity);
+            DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize);
+            return newBuffer;
+        }
+        DEBUGLOG(5, "ZSTDMT_resizeBuffer: buffer allocation failure !!");
+    }
+    return buffer;
+}
+#endif
+
+/* store buffer for later re-use, up to pool capacity */
+static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
+{
+    DEBUGLOG(5, "ZSTDMT_releaseBuffer");
+    if (buf.start == NULL) return;   /* compatible with release on NULL */
+    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
+    if (bufPool->nbBuffers < bufPool->totalBuffers) {
+        bufPool->bTable[bufPool->nbBuffers++] = buf;  /* stored for later use */
+        DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
+                    (U32)buf.capacity, (U32)(bufPool->nbBuffers-1));
+        ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+        return;
+    }
+    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
+    /* Reached bufferPool capacity (should not happen) */
+    DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing ");
+    ZSTD_free(buf.start, bufPool->cMem);
+}
+
+
+/* =====   Seq Pool Wrapper   ====== */
+
+static rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0};
+
+typedef ZSTDMT_bufferPool ZSTDMT_seqPool;
+
+static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool)
+{
+    return ZSTDMT_sizeof_bufferPool(seqPool);
+}
+
+static rawSeqStore_t bufferToSeq(buffer_t buffer)
+{
+    rawSeqStore_t seq = {NULL, 0, 0, 0};
+    seq.seq = (rawSeq*)buffer.start;
+    seq.capacity = buffer.capacity / sizeof(rawSeq);
+    return seq;
+}
+
+static buffer_t seqToBuffer(rawSeqStore_t seq)
+{
+    buffer_t buffer;
+    buffer.start = seq.seq;
+    buffer.capacity = seq.capacity * sizeof(rawSeq);
+    return buffer;
+}
+
+static rawSeqStore_t ZSTDMT_getSeq(ZSTDMT_seqPool* seqPool)
+{
+    if (seqPool->bufferSize == 0) {
+        return kNullRawSeqStore;
+    }
+    return bufferToSeq(ZSTDMT_getBuffer(seqPool));
+}
+
+#if ZSTD_RESIZE_SEQPOOL
+static rawSeqStore_t ZSTDMT_resizeSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq)
+{
+  return bufferToSeq(ZSTDMT_resizeBuffer(seqPool, seqToBuffer(seq)));
+}
+#endif
+
+static void ZSTDMT_releaseSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq)
+{
+  ZSTDMT_releaseBuffer(seqPool, seqToBuffer(seq));
+}
+
+static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq)
+{
+  ZSTDMT_setBufferSize(seqPool, nbSeq * sizeof(rawSeq));
+}
+
+static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem)
+{
+    ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
+    if (seqPool == NULL) return NULL;
+    ZSTDMT_setNbSeq(seqPool, 0);
+    return seqPool;
+}
+
+static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool)
+{
+    ZSTDMT_freeBufferPool(seqPool);
+}
+
+static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers)
+{
+    return ZSTDMT_expandBufferPool(pool, nbWorkers);
+}
+
+
+/* =====   CCtx Pool   ===== */
+/* a single CCtx Pool can be invoked from multiple threads in parallel */
+
+typedef struct {
+    ZSTD_pthread_mutex_t poolMutex;
+    int totalCCtx;
+    int availCCtx;
+    ZSTD_customMem cMem;
+    ZSTD_CCtx* cctx[1];   /* variable size */
+} ZSTDMT_CCtxPool;
+
+/* note : all CCtx borrowed from the pool should be released back to the pool _before_ freeing the pool */
+static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
+{
+    int cid;
+    for (cid=0; cid<pool->totalCCtx; cid++)
+        ZSTD_freeCCtx(pool->cctx[cid]);  /* note : compatible with free on NULL */
+    ZSTD_pthread_mutex_destroy(&pool->poolMutex);
+    ZSTD_free(pool, pool->cMem);
+}
+
+/* ZSTDMT_createCCtxPool() :
+ * implies nbWorkers >= 1 , checked by caller ZSTDMT_createCCtx() */
+static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers,
+                                              ZSTD_customMem cMem)
+{
+    ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
+        sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem);
+    assert(nbWorkers > 0);
+    if (!cctxPool) return NULL;
+    if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
+        ZSTD_free(cctxPool, cMem);
+        return NULL;
+    }
+    cctxPool->cMem = cMem;
+    cctxPool->totalCCtx = nbWorkers;
+    cctxPool->availCCtx = 1;   /* at least one cctx for single-thread mode */
+    cctxPool->cctx[0] = ZSTD_createCCtx_advanced(cMem);
+    if (!cctxPool->cctx[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; }
+    DEBUGLOG(3, "cctxPool created, with %u workers", nbWorkers);
+    return cctxPool;
+}
+
+static ZSTDMT_CCtxPool* ZSTDMT_expandCCtxPool(ZSTDMT_CCtxPool* srcPool,
+                                              int nbWorkers)
+{
+    if (srcPool==NULL) return NULL;
+    if (nbWorkers <= srcPool->totalCCtx) return srcPool;   /* good enough */
+    /* need a larger cctx pool */
+    {   ZSTD_customMem const cMem = srcPool->cMem;
+        ZSTDMT_freeCCtxPool(srcPool);
+        return ZSTDMT_createCCtxPool(nbWorkers, cMem);
+    }
+}
+
+/* only works during initialization phase, not during compression */
+static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
+{
+    ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
+    {   unsigned const nbWorkers = cctxPool->totalCCtx;
+        size_t const poolSize = sizeof(*cctxPool)
+                                + (nbWorkers-1) * sizeof(ZSTD_CCtx*);
+        unsigned u;
+        size_t totalCCtxSize = 0;
+        for (u=0; u<nbWorkers; u++) {
+            totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]);
+        }
+        ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
+        assert(nbWorkers > 0);
+        return poolSize + totalCCtxSize;
+    }
+}
+
+static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
+{
+    DEBUGLOG(5, "ZSTDMT_getCCtx");
+    ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
+    if (cctxPool->availCCtx) {
+        cctxPool->availCCtx--;
+        {   ZSTD_CCtx* const cctx = cctxPool->cctx[cctxPool->availCCtx];
+            ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
+            return cctx;
+    }   }
+    ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
+    DEBUGLOG(5, "create one more CCtx");
+    return ZSTD_createCCtx_advanced(cctxPool->cMem);   /* note : can be NULL, when creation fails ! */
+}
+
+static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
+{
+    if (cctx==NULL) return;   /* compatibility with release on NULL */
+    ZSTD_pthread_mutex_lock(&pool->poolMutex);
+    if (pool->availCCtx < pool->totalCCtx)
+        pool->cctx[pool->availCCtx++] = cctx;
+    else {
+        /* pool overflow : should not happen, since totalCCtx==nbWorkers */
+        DEBUGLOG(4, "CCtx pool overflow : free cctx");
+        ZSTD_freeCCtx(cctx);
+    }
+    ZSTD_pthread_mutex_unlock(&pool->poolMutex);
+}
+
+/* ====   Serial State   ==== */
+
+typedef struct {
+    void const* start;
+    size_t size;
+} range_t;
+
+typedef struct {
+    /* All variables in the struct are protected by mutex. */
+    ZSTD_pthread_mutex_t mutex;
+    ZSTD_pthread_cond_t cond;
+    ZSTD_CCtx_params params;
+    ldmState_t ldmState;
+    XXH64_state_t xxhState;
+    unsigned nextJobID;
+    /* Protects ldmWindow.
+     * Must be acquired after the main mutex when acquiring both.
+     */
+    ZSTD_pthread_mutex_t ldmWindowMutex;
+    ZSTD_pthread_cond_t ldmWindowCond;  /* Signaled when ldmWindow is udpated */
+    ZSTD_window_t ldmWindow;  /* A thread-safe copy of ldmState.window */
+} serialState_t;
+
+static int ZSTDMT_serialState_reset(serialState_t* serialState, ZSTDMT_seqPool* seqPool, ZSTD_CCtx_params params, size_t jobSize)
+{
+    /* Adjust parameters */
+    if (params.ldmParams.enableLdm) {
+        DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10);
+        ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
+        assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
+        assert(params.ldmParams.hashRateLog < 32);
+        serialState->ldmState.hashPower =
+                ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+    } else {
+        memset(&params.ldmParams, 0, sizeof(params.ldmParams));
+    }
+    serialState->nextJobID = 0;
+    if (params.fParams.checksumFlag)
+        XXH64_reset(&serialState->xxhState, 0);
+    if (params.ldmParams.enableLdm) {
+        ZSTD_customMem cMem = params.customMem;
+        unsigned const hashLog = params.ldmParams.hashLog;
+        size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
+        unsigned const bucketLog =
+            params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
+        size_t const bucketSize = (size_t)1 << bucketLog;
+        unsigned const prevBucketLog =
+            serialState->params.ldmParams.hashLog -
+            serialState->params.ldmParams.bucketSizeLog;
+        /* Size the seq pool tables */
+        ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize));
+        /* Reset the window */
+        ZSTD_window_clear(&serialState->ldmState.window);
+        serialState->ldmWindow = serialState->ldmState.window;
+        /* Resize tables and output space if necessary. */
+        if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) {
+            ZSTD_free(serialState->ldmState.hashTable, cMem);
+            serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_malloc(hashSize, cMem);
+        }
+        if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) {
+            ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
+            serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_malloc(bucketSize, cMem);
+        }
+        if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets)
+            return 1;
+        /* Zero the tables */
+        memset(serialState->ldmState.hashTable, 0, hashSize);
+        memset(serialState->ldmState.bucketOffsets, 0, bucketSize);
+    }
+    serialState->params = params;
+    serialState->params.jobSize = (U32)jobSize;
+    return 0;
+}
+
+static int ZSTDMT_serialState_init(serialState_t* serialState)
+{
+    int initError = 0;
+    memset(serialState, 0, sizeof(*serialState));
+    initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL);
+    initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL);
+    initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL);
+    initError |= ZSTD_pthread_cond_init(&serialState->ldmWindowCond, NULL);
+    return initError;
+}
+
+static void ZSTDMT_serialState_free(serialState_t* serialState)
+{
+    ZSTD_customMem cMem = serialState->params.customMem;
+    ZSTD_pthread_mutex_destroy(&serialState->mutex);
+    ZSTD_pthread_cond_destroy(&serialState->cond);
+    ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex);
+    ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond);
+    ZSTD_free(serialState->ldmState.hashTable, cMem);
+    ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
+}
+
+static void ZSTDMT_serialState_update(serialState_t* serialState,
+                                      ZSTD_CCtx* jobCCtx, rawSeqStore_t seqStore,
+                                      range_t src, unsigned jobID)
+{
+    /* Wait for our turn */
+    ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
+    while (serialState->nextJobID < jobID) {
+        DEBUGLOG(5, "wait for serialState->cond");
+        ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex);
+    }
+    /* A future job may error and skip our job */
+    if (serialState->nextJobID == jobID) {
+        /* It is now our turn, do any processing necessary */
+        if (serialState->params.ldmParams.enableLdm) {
+            size_t error;
+            assert(seqStore.seq != NULL && seqStore.pos == 0 &&
+                   seqStore.size == 0 && seqStore.capacity > 0);
+            assert(src.size <= serialState->params.jobSize);
+            ZSTD_window_update(&serialState->ldmState.window, src.start, src.size);
+            error = ZSTD_ldm_generateSequences(
+                &serialState->ldmState, &seqStore,
+                &serialState->params.ldmParams, src.start, src.size);
+            /* We provide a large enough buffer to never fail. */
+            assert(!ZSTD_isError(error)); (void)error;
+            /* Update ldmWindow to match the ldmState.window and signal the main
+             * thread if it is waiting for a buffer.
+             */
+            ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
+            serialState->ldmWindow = serialState->ldmState.window;
+            ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
+            ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
+        }
+        if (serialState->params.fParams.checksumFlag && src.size > 0)
+            XXH64_update(&serialState->xxhState, src.start, src.size);
+    }
+    /* Now it is the next jobs turn */
+    serialState->nextJobID++;
+    ZSTD_pthread_cond_broadcast(&serialState->cond);
+    ZSTD_pthread_mutex_unlock(&serialState->mutex);
+
+    if (seqStore.size > 0) {
+        size_t const err = ZSTD_referenceExternalSequences(
+            jobCCtx, seqStore.seq, seqStore.size);
+        assert(serialState->params.ldmParams.enableLdm);
+        assert(!ZSTD_isError(err));
+        (void)err;
+    }
+}
+
+static void ZSTDMT_serialState_ensureFinished(serialState_t* serialState,
+                                              unsigned jobID, size_t cSize)
+{
+    ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex);
+    if (serialState->nextJobID <= jobID) {
+        assert(ZSTD_isError(cSize)); (void)cSize;
+        DEBUGLOG(5, "Skipping past job %u because of error", jobID);
+        serialState->nextJobID = jobID + 1;
+        ZSTD_pthread_cond_broadcast(&serialState->cond);
+
+        ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
+        ZSTD_window_clear(&serialState->ldmWindow);
+        ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
+        ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
+    }
+    ZSTD_pthread_mutex_unlock(&serialState->mutex);
+
+}
+
+
+/* ------------------------------------------ */
+/* =====          Worker thread         ===== */
+/* ------------------------------------------ */
+
+static const range_t kNullRange = { NULL, 0 };
+
+typedef struct {
+    size_t   consumed;                   /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx */
+    size_t   cSize;                      /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx, then set0 by mtctx */
+    ZSTD_pthread_mutex_t job_mutex;      /* Thread-safe - used by mtctx and worker */
+    ZSTD_pthread_cond_t job_cond;        /* Thread-safe - used by mtctx and worker */
+    ZSTDMT_CCtxPool* cctxPool;           /* Thread-safe - used by mtctx and (all) workers */
+    ZSTDMT_bufferPool* bufPool;          /* Thread-safe - used by mtctx and (all) workers */
+    ZSTDMT_seqPool* seqPool;             /* Thread-safe - used by mtctx and (all) workers */
+    serialState_t* serial;               /* Thread-safe - used by mtctx and (all) workers */
+    buffer_t dstBuff;                    /* set by worker (or mtctx), then read by worker & mtctx, then modified by mtctx => no barrier */
+    range_t prefix;                      /* set by mtctx, then read by worker & mtctx => no barrier */
+    range_t src;                         /* set by mtctx, then read by worker & mtctx => no barrier */
+    unsigned jobID;                      /* set by mtctx, then read by worker => no barrier */
+    unsigned firstJob;                   /* set by mtctx, then read by worker => no barrier */
+    unsigned lastJob;                    /* set by mtctx, then read by worker => no barrier */
+    ZSTD_CCtx_params params;             /* set by mtctx, then read by worker => no barrier */
+    const ZSTD_CDict* cdict;             /* set by mtctx, then read by worker => no barrier */
+    unsigned long long fullFrameSize;    /* set by mtctx, then read by worker => no barrier */
+    size_t   dstFlushed;                 /* used only by mtctx */
+    unsigned frameChecksumNeeded;        /* used only by mtctx */
+} ZSTDMT_jobDescription;
+
+#define JOB_ERROR(e) {                          \
+    ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);   \
+    job->cSize = e;                             \
+    ZSTD_pthread_mutex_unlock(&job->job_mutex); \
+    goto _endJob;                               \
+}
+
+/* ZSTDMT_compressionJob() is a POOL_function type */
+static void ZSTDMT_compressionJob(void* jobDescription)
+{
+    ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
+    ZSTD_CCtx_params jobParams = job->params;   /* do not modify job->params ! copy it, modify the copy */
+    ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool);
+    rawSeqStore_t rawSeqStore = ZSTDMT_getSeq(job->seqPool);
+    buffer_t dstBuff = job->dstBuff;
+    size_t lastCBlockSize = 0;
+
+    /* ressources */
+    if (cctx==NULL) JOB_ERROR(ERROR(memory_allocation));
+    if (dstBuff.start == NULL) {   /* streaming job : doesn't provide a dstBuffer */
+        dstBuff = ZSTDMT_getBuffer(job->bufPool);
+        if (dstBuff.start==NULL) JOB_ERROR(ERROR(memory_allocation));
+        job->dstBuff = dstBuff;   /* this value can be read in ZSTDMT_flush, when it copies the whole job */
+    }
+    if (jobParams.ldmParams.enableLdm && rawSeqStore.seq == NULL)
+        JOB_ERROR(ERROR(memory_allocation));
+
+    /* Don't compute the checksum for chunks, since we compute it externally,
+     * but write it in the header.
+     */
+    if (job->jobID != 0) jobParams.fParams.checksumFlag = 0;
+    /* Don't run LDM for the chunks, since we handle it externally */
+    jobParams.ldmParams.enableLdm = 0;
+
+
+    /* init */
+    if (job->cdict) {
+        size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, job->cdict, jobParams, job->fullFrameSize);
+        assert(job->firstJob);  /* only allowed for first job */
+        if (ZSTD_isError(initError)) JOB_ERROR(initError);
+    } else {  /* srcStart points at reloaded section */
+        U64 const pledgedSrcSize = job->firstJob ? job->fullFrameSize : job->src.size;
+        {   size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob);
+            if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError);
+        }
+        {   size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
+                                        job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
+                                        ZSTD_dtlm_fast,
+                                        NULL, /*cdict*/
+                                        jobParams, pledgedSrcSize);
+            if (ZSTD_isError(initError)) JOB_ERROR(initError);
+    }   }
+
+    /* Perform serial step as early as possible, but after CCtx initialization */
+    ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID);
+
+    if (!job->firstJob) {  /* flush and overwrite frame header when it's not first job */
+        size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0);
+        if (ZSTD_isError(hSize)) JOB_ERROR(hSize);
+        DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize);
+        ZSTD_invalidateRepCodes(cctx);
+    }
+
+    /* compress */
+    {   size_t const chunkSize = 4*ZSTD_BLOCKSIZE_MAX;
+        int const nbChunks = (int)((job->src.size + (chunkSize-1)) / chunkSize);
+        const BYTE* ip = (const BYTE*) job->src.start;
+        BYTE* const ostart = (BYTE*)dstBuff.start;
+        BYTE* op = ostart;
+        BYTE* oend = op + dstBuff.capacity;
+        int chunkNb;
+        if (sizeof(size_t) > sizeof(int)) assert(job->src.size < ((size_t)INT_MAX) * chunkSize);   /* check overflow */
+        DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks);
+        assert(job->cSize == 0);
+        for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) {
+            size_t const cSize = ZSTD_compressContinue(cctx, op, oend-op, ip, chunkSize);
+            if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
+            ip += chunkSize;
+            op += cSize; assert(op < oend);
+            /* stats */
+            ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
+            job->cSize += cSize;
+            job->consumed = chunkSize * chunkNb;
+            DEBUGLOG(5, "ZSTDMT_compressionJob: compress new block : cSize==%u bytes (total: %u)",
+                        (U32)cSize, (U32)job->cSize);
+            ZSTD_pthread_cond_signal(&job->job_cond);   /* warns some more data is ready to be flushed */
+            ZSTD_pthread_mutex_unlock(&job->job_mutex);
+        }
+        /* last block */
+        assert(chunkSize > 0);
+        assert((chunkSize & (chunkSize - 1)) == 0);  /* chunkSize must be power of 2 for mask==(chunkSize-1) to work */
+        if ((nbChunks > 0) | job->lastJob /*must output a "last block" flag*/ ) {
+            size_t const lastBlockSize1 = job->src.size & (chunkSize-1);
+            size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1;
+            size_t const cSize = (job->lastJob) ?
+                 ZSTD_compressEnd     (cctx, op, oend-op, ip, lastBlockSize) :
+                 ZSTD_compressContinue(cctx, op, oend-op, ip, lastBlockSize);
+            if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
+            lastCBlockSize = cSize;
+    }   }
+
+_endJob:
+    ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize);
+    if (job->prefix.size > 0)
+        DEBUGLOG(5, "Finished with prefix: %zx", (size_t)job->prefix.start);
+    DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start);
+    /* release resources */
+    ZSTDMT_releaseSeq(job->seqPool, rawSeqStore);
+    ZSTDMT_releaseCCtx(job->cctxPool, cctx);
+    /* report */
+    ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
+    if (ZSTD_isError(job->cSize)) assert(lastCBlockSize == 0);
+    job->cSize += lastCBlockSize;
+    job->consumed = job->src.size;  /* when job->consumed == job->src.size , compression job is presumed completed */
+    ZSTD_pthread_cond_signal(&job->job_cond);
+    ZSTD_pthread_mutex_unlock(&job->job_mutex);
+}
+
+
+/* ------------------------------------------ */
+/* =====   Multi-threaded compression   ===== */
+/* ------------------------------------------ */
+
+typedef struct {
+    range_t prefix;         /* read-only non-owned prefix buffer */
+    buffer_t buffer;
+    size_t filled;
+} inBuff_t;
+
+typedef struct {
+  BYTE* buffer;     /* The round input buffer. All jobs get references
+                     * to pieces of the buffer. ZSTDMT_tryGetInputRange()
+                     * handles handing out job input buffers, and makes
+                     * sure it doesn't overlap with any pieces still in use.
+                     */
+  size_t capacity;  /* The capacity of buffer. */
+  size_t pos;       /* The position of the current inBuff in the round
+                     * buffer. Updated past the end if the inBuff once
+                     * the inBuff is sent to the worker thread.
+                     * pos <= capacity.
+                     */
+} roundBuff_t;
+
+static const roundBuff_t kNullRoundBuff = {NULL, 0, 0};
+
+#define RSYNC_LENGTH 32
+
+typedef struct {
+  U64 hash;
+  U64 hitMask;
+  U64 primePower;
+} rsyncState_t;
+
+struct ZSTDMT_CCtx_s {
+    POOL_ctx* factory;
+    ZSTDMT_jobDescription* jobs;
+    ZSTDMT_bufferPool* bufPool;
+    ZSTDMT_CCtxPool* cctxPool;
+    ZSTDMT_seqPool* seqPool;
+    ZSTD_CCtx_params params;
+    size_t targetSectionSize;
+    size_t targetPrefixSize;
+    int jobReady;        /* 1 => one job is already prepared, but pool has shortage of workers. Don't create a new job. */
+    inBuff_t inBuff;
+    roundBuff_t roundBuff;
+    serialState_t serial;
+    rsyncState_t rsync;
+    unsigned singleBlockingThread;
+    unsigned jobIDMask;
+    unsigned doneJobID;
+    unsigned nextJobID;
+    unsigned frameEnded;
+    unsigned allJobsCompleted;
+    unsigned long long frameContentSize;
+    unsigned long long consumed;
+    unsigned long long produced;
+    ZSTD_customMem cMem;
+    ZSTD_CDict* cdictLocal;
+    const ZSTD_CDict* cdict;
+};
+
+static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem)
+{
+    U32 jobNb;
+    if (jobTable == NULL) return;
+    for (jobNb=0; jobNb<nbJobs; jobNb++) {
+        ZSTD_pthread_mutex_destroy(&jobTable[jobNb].job_mutex);
+        ZSTD_pthread_cond_destroy(&jobTable[jobNb].job_cond);
+    }
+    ZSTD_free(jobTable, cMem);
+}
+
+/* ZSTDMT_allocJobsTable()
+ * allocate and init a job table.
+ * update *nbJobsPtr to next power of 2 value, as size of table */
+static ZSTDMT_jobDescription* ZSTDMT_createJobsTable(U32* nbJobsPtr, ZSTD_customMem cMem)
+{
+    U32 const nbJobsLog2 = ZSTD_highbit32(*nbJobsPtr) + 1;
+    U32 const nbJobs = 1 << nbJobsLog2;
+    U32 jobNb;
+    ZSTDMT_jobDescription* const jobTable = (ZSTDMT_jobDescription*)
+                ZSTD_calloc(nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
+    int initError = 0;
+    if (jobTable==NULL) return NULL;
+    *nbJobsPtr = nbJobs;
+    for (jobNb=0; jobNb<nbJobs; jobNb++) {
+        initError |= ZSTD_pthread_mutex_init(&jobTable[jobNb].job_mutex, NULL);
+        initError |= ZSTD_pthread_cond_init(&jobTable[jobNb].job_cond, NULL);
+    }
+    if (initError != 0) {
+        ZSTDMT_freeJobsTable(jobTable, nbJobs, cMem);
+        return NULL;
+    }
+    return jobTable;
+}
+
+static size_t ZSTDMT_expandJobsTable (ZSTDMT_CCtx* mtctx, U32 nbWorkers) {
+    U32 nbJobs = nbWorkers + 2;
+    if (nbJobs > mtctx->jobIDMask+1) {  /* need more job capacity */
+        ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
+        mtctx->jobIDMask = 0;
+        mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, mtctx->cMem);
+        if (mtctx->jobs==NULL) return ERROR(memory_allocation);
+        assert((nbJobs != 0) && ((nbJobs & (nbJobs - 1)) == 0));  /* ensure nbJobs is a power of 2 */
+        mtctx->jobIDMask = nbJobs - 1;
+    }
+    return 0;
+}
+
+
+/* ZSTDMT_CCtxParam_setNbWorkers():
+ * Internal use only */
+size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers)
+{
+    if (nbWorkers > ZSTDMT_NBWORKERS_MAX) nbWorkers = ZSTDMT_NBWORKERS_MAX;
+    params->nbWorkers = nbWorkers;
+    params->overlapLog = ZSTDMT_OVERLAPLOG_DEFAULT;
+    params->jobSize = 0;
+    return nbWorkers;
+}
+
+ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem)
+{
+    ZSTDMT_CCtx* mtctx;
+    U32 nbJobs = nbWorkers + 2;
+    int initError;
+    DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbWorkers = %u)", nbWorkers);
+
+    if (nbWorkers < 1) return NULL;
+    nbWorkers = MIN(nbWorkers , ZSTDMT_NBWORKERS_MAX);
+    if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL))
+        /* invalid custom allocator */
+        return NULL;
+
+    mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
+    if (!mtctx) return NULL;
+    ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
+    mtctx->cMem = cMem;
+    mtctx->allJobsCompleted = 1;
+    mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem);
+    mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem);
+    assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0);  /* ensure nbJobs is a power of 2 */
+    mtctx->jobIDMask = nbJobs - 1;
+    mtctx->bufPool = ZSTDMT_createBufferPool(nbWorkers, cMem);
+    mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem);
+    mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem);
+    initError = ZSTDMT_serialState_init(&mtctx->serial);
+    mtctx->roundBuff = kNullRoundBuff;
+    if (!mtctx->factory | !mtctx->jobs | !mtctx->bufPool | !mtctx->cctxPool | !mtctx->seqPool | initError) {
+        ZSTDMT_freeCCtx(mtctx);
+        return NULL;
+    }
+    DEBUGLOG(3, "mt_cctx created, for %u threads", nbWorkers);
+    return mtctx;
+}
+
+ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers)
+{
+    return ZSTDMT_createCCtx_advanced(nbWorkers, ZSTD_defaultCMem);
+}
+
+
+/* ZSTDMT_releaseAllJobResources() :
+ * note : ensure all workers are killed first ! */
+static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
+{
+    unsigned jobID;
+    DEBUGLOG(3, "ZSTDMT_releaseAllJobResources");
+    for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) {
+        DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start);
+        ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
+        mtctx->jobs[jobID].dstBuff = g_nullBuffer;
+        mtctx->jobs[jobID].cSize = 0;
+    }
+    memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription));
+    mtctx->inBuff.buffer = g_nullBuffer;
+    mtctx->inBuff.filled = 0;
+    mtctx->allJobsCompleted = 1;
+}
+
+static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx)
+{
+    DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
+    while (mtctx->doneJobID < mtctx->nextJobID) {
+        unsigned const jobID = mtctx->doneJobID & mtctx->jobIDMask;
+        ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
+        while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
+            DEBUGLOG(4, "waiting for jobCompleted signal from job %u", mtctx->doneJobID);   /* we want to block when waiting for data to flush */
+            ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
+        }
+        ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
+        mtctx->doneJobID++;
+    }
+}
+
+size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
+{
+    if (mtctx==NULL) return 0;   /* compatible with free on NULL */
+    POOL_free(mtctx->factory);   /* stop and free worker threads */
+    ZSTDMT_releaseAllJobResources(mtctx);  /* release job resources into pools first */
+    ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
+    ZSTDMT_freeBufferPool(mtctx->bufPool);
+    ZSTDMT_freeCCtxPool(mtctx->cctxPool);
+    ZSTDMT_freeSeqPool(mtctx->seqPool);
+    ZSTDMT_serialState_free(&mtctx->serial);
+    ZSTD_freeCDict(mtctx->cdictLocal);
+    if (mtctx->roundBuff.buffer)
+        ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
+    ZSTD_free(mtctx, mtctx->cMem);
+    return 0;
+}
+
+size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
+{
+    if (mtctx == NULL) return 0;   /* supports sizeof NULL */
+    return sizeof(*mtctx)
+            + POOL_sizeof(mtctx->factory)
+            + ZSTDMT_sizeof_bufferPool(mtctx->bufPool)
+            + (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription)
+            + ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool)
+            + ZSTDMT_sizeof_seqPool(mtctx->seqPool)
+            + ZSTD_sizeof_CDict(mtctx->cdictLocal)
+            + mtctx->roundBuff.capacity;
+}
+
+/* Internal only */
+size_t
+ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params,
+                                   ZSTDMT_parameter parameter,
+                                   int value)
+{
+    DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter");
+    switch(parameter)
+    {
+    case ZSTDMT_p_jobSize :
+        DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %i", value);
+        if ( value != 0  /* default */
+          && value < ZSTDMT_JOBSIZE_MIN)
+            value = ZSTDMT_JOBSIZE_MIN;
+        assert(value >= 0);
+        if (value > ZSTDMT_JOBSIZE_MAX) value = ZSTDMT_JOBSIZE_MAX;
+        params->jobSize = value;
+        return value;
+
+    case ZSTDMT_p_overlapLog :
+        DEBUGLOG(4, "ZSTDMT_p_overlapLog : %i", value);
+        if (value < ZSTD_OVERLAPLOG_MIN) value = ZSTD_OVERLAPLOG_MIN;
+        if (value > ZSTD_OVERLAPLOG_MAX) value = ZSTD_OVERLAPLOG_MAX;
+        params->overlapLog = value;
+        return value;
+
+    case ZSTDMT_p_rsyncable :
+        value = (value != 0);
+        params->rsyncable = value;
+        return value;
+
+    default :
+        return ERROR(parameter_unsupported);
+    }
+}
+
+size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value)
+{
+    DEBUGLOG(4, "ZSTDMT_setMTCtxParameter");
+    return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
+}
+
+size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value)
+{
+    switch (parameter) {
+    case ZSTDMT_p_jobSize:
+        assert(mtctx->params.jobSize <= INT_MAX);
+        *value = (int)(mtctx->params.jobSize);
+        break;
+    case ZSTDMT_p_overlapLog:
+        *value = mtctx->params.overlapLog;
+        break;
+    case ZSTDMT_p_rsyncable:
+        *value = mtctx->params.rsyncable;
+        break;
+    default:
+        return ERROR(parameter_unsupported);
+    }
+    return 0;
+}
+
+/* Sets parameters relevant to the compression job,
+ * initializing others to default values. */
+static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(ZSTD_CCtx_params const params)
+{
+    ZSTD_CCtx_params jobParams;
+    memset(&jobParams, 0, sizeof(jobParams));
+
+    jobParams.cParams = params.cParams;
+    jobParams.fParams = params.fParams;
+    jobParams.compressionLevel = params.compressionLevel;
+
+    return jobParams;
+}
+
+
+/* ZSTDMT_resize() :
+ * @return : error code if fails, 0 on success */
+static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers)
+{
+    if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation);
+    CHECK_F( ZSTDMT_expandJobsTable(mtctx, nbWorkers) );
+    mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, nbWorkers);
+    if (mtctx->bufPool == NULL) return ERROR(memory_allocation);
+    mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers);
+    if (mtctx->cctxPool == NULL) return ERROR(memory_allocation);
+    mtctx->seqPool = ZSTDMT_expandSeqPool(mtctx->seqPool, nbWorkers);
+    if (mtctx->seqPool == NULL) return ERROR(memory_allocation);
+    ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
+    return 0;
+}
+
+
+/*! ZSTDMT_updateCParams_whileCompressing() :
+ *  Updates a selected set of compression parameters, remaining compatible with currently active frame.
+ *  New parameters will be applied to next compression job. */
+void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams)
+{
+    U32 const saved_wlog = mtctx->params.cParams.windowLog;   /* Do not modify windowLog while compressing */
+    int const compressionLevel = cctxParams->compressionLevel;
+    DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)",
+                compressionLevel);
+    mtctx->params.compressionLevel = compressionLevel;
+    {   ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, 0, 0);
+        cParams.windowLog = saved_wlog;
+        mtctx->params.cParams = cParams;
+    }
+}
+
+/* ZSTDMT_getFrameProgression():
+ * tells how much data has been consumed (input) and produced (output) for current frame.
+ * able to count progression inside worker threads.
+ * Note : mutex will be acquired during statistics collection inside workers. */
+ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
+{
+    ZSTD_frameProgression fps;
+    DEBUGLOG(5, "ZSTDMT_getFrameProgression");
+    fps.ingested = mtctx->consumed + mtctx->inBuff.filled;
+    fps.consumed = mtctx->consumed;
+    fps.produced = fps.flushed = mtctx->produced;
+    fps.currentJobID = mtctx->nextJobID;
+    fps.nbActiveWorkers = 0;
+    {   unsigned jobNb;
+        unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
+        DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)",
+                    mtctx->doneJobID, lastJobNb, mtctx->jobReady)
+        for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) {
+            unsigned const wJobID = jobNb & mtctx->jobIDMask;
+            ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID];
+            ZSTD_pthread_mutex_lock(&jobPtr->job_mutex);
+            {   size_t const cResult = jobPtr->cSize;
+                size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
+                size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed;
+                assert(flushed <= produced);
+                fps.ingested += jobPtr->src.size;
+                fps.consumed += jobPtr->consumed;
+                fps.produced += produced;
+                fps.flushed  += flushed;
+                fps.nbActiveWorkers += (jobPtr->consumed < jobPtr->src.size);
+            }
+            ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+        }
+    }
+    return fps;
+}
+
+
+size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx)
+{
+    size_t toFlush;
+    unsigned const jobID = mtctx->doneJobID;
+    assert(jobID <= mtctx->nextJobID);
+    if (jobID == mtctx->nextJobID) return 0;   /* no active job => nothing to flush */
+
+    /* look into oldest non-fully-flushed job */
+    {   unsigned const wJobID = jobID & mtctx->jobIDMask;
+        ZSTDMT_jobDescription* const jobPtr = &mtctx->jobs[wJobID];
+        ZSTD_pthread_mutex_lock(&jobPtr->job_mutex);
+        {   size_t const cResult = jobPtr->cSize;
+            size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
+            size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed;
+            assert(flushed <= produced);
+            toFlush = produced - flushed;
+            if (toFlush==0 && (jobPtr->consumed >= jobPtr->src.size)) {
+                /* doneJobID is not-fully-flushed, but toFlush==0 : doneJobID should be compressing some more data */
+                assert(jobPtr->consumed < jobPtr->src.size);
+            }
+        }
+        ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+    }
+
+    return toFlush;
+}
+
+
+/* ------------------------------------------ */
+/* =====   Multi-threaded compression   ===== */
+/* ------------------------------------------ */
+
+static unsigned ZSTDMT_computeTargetJobLog(ZSTD_CCtx_params const params)
+{
+    if (params.ldmParams.enableLdm)
+        /* In Long Range Mode, the windowLog is typically oversized.
+         * In which case, it's preferable to determine the jobSize
+         * based on chainLog instead. */
+        return MAX(21, params.cParams.chainLog + 4);
+    return MAX(20, params.cParams.windowLog + 2);
+}
+
+static int ZSTDMT_overlapLog_default(ZSTD_strategy strat)
+{
+    switch(strat)
+    {
+        case ZSTD_btultra2:
+            return 9;
+        case ZSTD_btultra:
+        case ZSTD_btopt:
+            return 8;
+        case ZSTD_btlazy2:
+        case ZSTD_lazy2:
+            return 7;
+        case ZSTD_lazy:
+        case ZSTD_greedy:
+        case ZSTD_dfast:
+        case ZSTD_fast:
+        default:;
+    }
+    return 6;
+}
+
+static int ZSTDMT_overlapLog(int ovlog, ZSTD_strategy strat)
+{
+    assert(0 <= ovlog && ovlog <= 9);
+    if (ovlog == 0) return ZSTDMT_overlapLog_default(strat);
+    return ovlog;
+}
+
+static size_t ZSTDMT_computeOverlapSize(ZSTD_CCtx_params const params)
+{
+    int const overlapRLog = 9 - ZSTDMT_overlapLog(params.overlapLog, params.cParams.strategy);
+    int ovLog = (overlapRLog >= 8) ? 0 : (params.cParams.windowLog - overlapRLog);
+    assert(0 <= overlapRLog && overlapRLog <= 8);
+    if (params.ldmParams.enableLdm) {
+        /* In Long Range Mode, the windowLog is typically oversized.
+         * In which case, it's preferable to determine the jobSize
+         * based on chainLog instead.
+         * Then, ovLog becomes a fraction of the jobSize, rather than windowSize */
+        ovLog = MIN(params.cParams.windowLog, ZSTDMT_computeTargetJobLog(params) - 2)
+                - overlapRLog;
+    }
+    assert(0 <= ovLog && ovLog <= 30);
+    DEBUGLOG(4, "overlapLog : %i", params.overlapLog);
+    DEBUGLOG(4, "overlap size : %i", 1 << ovLog);
+    return (ovLog==0) ? 0 : (size_t)1 << ovLog;
+}
+
+static unsigned
+ZSTDMT_computeNbJobs(ZSTD_CCtx_params params, size_t srcSize, unsigned nbWorkers)
+{
+    assert(nbWorkers>0);
+    {   size_t const jobSizeTarget = (size_t)1 << ZSTDMT_computeTargetJobLog(params);
+        size_t const jobMaxSize = jobSizeTarget << 2;
+        size_t const passSizeMax = jobMaxSize * nbWorkers;
+        unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
+        unsigned const nbJobsLarge = multiplier * nbWorkers;
+        unsigned const nbJobsMax = (unsigned)(srcSize / jobSizeTarget) + 1;
+        unsigned const nbJobsSmall = MIN(nbJobsMax, nbWorkers);
+        return (multiplier>1) ? nbJobsLarge : nbJobsSmall;
+}   }
+
+/* ZSTDMT_compress_advanced_internal() :
+ * This is a blocking function : it will only give back control to caller after finishing its compression job.
+ */
+static size_t ZSTDMT_compress_advanced_internal(
+                ZSTDMT_CCtx* mtctx,
+                void* dst, size_t dstCapacity,
+          const void* src, size_t srcSize,
+          const ZSTD_CDict* cdict,
+                ZSTD_CCtx_params params)
+{
+    ZSTD_CCtx_params const jobParams = ZSTDMT_initJobCCtxParams(params);
+    size_t const overlapSize = ZSTDMT_computeOverlapSize(params);
+    unsigned const nbJobs = ZSTDMT_computeNbJobs(params, srcSize, params.nbWorkers);
+    size_t const proposedJobSize = (srcSize + (nbJobs-1)) / nbJobs;
+    size_t const avgJobSize = (((proposedJobSize-1) & 0x1FFFF) < 0x7FFF) ? proposedJobSize + 0xFFFF : proposedJobSize;   /* avoid too small last block */
+    const char* const srcStart = (const char*)src;
+    size_t remainingSrcSize = srcSize;
+    unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbJobs : (unsigned)(dstCapacity / ZSTD_compressBound(avgJobSize));  /* presumes avgJobSize >= 256 KB, which should be the case */
+    size_t frameStartPos = 0, dstBufferPos = 0;
+    assert(jobParams.nbWorkers == 0);
+    assert(mtctx->cctxPool->totalCCtx == params.nbWorkers);
+
+    params.jobSize = (U32)avgJobSize;
+    DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbJobs=%2u (rawSize=%u bytes; fixedSize=%u) ",
+                nbJobs, (U32)proposedJobSize, (U32)avgJobSize);
+
+    if ((nbJobs==1) | (params.nbWorkers<=1)) {   /* fallback to single-thread mode : this is a blocking invocation anyway */
+        ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
+        DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: fallback to single-thread mode");
+        if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
+        return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, jobParams);
+    }
+
+    assert(avgJobSize >= 256 KB);  /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */
+    ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) );
+    if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, avgJobSize))
+        return ERROR(memory_allocation);
+
+    CHECK_F( ZSTDMT_expandJobsTable(mtctx, nbJobs) );  /* only expands if necessary */
+
+    {   unsigned u;
+        for (u=0; u<nbJobs; u++) {
+            size_t const jobSize = MIN(remainingSrcSize, avgJobSize);
+            size_t const dstBufferCapacity = ZSTD_compressBound(jobSize);
+            buffer_t const dstAsBuffer = { (char*)dst + dstBufferPos, dstBufferCapacity };
+            buffer_t const dstBuffer = u < compressWithinDst ? dstAsBuffer : g_nullBuffer;
+            size_t dictSize = u ? overlapSize : 0;
+
+            mtctx->jobs[u].prefix.start = srcStart + frameStartPos - dictSize;
+            mtctx->jobs[u].prefix.size = dictSize;
+            mtctx->jobs[u].src.start = srcStart + frameStartPos;
+            mtctx->jobs[u].src.size = jobSize; assert(jobSize > 0);  /* avoid job.src.size == 0 */
+            mtctx->jobs[u].consumed = 0;
+            mtctx->jobs[u].cSize = 0;
+            mtctx->jobs[u].cdict = (u==0) ? cdict : NULL;
+            mtctx->jobs[u].fullFrameSize = srcSize;
+            mtctx->jobs[u].params = jobParams;
+            /* do not calculate checksum within sections, but write it in header for first section */
+            mtctx->jobs[u].dstBuff = dstBuffer;
+            mtctx->jobs[u].cctxPool = mtctx->cctxPool;
+            mtctx->jobs[u].bufPool = mtctx->bufPool;
+            mtctx->jobs[u].seqPool = mtctx->seqPool;
+            mtctx->jobs[u].serial = &mtctx->serial;
+            mtctx->jobs[u].jobID = u;
+            mtctx->jobs[u].firstJob = (u==0);
+            mtctx->jobs[u].lastJob = (u==nbJobs-1);
+
+            DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u  (%u bytes)", u, (U32)jobSize);
+            DEBUG_PRINTHEX(6, mtctx->jobs[u].prefix.start, 12);
+            POOL_add(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[u]);
+
+            frameStartPos += jobSize;
+            dstBufferPos += dstBufferCapacity;
+            remainingSrcSize -= jobSize;
+    }   }
+
+    /* collect result */
+    {   size_t error = 0, dstPos = 0;
+        unsigned jobID;
+        for (jobID=0; jobID<nbJobs; jobID++) {
+            DEBUGLOG(5, "waiting for job %u ", jobID);
+            ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
+            while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
+                DEBUGLOG(5, "waiting for jobCompleted signal from job %u", jobID);
+                ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
+            }
+            ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
+            DEBUGLOG(5, "ready to write job %u ", jobID);
+
+            {   size_t const cSize = mtctx->jobs[jobID].cSize;
+                if (ZSTD_isError(cSize)) error = cSize;
+                if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall);
+                if (jobID) {   /* note : job 0 is written directly at dst, which is correct position */
+                    if (!error)
+                        memmove((char*)dst + dstPos, mtctx->jobs[jobID].dstBuff.start, cSize);  /* may overlap when job compressed within dst */
+                    if (jobID >= compressWithinDst) {  /* job compressed into its own buffer, which must be released */
+                        DEBUGLOG(5, "releasing buffer %u>=%u", jobID, compressWithinDst);
+                        ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
+                }   }
+                mtctx->jobs[jobID].dstBuff = g_nullBuffer;
+                mtctx->jobs[jobID].cSize = 0;
+                dstPos += cSize ;
+            }
+        }  /* for (jobID=0; jobID<nbJobs; jobID++) */
+
+        DEBUGLOG(4, "checksumFlag : %u ", params.fParams.checksumFlag);
+        if (params.fParams.checksumFlag) {
+            U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
+            if (dstPos + 4 > dstCapacity) {
+                error = ERROR(dstSize_tooSmall);
+            } else {
+                DEBUGLOG(4, "writing checksum : %08X \n", checksum);
+                MEM_writeLE32((char*)dst + dstPos, checksum);
+                dstPos += 4;
+        }   }
+
+        if (!error) DEBUGLOG(4, "compressed size : %u  ", (U32)dstPos);
+        return error ? error : dstPos;
+    }
+}
+
+size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
+                                void* dst, size_t dstCapacity,
+                          const void* src, size_t srcSize,
+                          const ZSTD_CDict* cdict,
+                                ZSTD_parameters params,
+                                int overlapLog)
+{
+    ZSTD_CCtx_params cctxParams = mtctx->params;
+    cctxParams.cParams = params.cParams;
+    cctxParams.fParams = params.fParams;
+    assert(ZSTD_OVERLAPLOG_MIN <= overlapLog && overlapLog <= ZSTD_OVERLAPLOG_MAX);
+    cctxParams.overlapLog = overlapLog;
+    return ZSTDMT_compress_advanced_internal(mtctx,
+                                             dst, dstCapacity,
+                                             src, srcSize,
+                                             cdict, cctxParams);
+}
+
+
+size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
+                           void* dst, size_t dstCapacity,
+                     const void* src, size_t srcSize,
+                           int compressionLevel)
+{
+    ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0);
+    int const overlapLog = ZSTDMT_overlapLog_default(params.cParams.strategy);
+    params.fParams.contentSizeFlag = 1;
+    return ZSTDMT_compress_advanced(mtctx, dst, dstCapacity, src, srcSize, NULL, params, overlapLog);
+}
+
+
+/* ====================================== */
+/* =======      Streaming API     ======= */
+/* ====================================== */
+
+size_t ZSTDMT_initCStream_internal(
+        ZSTDMT_CCtx* mtctx,
+        const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
+        const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
+        unsigned long long pledgedSrcSize)
+{
+    DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u, nbWorkers=%u, cctxPool=%u)",
+                (U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx);
+
+    /* params supposed partially fully validated at this point */
+    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+    assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
+
+    /* init */
+    if (params.nbWorkers != mtctx->params.nbWorkers)
+        CHECK_F( ZSTDMT_resize(mtctx, params.nbWorkers) );
+
+    if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN;
+    if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = ZSTDMT_JOBSIZE_MAX;
+
+    mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN);  /* do not trigger multi-threading when srcSize is too small */
+    if (mtctx->singleBlockingThread) {
+        ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(params);
+        DEBUGLOG(5, "ZSTDMT_initCStream_internal: switch to single blocking thread mode");
+        assert(singleThreadParams.nbWorkers == 0);
+        return ZSTD_initCStream_internal(mtctx->cctxPool->cctx[0],
+                                         dict, dictSize, cdict,
+                                         singleThreadParams, pledgedSrcSize);
+    }
+
+    DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers);
+
+    if (mtctx->allJobsCompleted == 0) {   /* previous compression not correctly finished */
+        ZSTDMT_waitForAllJobsCompleted(mtctx);
+        ZSTDMT_releaseAllJobResources(mtctx);
+        mtctx->allJobsCompleted = 1;
+    }
+
+    mtctx->params = params;
+    mtctx->frameContentSize = pledgedSrcSize;
+    if (dict) {
+        ZSTD_freeCDict(mtctx->cdictLocal);
+        mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
+                                                    ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */
+                                                    params.cParams, mtctx->cMem);
+        mtctx->cdict = mtctx->cdictLocal;
+        if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation);
+    } else {
+        ZSTD_freeCDict(mtctx->cdictLocal);
+        mtctx->cdictLocal = NULL;
+        mtctx->cdict = cdict;
+    }
+
+    mtctx->targetPrefixSize = ZSTDMT_computeOverlapSize(params);
+    DEBUGLOG(4, "overlapLog=%i => %u KB", params.overlapLog, (U32)(mtctx->targetPrefixSize>>10));
+    mtctx->targetSectionSize = params.jobSize;
+    if (mtctx->targetSectionSize == 0) {
+        mtctx->targetSectionSize = 1ULL << ZSTDMT_computeTargetJobLog(params);
+    }
+    if (params.rsyncable) {
+        /* Aim for the targetsectionSize as the average job size. */
+        U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20);
+        U32 const rsyncBits = ZSTD_highbit32(jobSizeMB) + 20;
+        assert(jobSizeMB >= 1);
+        DEBUGLOG(4, "rsyncLog = %u", rsyncBits);
+        mtctx->rsync.hash = 0;
+        mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1;
+        mtctx->rsync.primePower = ZSTD_rollingHash_primePower(RSYNC_LENGTH);
+    }
+    if (mtctx->targetSectionSize < mtctx->targetPrefixSize) mtctx->targetSectionSize = mtctx->targetPrefixSize;  /* job size must be >= overlap size */
+    DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(mtctx->targetSectionSize>>10), (U32)params.jobSize);
+    DEBUGLOG(4, "inBuff Size : %u KB", (U32)(mtctx->targetSectionSize>>10));
+    ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize));
+    {
+        /* If ldm is enabled we need windowSize space. */
+        size_t const windowSize = mtctx->params.ldmParams.enableLdm ? (1U << mtctx->params.cParams.windowLog) : 0;
+        /* Two buffers of slack, plus extra space for the overlap
+         * This is the minimum slack that LDM works with. One extra because
+         * flush might waste up to targetSectionSize-1 bytes. Another extra
+         * for the overlap (if > 0), then one to fill which doesn't overlap
+         * with the LDM window.
+         */
+        size_t const nbSlackBuffers = 2 + (mtctx->targetPrefixSize > 0);
+        size_t const slackSize = mtctx->targetSectionSize * nbSlackBuffers;
+        /* Compute the total size, and always have enough slack */
+        size_t const nbWorkers = MAX(mtctx->params.nbWorkers, 1);
+        size_t const sectionsSize = mtctx->targetSectionSize * nbWorkers;
+        size_t const capacity = MAX(windowSize, sectionsSize) + slackSize;
+        if (mtctx->roundBuff.capacity < capacity) {
+            if (mtctx->roundBuff.buffer)
+                ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
+            mtctx->roundBuff.buffer = (BYTE*)ZSTD_malloc(capacity, mtctx->cMem);
+            if (mtctx->roundBuff.buffer == NULL) {
+                mtctx->roundBuff.capacity = 0;
+                return ERROR(memory_allocation);
+            }
+            mtctx->roundBuff.capacity = capacity;
+        }
+    }
+    DEBUGLOG(4, "roundBuff capacity : %u KB", (U32)(mtctx->roundBuff.capacity>>10));
+    mtctx->roundBuff.pos = 0;
+    mtctx->inBuff.buffer = g_nullBuffer;
+    mtctx->inBuff.filled = 0;
+    mtctx->inBuff.prefix = kNullRange;
+    mtctx->doneJobID = 0;
+    mtctx->nextJobID = 0;
+    mtctx->frameEnded = 0;
+    mtctx->allJobsCompleted = 0;
+    mtctx->consumed = 0;
+    mtctx->produced = 0;
+    if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize))
+        return ERROR(memory_allocation);
+    return 0;
+}
+
+size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
+                             const void* dict, size_t dictSize,
+                                   ZSTD_parameters params,
+                                   unsigned long long pledgedSrcSize)
+{
+    ZSTD_CCtx_params cctxParams = mtctx->params;  /* retrieve sticky params */
+    DEBUGLOG(4, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
+    cctxParams.cParams = params.cParams;
+    cctxParams.fParams = params.fParams;
+    return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dct_auto, NULL,
+                                       cctxParams, pledgedSrcSize);
+}
+
+size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
+                               const ZSTD_CDict* cdict,
+                                     ZSTD_frameParameters fParams,
+                                     unsigned long long pledgedSrcSize)
+{
+    ZSTD_CCtx_params cctxParams = mtctx->params;
+    if (cdict==NULL) return ERROR(dictionary_wrong);   /* method incompatible with NULL cdict */
+    cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict);
+    cctxParams.fParams = fParams;
+    return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dct_auto, cdict,
+                                       cctxParams, pledgedSrcSize);
+}
+
+
+/* ZSTDMT_resetCStream() :
+ * pledgedSrcSize can be zero == unknown (for the time being)
+ * prefer using ZSTD_CONTENTSIZE_UNKNOWN,
+ * as `0` might mean "empty" in the future */
+size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize)
+{
+    if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+    return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, 0, mtctx->params,
+                                       pledgedSrcSize);
+}
+
+size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel) {
+    ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+    ZSTD_CCtx_params cctxParams = mtctx->params;   /* retrieve sticky params */
+    DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
+    cctxParams.cParams = params.cParams;
+    cctxParams.fParams = params.fParams;
+    return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+
+/* ZSTDMT_writeLastEmptyBlock()
+ * Write a single empty block with an end-of-frame to finish a frame.
+ * Job must be created from streaming variant.
+ * This function is always successfull if expected conditions are fulfilled.
+ */
+static void ZSTDMT_writeLastEmptyBlock(ZSTDMT_jobDescription* job)
+{
+    assert(job->lastJob == 1);
+    assert(job->src.size == 0);   /* last job is empty -> will be simplified into a last empty block */
+    assert(job->firstJob == 0);   /* cannot be first job, as it also needs to create frame header */
+    assert(job->dstBuff.start == NULL);   /* invoked from streaming variant only (otherwise, dstBuff might be user's output) */
+    job->dstBuff = ZSTDMT_getBuffer(job->bufPool);
+    if (job->dstBuff.start == NULL) {
+      job->cSize = ERROR(memory_allocation);
+      return;
+    }
+    assert(job->dstBuff.capacity >= ZSTD_blockHeaderSize);   /* no buffer should ever be that small */
+    job->src = kNullRange;
+    job->cSize = ZSTD_writeLastEmptyBlock(job->dstBuff.start, job->dstBuff.capacity);
+    assert(!ZSTD_isError(job->cSize));
+    assert(job->consumed == 0);
+}
+
+static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* mtctx, size_t srcSize, ZSTD_EndDirective endOp)
+{
+    unsigned const jobID = mtctx->nextJobID & mtctx->jobIDMask;
+    int const endFrame = (endOp == ZSTD_e_end);
+
+    if (mtctx->nextJobID > mtctx->doneJobID + mtctx->jobIDMask) {
+        DEBUGLOG(5, "ZSTDMT_createCompressionJob: will not create new job : table is full");
+        assert((mtctx->nextJobID & mtctx->jobIDMask) == (mtctx->doneJobID & mtctx->jobIDMask));
+        return 0;
+    }
+
+    if (!mtctx->jobReady) {
+        BYTE const* src = (BYTE const*)mtctx->inBuff.buffer.start;
+        DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ",
+                    mtctx->nextJobID, (U32)srcSize, (U32)mtctx->inBuff.prefix.size);
+        mtctx->jobs[jobID].src.start = src;
+        mtctx->jobs[jobID].src.size = srcSize;
+        assert(mtctx->inBuff.filled >= srcSize);
+        mtctx->jobs[jobID].prefix = mtctx->inBuff.prefix;
+        mtctx->jobs[jobID].consumed = 0;
+        mtctx->jobs[jobID].cSize = 0;
+        mtctx->jobs[jobID].params = mtctx->params;
+        mtctx->jobs[jobID].cdict = mtctx->nextJobID==0 ? mtctx->cdict : NULL;
+        mtctx->jobs[jobID].fullFrameSize = mtctx->frameContentSize;
+        mtctx->jobs[jobID].dstBuff = g_nullBuffer;
+        mtctx->jobs[jobID].cctxPool = mtctx->cctxPool;
+        mtctx->jobs[jobID].bufPool = mtctx->bufPool;
+        mtctx->jobs[jobID].seqPool = mtctx->seqPool;
+        mtctx->jobs[jobID].serial = &mtctx->serial;
+        mtctx->jobs[jobID].jobID = mtctx->nextJobID;
+        mtctx->jobs[jobID].firstJob = (mtctx->nextJobID==0);
+        mtctx->jobs[jobID].lastJob = endFrame;
+        mtctx->jobs[jobID].frameChecksumNeeded = mtctx->params.fParams.checksumFlag && endFrame && (mtctx->nextJobID>0);
+        mtctx->jobs[jobID].dstFlushed = 0;
+
+        /* Update the round buffer pos and clear the input buffer to be reset */
+        mtctx->roundBuff.pos += srcSize;
+        mtctx->inBuff.buffer = g_nullBuffer;
+        mtctx->inBuff.filled = 0;
+        /* Set the prefix */
+        if (!endFrame) {
+            size_t const newPrefixSize = MIN(srcSize, mtctx->targetPrefixSize);
+            mtctx->inBuff.prefix.start = src + srcSize - newPrefixSize;
+            mtctx->inBuff.prefix.size = newPrefixSize;
+        } else {   /* endFrame==1 => no need for another input buffer */
+            mtctx->inBuff.prefix = kNullRange;
+            mtctx->frameEnded = endFrame;
+            if (mtctx->nextJobID == 0) {
+                /* single job exception : checksum is already calculated directly within worker thread */
+                mtctx->params.fParams.checksumFlag = 0;
+        }   }
+
+        if ( (srcSize == 0)
+          && (mtctx->nextJobID>0)/*single job must also write frame header*/ ) {
+            DEBUGLOG(5, "ZSTDMT_createCompressionJob: creating a last empty block to end frame");
+            assert(endOp == ZSTD_e_end);  /* only possible case : need to end the frame with an empty last block */
+            ZSTDMT_writeLastEmptyBlock(mtctx->jobs + jobID);
+            mtctx->nextJobID++;
+            return 0;
+        }
+    }
+
+    DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes  (end:%u, jobNb == %u (mod:%u))",
+                mtctx->nextJobID,
+                (U32)mtctx->jobs[jobID].src.size,
+                mtctx->jobs[jobID].lastJob,
+                mtctx->nextJobID,
+                jobID);
+    if (POOL_tryAdd(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[jobID])) {
+        mtctx->nextJobID++;
+        mtctx->jobReady = 0;
+    } else {
+        DEBUGLOG(5, "ZSTDMT_createCompressionJob: no worker available for job %u", mtctx->nextJobID);
+        mtctx->jobReady = 1;
+    }
+    return 0;
+}
+
+
+/*! ZSTDMT_flushProduced() :
+ *  flush whatever data has been produced but not yet flushed in current job.
+ *  move to next job if current one is fully flushed.
+ * `output` : `pos` will be updated with amount of data flushed .
+ * `blockToFlush` : if >0, the function will block and wait if there is no data available to flush .
+ * @return : amount of data remaining within internal buffer, 0 if no more, 1 if unknown but > 0, or an error code */
+static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned blockToFlush, ZSTD_EndDirective end)
+{
+    unsigned const wJobID = mtctx->doneJobID & mtctx->jobIDMask;
+    DEBUGLOG(5, "ZSTDMT_flushProduced (blocking:%u , job %u <= %u)",
+                blockToFlush, mtctx->doneJobID, mtctx->nextJobID);
+    assert(output->size >= output->pos);
+
+    ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex);
+    if (  blockToFlush
+      && (mtctx->doneJobID < mtctx->nextJobID) ) {
+        assert(mtctx->jobs[wJobID].dstFlushed <= mtctx->jobs[wJobID].cSize);
+        while (mtctx->jobs[wJobID].dstFlushed == mtctx->jobs[wJobID].cSize) {  /* nothing to flush */
+            if (mtctx->jobs[wJobID].consumed == mtctx->jobs[wJobID].src.size) {
+                DEBUGLOG(5, "job %u is completely consumed (%u == %u) => don't wait for cond, there will be none",
+                            mtctx->doneJobID, (U32)mtctx->jobs[wJobID].consumed, (U32)mtctx->jobs[wJobID].src.size);
+                break;
+            }
+            DEBUGLOG(5, "waiting for something to flush from job %u (currently flushed: %u bytes)",
+                        mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed);
+            ZSTD_pthread_cond_wait(&mtctx->jobs[wJobID].job_cond, &mtctx->jobs[wJobID].job_mutex);  /* block when nothing to flush but some to come */
+    }   }
+
+    /* try to flush something */
+    {   size_t cSize = mtctx->jobs[wJobID].cSize;                  /* shared */
+        size_t const srcConsumed = mtctx->jobs[wJobID].consumed;   /* shared */
+        size_t const srcSize = mtctx->jobs[wJobID].src.size;       /* read-only, could be done after mutex lock, but no-declaration-after-statement */
+        ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+        if (ZSTD_isError(cSize)) {
+            DEBUGLOG(5, "ZSTDMT_flushProduced: job %u : compression error detected : %s",
+                        mtctx->doneJobID, ZSTD_getErrorName(cSize));
+            ZSTDMT_waitForAllJobsCompleted(mtctx);
+            ZSTDMT_releaseAllJobResources(mtctx);
+            return cSize;
+        }
+        /* add frame checksum if necessary (can only happen once) */
+        assert(srcConsumed <= srcSize);
+        if ( (srcConsumed == srcSize)   /* job completed -> worker no longer active */
+          && mtctx->jobs[wJobID].frameChecksumNeeded ) {
+            U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
+            DEBUGLOG(4, "ZSTDMT_flushProduced: writing checksum : %08X \n", checksum);
+            MEM_writeLE32((char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].cSize, checksum);
+            cSize += 4;
+            mtctx->jobs[wJobID].cSize += 4;  /* can write this shared value, as worker is no longer active */
+            mtctx->jobs[wJobID].frameChecksumNeeded = 0;
+        }
+
+        if (cSize > 0) {   /* compression is ongoing or completed */
+            size_t const toFlush = MIN(cSize - mtctx->jobs[wJobID].dstFlushed, output->size - output->pos);
+            DEBUGLOG(5, "ZSTDMT_flushProduced: Flushing %u bytes from job %u (completion:%u/%u, generated:%u)",
+                        (U32)toFlush, mtctx->doneJobID, (U32)srcConsumed, (U32)srcSize, (U32)cSize);
+            assert(mtctx->doneJobID < mtctx->nextJobID);
+            assert(cSize >= mtctx->jobs[wJobID].dstFlushed);
+            assert(mtctx->jobs[wJobID].dstBuff.start != NULL);
+            memcpy((char*)output->dst + output->pos,
+                   (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
+                   toFlush);
+            output->pos += toFlush;
+            mtctx->jobs[wJobID].dstFlushed += toFlush;  /* can write : this value is only used by mtctx */
+
+            if ( (srcConsumed == srcSize)    /* job is completed */
+              && (mtctx->jobs[wJobID].dstFlushed == cSize) ) {   /* output buffer fully flushed => free this job position */
+                DEBUGLOG(5, "Job %u completed (%u bytes), moving to next one",
+                        mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed);
+                ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[wJobID].dstBuff);
+                DEBUGLOG(5, "dstBuffer released");
+                mtctx->jobs[wJobID].dstBuff = g_nullBuffer;
+                mtctx->jobs[wJobID].cSize = 0;   /* ensure this job slot is considered "not started" in future check */
+                mtctx->consumed += srcSize;
+                mtctx->produced += cSize;
+                mtctx->doneJobID++;
+        }   }
+
+        /* return value : how many bytes left in buffer ; fake it to 1 when unknown but >0 */
+        if (cSize > mtctx->jobs[wJobID].dstFlushed) return (cSize - mtctx->jobs[wJobID].dstFlushed);
+        if (srcSize > srcConsumed) return 1;   /* current job not completely compressed */
+    }
+    if (mtctx->doneJobID < mtctx->nextJobID) return 1;   /* some more jobs ongoing */
+    if (mtctx->jobReady) return 1;      /* one job is ready to push, just not yet in the list */
+    if (mtctx->inBuff.filled > 0) return 1;   /* input is not empty, and still needs to be converted into a job */
+    mtctx->allJobsCompleted = mtctx->frameEnded;   /* all jobs are entirely flushed => if this one is last one, frame is completed */
+    if (end == ZSTD_e_end) return !mtctx->frameEnded;  /* for ZSTD_e_end, question becomes : is frame completed ? instead of : are internal buffers fully flushed ? */
+    return 0;   /* internal buffers fully flushed */
+}
+
+/**
+ * Returns the range of data used by the earliest job that is not yet complete.
+ * If the data of the first job is broken up into two segments, we cover both
+ * sections.
+ */
+static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx)
+{
+    unsigned const firstJobID = mtctx->doneJobID;
+    unsigned const lastJobID = mtctx->nextJobID;
+    unsigned jobID;
+
+    for (jobID = firstJobID; jobID < lastJobID; ++jobID) {
+        unsigned const wJobID = jobID & mtctx->jobIDMask;
+        size_t consumed;
+
+        ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex);
+        consumed = mtctx->jobs[wJobID].consumed;
+        ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
+
+        if (consumed < mtctx->jobs[wJobID].src.size) {
+            range_t range = mtctx->jobs[wJobID].prefix;
+            if (range.size == 0) {
+                /* Empty prefix */
+                range = mtctx->jobs[wJobID].src;
+            }
+            /* Job source in multiple segments not supported yet */
+            assert(range.start <= mtctx->jobs[wJobID].src.start);
+            return range;
+        }
+    }
+    return kNullRange;
+}
+
+/**
+ * Returns non-zero iff buffer and range overlap.
+ */
+static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range)
+{
+    BYTE const* const bufferStart = (BYTE const*)buffer.start;
+    BYTE const* const bufferEnd = bufferStart + buffer.capacity;
+    BYTE const* const rangeStart = (BYTE const*)range.start;
+    BYTE const* const rangeEnd = rangeStart + range.size;
+
+    if (rangeStart == NULL || bufferStart == NULL)
+        return 0;
+    /* Empty ranges cannot overlap */
+    if (bufferStart == bufferEnd || rangeStart == rangeEnd)
+        return 0;
+
+    return bufferStart < rangeEnd && rangeStart < bufferEnd;
+}
+
+static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window)
+{
+    range_t extDict;
+    range_t prefix;
+
+    DEBUGLOG(5, "ZSTDMT_doesOverlapWindow");
+    extDict.start = window.dictBase + window.lowLimit;
+    extDict.size = window.dictLimit - window.lowLimit;
+
+    prefix.start = window.base + window.dictLimit;
+    prefix.size = window.nextSrc - (window.base + window.dictLimit);
+    DEBUGLOG(5, "extDict [0x%zx, 0x%zx)",
+                (size_t)extDict.start,
+                (size_t)extDict.start + extDict.size);
+    DEBUGLOG(5, "prefix  [0x%zx, 0x%zx)",
+                (size_t)prefix.start,
+                (size_t)prefix.start + prefix.size);
+
+    return ZSTDMT_isOverlapped(buffer, extDict)
+        || ZSTDMT_isOverlapped(buffer, prefix);
+}
+
+static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer)
+{
+    if (mtctx->params.ldmParams.enableLdm) {
+        ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex;
+        DEBUGLOG(5, "ZSTDMT_waitForLdmComplete");
+        DEBUGLOG(5, "source  [0x%zx, 0x%zx)",
+                    (size_t)buffer.start,
+                    (size_t)buffer.start + buffer.capacity);
+        ZSTD_PTHREAD_MUTEX_LOCK(mutex);
+        while (ZSTDMT_doesOverlapWindow(buffer, mtctx->serial.ldmWindow)) {
+            DEBUGLOG(5, "Waiting for LDM to finish...");
+            ZSTD_pthread_cond_wait(&mtctx->serial.ldmWindowCond, mutex);
+        }
+        DEBUGLOG(6, "Done waiting for LDM to finish");
+        ZSTD_pthread_mutex_unlock(mutex);
+    }
+}
+
+/**
+ * Attempts to set the inBuff to the next section to fill.
+ * If any part of the new section is still in use we give up.
+ * Returns non-zero if the buffer is filled.
+ */
+static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx)
+{
+    range_t const inUse = ZSTDMT_getInputDataInUse(mtctx);
+    size_t const spaceLeft = mtctx->roundBuff.capacity - mtctx->roundBuff.pos;
+    size_t const target = mtctx->targetSectionSize;
+    buffer_t buffer;
+
+    DEBUGLOG(5, "ZSTDMT_tryGetInputRange");
+    assert(mtctx->inBuff.buffer.start == NULL);
+    assert(mtctx->roundBuff.capacity >= target);
+
+    if (spaceLeft < target) {
+        /* ZSTD_invalidateRepCodes() doesn't work for extDict variants.
+         * Simply copy the prefix to the beginning in that case.
+         */
+        BYTE* const start = (BYTE*)mtctx->roundBuff.buffer;
+        size_t const prefixSize = mtctx->inBuff.prefix.size;
+
+        buffer.start = start;
+        buffer.capacity = prefixSize;
+        if (ZSTDMT_isOverlapped(buffer, inUse)) {
+            DEBUGLOG(5, "Waiting for buffer...");
+            return 0;
+        }
+        ZSTDMT_waitForLdmComplete(mtctx, buffer);
+        memmove(start, mtctx->inBuff.prefix.start, prefixSize);
+        mtctx->inBuff.prefix.start = start;
+        mtctx->roundBuff.pos = prefixSize;
+    }
+    buffer.start = mtctx->roundBuff.buffer + mtctx->roundBuff.pos;
+    buffer.capacity = target;
+
+    if (ZSTDMT_isOverlapped(buffer, inUse)) {
+        DEBUGLOG(5, "Waiting for buffer...");
+        return 0;
+    }
+    assert(!ZSTDMT_isOverlapped(buffer, mtctx->inBuff.prefix));
+
+    ZSTDMT_waitForLdmComplete(mtctx, buffer);
+
+    DEBUGLOG(5, "Using prefix range [%zx, %zx)",
+                (size_t)mtctx->inBuff.prefix.start,
+                (size_t)mtctx->inBuff.prefix.start + mtctx->inBuff.prefix.size);
+    DEBUGLOG(5, "Using source range [%zx, %zx)",
+                (size_t)buffer.start,
+                (size_t)buffer.start + buffer.capacity);
+
+
+    mtctx->inBuff.buffer = buffer;
+    mtctx->inBuff.filled = 0;
+    assert(mtctx->roundBuff.pos + buffer.capacity <= mtctx->roundBuff.capacity);
+    return 1;
+}
+
+typedef struct {
+  size_t toLoad;  /* The number of bytes to load from the input. */
+  int flush;      /* Boolean declaring if we must flush because we found a synchronization point. */
+} syncPoint_t;
+
+/**
+ * Searches through the input for a synchronization point. If one is found, we
+ * will instruct the caller to flush, and return the number of bytes to load.
+ * Otherwise, we will load as many bytes as possible and instruct the caller
+ * to continue as normal.
+ */
+static syncPoint_t
+findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input)
+{
+    BYTE const* const istart = (BYTE const*)input.src + input.pos;
+    U64 const primePower = mtctx->rsync.primePower;
+    U64 const hitMask = mtctx->rsync.hitMask;
+
+    syncPoint_t syncPoint;
+    U64 hash;
+    BYTE const* prev;
+    size_t pos;
+
+    syncPoint.toLoad = MIN(input.size - input.pos, mtctx->targetSectionSize - mtctx->inBuff.filled);
+    syncPoint.flush = 0;
+    if (!mtctx->params.rsyncable)
+        /* Rsync is disabled. */
+        return syncPoint;
+    if (mtctx->inBuff.filled + syncPoint.toLoad < RSYNC_LENGTH)
+        /* Not enough to compute the hash.
+         * We will miss any synchronization points in this RSYNC_LENGTH byte
+         * window. However, since it depends only in the internal buffers, if the
+         * state is already synchronized, we will remain synchronized.
+         * Additionally, the probability that we miss a synchronization point is
+         * low: RSYNC_LENGTH / targetSectionSize.
+         */
+        return syncPoint;
+    /* Initialize the loop variables. */
+    if (mtctx->inBuff.filled >= RSYNC_LENGTH) {
+        /* We have enough bytes buffered to initialize the hash.
+         * Start scanning at the beginning of the input.
+         */
+        pos = 0;
+        prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH;
+        hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH);
+    } else {
+        /* We don't have enough bytes buffered to initialize the hash, but
+         * we know we have at least RSYNC_LENGTH bytes total.
+         * Start scanning after the first RSYNC_LENGTH bytes less the bytes
+         * already buffered.
+         */
+        pos = RSYNC_LENGTH - mtctx->inBuff.filled;
+        prev = (BYTE const*)mtctx->inBuff.buffer.start - pos;
+        hash = ZSTD_rollingHash_compute(mtctx->inBuff.buffer.start, mtctx->inBuff.filled);
+        hash = ZSTD_rollingHash_append(hash, istart, pos);
+    }
+    /* Starting with the hash of the previous RSYNC_LENGTH bytes, roll
+     * through the input. If we hit a synchronization point, then cut the
+     * job off, and tell the compressor to flush the job. Otherwise, load
+     * all the bytes and continue as normal.
+     * If we go too long without a synchronization point (targetSectionSize)
+     * then a block will be emitted anyways, but this is okay, since if we
+     * are already synchronized we will remain synchronized.
+     */
+    for (; pos < syncPoint.toLoad; ++pos) {
+        BYTE const toRemove = pos < RSYNC_LENGTH ? prev[pos] : istart[pos - RSYNC_LENGTH];
+        /* if (pos >= RSYNC_LENGTH) assert(ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); */
+        hash = ZSTD_rollingHash_rotate(hash, toRemove, istart[pos], primePower);
+        if ((hash & hitMask) == hitMask) {
+            syncPoint.toLoad = pos + 1;
+            syncPoint.flush = 1;
+            break;
+        }
+    }
+    return syncPoint;
+}
+
+size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx)
+{
+    size_t hintInSize = mtctx->targetSectionSize - mtctx->inBuff.filled;
+    if (hintInSize==0) hintInSize = mtctx->targetSectionSize;
+    return hintInSize;
+}
+
+/** ZSTDMT_compressStream_generic() :
+ *  internal use only - exposed to be invoked from zstd_compress.c
+ *  assumption : output and input are valid (pos <= size)
+ * @return : minimum amount of data remaining to flush, 0 if none */
+size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
+                                     ZSTD_outBuffer* output,
+                                     ZSTD_inBuffer* input,
+                                     ZSTD_EndDirective endOp)
+{
+    unsigned forwardInputProgress = 0;
+    DEBUGLOG(5, "ZSTDMT_compressStream_generic (endOp=%u, srcSize=%u)",
+                (U32)endOp, (U32)(input->size - input->pos));
+    assert(output->pos <= output->size);
+    assert(input->pos  <= input->size);
+
+    if (mtctx->singleBlockingThread) {  /* delegate to single-thread (synchronous) */
+        return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
+    }
+
+    if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
+        /* current frame being ended. Only flush/end are allowed */
+        return ERROR(stage_wrong);
+    }
+
+    /* single-pass shortcut (note : synchronous-mode) */
+    if ( (!mtctx->params.rsyncable)   /* rsyncable mode is disabled */
+      && (mtctx->nextJobID == 0)      /* just started */
+      && (mtctx->inBuff.filled == 0)  /* nothing buffered */
+      && (!mtctx->jobReady)           /* no job already created */
+      && (endOp == ZSTD_e_end)        /* end order */
+      && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough space in dst */
+        size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx,
+                (char*)output->dst + output->pos, output->size - output->pos,
+                (const char*)input->src + input->pos, input->size - input->pos,
+                mtctx->cdict, mtctx->params);
+        if (ZSTD_isError(cSize)) return cSize;
+        input->pos = input->size;
+        output->pos += cSize;
+        mtctx->allJobsCompleted = 1;
+        mtctx->frameEnded = 1;
+        return 0;
+    }
+
+    /* fill input buffer */
+    if ( (!mtctx->jobReady)
+      && (input->size > input->pos) ) {   /* support NULL input */
+        if (mtctx->inBuff.buffer.start == NULL) {
+            assert(mtctx->inBuff.filled == 0); /* Can't fill an empty buffer */
+            if (!ZSTDMT_tryGetInputRange(mtctx)) {
+                /* It is only possible for this operation to fail if there are
+                 * still compression jobs ongoing.
+                 */
+                DEBUGLOG(5, "ZSTDMT_tryGetInputRange failed");
+                assert(mtctx->doneJobID != mtctx->nextJobID);
+            } else
+                DEBUGLOG(5, "ZSTDMT_tryGetInputRange completed successfully : mtctx->inBuff.buffer.start = %p", mtctx->inBuff.buffer.start);
+        }
+        if (mtctx->inBuff.buffer.start != NULL) {
+            syncPoint_t const syncPoint = findSynchronizationPoint(mtctx, *input);
+            if (syncPoint.flush && endOp == ZSTD_e_continue) {
+                endOp = ZSTD_e_flush;
+            }
+            assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize);
+            DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u",
+                        (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize);
+            memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad);
+            input->pos += syncPoint.toLoad;
+            mtctx->inBuff.filled += syncPoint.toLoad;
+            forwardInputProgress = syncPoint.toLoad>0;
+        }
+        if ((input->pos < input->size) && (endOp == ZSTD_e_end))
+            endOp = ZSTD_e_flush;   /* can't end now : not all input consumed */
+    }
+
+    if ( (mtctx->jobReady)
+      || (mtctx->inBuff.filled >= mtctx->targetSectionSize)  /* filled enough : let's compress */
+      || ((endOp != ZSTD_e_continue) && (mtctx->inBuff.filled > 0))  /* something to flush : let's go */
+      || ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) {   /* must finish the frame with a zero-size block */
+        size_t const jobSize = mtctx->inBuff.filled;
+        assert(mtctx->inBuff.filled <= mtctx->targetSectionSize);
+        CHECK_F( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) );
+    }
+
+    /* check for potential compressed data ready to be flushed */
+    {   size_t const remainingToFlush = ZSTDMT_flushProduced(mtctx, output, !forwardInputProgress, endOp); /* block if there was no forward input progress */
+        if (input->pos < input->size) return MAX(remainingToFlush, 1);  /* input not consumed : do not end flush yet */
+        DEBUGLOG(5, "end of ZSTDMT_compressStream_generic: remainingToFlush = %u", (U32)remainingToFlush);
+        return remainingToFlush;
+    }
+}
+
+
+size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+    CHECK_F( ZSTDMT_compressStream_generic(mtctx, output, input, ZSTD_e_continue) );
+
+    /* recommended next input size : fill current input buffer */
+    return mtctx->targetSectionSize - mtctx->inBuff.filled;   /* note : could be zero when input buffer is fully filled and no more availability to create new job */
+}
+
+
+static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_EndDirective endFrame)
+{
+    size_t const srcSize = mtctx->inBuff.filled;
+    DEBUGLOG(5, "ZSTDMT_flushStream_internal");
+
+    if ( mtctx->jobReady     /* one job ready for a worker to pick up */
+      || (srcSize > 0)       /* still some data within input buffer */
+      || ((endFrame==ZSTD_e_end) && !mtctx->frameEnded)) {  /* need a last 0-size block to end frame */
+           DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job (%u bytes, end:%u)",
+                        (U32)srcSize, (U32)endFrame);
+        CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
+    }
+
+    /* check if there is any data available to flush */
+    return ZSTDMT_flushProduced(mtctx, output, 1 /* blockToFlush */, endFrame);
+}
+
+
+size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
+{
+    DEBUGLOG(5, "ZSTDMT_flushStream");
+    if (mtctx->singleBlockingThread)
+        return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
+    return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_flush);
+}
+
+size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
+{
+    DEBUGLOG(4, "ZSTDMT_endStream");
+    if (mtctx->singleBlockingThread)
+        return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
+    return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_end);
+}
diff --git a/Utilities/cmzstd/lib/compress/zstdmt_compress.h b/Utilities/cmzstd/lib/compress/zstdmt_compress.h
new file mode 100644
index 0000000..ee77168
--- /dev/null
+++ b/Utilities/cmzstd/lib/compress/zstdmt_compress.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+ #ifndef ZSTDMT_COMPRESS_H
+ #define ZSTDMT_COMPRESS_H
+
+ #if defined (__cplusplus)
+ extern "C" {
+ #endif
+
+
+/* Note : This is an internal API.
+ *        Some methods are still exposed (ZSTDLIB_API),
+ *        because it used to be the only way to invoke MT compression.
+ *        Now, it's recommended to use ZSTD_compress_generic() instead.
+ *        These methods will stop being exposed in a future version */
+
+/* ===   Dependencies   === */
+#include <stddef.h>                /* size_t */
+#define ZSTD_STATIC_LINKING_ONLY   /* ZSTD_parameters */
+#include "zstd.h"            /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */
+
+
+/* ===   Constants   === */
+#ifndef ZSTDMT_NBWORKERS_MAX
+#  define ZSTDMT_NBWORKERS_MAX 200
+#endif
+#ifndef ZSTDMT_JOBSIZE_MIN
+#  define ZSTDMT_JOBSIZE_MIN (1 MB)
+#endif
+#define ZSTDMT_JOBSIZE_MAX  (MEM_32bits() ? (512 MB) : (1024 MB))
+
+
+/* ===   Memory management   === */
+typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx;
+ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers);
+ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers,
+                                                    ZSTD_customMem cMem);
+ZSTDLIB_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
+
+ZSTDLIB_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
+
+
+/* ===   Simple one-pass compression function   === */
+
+ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
+                                       void* dst, size_t dstCapacity,
+                                 const void* src, size_t srcSize,
+                                       int compressionLevel);
+
+
+
+/* ===   Streaming functions   === */
+
+ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
+ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize);  /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */
+
+ZSTDLIB_API size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx);
+ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+
+ZSTDLIB_API size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);   /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
+ZSTDLIB_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);     /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
+
+
+/* ===   Advanced functions and parameters  === */
+
+ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
+                                           void* dst, size_t dstCapacity,
+                                     const void* src, size_t srcSize,
+                                     const ZSTD_CDict* cdict,
+                                           ZSTD_parameters params,
+                                           int overlapLog);
+
+ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
+                                        const void* dict, size_t dictSize,   /* dict can be released after init, a local copy is preserved within zcs */
+                                        ZSTD_parameters params,
+                                        unsigned long long pledgedSrcSize);  /* pledgedSrcSize is optional and can be zero == unknown */
+
+ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
+                                        const ZSTD_CDict* cdict,
+                                        ZSTD_frameParameters fparams,
+                                        unsigned long long pledgedSrcSize);  /* note : zero means empty */
+
+/* ZSTDMT_parameter :
+ * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
+typedef enum {
+    ZSTDMT_p_jobSize,     /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */
+    ZSTDMT_p_overlapLog,  /* Each job may reload a part of previous job to enhance compressionr ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window. This is a "sticky" parameter : its value will be re-used on next compression job */
+    ZSTDMT_p_rsyncable    /* Enables rsyncable mode. */
+} ZSTDMT_parameter;
+
+/* ZSTDMT_setMTCtxParameter() :
+ * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
+ * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__
+ * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
+ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value);
+
+/* ZSTDMT_getMTCtxParameter() :
+ * Query the ZSTDMT_CCtx for a parameter value.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
+ZSTDLIB_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value);
+
+
+/*! ZSTDMT_compressStream_generic() :
+ *  Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream()
+ *  depending on flush directive.
+ * @return : minimum amount of data still to be flushed
+ *           0 if fully flushed
+ *           or an error code
+ *  note : needs to be init using any ZSTD_initCStream*() variant */
+ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
+                                                ZSTD_outBuffer* output,
+                                                ZSTD_inBuffer* input,
+                                                ZSTD_EndDirective endOp);
+
+
+/* ========================================================
+ * ===  Private interface, for use by ZSTD_compress.c   ===
+ * ===  Not exposed in libzstd. Never invoke directly   ===
+ * ======================================================== */
+
+ /*! ZSTDMT_toFlushNow()
+  *  Tell how many bytes are ready to be flushed immediately.
+  *  Probe the oldest active job (not yet entirely flushed) and check its output buffer.
+  *  If return 0, it means there is no active job,
+  *  or, it means oldest job is still active, but everything produced has been flushed so far,
+  *  therefore flushing is limited by speed of oldest job. */
+size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx);
+
+/*! ZSTDMT_CCtxParam_setMTCtxParameter()
+ *  like ZSTDMT_setMTCtxParameter(), but into a ZSTD_CCtx_Params */
+size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, int value);
+
+/*! ZSTDMT_CCtxParam_setNbWorkers()
+ *  Set nbWorkers, and clamp it.
+ *  Also reset jobSize and overlapLog */
+size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers);
+
+/*! ZSTDMT_updateCParams_whileCompressing() :
+ *  Updates only a selected set of compression parameters, to remain compatible with current frame.
+ *  New parameters will be applied to next compression job. */
+void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams);
+
+/*! ZSTDMT_getFrameProgression():
+ *  tells how much data has been consumed (input) and produced (output) for current frame.
+ *  able to count progression inside worker threads.
+ */
+ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx);
+
+
+/*! ZSTDMT_initCStream_internal() :
+ *  Private use only. Init streaming operation.
+ *  expects params to be valid.
+ *  must receive dict, or cdict, or none, but not both.
+ *  @return : 0, or an error code */
+size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
+                    const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
+                    const ZSTD_CDict* cdict,
+                    ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif   /* ZSTDMT_COMPRESS_H */
diff --git a/Utilities/cmzstd/lib/decompress/huf_decompress.c b/Utilities/cmzstd/lib/decompress/huf_decompress.c
new file mode 100644
index 0000000..3f8bd29
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/huf_decompress.c
@@ -0,0 +1,1232 @@
+/* ******************************************************************
+   huff0 huffman decoder,
+   part of Finite State Entropy library
+   Copyright (C) 2013-present, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+    - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+
+/* **************************************************************
+*  Dependencies
+****************************************************************/
+#include <string.h>     /* memcpy, memset */
+#include "compiler.h"
+#include "bitstream.h"  /* BIT_* */
+#include "fse.h"        /* to compress headers */
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "error_private.h"
+
+/* **************************************************************
+*  Macros
+****************************************************************/
+
+/* These two optional macros force the use one way or another of the two
+ * Huffman decompression implementations. You can't force in both directions
+ * at the same time.
+ */
+#if defined(HUF_FORCE_DECOMPRESS_X1) && \
+    defined(HUF_FORCE_DECOMPRESS_X2)
+#error "Cannot force the use of the X1 and X2 decoders at the same time!"
+#endif
+
+
+/* **************************************************************
+*  Error Management
+****************************************************************/
+#define HUF_isError ERR_isError
+#define CHECK_F(f) { size_t const err_ = (f); if (HUF_isError(err_)) return err_; }
+
+
+/* **************************************************************
+*  Byte alignment for workSpace management
+****************************************************************/
+#define HUF_ALIGN(x, a)         HUF_ALIGN_MASK((x), (a) - 1)
+#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+
+/* **************************************************************
+*  BMI2 Variant Wrappers
+****************************************************************/
+#if DYNAMIC_BMI2
+
+#define HUF_DGEN(fn)                                                        \
+                                                                            \
+    static size_t fn##_default(                                             \
+                  void* dst,  size_t dstSize,                               \
+            const void* cSrc, size_t cSrcSize,                              \
+            const HUF_DTable* DTable)                                       \
+    {                                                                       \
+        return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable);             \
+    }                                                                       \
+                                                                            \
+    static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2(                       \
+                  void* dst,  size_t dstSize,                               \
+            const void* cSrc, size_t cSrcSize,                              \
+            const HUF_DTable* DTable)                                       \
+    {                                                                       \
+        return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable);             \
+    }                                                                       \
+                                                                            \
+    static size_t fn(void* dst, size_t dstSize, void const* cSrc,           \
+                     size_t cSrcSize, HUF_DTable const* DTable, int bmi2)   \
+    {                                                                       \
+        if (bmi2) {                                                         \
+            return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable);         \
+        }                                                                   \
+        return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable);          \
+    }
+
+#else
+
+#define HUF_DGEN(fn)                                                        \
+    static size_t fn(void* dst, size_t dstSize, void const* cSrc,           \
+                     size_t cSrcSize, HUF_DTable const* DTable, int bmi2)   \
+    {                                                                       \
+        (void)bmi2;                                                         \
+        return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable);             \
+    }
+
+#endif
+
+
+/*-***************************/
+/*  generic DTableDesc       */
+/*-***************************/
+typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
+
+static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
+{
+    DTableDesc dtd;
+    memcpy(&dtd, table, sizeof(dtd));
+    return dtd;
+}
+
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+
+/*-***************************/
+/*  single-symbol decoding   */
+/*-***************************/
+typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1;   /* single-symbol decoding */
+
+size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
+{
+    U32 tableLog = 0;
+    U32 nbSymbols = 0;
+    size_t iSize;
+    void* const dtPtr = DTable + 1;
+    HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr;
+
+    U32* rankVal;
+    BYTE* huffWeight;
+    size_t spaceUsed32 = 0;
+
+    rankVal = (U32 *)workSpace + spaceUsed32;
+    spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
+    huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
+    spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+    if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+
+    DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
+    /* memset(huffWeight, 0, sizeof(huffWeight)); */   /* is not necessary, even though some analyzer complain ... */
+
+    iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
+    if (HUF_isError(iSize)) return iSize;
+
+    /* Table header */
+    {   DTableDesc dtd = HUF_getDTableDesc(DTable);
+        if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge);   /* DTable too small, Huffman tree cannot fit in */
+        dtd.tableType = 0;
+        dtd.tableLog = (BYTE)tableLog;
+        memcpy(DTable, &dtd, sizeof(dtd));
+    }
+
+    /* Calculate starting value for each rank */
+    {   U32 n, nextRankStart = 0;
+        for (n=1; n<tableLog+1; n++) {
+            U32 const current = nextRankStart;
+            nextRankStart += (rankVal[n] << (n-1));
+            rankVal[n] = current;
+    }   }
+
+    /* fill DTable */
+    {   U32 n;
+        for (n=0; n<nbSymbols; n++) {
+            U32 const w = huffWeight[n];
+            U32 const length = (1 << w) >> 1;
+            U32 u;
+            HUF_DEltX1 D;
+            D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
+            for (u = rankVal[w]; u < rankVal[w] + length; u++)
+                dt[u] = D;
+            rankVal[w] += length;
+    }   }
+
+    return iSize;
+}
+
+size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_readDTableX1_wksp(DTable, src, srcSize,
+                                 workSpace, sizeof(workSpace));
+}
+
+FORCE_INLINE_TEMPLATE BYTE
+HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog)
+{
+    size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
+    BYTE const c = dt[val].byte;
+    BIT_skipBits(Dstream, dt[val].nbBits);
+    return c;
+}
+
+#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
+    *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr)  \
+    if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
+        HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
+
+#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
+    if (MEM_64bits()) \
+        HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
+
+HINT_INLINE size_t
+HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
+{
+    BYTE* const pStart = p;
+
+    /* up to 4 symbols at a time */
+    while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) {
+        HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
+        HUF_DECODE_SYMBOLX1_1(p, bitDPtr);
+        HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
+        HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+    }
+
+    /* [0-3] symbols remaining */
+    if (MEM_32bits())
+        while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd))
+            HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+
+    /* no more data to retrieve from bitstream, no need to reload */
+    while (p < pEnd)
+        HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+
+    return pEnd-pStart;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress1X1_usingDTable_internal_body(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    BYTE* op = (BYTE*)dst;
+    BYTE* const oend = op + dstSize;
+    const void* dtPtr = DTable + 1;
+    const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
+    BIT_DStream_t bitD;
+    DTableDesc const dtd = HUF_getDTableDesc(DTable);
+    U32 const dtLog = dtd.tableLog;
+
+    CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
+
+    HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog);
+
+    if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+
+    return dstSize;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress4X1_usingDTable_internal_body(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    /* Check */
+    if (cSrcSize < 10) return ERROR(corruption_detected);  /* strict minimum : jump table + 1 byte per stream */
+
+    {   const BYTE* const istart = (const BYTE*) cSrc;
+        BYTE* const ostart = (BYTE*) dst;
+        BYTE* const oend = ostart + dstSize;
+        const void* const dtPtr = DTable + 1;
+        const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
+
+        /* Init */
+        BIT_DStream_t bitD1;
+        BIT_DStream_t bitD2;
+        BIT_DStream_t bitD3;
+        BIT_DStream_t bitD4;
+        size_t const length1 = MEM_readLE16(istart);
+        size_t const length2 = MEM_readLE16(istart+2);
+        size_t const length3 = MEM_readLE16(istart+4);
+        size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
+        const BYTE* const istart1 = istart + 6;  /* jumpTable */
+        const BYTE* const istart2 = istart1 + length1;
+        const BYTE* const istart3 = istart2 + length2;
+        const BYTE* const istart4 = istart3 + length3;
+        const size_t segmentSize = (dstSize+3) / 4;
+        BYTE* const opStart2 = ostart + segmentSize;
+        BYTE* const opStart3 = opStart2 + segmentSize;
+        BYTE* const opStart4 = opStart3 + segmentSize;
+        BYTE* op1 = ostart;
+        BYTE* op2 = opStart2;
+        BYTE* op3 = opStart3;
+        BYTE* op4 = opStart4;
+        U32 endSignal = BIT_DStream_unfinished;
+        DTableDesc const dtd = HUF_getDTableDesc(DTable);
+        U32 const dtLog = dtd.tableLog;
+
+        if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
+        CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
+        CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
+        CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
+        CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
+
+        /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */
+        endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
+        while ( (endSignal==BIT_DStream_unfinished) && (op4<(oend-3)) ) {
+            HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
+            HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
+            HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
+            HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
+            HUF_DECODE_SYMBOLX1_1(op1, &bitD1);
+            HUF_DECODE_SYMBOLX1_1(op2, &bitD2);
+            HUF_DECODE_SYMBOLX1_1(op3, &bitD3);
+            HUF_DECODE_SYMBOLX1_1(op4, &bitD4);
+            HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
+            HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
+            HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
+            HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
+            HUF_DECODE_SYMBOLX1_0(op1, &bitD1);
+            HUF_DECODE_SYMBOLX1_0(op2, &bitD2);
+            HUF_DECODE_SYMBOLX1_0(op3, &bitD3);
+            HUF_DECODE_SYMBOLX1_0(op4, &bitD4);
+            BIT_reloadDStream(&bitD1);
+            BIT_reloadDStream(&bitD2);
+            BIT_reloadDStream(&bitD3);
+            BIT_reloadDStream(&bitD4);
+        }
+
+        /* check corruption */
+        /* note : should not be necessary : op# advance in lock step, and we control op4.
+         *        but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */
+        if (op1 > opStart2) return ERROR(corruption_detected);
+        if (op2 > opStart3) return ERROR(corruption_detected);
+        if (op3 > opStart4) return ERROR(corruption_detected);
+        /* note : op4 supposed already verified within main loop */
+
+        /* finish bitStreams one by one */
+        HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog);
+        HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog);
+        HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog);
+        HUF_decodeStreamX1(op4, &bitD4, oend,     dt, dtLog);
+
+        /* check */
+        { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+          if (!endCheck) return ERROR(corruption_detected); }
+
+        /* decoded size */
+        return dstSize;
+    }
+}
+
+
+typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
+                                               const void *cSrc,
+                                               size_t cSrcSize,
+                                               const HUF_DTable *DTable);
+
+HUF_DGEN(HUF_decompress1X1_usingDTable_internal)
+HUF_DGEN(HUF_decompress4X1_usingDTable_internal)
+
+
+
+size_t HUF_decompress1X1_usingDTable(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    DTableDesc dtd = HUF_getDTableDesc(DTable);
+    if (dtd.tableType != 0) return ERROR(GENERIC);
+    return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
+                                   const void* cSrc, size_t cSrcSize,
+                                   void* workSpace, size_t wkspSize)
+{
+    const BYTE* ip = (const BYTE*) cSrc;
+
+    size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize);
+    if (HUF_isError(hSize)) return hSize;
+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+    ip += hSize; cSrcSize -= hSize;
+
+    return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+                              const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+size_t HUF_decompress4X1_usingDTable(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    DTableDesc dtd = HUF_getDTableDesc(DTable);
+    if (dtd.tableType != 0) return ERROR(GENERIC);
+    return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
+                                   const void* cSrc, size_t cSrcSize,
+                                   void* workSpace, size_t wkspSize, int bmi2)
+{
+    const BYTE* ip = (const BYTE*) cSrc;
+
+    size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize,
+                                                workSpace, wkspSize);
+    if (HUF_isError(hSize)) return hSize;
+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+    ip += hSize; cSrcSize -= hSize;
+
+    return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+
+size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+                                   const void* cSrc, size_t cSrcSize,
+                                   void* workSpace, size_t wkspSize)
+{
+    return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0);
+}
+
+
+size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+#endif /* HUF_FORCE_DECOMPRESS_X2 */
+
+
+#ifndef HUF_FORCE_DECOMPRESS_X1
+
+/* *************************/
+/* double-symbols decoding */
+/* *************************/
+
+typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2;  /* double-symbols decoding */
+typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
+typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
+typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
+
+
+/* HUF_fillDTableX2Level2() :
+ * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
+static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
+                           const U32* rankValOrigin, const int minWeight,
+                           const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
+                           U32 nbBitsBaseline, U16 baseSeq)
+{
+    HUF_DEltX2 DElt;
+    U32 rankVal[HUF_TABLELOG_MAX + 1];
+
+    /* get pre-calculated rankVal */
+    memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+
+    /* fill skipped values */
+    if (minWeight>1) {
+        U32 i, skipSize = rankVal[minWeight];
+        MEM_writeLE16(&(DElt.sequence), baseSeq);
+        DElt.nbBits   = (BYTE)(consumed);
+        DElt.length   = 1;
+        for (i = 0; i < skipSize; i++)
+            DTable[i] = DElt;
+    }
+
+    /* fill DTable */
+    {   U32 s; for (s=0; s<sortedListSize; s++) {   /* note : sortedSymbols already skipped */
+            const U32 symbol = sortedSymbols[s].symbol;
+            const U32 weight = sortedSymbols[s].weight;
+            const U32 nbBits = nbBitsBaseline - weight;
+            const U32 length = 1 << (sizeLog-nbBits);
+            const U32 start = rankVal[weight];
+            U32 i = start;
+            const U32 end = start + length;
+
+            MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
+            DElt.nbBits = (BYTE)(nbBits + consumed);
+            DElt.length = 2;
+            do { DTable[i++] = DElt; } while (i<end);   /* since length >= 1 */
+
+            rankVal[weight] += length;
+    }   }
+}
+
+
+static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
+                           const sortedSymbol_t* sortedList, const U32 sortedListSize,
+                           const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
+                           const U32 nbBitsBaseline)
+{
+    U32 rankVal[HUF_TABLELOG_MAX + 1];
+    const int scaleLog = nbBitsBaseline - targetLog;   /* note : targetLog >= srcLog, hence scaleLog <= 1 */
+    const U32 minBits  = nbBitsBaseline - maxWeight;
+    U32 s;
+
+    memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+
+    /* fill DTable */
+    for (s=0; s<sortedListSize; s++) {
+        const U16 symbol = sortedList[s].symbol;
+        const U32 weight = sortedList[s].weight;
+        const U32 nbBits = nbBitsBaseline - weight;
+        const U32 start = rankVal[weight];
+        const U32 length = 1 << (targetLog-nbBits);
+
+        if (targetLog-nbBits >= minBits) {   /* enough room for a second symbol */
+            U32 sortedRank;
+            int minWeight = nbBits + scaleLog;
+            if (minWeight < 1) minWeight = 1;
+            sortedRank = rankStart[minWeight];
+            HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
+                           rankValOrigin[nbBits], minWeight,
+                           sortedList+sortedRank, sortedListSize-sortedRank,
+                           nbBitsBaseline, symbol);
+        } else {
+            HUF_DEltX2 DElt;
+            MEM_writeLE16(&(DElt.sequence), symbol);
+            DElt.nbBits = (BYTE)(nbBits);
+            DElt.length = 1;
+            {   U32 const end = start + length;
+                U32 u;
+                for (u = start; u < end; u++) DTable[u] = DElt;
+        }   }
+        rankVal[weight] += length;
+    }
+}
+
+size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
+                       const void* src, size_t srcSize,
+                             void* workSpace, size_t wkspSize)
+{
+    U32 tableLog, maxW, sizeOfSort, nbSymbols;
+    DTableDesc dtd = HUF_getDTableDesc(DTable);
+    U32 const maxTableLog = dtd.maxTableLog;
+    size_t iSize;
+    void* dtPtr = DTable+1;   /* force compiler to avoid strict-aliasing */
+    HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
+    U32 *rankStart;
+
+    rankValCol_t* rankVal;
+    U32* rankStats;
+    U32* rankStart0;
+    sortedSymbol_t* sortedSymbol;
+    BYTE* weightList;
+    size_t spaceUsed32 = 0;
+
+    rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32);
+    spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
+    rankStats = (U32 *)workSpace + spaceUsed32;
+    spaceUsed32 += HUF_TABLELOG_MAX + 1;
+    rankStart0 = (U32 *)workSpace + spaceUsed32;
+    spaceUsed32 += HUF_TABLELOG_MAX + 2;
+    sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t);
+    spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
+    weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
+    spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+    if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+
+    rankStart = rankStart0 + 1;
+    memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
+
+    DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable));   /* if compiler fails here, assertion is wrong */
+    if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+    /* memset(weightList, 0, sizeof(weightList)); */  /* is not necessary, even though some analyzer complain ... */
+
+    iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
+    if (HUF_isError(iSize)) return iSize;
+
+    /* check result */
+    if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge);   /* DTable can't fit code depth */
+
+    /* find maxWeight */
+    for (maxW = tableLog; rankStats[maxW]==0; maxW--) {}  /* necessarily finds a solution before 0 */
+
+    /* Get start index of each weight */
+    {   U32 w, nextRankStart = 0;
+        for (w=1; w<maxW+1; w++) {
+            U32 current = nextRankStart;
+            nextRankStart += rankStats[w];
+            rankStart[w] = current;
+        }
+        rankStart[0] = nextRankStart;   /* put all 0w symbols at the end of sorted list*/
+        sizeOfSort = nextRankStart;
+    }
+
+    /* sort symbols by weight */
+    {   U32 s;
+        for (s=0; s<nbSymbols; s++) {
+            U32 const w = weightList[s];
+            U32 const r = rankStart[w]++;
+            sortedSymbol[r].symbol = (BYTE)s;
+            sortedSymbol[r].weight = (BYTE)w;
+        }
+        rankStart[0] = 0;   /* forget 0w symbols; this is beginning of weight(1) */
+    }
+
+    /* Build rankVal */
+    {   U32* const rankVal0 = rankVal[0];
+        {   int const rescale = (maxTableLog-tableLog) - 1;   /* tableLog <= maxTableLog */
+            U32 nextRankVal = 0;
+            U32 w;
+            for (w=1; w<maxW+1; w++) {
+                U32 current = nextRankVal;
+                nextRankVal += rankStats[w] << (w+rescale);
+                rankVal0[w] = current;
+        }   }
+        {   U32 const minBits = tableLog+1 - maxW;
+            U32 consumed;
+            for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
+                U32* const rankValPtr = rankVal[consumed];
+                U32 w;
+                for (w = 1; w < maxW+1; w++) {
+                    rankValPtr[w] = rankVal0[w] >> consumed;
+    }   }   }   }
+
+    HUF_fillDTableX2(dt, maxTableLog,
+                   sortedSymbol, sizeOfSort,
+                   rankStart0, rankVal, maxW,
+                   tableLog+1);
+
+    dtd.tableLog = (BYTE)maxTableLog;
+    dtd.tableType = 1;
+    memcpy(DTable, &dtd, sizeof(dtd));
+    return iSize;
+}
+
+size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+  U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+  return HUF_readDTableX2_wksp(DTable, src, srcSize,
+                               workSpace, sizeof(workSpace));
+}
+
+
+FORCE_INLINE_TEMPLATE U32
+HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
+{
+    size_t const val = BIT_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
+    memcpy(op, dt+val, 2);
+    BIT_skipBits(DStream, dt[val].nbBits);
+    return dt[val].length;
+}
+
+FORCE_INLINE_TEMPLATE U32
+HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
+{
+    size_t const val = BIT_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
+    memcpy(op, dt+val, 1);
+    if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
+    else {
+        if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
+            BIT_skipBits(DStream, dt[val].nbBits);
+            if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
+                /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
+                DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8);
+    }   }
+    return 1;
+}
+
+#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
+    ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
+    if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
+        ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
+    if (MEM_64bits()) \
+        ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+HINT_INLINE size_t
+HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
+                const HUF_DEltX2* const dt, const U32 dtLog)
+{
+    BYTE* const pStart = p;
+
+    /* up to 8 symbols at a time */
+    while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
+        HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
+        HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
+        HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
+        HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
+    }
+
+    /* closer to end : up to 2 symbols at a time */
+    while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
+        HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
+
+    while (p <= pEnd-2)
+        HUF_DECODE_SYMBOLX2_0(p, bitDPtr);   /* no need to reload : reached the end of DStream */
+
+    if (p < pEnd)
+        p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog);
+
+    return p-pStart;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress1X2_usingDTable_internal_body(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    BIT_DStream_t bitD;
+
+    /* Init */
+    CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
+
+    /* decode */
+    {   BYTE* const ostart = (BYTE*) dst;
+        BYTE* const oend = ostart + dstSize;
+        const void* const dtPtr = DTable+1;   /* force compiler to not use strict-aliasing */
+        const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+        DTableDesc const dtd = HUF_getDTableDesc(DTable);
+        HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog);
+    }
+
+    /* check */
+    if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+
+    /* decoded size */
+    return dstSize;
+}
+
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress4X2_usingDTable_internal_body(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    if (cSrcSize < 10) return ERROR(corruption_detected);   /* strict minimum : jump table + 1 byte per stream */
+
+    {   const BYTE* const istart = (const BYTE*) cSrc;
+        BYTE* const ostart = (BYTE*) dst;
+        BYTE* const oend = ostart + dstSize;
+        const void* const dtPtr = DTable+1;
+        const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+
+        /* Init */
+        BIT_DStream_t bitD1;
+        BIT_DStream_t bitD2;
+        BIT_DStream_t bitD3;
+        BIT_DStream_t bitD4;
+        size_t const length1 = MEM_readLE16(istart);
+        size_t const length2 = MEM_readLE16(istart+2);
+        size_t const length3 = MEM_readLE16(istart+4);
+        size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
+        const BYTE* const istart1 = istart + 6;  /* jumpTable */
+        const BYTE* const istart2 = istart1 + length1;
+        const BYTE* const istart3 = istart2 + length2;
+        const BYTE* const istart4 = istart3 + length3;
+        size_t const segmentSize = (dstSize+3) / 4;
+        BYTE* const opStart2 = ostart + segmentSize;
+        BYTE* const opStart3 = opStart2 + segmentSize;
+        BYTE* const opStart4 = opStart3 + segmentSize;
+        BYTE* op1 = ostart;
+        BYTE* op2 = opStart2;
+        BYTE* op3 = opStart3;
+        BYTE* op4 = opStart4;
+        U32 endSignal;
+        DTableDesc const dtd = HUF_getDTableDesc(DTable);
+        U32 const dtLog = dtd.tableLog;
+
+        if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
+        CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
+        CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
+        CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
+        CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
+
+        /* 16-32 symbols per loop (4-8 symbols per stream) */
+        endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
+        for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) {
+            HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+            HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+            HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+            HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+            HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
+            HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
+            HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
+            HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
+            HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+            HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+            HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+            HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+            HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
+            HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
+            HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
+            HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
+
+            endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
+        }
+
+        /* check corruption */
+        if (op1 > opStart2) return ERROR(corruption_detected);
+        if (op2 > opStart3) return ERROR(corruption_detected);
+        if (op3 > opStart4) return ERROR(corruption_detected);
+        /* note : op4 already verified within main loop */
+
+        /* finish bitStreams one by one */
+        HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
+        HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
+        HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
+        HUF_decodeStreamX2(op4, &bitD4, oend,     dt, dtLog);
+
+        /* check */
+        { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+          if (!endCheck) return ERROR(corruption_detected); }
+
+        /* decoded size */
+        return dstSize;
+    }
+}
+
+HUF_DGEN(HUF_decompress1X2_usingDTable_internal)
+HUF_DGEN(HUF_decompress4X2_usingDTable_internal)
+
+size_t HUF_decompress1X2_usingDTable(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    DTableDesc dtd = HUF_getDTableDesc(DTable);
+    if (dtd.tableType != 1) return ERROR(GENERIC);
+    return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
+                                   const void* cSrc, size_t cSrcSize,
+                                   void* workSpace, size_t wkspSize)
+{
+    const BYTE* ip = (const BYTE*) cSrc;
+
+    size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize,
+                                               workSpace, wkspSize);
+    if (HUF_isError(hSize)) return hSize;
+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+    ip += hSize; cSrcSize -= hSize;
+
+    return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+                              const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+size_t HUF_decompress4X2_usingDTable(
+          void* dst,  size_t dstSize,
+    const void* cSrc, size_t cSrcSize,
+    const HUF_DTable* DTable)
+{
+    DTableDesc dtd = HUF_getDTableDesc(DTable);
+    if (dtd.tableType != 1) return ERROR(GENERIC);
+    return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
+                                   const void* cSrc, size_t cSrcSize,
+                                   void* workSpace, size_t wkspSize, int bmi2)
+{
+    const BYTE* ip = (const BYTE*) cSrc;
+
+    size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize,
+                                         workSpace, wkspSize);
+    if (HUF_isError(hSize)) return hSize;
+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+    ip += hSize; cSrcSize -= hSize;
+
+    return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+                                   const void* cSrc, size_t cSrcSize,
+                                   void* workSpace, size_t wkspSize)
+{
+    return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+                              const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+#endif /* HUF_FORCE_DECOMPRESS_X1 */
+
+
+/* ***********************************/
+/* Universal decompression selectors */
+/* ***********************************/
+
+size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
+                                    const void* cSrc, size_t cSrcSize,
+                                    const HUF_DTable* DTable)
+{
+    DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+    (void)dtd;
+    assert(dtd.tableType == 0);
+    return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+    (void)dtd;
+    assert(dtd.tableType == 1);
+    return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#else
+    return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
+                           HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#endif
+}
+
+size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
+                                    const void* cSrc, size_t cSrcSize,
+                                    const HUF_DTable* DTable)
+{
+    DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+    (void)dtd;
+    assert(dtd.tableType == 0);
+    return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+    (void)dtd;
+    assert(dtd.tableType == 1);
+    return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#else
+    return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
+                           HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#endif
+}
+
+
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
+static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
+{
+    /* single, double, quad */
+    {{0,0}, {1,1}, {2,2}},  /* Q==0 : impossible */
+    {{0,0}, {1,1}, {2,2}},  /* Q==1 : impossible */
+    {{  38,130}, {1313, 74}, {2151, 38}},   /* Q == 2 : 12-18% */
+    {{ 448,128}, {1353, 74}, {2238, 41}},   /* Q == 3 : 18-25% */
+    {{ 556,128}, {1353, 74}, {2238, 47}},   /* Q == 4 : 25-32% */
+    {{ 714,128}, {1418, 74}, {2436, 53}},   /* Q == 5 : 32-38% */
+    {{ 883,128}, {1437, 74}, {2464, 61}},   /* Q == 6 : 38-44% */
+    {{ 897,128}, {1515, 75}, {2622, 68}},   /* Q == 7 : 44-50% */
+    {{ 926,128}, {1613, 75}, {2730, 75}},   /* Q == 8 : 50-56% */
+    {{ 947,128}, {1729, 77}, {3359, 77}},   /* Q == 9 : 56-62% */
+    {{1107,128}, {2083, 81}, {4006, 84}},   /* Q ==10 : 62-69% */
+    {{1177,128}, {2379, 87}, {4785, 88}},   /* Q ==11 : 69-75% */
+    {{1242,128}, {2415, 93}, {5155, 84}},   /* Q ==12 : 75-81% */
+    {{1349,128}, {2644,106}, {5260,106}},   /* Q ==13 : 81-87% */
+    {{1455,128}, {2422,124}, {4174,124}},   /* Q ==14 : 87-93% */
+    {{ 722,128}, {1891,145}, {1936,146}},   /* Q ==15 : 93-99% */
+};
+#endif
+
+/** HUF_selectDecoder() :
+ *  Tells which decoder is likely to decode faster,
+ *  based on a set of pre-computed metrics.
+ * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
+ *  Assumption : 0 < dstSize <= 128 KB */
+U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
+{
+    assert(dstSize > 0);
+    assert(dstSize <= 128*1024);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+    (void)dstSize;
+    (void)cSrcSize;
+    return 0;
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+    (void)dstSize;
+    (void)cSrcSize;
+    return 1;
+#else
+    /* decoder timing evaluation */
+    {   U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize);   /* Q < 16 */
+        U32 const D256 = (U32)(dstSize >> 8);
+        U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
+        U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
+        DTime1 += DTime1 >> 3;  /* advantage to algorithm using less memory, to reduce cache eviction */
+        return DTime1 < DTime0;
+    }
+#endif
+}
+
+
+typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+
+size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+    static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
+#endif
+
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
+    if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
+    if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);
+#else
+        return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
+#endif
+    }
+}
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
+    if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
+    if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#else
+        return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
+                        HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+#endif
+    }
+}
+
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                         workSpace, sizeof(workSpace));
+}
+
+
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst,
+                                     size_t dstSize, const void* cSrc,
+                                     size_t cSrcSize, void* workSpace,
+                                     size_t wkspSize)
+{
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize == 0) return ERROR(corruption_detected);
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#else
+        return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+                            cSrcSize, workSpace, wkspSize):
+                        HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#endif
+    }
+}
+
+size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+                                  const void* cSrc, size_t cSrcSize,
+                                  void* workSpace, size_t wkspSize)
+{
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
+    if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
+    if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
+                                cSrcSize, workSpace, wkspSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+                                cSrcSize, workSpace, wkspSize);
+#else
+        return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+                                cSrcSize, workSpace, wkspSize):
+                        HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
+                                cSrcSize, workSpace, wkspSize);
+#endif
+    }
+}
+
+size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+                             const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                      workSpace, sizeof(workSpace));
+}
+
+
+size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
+{
+    DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+    (void)dtd;
+    assert(dtd.tableType == 0);
+    return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+    (void)dtd;
+    assert(dtd.tableType == 1);
+    return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#else
+    return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
+                           HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#endif
+}
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
+    const BYTE* ip = (const BYTE*) cSrc;
+
+    size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize);
+    if (HUF_isError(hSize)) return hSize;
+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+    ip += hSize; cSrcSize -= hSize;
+
+    return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+#endif
+
+size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
+{
+    DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+    (void)dtd;
+    assert(dtd.tableType == 0);
+    return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+    (void)dtd;
+    assert(dtd.tableType == 1);
+    return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#else
+    return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
+                           HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#endif
+}
+
+size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize == 0) return ERROR(corruption_detected);
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#else
+        return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) :
+                        HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#endif
+    }
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_ddict.c b/Utilities/cmzstd/lib/decompress/zstd_ddict.c
new file mode 100644
index 0000000..2ad0440
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_ddict.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* zstd_ddict.c :
+ * concentrates all logic that needs to know the internals of ZSTD_DDict object */
+
+/*-*******************************************************
+*  Dependencies
+*********************************************************/
+#include <string.h>      /* memcpy, memmove, memset */
+#include "cpu.h"         /* bmi2 */
+#include "mem.h"         /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_decompress_internal.h"
+#include "zstd_ddict.h"
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+#  include "zstd_legacy.h"
+#endif
+
+
+
+/*-*******************************************************
+*  Types
+*********************************************************/
+struct ZSTD_DDict_s {
+    void* dictBuffer;
+    const void* dictContent;
+    size_t dictSize;
+    ZSTD_entropyDTables_t entropy;
+    U32 dictID;
+    U32 entropyPresent;
+    ZSTD_customMem cMem;
+};  /* typedef'd to ZSTD_DDict within "zstd.h" */
+
+const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict)
+{
+    assert(ddict != NULL);
+    return ddict->dictContent;
+}
+
+size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict)
+{
+    assert(ddict != NULL);
+    return ddict->dictSize;
+}
+
+void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+    DEBUGLOG(4, "ZSTD_copyDDictParameters");
+    assert(dctx != NULL);
+    assert(ddict != NULL);
+    dctx->dictID = ddict->dictID;
+    dctx->prefixStart = ddict->dictContent;
+    dctx->virtualStart = ddict->dictContent;
+    dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
+    dctx->previousDstEnd = dctx->dictEnd;
+    if (ddict->entropyPresent) {
+        dctx->litEntropy = 1;
+        dctx->fseEntropy = 1;
+        dctx->LLTptr = ddict->entropy.LLTable;
+        dctx->MLTptr = ddict->entropy.MLTable;
+        dctx->OFTptr = ddict->entropy.OFTable;
+        dctx->HUFptr = ddict->entropy.hufTable;
+        dctx->entropy.rep[0] = ddict->entropy.rep[0];
+        dctx->entropy.rep[1] = ddict->entropy.rep[1];
+        dctx->entropy.rep[2] = ddict->entropy.rep[2];
+    } else {
+        dctx->litEntropy = 0;
+        dctx->fseEntropy = 0;
+    }
+}
+
+
+static size_t
+ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,
+                           ZSTD_dictContentType_e dictContentType)
+{
+    ddict->dictID = 0;
+    ddict->entropyPresent = 0;
+    if (dictContentType == ZSTD_dct_rawContent) return 0;
+
+    if (ddict->dictSize < 8) {
+        if (dictContentType == ZSTD_dct_fullDict)
+            return ERROR(dictionary_corrupted);   /* only accept specified dictionaries */
+        return 0;   /* pure content mode */
+    }
+    {   U32 const magic = MEM_readLE32(ddict->dictContent);
+        if (magic != ZSTD_MAGIC_DICTIONARY) {
+            if (dictContentType == ZSTD_dct_fullDict)
+                return ERROR(dictionary_corrupted);   /* only accept specified dictionaries */
+            return 0;   /* pure content mode */
+        }
+    }
+    ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE);
+
+    /* load entropy tables */
+    CHECK_E( ZSTD_loadDEntropy(&ddict->entropy,
+                                ddict->dictContent, ddict->dictSize),
+             dictionary_corrupted );
+    ddict->entropyPresent = 1;
+    return 0;
+}
+
+
+static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
+                                      const void* dict, size_t dictSize,
+                                      ZSTD_dictLoadMethod_e dictLoadMethod,
+                                      ZSTD_dictContentType_e dictContentType)
+{
+    if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
+        ddict->dictBuffer = NULL;
+        ddict->dictContent = dict;
+        if (!dict) dictSize = 0;
+    } else {
+        void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);
+        ddict->dictBuffer = internalBuffer;
+        ddict->dictContent = internalBuffer;
+        if (!internalBuffer) return ERROR(memory_allocation);
+        memcpy(internalBuffer, dict, dictSize);
+    }
+    ddict->dictSize = dictSize;
+    ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */
+
+    /* parse dictionary content */
+    CHECK_F( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) );
+
+    return 0;
+}
+
+ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
+                                      ZSTD_dictLoadMethod_e dictLoadMethod,
+                                      ZSTD_dictContentType_e dictContentType,
+                                      ZSTD_customMem customMem)
+{
+    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+    {   ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
+        if (ddict == NULL) return NULL;
+        ddict->cMem = customMem;
+        {   size_t const initResult = ZSTD_initDDict_internal(ddict,
+                                            dict, dictSize,
+                                            dictLoadMethod, dictContentType);
+            if (ZSTD_isError(initResult)) {
+                ZSTD_freeDDict(ddict);
+                return NULL;
+        }   }
+        return ddict;
+    }
+}
+
+/*! ZSTD_createDDict() :
+*   Create a digested dictionary, to start decompression without startup delay.
+*   `dict` content is copied inside DDict.
+*   Consequently, `dict` can be released after `ZSTD_DDict` creation */
+ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
+{
+    ZSTD_customMem const allocator = { NULL, NULL, NULL };
+    return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);
+}
+
+/*! ZSTD_createDDict_byReference() :
+ *  Create a digested dictionary, to start decompression without startup delay.
+ *  Dictionary content is simply referenced, it will be accessed during decompression.
+ *  Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */
+ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
+{
+    ZSTD_customMem const allocator = { NULL, NULL, NULL };
+    return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);
+}
+
+
+const ZSTD_DDict* ZSTD_initStaticDDict(
+                                void* sBuffer, size_t sBufferSize,
+                                const void* dict, size_t dictSize,
+                                ZSTD_dictLoadMethod_e dictLoadMethod,
+                                ZSTD_dictContentType_e dictContentType)
+{
+    size_t const neededSpace = sizeof(ZSTD_DDict)
+                             + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+    ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer;
+    assert(sBuffer != NULL);
+    assert(dict != NULL);
+    if ((size_t)sBuffer & 7) return NULL;   /* 8-aligned */
+    if (sBufferSize < neededSpace) return NULL;
+    if (dictLoadMethod == ZSTD_dlm_byCopy) {
+        memcpy(ddict+1, dict, dictSize);  /* local copy */
+        dict = ddict+1;
+    }
+    if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
+                                              dict, dictSize,
+                                              ZSTD_dlm_byRef, dictContentType) ))
+        return NULL;
+    return ddict;
+}
+
+
+size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
+{
+    if (ddict==NULL) return 0;   /* support free on NULL */
+    {   ZSTD_customMem const cMem = ddict->cMem;
+        ZSTD_free(ddict->dictBuffer, cMem);
+        ZSTD_free(ddict, cMem);
+        return 0;
+    }
+}
+
+/*! ZSTD_estimateDDictSize() :
+ *  Estimate amount of memory that will be needed to create a dictionary for decompression.
+ *  Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */
+size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
+{
+    return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+}
+
+size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
+{
+    if (ddict==NULL) return 0;   /* support sizeof on NULL */
+    return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ;
+}
+
+/*! ZSTD_getDictID_fromDDict() :
+ *  Provides the dictID of the dictionary loaded into `ddict`.
+ *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
+{
+    if (ddict==NULL) return 0;
+    return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_ddict.h b/Utilities/cmzstd/lib/decompress/zstd_ddict.h
new file mode 100644
index 0000000..0479d11
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_ddict.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+#ifndef ZSTD_DDICT_H
+#define ZSTD_DDICT_H
+
+/*-*******************************************************
+ *  Dependencies
+ *********************************************************/
+#include <stddef.h>   /* size_t */
+#include "zstd.h"     /* ZSTD_DDict, and several public functions */
+
+
+/*-*******************************************************
+ *  Interface
+ *********************************************************/
+
+/* note: several prototypes are already published in `zstd.h` :
+ * ZSTD_createDDict()
+ * ZSTD_createDDict_byReference()
+ * ZSTD_createDDict_advanced()
+ * ZSTD_freeDDict()
+ * ZSTD_initStaticDDict()
+ * ZSTD_sizeof_DDict()
+ * ZSTD_estimateDDictSize()
+ * ZSTD_getDictID_fromDict()
+ */
+
+const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict);
+size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict);
+
+void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+
+
+#endif /* ZSTD_DDICT_H */
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress.c b/Utilities/cmzstd/lib/decompress/zstd_decompress.c
new file mode 100644
index 0000000..feef1ef
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress.c
@@ -0,0 +1,1672 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ***************************************************************
+*  Tuning parameters
+*****************************************************************/
+/*!
+ * HEAPMODE :
+ * Select how default decompression function ZSTD_decompress() allocates its context,
+ * on stack (0), or into heap (1, default; requires malloc()).
+ * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
+ */
+#ifndef ZSTD_HEAPMODE
+#  define ZSTD_HEAPMODE 1
+#endif
+
+/*!
+*  LEGACY_SUPPORT :
+*  if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
+*/
+#ifndef ZSTD_LEGACY_SUPPORT
+#  define ZSTD_LEGACY_SUPPORT 0
+#endif
+
+/*!
+ *  MAXWINDOWSIZE_DEFAULT :
+ *  maximum window size accepted by DStream __by default__.
+ *  Frames requiring more memory will be rejected.
+ *  It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
+ */
+#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
+#  define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
+#endif
+
+/*!
+ *  NO_FORWARD_PROGRESS_MAX :
+ *  maximum allowed nb of calls to ZSTD_decompressStream()
+ *  without any forward progress
+ *  (defined as: no byte read from input, and no byte flushed to output)
+ *  before triggering an error.
+ */
+#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
+#  define ZSTD_NO_FORWARD_PROGRESS_MAX 16
+#endif
+
+
+/*-*******************************************************
+*  Dependencies
+*********************************************************/
+#include <string.h>      /* memcpy, memmove, memset */
+#include "cpu.h"         /* bmi2 */
+#include "mem.h"         /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_internal.h"  /* blockProperties_t */
+#include "zstd_decompress_internal.h"   /* ZSTD_DCtx */
+#include "zstd_ddict.h"  /* ZSTD_DDictDictContent */
+#include "zstd_decompress_block.h"   /* ZSTD_decompressBlock_internal */
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+#  include "zstd_legacy.h"
+#endif
+
+
+/*-*************************************************************
+*   Context management
+***************************************************************/
+size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
+{
+    if (dctx==NULL) return 0;   /* support sizeof NULL */
+    return sizeof(*dctx)
+           + ZSTD_sizeof_DDict(dctx->ddictLocal)
+           + dctx->inBuffSize + dctx->outBuffSize;
+}
+
+size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
+
+
+static size_t ZSTD_startingInputLength(ZSTD_format_e format)
+{
+    size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ?
+                    ZSTD_FRAMEHEADERSIZE_PREFIX - ZSTD_FRAMEIDSIZE :
+                    ZSTD_FRAMEHEADERSIZE_PREFIX;
+    ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE);
+    /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
+    assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
+    return startingInputLength;
+}
+
+static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
+{
+    dctx->format = ZSTD_f_zstd1;  /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
+    dctx->staticSize  = 0;
+    dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+    dctx->ddict       = NULL;
+    dctx->ddictLocal  = NULL;
+    dctx->dictEnd     = NULL;
+    dctx->ddictIsCold = 0;
+    dctx->inBuff      = NULL;
+    dctx->inBuffSize  = 0;
+    dctx->outBuffSize = 0;
+    dctx->streamStage = zdss_init;
+    dctx->legacyContext = NULL;
+    dctx->previousLegacyVersion = 0;
+    dctx->noForwardProgress = 0;
+    dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+}
+
+ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
+{
+    ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
+
+    if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
+    if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL;  /* minimum size */
+
+    ZSTD_initDCtx_internal(dctx);
+    dctx->staticSize = workspaceSize;
+    dctx->inBuff = (char*)(dctx+1);
+    return dctx;
+}
+
+ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
+{
+    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+    {   ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
+        if (!dctx) return NULL;
+        dctx->customMem = customMem;
+        ZSTD_initDCtx_internal(dctx);
+        return dctx;
+    }
+}
+
+ZSTD_DCtx* ZSTD_createDCtx(void)
+{
+    DEBUGLOG(3, "ZSTD_createDCtx");
+    return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
+{
+    if (dctx==NULL) return 0;   /* support free on NULL */
+    if (dctx->staticSize) return ERROR(memory_allocation);   /* not compatible with static DCtx */
+    {   ZSTD_customMem const cMem = dctx->customMem;
+        ZSTD_freeDDict(dctx->ddictLocal);
+        dctx->ddictLocal = NULL;
+        ZSTD_free(dctx->inBuff, cMem);
+        dctx->inBuff = NULL;
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+        if (dctx->legacyContext)
+            ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
+#endif
+        ZSTD_free(dctx, cMem);
+        return 0;
+    }
+}
+
+/* no longer useful */
+void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
+{
+    size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
+    memcpy(dstDCtx, srcDCtx, toCopy);  /* no need to copy workspace */
+}
+
+
+/*-*************************************************************
+ *   Frame header decoding
+ ***************************************************************/
+
+/*! ZSTD_isFrame() :
+ *  Tells if the content of `buffer` starts with a valid Frame Identifier.
+ *  Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
+ *  Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
+ *  Note 3 : Skippable Frame Identifiers are considered valid. */
+unsigned ZSTD_isFrame(const void* buffer, size_t size)
+{
+    if (size < ZSTD_FRAMEIDSIZE) return 0;
+    {   U32 const magic = MEM_readLE32(buffer);
+        if (magic == ZSTD_MAGICNUMBER) return 1;
+        if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
+    }
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+    if (ZSTD_isLegacy(buffer, size)) return 1;
+#endif
+    return 0;
+}
+
+/** ZSTD_frameHeaderSize_internal() :
+ *  srcSize must be large enough to reach header size fields.
+ *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
+ * @return : size of the Frame Header
+ *           or an error code, which can be tested with ZSTD_isError() */
+static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
+{
+    size_t const minInputSize = ZSTD_startingInputLength(format);
+    if (srcSize < minInputSize) return ERROR(srcSize_wrong);
+
+    {   BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
+        U32 const dictID= fhd & 3;
+        U32 const singleSegment = (fhd >> 5) & 1;
+        U32 const fcsId = fhd >> 6;
+        return minInputSize + !singleSegment
+             + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
+             + (singleSegment && !fcsId);
+    }
+}
+
+/** ZSTD_frameHeaderSize() :
+ *  srcSize must be >= ZSTD_frameHeaderSize_prefix.
+ * @return : size of the Frame Header,
+ *           or an error code (if srcSize is too small) */
+size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
+{
+    return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
+}
+
+
+/** ZSTD_getFrameHeader_advanced() :
+ *  decode Frame Header, or require larger `srcSize`.
+ *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
+ * @return : 0, `zfhPtr` is correctly filled,
+ *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ *           or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
+{
+    const BYTE* ip = (const BYTE*)src;
+    size_t const minInputSize = ZSTD_startingInputLength(format);
+
+    memset(zfhPtr, 0, sizeof(*zfhPtr));   /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
+    if (srcSize < minInputSize) return minInputSize;
+    if (src==NULL) return ERROR(GENERIC);   /* invalid parameter */
+
+    if ( (format != ZSTD_f_zstd1_magicless)
+      && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
+        if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+            /* skippable frame */
+            if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
+                return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
+            memset(zfhPtr, 0, sizeof(*zfhPtr));
+            zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
+            zfhPtr->frameType = ZSTD_skippableFrame;
+            return 0;
+        }
+        return ERROR(prefix_unknown);
+    }
+
+    /* ensure there is enough `srcSize` to fully read/decode frame header */
+    {   size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
+        if (srcSize < fhsize) return fhsize;
+        zfhPtr->headerSize = (U32)fhsize;
+    }
+
+    {   BYTE const fhdByte = ip[minInputSize-1];
+        size_t pos = minInputSize;
+        U32 const dictIDSizeCode = fhdByte&3;
+        U32 const checksumFlag = (fhdByte>>2)&1;
+        U32 const singleSegment = (fhdByte>>5)&1;
+        U32 const fcsID = fhdByte>>6;
+        U64 windowSize = 0;
+        U32 dictID = 0;
+        U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
+        if ((fhdByte & 0x08) != 0)
+            return ERROR(frameParameter_unsupported); /* reserved bits, must be zero */
+
+        if (!singleSegment) {
+            BYTE const wlByte = ip[pos++];
+            U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
+            if (windowLog > ZSTD_WINDOWLOG_MAX)
+                return ERROR(frameParameter_windowTooLarge);
+            windowSize = (1ULL << windowLog);
+            windowSize += (windowSize >> 3) * (wlByte&7);
+        }
+        switch(dictIDSizeCode)
+        {
+            default: assert(0);  /* impossible */
+            case 0 : break;
+            case 1 : dictID = ip[pos]; pos++; break;
+            case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
+            case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
+        }
+        switch(fcsID)
+        {
+            default: assert(0);  /* impossible */
+            case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
+            case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
+            case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
+            case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
+        }
+        if (singleSegment) windowSize = frameContentSize;
+
+        zfhPtr->frameType = ZSTD_frame;
+        zfhPtr->frameContentSize = frameContentSize;
+        zfhPtr->windowSize = windowSize;
+        zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+        zfhPtr->dictID = dictID;
+        zfhPtr->checksumFlag = checksumFlag;
+    }
+    return 0;
+}
+
+/** ZSTD_getFrameHeader() :
+ *  decode Frame Header, or require larger `srcSize`.
+ *  note : this function does not consume input, it only reads it.
+ * @return : 0, `zfhPtr` is correctly filled,
+ *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ *           or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
+{
+    return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
+}
+
+
+/** ZSTD_getFrameContentSize() :
+ *  compatible with legacy mode
+ * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
+ *         - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
+ *         - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
+unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
+{
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+    if (ZSTD_isLegacy(src, srcSize)) {
+        unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);
+        return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;
+    }
+#endif
+    {   ZSTD_frameHeader zfh;
+        if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
+            return ZSTD_CONTENTSIZE_ERROR;
+        if (zfh.frameType == ZSTD_skippableFrame) {
+            return 0;
+        } else {
+            return zfh.frameContentSize;
+    }   }
+}
+
+static size_t readSkippableFrameSize(void const* src, size_t srcSize)
+{
+    size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
+    U32 sizeU32;
+
+    if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
+        return ERROR(srcSize_wrong);
+
+    sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
+    if ((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32)
+        return ERROR(frameParameter_unsupported);
+
+    return skippableHeaderSize + sizeU32;
+}
+
+/** ZSTD_findDecompressedSize() :
+ *  compatible with legacy mode
+ *  `srcSize` must be the exact length of some number of ZSTD compressed and/or
+ *      skippable frames
+ *  @return : decompressed size of the frames contained */
+unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
+{
+    unsigned long long totalDstSize = 0;
+
+    while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
+        U32 const magicNumber = MEM_readLE32(src);
+
+        if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+            size_t const skippableSize = readSkippableFrameSize(src, srcSize);
+            if (ZSTD_isError(skippableSize))
+                return skippableSize;
+            if (srcSize < skippableSize) {
+                return ZSTD_CONTENTSIZE_ERROR;
+            }
+
+            src = (const BYTE *)src + skippableSize;
+            srcSize -= skippableSize;
+            continue;
+        }
+
+        {   unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
+            if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
+
+            /* check for overflow */
+            if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
+            totalDstSize += ret;
+        }
+        {   size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
+            if (ZSTD_isError(frameSrcSize)) {
+                return ZSTD_CONTENTSIZE_ERROR;
+            }
+
+            src = (const BYTE *)src + frameSrcSize;
+            srcSize -= frameSrcSize;
+        }
+    }  /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
+
+    if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
+
+    return totalDstSize;
+}
+
+/** ZSTD_getDecompressedSize() :
+ *  compatible with legacy mode
+ * @return : decompressed size if known, 0 otherwise
+             note : 0 can mean any of the following :
+                   - frame content is empty
+                   - decompressed size field is not present in frame header
+                   - frame header unknown / not supported
+                   - frame header not complete (`srcSize` too small) */
+unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
+{
+    unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
+    ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
+    return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
+}
+
+
+/** ZSTD_decodeFrameHeader() :
+ * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
+ * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
+static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
+{
+    size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
+    if (ZSTD_isError(result)) return result;    /* invalid header */
+    if (result>0) return ERROR(srcSize_wrong);  /* headerSize too small */
+    if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
+        return ERROR(dictionary_wrong);
+    if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
+    return 0;
+}
+
+
+/** ZSTD_findFrameCompressedSize() :
+ *  compatible with legacy mode
+ *  `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
+ *  `srcSize` must be at least as large as the frame contained
+ *  @return : the compressed size of the frame starting at `src` */
+size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
+{
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+    if (ZSTD_isLegacy(src, srcSize))
+        return ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
+#endif
+    if ( (srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
+      && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START ) {
+        return readSkippableFrameSize(src, srcSize);
+    } else {
+        const BYTE* ip = (const BYTE*)src;
+        const BYTE* const ipstart = ip;
+        size_t remainingSize = srcSize;
+        ZSTD_frameHeader zfh;
+
+        /* Extract Frame Header */
+        {   size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
+            if (ZSTD_isError(ret)) return ret;
+            if (ret > 0) return ERROR(srcSize_wrong);
+        }
+
+        ip += zfh.headerSize;
+        remainingSize -= zfh.headerSize;
+
+        /* Loop on each block */
+        while (1) {
+            blockProperties_t blockProperties;
+            size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
+            if (ZSTD_isError(cBlockSize)) return cBlockSize;
+
+            if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
+                return ERROR(srcSize_wrong);
+
+            ip += ZSTD_blockHeaderSize + cBlockSize;
+            remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
+
+            if (blockProperties.lastBlock) break;
+        }
+
+        if (zfh.checksumFlag) {   /* Final frame content checksum */
+            if (remainingSize < 4) return ERROR(srcSize_wrong);
+            ip += 4;
+        }
+
+        return ip - ipstart;
+    }
+}
+
+
+
+/*-*************************************************************
+ *   Frame decoding
+ ***************************************************************/
+
+
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
+{
+    if (dst != dctx->previousDstEnd) {   /* not contiguous */
+        dctx->dictEnd = dctx->previousDstEnd;
+        dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
+        dctx->prefixStart = dst;
+        dctx->previousDstEnd = dst;
+    }
+}
+
+/** ZSTD_insertBlock() :
+    insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
+size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
+{
+    ZSTD_checkContinuity(dctx, blockStart);
+    dctx->previousDstEnd = (const char*)blockStart + blockSize;
+    return blockSize;
+}
+
+
+static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
+                          const void* src, size_t srcSize)
+{
+    DEBUGLOG(5, "ZSTD_copyRawBlock");
+    if (dst == NULL) {
+        if (srcSize == 0) return 0;
+        return ERROR(dstBuffer_null);
+    }
+    if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall);
+    memcpy(dst, src, srcSize);
+    return srcSize;
+}
+
+static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
+                               BYTE b,
+                               size_t regenSize)
+{
+    if (dst == NULL) {
+        if (regenSize == 0) return 0;
+        return ERROR(dstBuffer_null);
+    }
+    if (regenSize > dstCapacity) return ERROR(dstSize_tooSmall);
+    memset(dst, b, regenSize);
+    return regenSize;
+}
+
+
+/*! ZSTD_decompressFrame() :
+ * @dctx must be properly initialized
+ *  will update *srcPtr and *srcSizePtr,
+ *  to make *srcPtr progress by one frame. */
+static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
+                                   void* dst, size_t dstCapacity,
+                             const void** srcPtr, size_t *srcSizePtr)
+{
+    const BYTE* ip = (const BYTE*)(*srcPtr);
+    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const oend = ostart + dstCapacity;
+    BYTE* op = ostart;
+    size_t remainingSrcSize = *srcSizePtr;
+
+    DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);
+
+    /* check */
+    if (remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN+ZSTD_blockHeaderSize)
+        return ERROR(srcSize_wrong);
+
+    /* Frame Header */
+    {   size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_FRAMEHEADERSIZE_PREFIX);
+        if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
+        if (remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize)
+            return ERROR(srcSize_wrong);
+        CHECK_F( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) );
+        ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
+    }
+
+    /* Loop on each block */
+    while (1) {
+        size_t decodedSize;
+        blockProperties_t blockProperties;
+        size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
+        if (ZSTD_isError(cBlockSize)) return cBlockSize;
+
+        ip += ZSTD_blockHeaderSize;
+        remainingSrcSize -= ZSTD_blockHeaderSize;
+        if (cBlockSize > remainingSrcSize) return ERROR(srcSize_wrong);
+
+        switch(blockProperties.blockType)
+        {
+        case bt_compressed:
+            decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
+            break;
+        case bt_raw :
+            decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
+            break;
+        case bt_rle :
+            decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
+            break;
+        case bt_reserved :
+        default:
+            return ERROR(corruption_detected);
+        }
+
+        if (ZSTD_isError(decodedSize)) return decodedSize;
+        if (dctx->fParams.checksumFlag)
+            XXH64_update(&dctx->xxhState, op, decodedSize);
+        op += decodedSize;
+        ip += cBlockSize;
+        remainingSrcSize -= cBlockSize;
+        if (blockProperties.lastBlock) break;
+    }
+
+    if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+        if ((U64)(op-ostart) != dctx->fParams.frameContentSize) {
+            return ERROR(corruption_detected);
+    }   }
+    if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
+        U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
+        U32 checkRead;
+        if (remainingSrcSize<4) return ERROR(checksum_wrong);
+        checkRead = MEM_readLE32(ip);
+        if (checkRead != checkCalc) return ERROR(checksum_wrong);
+        ip += 4;
+        remainingSrcSize -= 4;
+    }
+
+    /* Allow caller to get size read */
+    *srcPtr = ip;
+    *srcSizePtr = remainingSrcSize;
+    return op-ostart;
+}
+
+static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
+                                        void* dst, size_t dstCapacity,
+                                  const void* src, size_t srcSize,
+                                  const void* dict, size_t dictSize,
+                                  const ZSTD_DDict* ddict)
+{
+    void* const dststart = dst;
+    int moreThan1Frame = 0;
+
+    DEBUGLOG(5, "ZSTD_decompressMultiFrame");
+    assert(dict==NULL || ddict==NULL);  /* either dict or ddict set, not both */
+
+    if (ddict) {
+        dict = ZSTD_DDict_dictContent(ddict);
+        dictSize = ZSTD_DDict_dictSize(ddict);
+    }
+
+    while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+        if (ZSTD_isLegacy(src, srcSize)) {
+            size_t decodedSize;
+            size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
+            if (ZSTD_isError(frameSize)) return frameSize;
+            /* legacy support is not compatible with static dctx */
+            if (dctx->staticSize) return ERROR(memory_allocation);
+
+            decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
+            if (ZSTD_isError(decodedSize)) return decodedSize;
+
+            assert(decodedSize <=- dstCapacity);
+            dst = (BYTE*)dst + decodedSize;
+            dstCapacity -= decodedSize;
+
+            src = (const BYTE*)src + frameSize;
+            srcSize -= frameSize;
+
+            continue;
+        }
+#endif
+
+        {   U32 const magicNumber = MEM_readLE32(src);
+            DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
+                        (unsigned)magicNumber, ZSTD_MAGICNUMBER);
+            if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+                size_t const skippableSize = readSkippableFrameSize(src, srcSize);
+                if (ZSTD_isError(skippableSize))
+                    return skippableSize;
+                if (srcSize < skippableSize) return ERROR(srcSize_wrong);
+
+                src = (const BYTE *)src + skippableSize;
+                srcSize -= skippableSize;
+                continue;
+        }   }
+
+        if (ddict) {
+            /* we were called from ZSTD_decompress_usingDDict */
+            CHECK_F(ZSTD_decompressBegin_usingDDict(dctx, ddict));
+        } else {
+            /* this will initialize correctly with no dict if dict == NULL, so
+             * use this in all cases but ddict */
+            CHECK_F(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize));
+        }
+        ZSTD_checkContinuity(dctx, dst);
+
+        {   const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
+                                                    &src, &srcSize);
+            if ( (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
+              && (moreThan1Frame==1) ) {
+                /* at least one frame successfully completed,
+                 * but following bytes are garbage :
+                 * it's more likely to be a srcSize error,
+                 * specifying more bytes than compressed size of frame(s).
+                 * This error message replaces ERROR(prefix_unknown),
+                 * which would be confusing, as the first header is actually correct.
+                 * Note that one could be unlucky, it might be a corruption error instead,
+                 * happening right at the place where we expect zstd magic bytes.
+                 * But this is _much_ less likely than a srcSize field error. */
+                return ERROR(srcSize_wrong);
+            }
+            if (ZSTD_isError(res)) return res;
+            assert(res <= dstCapacity);
+            dst = (BYTE*)dst + res;
+            dstCapacity -= res;
+        }
+        moreThan1Frame = 1;
+    }  /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
+
+    if (srcSize) return ERROR(srcSize_wrong); /* input not entirely consumed */
+
+    return (BYTE*)dst - (BYTE*)dststart;
+}
+
+size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
+                                 void* dst, size_t dstCapacity,
+                           const void* src, size_t srcSize,
+                           const void* dict, size_t dictSize)
+{
+    return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
+}
+
+
+size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0);
+}
+
+
+size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
+    size_t regenSize;
+    ZSTD_DCtx* const dctx = ZSTD_createDCtx();
+    if (dctx==NULL) return ERROR(memory_allocation);
+    regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
+    ZSTD_freeDCtx(dctx);
+    return regenSize;
+#else   /* stack mode */
+    ZSTD_DCtx dctx;
+    ZSTD_initDCtx_internal(&dctx);
+    return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
+#endif
+}
+
+
+/*-**************************************
+*   Advanced Streaming Decompression API
+*   Bufferless and synchronous
+****************************************/
+size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
+
+ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
+    switch(dctx->stage)
+    {
+    default:   /* should not happen */
+        assert(0);
+    case ZSTDds_getFrameHeaderSize:
+    case ZSTDds_decodeFrameHeader:
+        return ZSTDnit_frameHeader;
+    case ZSTDds_decodeBlockHeader:
+        return ZSTDnit_blockHeader;
+    case ZSTDds_decompressBlock:
+        return ZSTDnit_block;
+    case ZSTDds_decompressLastBlock:
+        return ZSTDnit_lastBlock;
+    case ZSTDds_checkChecksum:
+        return ZSTDnit_checksum;
+    case ZSTDds_decodeSkippableHeader:
+    case ZSTDds_skipFrame:
+        return ZSTDnit_skippableFrame;
+    }
+}
+
+static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }
+
+/** ZSTD_decompressContinue() :
+ *  srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())
+ *  @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
+ *            or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
+    /* Sanity check */
+    if (srcSize != dctx->expected)
+        return ERROR(srcSize_wrong);  /* not allowed */
+    if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
+
+    switch (dctx->stage)
+    {
+    case ZSTDds_getFrameHeaderSize :
+        assert(src != NULL);
+        if (dctx->format == ZSTD_f_zstd1) {  /* allows header */
+            assert(srcSize >= ZSTD_FRAMEIDSIZE);  /* to read skippable magic number */
+            if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
+                memcpy(dctx->headerBuffer, src, srcSize);
+                dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize;  /* remaining to load to get full skippable frame header */
+                dctx->stage = ZSTDds_decodeSkippableHeader;
+                return 0;
+        }   }
+        dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
+        if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
+        memcpy(dctx->headerBuffer, src, srcSize);
+        dctx->expected = dctx->headerSize - srcSize;
+        dctx->stage = ZSTDds_decodeFrameHeader;
+        return 0;
+
+    case ZSTDds_decodeFrameHeader:
+        assert(src != NULL);
+        memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
+        CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
+        dctx->expected = ZSTD_blockHeaderSize;
+        dctx->stage = ZSTDds_decodeBlockHeader;
+        return 0;
+
+    case ZSTDds_decodeBlockHeader:
+        {   blockProperties_t bp;
+            size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
+            if (ZSTD_isError(cBlockSize)) return cBlockSize;
+            dctx->expected = cBlockSize;
+            dctx->bType = bp.blockType;
+            dctx->rleSize = bp.origSize;
+            if (cBlockSize) {
+                dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
+                return 0;
+            }
+            /* empty block */
+            if (bp.lastBlock) {
+                if (dctx->fParams.checksumFlag) {
+                    dctx->expected = 4;
+                    dctx->stage = ZSTDds_checkChecksum;
+                } else {
+                    dctx->expected = 0; /* end of frame */
+                    dctx->stage = ZSTDds_getFrameHeaderSize;
+                }
+            } else {
+                dctx->expected = ZSTD_blockHeaderSize;  /* jump to next header */
+                dctx->stage = ZSTDds_decodeBlockHeader;
+            }
+            return 0;
+        }
+
+    case ZSTDds_decompressLastBlock:
+    case ZSTDds_decompressBlock:
+        DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
+        {   size_t rSize;
+            switch(dctx->bType)
+            {
+            case bt_compressed:
+                DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
+                rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
+                break;
+            case bt_raw :
+                rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
+                break;
+            case bt_rle :
+                rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
+                break;
+            case bt_reserved :   /* should never happen */
+            default:
+                return ERROR(corruption_detected);
+            }
+            if (ZSTD_isError(rSize)) return rSize;
+            DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
+            dctx->decodedSize += rSize;
+            if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
+
+            if (dctx->stage == ZSTDds_decompressLastBlock) {   /* end of frame */
+                DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
+                if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+                    if (dctx->decodedSize != dctx->fParams.frameContentSize) {
+                        return ERROR(corruption_detected);
+                }   }
+                if (dctx->fParams.checksumFlag) {  /* another round for frame checksum */
+                    dctx->expected = 4;
+                    dctx->stage = ZSTDds_checkChecksum;
+                } else {
+                    dctx->expected = 0;   /* ends here */
+                    dctx->stage = ZSTDds_getFrameHeaderSize;
+                }
+            } else {
+                dctx->stage = ZSTDds_decodeBlockHeader;
+                dctx->expected = ZSTD_blockHeaderSize;
+                dctx->previousDstEnd = (char*)dst + rSize;
+            }
+            return rSize;
+        }
+
+    case ZSTDds_checkChecksum:
+        assert(srcSize == 4);  /* guaranteed by dctx->expected */
+        {   U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
+            U32 const check32 = MEM_readLE32(src);
+            DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
+            if (check32 != h32) return ERROR(checksum_wrong);
+            dctx->expected = 0;
+            dctx->stage = ZSTDds_getFrameHeaderSize;
+            return 0;
+        }
+
+    case ZSTDds_decodeSkippableHeader:
+        assert(src != NULL);
+        assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
+        memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize);   /* complete skippable header */
+        dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE);   /* note : dctx->expected can grow seriously large, beyond local buffer size */
+        dctx->stage = ZSTDds_skipFrame;
+        return 0;
+
+    case ZSTDds_skipFrame:
+        dctx->expected = 0;
+        dctx->stage = ZSTDds_getFrameHeaderSize;
+        return 0;
+
+    default:
+        assert(0);   /* impossible */
+        return ERROR(GENERIC);   /* some compiler require default to do something */
+    }
+}
+
+
+static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+    dctx->dictEnd = dctx->previousDstEnd;
+    dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
+    dctx->prefixStart = dict;
+    dctx->previousDstEnd = (const char*)dict + dictSize;
+    return 0;
+}
+
+/*! ZSTD_loadDEntropy() :
+ *  dict : must point at beginning of a valid zstd dictionary.
+ * @return : size of entropy tables read */
+size_t
+ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
+                  const void* const dict, size_t const dictSize)
+{
+    const BYTE* dictPtr = (const BYTE*)dict;
+    const BYTE* const dictEnd = dictPtr + dictSize;
+
+    if (dictSize <= 8) return ERROR(dictionary_corrupted);
+    assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY);   /* dict must be valid */
+    dictPtr += 8;   /* skip header = magic + dictID */
+
+    ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));
+    ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));
+    ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);
+    {   void* const workspace = &entropy->LLTable;   /* use fse tables as temporary workspace; implies fse tables are grouped together */
+        size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);
+#ifdef HUF_FORCE_DECOMPRESS_X1
+        /* in minimal huffman, we always use X1 variants */
+        size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
+                                                dictPtr, dictEnd - dictPtr,
+                                                workspace, workspaceSize);
+#else
+        size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
+                                                dictPtr, dictEnd - dictPtr,
+                                                workspace, workspaceSize);
+#endif
+        if (HUF_isError(hSize)) return ERROR(dictionary_corrupted);
+        dictPtr += hSize;
+    }
+
+    {   short offcodeNCount[MaxOff+1];
+        unsigned offcodeMaxValue = MaxOff, offcodeLog;
+        size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+        if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
+        if (offcodeMaxValue > MaxOff) return ERROR(dictionary_corrupted);
+        if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
+        ZSTD_buildFSETable( entropy->OFTable,
+                            offcodeNCount, offcodeMaxValue,
+                            OF_base, OF_bits,
+                            offcodeLog);
+        dictPtr += offcodeHeaderSize;
+    }
+
+    {   short matchlengthNCount[MaxML+1];
+        unsigned matchlengthMaxValue = MaxML, matchlengthLog;
+        size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+        if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
+        if (matchlengthMaxValue > MaxML) return ERROR(dictionary_corrupted);
+        if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
+        ZSTD_buildFSETable( entropy->MLTable,
+                            matchlengthNCount, matchlengthMaxValue,
+                            ML_base, ML_bits,
+                            matchlengthLog);
+        dictPtr += matchlengthHeaderSize;
+    }
+
+    {   short litlengthNCount[MaxLL+1];
+        unsigned litlengthMaxValue = MaxLL, litlengthLog;
+        size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+        if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
+        if (litlengthMaxValue > MaxLL) return ERROR(dictionary_corrupted);
+        if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
+        ZSTD_buildFSETable( entropy->LLTable,
+                            litlengthNCount, litlengthMaxValue,
+                            LL_base, LL_bits,
+                            litlengthLog);
+        dictPtr += litlengthHeaderSize;
+    }
+
+    if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
+    {   int i;
+        size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
+        for (i=0; i<3; i++) {
+            U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
+            if (rep==0 || rep >= dictContentSize) return ERROR(dictionary_corrupted);
+            entropy->rep[i] = rep;
+    }   }
+
+    return dictPtr - (const BYTE*)dict;
+}
+
+static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+    if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
+    {   U32 const magic = MEM_readLE32(dict);
+        if (magic != ZSTD_MAGIC_DICTIONARY) {
+            return ZSTD_refDictContent(dctx, dict, dictSize);   /* pure content mode */
+    }   }
+    dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
+
+    /* load entropy tables */
+    {   size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
+        if (ZSTD_isError(eSize)) return ERROR(dictionary_corrupted);
+        dict = (const char*)dict + eSize;
+        dictSize -= eSize;
+    }
+    dctx->litEntropy = dctx->fseEntropy = 1;
+
+    /* reference dictionary content */
+    return ZSTD_refDictContent(dctx, dict, dictSize);
+}
+
+size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
+{
+    assert(dctx != NULL);
+    dctx->expected = ZSTD_startingInputLength(dctx->format);  /* dctx->format must be properly set */
+    dctx->stage = ZSTDds_getFrameHeaderSize;
+    dctx->decodedSize = 0;
+    dctx->previousDstEnd = NULL;
+    dctx->prefixStart = NULL;
+    dctx->virtualStart = NULL;
+    dctx->dictEnd = NULL;
+    dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */
+    dctx->litEntropy = dctx->fseEntropy = 0;
+    dctx->dictID = 0;
+    ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
+    memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */
+    dctx->LLTptr = dctx->entropy.LLTable;
+    dctx->MLTptr = dctx->entropy.MLTable;
+    dctx->OFTptr = dctx->entropy.OFTable;
+    dctx->HUFptr = dctx->entropy.hufTable;
+    return 0;
+}
+
+size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+    CHECK_F( ZSTD_decompressBegin(dctx) );
+    if (dict && dictSize)
+        CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted);
+    return 0;
+}
+
+
+/* ======   ZSTD_DDict   ====== */
+
+size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+    DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");
+    assert(dctx != NULL);
+    if (ddict) {
+        const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);
+        size_t const dictSize = ZSTD_DDict_dictSize(ddict);
+        const void* const dictEnd = dictStart + dictSize;
+        dctx->ddictIsCold = (dctx->dictEnd != dictEnd);
+        DEBUGLOG(4, "DDict is %s",
+                    dctx->ddictIsCold ? "~cold~" : "hot!");
+    }
+    CHECK_F( ZSTD_decompressBegin(dctx) );
+    if (ddict) {   /* NULL ddict is equivalent to no dictionary */
+        ZSTD_copyDDictParameters(dctx, ddict);
+    }
+    return 0;
+}
+
+/*! ZSTD_getDictID_fromDict() :
+ *  Provides the dictID stored within dictionary.
+ *  if @return == 0, the dictionary is not conformant with Zstandard specification.
+ *  It can still be loaded, but as a content-only dictionary. */
+unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
+{
+    if (dictSize < 8) return 0;
+    if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
+    return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
+}
+
+/*! ZSTD_getDictID_fromFrame() :
+ *  Provides the dictID required to decompresse frame stored within `src`.
+ *  If @return == 0, the dictID could not be decoded.
+ *  This could for one of the following reasons :
+ *  - The frame does not require a dictionary (most common case).
+ *  - The frame was built with dictID intentionally removed.
+ *    Needed dictionary is a hidden information.
+ *    Note : this use case also happens when using a non-conformant dictionary.
+ *  - `srcSize` is too small, and as a result, frame header could not be decoded.
+ *    Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
+ *  - This is not a Zstandard frame.
+ *  When identifying the exact failure cause, it's possible to use
+ *  ZSTD_getFrameHeader(), which will provide a more precise error code. */
+unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
+{
+    ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
+    size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
+    if (ZSTD_isError(hError)) return 0;
+    return zfp.dictID;
+}
+
+
+/*! ZSTD_decompress_usingDDict() :
+*   Decompression using a pre-digested Dictionary
+*   Use dictionary without significant overhead. */
+size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
+                                  void* dst, size_t dstCapacity,
+                            const void* src, size_t srcSize,
+                            const ZSTD_DDict* ddict)
+{
+    /* pass content and size in case legacy frames are encountered */
+    return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
+                                     NULL, 0,
+                                     ddict);
+}
+
+
+/*=====================================
+*   Streaming decompression
+*====================================*/
+
+ZSTD_DStream* ZSTD_createDStream(void)
+{
+    DEBUGLOG(3, "ZSTD_createDStream");
+    return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
+}
+
+ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
+{
+    return ZSTD_initStaticDCtx(workspace, workspaceSize);
+}
+
+ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
+{
+    return ZSTD_createDCtx_advanced(customMem);
+}
+
+size_t ZSTD_freeDStream(ZSTD_DStream* zds)
+{
+    return ZSTD_freeDCtx(zds);
+}
+
+
+/* ***  Initialization  *** */
+
+size_t ZSTD_DStreamInSize(void)  { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
+size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
+
+size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
+                                   const void* dict, size_t dictSize,
+                                         ZSTD_dictLoadMethod_e dictLoadMethod,
+                                         ZSTD_dictContentType_e dictContentType)
+{
+    if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+    ZSTD_freeDDict(dctx->ddictLocal);
+    if (dict && dictSize >= 8) {
+        dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
+        if (dctx->ddictLocal == NULL) return ERROR(memory_allocation);
+    } else {
+        dctx->ddictLocal = NULL;
+    }
+    dctx->ddict = dctx->ddictLocal;
+    return 0;
+}
+
+size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+    return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
+}
+
+size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+    return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
+}
+
+size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
+{
+    return ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType);
+}
+
+size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
+{
+    return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
+}
+
+
+/* ZSTD_initDStream_usingDict() :
+ * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
+ * this function cannot fail */
+size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
+{
+    DEBUGLOG(4, "ZSTD_initDStream_usingDict");
+    zds->streamStage = zdss_init;
+    zds->noForwardProgress = 0;
+    CHECK_F( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) );
+    return ZSTD_FRAMEHEADERSIZE_PREFIX;
+}
+
+/* note : this variant can't fail */
+size_t ZSTD_initDStream(ZSTD_DStream* zds)
+{
+    DEBUGLOG(4, "ZSTD_initDStream");
+    return ZSTD_initDStream_usingDict(zds, NULL, 0);
+}
+
+/* ZSTD_initDStream_usingDDict() :
+ * ddict will just be referenced, and must outlive decompression session
+ * this function cannot fail */
+size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
+{
+    size_t const initResult = ZSTD_initDStream(dctx);
+    dctx->ddict = ddict;
+    return initResult;
+}
+
+/* ZSTD_resetDStream() :
+ * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
+ * this function cannot fail */
+size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
+{
+    DEBUGLOG(4, "ZSTD_resetDStream");
+    dctx->streamStage = zdss_loadHeader;
+    dctx->lhSize = dctx->inPos = dctx->outStart = dctx->outEnd = 0;
+    dctx->legacyVersion = 0;
+    dctx->hostageByte = 0;
+    return ZSTD_FRAMEHEADERSIZE_PREFIX;
+}
+
+
+size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+    if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+    dctx->ddict = ddict;
+    return 0;
+}
+
+/* ZSTD_DCtx_setMaxWindowSize() :
+ * note : no direct equivalence in ZSTD_DCtx_setParameter,
+ * since this version sets windowSize, and the other sets windowLog */
+size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
+{
+    ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
+    size_t const min = (size_t)1 << bounds.lowerBound;
+    size_t const max = (size_t)1 << bounds.upperBound;
+    if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+    if (maxWindowSize < min) return ERROR(parameter_outOfBound);
+    if (maxWindowSize > max) return ERROR(parameter_outOfBound);
+    dctx->maxWindowSize = maxWindowSize;
+    return 0;
+}
+
+size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
+{
+    return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
+}
+
+ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
+{
+    ZSTD_bounds bounds = { 0, 0, 0 };
+    switch(dParam) {
+        case ZSTD_d_windowLogMax:
+            bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
+            bounds.upperBound = ZSTD_WINDOWLOG_MAX;
+            return bounds;
+        case ZSTD_d_format:
+            bounds.lowerBound = (int)ZSTD_f_zstd1;
+            bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
+            ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
+            return bounds;
+        default:;
+    }
+    bounds.error = ERROR(parameter_unsupported);
+    return bounds;
+}
+
+/* ZSTD_dParam_withinBounds:
+ * @return 1 if value is within dParam bounds,
+ * 0 otherwise */
+static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
+{
+    ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);
+    if (ZSTD_isError(bounds.error)) return 0;
+    if (value < bounds.lowerBound) return 0;
+    if (value > bounds.upperBound) return 0;
+    return 1;
+}
+
+#define CHECK_DBOUNDS(p,v) {                \
+    if (!ZSTD_dParam_withinBounds(p, v))    \
+        return ERROR(parameter_outOfBound); \
+}
+
+size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
+{
+    if (dctx->streamStage != zdss_init) return ERROR(stage_wrong);
+    switch(dParam) {
+        case ZSTD_d_windowLogMax:
+            CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);
+            dctx->maxWindowSize = ((size_t)1) << value;
+            return 0;
+        case ZSTD_d_format:
+            CHECK_DBOUNDS(ZSTD_d_format, value);
+            dctx->format = (ZSTD_format_e)value;
+            return 0;
+        default:;
+    }
+    return ERROR(parameter_unsupported);
+}
+
+size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
+{
+    if ( (reset == ZSTD_reset_session_only)
+      || (reset == ZSTD_reset_session_and_parameters) ) {
+        (void)ZSTD_initDStream(dctx);
+    }
+    if ( (reset == ZSTD_reset_parameters)
+      || (reset == ZSTD_reset_session_and_parameters) ) {
+        if (dctx->streamStage != zdss_init)
+            return ERROR(stage_wrong);
+        dctx->format = ZSTD_f_zstd1;
+        dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+    }
+    return 0;
+}
+
+
+size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
+{
+    return ZSTD_sizeof_DCtx(dctx);
+}
+
+size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
+{
+    size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+    unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
+    unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
+    size_t const minRBSize = (size_t) neededSize;
+    if ((unsigned long long)minRBSize != neededSize) return ERROR(frameParameter_windowTooLarge);
+    return minRBSize;
+}
+
+size_t ZSTD_estimateDStreamSize(size_t windowSize)
+{
+    size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+    size_t const inBuffSize = blockSize;  /* no block can be larger */
+    size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
+    return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
+}
+
+size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
+{
+    U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;   /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
+    ZSTD_frameHeader zfh;
+    size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
+    if (ZSTD_isError(err)) return err;
+    if (err>0) return ERROR(srcSize_wrong);
+    if (zfh.windowSize > windowSizeMax)
+        return ERROR(frameParameter_windowTooLarge);
+    return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
+}
+
+
+/* *****   Decompression   ***** */
+
+MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+    size_t const length = MIN(dstCapacity, srcSize);
+    memcpy(dst, src, length);
+    return length;
+}
+
+
+size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+    const char* const istart = (const char*)(input->src) + input->pos;
+    const char* const iend = (const char*)(input->src) + input->size;
+    const char* ip = istart;
+    char* const ostart = (char*)(output->dst) + output->pos;
+    char* const oend = (char*)(output->dst) + output->size;
+    char* op = ostart;
+    U32 someMoreWork = 1;
+
+    DEBUGLOG(5, "ZSTD_decompressStream");
+    if (input->pos > input->size) {  /* forbidden */
+        DEBUGLOG(5, "in: pos: %u   vs size: %u",
+                    (U32)input->pos, (U32)input->size);
+        return ERROR(srcSize_wrong);
+    }
+    if (output->pos > output->size) {  /* forbidden */
+        DEBUGLOG(5, "out: pos: %u   vs size: %u",
+                    (U32)output->pos, (U32)output->size);
+        return ERROR(dstSize_tooSmall);
+    }
+    DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
+
+    while (someMoreWork) {
+        switch(zds->streamStage)
+        {
+        case zdss_init :
+            DEBUGLOG(5, "stage zdss_init => transparent reset ");
+            ZSTD_resetDStream(zds);   /* transparent reset on starting decoding a new frame */
+            /* fall-through */
+
+        case zdss_loadHeader :
+            DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+            if (zds->legacyVersion) {
+                /* legacy support is incompatible with static dctx */
+                if (zds->staticSize) return ERROR(memory_allocation);
+                {   size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
+                    if (hint==0) zds->streamStage = zdss_init;
+                    return hint;
+            }   }
+#endif
+            {   size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
+                DEBUGLOG(5, "header size : %u", (U32)hSize);
+                if (ZSTD_isError(hSize)) {
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+                    U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
+                    if (legacyVersion) {
+                        const void* const dict = zds->ddict ? ZSTD_DDict_dictContent(zds->ddict) : NULL;
+                        size_t const dictSize = zds->ddict ? ZSTD_DDict_dictSize(zds->ddict) : 0;
+                        DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
+                        /* legacy support is incompatible with static dctx */
+                        if (zds->staticSize) return ERROR(memory_allocation);
+                        CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext,
+                                    zds->previousLegacyVersion, legacyVersion,
+                                    dict, dictSize));
+                        zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
+                        {   size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
+                            if (hint==0) zds->streamStage = zdss_init;   /* or stay in stage zdss_loadHeader */
+                            return hint;
+                    }   }
+#endif
+                    return hSize;   /* error */
+                }
+                if (hSize != 0) {   /* need more input */
+                    size_t const toLoad = hSize - zds->lhSize;   /* if hSize!=0, hSize > zds->lhSize */
+                    size_t const remainingInput = (size_t)(iend-ip);
+                    assert(iend >= ip);
+                    if (toLoad > remainingInput) {   /* not enough input to load full header */
+                        if (remainingInput > 0) {
+                            memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
+                            zds->lhSize += remainingInput;
+                        }
+                        input->pos = input->size;
+                        return (MAX(ZSTD_FRAMEHEADERSIZE_MIN, hSize) - zds->lhSize) + ZSTD_blockHeaderSize;   /* remaining header bytes + next block header */
+                    }
+                    assert(ip != NULL);
+                    memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
+                    break;
+            }   }
+
+            /* check for single-pass mode opportunity */
+            if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
+                && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
+                size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
+                if (cSize <= (size_t)(iend-istart)) {
+                    /* shortcut : using single-pass mode */
+                    size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, zds->ddict);
+                    if (ZSTD_isError(decompressedSize)) return decompressedSize;
+                    DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
+                    ip = istart + cSize;
+                    op += decompressedSize;
+                    zds->expected = 0;
+                    zds->streamStage = zdss_init;
+                    someMoreWork = 0;
+                    break;
+            }   }
+
+            /* Consume header (see ZSTDds_decodeFrameHeader) */
+            DEBUGLOG(4, "Consume header");
+            CHECK_F(ZSTD_decompressBegin_usingDDict(zds, zds->ddict));
+
+            if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {  /* skippable frame */
+                zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
+                zds->stage = ZSTDds_skipFrame;
+            } else {
+                CHECK_F(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
+                zds->expected = ZSTD_blockHeaderSize;
+                zds->stage = ZSTDds_decodeBlockHeader;
+            }
+
+            /* control buffer memory usage */
+            DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",
+                        (U32)(zds->fParams.windowSize >>10),
+                        (U32)(zds->maxWindowSize >> 10) );
+            zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
+            if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
+
+            /* Adapt buffer sizes to frame header instructions */
+            {   size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
+                size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize);
+                if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) {
+                    size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
+                    DEBUGLOG(4, "inBuff  : from %u to %u",
+                                (U32)zds->inBuffSize, (U32)neededInBuffSize);
+                    DEBUGLOG(4, "outBuff : from %u to %u",
+                                (U32)zds->outBuffSize, (U32)neededOutBuffSize);
+                    if (zds->staticSize) {  /* static DCtx */
+                        DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
+                        assert(zds->staticSize >= sizeof(ZSTD_DCtx));  /* controlled at init */
+                        if (bufferSize > zds->staticSize - sizeof(ZSTD_DCtx))
+                            return ERROR(memory_allocation);
+                    } else {
+                        ZSTD_free(zds->inBuff, zds->customMem);
+                        zds->inBuffSize = 0;
+                        zds->outBuffSize = 0;
+                        zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
+                        if (zds->inBuff == NULL) return ERROR(memory_allocation);
+                    }
+                    zds->inBuffSize = neededInBuffSize;
+                    zds->outBuff = zds->inBuff + zds->inBuffSize;
+                    zds->outBuffSize = neededOutBuffSize;
+            }   }
+            zds->streamStage = zdss_read;
+            /* fall-through */
+
+        case zdss_read:
+            DEBUGLOG(5, "stage zdss_read");
+            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
+                DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
+                if (neededInSize==0) {  /* end of frame */
+                    zds->streamStage = zdss_init;
+                    someMoreWork = 0;
+                    break;
+                }
+                if ((size_t)(iend-ip) >= neededInSize) {  /* decode directly from src */
+                    int const isSkipFrame = ZSTD_isSkipFrame(zds);
+                    size_t const decodedSize = ZSTD_decompressContinue(zds,
+                        zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart),
+                        ip, neededInSize);
+                    if (ZSTD_isError(decodedSize)) return decodedSize;
+                    ip += neededInSize;
+                    if (!decodedSize && !isSkipFrame) break;   /* this was just a header */
+                    zds->outEnd = zds->outStart + decodedSize;
+                    zds->streamStage = zdss_flush;
+                    break;
+            }   }
+            if (ip==iend) { someMoreWork = 0; break; }   /* no more input */
+            zds->streamStage = zdss_load;
+            /* fall-through */
+
+        case zdss_load:
+            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
+                size_t const toLoad = neededInSize - zds->inPos;
+                int const isSkipFrame = ZSTD_isSkipFrame(zds);
+                size_t loadedSize;
+                if (isSkipFrame) {
+                    loadedSize = MIN(toLoad, (size_t)(iend-ip));
+                } else {
+                    if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected);   /* should never happen */
+                    loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
+                }
+                ip += loadedSize;
+                zds->inPos += loadedSize;
+                if (loadedSize < toLoad) { someMoreWork = 0; break; }   /* not enough input, wait for more */
+
+                /* decode loaded input */
+                {   size_t const decodedSize = ZSTD_decompressContinue(zds,
+                        zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
+                        zds->inBuff, neededInSize);
+                    if (ZSTD_isError(decodedSize)) return decodedSize;
+                    zds->inPos = 0;   /* input is consumed */
+                    if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; }   /* this was just a header */
+                    zds->outEnd = zds->outStart +  decodedSize;
+            }   }
+            zds->streamStage = zdss_flush;
+            /* fall-through */
+
+        case zdss_flush:
+            {   size_t const toFlushSize = zds->outEnd - zds->outStart;
+                size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
+                op += flushedSize;
+                zds->outStart += flushedSize;
+                if (flushedSize == toFlushSize) {  /* flush completed */
+                    zds->streamStage = zdss_read;
+                    if ( (zds->outBuffSize < zds->fParams.frameContentSize)
+                      && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
+                        DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
+                                (int)(zds->outBuffSize - zds->outStart),
+                                (U32)zds->fParams.blockSizeMax);
+                        zds->outStart = zds->outEnd = 0;
+                    }
+                    break;
+            }   }
+            /* cannot complete flush */
+            someMoreWork = 0;
+            break;
+
+        default:
+            assert(0);    /* impossible */
+            return ERROR(GENERIC);   /* some compiler require default to do something */
+    }   }
+
+    /* result */
+    input->pos = (size_t)(ip - (const char*)(input->src));
+    output->pos = (size_t)(op - (char*)(output->dst));
+    if ((ip==istart) && (op==ostart)) {  /* no forward progress */
+        zds->noForwardProgress ++;
+        if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
+            if (op==oend) return ERROR(dstSize_tooSmall);
+            if (ip==iend) return ERROR(srcSize_wrong);
+            assert(0);
+        }
+    } else {
+        zds->noForwardProgress = 0;
+    }
+    {   size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
+        if (!nextSrcSizeHint) {   /* frame fully decoded */
+            if (zds->outEnd == zds->outStart) {  /* output fully flushed */
+                if (zds->hostageByte) {
+                    if (input->pos >= input->size) {
+                        /* can't release hostage (not present) */
+                        zds->streamStage = zdss_read;
+                        return 1;
+                    }
+                    input->pos++;  /* release hostage */
+                }   /* zds->hostageByte */
+                return 0;
+            }  /* zds->outEnd == zds->outStart */
+            if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
+                input->pos--;   /* note : pos > 0, otherwise, impossible to finish reading last block */
+                zds->hostageByte=1;
+            }
+            return 1;
+        }  /* nextSrcSizeHint==0 */
+        nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block);   /* preload header of next block */
+        assert(zds->inPos <= nextSrcSizeHint);
+        nextSrcSizeHint -= zds->inPos;   /* part already loaded*/
+        return nextSrcSizeHint;
+    }
+}
+
+size_t ZSTD_decompressStream_simpleArgs (
+                            ZSTD_DCtx* dctx,
+                            void* dst, size_t dstCapacity, size_t* dstPos,
+                      const void* src, size_t srcSize, size_t* srcPos)
+{
+    ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
+    ZSTD_inBuffer  input  = { src, srcSize, *srcPos };
+    /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
+    size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
+    *dstPos = output.pos;
+    *srcPos = input.pos;
+    return cErr;
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress_block.c b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.c
new file mode 100644
index 0000000..32baad9
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.c
@@ -0,0 +1,1307 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* zstd_decompress_block :
+ * this module takes care of decompressing _compressed_ block */
+
+/*-*******************************************************
+*  Dependencies
+*********************************************************/
+#include <string.h>      /* memcpy, memmove, memset */
+#include "compiler.h"    /* prefetch */
+#include "cpu.h"         /* bmi2 */
+#include "mem.h"         /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#include "zstd_internal.h"
+#include "zstd_decompress_internal.h"   /* ZSTD_DCtx */
+#include "zstd_ddict.h"  /* ZSTD_DDictDictContent */
+#include "zstd_decompress_block.h"
+
+/*_*******************************************************
+*  Macros
+**********************************************************/
+
+/* These two optional macros force the use one way or another of the two
+ * ZSTD_decompressSequences implementations. You can't force in both directions
+ * at the same time.
+ */
+#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+    defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!"
+#endif
+
+
+/*_*******************************************************
+*  Memory operations
+**********************************************************/
+static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
+
+
+/*-*************************************************************
+ *   Block decoding
+ ***************************************************************/
+
+/*! ZSTD_getcBlockSize() :
+ *  Provides the size of compressed block from block header `src` */
+size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
+                          blockProperties_t* bpPtr)
+{
+    if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
+    {   U32 const cBlockHeader = MEM_readLE24(src);
+        U32 const cSize = cBlockHeader >> 3;
+        bpPtr->lastBlock = cBlockHeader & 1;
+        bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
+        bpPtr->origSize = cSize;   /* only useful for RLE */
+        if (bpPtr->blockType == bt_rle) return 1;
+        if (bpPtr->blockType == bt_reserved) return ERROR(corruption_detected);
+        return cSize;
+    }
+}
+
+
+/* Hidden declaration for fullbench */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
+                          const void* src, size_t srcSize);
+/*! ZSTD_decodeLiteralsBlock() :
+ * @return : nb of bytes read from src (< srcSize )
+ *  note : symbol not declared but exposed for fullbench */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
+                          const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
+{
+    if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected);
+
+    {   const BYTE* const istart = (const BYTE*) src;
+        symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
+
+        switch(litEncType)
+        {
+        case set_repeat:
+            if (dctx->litEntropy==0) return ERROR(dictionary_corrupted);
+            /* fall-through */
+
+        case set_compressed:
+            if (srcSize < 5) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
+            {   size_t lhSize, litSize, litCSize;
+                U32 singleStream=0;
+                U32 const lhlCode = (istart[0] >> 2) & 3;
+                U32 const lhc = MEM_readLE32(istart);
+                size_t hufSuccess;
+                switch(lhlCode)
+                {
+                case 0: case 1: default:   /* note : default is impossible, since lhlCode into [0..3] */
+                    /* 2 - 2 - 10 - 10 */
+                    singleStream = !lhlCode;
+                    lhSize = 3;
+                    litSize  = (lhc >> 4) & 0x3FF;
+                    litCSize = (lhc >> 14) & 0x3FF;
+                    break;
+                case 2:
+                    /* 2 - 2 - 14 - 14 */
+                    lhSize = 4;
+                    litSize  = (lhc >> 4) & 0x3FFF;
+                    litCSize = lhc >> 18;
+                    break;
+                case 3:
+                    /* 2 - 2 - 18 - 18 */
+                    lhSize = 5;
+                    litSize  = (lhc >> 4) & 0x3FFFF;
+                    litCSize = (lhc >> 22) + (istart[4] << 10);
+                    break;
+                }
+                if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected);
+                if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
+
+                /* prefetch huffman table if cold */
+                if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) {
+                    PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable));
+                }
+
+                if (litEncType==set_repeat) {
+                    if (singleStream) {
+                        hufSuccess = HUF_decompress1X_usingDTable_bmi2(
+                            dctx->litBuffer, litSize, istart+lhSize, litCSize,
+                            dctx->HUFptr, dctx->bmi2);
+                    } else {
+                        hufSuccess = HUF_decompress4X_usingDTable_bmi2(
+                            dctx->litBuffer, litSize, istart+lhSize, litCSize,
+                            dctx->HUFptr, dctx->bmi2);
+                    }
+                } else {
+                    if (singleStream) {
+#if defined(HUF_FORCE_DECOMPRESS_X2)
+                        hufSuccess = HUF_decompress1X_DCtx_wksp(
+                            dctx->entropy.hufTable, dctx->litBuffer, litSize,
+                            istart+lhSize, litCSize, dctx->workspace,
+                            sizeof(dctx->workspace));
+#else
+                        hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2(
+                            dctx->entropy.hufTable, dctx->litBuffer, litSize,
+                            istart+lhSize, litCSize, dctx->workspace,
+                            sizeof(dctx->workspace), dctx->bmi2);
+#endif
+                    } else {
+                        hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2(
+                            dctx->entropy.hufTable, dctx->litBuffer, litSize,
+                            istart+lhSize, litCSize, dctx->workspace,
+                            sizeof(dctx->workspace), dctx->bmi2);
+                    }
+                }
+
+                if (HUF_isError(hufSuccess)) return ERROR(corruption_detected);
+
+                dctx->litPtr = dctx->litBuffer;
+                dctx->litSize = litSize;
+                dctx->litEntropy = 1;
+                if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable;
+                memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+                return litCSize + lhSize;
+            }
+
+        case set_basic:
+            {   size_t litSize, lhSize;
+                U32 const lhlCode = ((istart[0]) >> 2) & 3;
+                switch(lhlCode)
+                {
+                case 0: case 2: default:   /* note : default is impossible, since lhlCode into [0..3] */
+                    lhSize = 1;
+                    litSize = istart[0] >> 3;
+                    break;
+                case 1:
+                    lhSize = 2;
+                    litSize = MEM_readLE16(istart) >> 4;
+                    break;
+                case 3:
+                    lhSize = 3;
+                    litSize = MEM_readLE24(istart) >> 4;
+                    break;
+                }
+
+                if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) {  /* risk reading beyond src buffer with wildcopy */
+                    if (litSize+lhSize > srcSize) return ERROR(corruption_detected);
+                    memcpy(dctx->litBuffer, istart+lhSize, litSize);
+                    dctx->litPtr = dctx->litBuffer;
+                    dctx->litSize = litSize;
+                    memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+                    return lhSize+litSize;
+                }
+                /* direct reference into compressed stream */
+                dctx->litPtr = istart+lhSize;
+                dctx->litSize = litSize;
+                return lhSize+litSize;
+            }
+
+        case set_rle:
+            {   U32 const lhlCode = ((istart[0]) >> 2) & 3;
+                size_t litSize, lhSize;
+                switch(lhlCode)
+                {
+                case 0: case 2: default:   /* note : default is impossible, since lhlCode into [0..3] */
+                    lhSize = 1;
+                    litSize = istart[0] >> 3;
+                    break;
+                case 1:
+                    lhSize = 2;
+                    litSize = MEM_readLE16(istart) >> 4;
+                    break;
+                case 3:
+                    lhSize = 3;
+                    litSize = MEM_readLE24(istart) >> 4;
+                    if (srcSize<4) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
+                    break;
+                }
+                if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected);
+                memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
+                dctx->litPtr = dctx->litBuffer;
+                dctx->litSize = litSize;
+                return lhSize+1;
+            }
+        default:
+            return ERROR(corruption_detected);   /* impossible */
+        }
+    }
+}
+
+/* Default FSE distribution tables.
+ * These are pre-calculated FSE decoding tables using default distributions as defined in specification :
+ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions
+ * They were generated programmatically with following method :
+ * - start from default distributions, present in /lib/common/zstd_internal.h
+ * - generate tables normally, using ZSTD_buildFSETable()
+ * - printout the content of tables
+ * - pretify output, report below, test with fuzzer to ensure it's correct */
+
+/* Default FSE distribution table for Literal Lengths */
+static const ZSTD_seqSymbol LL_defaultDTable[(1<<LL_DEFAULTNORMLOG)+1] = {
+     {  1,  1,  1, LL_DEFAULTNORMLOG},  /* header : fastMode, tableLog */
+     /* nextState, nbAddBits, nbBits, baseVal */
+     {  0,  0,  4,    0},  { 16,  0,  4,    0},
+     { 32,  0,  5,    1},  {  0,  0,  5,    3},
+     {  0,  0,  5,    4},  {  0,  0,  5,    6},
+     {  0,  0,  5,    7},  {  0,  0,  5,    9},
+     {  0,  0,  5,   10},  {  0,  0,  5,   12},
+     {  0,  0,  6,   14},  {  0,  1,  5,   16},
+     {  0,  1,  5,   20},  {  0,  1,  5,   22},
+     {  0,  2,  5,   28},  {  0,  3,  5,   32},
+     {  0,  4,  5,   48},  { 32,  6,  5,   64},
+     {  0,  7,  5,  128},  {  0,  8,  6,  256},
+     {  0, 10,  6, 1024},  {  0, 12,  6, 4096},
+     { 32,  0,  4,    0},  {  0,  0,  4,    1},
+     {  0,  0,  5,    2},  { 32,  0,  5,    4},
+     {  0,  0,  5,    5},  { 32,  0,  5,    7},
+     {  0,  0,  5,    8},  { 32,  0,  5,   10},
+     {  0,  0,  5,   11},  {  0,  0,  6,   13},
+     { 32,  1,  5,   16},  {  0,  1,  5,   18},
+     { 32,  1,  5,   22},  {  0,  2,  5,   24},
+     { 32,  3,  5,   32},  {  0,  3,  5,   40},
+     {  0,  6,  4,   64},  { 16,  6,  4,   64},
+     { 32,  7,  5,  128},  {  0,  9,  6,  512},
+     {  0, 11,  6, 2048},  { 48,  0,  4,    0},
+     { 16,  0,  4,    1},  { 32,  0,  5,    2},
+     { 32,  0,  5,    3},  { 32,  0,  5,    5},
+     { 32,  0,  5,    6},  { 32,  0,  5,    8},
+     { 32,  0,  5,    9},  { 32,  0,  5,   11},
+     { 32,  0,  5,   12},  {  0,  0,  6,   15},
+     { 32,  1,  5,   18},  { 32,  1,  5,   20},
+     { 32,  2,  5,   24},  { 32,  2,  5,   28},
+     { 32,  3,  5,   40},  { 32,  4,  5,   48},
+     {  0, 16,  6,65536},  {  0, 15,  6,32768},
+     {  0, 14,  6,16384},  {  0, 13,  6, 8192},
+};   /* LL_defaultDTable */
+
+/* Default FSE distribution table for Offset Codes */
+static const ZSTD_seqSymbol OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
+    {  1,  1,  1, OF_DEFAULTNORMLOG},  /* header : fastMode, tableLog */
+    /* nextState, nbAddBits, nbBits, baseVal */
+    {  0,  0,  5,    0},     {  0,  6,  4,   61},
+    {  0,  9,  5,  509},     {  0, 15,  5,32765},
+    {  0, 21,  5,2097149},   {  0,  3,  5,    5},
+    {  0,  7,  4,  125},     {  0, 12,  5, 4093},
+    {  0, 18,  5,262141},    {  0, 23,  5,8388605},
+    {  0,  5,  5,   29},     {  0,  8,  4,  253},
+    {  0, 14,  5,16381},     {  0, 20,  5,1048573},
+    {  0,  2,  5,    1},     { 16,  7,  4,  125},
+    {  0, 11,  5, 2045},     {  0, 17,  5,131069},
+    {  0, 22,  5,4194301},   {  0,  4,  5,   13},
+    { 16,  8,  4,  253},     {  0, 13,  5, 8189},
+    {  0, 19,  5,524285},    {  0,  1,  5,    1},
+    { 16,  6,  4,   61},     {  0, 10,  5, 1021},
+    {  0, 16,  5,65533},     {  0, 28,  5,268435453},
+    {  0, 27,  5,134217725}, {  0, 26,  5,67108861},
+    {  0, 25,  5,33554429},  {  0, 24,  5,16777213},
+};   /* OF_defaultDTable */
+
+
+/* Default FSE distribution table for Match Lengths */
+static const ZSTD_seqSymbol ML_defaultDTable[(1<<ML_DEFAULTNORMLOG)+1] = {
+    {  1,  1,  1, ML_DEFAULTNORMLOG},  /* header : fastMode, tableLog */
+    /* nextState, nbAddBits, nbBits, baseVal */
+    {  0,  0,  6,    3},  {  0,  0,  4,    4},
+    { 32,  0,  5,    5},  {  0,  0,  5,    6},
+    {  0,  0,  5,    8},  {  0,  0,  5,    9},
+    {  0,  0,  5,   11},  {  0,  0,  6,   13},
+    {  0,  0,  6,   16},  {  0,  0,  6,   19},
+    {  0,  0,  6,   22},  {  0,  0,  6,   25},
+    {  0,  0,  6,   28},  {  0,  0,  6,   31},
+    {  0,  0,  6,   34},  {  0,  1,  6,   37},
+    {  0,  1,  6,   41},  {  0,  2,  6,   47},
+    {  0,  3,  6,   59},  {  0,  4,  6,   83},
+    {  0,  7,  6,  131},  {  0,  9,  6,  515},
+    { 16,  0,  4,    4},  {  0,  0,  4,    5},
+    { 32,  0,  5,    6},  {  0,  0,  5,    7},
+    { 32,  0,  5,    9},  {  0,  0,  5,   10},
+    {  0,  0,  6,   12},  {  0,  0,  6,   15},
+    {  0,  0,  6,   18},  {  0,  0,  6,   21},
+    {  0,  0,  6,   24},  {  0,  0,  6,   27},
+    {  0,  0,  6,   30},  {  0,  0,  6,   33},
+    {  0,  1,  6,   35},  {  0,  1,  6,   39},
+    {  0,  2,  6,   43},  {  0,  3,  6,   51},
+    {  0,  4,  6,   67},  {  0,  5,  6,   99},
+    {  0,  8,  6,  259},  { 32,  0,  4,    4},
+    { 48,  0,  4,    4},  { 16,  0,  4,    5},
+    { 32,  0,  5,    7},  { 32,  0,  5,    8},
+    { 32,  0,  5,   10},  { 32,  0,  5,   11},
+    {  0,  0,  6,   14},  {  0,  0,  6,   17},
+    {  0,  0,  6,   20},  {  0,  0,  6,   23},
+    {  0,  0,  6,   26},  {  0,  0,  6,   29},
+    {  0,  0,  6,   32},  {  0, 16,  6,65539},
+    {  0, 15,  6,32771},  {  0, 14,  6,16387},
+    {  0, 13,  6, 8195},  {  0, 12,  6, 4099},
+    {  0, 11,  6, 2051},  {  0, 10,  6, 1027},
+};   /* ML_defaultDTable */
+
+
+static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddBits)
+{
+    void* ptr = dt;
+    ZSTD_seqSymbol_header* const DTableH = (ZSTD_seqSymbol_header*)ptr;
+    ZSTD_seqSymbol* const cell = dt + 1;
+
+    DTableH->tableLog = 0;
+    DTableH->fastMode = 0;
+
+    cell->nbBits = 0;
+    cell->nextState = 0;
+    assert(nbAddBits < 255);
+    cell->nbAdditionalBits = (BYTE)nbAddBits;
+    cell->baseValue = baseValue;
+}
+
+
+/* ZSTD_buildFSETable() :
+ * generate FSE decoding table for one symbol (ll, ml or off)
+ * cannot fail if input is valid =>
+ * all inputs are presumed validated at this stage */
+void
+ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+            const short* normalizedCounter, unsigned maxSymbolValue,
+            const U32* baseValue, const U32* nbAdditionalBits,
+            unsigned tableLog)
+{
+    ZSTD_seqSymbol* const tableDecode = dt+1;
+    U16 symbolNext[MaxSeq+1];
+
+    U32 const maxSV1 = maxSymbolValue + 1;
+    U32 const tableSize = 1 << tableLog;
+    U32 highThreshold = tableSize-1;
+
+    /* Sanity Checks */
+    assert(maxSymbolValue <= MaxSeq);
+    assert(tableLog <= MaxFSELog);
+
+    /* Init, lay down lowprob symbols */
+    {   ZSTD_seqSymbol_header DTableH;
+        DTableH.tableLog = tableLog;
+        DTableH.fastMode = 1;
+        {   S16 const largeLimit= (S16)(1 << (tableLog-1));
+            U32 s;
+            for (s=0; s<maxSV1; s++) {
+                if (normalizedCounter[s]==-1) {
+                    tableDecode[highThreshold--].baseValue = s;
+                    symbolNext[s] = 1;
+                } else {
+                    if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
+                    symbolNext[s] = normalizedCounter[s];
+        }   }   }
+        memcpy(dt, &DTableH, sizeof(DTableH));
+    }
+
+    /* Spread symbols */
+    {   U32 const tableMask = tableSize-1;
+        U32 const step = FSE_TABLESTEP(tableSize);
+        U32 s, position = 0;
+        for (s=0; s<maxSV1; s++) {
+            int i;
+            for (i=0; i<normalizedCounter[s]; i++) {
+                tableDecode[position].baseValue = s;
+                position = (position + step) & tableMask;
+                while (position > highThreshold) position = (position + step) & tableMask;   /* lowprob area */
+        }   }
+        assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+    }
+
+    /* Build Decoding table */
+    {   U32 u;
+        for (u=0; u<tableSize; u++) {
+            U32 const symbol = tableDecode[u].baseValue;
+            U32 const nextState = symbolNext[symbol]++;
+            tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
+            tableDecode[u].nextState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
+            assert(nbAdditionalBits[symbol] < 255);
+            tableDecode[u].nbAdditionalBits = (BYTE)nbAdditionalBits[symbol];
+            tableDecode[u].baseValue = baseValue[symbol];
+    }   }
+}
+
+
+/*! ZSTD_buildSeqTable() :
+ * @return : nb bytes read from src,
+ *           or an error code if it fails */
+static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymbol** DTablePtr,
+                                 symbolEncodingType_e type, unsigned max, U32 maxLog,
+                                 const void* src, size_t srcSize,
+                                 const U32* baseValue, const U32* nbAdditionalBits,
+                                 const ZSTD_seqSymbol* defaultTable, U32 flagRepeatTable,
+                                 int ddictIsCold, int nbSeq)
+{
+    switch(type)
+    {
+    case set_rle :
+        if (!srcSize) return ERROR(srcSize_wrong);
+        if ( (*(const BYTE*)src) > max) return ERROR(corruption_detected);
+        {   U32 const symbol = *(const BYTE*)src;
+            U32 const baseline = baseValue[symbol];
+            U32 const nbBits = nbAdditionalBits[symbol];
+            ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
+        }
+        *DTablePtr = DTableSpace;
+        return 1;
+    case set_basic :
+        *DTablePtr = defaultTable;
+        return 0;
+    case set_repeat:
+        if (!flagRepeatTable) return ERROR(corruption_detected);
+        /* prefetch FSE table if used */
+        if (ddictIsCold && (nbSeq > 24 /* heuristic */)) {
+            const void* const pStart = *DTablePtr;
+            size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog));
+            PREFETCH_AREA(pStart, pSize);
+        }
+        return 0;
+    case set_compressed :
+        {   unsigned tableLog;
+            S16 norm[MaxSeq+1];
+            size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
+            if (FSE_isError(headerSize)) return ERROR(corruption_detected);
+            if (tableLog > maxLog) return ERROR(corruption_detected);
+            ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
+            *DTablePtr = DTableSpace;
+            return headerSize;
+        }
+    default :   /* impossible */
+        assert(0);
+        return ERROR(GENERIC);
+    }
+}
+
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
+                             const void* src, size_t srcSize)
+{
+    const BYTE* const istart = (const BYTE* const)src;
+    const BYTE* const iend = istart + srcSize;
+    const BYTE* ip = istart;
+    int nbSeq;
+    DEBUGLOG(5, "ZSTD_decodeSeqHeaders");
+
+    /* check */
+    if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong);
+
+    /* SeqHead */
+    nbSeq = *ip++;
+    if (!nbSeq) {
+        *nbSeqPtr=0;
+        if (srcSize != 1) return ERROR(srcSize_wrong);
+        return 1;
+    }
+    if (nbSeq > 0x7F) {
+        if (nbSeq == 0xFF) {
+            if (ip+2 > iend) return ERROR(srcSize_wrong);
+            nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
+        } else {
+            if (ip >= iend) return ERROR(srcSize_wrong);
+            nbSeq = ((nbSeq-0x80)<<8) + *ip++;
+        }
+    }
+    *nbSeqPtr = nbSeq;
+
+    /* FSE table descriptors */
+    if (ip+4 > iend) return ERROR(srcSize_wrong); /* minimum possible size */
+    {   symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
+        symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
+        symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
+        ip++;
+
+        /* Build DTables */
+        {   size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
+                                                      LLtype, MaxLL, LLFSELog,
+                                                      ip, iend-ip,
+                                                      LL_base, LL_bits,
+                                                      LL_defaultDTable, dctx->fseEntropy,
+                                                      dctx->ddictIsCold, nbSeq);
+            if (ZSTD_isError(llhSize)) return ERROR(corruption_detected);
+            ip += llhSize;
+        }
+
+        {   size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
+                                                      OFtype, MaxOff, OffFSELog,
+                                                      ip, iend-ip,
+                                                      OF_base, OF_bits,
+                                                      OF_defaultDTable, dctx->fseEntropy,
+                                                      dctx->ddictIsCold, nbSeq);
+            if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected);
+            ip += ofhSize;
+        }
+
+        {   size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
+                                                      MLtype, MaxML, MLFSELog,
+                                                      ip, iend-ip,
+                                                      ML_base, ML_bits,
+                                                      ML_defaultDTable, dctx->fseEntropy,
+                                                      dctx->ddictIsCold, nbSeq);
+            if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected);
+            ip += mlhSize;
+        }
+    }
+
+    return ip-istart;
+}
+
+
+typedef struct {
+    size_t litLength;
+    size_t matchLength;
+    size_t offset;
+    const BYTE* match;
+} seq_t;
+
+typedef struct {
+    size_t state;
+    const ZSTD_seqSymbol* table;
+} ZSTD_fseState;
+
+typedef struct {
+    BIT_DStream_t DStream;
+    ZSTD_fseState stateLL;
+    ZSTD_fseState stateOffb;
+    ZSTD_fseState stateML;
+    size_t prevOffset[ZSTD_REP_NUM];
+    const BYTE* prefixStart;
+    const BYTE* dictEnd;
+    size_t pos;
+} seqState_t;
+
+
+/* ZSTD_execSequenceLast7():
+ * exceptional case : decompress a match starting within last 7 bytes of output buffer.
+ * requires more careful checks, to ensure there is no overflow.
+ * performance does not matter though.
+ * note : this case is supposed to be never generated "naturally" by reference encoder,
+ *        since in most cases it needs at least 8 bytes to look for a match.
+ *        but it's allowed by the specification. */
+FORCE_NOINLINE
+size_t ZSTD_execSequenceLast7(BYTE* op,
+                              BYTE* const oend, seq_t sequence,
+                              const BYTE** litPtr, const BYTE* const litLimit,
+                              const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
+{
+    BYTE* const oLitEnd = op + sequence.litLength;
+    size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+    BYTE* const oMatchEnd = op + sequenceLength;   /* risk : address space overflow (32-bits) */
+    const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+    const BYTE* match = oLitEnd - sequence.offset;
+
+    /* check */
+    if (oMatchEnd>oend) return ERROR(dstSize_tooSmall);   /* last match must fit within dstBuffer */
+    if (iLitEnd > litLimit) return ERROR(corruption_detected);   /* try to read beyond literal buffer */
+
+    /* copy literals */
+    while (op < oLitEnd) *op++ = *(*litPtr)++;
+
+    /* copy Match */
+    if (sequence.offset > (size_t)(oLitEnd - base)) {
+        /* offset beyond prefix */
+        if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
+        match = dictEnd - (base-match);
+        if (match + sequence.matchLength <= dictEnd) {
+            memmove(oLitEnd, match, sequence.matchLength);
+            return sequenceLength;
+        }
+        /* span extDict & currentPrefixSegment */
+        {   size_t const length1 = dictEnd - match;
+            memmove(oLitEnd, match, length1);
+            op = oLitEnd + length1;
+            sequence.matchLength -= length1;
+            match = base;
+    }   }
+    while (op < oMatchEnd) *op++ = *match++;
+    return sequenceLength;
+}
+
+
+HINT_INLINE
+size_t ZSTD_execSequence(BYTE* op,
+                         BYTE* const oend, seq_t sequence,
+                         const BYTE** litPtr, const BYTE* const litLimit,
+                         const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
+{
+    BYTE* const oLitEnd = op + sequence.litLength;
+    size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+    BYTE* const oMatchEnd = op + sequenceLength;   /* risk : address space overflow (32-bits) */
+    BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
+    const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+    const BYTE* match = oLitEnd - sequence.offset;
+
+    /* check */
+    if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+    if (iLitEnd > litLimit) return ERROR(corruption_detected);   /* over-read beyond lit buffer */
+    if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd);
+
+    /* copy Literals */
+    ZSTD_copy8(op, *litPtr);
+    if (sequence.litLength > 8)
+        ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8);   /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
+    op = oLitEnd;
+    *litPtr = iLitEnd;   /* update for next sequence */
+
+    /* copy Match */
+    if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
+        /* offset beyond prefix -> go into extDict */
+        if (sequence.offset > (size_t)(oLitEnd - virtualStart))
+            return ERROR(corruption_detected);
+        match = dictEnd + (match - prefixStart);
+        if (match + sequence.matchLength <= dictEnd) {
+            memmove(oLitEnd, match, sequence.matchLength);
+            return sequenceLength;
+        }
+        /* span extDict & currentPrefixSegment */
+        {   size_t const length1 = dictEnd - match;
+            memmove(oLitEnd, match, length1);
+            op = oLitEnd + length1;
+            sequence.matchLength -= length1;
+            match = prefixStart;
+            if (op > oend_w || sequence.matchLength < MINMATCH) {
+              U32 i;
+              for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
+              return sequenceLength;
+            }
+    }   }
+    /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
+
+    /* match within prefix */
+    if (sequence.offset < 8) {
+        /* close range match, overlap */
+        static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };   /* added */
+        static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 };   /* subtracted */
+        int const sub2 = dec64table[sequence.offset];
+        op[0] = match[0];
+        op[1] = match[1];
+        op[2] = match[2];
+        op[3] = match[3];
+        match += dec32table[sequence.offset];
+        ZSTD_copy4(op+4, match);
+        match -= sub2;
+    } else {
+        ZSTD_copy8(op, match);
+    }
+    op += 8; match += 8;
+
+    if (oMatchEnd > oend-(16-MINMATCH)) {
+        if (op < oend_w) {
+            ZSTD_wildcopy(op, match, oend_w - op);
+            match += oend_w - op;
+            op = oend_w;
+        }
+        while (op < oMatchEnd) *op++ = *match++;
+    } else {
+        ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8);   /* works even if matchLength < 8 */
+    }
+    return sequenceLength;
+}
+
+
+HINT_INLINE
+size_t ZSTD_execSequenceLong(BYTE* op,
+                             BYTE* const oend, seq_t sequence,
+                             const BYTE** litPtr, const BYTE* const litLimit,
+                             const BYTE* const prefixStart, const BYTE* const dictStart, const BYTE* const dictEnd)
+{
+    BYTE* const oLitEnd = op + sequence.litLength;
+    size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+    BYTE* const oMatchEnd = op + sequenceLength;   /* risk : address space overflow (32-bits) */
+    BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
+    const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+    const BYTE* match = sequence.match;
+
+    /* check */
+    if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+    if (iLitEnd > litLimit) return ERROR(corruption_detected);   /* over-read beyond lit buffer */
+    if (oLitEnd > oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, dictStart, dictEnd);
+
+    /* copy Literals */
+    ZSTD_copy8(op, *litPtr);  /* note : op <= oLitEnd <= oend_w == oend - 8 */
+    if (sequence.litLength > 8)
+        ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8);   /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
+    op = oLitEnd;
+    *litPtr = iLitEnd;   /* update for next sequence */
+
+    /* copy Match */
+    if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
+        /* offset beyond prefix */
+        if (sequence.offset > (size_t)(oLitEnd - dictStart)) return ERROR(corruption_detected);
+        if (match + sequence.matchLength <= dictEnd) {
+            memmove(oLitEnd, match, sequence.matchLength);
+            return sequenceLength;
+        }
+        /* span extDict & currentPrefixSegment */
+        {   size_t const length1 = dictEnd - match;
+            memmove(oLitEnd, match, length1);
+            op = oLitEnd + length1;
+            sequence.matchLength -= length1;
+            match = prefixStart;
+            if (op > oend_w || sequence.matchLength < MINMATCH) {
+              U32 i;
+              for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
+              return sequenceLength;
+            }
+    }   }
+    assert(op <= oend_w);
+    assert(sequence.matchLength >= MINMATCH);
+
+    /* match within prefix */
+    if (sequence.offset < 8) {
+        /* close range match, overlap */
+        static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };   /* added */
+        static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 };   /* subtracted */
+        int const sub2 = dec64table[sequence.offset];
+        op[0] = match[0];
+        op[1] = match[1];
+        op[2] = match[2];
+        op[3] = match[3];
+        match += dec32table[sequence.offset];
+        ZSTD_copy4(op+4, match);
+        match -= sub2;
+    } else {
+        ZSTD_copy8(op, match);
+    }
+    op += 8; match += 8;
+
+    if (oMatchEnd > oend-(16-MINMATCH)) {
+        if (op < oend_w) {
+            ZSTD_wildcopy(op, match, oend_w - op);
+            match += oend_w - op;
+            op = oend_w;
+        }
+        while (op < oMatchEnd) *op++ = *match++;
+    } else {
+        ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8);   /* works even if matchLength < 8 */
+    }
+    return sequenceLength;
+}
+
+static void
+ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt)
+{
+    const void* ptr = dt;
+    const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr;
+    DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
+    DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits",
+                (U32)DStatePtr->state, DTableH->tableLog);
+    BIT_reloadDStream(bitD);
+    DStatePtr->table = dt + 1;
+}
+
+FORCE_INLINE_TEMPLATE void
+ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
+{
+    ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state];
+    U32 const nbBits = DInfo.nbBits;
+    size_t const lowBits = BIT_readBits(bitD, nbBits);
+    DStatePtr->state = DInfo.nextState + lowBits;
+}
+
+/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
+ * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
+ * bits before reloading. This value is the maximum number of bytes we read
+ * after reloading when we are decoding long offets.
+ */
+#define LONG_OFFSETS_MAX_EXTRA_BITS_32                       \
+    (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32       \
+        ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32  \
+        : 0)
+
+typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+FORCE_INLINE_TEMPLATE seq_t
+ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
+{
+    seq_t seq;
+    U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
+    U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
+    U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
+    U32 const totalBits = llBits+mlBits+ofBits;
+    U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
+    U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
+    U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
+
+    /* sequence */
+    {   size_t offset;
+        if (!ofBits)
+            offset = 0;
+        else {
+            ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
+            ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
+            assert(ofBits <= MaxOff);
+            if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) {
+                U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed);
+                offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
+                BIT_reloadDStream(&seqState->DStream);
+                if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
+                assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32);   /* to avoid another reload */
+            } else {
+                offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/);   /* <=  (ZSTD_WINDOWLOG_MAX-1) bits */
+                if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+            }
+        }
+
+        if (ofBits <= 1) {
+            offset += (llBase==0);
+            if (offset) {
+                size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+                temp += !temp;   /* 0 is not valid; input is corrupted; force offset to 1 */
+                if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+                seqState->prevOffset[1] = seqState->prevOffset[0];
+                seqState->prevOffset[0] = offset = temp;
+            } else {  /* offset == 0 */
+                offset = seqState->prevOffset[0];
+            }
+        } else {
+            seqState->prevOffset[2] = seqState->prevOffset[1];
+            seqState->prevOffset[1] = seqState->prevOffset[0];
+            seqState->prevOffset[0] = offset;
+        }
+        seq.offset = offset;
+    }
+
+    seq.matchLength = mlBase
+                    + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/) : 0);  /* <=  16 bits */
+    if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
+        BIT_reloadDStream(&seqState->DStream);
+    if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
+        BIT_reloadDStream(&seqState->DStream);
+    /* Ensure there are enough bits to read the rest of data in 64-bit mode. */
+    ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
+
+    seq.litLength = llBase
+                  + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits/*>0*/) : 0);    /* <=  16 bits */
+    if (MEM_32bits())
+        BIT_reloadDStream(&seqState->DStream);
+
+    DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
+                (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
+
+    /* ANS state update */
+    ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */
+    ZSTD_updateFseState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */
+    if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */
+    ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */
+
+    return seq;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
+                               void* dst, size_t maxDstSize,
+                         const void* seqStart, size_t seqSize, int nbSeq,
+                         const ZSTD_longOffset_e isLongOffset)
+{
+    const BYTE* ip = (const BYTE*)seqStart;
+    const BYTE* const iend = ip + seqSize;
+    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const oend = ostart + maxDstSize;
+    BYTE* op = ostart;
+    const BYTE* litPtr = dctx->litPtr;
+    const BYTE* const litEnd = litPtr + dctx->litSize;
+    const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
+    const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
+    const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+    DEBUGLOG(5, "ZSTD_decompressSequences_body");
+
+    /* Regen sequences */
+    if (nbSeq) {
+        seqState_t seqState;
+        dctx->fseEntropy = 1;
+        { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
+        CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
+        ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
+        ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
+        ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
+
+        for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
+            nbSeq--;
+            {   seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
+                size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
+                DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
+                if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+                op += oneSeqSize;
+        }   }
+
+        /* check if reached exact end */
+        DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
+        if (nbSeq) return ERROR(corruption_detected);
+        /* save reps for next block */
+        { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+    }
+
+    /* last literal segment */
+    {   size_t const lastLLSize = litEnd - litPtr;
+        if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
+        memcpy(op, litPtr, lastLLSize);
+        op += lastLLSize;
+    }
+
+    return op-ostart;
+}
+
+static size_t
+ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
+                                 void* dst, size_t maxDstSize,
+                           const void* seqStart, size_t seqSize, int nbSeq,
+                           const ZSTD_longOffset_e isLongOffset)
+{
+    return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+FORCE_INLINE_TEMPLATE seq_t
+ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
+{
+    seq_t seq;
+    U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
+    U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
+    U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
+    U32 const totalBits = llBits+mlBits+ofBits;
+    U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
+    U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
+    U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
+
+    /* sequence */
+    {   size_t offset;
+        if (!ofBits)
+            offset = 0;
+        else {
+            ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
+            ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
+            assert(ofBits <= MaxOff);
+            if (MEM_32bits() && longOffsets) {
+                U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
+                offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
+                if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
+                if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
+            } else {
+                offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits);   /* <=  (ZSTD_WINDOWLOG_MAX-1) bits */
+                if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+            }
+        }
+
+        if (ofBits <= 1) {
+            offset += (llBase==0);
+            if (offset) {
+                size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+                temp += !temp;   /* 0 is not valid; input is corrupted; force offset to 1 */
+                if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+                seqState->prevOffset[1] = seqState->prevOffset[0];
+                seqState->prevOffset[0] = offset = temp;
+            } else {
+                offset = seqState->prevOffset[0];
+            }
+        } else {
+            seqState->prevOffset[2] = seqState->prevOffset[1];
+            seqState->prevOffset[1] = seqState->prevOffset[0];
+            seqState->prevOffset[0] = offset;
+        }
+        seq.offset = offset;
+    }
+
+    seq.matchLength = mlBase + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0);  /* <=  16 bits */
+    if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
+        BIT_reloadDStream(&seqState->DStream);
+    if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
+        BIT_reloadDStream(&seqState->DStream);
+    /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
+    ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
+
+    seq.litLength = llBase + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0);    /* <=  16 bits */
+    if (MEM_32bits())
+        BIT_reloadDStream(&seqState->DStream);
+
+    {   size_t const pos = seqState->pos + seq.litLength;
+        const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
+        seq.match = matchBase + pos - seq.offset;  /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
+                                                    * No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */
+        seqState->pos = pos + seq.matchLength;
+    }
+
+    /* ANS state update */
+    ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */
+    ZSTD_updateFseState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */
+    if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */
+    ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */
+
+    return seq;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_decompressSequencesLong_body(
+                               ZSTD_DCtx* dctx,
+                               void* dst, size_t maxDstSize,
+                         const void* seqStart, size_t seqSize, int nbSeq,
+                         const ZSTD_longOffset_e isLongOffset)
+{
+    const BYTE* ip = (const BYTE*)seqStart;
+    const BYTE* const iend = ip + seqSize;
+    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const oend = ostart + maxDstSize;
+    BYTE* op = ostart;
+    const BYTE* litPtr = dctx->litPtr;
+    const BYTE* const litEnd = litPtr + dctx->litSize;
+    const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
+    const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
+    const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+
+    /* Regen sequences */
+    if (nbSeq) {
+#define STORED_SEQS 4
+#define STORED_SEQS_MASK (STORED_SEQS-1)
+#define ADVANCED_SEQS 4
+        seq_t sequences[STORED_SEQS];
+        int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
+        seqState_t seqState;
+        int seqNb;
+        dctx->fseEntropy = 1;
+        { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
+        seqState.prefixStart = prefixStart;
+        seqState.pos = (size_t)(op-prefixStart);
+        seqState.dictEnd = dictEnd;
+        assert(iend >= ip);
+        CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
+        ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
+        ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
+        ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
+
+        /* prepare in advance */
+        for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
+            sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
+            PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+        }
+        if (seqNb<seqAdvance) return ERROR(corruption_detected);
+
+        /* decode and decompress */
+        for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
+            seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
+            size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
+            if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+            PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+            sequences[seqNb & STORED_SEQS_MASK] = sequence;
+            op += oneSeqSize;
+        }
+        if (seqNb<nbSeq) return ERROR(corruption_detected);
+
+        /* finish queue */
+        seqNb -= seqAdvance;
+        for ( ; seqNb<nbSeq ; seqNb++) {
+            size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
+            if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+            op += oneSeqSize;
+        }
+
+        /* save reps for next block */
+        { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+    }
+
+    /* last literal segment */
+    {   size_t const lastLLSize = litEnd - litPtr;
+        if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
+        memcpy(op, litPtr, lastLLSize);
+        op += lastLLSize;
+    }
+
+    return op-ostart;
+}
+
+static size_t
+ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
+                                 void* dst, size_t maxDstSize,
+                           const void* seqStart, size_t seqSize, int nbSeq,
+                           const ZSTD_longOffset_e isLongOffset)
+{
+    return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+
+
+#if DYNAMIC_BMI2
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
+                                 void* dst, size_t maxDstSize,
+                           const void* seqStart, size_t seqSize, int nbSeq,
+                           const ZSTD_longOffset_e isLongOffset)
+{
+    return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
+                                 void* dst, size_t maxDstSize,
+                           const void* seqStart, size_t seqSize, int nbSeq,
+                           const ZSTD_longOffset_e isLongOffset)
+{
+    return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+#endif /* DYNAMIC_BMI2 */
+
+typedef size_t (*ZSTD_decompressSequences_t)(
+                            ZSTD_DCtx* dctx,
+                            void* dst, size_t maxDstSize,
+                            const void* seqStart, size_t seqSize, int nbSeq,
+                            const ZSTD_longOffset_e isLongOffset);
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+static size_t
+ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
+                   const void* seqStart, size_t seqSize, int nbSeq,
+                   const ZSTD_longOffset_e isLongOffset)
+{
+    DEBUGLOG(5, "ZSTD_decompressSequences");
+#if DYNAMIC_BMI2
+    if (dctx->bmi2) {
+        return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+    }
+#endif
+  return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+/* ZSTD_decompressSequencesLong() :
+ * decompression function triggered when a minimum share of offsets is considered "long",
+ * aka out of cache.
+ * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes mearning "farther than memory cache distance".
+ * This function will try to mitigate main memory latency through the use of prefetching */
+static size_t
+ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
+                             void* dst, size_t maxDstSize,
+                             const void* seqStart, size_t seqSize, int nbSeq,
+                             const ZSTD_longOffset_e isLongOffset)
+{
+    DEBUGLOG(5, "ZSTD_decompressSequencesLong");
+#if DYNAMIC_BMI2
+    if (dctx->bmi2) {
+        return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+    }
+#endif
+  return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+    !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+/* ZSTD_getLongOffsetsShare() :
+ * condition : offTable must be valid
+ * @return : "share" of long offsets (arbitrarily defined as > (1<<23))
+ *           compared to maximum possible of (1<<OffFSELog) */
+static unsigned
+ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
+{
+    const void* ptr = offTable;
+    U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
+    const ZSTD_seqSymbol* table = offTable + 1;
+    U32 const max = 1 << tableLog;
+    U32 u, total = 0;
+    DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
+
+    assert(max <= (1 << OffFSELog));  /* max not too large */
+    for (u=0; u<max; u++) {
+        if (table[u].nbAdditionalBits > 22) total += 1;
+    }
+
+    assert(tableLog <= OffFSELog);
+    total <<= (OffFSELog - tableLog);  /* scale to OffFSELog */
+
+    return total;
+}
+#endif
+
+
+size_t
+ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
+                              void* dst, size_t dstCapacity,
+                        const void* src, size_t srcSize, const int frame)
+{   /* blockType == blockCompressed */
+    const BYTE* ip = (const BYTE*)src;
+    /* isLongOffset must be true if there are long offsets.
+     * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
+     * We don't expect that to be the case in 64-bit mode.
+     * In block mode, window size is not known, so we have to be conservative.
+     * (note: but it could be evaluated from current-lowLimit)
+     */
+    ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))));
+    DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
+
+    if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
+
+    /* Decode literals section */
+    {   size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
+        DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize);
+        if (ZSTD_isError(litCSize)) return litCSize;
+        ip += litCSize;
+        srcSize -= litCSize;
+    }
+
+    /* Build Decoding Tables */
+    {
+        /* These macros control at build-time which decompressor implementation
+         * we use. If neither is defined, we do some inspection and dispatch at
+         * runtime.
+         */
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+    !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+        int usePrefetchDecoder = dctx->ddictIsCold;
+#endif
+        int nbSeq;
+        size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize);
+        if (ZSTD_isError(seqHSize)) return seqHSize;
+        ip += seqHSize;
+        srcSize -= seqHSize;
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+    !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+        if ( !usePrefetchDecoder
+          && (!frame || (dctx->fParams.windowSize > (1<<24)))
+          && (nbSeq>ADVANCED_SEQS) ) {  /* could probably use a larger nbSeq limit */
+            U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr);
+            U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */
+            usePrefetchDecoder = (shareLongOffsets >= minShare);
+        }
+#endif
+
+        dctx->ddictIsCold = 0;
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+    !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+        if (usePrefetchDecoder)
+#endif
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+            return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
+#endif
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+        /* else */
+        return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
+#endif
+    }
+}
+
+
+size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
+                            void* dst, size_t dstCapacity,
+                      const void* src, size_t srcSize)
+{
+    size_t dSize;
+    ZSTD_checkContinuity(dctx, dst);
+    dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
+    dctx->previousDstEnd = (char*)dst + dSize;
+    return dSize;
+}
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress_block.h b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.h
new file mode 100644
index 0000000..7e92960
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress_block.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+#ifndef ZSTD_DEC_BLOCK_H
+#define ZSTD_DEC_BLOCK_H
+
+/*-*******************************************************
+ *  Dependencies
+ *********************************************************/
+#include <stddef.h>   /* size_t */
+#include "zstd.h"    /* DCtx, and some public functions */
+#include "zstd_internal.h"  /* blockProperties_t, and some public functions */
+#include "zstd_decompress_internal.h"  /* ZSTD_seqSymbol */
+
+
+/* ===   Prototypes   === */
+
+/* note: prototypes already published within `zstd.h` :
+ * ZSTD_decompressBlock()
+ */
+
+/* note: prototypes already published within `zstd_internal.h` :
+ * ZSTD_getcBlockSize()
+ * ZSTD_decodeSeqHeaders()
+ */
+
+
+/* ZSTD_decompressBlock_internal() :
+ * decompress block, starting at `src`,
+ * into destination buffer `dst`.
+ * @return : decompressed block size,
+ *           or an error code (which can be tested using ZSTD_isError())
+ */
+size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
+                               void* dst, size_t dstCapacity,
+                         const void* src, size_t srcSize, const int frame);
+
+/* ZSTD_buildFSETable() :
+ * generate FSE decoding table for one symbol (ll, ml or off)
+ * this function must be called with valid parameters only
+ * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.)
+ * in which case it cannot fail.
+ * Internal use only.
+ */
+void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+             const short* normalizedCounter, unsigned maxSymbolValue,
+             const U32* baseValue, const U32* nbAdditionalBits,
+                   unsigned tableLog);
+
+
+#endif /* ZSTD_DEC_BLOCK_H */
diff --git a/Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h b/Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h
new file mode 100644
index 0000000..abd0030
--- /dev/null
+++ b/Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* zstd_decompress_internal:
+ * objects and definitions shared within lib/decompress modules */
+
+ #ifndef ZSTD_DECOMPRESS_INTERNAL_H
+ #define ZSTD_DECOMPRESS_INTERNAL_H
+
+
+/*-*******************************************************
+ *  Dependencies
+ *********************************************************/
+#include "mem.h"             /* BYTE, U16, U32 */
+#include "zstd_internal.h"   /* ZSTD_seqSymbol */
+
+
+
+/*-*******************************************************
+ *  Constants
+ *********************************************************/
+static const U32 LL_base[MaxLL+1] = {
+                 0,    1,    2,     3,     4,     5,     6,      7,
+                 8,    9,   10,    11,    12,    13,    14,     15,
+                16,   18,   20,    22,    24,    28,    32,     40,
+                48,   64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
+                0x2000, 0x4000, 0x8000, 0x10000 };
+
+static const U32 OF_base[MaxOff+1] = {
+                 0,        1,       1,       5,     0xD,     0x1D,     0x3D,     0x7D,
+                 0xFD,   0x1FD,   0x3FD,   0x7FD,   0xFFD,   0x1FFD,   0x3FFD,   0x7FFD,
+                 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
+                 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
+
+static const U32 OF_bits[MaxOff+1] = {
+                     0,  1,  2,  3,  4,  5,  6,  7,
+                     8,  9, 10, 11, 12, 13, 14, 15,
+                    16, 17, 18, 19, 20, 21, 22, 23,
+                    24, 25, 26, 27, 28, 29, 30, 31 };
+
+static const U32 ML_base[MaxML+1] = {
+                     3,  4,  5,    6,     7,     8,     9,    10,
+                    11, 12, 13,   14,    15,    16,    17,    18,
+                    19, 20, 21,   22,    23,    24,    25,    26,
+                    27, 28, 29,   30,    31,    32,    33,    34,
+                    35, 37, 39,   41,    43,    47,    51,    59,
+                    67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
+                    0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
+
+
+/*-*******************************************************
+ *  Decompression types
+ *********************************************************/
+ typedef struct {
+     U32 fastMode;
+     U32 tableLog;
+ } ZSTD_seqSymbol_header;
+
+ typedef struct {
+     U16  nextState;
+     BYTE nbAdditionalBits;
+     BYTE nbBits;
+     U32  baseValue;
+ } ZSTD_seqSymbol;
+
+ #define SEQSYMBOL_TABLE_SIZE(log)   (1 + (1 << (log)))
+
+typedef struct {
+    ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)];    /* Note : Space reserved for FSE Tables */
+    ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)];   /* is also used as temporary workspace while building hufTable during DDict creation */
+    ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)];    /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
+    HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)];  /* can accommodate HUF_decompress4X */
+    U32 rep[ZSTD_REP_NUM];
+} ZSTD_entropyDTables_t;
+
+typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
+               ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
+               ZSTDds_decompressLastBlock, ZSTDds_checkChecksum,
+               ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage;
+
+typedef enum { zdss_init=0, zdss_loadHeader,
+               zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
+
+struct ZSTD_DCtx_s
+{
+    const ZSTD_seqSymbol* LLTptr;
+    const ZSTD_seqSymbol* MLTptr;
+    const ZSTD_seqSymbol* OFTptr;
+    const HUF_DTable* HUFptr;
+    ZSTD_entropyDTables_t entropy;
+    U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];   /* space needed when building huffman tables */
+    const void* previousDstEnd;   /* detect continuity */
+    const void* prefixStart;      /* start of current segment */
+    const void* virtualStart;     /* virtual start of previous segment if it was just before current one */
+    const void* dictEnd;          /* end of previous segment */
+    size_t expected;
+    ZSTD_frameHeader fParams;
+    U64 decodedSize;
+    blockType_e bType;            /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
+    ZSTD_dStage stage;
+    U32 litEntropy;
+    U32 fseEntropy;
+    XXH64_state_t xxhState;
+    size_t headerSize;
+    ZSTD_format_e format;
+    const BYTE* litPtr;
+    ZSTD_customMem customMem;
+    size_t litSize;
+    size_t rleSize;
+    size_t staticSize;
+    int bmi2;                     /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
+
+    /* dictionary */
+    ZSTD_DDict* ddictLocal;
+    const ZSTD_DDict* ddict;     /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */
+    U32 dictID;
+    int ddictIsCold;             /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
+
+    /* streaming */
+    ZSTD_dStreamStage streamStage;
+    char*  inBuff;
+    size_t inBuffSize;
+    size_t inPos;
+    size_t maxWindowSize;
+    char*  outBuff;
+    size_t outBuffSize;
+    size_t outStart;
+    size_t outEnd;
+    size_t lhSize;
+    void* legacyContext;
+    U32 previousLegacyVersion;
+    U32 legacyVersion;
+    U32 hostageByte;
+    int noForwardProgress;
+
+    /* workspace */
+    BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH];
+    BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
+};  /* typedef'd to ZSTD_DCtx within "zstd.h" */
+
+
+/*-*******************************************************
+ *  Shared internal functions
+ *********************************************************/
+
+/*! ZSTD_loadDEntropy() :
+ *  dict : must point at beginning of a valid zstd dictionary.
+ * @return : size of entropy tables read */
+size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
+                   const void* const dict, size_t const dictSize);
+
+/*! ZSTD_checkContinuity() :
+ *  check if next `dst` follows previous position, where decompression ended.
+ *  If yes, do nothing (continue on current segment).
+ *  If not, classify previous segment as "external dictionary", and start a new segment.
+ *  This function cannot fail. */
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst);
+
+
+#endif /* ZSTD_DECOMPRESS_INTERNAL_H */
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff.h b/Utilities/cmzstd/lib/deprecated/zbuff.h
new file mode 100644
index 0000000..a93115d
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* ***************************************************************
+*  NOTES/WARNINGS
+******************************************************************/
+/* The streaming API defined here is deprecated.
+ * Consider migrating towards ZSTD_compressStream() API in `zstd.h`
+ * See 'lib/README.md'.
+ *****************************************************************/
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef ZSTD_BUFFERED_H_23987
+#define ZSTD_BUFFERED_H_23987
+
+/* *************************************
+*  Dependencies
+***************************************/
+#include <stddef.h>      /* size_t */
+#include "zstd.h"        /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */
+
+
+/* ***************************************************************
+*  Compiler specifics
+*****************************************************************/
+/* Deprecation warnings */
+/* Should these warnings be a problem,
+   it is generally possible to disable them,
+   typically with -Wno-deprecated-declarations for gcc
+   or _CRT_SECURE_NO_WARNINGS in Visual.
+   Otherwise, it's also possible to define ZBUFF_DISABLE_DEPRECATE_WARNINGS */
+#ifdef ZBUFF_DISABLE_DEPRECATE_WARNINGS
+#  define ZBUFF_DEPRECATED(message) ZSTDLIB_API  /* disable deprecation warnings */
+#else
+#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+#    define ZBUFF_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_API
+#  elif (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__)
+#    define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated(message)))
+#  elif defined(__GNUC__) && (__GNUC__ >= 3)
+#    define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated))
+#  elif defined(_MSC_VER)
+#    define ZBUFF_DEPRECATED(message) ZSTDLIB_API __declspec(deprecated(message))
+#  else
+#    pragma message("WARNING: You need to implement ZBUFF_DEPRECATED for this compiler")
+#    define ZBUFF_DEPRECATED(message) ZSTDLIB_API
+#  endif
+#endif /* ZBUFF_DISABLE_DEPRECATE_WARNINGS */
+
+
+/* *************************************
+*  Streaming functions
+***************************************/
+/* This is the easier "buffered" streaming API,
+*  using an internal buffer to lift all restrictions on user-provided buffers
+*  which can be any size, any place, for both input and output.
+*  ZBUFF and ZSTD are 100% interoperable,
+*  frames created by one can be decoded by the other one */
+
+typedef ZSTD_CStream ZBUFF_CCtx;
+ZBUFF_DEPRECATED("use ZSTD_createCStream") ZBUFF_CCtx* ZBUFF_createCCtx(void);
+ZBUFF_DEPRECATED("use ZSTD_freeCStream")   size_t      ZBUFF_freeCCtx(ZBUFF_CCtx* cctx);
+
+ZBUFF_DEPRECATED("use ZSTD_initCStream")           size_t ZBUFF_compressInit(ZBUFF_CCtx* cctx, int compressionLevel);
+ZBUFF_DEPRECATED("use ZSTD_initCStream_usingDict") size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
+
+ZBUFF_DEPRECATED("use ZSTD_compressStream") size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr);
+ZBUFF_DEPRECATED("use ZSTD_flushStream")    size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr);
+ZBUFF_DEPRECATED("use ZSTD_endStream")      size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr);
+
+/*-*************************************************
+*  Streaming compression - howto
+*
+*  A ZBUFF_CCtx object is required to track streaming operation.
+*  Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources.
+*  ZBUFF_CCtx objects can be reused multiple times.
+*
+*  Start by initializing ZBUF_CCtx.
+*  Use ZBUFF_compressInit() to start a new compression operation.
+*  Use ZBUFF_compressInitDictionary() for a compression which requires a dictionary.
+*
+*  Use ZBUFF_compressContinue() repetitively to consume input stream.
+*  *srcSizePtr and *dstCapacityPtr can be any size.
+*  The function will report how many bytes were read or written within *srcSizePtr and *dstCapacityPtr.
+*  Note that it may not consume the entire input, in which case it's up to the caller to present again remaining data.
+*  The content of `dst` will be overwritten (up to *dstCapacityPtr) at each call, so save its content if it matters or change @dst .
+*  @return : a hint to preferred nb of bytes to use as input for next function call (it's just a hint, to improve latency)
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  At any moment, it's possible to flush whatever data remains within buffer, using ZBUFF_compressFlush().
+*  The nb of bytes written into `dst` will be reported into *dstCapacityPtr.
+*  Note that the function cannot output more than *dstCapacityPtr,
+*  therefore, some content might still be left into internal buffer if *dstCapacityPtr is too small.
+*  @return : nb of bytes still present into internal buffer (0 if it's empty)
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  ZBUFF_compressEnd() instructs to finish a frame.
+*  It will perform a flush and write frame epilogue.
+*  The epilogue is required for decoders to consider a frame completed.
+*  Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small.
+*  In which case, call again ZBUFF_compressFlush() to complete the flush.
+*  @return : nb of bytes still present into internal buffer (0 if it's empty)
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  Hint : _recommended buffer_ sizes (not compulsory) : ZBUFF_recommendedCInSize() / ZBUFF_recommendedCOutSize()
+*  input : ZBUFF_recommendedCInSize==128 KB block size is the internal unit, use this value to reduce intermediate stages (better latency)
+*  output : ZBUFF_recommendedCOutSize==ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block. Skip some buffering.
+*  By using both, it ensures that input will be entirely consumed, and output will always contain the result, reducing intermediate buffering.
+* **************************************************/
+
+
+typedef ZSTD_DStream ZBUFF_DCtx;
+ZBUFF_DEPRECATED("use ZSTD_createDStream") ZBUFF_DCtx* ZBUFF_createDCtx(void);
+ZBUFF_DEPRECATED("use ZSTD_freeDStream")   size_t      ZBUFF_freeDCtx(ZBUFF_DCtx* dctx);
+
+ZBUFF_DEPRECATED("use ZSTD_initDStream")           size_t ZBUFF_decompressInit(ZBUFF_DCtx* dctx);
+ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* dctx, const void* dict, size_t dictSize);
+
+ZBUFF_DEPRECATED("use ZSTD_decompressStream") size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx,
+                                            void* dst, size_t* dstCapacityPtr,
+                                      const void* src, size_t* srcSizePtr);
+
+/*-***************************************************************************
+*  Streaming decompression howto
+*
+*  A ZBUFF_DCtx object is required to track streaming operations.
+*  Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
+*  Use ZBUFF_decompressInit() to start a new decompression operation,
+*   or ZBUFF_decompressInitDictionary() if decompression requires a dictionary.
+*  Note that ZBUFF_DCtx objects can be re-init multiple times.
+*
+*  Use ZBUFF_decompressContinue() repetitively to consume your input.
+*  *srcSizePtr and *dstCapacityPtr can be any size.
+*  The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
+*  Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
+*  The content of `dst` will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change `dst`.
+*  @return : 0 when a frame is completely decoded and fully flushed,
+*            1 when there is still some data left within internal buffer to flush,
+*            >1 when more data is expected, with value being a suggested next input size (it's just a hint, which helps latency),
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize()
+*  output : ZBUFF_recommendedDOutSize== 128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
+*  input  : ZBUFF_recommendedDInSize == 128KB + 3;
+*           just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
+* *******************************************************************************/
+
+
+/* *************************************
+*  Tool functions
+***************************************/
+ZBUFF_DEPRECATED("use ZSTD_isError")      unsigned ZBUFF_isError(size_t errorCode);
+ZBUFF_DEPRECATED("use ZSTD_getErrorName") const char* ZBUFF_getErrorName(size_t errorCode);
+
+/** Functions below provide recommended buffer sizes for Compression or Decompression operations.
+*   These sizes are just hints, they tend to offer better latency */
+ZBUFF_DEPRECATED("use ZSTD_CStreamInSize")  size_t ZBUFF_recommendedCInSize(void);
+ZBUFF_DEPRECATED("use ZSTD_CStreamOutSize") size_t ZBUFF_recommendedCOutSize(void);
+ZBUFF_DEPRECATED("use ZSTD_DStreamInSize")  size_t ZBUFF_recommendedDInSize(void);
+ZBUFF_DEPRECATED("use ZSTD_DStreamOutSize") size_t ZBUFF_recommendedDOutSize(void);
+
+#endif  /* ZSTD_BUFFERED_H_23987 */
+
+
+#ifdef ZBUFF_STATIC_LINKING_ONLY
+#ifndef ZBUFF_STATIC_H_30298098432
+#define ZBUFF_STATIC_H_30298098432
+
+/* ====================================================================================
+ * The definitions in this section are considered experimental.
+ * They should never be used in association with a dynamic library, as they may change in the future.
+ * They are provided for advanced usages.
+ * Use them only in association with static linking.
+ * ==================================================================================== */
+
+/*--- Dependency ---*/
+#define ZSTD_STATIC_LINKING_ONLY   /* ZSTD_parameters, ZSTD_customMem */
+#include "zstd.h"
+
+
+/*--- Custom memory allocator ---*/
+/*! ZBUFF_createCCtx_advanced() :
+ *  Create a ZBUFF compression context using external alloc and free functions */
+ZBUFF_DEPRECATED("use ZSTD_createCStream_advanced") ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem);
+
+/*! ZBUFF_createDCtx_advanced() :
+ *  Create a ZBUFF decompression context using external alloc and free functions */
+ZBUFF_DEPRECATED("use ZSTD_createDStream_advanced") ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem);
+
+
+/*--- Advanced Streaming Initialization ---*/
+ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc,
+                                               const void* dict, size_t dictSize,
+                                               ZSTD_parameters params, unsigned long long pledgedSrcSize);
+
+
+#endif    /* ZBUFF_STATIC_H_30298098432 */
+#endif    /* ZBUFF_STATIC_LINKING_ONLY */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff_common.c b/Utilities/cmzstd/lib/deprecated/zbuff_common.c
new file mode 100644
index 0000000..661b9b0
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff_common.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include "error_private.h"
+#include "zbuff.h"
+
+/*-****************************************
+*  ZBUFF Error Management  (deprecated)
+******************************************/
+
+/*! ZBUFF_isError() :
+*   tells if a return value is an error code */
+unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); }
+/*! ZBUFF_getErrorName() :
+*   provides error code string from function result (useful for debugging) */
+const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff_compress.c b/Utilities/cmzstd/lib/deprecated/zbuff_compress.c
new file mode 100644
index 0000000..f39c60d
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff_compress.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/* *************************************
+*  Dependencies
+***************************************/
+#define ZBUFF_STATIC_LINKING_ONLY
+#include "zbuff.h"
+
+
+/*-***********************************************************
+*  Streaming compression
+*
+*  A ZBUFF_CCtx object is required to track streaming operation.
+*  Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources.
+*  Use ZBUFF_compressInit() to start a new compression operation.
+*  ZBUFF_CCtx objects can be reused multiple times.
+*
+*  Use ZBUFF_compressContinue() repetitively to consume your input.
+*  *srcSizePtr and *dstCapacityPtr can be any size.
+*  The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
+*  Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input.
+*  The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst .
+*  @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency)
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer.
+*  Note that it will not output more than *dstCapacityPtr.
+*  Therefore, some content might still be left into its internal buffer if dst buffer is too small.
+*  @return : nb of bytes still present into internal buffer (0 if it's empty)
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  ZBUFF_compressEnd() instructs to finish a frame.
+*  It will perform a flush and write frame epilogue.
+*  Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small.
+*  @return : nb of bytes still present into internal buffer (0 if it's empty)
+*            or an error code, which can be tested using ZBUFF_isError().
+*
+*  Hint : recommended buffer sizes (not compulsory)
+*  input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value.
+*  output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed.
+* ***********************************************************/
+
+ZBUFF_CCtx* ZBUFF_createCCtx(void)
+{
+    return ZSTD_createCStream();
+}
+
+ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem)
+{
+    return ZSTD_createCStream_advanced(customMem);
+}
+
+size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc)
+{
+    return ZSTD_freeCStream(zbc);
+}
+
+
+/* ======   Initialization   ====== */
+
+size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc,
+                                   const void* dict, size_t dictSize,
+                                   ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+    if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;  /* preserve "0 == unknown" behavior */
+    return ZSTD_initCStream_advanced(zbc, dict, dictSize, params, pledgedSrcSize);
+}
+
+
+size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel)
+{
+    return ZSTD_initCStream_usingDict(zbc, dict, dictSize, compressionLevel);
+}
+
+size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel)
+{
+    return ZSTD_initCStream(zbc, compressionLevel);
+}
+
+/* ======   Compression   ====== */
+
+
+size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc,
+                              void* dst, size_t* dstCapacityPtr,
+                        const void* src, size_t* srcSizePtr)
+{
+    size_t result;
+    ZSTD_outBuffer outBuff;
+    ZSTD_inBuffer inBuff;
+    outBuff.dst = dst;
+    outBuff.pos = 0;
+    outBuff.size = *dstCapacityPtr;
+    inBuff.src = src;
+    inBuff.pos = 0;
+    inBuff.size = *srcSizePtr;
+    result = ZSTD_compressStream(zbc, &outBuff, &inBuff);
+    *dstCapacityPtr = outBuff.pos;
+    *srcSizePtr = inBuff.pos;
+    return result;
+}
+
+
+
+/* ======   Finalize   ====== */
+
+size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
+{
+    size_t result;
+    ZSTD_outBuffer outBuff;
+    outBuff.dst = dst;
+    outBuff.pos = 0;
+    outBuff.size = *dstCapacityPtr;
+    result = ZSTD_flushStream(zbc, &outBuff);
+    *dstCapacityPtr = outBuff.pos;
+    return result;
+}
+
+
+size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
+{
+    size_t result;
+    ZSTD_outBuffer outBuff;
+    outBuff.dst = dst;
+    outBuff.pos = 0;
+    outBuff.size = *dstCapacityPtr;
+    result = ZSTD_endStream(zbc, &outBuff);
+    *dstCapacityPtr = outBuff.pos;
+    return result;
+}
+
+
+
+/* *************************************
+*  Tool functions
+***************************************/
+size_t ZBUFF_recommendedCInSize(void)  { return ZSTD_CStreamInSize(); }
+size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_CStreamOutSize(); }
diff --git a/Utilities/cmzstd/lib/deprecated/zbuff_decompress.c b/Utilities/cmzstd/lib/deprecated/zbuff_decompress.c
new file mode 100644
index 0000000..923c22b
--- /dev/null
+++ b/Utilities/cmzstd/lib/deprecated/zbuff_decompress.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/* *************************************
+*  Dependencies
+***************************************/
+#define ZBUFF_STATIC_LINKING_ONLY
+#include "zbuff.h"
+
+
+ZBUFF_DCtx* ZBUFF_createDCtx(void)
+{
+    return ZSTD_createDStream();
+}
+
+ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem)
+{
+    return ZSTD_createDStream_advanced(customMem);
+}
+
+size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbd)
+{
+    return ZSTD_freeDStream(zbd);
+}
+
+
+/* *** Initialization *** */
+
+size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbd, const void* dict, size_t dictSize)
+{
+    return ZSTD_initDStream_usingDict(zbd, dict, dictSize);
+}
+
+size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbd)
+{
+    return ZSTD_initDStream(zbd);
+}
+
+
+/* *** Decompression *** */
+
+size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbd,
+                                void* dst, size_t* dstCapacityPtr,
+                          const void* src, size_t* srcSizePtr)
+{
+    ZSTD_outBuffer outBuff;
+    ZSTD_inBuffer inBuff;
+    size_t result;
+    outBuff.dst  = dst;
+    outBuff.pos  = 0;
+    outBuff.size = *dstCapacityPtr;
+    inBuff.src  = src;
+    inBuff.pos  = 0;
+    inBuff.size = *srcSizePtr;
+    result = ZSTD_decompressStream(zbd, &outBuff, &inBuff);
+    *dstCapacityPtr = outBuff.pos;
+    *srcSizePtr = inBuff.pos;
+    return result;
+}
+
+
+/* *************************************
+*  Tool functions
+***************************************/
+size_t ZBUFF_recommendedDInSize(void)  { return ZSTD_DStreamInSize(); }
+size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_DStreamOutSize(); }
diff --git a/Utilities/cmzstd/lib/dictBuilder/cover.c b/Utilities/cmzstd/lib/dictBuilder/cover.c
new file mode 100644
index 0000000..b55bfb5
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/cover.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* *****************************************************************************
+ * Constructs a dictionary using a heuristic based on the following paper:
+ *
+ * Liao, Petri, Moffat, Wirth
+ * Effective Construction of Relative Lempel-Ziv Dictionaries
+ * Published in WWW 2016.
+ *
+ * Adapted from code originally written by @ot (Giuseppe Ottaviano).
+ ******************************************************************************/
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include <stdio.h>  /* fprintf */
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memset */
+#include <time.h>   /* clock */
+
+#include "mem.h" /* read */
+#include "pool.h"
+#include "threading.h"
+#include "cover.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+/*-*************************************
+*  Constants
+***************************************/
+#define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
+#define DEFAULT_SPLITPOINT 1.0
+
+/*-*************************************
+*  Console display
+***************************************/
+static int g_displayLevel = 2;
+#define DISPLAY(...)                                                           \
+  {                                                                            \
+    fprintf(stderr, __VA_ARGS__);                                              \
+    fflush(stderr);                                                            \
+  }
+#define LOCALDISPLAYLEVEL(displayLevel, l, ...)                                \
+  if (displayLevel >= l) {                                                     \
+    DISPLAY(__VA_ARGS__);                                                      \
+  } /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */
+#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
+
+#define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \
+  if (displayLevel >= l) {                                                     \
+    if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \
+      g_time = clock();                                                        \
+      DISPLAY(__VA_ARGS__);                                                    \
+    }                                                                          \
+  }
+#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
+static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
+static clock_t g_time = 0;
+
+/*-*************************************
+* Hash table
+***************************************
+* A small specialized hash map for storing activeDmers.
+* The map does not resize, so if it becomes full it will loop forever.
+* Thus, the map must be large enough to store every value.
+* The map implements linear probing and keeps its load less than 0.5.
+*/
+
+#define MAP_EMPTY_VALUE ((U32)-1)
+typedef struct COVER_map_pair_t_s {
+  U32 key;
+  U32 value;
+} COVER_map_pair_t;
+
+typedef struct COVER_map_s {
+  COVER_map_pair_t *data;
+  U32 sizeLog;
+  U32 size;
+  U32 sizeMask;
+} COVER_map_t;
+
+/**
+ * Clear the map.
+ */
+static void COVER_map_clear(COVER_map_t *map) {
+  memset(map->data, MAP_EMPTY_VALUE, map->size * sizeof(COVER_map_pair_t));
+}
+
+/**
+ * Initializes a map of the given size.
+ * Returns 1 on success and 0 on failure.
+ * The map must be destroyed with COVER_map_destroy().
+ * The map is only guaranteed to be large enough to hold size elements.
+ */
+static int COVER_map_init(COVER_map_t *map, U32 size) {
+  map->sizeLog = ZSTD_highbit32(size) + 2;
+  map->size = (U32)1 << map->sizeLog;
+  map->sizeMask = map->size - 1;
+  map->data = (COVER_map_pair_t *)malloc(map->size * sizeof(COVER_map_pair_t));
+  if (!map->data) {
+    map->sizeLog = 0;
+    map->size = 0;
+    return 0;
+  }
+  COVER_map_clear(map);
+  return 1;
+}
+
+/**
+ * Internal hash function
+ */
+static const U32 prime4bytes = 2654435761U;
+static U32 COVER_map_hash(COVER_map_t *map, U32 key) {
+  return (key * prime4bytes) >> (32 - map->sizeLog);
+}
+
+/**
+ * Helper function that returns the index that a key should be placed into.
+ */
+static U32 COVER_map_index(COVER_map_t *map, U32 key) {
+  const U32 hash = COVER_map_hash(map, key);
+  U32 i;
+  for (i = hash;; i = (i + 1) & map->sizeMask) {
+    COVER_map_pair_t *pos = &map->data[i];
+    if (pos->value == MAP_EMPTY_VALUE) {
+      return i;
+    }
+    if (pos->key == key) {
+      return i;
+    }
+  }
+}
+
+/**
+ * Returns the pointer to the value for key.
+ * If key is not in the map, it is inserted and the value is set to 0.
+ * The map must not be full.
+ */
+static U32 *COVER_map_at(COVER_map_t *map, U32 key) {
+  COVER_map_pair_t *pos = &map->data[COVER_map_index(map, key)];
+  if (pos->value == MAP_EMPTY_VALUE) {
+    pos->key = key;
+    pos->value = 0;
+  }
+  return &pos->value;
+}
+
+/**
+ * Deletes key from the map if present.
+ */
+static void COVER_map_remove(COVER_map_t *map, U32 key) {
+  U32 i = COVER_map_index(map, key);
+  COVER_map_pair_t *del = &map->data[i];
+  U32 shift = 1;
+  if (del->value == MAP_EMPTY_VALUE) {
+    return;
+  }
+  for (i = (i + 1) & map->sizeMask;; i = (i + 1) & map->sizeMask) {
+    COVER_map_pair_t *const pos = &map->data[i];
+    /* If the position is empty we are done */
+    if (pos->value == MAP_EMPTY_VALUE) {
+      del->value = MAP_EMPTY_VALUE;
+      return;
+    }
+    /* If pos can be moved to del do so */
+    if (((i - COVER_map_hash(map, pos->key)) & map->sizeMask) >= shift) {
+      del->key = pos->key;
+      del->value = pos->value;
+      del = pos;
+      shift = 1;
+    } else {
+      ++shift;
+    }
+  }
+}
+
+/**
+ * Destroys a map that is inited with COVER_map_init().
+ */
+static void COVER_map_destroy(COVER_map_t *map) {
+  if (map->data) {
+    free(map->data);
+  }
+  map->data = NULL;
+  map->size = 0;
+}
+
+/*-*************************************
+* Context
+***************************************/
+
+typedef struct {
+  const BYTE *samples;
+  size_t *offsets;
+  const size_t *samplesSizes;
+  size_t nbSamples;
+  size_t nbTrainSamples;
+  size_t nbTestSamples;
+  U32 *suffix;
+  size_t suffixSize;
+  U32 *freqs;
+  U32 *dmerAt;
+  unsigned d;
+} COVER_ctx_t;
+
+/* We need a global context for qsort... */
+static COVER_ctx_t *g_ctx = NULL;
+
+/*-*************************************
+*  Helper functions
+***************************************/
+
+/**
+ * Returns the sum of the sample sizes.
+ */
+size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) {
+  size_t sum = 0;
+  unsigned i;
+  for (i = 0; i < nbSamples; ++i) {
+    sum += samplesSizes[i];
+  }
+  return sum;
+}
+
+/**
+ * Returns -1 if the dmer at lp is less than the dmer at rp.
+ * Return 0 if the dmers at lp and rp are equal.
+ * Returns 1 if the dmer at lp is greater than the dmer at rp.
+ */
+static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) {
+  U32 const lhs = *(U32 const *)lp;
+  U32 const rhs = *(U32 const *)rp;
+  return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d);
+}
+/**
+ * Faster version for d <= 8.
+ */
+static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) {
+  U64 const mask = (ctx->d == 8) ? (U64)-1 : (((U64)1 << (8 * ctx->d)) - 1);
+  U64 const lhs = MEM_readLE64(ctx->samples + *(U32 const *)lp) & mask;
+  U64 const rhs = MEM_readLE64(ctx->samples + *(U32 const *)rp) & mask;
+  if (lhs < rhs) {
+    return -1;
+  }
+  return (lhs > rhs);
+}
+
+/**
+ * Same as COVER_cmp() except ties are broken by pointer value
+ * NOTE: g_ctx must be set to call this function.  A global is required because
+ * qsort doesn't take an opaque pointer.
+ */
+static int COVER_strict_cmp(const void *lp, const void *rp) {
+  int result = COVER_cmp(g_ctx, lp, rp);
+  if (result == 0) {
+    result = lp < rp ? -1 : 1;
+  }
+  return result;
+}
+/**
+ * Faster version for d <= 8.
+ */
+static int COVER_strict_cmp8(const void *lp, const void *rp) {
+  int result = COVER_cmp8(g_ctx, lp, rp);
+  if (result == 0) {
+    result = lp < rp ? -1 : 1;
+  }
+  return result;
+}
+
+/**
+ * Returns the first pointer in [first, last) whose element does not compare
+ * less than value.  If no such element exists it returns last.
+ */
+static const size_t *COVER_lower_bound(const size_t *first, const size_t *last,
+                                       size_t value) {
+  size_t count = last - first;
+  while (count != 0) {
+    size_t step = count / 2;
+    const size_t *ptr = first;
+    ptr += step;
+    if (*ptr < value) {
+      first = ++ptr;
+      count -= step + 1;
+    } else {
+      count = step;
+    }
+  }
+  return first;
+}
+
+/**
+ * Generic groupBy function.
+ * Groups an array sorted by cmp into groups with equivalent values.
+ * Calls grp for each group.
+ */
+static void
+COVER_groupBy(const void *data, size_t count, size_t size, COVER_ctx_t *ctx,
+              int (*cmp)(COVER_ctx_t *, const void *, const void *),
+              void (*grp)(COVER_ctx_t *, const void *, const void *)) {
+  const BYTE *ptr = (const BYTE *)data;
+  size_t num = 0;
+  while (num < count) {
+    const BYTE *grpEnd = ptr + size;
+    ++num;
+    while (num < count && cmp(ctx, ptr, grpEnd) == 0) {
+      grpEnd += size;
+      ++num;
+    }
+    grp(ctx, ptr, grpEnd);
+    ptr = grpEnd;
+  }
+}
+
+/*-*************************************
+*  Cover functions
+***************************************/
+
+/**
+ * Called on each group of positions with the same dmer.
+ * Counts the frequency of each dmer and saves it in the suffix array.
+ * Fills `ctx->dmerAt`.
+ */
+static void COVER_group(COVER_ctx_t *ctx, const void *group,
+                        const void *groupEnd) {
+  /* The group consists of all the positions with the same first d bytes. */
+  const U32 *grpPtr = (const U32 *)group;
+  const U32 *grpEnd = (const U32 *)groupEnd;
+  /* The dmerId is how we will reference this dmer.
+   * This allows us to map the whole dmer space to a much smaller space, the
+   * size of the suffix array.
+   */
+  const U32 dmerId = (U32)(grpPtr - ctx->suffix);
+  /* Count the number of samples this dmer shows up in */
+  U32 freq = 0;
+  /* Details */
+  const size_t *curOffsetPtr = ctx->offsets;
+  const size_t *offsetsEnd = ctx->offsets + ctx->nbSamples;
+  /* Once *grpPtr >= curSampleEnd this occurrence of the dmer is in a
+   * different sample than the last.
+   */
+  size_t curSampleEnd = ctx->offsets[0];
+  for (; grpPtr != grpEnd; ++grpPtr) {
+    /* Save the dmerId for this position so we can get back to it. */
+    ctx->dmerAt[*grpPtr] = dmerId;
+    /* Dictionaries only help for the first reference to the dmer.
+     * After that zstd can reference the match from the previous reference.
+     * So only count each dmer once for each sample it is in.
+     */
+    if (*grpPtr < curSampleEnd) {
+      continue;
+    }
+    freq += 1;
+    /* Binary search to find the end of the sample *grpPtr is in.
+     * In the common case that grpPtr + 1 == grpEnd we can skip the binary
+     * search because the loop is over.
+     */
+    if (grpPtr + 1 != grpEnd) {
+      const size_t *sampleEndPtr =
+          COVER_lower_bound(curOffsetPtr, offsetsEnd, *grpPtr);
+      curSampleEnd = *sampleEndPtr;
+      curOffsetPtr = sampleEndPtr + 1;
+    }
+  }
+  /* At this point we are never going to look at this segment of the suffix
+   * array again.  We take advantage of this fact to save memory.
+   * We store the frequency of the dmer in the first position of the group,
+   * which is dmerId.
+   */
+  ctx->suffix[dmerId] = freq;
+}
+
+
+/**
+ * Selects the best segment in an epoch.
+ * Segments of are scored according to the function:
+ *
+ * Let F(d) be the frequency of dmer d.
+ * Let S_i be the dmer at position i of segment S which has length k.
+ *
+ *     Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1})
+ *
+ * Once the dmer d is in the dictionay we set F(d) = 0.
+ */
+static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs,
+                                           COVER_map_t *activeDmers, U32 begin,
+                                           U32 end,
+                                           ZDICT_cover_params_t parameters) {
+  /* Constants */
+  const U32 k = parameters.k;
+  const U32 d = parameters.d;
+  const U32 dmersInK = k - d + 1;
+  /* Try each segment (activeSegment) and save the best (bestSegment) */
+  COVER_segment_t bestSegment = {0, 0, 0};
+  COVER_segment_t activeSegment;
+  /* Reset the activeDmers in the segment */
+  COVER_map_clear(activeDmers);
+  /* The activeSegment starts at the beginning of the epoch. */
+  activeSegment.begin = begin;
+  activeSegment.end = begin;
+  activeSegment.score = 0;
+  /* Slide the activeSegment through the whole epoch.
+   * Save the best segment in bestSegment.
+   */
+  while (activeSegment.end < end) {
+    /* The dmerId for the dmer at the next position */
+    U32 newDmer = ctx->dmerAt[activeSegment.end];
+    /* The entry in activeDmers for this dmerId */
+    U32 *newDmerOcc = COVER_map_at(activeDmers, newDmer);
+    /* If the dmer isn't already present in the segment add its score. */
+    if (*newDmerOcc == 0) {
+      /* The paper suggest using the L-0.5 norm, but experiments show that it
+       * doesn't help.
+       */
+      activeSegment.score += freqs[newDmer];
+    }
+    /* Add the dmer to the segment */
+    activeSegment.end += 1;
+    *newDmerOcc += 1;
+
+    /* If the window is now too large, drop the first position */
+    if (activeSegment.end - activeSegment.begin == dmersInK + 1) {
+      U32 delDmer = ctx->dmerAt[activeSegment.begin];
+      U32 *delDmerOcc = COVER_map_at(activeDmers, delDmer);
+      activeSegment.begin += 1;
+      *delDmerOcc -= 1;
+      /* If this is the last occurence of the dmer, subtract its score */
+      if (*delDmerOcc == 0) {
+        COVER_map_remove(activeDmers, delDmer);
+        activeSegment.score -= freqs[delDmer];
+      }
+    }
+
+    /* If this segment is the best so far save it */
+    if (activeSegment.score > bestSegment.score) {
+      bestSegment = activeSegment;
+    }
+  }
+  {
+    /* Trim off the zero frequency head and tail from the segment. */
+    U32 newBegin = bestSegment.end;
+    U32 newEnd = bestSegment.begin;
+    U32 pos;
+    for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {
+      U32 freq = freqs[ctx->dmerAt[pos]];
+      if (freq != 0) {
+        newBegin = MIN(newBegin, pos);
+        newEnd = pos + 1;
+      }
+    }
+    bestSegment.begin = newBegin;
+    bestSegment.end = newEnd;
+  }
+  {
+    /* Zero out the frequency of each dmer covered by the chosen segment. */
+    U32 pos;
+    for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {
+      freqs[ctx->dmerAt[pos]] = 0;
+    }
+  }
+  return bestSegment;
+}
+
+/**
+ * Check the validity of the parameters.
+ * Returns non-zero if the parameters are valid and 0 otherwise.
+ */
+static int COVER_checkParameters(ZDICT_cover_params_t parameters,
+                                 size_t maxDictSize) {
+  /* k and d are required parameters */
+  if (parameters.d == 0 || parameters.k == 0) {
+    return 0;
+  }
+  /* k <= maxDictSize */
+  if (parameters.k > maxDictSize) {
+    return 0;
+  }
+  /* d <= k */
+  if (parameters.d > parameters.k) {
+    return 0;
+  }
+  /* 0 < splitPoint <= 1 */
+  if (parameters.splitPoint <= 0 || parameters.splitPoint > 1){
+    return 0;
+  }
+  return 1;
+}
+
+/**
+ * Clean up a context initialized with `COVER_ctx_init()`.
+ */
+static void COVER_ctx_destroy(COVER_ctx_t *ctx) {
+  if (!ctx) {
+    return;
+  }
+  if (ctx->suffix) {
+    free(ctx->suffix);
+    ctx->suffix = NULL;
+  }
+  if (ctx->freqs) {
+    free(ctx->freqs);
+    ctx->freqs = NULL;
+  }
+  if (ctx->dmerAt) {
+    free(ctx->dmerAt);
+    ctx->dmerAt = NULL;
+  }
+  if (ctx->offsets) {
+    free(ctx->offsets);
+    ctx->offsets = NULL;
+  }
+}
+
+/**
+ * Prepare a context for dictionary building.
+ * The context is only dependent on the parameter `d` and can used multiple
+ * times.
+ * Returns 1 on success or zero on error.
+ * The context must be destroyed with `COVER_ctx_destroy()`.
+ */
+static int COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
+                          const size_t *samplesSizes, unsigned nbSamples,
+                          unsigned d, double splitPoint) {
+  const BYTE *const samples = (const BYTE *)samplesBuffer;
+  const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
+  /* Split samples into testing and training sets */
+  const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples;
+  const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples;
+  const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize;
+  const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize;
+  /* Checks */
+  if (totalSamplesSize < MAX(d, sizeof(U64)) ||
+      totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
+    DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
+                 (unsigned)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20));
+    return 0;
+  }
+  /* Check if there are at least 5 training samples */
+  if (nbTrainSamples < 5) {
+    DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid.", nbTrainSamples);
+    return 0;
+  }
+  /* Check if there's testing sample */
+  if (nbTestSamples < 1) {
+    DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.", nbTestSamples);
+    return 0;
+  }
+  /* Zero the context */
+  memset(ctx, 0, sizeof(*ctx));
+  DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples,
+               (unsigned)trainingSamplesSize);
+  DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples,
+               (unsigned)testSamplesSize);
+  ctx->samples = samples;
+  ctx->samplesSizes = samplesSizes;
+  ctx->nbSamples = nbSamples;
+  ctx->nbTrainSamples = nbTrainSamples;
+  ctx->nbTestSamples = nbTestSamples;
+  /* Partial suffix array */
+  ctx->suffixSize = trainingSamplesSize - MAX(d, sizeof(U64)) + 1;
+  ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+  /* Maps index to the dmerID */
+  ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+  /* The offsets of each file */
+  ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t));
+  if (!ctx->suffix || !ctx->dmerAt || !ctx->offsets) {
+    DISPLAYLEVEL(1, "Failed to allocate scratch buffers\n");
+    COVER_ctx_destroy(ctx);
+    return 0;
+  }
+  ctx->freqs = NULL;
+  ctx->d = d;
+
+  /* Fill offsets from the samplesSizes */
+  {
+    U32 i;
+    ctx->offsets[0] = 0;
+    for (i = 1; i <= nbSamples; ++i) {
+      ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1];
+    }
+  }
+  DISPLAYLEVEL(2, "Constructing partial suffix array\n");
+  {
+    /* suffix is a partial suffix array.
+     * It only sorts suffixes by their first parameters.d bytes.
+     * The sort is stable, so each dmer group is sorted by position in input.
+     */
+    U32 i;
+    for (i = 0; i < ctx->suffixSize; ++i) {
+      ctx->suffix[i] = i;
+    }
+    /* qsort doesn't take an opaque pointer, so pass as a global.
+     * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is.
+     */
+    g_ctx = ctx;
+#if defined(__OpenBSD__)
+    mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32),
+          (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
+#else
+    qsort(ctx->suffix, ctx->suffixSize, sizeof(U32),
+          (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
+#endif
+  }
+  DISPLAYLEVEL(2, "Computing frequencies\n");
+  /* For each dmer group (group of positions with the same first d bytes):
+   * 1. For each position we set dmerAt[position] = dmerID.  The dmerID is
+   *    (groupBeginPtr - suffix).  This allows us to go from position to
+   *    dmerID so we can look up values in freq.
+   * 2. We calculate how many samples the dmer occurs in and save it in
+   *    freqs[dmerId].
+   */
+  COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx,
+                (ctx->d <= 8 ? &COVER_cmp8 : &COVER_cmp), &COVER_group);
+  ctx->freqs = ctx->suffix;
+  ctx->suffix = NULL;
+  return 1;
+}
+
+/**
+ * Given the prepared context build the dictionary.
+ */
+static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
+                                    COVER_map_t *activeDmers, void *dictBuffer,
+                                    size_t dictBufferCapacity,
+                                    ZDICT_cover_params_t parameters) {
+  BYTE *const dict = (BYTE *)dictBuffer;
+  size_t tail = dictBufferCapacity;
+  /* Divide the data up into epochs of equal size.
+   * We will select at least one segment from each epoch.
+   */
+  const unsigned epochs = MAX(1, (U32)(dictBufferCapacity / parameters.k / 4));
+  const unsigned epochSize = (U32)(ctx->suffixSize / epochs);
+  size_t epoch;
+  DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n",
+                epochs, epochSize);
+  /* Loop through the epochs until there are no more segments or the dictionary
+   * is full.
+   */
+  for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs) {
+    const U32 epochBegin = (U32)(epoch * epochSize);
+    const U32 epochEnd = epochBegin + epochSize;
+    size_t segmentSize;
+    /* Select a segment */
+    COVER_segment_t segment = COVER_selectSegment(
+        ctx, freqs, activeDmers, epochBegin, epochEnd, parameters);
+    /* If the segment covers no dmers, then we are out of content */
+    if (segment.score == 0) {
+      break;
+    }
+    /* Trim the segment if necessary and if it is too small then we are done */
+    segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
+    if (segmentSize < parameters.d) {
+      break;
+    }
+    /* We fill the dictionary from the back to allow the best segments to be
+     * referenced with the smallest offsets.
+     */
+    tail -= segmentSize;
+    memcpy(dict + tail, ctx->samples + segment.begin, segmentSize);
+    DISPLAYUPDATE(
+        2, "\r%u%%       ",
+        (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity));
+  }
+  DISPLAYLEVEL(2, "\r%79s\r", "");
+  return tail;
+}
+
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
+    void *dictBuffer, size_t dictBufferCapacity,
+    const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+    ZDICT_cover_params_t parameters)
+{
+  BYTE* const dict = (BYTE*)dictBuffer;
+  COVER_ctx_t ctx;
+  COVER_map_t activeDmers;
+  parameters.splitPoint = 1.0;
+  /* Initialize global data */
+  g_displayLevel = parameters.zParams.notificationLevel;
+  /* Checks */
+  if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
+    DISPLAYLEVEL(1, "Cover parameters incorrect\n");
+    return ERROR(GENERIC);
+  }
+  if (nbSamples == 0) {
+    DISPLAYLEVEL(1, "Cover must have at least one input file\n");
+    return ERROR(GENERIC);
+  }
+  if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+    DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
+                 ZDICT_DICTSIZE_MIN);
+    return ERROR(dstSize_tooSmall);
+  }
+  /* Initialize context and activeDmers */
+  if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
+                      parameters.d, parameters.splitPoint)) {
+    return ERROR(GENERIC);
+  }
+  if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {
+    DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");
+    COVER_ctx_destroy(&ctx);
+    return ERROR(GENERIC);
+  }
+
+  DISPLAYLEVEL(2, "Building dictionary\n");
+  {
+    const size_t tail =
+        COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer,
+                              dictBufferCapacity, parameters);
+    const size_t dictionarySize = ZDICT_finalizeDictionary(
+        dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+        samplesBuffer, samplesSizes, nbSamples, parameters.zParams);
+    if (!ZSTD_isError(dictionarySize)) {
+      DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",
+                   (unsigned)dictionarySize);
+    }
+    COVER_ctx_destroy(&ctx);
+    COVER_map_destroy(&activeDmers);
+    return dictionarySize;
+  }
+}
+
+
+
+size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters,
+                                    const size_t *samplesSizes, const BYTE *samples,
+                                    size_t *offsets,
+                                    size_t nbTrainSamples, size_t nbSamples,
+                                    BYTE *const dict, size_t dictBufferCapacity) {
+  size_t totalCompressedSize = ERROR(GENERIC);
+  /* Pointers */
+  ZSTD_CCtx *cctx;
+  ZSTD_CDict *cdict;
+  void *dst;
+  /* Local variables */
+  size_t dstCapacity;
+  size_t i;
+  /* Allocate dst with enough space to compress the maximum sized sample */
+  {
+    size_t maxSampleSize = 0;
+    i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0;
+    for (; i < nbSamples; ++i) {
+      maxSampleSize = MAX(samplesSizes[i], maxSampleSize);
+    }
+    dstCapacity = ZSTD_compressBound(maxSampleSize);
+    dst = malloc(dstCapacity);
+  }
+  /* Create the cctx and cdict */
+  cctx = ZSTD_createCCtx();
+  cdict = ZSTD_createCDict(dict, dictBufferCapacity,
+                           parameters.zParams.compressionLevel);
+  if (!dst || !cctx || !cdict) {
+    goto _compressCleanup;
+  }
+  /* Compress each sample and sum their sizes (or error) */
+  totalCompressedSize = dictBufferCapacity;
+  i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0;
+  for (; i < nbSamples; ++i) {
+    const size_t size = ZSTD_compress_usingCDict(
+        cctx, dst, dstCapacity, samples + offsets[i],
+        samplesSizes[i], cdict);
+    if (ZSTD_isError(size)) {
+      totalCompressedSize = ERROR(GENERIC);
+      goto _compressCleanup;
+    }
+    totalCompressedSize += size;
+  }
+_compressCleanup:
+  ZSTD_freeCCtx(cctx);
+  ZSTD_freeCDict(cdict);
+  if (dst) {
+    free(dst);
+  }
+  return totalCompressedSize;
+}
+
+
+/**
+ * Initialize the `COVER_best_t`.
+ */
+void COVER_best_init(COVER_best_t *best) {
+  if (best==NULL) return; /* compatible with init on NULL */
+  (void)ZSTD_pthread_mutex_init(&best->mutex, NULL);
+  (void)ZSTD_pthread_cond_init(&best->cond, NULL);
+  best->liveJobs = 0;
+  best->dict = NULL;
+  best->dictSize = 0;
+  best->compressedSize = (size_t)-1;
+  memset(&best->parameters, 0, sizeof(best->parameters));
+}
+
+/**
+ * Wait until liveJobs == 0.
+ */
+void COVER_best_wait(COVER_best_t *best) {
+  if (!best) {
+    return;
+  }
+  ZSTD_pthread_mutex_lock(&best->mutex);
+  while (best->liveJobs != 0) {
+    ZSTD_pthread_cond_wait(&best->cond, &best->mutex);
+  }
+  ZSTD_pthread_mutex_unlock(&best->mutex);
+}
+
+/**
+ * Call COVER_best_wait() and then destroy the COVER_best_t.
+ */
+void COVER_best_destroy(COVER_best_t *best) {
+  if (!best) {
+    return;
+  }
+  COVER_best_wait(best);
+  if (best->dict) {
+    free(best->dict);
+  }
+  ZSTD_pthread_mutex_destroy(&best->mutex);
+  ZSTD_pthread_cond_destroy(&best->cond);
+}
+
+/**
+ * Called when a thread is about to be launched.
+ * Increments liveJobs.
+ */
+void COVER_best_start(COVER_best_t *best) {
+  if (!best) {
+    return;
+  }
+  ZSTD_pthread_mutex_lock(&best->mutex);
+  ++best->liveJobs;
+  ZSTD_pthread_mutex_unlock(&best->mutex);
+}
+
+/**
+ * Called when a thread finishes executing, both on error or success.
+ * Decrements liveJobs and signals any waiting threads if liveJobs == 0.
+ * If this dictionary is the best so far save it and its parameters.
+ */
+void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
+                              ZDICT_cover_params_t parameters, void *dict,
+                              size_t dictSize) {
+  if (!best) {
+    return;
+  }
+  {
+    size_t liveJobs;
+    ZSTD_pthread_mutex_lock(&best->mutex);
+    --best->liveJobs;
+    liveJobs = best->liveJobs;
+    /* If the new dictionary is better */
+    if (compressedSize < best->compressedSize) {
+      /* Allocate space if necessary */
+      if (!best->dict || best->dictSize < dictSize) {
+        if (best->dict) {
+          free(best->dict);
+        }
+        best->dict = malloc(dictSize);
+        if (!best->dict) {
+          best->compressedSize = ERROR(GENERIC);
+          best->dictSize = 0;
+          ZSTD_pthread_cond_signal(&best->cond);
+          ZSTD_pthread_mutex_unlock(&best->mutex);
+          return;
+        }
+      }
+      /* Save the dictionary, parameters, and size */
+      memcpy(best->dict, dict, dictSize);
+      best->dictSize = dictSize;
+      best->parameters = parameters;
+      best->compressedSize = compressedSize;
+    }
+    if (liveJobs == 0) {
+      ZSTD_pthread_cond_broadcast(&best->cond);
+    }
+    ZSTD_pthread_mutex_unlock(&best->mutex);
+  }
+}
+
+/**
+ * Parameters for COVER_tryParameters().
+ */
+typedef struct COVER_tryParameters_data_s {
+  const COVER_ctx_t *ctx;
+  COVER_best_t *best;
+  size_t dictBufferCapacity;
+  ZDICT_cover_params_t parameters;
+} COVER_tryParameters_data_t;
+
+/**
+ * Tries a set of parameters and updates the COVER_best_t with the results.
+ * This function is thread safe if zstd is compiled with multithreaded support.
+ * It takes its parameters as an *OWNING* opaque pointer to support threading.
+ */
+static void COVER_tryParameters(void *opaque) {
+  /* Save parameters as local variables */
+  COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque;
+  const COVER_ctx_t *const ctx = data->ctx;
+  const ZDICT_cover_params_t parameters = data->parameters;
+  size_t dictBufferCapacity = data->dictBufferCapacity;
+  size_t totalCompressedSize = ERROR(GENERIC);
+  /* Allocate space for hash table, dict, and freqs */
+  COVER_map_t activeDmers;
+  BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
+  U32 *freqs = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+  if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {
+    DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");
+    goto _cleanup;
+  }
+  if (!dict || !freqs) {
+    DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n");
+    goto _cleanup;
+  }
+  /* Copy the frequencies because we need to modify them */
+  memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32));
+  /* Build the dictionary */
+  {
+    const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict,
+                                              dictBufferCapacity, parameters);
+    dictBufferCapacity = ZDICT_finalizeDictionary(
+        dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+        ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples,
+        parameters.zParams);
+    if (ZDICT_isError(dictBufferCapacity)) {
+      DISPLAYLEVEL(1, "Failed to finalize dictionary\n");
+      goto _cleanup;
+    }
+  }
+  /* Check total compressed size */
+  totalCompressedSize = COVER_checkTotalCompressedSize(parameters, ctx->samplesSizes,
+                                                       ctx->samples, ctx->offsets,
+                                                       ctx->nbTrainSamples, ctx->nbSamples,
+                                                       dict, dictBufferCapacity);
+
+_cleanup:
+  COVER_best_finish(data->best, totalCompressedSize, parameters, dict,
+                    dictBufferCapacity);
+  free(data);
+  COVER_map_destroy(&activeDmers);
+  if (dict) {
+    free(dict);
+  }
+  if (freqs) {
+    free(freqs);
+  }
+}
+
+ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
+    void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
+    const size_t *samplesSizes, unsigned nbSamples,
+    ZDICT_cover_params_t *parameters) {
+  /* constants */
+  const unsigned nbThreads = parameters->nbThreads;
+  const double splitPoint =
+      parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
+  const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
+  const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
+  const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
+  const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k;
+  const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps;
+  const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);
+  const unsigned kIterations =
+      (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
+  /* Local variables */
+  const int displayLevel = parameters->zParams.notificationLevel;
+  unsigned iteration = 1;
+  unsigned d;
+  unsigned k;
+  COVER_best_t best;
+  POOL_ctx *pool = NULL;
+
+  /* Checks */
+  if (splitPoint <= 0 || splitPoint > 1) {
+    LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
+    return ERROR(GENERIC);
+  }
+  if (kMinK < kMaxD || kMaxK < kMinK) {
+    LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
+    return ERROR(GENERIC);
+  }
+  if (nbSamples == 0) {
+    DISPLAYLEVEL(1, "Cover must have at least one input file\n");
+    return ERROR(GENERIC);
+  }
+  if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+    DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
+                 ZDICT_DICTSIZE_MIN);
+    return ERROR(dstSize_tooSmall);
+  }
+  if (nbThreads > 1) {
+    pool = POOL_create(nbThreads, 1);
+    if (!pool) {
+      return ERROR(memory_allocation);
+    }
+  }
+  /* Initialization */
+  COVER_best_init(&best);
+  /* Turn down global display level to clean up display at level 2 and below */
+  g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
+  /* Loop through d first because each new value needs a new context */
+  LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
+                    kIterations);
+  for (d = kMinD; d <= kMaxD; d += 2) {
+    /* Initialize the context for this value of d */
+    COVER_ctx_t ctx;
+    LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);
+    if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint)) {
+      LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");
+      COVER_best_destroy(&best);
+      POOL_free(pool);
+      return ERROR(GENERIC);
+    }
+    /* Loop through k reusing the same context */
+    for (k = kMinK; k <= kMaxK; k += kStepSize) {
+      /* Prepare the arguments */
+      COVER_tryParameters_data_t *data = (COVER_tryParameters_data_t *)malloc(
+          sizeof(COVER_tryParameters_data_t));
+      LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);
+      if (!data) {
+        LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");
+        COVER_best_destroy(&best);
+        COVER_ctx_destroy(&ctx);
+        POOL_free(pool);
+        return ERROR(GENERIC);
+      }
+      data->ctx = &ctx;
+      data->best = &best;
+      data->dictBufferCapacity = dictBufferCapacity;
+      data->parameters = *parameters;
+      data->parameters.k = k;
+      data->parameters.d = d;
+      data->parameters.splitPoint = splitPoint;
+      data->parameters.steps = kSteps;
+      data->parameters.zParams.notificationLevel = g_displayLevel;
+      /* Check the parameters */
+      if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) {
+        DISPLAYLEVEL(1, "Cover parameters incorrect\n");
+        free(data);
+        continue;
+      }
+      /* Call the function and pass ownership of data to it */
+      COVER_best_start(&best);
+      if (pool) {
+        POOL_add(pool, &COVER_tryParameters, data);
+      } else {
+        COVER_tryParameters(data);
+      }
+      /* Print status */
+      LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%%       ",
+                         (unsigned)((iteration * 100) / kIterations));
+      ++iteration;
+    }
+    COVER_best_wait(&best);
+    COVER_ctx_destroy(&ctx);
+  }
+  LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");
+  /* Fill the output buffer and parameters with output of the best parameters */
+  {
+    const size_t dictSize = best.dictSize;
+    if (ZSTD_isError(best.compressedSize)) {
+      const size_t compressedSize = best.compressedSize;
+      COVER_best_destroy(&best);
+      POOL_free(pool);
+      return compressedSize;
+    }
+    *parameters = best.parameters;
+    memcpy(dictBuffer, best.dict, dictSize);
+    COVER_best_destroy(&best);
+    POOL_free(pool);
+    return dictSize;
+  }
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/cover.h b/Utilities/cmzstd/lib/dictBuilder/cover.h
new file mode 100644
index 0000000..82e2e1c
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/cover.h
@@ -0,0 +1,83 @@
+#include <stdio.h>  /* fprintf */
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memset */
+#include <time.h>   /* clock */
+#include "mem.h" /* read */
+#include "pool.h"
+#include "threading.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+/**
+ * COVER_best_t is used for two purposes:
+ * 1. Synchronizing threads.
+ * 2. Saving the best parameters and dictionary.
+ *
+ * All of the methods except COVER_best_init() are thread safe if zstd is
+ * compiled with multithreaded support.
+ */
+typedef struct COVER_best_s {
+  ZSTD_pthread_mutex_t mutex;
+  ZSTD_pthread_cond_t cond;
+  size_t liveJobs;
+  void *dict;
+  size_t dictSize;
+  ZDICT_cover_params_t parameters;
+  size_t compressedSize;
+} COVER_best_t;
+
+/**
+ * A segment is a range in the source as well as the score of the segment.
+ */
+typedef struct {
+  U32 begin;
+  U32 end;
+  U32 score;
+} COVER_segment_t;
+
+/**
+ *  Checks total compressed size of a dictionary
+ */
+size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters,
+                                      const size_t *samplesSizes, const BYTE *samples,
+                                      size_t *offsets,
+                                      size_t nbTrainSamples, size_t nbSamples,
+                                      BYTE *const dict, size_t dictBufferCapacity);
+
+/**
+ * Returns the sum of the sample sizes.
+ */
+size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) ;
+
+/**
+ * Initialize the `COVER_best_t`.
+ */
+void COVER_best_init(COVER_best_t *best);
+
+/**
+ * Wait until liveJobs == 0.
+ */
+void COVER_best_wait(COVER_best_t *best);
+
+/**
+ * Call COVER_best_wait() and then destroy the COVER_best_t.
+ */
+void COVER_best_destroy(COVER_best_t *best);
+
+/**
+ * Called when a thread is about to be launched.
+ * Increments liveJobs.
+ */
+void COVER_best_start(COVER_best_t *best);
+
+/**
+ * Called when a thread finishes executing, both on error or success.
+ * Decrements liveJobs and signals any waiting threads if liveJobs == 0.
+ * If this dictionary is the best so far save it and its parameters.
+ */
+void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
+                       ZDICT_cover_params_t parameters, void *dict,
+                       size_t dictSize);
diff --git a/Utilities/cmzstd/lib/dictBuilder/divsufsort.c b/Utilities/cmzstd/lib/dictBuilder/divsufsort.c
new file mode 100644
index 0000000..ead9220
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/divsufsort.c
@@ -0,0 +1,1913 @@
+/*
+ * divsufsort.c for libdivsufsort-lite
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*- Compiler specifics -*/
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+#if defined(_MSC_VER)
+#  pragma warning(disable : 4244)
+#  pragma warning(disable : 4127)    /* C4127 : Condition expression is constant */
+#endif
+
+
+/*- Dependencies -*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "divsufsort.h"
+
+/*- Constants -*/
+#if defined(INLINE)
+# undef INLINE
+#endif
+#if !defined(INLINE)
+# define INLINE __inline
+#endif
+#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1)
+# undef ALPHABET_SIZE
+#endif
+#if !defined(ALPHABET_SIZE)
+# define ALPHABET_SIZE (256)
+#endif
+#define BUCKET_A_SIZE (ALPHABET_SIZE)
+#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE)
+#if defined(SS_INSERTIONSORT_THRESHOLD)
+# if SS_INSERTIONSORT_THRESHOLD < 1
+#  undef SS_INSERTIONSORT_THRESHOLD
+#  define SS_INSERTIONSORT_THRESHOLD (1)
+# endif
+#else
+# define SS_INSERTIONSORT_THRESHOLD (8)
+#endif
+#if defined(SS_BLOCKSIZE)
+# if SS_BLOCKSIZE < 0
+#  undef SS_BLOCKSIZE
+#  define SS_BLOCKSIZE (0)
+# elif 32768 <= SS_BLOCKSIZE
+#  undef SS_BLOCKSIZE
+#  define SS_BLOCKSIZE (32767)
+# endif
+#else
+# define SS_BLOCKSIZE (1024)
+#endif
+/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */
+#if SS_BLOCKSIZE == 0
+# define SS_MISORT_STACKSIZE (96)
+#elif SS_BLOCKSIZE <= 4096
+# define SS_MISORT_STACKSIZE (16)
+#else
+# define SS_MISORT_STACKSIZE (24)
+#endif
+#define SS_SMERGE_STACKSIZE (32)
+#define TR_INSERTIONSORT_THRESHOLD (8)
+#define TR_STACKSIZE (64)
+
+
+/*- Macros -*/
+#ifndef SWAP
+# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0)
+#endif /* SWAP */
+#ifndef MIN
+# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif /* MIN */
+#ifndef MAX
+# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif /* MAX */
+#define STACK_PUSH(_a, _b, _c, _d)\
+  do {\
+    assert(ssize < STACK_SIZE);\
+    stack[ssize].a = (_a), stack[ssize].b = (_b),\
+    stack[ssize].c = (_c), stack[ssize++].d = (_d);\
+  } while(0)
+#define STACK_PUSH5(_a, _b, _c, _d, _e)\
+  do {\
+    assert(ssize < STACK_SIZE);\
+    stack[ssize].a = (_a), stack[ssize].b = (_b),\
+    stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\
+  } while(0)
+#define STACK_POP(_a, _b, _c, _d)\
+  do {\
+    assert(0 <= ssize);\
+    if(ssize == 0) { return; }\
+    (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\
+    (_c) = stack[ssize].c, (_d) = stack[ssize].d;\
+  } while(0)
+#define STACK_POP5(_a, _b, _c, _d, _e)\
+  do {\
+    assert(0 <= ssize);\
+    if(ssize == 0) { return; }\
+    (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\
+    (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\
+  } while(0)
+#define BUCKET_A(_c0) bucket_A[(_c0)]
+#if ALPHABET_SIZE == 256
+#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)])
+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)])
+#else
+#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)])
+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)])
+#endif
+
+
+/*- Private Functions -*/
+
+static const int lg_table[256]= {
+ -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+  5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
+
+static INLINE
+int
+ss_ilg(int n) {
+#if SS_BLOCKSIZE == 0
+  return (n & 0xffff0000) ?
+          ((n & 0xff000000) ?
+            24 + lg_table[(n >> 24) & 0xff] :
+            16 + lg_table[(n >> 16) & 0xff]) :
+          ((n & 0x0000ff00) ?
+             8 + lg_table[(n >>  8) & 0xff] :
+             0 + lg_table[(n >>  0) & 0xff]);
+#elif SS_BLOCKSIZE < 256
+  return lg_table[n];
+#else
+  return (n & 0xff00) ?
+          8 + lg_table[(n >> 8) & 0xff] :
+          0 + lg_table[(n >> 0) & 0xff];
+#endif
+}
+
+#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
+
+#if SS_BLOCKSIZE != 0
+
+static const int sqq_table[256] = {
+  0,  16,  22,  27,  32,  35,  39,  42,  45,  48,  50,  53,  55,  57,  59,  61,
+ 64,  65,  67,  69,  71,  73,  75,  76,  78,  80,  81,  83,  84,  86,  87,  89,
+ 90,  91,  93,  94,  96,  97,  98,  99, 101, 102, 103, 104, 106, 107, 108, 109,
+110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,
+156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
+169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180,
+181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191,
+192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201,
+202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
+212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221,
+221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230,
+230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
+239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
+247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
+};
+
+static INLINE
+int
+ss_isqrt(int x) {
+  int y, e;
+
+  if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; }
+  e = (x & 0xffff0000) ?
+        ((x & 0xff000000) ?
+          24 + lg_table[(x >> 24) & 0xff] :
+          16 + lg_table[(x >> 16) & 0xff]) :
+        ((x & 0x0000ff00) ?
+           8 + lg_table[(x >>  8) & 0xff] :
+           0 + lg_table[(x >>  0) & 0xff]);
+
+  if(e >= 16) {
+    y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7);
+    if(e >= 24) { y = (y + 1 + x / y) >> 1; }
+    y = (y + 1 + x / y) >> 1;
+  } else if(e >= 8) {
+    y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1;
+  } else {
+    return sqq_table[x] >> 4;
+  }
+
+  return (x < (y * y)) ? y - 1 : y;
+}
+
+#endif /* SS_BLOCKSIZE != 0 */
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Compares two suffixes. */
+static INLINE
+int
+ss_compare(const unsigned char *T,
+           const int *p1, const int *p2,
+           int depth) {
+  const unsigned char *U1, *U2, *U1n, *U2n;
+
+  for(U1 = T + depth + *p1,
+      U2 = T + depth + *p2,
+      U1n = T + *(p1 + 1) + 2,
+      U2n = T + *(p2 + 1) + 2;
+      (U1 < U1n) && (U2 < U2n) && (*U1 == *U2);
+      ++U1, ++U2) {
+  }
+
+  return U1 < U1n ?
+        (U2 < U2n ? *U1 - *U2 : 1) :
+        (U2 < U2n ? -1 : 0);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)
+
+/* Insertionsort for small size groups */
+static
+void
+ss_insertionsort(const unsigned char *T, const int *PA,
+                 int *first, int *last, int depth) {
+  int *i, *j;
+  int t;
+  int r;
+
+  for(i = last - 2; first <= i; --i) {
+    for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) {
+      do { *(j - 1) = *j; } while((++j < last) && (*j < 0));
+      if(last <= j) { break; }
+    }
+    if(r == 0) { *j = ~*j; }
+    *(j - 1) = t;
+  }
+}
+
+#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */
+
+
+/*---------------------------------------------------------------------------*/
+
+#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
+
+static INLINE
+void
+ss_fixdown(const unsigned char *Td, const int *PA,
+           int *SA, int i, int size) {
+  int j, k;
+  int v;
+  int c, d, e;
+
+  for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
+    d = Td[PA[SA[k = j++]]];
+    if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; }
+    if(d <= c) { break; }
+  }
+  SA[i] = v;
+}
+
+/* Simple top-down heapsort. */
+static
+void
+ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) {
+  int i, m;
+  int t;
+
+  m = size;
+  if((size % 2) == 0) {
+    m--;
+    if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); }
+  }
+
+  for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); }
+  if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); }
+  for(i = m - 1; 0 < i; --i) {
+    t = SA[0], SA[0] = SA[i];
+    ss_fixdown(Td, PA, SA, 0, i);
+    SA[i] = t;
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Returns the median of three elements. */
+static INLINE
+int *
+ss_median3(const unsigned char *Td, const int *PA,
+           int *v1, int *v2, int *v3) {
+  int *t;
+  if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); }
+  if(Td[PA[*v2]] > Td[PA[*v3]]) {
+    if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; }
+    else { return v3; }
+  }
+  return v2;
+}
+
+/* Returns the median of five elements. */
+static INLINE
+int *
+ss_median5(const unsigned char *Td, const int *PA,
+           int *v1, int *v2, int *v3, int *v4, int *v5) {
+  int *t;
+  if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); }
+  if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); }
+  if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); }
+  if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); }
+  if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); }
+  if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; }
+  return v3;
+}
+
+/* Returns the pivot element. */
+static INLINE
+int *
+ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) {
+  int *middle;
+  int t;
+
+  t = last - first;
+  middle = first + t / 2;
+
+  if(t <= 512) {
+    if(t <= 32) {
+      return ss_median3(Td, PA, first, middle, last - 1);
+    } else {
+      t >>= 2;
+      return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1);
+    }
+  }
+  t >>= 3;
+  first  = ss_median3(Td, PA, first, first + t, first + (t << 1));
+  middle = ss_median3(Td, PA, middle - t, middle, middle + t);
+  last   = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1);
+  return ss_median3(Td, PA, first, middle, last);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Binary partition for substrings. */
+static INLINE
+int *
+ss_partition(const int *PA,
+                    int *first, int *last, int depth) {
+  int *a, *b;
+  int t;
+  for(a = first - 1, b = last;;) {
+    for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; }
+    for(; (a < --b) && ((PA[*b] + depth) <  (PA[*b + 1] + 1));) { }
+    if(b <= a) { break; }
+    t = ~*b;
+    *b = *a;
+    *a = t;
+  }
+  if(first < a) { *first = ~*first; }
+  return a;
+}
+
+/* Multikey introsort for medium size groups. */
+static
+void
+ss_mintrosort(const unsigned char *T, const int *PA,
+              int *first, int *last,
+              int depth) {
+#define STACK_SIZE SS_MISORT_STACKSIZE
+  struct { int *a, *b, c; int d; } stack[STACK_SIZE];
+  const unsigned char *Td;
+  int *a, *b, *c, *d, *e, *f;
+  int s, t;
+  int ssize;
+  int limit;
+  int v, x = 0;
+
+  for(ssize = 0, limit = ss_ilg(last - first);;) {
+
+    if((last - first) <= SS_INSERTIONSORT_THRESHOLD) {
+#if 1 < SS_INSERTIONSORT_THRESHOLD
+      if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); }
+#endif
+      STACK_POP(first, last, depth, limit);
+      continue;
+    }
+
+    Td = T + depth;
+    if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); }
+    if(limit < 0) {
+      for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) {
+        if((x = Td[PA[*a]]) != v) {
+          if(1 < (a - first)) { break; }
+          v = x;
+          first = a;
+        }
+      }
+      if(Td[PA[*first] - 1] < v) {
+        first = ss_partition(PA, first, a, depth);
+      }
+      if((a - first) <= (last - a)) {
+        if(1 < (a - first)) {
+          STACK_PUSH(a, last, depth, -1);
+          last = a, depth += 1, limit = ss_ilg(a - first);
+        } else {
+          first = a, limit = -1;
+        }
+      } else {
+        if(1 < (last - a)) {
+          STACK_PUSH(first, a, depth + 1, ss_ilg(a - first));
+          first = a, limit = -1;
+        } else {
+          last = a, depth += 1, limit = ss_ilg(a - first);
+        }
+      }
+      continue;
+    }
+
+    /* choose pivot */
+    a = ss_pivot(Td, PA, first, last);
+    v = Td[PA[*a]];
+    SWAP(*first, *a);
+
+    /* partition */
+    for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { }
+    if(((a = b) < last) && (x < v)) {
+      for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) {
+        if(x == v) { SWAP(*b, *a); ++a; }
+      }
+    }
+    for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { }
+    if((b < (d = c)) && (x > v)) {
+      for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
+        if(x == v) { SWAP(*c, *d); --d; }
+      }
+    }
+    for(; b < c;) {
+      SWAP(*b, *c);
+      for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) {
+        if(x == v) { SWAP(*b, *a); ++a; }
+      }
+      for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
+        if(x == v) { SWAP(*c, *d); --d; }
+      }
+    }
+
+    if(a <= d) {
+      c = b - 1;
+
+      if((s = a - first) > (t = b - a)) { s = t; }
+      for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+      if((s = d - c) > (t = last - d - 1)) { s = t; }
+      for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+
+      a = first + (b - a), c = last - (d - c);
+      b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth);
+
+      if((a - first) <= (last - c)) {
+        if((last - c) <= (c - b)) {
+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+          STACK_PUSH(c, last, depth, limit);
+          last = a;
+        } else if((a - first) <= (c - b)) {
+          STACK_PUSH(c, last, depth, limit);
+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+          last = a;
+        } else {
+          STACK_PUSH(c, last, depth, limit);
+          STACK_PUSH(first, a, depth, limit);
+          first = b, last = c, depth += 1, limit = ss_ilg(c - b);
+        }
+      } else {
+        if((a - first) <= (c - b)) {
+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+          STACK_PUSH(first, a, depth, limit);
+          first = c;
+        } else if((last - c) <= (c - b)) {
+          STACK_PUSH(first, a, depth, limit);
+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+          first = c;
+        } else {
+          STACK_PUSH(first, a, depth, limit);
+          STACK_PUSH(c, last, depth, limit);
+          first = b, last = c, depth += 1, limit = ss_ilg(c - b);
+        }
+      }
+    } else {
+      limit += 1;
+      if(Td[PA[*first] - 1] < v) {
+        first = ss_partition(PA, first, last, depth);
+        limit = ss_ilg(last - first);
+      }
+      depth += 1;
+    }
+  }
+#undef STACK_SIZE
+}
+
+#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
+
+
+/*---------------------------------------------------------------------------*/
+
+#if SS_BLOCKSIZE != 0
+
+static INLINE
+void
+ss_blockswap(int *a, int *b, int n) {
+  int t;
+  for(; 0 < n; --n, ++a, ++b) {
+    t = *a, *a = *b, *b = t;
+  }
+}
+
+static INLINE
+void
+ss_rotate(int *first, int *middle, int *last) {
+  int *a, *b, t;
+  int l, r;
+  l = middle - first, r = last - middle;
+  for(; (0 < l) && (0 < r);) {
+    if(l == r) { ss_blockswap(first, middle, l); break; }
+    if(l < r) {
+      a = last - 1, b = middle - 1;
+      t = *a;
+      do {
+        *a-- = *b, *b-- = *a;
+        if(b < first) {
+          *a = t;
+          last = a;
+          if((r -= l + 1) <= l) { break; }
+          a -= 1, b = middle - 1;
+          t = *a;
+        }
+      } while(1);
+    } else {
+      a = first, b = middle;
+      t = *a;
+      do {
+        *a++ = *b, *b++ = *a;
+        if(last <= b) {
+          *a = t;
+          first = a + 1;
+          if((l -= r + 1) <= r) { break; }
+          a += 1, b = middle;
+          t = *a;
+        }
+      } while(1);
+    }
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static
+void
+ss_inplacemerge(const unsigned char *T, const int *PA,
+                int *first, int *middle, int *last,
+                int depth) {
+  const int *p;
+  int *a, *b;
+  int len, half;
+  int q, r;
+  int x;
+
+  for(;;) {
+    if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); }
+    else                { x = 0; p = PA +  *(last - 1); }
+    for(a = first, len = middle - first, half = len >> 1, r = -1;
+        0 < len;
+        len = half, half >>= 1) {
+      b = a + half;
+      q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth);
+      if(q < 0) {
+        a = b + 1;
+        half -= (len & 1) ^ 1;
+      } else {
+        r = q;
+      }
+    }
+    if(a < middle) {
+      if(r == 0) { *a = ~*a; }
+      ss_rotate(a, middle, last);
+      last -= middle - a;
+      middle = a;
+      if(first == middle) { break; }
+    }
+    --last;
+    if(x != 0) { while(*--last < 0) { } }
+    if(middle == last) { break; }
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Merge-forward with internal buffer. */
+static
+void
+ss_mergeforward(const unsigned char *T, const int *PA,
+                int *first, int *middle, int *last,
+                int *buf, int depth) {
+  int *a, *b, *c, *bufend;
+  int t;
+  int r;
+
+  bufend = buf + (middle - first) - 1;
+  ss_blockswap(buf, first, middle - first);
+
+  for(t = *(a = first), b = buf, c = middle;;) {
+    r = ss_compare(T, PA + *b, PA + *c, depth);
+    if(r < 0) {
+      do {
+        *a++ = *b;
+        if(bufend <= b) { *bufend = t; return; }
+        *b++ = *a;
+      } while(*b < 0);
+    } else if(r > 0) {
+      do {
+        *a++ = *c, *c++ = *a;
+        if(last <= c) {
+          while(b < bufend) { *a++ = *b, *b++ = *a; }
+          *a = *b, *b = t;
+          return;
+        }
+      } while(*c < 0);
+    } else {
+      *c = ~*c;
+      do {
+        *a++ = *b;
+        if(bufend <= b) { *bufend = t; return; }
+        *b++ = *a;
+      } while(*b < 0);
+
+      do {
+        *a++ = *c, *c++ = *a;
+        if(last <= c) {
+          while(b < bufend) { *a++ = *b, *b++ = *a; }
+          *a = *b, *b = t;
+          return;
+        }
+      } while(*c < 0);
+    }
+  }
+}
+
+/* Merge-backward with internal buffer. */
+static
+void
+ss_mergebackward(const unsigned char *T, const int *PA,
+                 int *first, int *middle, int *last,
+                 int *buf, int depth) {
+  const int *p1, *p2;
+  int *a, *b, *c, *bufend;
+  int t;
+  int r;
+  int x;
+
+  bufend = buf + (last - middle) - 1;
+  ss_blockswap(buf, middle, last - middle);
+
+  x = 0;
+  if(*bufend < 0)       { p1 = PA + ~*bufend; x |= 1; }
+  else                  { p1 = PA +  *bufend; }
+  if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; }
+  else                  { p2 = PA +  *(middle - 1); }
+  for(t = *(a = last - 1), b = bufend, c = middle - 1;;) {
+    r = ss_compare(T, p1, p2, depth);
+    if(0 < r) {
+      if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
+      *a-- = *b;
+      if(b <= buf) { *buf = t; break; }
+      *b-- = *a;
+      if(*b < 0) { p1 = PA + ~*b; x |= 1; }
+      else       { p1 = PA +  *b; }
+    } else if(r < 0) {
+      if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
+      *a-- = *c, *c-- = *a;
+      if(c < first) {
+        while(buf < b) { *a-- = *b, *b-- = *a; }
+        *a = *b, *b = t;
+        break;
+      }
+      if(*c < 0) { p2 = PA + ~*c; x |= 2; }
+      else       { p2 = PA +  *c; }
+    } else {
+      if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
+      *a-- = ~*b;
+      if(b <= buf) { *buf = t; break; }
+      *b-- = *a;
+      if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
+      *a-- = *c, *c-- = *a;
+      if(c < first) {
+        while(buf < b) { *a-- = *b, *b-- = *a; }
+        *a = *b, *b = t;
+        break;
+      }
+      if(*b < 0) { p1 = PA + ~*b; x |= 1; }
+      else       { p1 = PA +  *b; }
+      if(*c < 0) { p2 = PA + ~*c; x |= 2; }
+      else       { p2 = PA +  *c; }
+    }
+  }
+}
+
+/* D&C based merge. */
+static
+void
+ss_swapmerge(const unsigned char *T, const int *PA,
+             int *first, int *middle, int *last,
+             int *buf, int bufsize, int depth) {
+#define STACK_SIZE SS_SMERGE_STACKSIZE
+#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a)))
+#define MERGE_CHECK(a, b, c)\
+  do {\
+    if(((c) & 1) ||\
+       (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\
+      *(a) = ~*(a);\
+    }\
+    if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\
+      *(b) = ~*(b);\
+    }\
+  } while(0)
+  struct { int *a, *b, *c; int d; } stack[STACK_SIZE];
+  int *l, *r, *lm, *rm;
+  int m, len, half;
+  int ssize;
+  int check, next;
+
+  for(check = 0, ssize = 0;;) {
+    if((last - middle) <= bufsize) {
+      if((first < middle) && (middle < last)) {
+        ss_mergebackward(T, PA, first, middle, last, buf, depth);
+      }
+      MERGE_CHECK(first, last, check);
+      STACK_POP(first, middle, last, check);
+      continue;
+    }
+
+    if((middle - first) <= bufsize) {
+      if(first < middle) {
+        ss_mergeforward(T, PA, first, middle, last, buf, depth);
+      }
+      MERGE_CHECK(first, last, check);
+      STACK_POP(first, middle, last, check);
+      continue;
+    }
+
+    for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1;
+        0 < len;
+        len = half, half >>= 1) {
+      if(ss_compare(T, PA + GETIDX(*(middle + m + half)),
+                       PA + GETIDX(*(middle - m - half - 1)), depth) < 0) {
+        m += half + 1;
+        half -= (len & 1) ^ 1;
+      }
+    }
+
+    if(0 < m) {
+      lm = middle - m, rm = middle + m;
+      ss_blockswap(lm, middle, m);
+      l = r = middle, next = 0;
+      if(rm < last) {
+        if(*rm < 0) {
+          *rm = ~*rm;
+          if(first < lm) { for(; *--l < 0;) { } next |= 4; }
+          next |= 1;
+        } else if(first < lm) {
+          for(; *r < 0; ++r) { }
+          next |= 2;
+        }
+      }
+
+      if((l - first) <= (last - r)) {
+        STACK_PUSH(r, rm, last, (next & 3) | (check & 4));
+        middle = lm, last = l, check = (check & 3) | (next & 4);
+      } else {
+        if((next & 2) && (r == middle)) { next ^= 6; }
+        STACK_PUSH(first, lm, l, (check & 3) | (next & 4));
+        first = r, middle = rm, check = (next & 3) | (check & 4);
+      }
+    } else {
+      if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) {
+        *middle = ~*middle;
+      }
+      MERGE_CHECK(first, last, check);
+      STACK_POP(first, middle, last, check);
+    }
+  }
+#undef STACK_SIZE
+}
+
+#endif /* SS_BLOCKSIZE != 0 */
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Substring sort */
+static
+void
+sssort(const unsigned char *T, const int *PA,
+       int *first, int *last,
+       int *buf, int bufsize,
+       int depth, int n, int lastsuffix) {
+  int *a;
+#if SS_BLOCKSIZE != 0
+  int *b, *middle, *curbuf;
+  int j, k, curbufsize, limit;
+#endif
+  int i;
+
+  if(lastsuffix != 0) { ++first; }
+
+#if SS_BLOCKSIZE == 0
+  ss_mintrosort(T, PA, first, last, depth);
+#else
+  if((bufsize < SS_BLOCKSIZE) &&
+      (bufsize < (last - first)) &&
+      (bufsize < (limit = ss_isqrt(last - first)))) {
+    if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; }
+    buf = middle = last - limit, bufsize = limit;
+  } else {
+    middle = last, limit = 0;
+  }
+  for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) {
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+    ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth);
+#elif 1 < SS_BLOCKSIZE
+    ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth);
+#endif
+    curbufsize = last - (a + SS_BLOCKSIZE);
+    curbuf = a + SS_BLOCKSIZE;
+    if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; }
+    for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) {
+      ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth);
+    }
+  }
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+  ss_mintrosort(T, PA, a, middle, depth);
+#elif 1 < SS_BLOCKSIZE
+  ss_insertionsort(T, PA, a, middle, depth);
+#endif
+  for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) {
+    if(i & 1) {
+      ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth);
+      a -= k;
+    }
+  }
+  if(limit != 0) {
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+    ss_mintrosort(T, PA, middle, last, depth);
+#elif 1 < SS_BLOCKSIZE
+    ss_insertionsort(T, PA, middle, last, depth);
+#endif
+    ss_inplacemerge(T, PA, first, middle, last, depth);
+  }
+#endif
+
+  if(lastsuffix != 0) {
+    /* Insert last type B* suffix. */
+    int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2;
+    for(a = first, i = *(first - 1);
+        (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth)));
+        ++a) {
+      *(a - 1) = *a;
+    }
+    *(a - 1) = i;
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+int
+tr_ilg(int n) {
+  return (n & 0xffff0000) ?
+          ((n & 0xff000000) ?
+            24 + lg_table[(n >> 24) & 0xff] :
+            16 + lg_table[(n >> 16) & 0xff]) :
+          ((n & 0x0000ff00) ?
+             8 + lg_table[(n >>  8) & 0xff] :
+             0 + lg_table[(n >>  0) & 0xff]);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Simple insertionsort for small size groups. */
+static
+void
+tr_insertionsort(const int *ISAd, int *first, int *last) {
+  int *a, *b;
+  int t, r;
+
+  for(a = first + 1; a < last; ++a) {
+    for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) {
+      do { *(b + 1) = *b; } while((first <= --b) && (*b < 0));
+      if(b < first) { break; }
+    }
+    if(r == 0) { *b = ~*b; }
+    *(b + 1) = t;
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+void
+tr_fixdown(const int *ISAd, int *SA, int i, int size) {
+  int j, k;
+  int v;
+  int c, d, e;
+
+  for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
+    d = ISAd[SA[k = j++]];
+    if(d < (e = ISAd[SA[j]])) { k = j; d = e; }
+    if(d <= c) { break; }
+  }
+  SA[i] = v;
+}
+
+/* Simple top-down heapsort. */
+static
+void
+tr_heapsort(const int *ISAd, int *SA, int size) {
+  int i, m;
+  int t;
+
+  m = size;
+  if((size % 2) == 0) {
+    m--;
+    if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); }
+  }
+
+  for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); }
+  if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); }
+  for(i = m - 1; 0 < i; --i) {
+    t = SA[0], SA[0] = SA[i];
+    tr_fixdown(ISAd, SA, 0, i);
+    SA[i] = t;
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Returns the median of three elements. */
+static INLINE
+int *
+tr_median3(const int *ISAd, int *v1, int *v2, int *v3) {
+  int *t;
+  if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); }
+  if(ISAd[*v2] > ISAd[*v3]) {
+    if(ISAd[*v1] > ISAd[*v3]) { return v1; }
+    else { return v3; }
+  }
+  return v2;
+}
+
+/* Returns the median of five elements. */
+static INLINE
+int *
+tr_median5(const int *ISAd,
+           int *v1, int *v2, int *v3, int *v4, int *v5) {
+  int *t;
+  if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); }
+  if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); }
+  if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); }
+  if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); }
+  if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); }
+  if(ISAd[*v3] > ISAd[*v4]) { return v4; }
+  return v3;
+}
+
+/* Returns the pivot element. */
+static INLINE
+int *
+tr_pivot(const int *ISAd, int *first, int *last) {
+  int *middle;
+  int t;
+
+  t = last - first;
+  middle = first + t / 2;
+
+  if(t <= 512) {
+    if(t <= 32) {
+      return tr_median3(ISAd, first, middle, last - 1);
+    } else {
+      t >>= 2;
+      return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1);
+    }
+  }
+  t >>= 3;
+  first  = tr_median3(ISAd, first, first + t, first + (t << 1));
+  middle = tr_median3(ISAd, middle - t, middle, middle + t);
+  last   = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1);
+  return tr_median3(ISAd, first, middle, last);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct _trbudget_t trbudget_t;
+struct _trbudget_t {
+  int chance;
+  int remain;
+  int incval;
+  int count;
+};
+
+static INLINE
+void
+trbudget_init(trbudget_t *budget, int chance, int incval) {
+  budget->chance = chance;
+  budget->remain = budget->incval = incval;
+}
+
+static INLINE
+int
+trbudget_check(trbudget_t *budget, int size) {
+  if(size <= budget->remain) { budget->remain -= size; return 1; }
+  if(budget->chance == 0) { budget->count += size; return 0; }
+  budget->remain += budget->incval - size;
+  budget->chance -= 1;
+  return 1;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+void
+tr_partition(const int *ISAd,
+             int *first, int *middle, int *last,
+             int **pa, int **pb, int v) {
+  int *a, *b, *c, *d, *e, *f;
+  int t, s;
+  int x = 0;
+
+  for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { }
+  if(((a = b) < last) && (x < v)) {
+    for(; (++b < last) && ((x = ISAd[*b]) <= v);) {
+      if(x == v) { SWAP(*b, *a); ++a; }
+    }
+  }
+  for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { }
+  if((b < (d = c)) && (x > v)) {
+    for(; (b < --c) && ((x = ISAd[*c]) >= v);) {
+      if(x == v) { SWAP(*c, *d); --d; }
+    }
+  }
+  for(; b < c;) {
+    SWAP(*b, *c);
+    for(; (++b < c) && ((x = ISAd[*b]) <= v);) {
+      if(x == v) { SWAP(*b, *a); ++a; }
+    }
+    for(; (b < --c) && ((x = ISAd[*c]) >= v);) {
+      if(x == v) { SWAP(*c, *d); --d; }
+    }
+  }
+
+  if(a <= d) {
+    c = b - 1;
+    if((s = a - first) > (t = b - a)) { s = t; }
+    for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+    if((s = d - c) > (t = last - d - 1)) { s = t; }
+    for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+    first += (b - a), last -= (d - c);
+  }
+  *pa = first, *pb = last;
+}
+
+static
+void
+tr_copy(int *ISA, const int *SA,
+        int *first, int *a, int *b, int *last,
+        int depth) {
+  /* sort suffixes of middle partition
+     by using sorted order of suffixes of left and right partition. */
+  int *c, *d, *e;
+  int s, v;
+
+  v = b - SA - 1;
+  for(c = first, d = a - 1; c <= d; ++c) {
+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+      *++d = s;
+      ISA[s] = d - SA;
+    }
+  }
+  for(c = last - 1, e = d + 1, d = b; e < d; --c) {
+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+      *--d = s;
+      ISA[s] = d - SA;
+    }
+  }
+}
+
+static
+void
+tr_partialcopy(int *ISA, const int *SA,
+               int *first, int *a, int *b, int *last,
+               int depth) {
+  int *c, *d, *e;
+  int s, v;
+  int rank, lastrank, newrank = -1;
+
+  v = b - SA - 1;
+  lastrank = -1;
+  for(c = first, d = a - 1; c <= d; ++c) {
+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+      *++d = s;
+      rank = ISA[s + depth];
+      if(lastrank != rank) { lastrank = rank; newrank = d - SA; }
+      ISA[s] = newrank;
+    }
+  }
+
+  lastrank = -1;
+  for(e = d; first <= e; --e) {
+    rank = ISA[*e];
+    if(lastrank != rank) { lastrank = rank; newrank = e - SA; }
+    if(newrank != rank) { ISA[*e] = newrank; }
+  }
+
+  lastrank = -1;
+  for(c = last - 1, e = d + 1, d = b; e < d; --c) {
+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+      *--d = s;
+      rank = ISA[s + depth];
+      if(lastrank != rank) { lastrank = rank; newrank = d - SA; }
+      ISA[s] = newrank;
+    }
+  }
+}
+
+static
+void
+tr_introsort(int *ISA, const int *ISAd,
+             int *SA, int *first, int *last,
+             trbudget_t *budget) {
+#define STACK_SIZE TR_STACKSIZE
+  struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE];
+  int *a, *b, *c;
+  int t;
+  int v, x = 0;
+  int incr = ISAd - ISA;
+  int limit, next;
+  int ssize, trlink = -1;
+
+  for(ssize = 0, limit = tr_ilg(last - first);;) {
+
+    if(limit < 0) {
+      if(limit == -1) {
+        /* tandem repeat partition */
+        tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1);
+
+        /* update ranks */
+        if(a < last) {
+          for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }
+        }
+        if(b < last) {
+          for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; }
+        }
+
+        /* push */
+        if(1 < (b - a)) {
+          STACK_PUSH5(NULL, a, b, 0, 0);
+          STACK_PUSH5(ISAd - incr, first, last, -2, trlink);
+          trlink = ssize - 2;
+        }
+        if((a - first) <= (last - b)) {
+          if(1 < (a - first)) {
+            STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink);
+            last = a, limit = tr_ilg(a - first);
+          } else if(1 < (last - b)) {
+            first = b, limit = tr_ilg(last - b);
+          } else {
+            STACK_POP5(ISAd, first, last, limit, trlink);
+          }
+        } else {
+          if(1 < (last - b)) {
+            STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink);
+            first = b, limit = tr_ilg(last - b);
+          } else if(1 < (a - first)) {
+            last = a, limit = tr_ilg(a - first);
+          } else {
+            STACK_POP5(ISAd, first, last, limit, trlink);
+          }
+        }
+      } else if(limit == -2) {
+        /* tandem repeat copy */
+        a = stack[--ssize].b, b = stack[ssize].c;
+        if(stack[ssize].d == 0) {
+          tr_copy(ISA, SA, first, a, b, last, ISAd - ISA);
+        } else {
+          if(0 <= trlink) { stack[trlink].d = -1; }
+          tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA);
+        }
+        STACK_POP5(ISAd, first, last, limit, trlink);
+      } else {
+        /* sorted partition */
+        if(0 <= *first) {
+          a = first;
+          do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a));
+          first = a;
+        }
+        if(first < last) {
+          a = first; do { *a = ~*a; } while(*++a < 0);
+          next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1;
+          if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } }
+
+          /* push */
+          if(trbudget_check(budget, a - first)) {
+            if((a - first) <= (last - a)) {
+              STACK_PUSH5(ISAd, a, last, -3, trlink);
+              ISAd += incr, last = a, limit = next;
+            } else {
+              if(1 < (last - a)) {
+                STACK_PUSH5(ISAd + incr, first, a, next, trlink);
+                first = a, limit = -3;
+              } else {
+                ISAd += incr, last = a, limit = next;
+              }
+            }
+          } else {
+            if(0 <= trlink) { stack[trlink].d = -1; }
+            if(1 < (last - a)) {
+              first = a, limit = -3;
+            } else {
+              STACK_POP5(ISAd, first, last, limit, trlink);
+            }
+          }
+        } else {
+          STACK_POP5(ISAd, first, last, limit, trlink);
+        }
+      }
+      continue;
+    }
+
+    if((last - first) <= TR_INSERTIONSORT_THRESHOLD) {
+      tr_insertionsort(ISAd, first, last);
+      limit = -3;
+      continue;
+    }
+
+    if(limit-- == 0) {
+      tr_heapsort(ISAd, first, last - first);
+      for(a = last - 1; first < a; a = b) {
+        for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; }
+      }
+      limit = -3;
+      continue;
+    }
+
+    /* choose pivot */
+    a = tr_pivot(ISAd, first, last);
+    SWAP(*first, *a);
+    v = ISAd[*first];
+
+    /* partition */
+    tr_partition(ISAd, first, first + 1, last, &a, &b, v);
+    if((last - first) != (b - a)) {
+      next = (ISA[*a] != v) ? tr_ilg(b - a) : -1;
+
+      /* update ranks */
+      for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }
+      if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } }
+
+      /* push */
+      if((1 < (b - a)) && (trbudget_check(budget, b - a))) {
+        if((a - first) <= (last - b)) {
+          if((last - b) <= (b - a)) {
+            if(1 < (a - first)) {
+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+              STACK_PUSH5(ISAd, b, last, limit, trlink);
+              last = a;
+            } else if(1 < (last - b)) {
+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+              first = b;
+            } else {
+              ISAd += incr, first = a, last = b, limit = next;
+            }
+          } else if((a - first) <= (b - a)) {
+            if(1 < (a - first)) {
+              STACK_PUSH5(ISAd, b, last, limit, trlink);
+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+              last = a;
+            } else {
+              STACK_PUSH5(ISAd, b, last, limit, trlink);
+              ISAd += incr, first = a, last = b, limit = next;
+            }
+          } else {
+            STACK_PUSH5(ISAd, b, last, limit, trlink);
+            STACK_PUSH5(ISAd, first, a, limit, trlink);
+            ISAd += incr, first = a, last = b, limit = next;
+          }
+        } else {
+          if((a - first) <= (b - a)) {
+            if(1 < (last - b)) {
+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+              STACK_PUSH5(ISAd, first, a, limit, trlink);
+              first = b;
+            } else if(1 < (a - first)) {
+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+              last = a;
+            } else {
+              ISAd += incr, first = a, last = b, limit = next;
+            }
+          } else if((last - b) <= (b - a)) {
+            if(1 < (last - b)) {
+              STACK_PUSH5(ISAd, first, a, limit, trlink);
+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+              first = b;
+            } else {
+              STACK_PUSH5(ISAd, first, a, limit, trlink);
+              ISAd += incr, first = a, last = b, limit = next;
+            }
+          } else {
+            STACK_PUSH5(ISAd, first, a, limit, trlink);
+            STACK_PUSH5(ISAd, b, last, limit, trlink);
+            ISAd += incr, first = a, last = b, limit = next;
+          }
+        }
+      } else {
+        if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; }
+        if((a - first) <= (last - b)) {
+          if(1 < (a - first)) {
+            STACK_PUSH5(ISAd, b, last, limit, trlink);
+            last = a;
+          } else if(1 < (last - b)) {
+            first = b;
+          } else {
+            STACK_POP5(ISAd, first, last, limit, trlink);
+          }
+        } else {
+          if(1 < (last - b)) {
+            STACK_PUSH5(ISAd, first, a, limit, trlink);
+            first = b;
+          } else if(1 < (a - first)) {
+            last = a;
+          } else {
+            STACK_POP5(ISAd, first, last, limit, trlink);
+          }
+        }
+      }
+    } else {
+      if(trbudget_check(budget, last - first)) {
+        limit = tr_ilg(last - first), ISAd += incr;
+      } else {
+        if(0 <= trlink) { stack[trlink].d = -1; }
+        STACK_POP5(ISAd, first, last, limit, trlink);
+      }
+    }
+  }
+#undef STACK_SIZE
+}
+
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Tandem repeat sort */
+static
+void
+trsort(int *ISA, int *SA, int n, int depth) {
+  int *ISAd;
+  int *first, *last;
+  trbudget_t budget;
+  int t, skip, unsorted;
+
+  trbudget_init(&budget, tr_ilg(n) * 2 / 3, n);
+/*  trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */
+  for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) {
+    first = SA;
+    skip = 0;
+    unsorted = 0;
+    do {
+      if((t = *first) < 0) { first -= t; skip += t; }
+      else {
+        if(skip != 0) { *(first + skip) = skip; skip = 0; }
+        last = SA + ISA[t] + 1;
+        if(1 < (last - first)) {
+          budget.count = 0;
+          tr_introsort(ISA, ISAd, SA, first, last, &budget);
+          if(budget.count != 0) { unsorted += budget.count; }
+          else { skip = first - last; }
+        } else if((last - first) == 1) {
+          skip = -1;
+        }
+        first = last;
+      }
+    } while(first < (SA + n));
+    if(skip != 0) { *(first + skip) = skip; }
+    if(unsorted == 0) { break; }
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Sorts suffixes of type B*. */
+static
+int
+sort_typeBstar(const unsigned char *T, int *SA,
+               int *bucket_A, int *bucket_B,
+               int n, int openMP) {
+  int *PAb, *ISAb, *buf;
+#ifdef LIBBSC_OPENMP
+  int *curbuf;
+  int l;
+#endif
+  int i, j, k, t, m, bufsize;
+  int c0, c1;
+#ifdef LIBBSC_OPENMP
+  int d0, d1;
+#endif
+  (void)openMP;
+
+  /* Initialize bucket arrays. */
+  for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; }
+  for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; }
+
+  /* Count the number of occurrences of the first one or two characters of each
+     type A, B and B* suffix. Moreover, store the beginning position of all
+     type B* suffixes into the array SA. */
+  for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) {
+    /* type A suffix. */
+    do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1));
+    if(0 <= i) {
+      /* type B* suffix. */
+      ++BUCKET_BSTAR(c0, c1);
+      SA[--m] = i;
+      /* type B suffix. */
+      for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) {
+        ++BUCKET_B(c0, c1);
+      }
+    }
+  }
+  m = n - m;
+/*
+note:
+  A type B* suffix is lexicographically smaller than a type B suffix that
+  begins with the same first two characters.
+*/
+
+  /* Calculate the index of start/end point of each bucket. */
+  for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) {
+    t = i + BUCKET_A(c0);
+    BUCKET_A(c0) = i + j; /* start point */
+    i = t + BUCKET_B(c0, c0);
+    for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) {
+      j += BUCKET_BSTAR(c0, c1);
+      BUCKET_BSTAR(c0, c1) = j; /* end point */
+      i += BUCKET_B(c0, c1);
+    }
+  }
+
+  if(0 < m) {
+    /* Sort the type B* suffixes by their first two characters. */
+    PAb = SA + n - m; ISAb = SA + m;
+    for(i = m - 2; 0 <= i; --i) {
+      t = PAb[i], c0 = T[t], c1 = T[t + 1];
+      SA[--BUCKET_BSTAR(c0, c1)] = i;
+    }
+    t = PAb[m - 1], c0 = T[t], c1 = T[t + 1];
+    SA[--BUCKET_BSTAR(c0, c1)] = m - 1;
+
+    /* Sort the type B* substrings using sssort. */
+#ifdef LIBBSC_OPENMP
+    if (openMP)
+    {
+        buf = SA + m;
+        c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m;
+#pragma omp parallel default(shared) private(bufsize, curbuf, k, l, d0, d1)
+        {
+          bufsize = (n - (2 * m)) / omp_get_num_threads();
+          curbuf = buf + omp_get_thread_num() * bufsize;
+          k = 0;
+          for(;;) {
+            #pragma omp critical(sssort_lock)
+            {
+              if(0 < (l = j)) {
+                d0 = c0, d1 = c1;
+                do {
+                  k = BUCKET_BSTAR(d0, d1);
+                  if(--d1 <= d0) {
+                    d1 = ALPHABET_SIZE - 1;
+                    if(--d0 < 0) { break; }
+                  }
+                } while(((l - k) <= 1) && (0 < (l = k)));
+                c0 = d0, c1 = d1, j = k;
+              }
+            }
+            if(l == 0) { break; }
+            sssort(T, PAb, SA + k, SA + l,
+                   curbuf, bufsize, 2, n, *(SA + k) == (m - 1));
+          }
+        }
+    }
+    else
+    {
+        buf = SA + m, bufsize = n - (2 * m);
+        for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {
+          for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {
+            i = BUCKET_BSTAR(c0, c1);
+            if(1 < (j - i)) {
+              sssort(T, PAb, SA + i, SA + j,
+                     buf, bufsize, 2, n, *(SA + i) == (m - 1));
+            }
+          }
+        }
+    }
+#else
+    buf = SA + m, bufsize = n - (2 * m);
+    for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {
+      for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {
+        i = BUCKET_BSTAR(c0, c1);
+        if(1 < (j - i)) {
+          sssort(T, PAb, SA + i, SA + j,
+                 buf, bufsize, 2, n, *(SA + i) == (m - 1));
+        }
+      }
+    }
+#endif
+
+    /* Compute ranks of type B* substrings. */
+    for(i = m - 1; 0 <= i; --i) {
+      if(0 <= SA[i]) {
+        j = i;
+        do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i]));
+        SA[i + 1] = i - j;
+        if(i <= 0) { break; }
+      }
+      j = i;
+      do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0);
+      ISAb[SA[i]] = j;
+    }
+
+    /* Construct the inverse suffix array of type B* suffixes using trsort. */
+    trsort(ISAb, SA, m, 1);
+
+    /* Set the sorted order of tyoe B* suffixes. */
+    for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) {
+      for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { }
+      if(0 <= i) {
+        t = i;
+        for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { }
+        SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t;
+      }
+    }
+
+    /* Calculate the index of start/end point of each bucket. */
+    BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */
+    for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) {
+      i = BUCKET_A(c0 + 1) - 1;
+      for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) {
+        t = i - BUCKET_B(c0, c1);
+        BUCKET_B(c0, c1) = i; /* end point */
+
+        /* Move all type B* suffixes to the correct position. */
+        for(i = t, j = BUCKET_BSTAR(c0, c1);
+            j <= k;
+            --i, --k) { SA[i] = SA[k]; }
+      }
+      BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */
+      BUCKET_B(c0, c0) = i; /* end point */
+    }
+  }
+
+  return m;
+}
+
+/* Constructs the suffix array by using the sorted order of type B* suffixes. */
+static
+void
+construct_SA(const unsigned char *T, int *SA,
+             int *bucket_A, int *bucket_B,
+             int n, int m) {
+  int *i, *j, *k;
+  int s;
+  int c0, c1, c2;
+
+  if(0 < m) {
+    /* Construct the sorted order of type B suffixes by using
+       the sorted order of type B* suffixes. */
+    for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+      /* Scan the suffix array from right to left. */
+      for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+          j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+          i <= j;
+          --j) {
+        if(0 < (s = *j)) {
+          assert(T[s] == c1);
+          assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+          assert(T[s - 1] <= T[s]);
+          *j = ~s;
+          c0 = T[--s];
+          if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+          if(c0 != c2) {
+            if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+            k = SA + BUCKET_B(c2 = c0, c1);
+          }
+          assert(k < j); assert(k != NULL);
+          *k-- = s;
+        } else {
+          assert(((s == 0) && (T[s] == c1)) || (s < 0));
+          *j = ~s;
+        }
+      }
+    }
+  }
+
+  /* Construct the suffix array by using
+     the sorted order of type B suffixes. */
+  k = SA + BUCKET_A(c2 = T[n - 1]);
+  *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1);
+  /* Scan the suffix array from left to right. */
+  for(i = SA, j = SA + n; i < j; ++i) {
+    if(0 < (s = *i)) {
+      assert(T[s - 1] >= T[s]);
+      c0 = T[--s];
+      if((s == 0) || (T[s - 1] < c0)) { s = ~s; }
+      if(c0 != c2) {
+        BUCKET_A(c2) = k - SA;
+        k = SA + BUCKET_A(c2 = c0);
+      }
+      assert(i < k);
+      *k++ = s;
+    } else {
+      assert(s < 0);
+      *i = ~s;
+    }
+  }
+}
+
+/* Constructs the burrows-wheeler transformed string directly
+   by using the sorted order of type B* suffixes. */
+static
+int
+construct_BWT(const unsigned char *T, int *SA,
+              int *bucket_A, int *bucket_B,
+              int n, int m) {
+  int *i, *j, *k, *orig;
+  int s;
+  int c0, c1, c2;
+
+  if(0 < m) {
+    /* Construct the sorted order of type B suffixes by using
+       the sorted order of type B* suffixes. */
+    for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+      /* Scan the suffix array from right to left. */
+      for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+          j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+          i <= j;
+          --j) {
+        if(0 < (s = *j)) {
+          assert(T[s] == c1);
+          assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+          assert(T[s - 1] <= T[s]);
+          c0 = T[--s];
+          *j = ~((int)c0);
+          if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+          if(c0 != c2) {
+            if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+            k = SA + BUCKET_B(c2 = c0, c1);
+          }
+          assert(k < j); assert(k != NULL);
+          *k-- = s;
+        } else if(s != 0) {
+          *j = ~s;
+#ifndef NDEBUG
+        } else {
+          assert(T[s] == c1);
+#endif
+        }
+      }
+    }
+  }
+
+  /* Construct the BWTed string by using
+     the sorted order of type B suffixes. */
+  k = SA + BUCKET_A(c2 = T[n - 1]);
+  *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1);
+  /* Scan the suffix array from left to right. */
+  for(i = SA, j = SA + n, orig = SA; i < j; ++i) {
+    if(0 < (s = *i)) {
+      assert(T[s - 1] >= T[s]);
+      c0 = T[--s];
+      *i = c0;
+      if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); }
+      if(c0 != c2) {
+        BUCKET_A(c2) = k - SA;
+        k = SA + BUCKET_A(c2 = c0);
+      }
+      assert(i < k);
+      *k++ = s;
+    } else if(s != 0) {
+      *i = ~s;
+    } else {
+      orig = i;
+    }
+  }
+
+  return orig - SA;
+}
+
+/* Constructs the burrows-wheeler transformed string directly
+   by using the sorted order of type B* suffixes. */
+static
+int
+construct_BWT_indexes(const unsigned char *T, int *SA,
+                      int *bucket_A, int *bucket_B,
+                      int n, int m,
+                      unsigned char * num_indexes, int * indexes) {
+  int *i, *j, *k, *orig;
+  int s;
+  int c0, c1, c2;
+
+  int mod = n / 8;
+  {
+      mod |= mod >> 1;  mod |= mod >> 2;
+      mod |= mod >> 4;  mod |= mod >> 8;
+      mod |= mod >> 16; mod >>= 1;
+
+      *num_indexes = (unsigned char)((n - 1) / (mod + 1));
+  }
+
+  if(0 < m) {
+    /* Construct the sorted order of type B suffixes by using
+       the sorted order of type B* suffixes. */
+    for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+      /* Scan the suffix array from right to left. */
+      for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+          j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+          i <= j;
+          --j) {
+        if(0 < (s = *j)) {
+          assert(T[s] == c1);
+          assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+          assert(T[s - 1] <= T[s]);
+
+          if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA;
+
+          c0 = T[--s];
+          *j = ~((int)c0);
+          if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+          if(c0 != c2) {
+            if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+            k = SA + BUCKET_B(c2 = c0, c1);
+          }
+          assert(k < j); assert(k != NULL);
+          *k-- = s;
+        } else if(s != 0) {
+          *j = ~s;
+#ifndef NDEBUG
+        } else {
+          assert(T[s] == c1);
+#endif
+        }
+      }
+    }
+  }
+
+  /* Construct the BWTed string by using
+     the sorted order of type B suffixes. */
+  k = SA + BUCKET_A(c2 = T[n - 1]);
+  if (T[n - 2] < c2) {
+    if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA;
+    *k++ = ~((int)T[n - 2]);
+  }
+  else {
+    *k++ = n - 1;
+  }
+
+  /* Scan the suffix array from left to right. */
+  for(i = SA, j = SA + n, orig = SA; i < j; ++i) {
+    if(0 < (s = *i)) {
+      assert(T[s - 1] >= T[s]);
+
+      if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA;
+
+      c0 = T[--s];
+      *i = c0;
+      if(c0 != c2) {
+        BUCKET_A(c2) = k - SA;
+        k = SA + BUCKET_A(c2 = c0);
+      }
+      assert(i < k);
+      if((0 < s) && (T[s - 1] < c0)) {
+          if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA;
+          *k++ = ~((int)T[s - 1]);
+      } else
+        *k++ = s;
+    } else if(s != 0) {
+      *i = ~s;
+    } else {
+      orig = i;
+    }
+  }
+
+  return orig - SA;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/*- Function -*/
+
+int
+divsufsort(const unsigned char *T, int *SA, int n, int openMP) {
+  int *bucket_A, *bucket_B;
+  int m;
+  int err = 0;
+
+  /* Check arguments. */
+  if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; }
+  else if(n == 0) { return 0; }
+  else if(n == 1) { SA[0] = 0; return 0; }
+  else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; }
+
+  bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int));
+  bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int));
+
+  /* Suffixsort. */
+  if((bucket_A != NULL) && (bucket_B != NULL)) {
+    m = sort_typeBstar(T, SA, bucket_A, bucket_B, n, openMP);
+    construct_SA(T, SA, bucket_A, bucket_B, n, m);
+  } else {
+    err = -2;
+  }
+
+  free(bucket_B);
+  free(bucket_A);
+
+  return err;
+}
+
+int
+divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP) {
+  int *B;
+  int *bucket_A, *bucket_B;
+  int m, pidx, i;
+
+  /* Check arguments. */
+  if((T == NULL) || (U == NULL) || (n < 0)) { return -1; }
+  else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; }
+
+  if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); }
+  bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int));
+  bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int));
+
+  /* Burrows-Wheeler Transform. */
+  if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) {
+    m = sort_typeBstar(T, B, bucket_A, bucket_B, n, openMP);
+
+    if (num_indexes == NULL || indexes == NULL) {
+        pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m);
+    } else {
+        pidx = construct_BWT_indexes(T, B, bucket_A, bucket_B, n, m, num_indexes, indexes);
+    }
+
+    /* Copy to output string. */
+    U[0] = T[n - 1];
+    for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; }
+    for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; }
+    pidx += 1;
+  } else {
+    pidx = -2;
+  }
+
+  free(bucket_B);
+  free(bucket_A);
+  if(A == NULL) { free(B); }
+
+  return pidx;
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/divsufsort.h b/Utilities/cmzstd/lib/dictBuilder/divsufsort.h
new file mode 100644
index 0000000..5440994
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/divsufsort.h
@@ -0,0 +1,67 @@
+/*
+ * divsufsort.h for libdivsufsort-lite
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DIVSUFSORT_H
+#define _DIVSUFSORT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*- Prototypes -*/
+
+/**
+ * Constructs the suffix array of a given string.
+ * @param T [0..n-1] The input string.
+ * @param SA [0..n-1] The output array of suffixes.
+ * @param n The length of the given string.
+ * @param openMP enables OpenMP optimization.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+int
+divsufsort(const unsigned char *T, int *SA, int n, int openMP);
+
+/**
+ * Constructs the burrows-wheeler transformed string of a given string.
+ * @param T [0..n-1] The input string.
+ * @param U [0..n-1] The output string. (can be T)
+ * @param A [0..n-1] The temporary array. (can be NULL)
+ * @param n The length of the given string.
+ * @param num_indexes The length of secondary indexes array. (can be NULL)
+ * @param indexes The secondary indexes array. (can be NULL)
+ * @param openMP enables OpenMP optimization.
+ * @return The primary index if no error occurred, -1 or -2 otherwise.
+ */
+int
+divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _DIVSUFSORT_H */
diff --git a/Utilities/cmzstd/lib/dictBuilder/fastcover.c b/Utilities/cmzstd/lib/dictBuilder/fastcover.c
new file mode 100644
index 0000000..c289c06
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/fastcover.c
@@ -0,0 +1,728 @@
+/*-*************************************
+*  Dependencies
+***************************************/
+#include <stdio.h>  /* fprintf */
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memset */
+#include <time.h>   /* clock */
+
+#include "mem.h" /* read */
+#include "pool.h"
+#include "threading.h"
+#include "cover.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+
+/*-*************************************
+*  Constants
+***************************************/
+#define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
+#define FASTCOVER_MAX_F 31
+#define FASTCOVER_MAX_ACCEL 10
+#define DEFAULT_SPLITPOINT 0.75
+#define DEFAULT_F 20
+#define DEFAULT_ACCEL 1
+
+
+/*-*************************************
+*  Console display
+***************************************/
+static int g_displayLevel = 2;
+#define DISPLAY(...)                                                           \
+  {                                                                            \
+    fprintf(stderr, __VA_ARGS__);                                              \
+    fflush(stderr);                                                            \
+  }
+#define LOCALDISPLAYLEVEL(displayLevel, l, ...)                                \
+  if (displayLevel >= l) {                                                     \
+    DISPLAY(__VA_ARGS__);                                                      \
+  } /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */
+#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
+
+#define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \
+  if (displayLevel >= l) {                                                     \
+    if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \
+      g_time = clock();                                                        \
+      DISPLAY(__VA_ARGS__);                                                    \
+    }                                                                          \
+  }
+#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
+static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
+static clock_t g_time = 0;
+
+
+/*-*************************************
+* Hash Functions
+***************************************/
+static const U64 prime6bytes = 227718039650203ULL;
+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; }
+static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
+
+static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
+static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
+
+
+/**
+ * Hash the d-byte value pointed to by p and mod 2^f
+ */
+static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 h, unsigned d) {
+  if (d == 6) {
+    return ZSTD_hash6Ptr(p, h) & ((1 << h) - 1);
+  }
+  return ZSTD_hash8Ptr(p, h) & ((1 << h) - 1);
+}
+
+
+/*-*************************************
+* Acceleration
+***************************************/
+typedef struct {
+  unsigned finalize;    /* Percentage of training samples used for ZDICT_finalizeDictionary */
+  unsigned skip;        /* Number of dmer skipped between each dmer counted in computeFrequency */
+} FASTCOVER_accel_t;
+
+
+static const FASTCOVER_accel_t FASTCOVER_defaultAccelParameters[FASTCOVER_MAX_ACCEL+1] = {
+  { 100, 0 },   /* accel = 0, should not happen because accel = 0 defaults to accel = 1 */
+  { 100, 0 },   /* accel = 1 */
+  { 50, 1 },   /* accel = 2 */
+  { 34, 2 },   /* accel = 3 */
+  { 25, 3 },   /* accel = 4 */
+  { 20, 4 },   /* accel = 5 */
+  { 17, 5 },   /* accel = 6 */
+  { 14, 6 },   /* accel = 7 */
+  { 13, 7 },   /* accel = 8 */
+  { 11, 8 },   /* accel = 9 */
+  { 10, 9 },   /* accel = 10 */
+};
+
+
+/*-*************************************
+* Context
+***************************************/
+typedef struct {
+  const BYTE *samples;
+  size_t *offsets;
+  const size_t *samplesSizes;
+  size_t nbSamples;
+  size_t nbTrainSamples;
+  size_t nbTestSamples;
+  size_t nbDmers;
+  U32 *freqs;
+  unsigned d;
+  unsigned f;
+  FASTCOVER_accel_t accelParams;
+} FASTCOVER_ctx_t;
+
+
+/*-*************************************
+*  Helper functions
+***************************************/
+/**
+ * Selects the best segment in an epoch.
+ * Segments of are scored according to the function:
+ *
+ * Let F(d) be the frequency of all dmers with hash value d.
+ * Let S_i be hash value of the dmer at position i of segment S which has length k.
+ *
+ *     Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1})
+ *
+ * Once the dmer with hash value d is in the dictionay we set F(d) = 0.
+ */
+static COVER_segment_t FASTCOVER_selectSegment(const FASTCOVER_ctx_t *ctx,
+                                              U32 *freqs, U32 begin, U32 end,
+                                              ZDICT_cover_params_t parameters,
+                                              U16* segmentFreqs) {
+  /* Constants */
+  const U32 k = parameters.k;
+  const U32 d = parameters.d;
+  const U32 f = ctx->f;
+  const U32 dmersInK = k - d + 1;
+
+  /* Try each segment (activeSegment) and save the best (bestSegment) */
+  COVER_segment_t bestSegment = {0, 0, 0};
+  COVER_segment_t activeSegment;
+
+  /* Reset the activeDmers in the segment */
+  /* The activeSegment starts at the beginning of the epoch. */
+  activeSegment.begin = begin;
+  activeSegment.end = begin;
+  activeSegment.score = 0;
+
+  /* Slide the activeSegment through the whole epoch.
+   * Save the best segment in bestSegment.
+   */
+  while (activeSegment.end < end) {
+    /* Get hash value of current dmer */
+    const size_t idx = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.end, f, d);
+
+    /* Add frequency of this index to score if this is the first occurence of index in active segment */
+    if (segmentFreqs[idx] == 0) {
+      activeSegment.score += freqs[idx];
+    }
+    /* Increment end of segment and segmentFreqs*/
+    activeSegment.end += 1;
+    segmentFreqs[idx] += 1;
+    /* If the window is now too large, drop the first position */
+    if (activeSegment.end - activeSegment.begin == dmersInK + 1) {
+      /* Get hash value of the dmer to be eliminated from active segment */
+      const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d);
+      segmentFreqs[delIndex] -= 1;
+      /* Subtract frequency of this index from score if this is the last occurrence of this index in active segment */
+      if (segmentFreqs[delIndex] == 0) {
+        activeSegment.score -= freqs[delIndex];
+      }
+      /* Increment start of segment */
+      activeSegment.begin += 1;
+    }
+
+    /* If this segment is the best so far save it */
+    if (activeSegment.score > bestSegment.score) {
+      bestSegment = activeSegment;
+    }
+  }
+
+  /* Zero out rest of segmentFreqs array */
+  while (activeSegment.begin < end) {
+    const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d);
+    segmentFreqs[delIndex] -= 1;
+    activeSegment.begin += 1;
+  }
+
+  {
+    /*  Zero the frequency of hash value of each dmer covered by the chosen segment. */
+    U32 pos;
+    for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {
+      const size_t i = FASTCOVER_hashPtrToIndex(ctx->samples + pos, f, d);
+      freqs[i] = 0;
+    }
+  }
+
+  return bestSegment;
+}
+
+
+static int FASTCOVER_checkParameters(ZDICT_cover_params_t parameters,
+                                     size_t maxDictSize, unsigned f,
+                                     unsigned accel) {
+  /* k, d, and f are required parameters */
+  if (parameters.d == 0 || parameters.k == 0) {
+    return 0;
+  }
+  /* d has to be 6 or 8 */
+  if (parameters.d != 6 && parameters.d != 8) {
+    return 0;
+  }
+  /* k <= maxDictSize */
+  if (parameters.k > maxDictSize) {
+    return 0;
+  }
+  /* d <= k */
+  if (parameters.d > parameters.k) {
+    return 0;
+  }
+  /* 0 < f <= FASTCOVER_MAX_F*/
+  if (f > FASTCOVER_MAX_F || f == 0) {
+    return 0;
+  }
+  /* 0 < splitPoint <= 1 */
+  if (parameters.splitPoint <= 0 || parameters.splitPoint > 1) {
+    return 0;
+  }
+  /* 0 < accel <= 10 */
+  if (accel > 10 || accel == 0) {
+    return 0;
+  }
+  return 1;
+}
+
+
+/**
+ * Clean up a context initialized with `FASTCOVER_ctx_init()`.
+ */
+static void
+FASTCOVER_ctx_destroy(FASTCOVER_ctx_t* ctx)
+{
+    if (!ctx) return;
+
+    free(ctx->freqs);
+    ctx->freqs = NULL;
+
+    free(ctx->offsets);
+    ctx->offsets = NULL;
+}
+
+
+/**
+ * Calculate for frequency of hash value of each dmer in ctx->samples
+ */
+static void
+FASTCOVER_computeFrequency(U32* freqs, const FASTCOVER_ctx_t* ctx)
+{
+    const unsigned f = ctx->f;
+    const unsigned d = ctx->d;
+    const unsigned skip = ctx->accelParams.skip;
+    const unsigned readLength = MAX(d, 8);
+    size_t i;
+    assert(ctx->nbTrainSamples >= 5);
+    assert(ctx->nbTrainSamples <= ctx->nbSamples);
+    for (i = 0; i < ctx->nbTrainSamples; i++) {
+        size_t start = ctx->offsets[i];  /* start of current dmer */
+        size_t const currSampleEnd = ctx->offsets[i+1];
+        while (start + readLength <= currSampleEnd) {
+            const size_t dmerIndex = FASTCOVER_hashPtrToIndex(ctx->samples + start, f, d);
+            freqs[dmerIndex]++;
+            start = start + skip + 1;
+        }
+    }
+}
+
+
+/**
+ * Prepare a context for dictionary building.
+ * The context is only dependent on the parameter `d` and can used multiple
+ * times.
+ * Returns 1 on success or zero on error.
+ * The context must be destroyed with `FASTCOVER_ctx_destroy()`.
+ */
+static int
+FASTCOVER_ctx_init(FASTCOVER_ctx_t* ctx,
+                   const void* samplesBuffer,
+                   const size_t* samplesSizes, unsigned nbSamples,
+                   unsigned d, double splitPoint, unsigned f,
+                   FASTCOVER_accel_t accelParams)
+{
+    const BYTE* const samples = (const BYTE*)samplesBuffer;
+    const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
+    /* Split samples into testing and training sets */
+    const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples;
+    const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples;
+    const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize;
+    const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize;
+
+    /* Checks */
+    if (totalSamplesSize < MAX(d, sizeof(U64)) ||
+        totalSamplesSize >= (size_t)FASTCOVER_MAX_SAMPLES_SIZE) {
+        DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
+                    (unsigned)(totalSamplesSize >> 20), (FASTCOVER_MAX_SAMPLES_SIZE >> 20));
+        return 0;
+    }
+
+    /* Check if there are at least 5 training samples */
+    if (nbTrainSamples < 5) {
+        DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid\n", nbTrainSamples);
+        return 0;
+    }
+
+    /* Check if there's testing sample */
+    if (nbTestSamples < 1) {
+        DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.\n", nbTestSamples);
+        return 0;
+    }
+
+    /* Zero the context */
+    memset(ctx, 0, sizeof(*ctx));
+    DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples,
+                    (unsigned)trainingSamplesSize);
+    DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples,
+                    (unsigned)testSamplesSize);
+
+    ctx->samples = samples;
+    ctx->samplesSizes = samplesSizes;
+    ctx->nbSamples = nbSamples;
+    ctx->nbTrainSamples = nbTrainSamples;
+    ctx->nbTestSamples = nbTestSamples;
+    ctx->nbDmers = trainingSamplesSize - MAX(d, sizeof(U64)) + 1;
+    ctx->d = d;
+    ctx->f = f;
+    ctx->accelParams = accelParams;
+
+    /* The offsets of each file */
+    ctx->offsets = (size_t*)calloc((nbSamples + 1), sizeof(size_t));
+    if (ctx->offsets == NULL) {
+        DISPLAYLEVEL(1, "Failed to allocate scratch buffers \n");
+        FASTCOVER_ctx_destroy(ctx);
+        return 0;
+    }
+
+    /* Fill offsets from the samplesSizes */
+    {   U32 i;
+        ctx->offsets[0] = 0;
+        assert(nbSamples >= 5);
+        for (i = 1; i <= nbSamples; ++i) {
+            ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1];
+        }
+    }
+
+    /* Initialize frequency array of size 2^f */
+    ctx->freqs = (U32*)calloc(((U64)1 << f), sizeof(U32));
+    if (ctx->freqs == NULL) {
+        DISPLAYLEVEL(1, "Failed to allocate frequency table \n");
+        FASTCOVER_ctx_destroy(ctx);
+        return 0;
+    }
+
+    DISPLAYLEVEL(2, "Computing frequencies\n");
+    FASTCOVER_computeFrequency(ctx->freqs, ctx);
+
+    return 1;
+}
+
+
+/**
+ * Given the prepared context build the dictionary.
+ */
+static size_t
+FASTCOVER_buildDictionary(const FASTCOVER_ctx_t* ctx,
+                          U32* freqs,
+                          void* dictBuffer, size_t dictBufferCapacity,
+                          ZDICT_cover_params_t parameters,
+                          U16* segmentFreqs)
+{
+  BYTE *const dict = (BYTE *)dictBuffer;
+  size_t tail = dictBufferCapacity;
+  /* Divide the data up into epochs of equal size.
+   * We will select at least one segment from each epoch.
+   */
+  const unsigned epochs = MAX(1, (U32)(dictBufferCapacity / parameters.k));
+  const unsigned epochSize = (U32)(ctx->nbDmers / epochs);
+  size_t epoch;
+  DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n",
+                epochs, epochSize);
+  /* Loop through the epochs until there are no more segments or the dictionary
+   * is full.
+   */
+  for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs) {
+    const U32 epochBegin = (U32)(epoch * epochSize);
+    const U32 epochEnd = epochBegin + epochSize;
+    size_t segmentSize;
+    /* Select a segment */
+    COVER_segment_t segment = FASTCOVER_selectSegment(
+        ctx, freqs, epochBegin, epochEnd, parameters, segmentFreqs);
+
+    /* If the segment covers no dmers, then we are out of content */
+    if (segment.score == 0) {
+      break;
+    }
+
+    /* Trim the segment if necessary and if it is too small then we are done */
+    segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
+    if (segmentSize < parameters.d) {
+      break;
+    }
+
+    /* We fill the dictionary from the back to allow the best segments to be
+     * referenced with the smallest offsets.
+     */
+    tail -= segmentSize;
+    memcpy(dict + tail, ctx->samples + segment.begin, segmentSize);
+    DISPLAYUPDATE(
+        2, "\r%u%%       ",
+        (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity));
+  }
+  DISPLAYLEVEL(2, "\r%79s\r", "");
+  return tail;
+}
+
+
+/**
+ * Parameters for FASTCOVER_tryParameters().
+ */
+typedef struct FASTCOVER_tryParameters_data_s {
+    const FASTCOVER_ctx_t* ctx;
+    COVER_best_t* best;
+    size_t dictBufferCapacity;
+    ZDICT_cover_params_t parameters;
+} FASTCOVER_tryParameters_data_t;
+
+
+/**
+ * Tries a set of parameters and updates the COVER_best_t with the results.
+ * This function is thread safe if zstd is compiled with multithreaded support.
+ * It takes its parameters as an *OWNING* opaque pointer to support threading.
+ */
+static void FASTCOVER_tryParameters(void *opaque)
+{
+  /* Save parameters as local variables */
+  FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t *)opaque;
+  const FASTCOVER_ctx_t *const ctx = data->ctx;
+  const ZDICT_cover_params_t parameters = data->parameters;
+  size_t dictBufferCapacity = data->dictBufferCapacity;
+  size_t totalCompressedSize = ERROR(GENERIC);
+  /* Initialize array to keep track of frequency of dmer within activeSegment */
+  U16* segmentFreqs = (U16 *)calloc(((U64)1 << ctx->f), sizeof(U16));
+  /* Allocate space for hash table, dict, and freqs */
+  BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
+  U32 *freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32));
+  if (!segmentFreqs || !dict || !freqs) {
+    DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n");
+    goto _cleanup;
+  }
+  /* Copy the frequencies because we need to modify them */
+  memcpy(freqs, ctx->freqs, ((U64)1 << ctx->f) * sizeof(U32));
+  /* Build the dictionary */
+  { const size_t tail = FASTCOVER_buildDictionary(ctx, freqs, dict, dictBufferCapacity,
+                                                  parameters, segmentFreqs);
+    const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100);
+    dictBufferCapacity = ZDICT_finalizeDictionary(
+        dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+        ctx->samples, ctx->samplesSizes, nbFinalizeSamples, parameters.zParams);
+    if (ZDICT_isError(dictBufferCapacity)) {
+      DISPLAYLEVEL(1, "Failed to finalize dictionary\n");
+      goto _cleanup;
+    }
+  }
+  /* Check total compressed size */
+  totalCompressedSize = COVER_checkTotalCompressedSize(parameters, ctx->samplesSizes,
+                                                       ctx->samples, ctx->offsets,
+                                                       ctx->nbTrainSamples, ctx->nbSamples,
+                                                       dict, dictBufferCapacity);
+_cleanup:
+  COVER_best_finish(data->best, totalCompressedSize, parameters, dict,
+                    dictBufferCapacity);
+  free(data);
+  free(segmentFreqs);
+  free(dict);
+  free(freqs);
+}
+
+
+static void
+FASTCOVER_convertToCoverParams(ZDICT_fastCover_params_t fastCoverParams,
+                               ZDICT_cover_params_t* coverParams)
+{
+    coverParams->k = fastCoverParams.k;
+    coverParams->d = fastCoverParams.d;
+    coverParams->steps = fastCoverParams.steps;
+    coverParams->nbThreads = fastCoverParams.nbThreads;
+    coverParams->splitPoint = fastCoverParams.splitPoint;
+    coverParams->zParams = fastCoverParams.zParams;
+}
+
+
+static void
+FASTCOVER_convertToFastCoverParams(ZDICT_cover_params_t coverParams,
+                                   ZDICT_fastCover_params_t* fastCoverParams,
+                                   unsigned f, unsigned accel)
+{
+    fastCoverParams->k = coverParams.k;
+    fastCoverParams->d = coverParams.d;
+    fastCoverParams->steps = coverParams.steps;
+    fastCoverParams->nbThreads = coverParams.nbThreads;
+    fastCoverParams->splitPoint = coverParams.splitPoint;
+    fastCoverParams->f = f;
+    fastCoverParams->accel = accel;
+    fastCoverParams->zParams = coverParams.zParams;
+}
+
+
+ZDICTLIB_API size_t
+ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity,
+                                const void* samplesBuffer,
+                                const size_t* samplesSizes, unsigned nbSamples,
+                                ZDICT_fastCover_params_t parameters)
+{
+    BYTE* const dict = (BYTE*)dictBuffer;
+    FASTCOVER_ctx_t ctx;
+    ZDICT_cover_params_t coverParams;
+    FASTCOVER_accel_t accelParams;
+    /* Initialize global data */
+    g_displayLevel = parameters.zParams.notificationLevel;
+    /* Assign splitPoint and f if not provided */
+    parameters.splitPoint = 1.0;
+    parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f;
+    parameters.accel = parameters.accel == 0 ? DEFAULT_ACCEL : parameters.accel;
+    /* Convert to cover parameter */
+    memset(&coverParams, 0 , sizeof(coverParams));
+    FASTCOVER_convertToCoverParams(parameters, &coverParams);
+    /* Checks */
+    if (!FASTCOVER_checkParameters(coverParams, dictBufferCapacity, parameters.f,
+                                   parameters.accel)) {
+      DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n");
+      return ERROR(GENERIC);
+    }
+    if (nbSamples == 0) {
+      DISPLAYLEVEL(1, "FASTCOVER must have at least one input file\n");
+      return ERROR(GENERIC);
+    }
+    if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+      DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
+                   ZDICT_DICTSIZE_MIN);
+      return ERROR(dstSize_tooSmall);
+    }
+    /* Assign corresponding FASTCOVER_accel_t to accelParams*/
+    accelParams = FASTCOVER_defaultAccelParameters[parameters.accel];
+    /* Initialize context */
+    if (!FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
+                            coverParams.d, parameters.splitPoint, parameters.f,
+                            accelParams)) {
+      DISPLAYLEVEL(1, "Failed to initialize context\n");
+      return ERROR(GENERIC);
+    }
+    /* Build the dictionary */
+    DISPLAYLEVEL(2, "Building dictionary\n");
+    {
+      /* Initialize array to keep track of frequency of dmer within activeSegment */
+      U16* segmentFreqs = (U16 *)calloc(((U64)1 << parameters.f), sizeof(U16));
+      const size_t tail = FASTCOVER_buildDictionary(&ctx, ctx.freqs, dictBuffer,
+                                                dictBufferCapacity, coverParams, segmentFreqs);
+      const unsigned nbFinalizeSamples = (unsigned)(ctx.nbTrainSamples * ctx.accelParams.finalize / 100);
+      const size_t dictionarySize = ZDICT_finalizeDictionary(
+          dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
+          samplesBuffer, samplesSizes, nbFinalizeSamples, coverParams.zParams);
+      if (!ZSTD_isError(dictionarySize)) {
+          DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",
+                      (unsigned)dictionarySize);
+      }
+      FASTCOVER_ctx_destroy(&ctx);
+      free(segmentFreqs);
+      return dictionarySize;
+    }
+}
+
+
+ZDICTLIB_API size_t
+ZDICT_optimizeTrainFromBuffer_fastCover(
+                    void* dictBuffer, size_t dictBufferCapacity,
+                    const void* samplesBuffer,
+                    const size_t* samplesSizes, unsigned nbSamples,
+                    ZDICT_fastCover_params_t* parameters)
+{
+    ZDICT_cover_params_t coverParams;
+    FASTCOVER_accel_t accelParams;
+    /* constants */
+    const unsigned nbThreads = parameters->nbThreads;
+    const double splitPoint =
+        parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
+    const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
+    const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
+    const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
+    const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k;
+    const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps;
+    const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);
+    const unsigned kIterations =
+        (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
+    const unsigned f = parameters->f == 0 ? DEFAULT_F : parameters->f;
+    const unsigned accel = parameters->accel == 0 ? DEFAULT_ACCEL : parameters->accel;
+    /* Local variables */
+    const int displayLevel = parameters->zParams.notificationLevel;
+    unsigned iteration = 1;
+    unsigned d;
+    unsigned k;
+    COVER_best_t best;
+    POOL_ctx *pool = NULL;
+    /* Checks */
+    if (splitPoint <= 0 || splitPoint > 1) {
+      LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect splitPoint\n");
+      return ERROR(GENERIC);
+    }
+    if (accel == 0 || accel > FASTCOVER_MAX_ACCEL) {
+      LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect accel\n");
+      return ERROR(GENERIC);
+    }
+    if (kMinK < kMaxD || kMaxK < kMinK) {
+      LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect k\n");
+      return ERROR(GENERIC);
+    }
+    if (nbSamples == 0) {
+      LOCALDISPLAYLEVEL(displayLevel, 1, "FASTCOVER must have at least one input file\n");
+      return ERROR(GENERIC);
+    }
+    if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
+      LOCALDISPLAYLEVEL(displayLevel, 1, "dictBufferCapacity must be at least %u\n",
+                   ZDICT_DICTSIZE_MIN);
+      return ERROR(dstSize_tooSmall);
+    }
+    if (nbThreads > 1) {
+      pool = POOL_create(nbThreads, 1);
+      if (!pool) {
+        return ERROR(memory_allocation);
+      }
+    }
+    /* Initialization */
+    COVER_best_init(&best);
+    memset(&coverParams, 0 , sizeof(coverParams));
+    FASTCOVER_convertToCoverParams(*parameters, &coverParams);
+    accelParams = FASTCOVER_defaultAccelParameters[accel];
+    /* Turn down global display level to clean up display at level 2 and below */
+    g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
+    /* Loop through d first because each new value needs a new context */
+    LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
+                      kIterations);
+    for (d = kMinD; d <= kMaxD; d += 2) {
+      /* Initialize the context for this value of d */
+      FASTCOVER_ctx_t ctx;
+      LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);
+      if (!FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams)) {
+        LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");
+        COVER_best_destroy(&best);
+        POOL_free(pool);
+        return ERROR(GENERIC);
+      }
+      /* Loop through k reusing the same context */
+      for (k = kMinK; k <= kMaxK; k += kStepSize) {
+        /* Prepare the arguments */
+        FASTCOVER_tryParameters_data_t *data = (FASTCOVER_tryParameters_data_t *)malloc(
+            sizeof(FASTCOVER_tryParameters_data_t));
+        LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);
+        if (!data) {
+          LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");
+          COVER_best_destroy(&best);
+          FASTCOVER_ctx_destroy(&ctx);
+          POOL_free(pool);
+          return ERROR(GENERIC);
+        }
+        data->ctx = &ctx;
+        data->best = &best;
+        data->dictBufferCapacity = dictBufferCapacity;
+        data->parameters = coverParams;
+        data->parameters.k = k;
+        data->parameters.d = d;
+        data->parameters.splitPoint = splitPoint;
+        data->parameters.steps = kSteps;
+        data->parameters.zParams.notificationLevel = g_displayLevel;
+        /* Check the parameters */
+        if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity,
+                                       data->ctx->f, accel)) {
+          DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n");
+          free(data);
+          continue;
+        }
+        /* Call the function and pass ownership of data to it */
+        COVER_best_start(&best);
+        if (pool) {
+          POOL_add(pool, &FASTCOVER_tryParameters, data);
+        } else {
+          FASTCOVER_tryParameters(data);
+        }
+        /* Print status */
+        LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%%       ",
+                           (unsigned)((iteration * 100) / kIterations));
+        ++iteration;
+      }
+      COVER_best_wait(&best);
+      FASTCOVER_ctx_destroy(&ctx);
+    }
+    LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");
+    /* Fill the output buffer and parameters with output of the best parameters */
+    {
+      const size_t dictSize = best.dictSize;
+      if (ZSTD_isError(best.compressedSize)) {
+        const size_t compressedSize = best.compressedSize;
+        COVER_best_destroy(&best);
+        POOL_free(pool);
+        return compressedSize;
+      }
+      FASTCOVER_convertToFastCoverParams(best.parameters, parameters, f, accel);
+      memcpy(dictBuffer, best.dict, dictSize);
+      COVER_best_destroy(&best);
+      POOL_free(pool);
+      return dictSize;
+    }
+
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/zdict.c b/Utilities/cmzstd/lib/dictBuilder/zdict.c
new file mode 100644
index 0000000..c753da0
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/zdict.c
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/*-**************************************
+*  Tuning parameters
+****************************************/
+#define MINRATIO 4   /* minimum nb of apparition to be selected in dictionary */
+#define ZDICT_MAX_SAMPLES_SIZE (2000U << 20)
+#define ZDICT_MIN_SAMPLES_SIZE (ZDICT_CONTENTSIZE_MIN * MINRATIO)
+
+
+/*-**************************************
+*  Compiler Options
+****************************************/
+/* Unix Large Files support (>4GB) */
+#define _FILE_OFFSET_BITS 64
+#if (defined(__sun__) && (!defined(__LP64__)))   /* Sun Solaris 32-bits requires specific definitions */
+#  define _LARGEFILE_SOURCE
+#elif ! defined(__LP64__)                        /* No point defining Large file for 64 bit */
+#  define _LARGEFILE64_SOURCE
+#endif
+
+
+/*-*************************************
+*  Dependencies
+***************************************/
+#include <stdlib.h>        /* malloc, free */
+#include <string.h>        /* memset */
+#include <stdio.h>         /* fprintf, fopen, ftello64 */
+#include <time.h>          /* clock */
+
+#include "mem.h"           /* read */
+#include "fse.h"           /* FSE_normalizeCount, FSE_writeNCount */
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"           /* HUF_buildCTable, HUF_writeCTable */
+#include "zstd_internal.h" /* includes zstd.h */
+#include "xxhash.h"        /* XXH64 */
+#include "divsufsort.h"
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#  define ZDICT_STATIC_LINKING_ONLY
+#endif
+#include "zdict.h"
+
+
+/*-*************************************
+*  Constants
+***************************************/
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define DICTLISTSIZE_DEFAULT 10000
+
+#define NOISELENGTH 32
+
+static const int g_compressionLevel_default = 3;
+static const U32 g_selectivity_default = 9;
+
+
+/*-*************************************
+*  Console display
+***************************************/
+#define DISPLAY(...)         { fprintf(stderr, __VA_ARGS__); fflush( stderr ); }
+#define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); }    /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */
+
+static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
+
+static void ZDICT_printHex(const void* ptr, size_t length)
+{
+    const BYTE* const b = (const BYTE*)ptr;
+    size_t u;
+    for (u=0; u<length; u++) {
+        BYTE c = b[u];
+        if (c<32 || c>126) c = '.';   /* non-printable char */
+        DISPLAY("%c", c);
+    }
+}
+
+
+/*-********************************************************
+*  Helper functions
+**********************************************************/
+unsigned ZDICT_isError(size_t errorCode) { return ERR_isError(errorCode); }
+
+const char* ZDICT_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
+
+unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize)
+{
+    if (dictSize < 8) return 0;
+    if (MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return 0;
+    return MEM_readLE32((const char*)dictBuffer + 4);
+}
+
+
+/*-********************************************************
+*  Dictionary training functions
+**********************************************************/
+static unsigned ZDICT_NbCommonBytes (size_t val)
+{
+    if (MEM_isLittleEndian()) {
+        if (MEM_64bits()) {
+#       if defined(_MSC_VER) && defined(_WIN64)
+            unsigned long r = 0;
+            _BitScanForward64( &r, (U64)val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 3)
+            return (__builtin_ctzll((U64)val) >> 3);
+#       else
+            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+#       endif
+        } else { /* 32 bits */
+#       if defined(_MSC_VER)
+            unsigned long r=0;
+            _BitScanForward( &r, (U32)val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 3)
+            return (__builtin_ctz((U32)val) >> 3);
+#       else
+            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+#       endif
+        }
+    } else {  /* Big Endian CPU */
+        if (MEM_64bits()) {
+#       if defined(_MSC_VER) && defined(_WIN64)
+            unsigned long r = 0;
+            _BitScanReverse64( &r, val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 3)
+            return (__builtin_clzll(val) >> 3);
+#       else
+            unsigned r;
+            const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */
+            if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
+            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+            r += (!val);
+            return r;
+#       endif
+        } else { /* 32 bits */
+#       if defined(_MSC_VER)
+            unsigned long r = 0;
+            _BitScanReverse( &r, (unsigned long)val );
+            return (unsigned)(r>>3);
+#       elif defined(__GNUC__) && (__GNUC__ >= 3)
+            return (__builtin_clz((U32)val) >> 3);
+#       else
+            unsigned r;
+            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+            r += (!val);
+            return r;
+#       endif
+    }   }
+}
+
+
+/*! ZDICT_count() :
+    Count the nb of common bytes between 2 pointers.
+    Note : this function presumes end of buffer followed by noisy guard band.
+*/
+static size_t ZDICT_count(const void* pIn, const void* pMatch)
+{
+    const char* const pStart = (const char*)pIn;
+    for (;;) {
+        size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+        if (!diff) {
+            pIn = (const char*)pIn+sizeof(size_t);
+            pMatch = (const char*)pMatch+sizeof(size_t);
+            continue;
+        }
+        pIn = (const char*)pIn+ZDICT_NbCommonBytes(diff);
+        return (size_t)((const char*)pIn - pStart);
+    }
+}
+
+
+typedef struct {
+    U32 pos;
+    U32 length;
+    U32 savings;
+} dictItem;
+
+static void ZDICT_initDictItem(dictItem* d)
+{
+    d->pos = 1;
+    d->length = 0;
+    d->savings = (U32)(-1);
+}
+
+
+#define LLIMIT 64          /* heuristic determined experimentally */
+#define MINMATCHLENGTH 7   /* heuristic determined experimentally */
+static dictItem ZDICT_analyzePos(
+                       BYTE* doneMarks,
+                       const int* suffix, U32 start,
+                       const void* buffer, U32 minRatio, U32 notificationLevel)
+{
+    U32 lengthList[LLIMIT] = {0};
+    U32 cumulLength[LLIMIT] = {0};
+    U32 savings[LLIMIT] = {0};
+    const BYTE* b = (const BYTE*)buffer;
+    size_t maxLength = LLIMIT;
+    size_t pos = suffix[start];
+    U32 end = start;
+    dictItem solution;
+
+    /* init */
+    memset(&solution, 0, sizeof(solution));
+    doneMarks[pos] = 1;
+
+    /* trivial repetition cases */
+    if ( (MEM_read16(b+pos+0) == MEM_read16(b+pos+2))
+       ||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3))
+       ||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) {
+        /* skip and mark segment */
+        U16 const pattern16 = MEM_read16(b+pos+4);
+        U32 u, patternEnd = 6;
+        while (MEM_read16(b+pos+patternEnd) == pattern16) patternEnd+=2 ;
+        if (b[pos+patternEnd] == b[pos+patternEnd-1]) patternEnd++;
+        for (u=1; u<patternEnd; u++)
+            doneMarks[pos+u] = 1;
+        return solution;
+    }
+
+    /* look forward */
+    {   size_t length;
+        do {
+            end++;
+            length = ZDICT_count(b + pos, b + suffix[end]);
+        } while (length >= MINMATCHLENGTH);
+    }
+
+    /* look backward */
+    {   size_t length;
+        do {
+            length = ZDICT_count(b + pos, b + *(suffix+start-1));
+            if (length >=MINMATCHLENGTH) start--;
+        } while(length >= MINMATCHLENGTH);
+    }
+
+    /* exit if not found a minimum nb of repetitions */
+    if (end-start < minRatio) {
+        U32 idx;
+        for(idx=start; idx<end; idx++)
+            doneMarks[suffix[idx]] = 1;
+        return solution;
+    }
+
+    {   int i;
+        U32 mml;
+        U32 refinedStart = start;
+        U32 refinedEnd = end;
+
+        DISPLAYLEVEL(4, "\n");
+        DISPLAYLEVEL(4, "found %3u matches of length >= %i at pos %7u  ", (unsigned)(end-start), MINMATCHLENGTH, (unsigned)pos);
+        DISPLAYLEVEL(4, "\n");
+
+        for (mml = MINMATCHLENGTH ; ; mml++) {
+            BYTE currentChar = 0;
+            U32 currentCount = 0;
+            U32 currentID = refinedStart;
+            U32 id;
+            U32 selectedCount = 0;
+            U32 selectedID = currentID;
+            for (id =refinedStart; id < refinedEnd; id++) {
+                if (b[suffix[id] + mml] != currentChar) {
+                    if (currentCount > selectedCount) {
+                        selectedCount = currentCount;
+                        selectedID = currentID;
+                    }
+                    currentID = id;
+                    currentChar = b[ suffix[id] + mml];
+                    currentCount = 0;
+                }
+                currentCount ++;
+            }
+            if (currentCount > selectedCount) {  /* for last */
+                selectedCount = currentCount;
+                selectedID = currentID;
+            }
+
+            if (selectedCount < minRatio)
+                break;
+            refinedStart = selectedID;
+            refinedEnd = refinedStart + selectedCount;
+        }
+
+        /* evaluate gain based on new dict */
+        start = refinedStart;
+        pos = suffix[refinedStart];
+        end = start;
+        memset(lengthList, 0, sizeof(lengthList));
+
+        /* look forward */
+        {   size_t length;
+            do {
+                end++;
+                length = ZDICT_count(b + pos, b + suffix[end]);
+                if (length >= LLIMIT) length = LLIMIT-1;
+                lengthList[length]++;
+            } while (length >=MINMATCHLENGTH);
+        }
+
+        /* look backward */
+        {   size_t length = MINMATCHLENGTH;
+            while ((length >= MINMATCHLENGTH) & (start > 0)) {
+                length = ZDICT_count(b + pos, b + suffix[start - 1]);
+                if (length >= LLIMIT) length = LLIMIT - 1;
+                lengthList[length]++;
+                if (length >= MINMATCHLENGTH) start--;
+            }
+        }
+
+        /* largest useful length */
+        memset(cumulLength, 0, sizeof(cumulLength));
+        cumulLength[maxLength-1] = lengthList[maxLength-1];
+        for (i=(int)(maxLength-2); i>=0; i--)
+            cumulLength[i] = cumulLength[i+1] + lengthList[i];
+
+        for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break;
+        maxLength = i;
+
+        /* reduce maxLength in case of final into repetitive data */
+        {   U32 l = (U32)maxLength;
+            BYTE const c = b[pos + maxLength-1];
+            while (b[pos+l-2]==c) l--;
+            maxLength = l;
+        }
+        if (maxLength < MINMATCHLENGTH) return solution;   /* skip : no long-enough solution */
+
+        /* calculate savings */
+        savings[5] = 0;
+        for (i=MINMATCHLENGTH; i<=(int)maxLength; i++)
+            savings[i] = savings[i-1] + (lengthList[i] * (i-3));
+
+        DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f)  \n",
+                     (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / maxLength);
+
+        solution.pos = (U32)pos;
+        solution.length = (U32)maxLength;
+        solution.savings = savings[maxLength];
+
+        /* mark positions done */
+        {   U32 id;
+            for (id=start; id<end; id++) {
+                U32 p, pEnd, length;
+                U32 const testedPos = suffix[id];
+                if (testedPos == pos)
+                    length = solution.length;
+                else {
+                    length = (U32)ZDICT_count(b+pos, b+testedPos);
+                    if (length > solution.length) length = solution.length;
+                }
+                pEnd = (U32)(testedPos + length);
+                for (p=testedPos; p<pEnd; p++)
+                    doneMarks[p] = 1;
+    }   }   }
+
+    return solution;
+}
+
+
+static int isIncluded(const void* in, const void* container, size_t length)
+{
+    const char* const ip = (const char*) in;
+    const char* const into = (const char*) container;
+    size_t u;
+
+    for (u=0; u<length; u++) {  /* works because end of buffer is a noisy guard band */
+        if (ip[u] != into[u]) break;
+    }
+
+    return u==length;
+}
+
+/*! ZDICT_tryMerge() :
+    check if dictItem can be merged, do it if possible
+    @return : id of destination elt, 0 if not merged
+*/
+static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const void* buffer)
+{
+    const U32 tableSize = table->pos;
+    const U32 eltEnd = elt.pos + elt.length;
+    const char* const buf = (const char*) buffer;
+
+    /* tail overlap */
+    U32 u; for (u=1; u<tableSize; u++) {
+        if (u==eltNbToSkip) continue;
+        if ((table[u].pos > elt.pos) && (table[u].pos <= eltEnd)) {  /* overlap, existing > new */
+            /* append */
+            U32 const addedLength = table[u].pos - elt.pos;
+            table[u].length += addedLength;
+            table[u].pos = elt.pos;
+            table[u].savings += elt.savings * addedLength / elt.length;   /* rough approx */
+            table[u].savings += elt.length / 8;    /* rough approx bonus */
+            elt = table[u];
+            /* sort : improve rank */
+            while ((u>1) && (table[u-1].savings < elt.savings))
+            table[u] = table[u-1], u--;
+            table[u] = elt;
+            return u;
+    }   }
+
+    /* front overlap */
+    for (u=1; u<tableSize; u++) {
+        if (u==eltNbToSkip) continue;
+
+        if ((table[u].pos + table[u].length >= elt.pos) && (table[u].pos < elt.pos)) {  /* overlap, existing < new */
+            /* append */
+            int const addedLength = (int)eltEnd - (table[u].pos + table[u].length);
+            table[u].savings += elt.length / 8;    /* rough approx bonus */
+            if (addedLength > 0) {   /* otherwise, elt fully included into existing */
+                table[u].length += addedLength;
+                table[u].savings += elt.savings * addedLength / elt.length;   /* rough approx */
+            }
+            /* sort : improve rank */
+            elt = table[u];
+            while ((u>1) && (table[u-1].savings < elt.savings))
+                table[u] = table[u-1], u--;
+            table[u] = elt;
+            return u;
+        }
+
+        if (MEM_read64(buf + table[u].pos) == MEM_read64(buf + elt.pos + 1)) {
+            if (isIncluded(buf + table[u].pos, buf + elt.pos + 1, table[u].length)) {
+                size_t const addedLength = MAX( (int)elt.length - (int)table[u].length , 1 );
+                table[u].pos = elt.pos;
+                table[u].savings += (U32)(elt.savings * addedLength / elt.length);
+                table[u].length = MIN(elt.length, table[u].length + 1);
+                return u;
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+static void ZDICT_removeDictItem(dictItem* table, U32 id)
+{
+    /* convention : table[0].pos stores nb of elts */
+    U32 const max = table[0].pos;
+    U32 u;
+    if (!id) return;   /* protection, should never happen */
+    for (u=id; u<max-1; u++)
+        table[u] = table[u+1];
+    table->pos--;
+}
+
+
+static void ZDICT_insertDictItem(dictItem* table, U32 maxSize, dictItem elt, const void* buffer)
+{
+    /* merge if possible */
+    U32 mergeId = ZDICT_tryMerge(table, elt, 0, buffer);
+    if (mergeId) {
+        U32 newMerge = 1;
+        while (newMerge) {
+            newMerge = ZDICT_tryMerge(table, table[mergeId], mergeId, buffer);
+            if (newMerge) ZDICT_removeDictItem(table, mergeId);
+            mergeId = newMerge;
+        }
+        return;
+    }
+
+    /* insert */
+    {   U32 current;
+        U32 nextElt = table->pos;
+        if (nextElt >= maxSize) nextElt = maxSize-1;
+        current = nextElt-1;
+        while (table[current].savings < elt.savings) {
+            table[current+1] = table[current];
+            current--;
+        }
+        table[current+1] = elt;
+        table->pos = nextElt+1;
+    }
+}
+
+
+static U32 ZDICT_dictSize(const dictItem* dictList)
+{
+    U32 u, dictSize = 0;
+    for (u=1; u<dictList[0].pos; u++)
+        dictSize += dictList[u].length;
+    return dictSize;
+}
+
+
+static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize,
+                            const void* const buffer, size_t bufferSize,   /* buffer must end with noisy guard band */
+                            const size_t* fileSizes, unsigned nbFiles,
+                            unsigned minRatio, U32 notificationLevel)
+{
+    int* const suffix0 = (int*)malloc((bufferSize+2)*sizeof(*suffix0));
+    int* const suffix = suffix0+1;
+    U32* reverseSuffix = (U32*)malloc((bufferSize)*sizeof(*reverseSuffix));
+    BYTE* doneMarks = (BYTE*)malloc((bufferSize+16)*sizeof(*doneMarks));   /* +16 for overflow security */
+    U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos));
+    size_t result = 0;
+    clock_t displayClock = 0;
+    clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;
+
+#   define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \
+            if (ZDICT_clockSpan(displayClock) > refreshRate)  \
+            { displayClock = clock(); DISPLAY(__VA_ARGS__); \
+            if (notificationLevel>=4) fflush(stderr); } }
+
+    /* init */
+    DISPLAYLEVEL(2, "\r%70s\r", "");   /* clean display line */
+    if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) {
+        result = ERROR(memory_allocation);
+        goto _cleanup;
+    }
+    if (minRatio < MINRATIO) minRatio = MINRATIO;
+    memset(doneMarks, 0, bufferSize+16);
+
+    /* limit sample set size (divsufsort limitation)*/
+    if (bufferSize > ZDICT_MAX_SAMPLES_SIZE) DISPLAYLEVEL(3, "sample set too large : reduced to %u MB ...\n", (unsigned)(ZDICT_MAX_SAMPLES_SIZE>>20));
+    while (bufferSize > ZDICT_MAX_SAMPLES_SIZE) bufferSize -= fileSizes[--nbFiles];
+
+    /* sort */
+    DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (unsigned)(bufferSize>>20));
+    {   int const divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0);
+        if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; }
+    }
+    suffix[bufferSize] = (int)bufferSize;   /* leads into noise */
+    suffix0[0] = (int)bufferSize;           /* leads into noise */
+    /* build reverse suffix sort */
+    {   size_t pos;
+        for (pos=0; pos < bufferSize; pos++)
+            reverseSuffix[suffix[pos]] = (U32)pos;
+        /* note filePos tracks borders between samples.
+           It's not used at this stage, but planned to become useful in a later update */
+        filePos[0] = 0;
+        for (pos=1; pos<nbFiles; pos++)
+            filePos[pos] = (U32)(filePos[pos-1] + fileSizes[pos-1]);
+    }
+
+    DISPLAYLEVEL(2, "finding patterns ... \n");
+    DISPLAYLEVEL(3, "minimum ratio : %u \n", minRatio);
+
+    {   U32 cursor; for (cursor=0; cursor < bufferSize; ) {
+            dictItem solution;
+            if (doneMarks[cursor]) { cursor++; continue; }
+            solution = ZDICT_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio, notificationLevel);
+            if (solution.length==0) { cursor++; continue; }
+            ZDICT_insertDictItem(dictList, dictListSize, solution, buffer);
+            cursor += solution.length;
+            DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100);
+    }   }
+
+_cleanup:
+    free(suffix0);
+    free(reverseSuffix);
+    free(doneMarks);
+    free(filePos);
+    return result;
+}
+
+
+static void ZDICT_fillNoise(void* buffer, size_t length)
+{
+    unsigned const prime1 = 2654435761U;
+    unsigned const prime2 = 2246822519U;
+    unsigned acc = prime1;
+    size_t p=0;;
+    for (p=0; p<length; p++) {
+        acc *= prime2;
+        ((unsigned char*)buffer)[p] = (unsigned char)(acc >> 21);
+    }
+}
+
+
+typedef struct
+{
+    ZSTD_CDict* dict;    /* dictionary */
+    ZSTD_CCtx* zc;     /* working context */
+    void* workPlace;   /* must be ZSTD_BLOCKSIZE_MAX allocated */
+} EStats_ress_t;
+
+#define MAXREPOFFSET 1024
+
+static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,
+                              unsigned* countLit, unsigned* offsetcodeCount, unsigned* matchlengthCount, unsigned* litlengthCount, U32* repOffsets,
+                              const void* src, size_t srcSize,
+                              U32 notificationLevel)
+{
+    size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params.cParams.windowLog);
+    size_t cSize;
+
+    if (srcSize > blockSizeMax) srcSize = blockSizeMax;   /* protection vs large samples */
+    {   size_t const errorCode = ZSTD_compressBegin_usingCDict(esr.zc, esr.dict);
+        if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_compressBegin_usingCDict failed \n"); return; }
+
+    }
+    cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize);
+    if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (unsigned)srcSize); return; }
+
+    if (cSize) {  /* if == 0; block is not compressible */
+        const seqStore_t* const seqStorePtr = ZSTD_getSeqStore(esr.zc);
+
+        /* literals stats */
+        {   const BYTE* bytePtr;
+            for(bytePtr = seqStorePtr->litStart; bytePtr < seqStorePtr->lit; bytePtr++)
+                countLit[*bytePtr]++;
+        }
+
+        /* seqStats */
+        {   U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+            ZSTD_seqToCodes(seqStorePtr);
+
+            {   const BYTE* codePtr = seqStorePtr->ofCode;
+                U32 u;
+                for (u=0; u<nbSeq; u++) offsetcodeCount[codePtr[u]]++;
+            }
+
+            {   const BYTE* codePtr = seqStorePtr->mlCode;
+                U32 u;
+                for (u=0; u<nbSeq; u++) matchlengthCount[codePtr[u]]++;
+            }
+
+            {   const BYTE* codePtr = seqStorePtr->llCode;
+                U32 u;
+                for (u=0; u<nbSeq; u++) litlengthCount[codePtr[u]]++;
+            }
+
+            if (nbSeq >= 2) { /* rep offsets */
+                const seqDef* const seq = seqStorePtr->sequencesStart;
+                U32 offset1 = seq[0].offset - 3;
+                U32 offset2 = seq[1].offset - 3;
+                if (offset1 >= MAXREPOFFSET) offset1 = 0;
+                if (offset2 >= MAXREPOFFSET) offset2 = 0;
+                repOffsets[offset1] += 3;
+                repOffsets[offset2] += 1;
+    }   }   }
+}
+
+static size_t ZDICT_totalSampleSize(const size_t* fileSizes, unsigned nbFiles)
+{
+    size_t total=0;
+    unsigned u;
+    for (u=0; u<nbFiles; u++) total += fileSizes[u];
+    return total;
+}
+
+typedef struct { U32 offset; U32 count; } offsetCount_t;
+
+static void ZDICT_insertSortCount(offsetCount_t table[ZSTD_REP_NUM+1], U32 val, U32 count)
+{
+    U32 u;
+    table[ZSTD_REP_NUM].offset = val;
+    table[ZSTD_REP_NUM].count = count;
+    for (u=ZSTD_REP_NUM; u>0; u--) {
+        offsetCount_t tmp;
+        if (table[u-1].count >= table[u].count) break;
+        tmp = table[u-1];
+        table[u-1] = table[u];
+        table[u] = tmp;
+    }
+}
+
+/* ZDICT_flatLit() :
+ * rewrite `countLit` to contain a mostly flat but still compressible distribution of literals.
+ * necessary to avoid generating a non-compressible distribution that HUF_writeCTable() cannot encode.
+ */
+static void ZDICT_flatLit(unsigned* countLit)
+{
+    int u;
+    for (u=1; u<256; u++) countLit[u] = 2;
+    countLit[0]   = 4;
+    countLit[253] = 1;
+    countLit[254] = 1;
+}
+
+#define OFFCODE_MAX 30  /* only applicable to first block */
+static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,
+                                   unsigned compressionLevel,
+                             const void*  srcBuffer, const size_t* fileSizes, unsigned nbFiles,
+                             const void* dictBuffer, size_t  dictBufferSize,
+                                   unsigned notificationLevel)
+{
+    unsigned countLit[256];
+    HUF_CREATE_STATIC_CTABLE(hufTable, 255);
+    unsigned offcodeCount[OFFCODE_MAX+1];
+    short offcodeNCount[OFFCODE_MAX+1];
+    U32 offcodeMax = ZSTD_highbit32((U32)(dictBufferSize + 128 KB));
+    unsigned matchLengthCount[MaxML+1];
+    short matchLengthNCount[MaxML+1];
+    unsigned litLengthCount[MaxLL+1];
+    short litLengthNCount[MaxLL+1];
+    U32 repOffset[MAXREPOFFSET];
+    offsetCount_t bestRepOffset[ZSTD_REP_NUM+1];
+    EStats_ress_t esr = { NULL, NULL, NULL };
+    ZSTD_parameters params;
+    U32 u, huffLog = 11, Offlog = OffFSELog, mlLog = MLFSELog, llLog = LLFSELog, total;
+    size_t pos = 0, errorCode;
+    size_t eSize = 0;
+    size_t const totalSrcSize = ZDICT_totalSampleSize(fileSizes, nbFiles);
+    size_t const averageSampleSize = totalSrcSize / (nbFiles + !nbFiles);
+    BYTE* dstPtr = (BYTE*)dstBuffer;
+
+    /* init */
+    DEBUGLOG(4, "ZDICT_analyzeEntropy");
+    if (offcodeMax>OFFCODE_MAX) { eSize = ERROR(dictionaryCreation_failed); goto _cleanup; }   /* too large dictionary */
+    for (u=0; u<256; u++) countLit[u] = 1;   /* any character must be described */
+    for (u=0; u<=offcodeMax; u++) offcodeCount[u] = 1;
+    for (u=0; u<=MaxML; u++) matchLengthCount[u] = 1;
+    for (u=0; u<=MaxLL; u++) litLengthCount[u] = 1;
+    memset(repOffset, 0, sizeof(repOffset));
+    repOffset[1] = repOffset[4] = repOffset[8] = 1;
+    memset(bestRepOffset, 0, sizeof(bestRepOffset));
+    if (compressionLevel==0) compressionLevel = g_compressionLevel_default;
+    params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize);
+
+    esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem);
+    esr.zc = ZSTD_createCCtx();
+    esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX);
+    if (!esr.dict || !esr.zc || !esr.workPlace) {
+        eSize = ERROR(memory_allocation);
+        DISPLAYLEVEL(1, "Not enough memory \n");
+        goto _cleanup;
+    }
+
+    /* collect stats on all samples */
+    for (u=0; u<nbFiles; u++) {
+        ZDICT_countEStats(esr, params,
+                          countLit, offcodeCount, matchLengthCount, litLengthCount, repOffset,
+                         (const char*)srcBuffer + pos, fileSizes[u],
+                          notificationLevel);
+        pos += fileSizes[u];
+    }
+
+    /* analyze, build stats, starting with literals */
+    {   size_t maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
+        if (HUF_isError(maxNbBits)) {
+            eSize = ERROR(GENERIC);
+            DISPLAYLEVEL(1, " HUF_buildCTable error \n");
+            goto _cleanup;
+        }
+        if (maxNbBits==8) {  /* not compressible : will fail on HUF_writeCTable() */
+            DISPLAYLEVEL(2, "warning : pathological dataset : literals are not compressible : samples are noisy or too regular \n");
+            ZDICT_flatLit(countLit);  /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */
+            maxNbBits = HUF_buildCTable (hufTable, countLit, 255, huffLog);
+            assert(maxNbBits==9);
+        }
+        huffLog = (U32)maxNbBits;
+    }
+
+    /* looking for most common first offsets */
+    {   U32 offset;
+        for (offset=1; offset<MAXREPOFFSET; offset++)
+            ZDICT_insertSortCount(bestRepOffset, offset, repOffset[offset]);
+    }
+    /* note : the result of this phase should be used to better appreciate the impact on statistics */
+
+    total=0; for (u=0; u<=offcodeMax; u++) total+=offcodeCount[u];
+    errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax);
+    if (FSE_isError(errorCode)) {
+        eSize = ERROR(GENERIC);
+        DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount \n");
+        goto _cleanup;
+    }
+    Offlog = (U32)errorCode;
+
+    total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u];
+    errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML);
+    if (FSE_isError(errorCode)) {
+        eSize = ERROR(GENERIC);
+        DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount \n");
+        goto _cleanup;
+    }
+    mlLog = (U32)errorCode;
+
+    total=0; for (u=0; u<=MaxLL; u++) total+=litLengthCount[u];
+    errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL);
+    if (FSE_isError(errorCode)) {
+        eSize = ERROR(GENERIC);
+        DISPLAYLEVEL(1, "FSE_normalizeCount error with litLengthCount \n");
+        goto _cleanup;
+    }
+    llLog = (U32)errorCode;
+
+    /* write result to buffer */
+    {   size_t const hhSize = HUF_writeCTable(dstPtr, maxDstSize, hufTable, 255, huffLog);
+        if (HUF_isError(hhSize)) {
+            eSize = ERROR(GENERIC);
+            DISPLAYLEVEL(1, "HUF_writeCTable error \n");
+            goto _cleanup;
+        }
+        dstPtr += hhSize;
+        maxDstSize -= hhSize;
+        eSize += hhSize;
+    }
+
+    {   size_t const ohSize = FSE_writeNCount(dstPtr, maxDstSize, offcodeNCount, OFFCODE_MAX, Offlog);
+        if (FSE_isError(ohSize)) {
+            eSize = ERROR(GENERIC);
+            DISPLAYLEVEL(1, "FSE_writeNCount error with offcodeNCount \n");
+            goto _cleanup;
+        }
+        dstPtr += ohSize;
+        maxDstSize -= ohSize;
+        eSize += ohSize;
+    }
+
+    {   size_t const mhSize = FSE_writeNCount(dstPtr, maxDstSize, matchLengthNCount, MaxML, mlLog);
+        if (FSE_isError(mhSize)) {
+            eSize = ERROR(GENERIC);
+            DISPLAYLEVEL(1, "FSE_writeNCount error with matchLengthNCount \n");
+            goto _cleanup;
+        }
+        dstPtr += mhSize;
+        maxDstSize -= mhSize;
+        eSize += mhSize;
+    }
+
+    {   size_t const lhSize = FSE_writeNCount(dstPtr, maxDstSize, litLengthNCount, MaxLL, llLog);
+        if (FSE_isError(lhSize)) {
+            eSize = ERROR(GENERIC);
+            DISPLAYLEVEL(1, "FSE_writeNCount error with litlengthNCount \n");
+            goto _cleanup;
+        }
+        dstPtr += lhSize;
+        maxDstSize -= lhSize;
+        eSize += lhSize;
+    }
+
+    if (maxDstSize<12) {
+        eSize = ERROR(GENERIC);
+        DISPLAYLEVEL(1, "not enough space to write RepOffsets \n");
+        goto _cleanup;
+    }
+# if 0
+    MEM_writeLE32(dstPtr+0, bestRepOffset[0].offset);
+    MEM_writeLE32(dstPtr+4, bestRepOffset[1].offset);
+    MEM_writeLE32(dstPtr+8, bestRepOffset[2].offset);
+#else
+    /* at this stage, we don't use the result of "most common first offset",
+       as the impact of statistics is not properly evaluated */
+    MEM_writeLE32(dstPtr+0, repStartValue[0]);
+    MEM_writeLE32(dstPtr+4, repStartValue[1]);
+    MEM_writeLE32(dstPtr+8, repStartValue[2]);
+#endif
+    eSize += 12;
+
+_cleanup:
+    ZSTD_freeCDict(esr.dict);
+    ZSTD_freeCCtx(esr.zc);
+    free(esr.workPlace);
+
+    return eSize;
+}
+
+
+
+size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
+                          const void* customDictContent, size_t dictContentSize,
+                          const void* samplesBuffer, const size_t* samplesSizes,
+                          unsigned nbSamples, ZDICT_params_t params)
+{
+    size_t hSize;
+#define HBUFFSIZE 256   /* should prove large enough for all entropy headers */
+    BYTE header[HBUFFSIZE];
+    int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
+    U32 const notificationLevel = params.notificationLevel;
+
+    /* check conditions */
+    DEBUGLOG(4, "ZDICT_finalizeDictionary");
+    if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall);
+    if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong);
+    if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall);
+
+    /* dictionary header */
+    MEM_writeLE32(header, ZSTD_MAGIC_DICTIONARY);
+    {   U64 const randomID = XXH64(customDictContent, dictContentSize, 0);
+        U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768;
+        U32 const dictID = params.dictID ? params.dictID : compliantID;
+        MEM_writeLE32(header+4, dictID);
+    }
+    hSize = 8;
+
+    /* entropy tables */
+    DISPLAYLEVEL(2, "\r%70s\r", "");   /* clean display line */
+    DISPLAYLEVEL(2, "statistics ... \n");
+    {   size_t const eSize = ZDICT_analyzeEntropy(header+hSize, HBUFFSIZE-hSize,
+                                  compressionLevel,
+                                  samplesBuffer, samplesSizes, nbSamples,
+                                  customDictContent, dictContentSize,
+                                  notificationLevel);
+        if (ZDICT_isError(eSize)) return eSize;
+        hSize += eSize;
+    }
+
+    /* copy elements in final buffer ; note : src and dst buffer can overlap */
+    if (hSize + dictContentSize > dictBufferCapacity) dictContentSize = dictBufferCapacity - hSize;
+    {   size_t const dictSize = hSize + dictContentSize;
+        char* dictEnd = (char*)dictBuffer + dictSize;
+        memmove(dictEnd - dictContentSize, customDictContent, dictContentSize);
+        memcpy(dictBuffer, header, hSize);
+        return dictSize;
+    }
+}
+
+
+static size_t ZDICT_addEntropyTablesFromBuffer_advanced(
+        void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
+        const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+        ZDICT_params_t params)
+{
+    int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
+    U32 const notificationLevel = params.notificationLevel;
+    size_t hSize = 8;
+
+    /* calculate entropy tables */
+    DISPLAYLEVEL(2, "\r%70s\r", "");   /* clean display line */
+    DISPLAYLEVEL(2, "statistics ... \n");
+    {   size_t const eSize = ZDICT_analyzeEntropy((char*)dictBuffer+hSize, dictBufferCapacity-hSize,
+                                  compressionLevel,
+                                  samplesBuffer, samplesSizes, nbSamples,
+                                  (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize,
+                                  notificationLevel);
+        if (ZDICT_isError(eSize)) return eSize;
+        hSize += eSize;
+    }
+
+    /* add dictionary header (after entropy tables) */
+    MEM_writeLE32(dictBuffer, ZSTD_MAGIC_DICTIONARY);
+    {   U64 const randomID = XXH64((char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, 0);
+        U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768;
+        U32 const dictID = params.dictID ? params.dictID : compliantID;
+        MEM_writeLE32((char*)dictBuffer+4, dictID);
+    }
+
+    if (hSize + dictContentSize < dictBufferCapacity)
+        memmove((char*)dictBuffer + hSize, (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize);
+    return MIN(dictBufferCapacity, hSize+dictContentSize);
+}
+
+/* Hidden declaration for dbio.c */
+size_t ZDICT_trainFromBuffer_unsafe_legacy(
+                            void* dictBuffer, size_t maxDictSize,
+                            const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+                            ZDICT_legacy_params_t params);
+/*! ZDICT_trainFromBuffer_unsafe_legacy() :
+*   Warning : `samplesBuffer` must be followed by noisy guard band.
+*   @return : size of dictionary, or an error code which can be tested with ZDICT_isError()
+*/
+size_t ZDICT_trainFromBuffer_unsafe_legacy(
+                            void* dictBuffer, size_t maxDictSize,
+                            const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+                            ZDICT_legacy_params_t params)
+{
+    U32 const dictListSize = MAX(MAX(DICTLISTSIZE_DEFAULT, nbSamples), (U32)(maxDictSize/16));
+    dictItem* const dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList));
+    unsigned const selectivity = params.selectivityLevel == 0 ? g_selectivity_default : params.selectivityLevel;
+    unsigned const minRep = (selectivity > 30) ? MINRATIO : nbSamples >> selectivity;
+    size_t const targetDictSize = maxDictSize;
+    size_t const samplesBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples);
+    size_t dictSize = 0;
+    U32 const notificationLevel = params.zParams.notificationLevel;
+
+    /* checks */
+    if (!dictList) return ERROR(memory_allocation);
+    if (maxDictSize < ZDICT_DICTSIZE_MIN) { free(dictList); return ERROR(dstSize_tooSmall); }   /* requested dictionary size is too small */
+    if (samplesBuffSize < ZDICT_MIN_SAMPLES_SIZE) { free(dictList); return ERROR(dictionaryCreation_failed); }   /* not enough source to create dictionary */
+
+    /* init */
+    ZDICT_initDictItem(dictList);
+
+    /* build dictionary */
+    ZDICT_trainBuffer_legacy(dictList, dictListSize,
+                       samplesBuffer, samplesBuffSize,
+                       samplesSizes, nbSamples,
+                       minRep, notificationLevel);
+
+    /* display best matches */
+    if (params.zParams.notificationLevel>= 3) {
+        unsigned const nb = MIN(25, dictList[0].pos);
+        unsigned const dictContentSize = ZDICT_dictSize(dictList);
+        unsigned u;
+        DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", (unsigned)dictList[0].pos-1, dictContentSize);
+        DISPLAYLEVEL(3, "list %u best segments \n", nb-1);
+        for (u=1; u<nb; u++) {
+            unsigned const pos = dictList[u].pos;
+            unsigned const length = dictList[u].length;
+            U32 const printedLength = MIN(40, length);
+            if ((pos > samplesBuffSize) || ((pos + length) > samplesBuffSize)) {
+                free(dictList);
+                return ERROR(GENERIC);   /* should never happen */
+            }
+            DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |",
+                         u, length, pos, (unsigned)dictList[u].savings);
+            ZDICT_printHex((const char*)samplesBuffer+pos, printedLength);
+            DISPLAYLEVEL(3, "| \n");
+    }   }
+
+
+    /* create dictionary */
+    {   unsigned dictContentSize = ZDICT_dictSize(dictList);
+        if (dictContentSize < ZDICT_CONTENTSIZE_MIN) { free(dictList); return ERROR(dictionaryCreation_failed); }   /* dictionary content too small */
+        if (dictContentSize < targetDictSize/4) {
+            DISPLAYLEVEL(2, "!  warning : selected content significantly smaller than requested (%u < %u) \n", dictContentSize, (unsigned)maxDictSize);
+            if (samplesBuffSize < 10 * targetDictSize)
+                DISPLAYLEVEL(2, "!  consider increasing the number of samples (total size : %u MB)\n", (unsigned)(samplesBuffSize>>20));
+            if (minRep > MINRATIO) {
+                DISPLAYLEVEL(2, "!  consider increasing selectivity to produce larger dictionary (-s%u) \n", selectivity+1);
+                DISPLAYLEVEL(2, "!  note : larger dictionaries are not necessarily better, test its efficiency on samples \n");
+            }
+        }
+
+        if ((dictContentSize > targetDictSize*3) && (nbSamples > 2*MINRATIO) && (selectivity>1)) {
+            unsigned proposedSelectivity = selectivity-1;
+            while ((nbSamples >> proposedSelectivity) <= MINRATIO) { proposedSelectivity--; }
+            DISPLAYLEVEL(2, "!  note : calculated dictionary significantly larger than requested (%u > %u) \n", dictContentSize, (unsigned)maxDictSize);
+            DISPLAYLEVEL(2, "!  consider increasing dictionary size, or produce denser dictionary (-s%u) \n", proposedSelectivity);
+            DISPLAYLEVEL(2, "!  always test dictionary efficiency on real samples \n");
+        }
+
+        /* limit dictionary size */
+        {   U32 const max = dictList->pos;   /* convention : nb of useful elts within dictList */
+            U32 currentSize = 0;
+            U32 n; for (n=1; n<max; n++) {
+                currentSize += dictList[n].length;
+                if (currentSize > targetDictSize) { currentSize -= dictList[n].length; break; }
+            }
+            dictList->pos = n;
+            dictContentSize = currentSize;
+        }
+
+        /* build dict content */
+        {   U32 u;
+            BYTE* ptr = (BYTE*)dictBuffer + maxDictSize;
+            for (u=1; u<dictList->pos; u++) {
+                U32 l = dictList[u].length;
+                ptr -= l;
+                if (ptr<(BYTE*)dictBuffer) { free(dictList); return ERROR(GENERIC); }   /* should not happen */
+                memcpy(ptr, (const char*)samplesBuffer+dictList[u].pos, l);
+        }   }
+
+        dictSize = ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, maxDictSize,
+                                                             samplesBuffer, samplesSizes, nbSamples,
+                                                             params.zParams);
+    }
+
+    /* clean up */
+    free(dictList);
+    return dictSize;
+}
+
+
+/* ZDICT_trainFromBuffer_legacy() :
+ * issue : samplesBuffer need to be followed by a noisy guard band.
+ * work around : duplicate the buffer, and add the noise */
+size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity,
+                              const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+                              ZDICT_legacy_params_t params)
+{
+    size_t result;
+    void* newBuff;
+    size_t const sBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples);
+    if (sBuffSize < ZDICT_MIN_SAMPLES_SIZE) return 0;   /* not enough content => no dictionary */
+
+    newBuff = malloc(sBuffSize + NOISELENGTH);
+    if (!newBuff) return ERROR(memory_allocation);
+
+    memcpy(newBuff, samplesBuffer, sBuffSize);
+    ZDICT_fillNoise((char*)newBuff + sBuffSize, NOISELENGTH);   /* guard band, for end of buffer condition */
+
+    result =
+        ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, dictBufferCapacity, newBuff,
+                                            samplesSizes, nbSamples, params);
+    free(newBuff);
+    return result;
+}
+
+
+size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
+                             const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)
+{
+    ZDICT_fastCover_params_t params;
+    DEBUGLOG(3, "ZDICT_trainFromBuffer");
+    memset(&params, 0, sizeof(params));
+    params.d = 8;
+    params.steps = 4;
+    /* Default to level 6 since no compression level information is available */
+    params.zParams.compressionLevel = 3;
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1)
+    params.zParams.notificationLevel = DEBUGLEVEL;
+#endif
+    return ZDICT_optimizeTrainFromBuffer_fastCover(dictBuffer, dictBufferCapacity,
+                                               samplesBuffer, samplesSizes, nbSamples,
+                                               &params);
+}
+
+size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
+                                  const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)
+{
+    ZDICT_params_t params;
+    memset(&params, 0, sizeof(params));
+    return ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, dictBufferCapacity,
+                                                     samplesBuffer, samplesSizes, nbSamples,
+                                                     params);
+}
diff --git a/Utilities/cmzstd/lib/dictBuilder/zdict.h b/Utilities/cmzstd/lib/dictBuilder/zdict.h
new file mode 100644
index 0000000..d57d59f
--- /dev/null
+++ b/Utilities/cmzstd/lib/dictBuilder/zdict.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef DICTBUILDER_H_001
+#define DICTBUILDER_H_001
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/*======  Dependencies  ======*/
+#include <stddef.h>  /* size_t */
+
+
+/* =====   ZDICTLIB_API : control library symbols visibility   ===== */
+#ifndef ZDICTLIB_VISIBILITY
+#  if defined(__GNUC__) && (__GNUC__ >= 4)
+#    define ZDICTLIB_VISIBILITY __attribute__ ((visibility ("default")))
+#  else
+#    define ZDICTLIB_VISIBILITY
+#  endif
+#endif
+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
+#  define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBILITY
+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
+#  define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+#  define ZDICTLIB_API ZDICTLIB_VISIBILITY
+#endif
+
+
+/*! ZDICT_trainFromBuffer():
+ *  Train a dictionary from an array of samples.
+ *  Redirect towards ZDICT_optimizeTrainFromBuffer_fastCover() single-threaded, with d=8, steps=4,
+ *  f=20, and accel=1.
+ *  Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ *  supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ *  The resulting dictionary will be saved into `dictBuffer`.
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ *          or an error code, which can be tested with ZDICT_isError().
+ *  Note: ZDICT_trainFromBuffer() requires about 9 bytes of memory for each input byte.
+ *  Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ *        It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ *        In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ *        It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
+                                    const void* samplesBuffer,
+                                    const size_t* samplesSizes, unsigned nbSamples);
+
+
+/*======   Helper functions   ======*/
+ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize);  /**< extracts dictID; @return zero if error (not a valid dictionary) */
+ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode);
+ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode);
+
+
+
+#ifdef ZDICT_STATIC_LINKING_ONLY
+
+/* ====================================================================================
+ * The definitions in this section are considered experimental.
+ * They should never be used with a dynamic library, as they may change in the future.
+ * They are provided for advanced usages.
+ * Use them only in association with static linking.
+ * ==================================================================================== */
+
+typedef struct {
+    int      compressionLevel;   /* optimize for a specific zstd compression level; 0 means default */
+    unsigned notificationLevel;  /* Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */
+    unsigned dictID;             /* force dictID value; 0 means auto mode (32-bits random value) */
+} ZDICT_params_t;
+
+/*! ZDICT_cover_params_t:
+ *  k and d are the only required parameters.
+ *  For others, value 0 means default.
+ */
+typedef struct {
+    unsigned k;                  /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */
+    unsigned d;                  /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */
+    unsigned steps;              /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */
+    unsigned nbThreads;          /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */
+    double splitPoint;           /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (1.0), 1.0 when all samples are used for both training and testing */
+    ZDICT_params_t zParams;
+} ZDICT_cover_params_t;
+
+typedef struct {
+    unsigned k;                  /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */
+    unsigned d;                  /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */
+    unsigned f;                  /* log of size of frequency array : constraint: 0 < f <= 31 : 1 means default(20)*/
+    unsigned steps;              /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */
+    unsigned nbThreads;          /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */
+    double splitPoint;           /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (0.75), 1.0 when all samples are used for both training and testing */
+    unsigned accel;              /* Acceleration level: constraint: 0 < accel <= 10, higher means faster and less accurate, 0 means default(1) */
+    ZDICT_params_t zParams;
+} ZDICT_fastCover_params_t;
+
+/*! ZDICT_trainFromBuffer_cover():
+ *  Train a dictionary from an array of samples using the COVER algorithm.
+ *  Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ *  supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ *  The resulting dictionary will be saved into `dictBuffer`.
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ *          or an error code, which can be tested with ZDICT_isError().
+ *  Note: ZDICT_trainFromBuffer_cover() requires about 9 bytes of memory for each input byte.
+ *  Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ *        It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ *        In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ *        It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
+          void *dictBuffer, size_t dictBufferCapacity,
+    const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+          ZDICT_cover_params_t parameters);
+
+/*! ZDICT_optimizeTrainFromBuffer_cover():
+ * The same requirements as above hold for all the parameters except `parameters`.
+ * This function tries many parameter combinations and picks the best parameters.
+ * `*parameters` is filled with the best parameters found,
+ * dictionary constructed with those parameters is stored in `dictBuffer`.
+ *
+ * All of the parameters d, k, steps are optional.
+ * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}.
+ * if steps is zero it defaults to its default value.
+ * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000].
+ *
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ *           or an error code, which can be tested with ZDICT_isError().
+ *           On success `*parameters` contains the parameters selected.
+ * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread.
+ */
+ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
+          void* dictBuffer, size_t dictBufferCapacity,
+    const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+          ZDICT_cover_params_t* parameters);
+
+/*! ZDICT_trainFromBuffer_fastCover():
+ *  Train a dictionary from an array of samples using a modified version of COVER algorithm.
+ *  Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ *  supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ *  d and k are required.
+ *  All other parameters are optional, will use default values if not provided
+ *  The resulting dictionary will be saved into `dictBuffer`.
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ *          or an error code, which can be tested with ZDICT_isError().
+ *  Note: ZDICT_trainFromBuffer_fastCover() requires about 1 bytes of memory for each input byte and additionally another 6 * 2^f bytes of memory .
+ *  Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ *        It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ *        In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ *        It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer,
+                    size_t dictBufferCapacity, const void *samplesBuffer,
+                    const size_t *samplesSizes, unsigned nbSamples,
+                    ZDICT_fastCover_params_t parameters);
+
+/*! ZDICT_optimizeTrainFromBuffer_fastCover():
+ * The same requirements as above hold for all the parameters except `parameters`.
+ * This function tries many parameter combinations (specifically, k and d combinations)
+ * and picks the best parameters. `*parameters` is filled with the best parameters found,
+ * dictionary constructed with those parameters is stored in `dictBuffer`.
+ * All of the parameters d, k, steps, f, and accel are optional.
+ * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}.
+ * if steps is zero it defaults to its default value.
+ * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000].
+ * If f is zero, default value of 20 is used.
+ * If accel is zero, default value of 1 is used.
+ *
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ *           or an error code, which can be tested with ZDICT_isError().
+ *           On success `*parameters` contains the parameters selected.
+ * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 1 byte of memory for each input byte and additionally another 6 * 2^f bytes of memory for each thread.
+ */
+ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer,
+                    size_t dictBufferCapacity, const void* samplesBuffer,
+                    const size_t* samplesSizes, unsigned nbSamples,
+                    ZDICT_fastCover_params_t* parameters);
+
+/*! ZDICT_finalizeDictionary():
+ * Given a custom content as a basis for dictionary, and a set of samples,
+ * finalize dictionary by adding headers and statistics.
+ *
+ * Samples must be stored concatenated in a flat buffer `samplesBuffer`,
+ * supplied with an array of sizes `samplesSizes`, providing the size of each sample in order.
+ *
+ * dictContentSize must be >= ZDICT_CONTENTSIZE_MIN bytes.
+ * maxDictSize must be >= dictContentSize, and must be >= ZDICT_DICTSIZE_MIN bytes.
+ *
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`),
+ *           or an error code, which can be tested by ZDICT_isError().
+ * Note: ZDICT_finalizeDictionary() will push notifications into stderr if instructed to, using notificationLevel>0.
+ * Note 2: dictBuffer and dictContent can overlap
+ */
+#define ZDICT_CONTENTSIZE_MIN 128
+#define ZDICT_DICTSIZE_MIN    256
+ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
+                                const void* dictContent, size_t dictContentSize,
+                                const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
+                                ZDICT_params_t parameters);
+
+typedef struct {
+    unsigned selectivityLevel;   /* 0 means default; larger => select more => larger dictionary */
+    ZDICT_params_t zParams;
+} ZDICT_legacy_params_t;
+
+/*! ZDICT_trainFromBuffer_legacy():
+ *  Train a dictionary from an array of samples.
+ *  Samples must be stored concatenated in a single flat buffer `samplesBuffer`,
+ *  supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.
+ *  The resulting dictionary will be saved into `dictBuffer`.
+ * `parameters` is optional and can be provided with values set to 0 to mean "default".
+ * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
+ *          or an error code, which can be tested with ZDICT_isError().
+ *  Tips: In general, a reasonable dictionary has a size of ~ 100 KB.
+ *        It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`.
+ *        In general, it's recommended to provide a few thousands samples, though this can vary a lot.
+ *        It's recommended that total size of all samples be about ~x100 times the target size of dictionary.
+ *  Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0.
+ */
+ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy(
+    void *dictBuffer, size_t dictBufferCapacity,
+    const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+    ZDICT_legacy_params_t parameters);
+
+/* Deprecation warnings */
+/* It is generally possible to disable deprecation warnings from compiler,
+   for example with -Wno-deprecated-declarations for gcc
+   or _CRT_SECURE_NO_WARNINGS in Visual.
+   Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */
+#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS
+#  define ZDICT_DEPRECATED(message) ZDICTLIB_API   /* disable deprecation warnings */
+#else
+#  define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+#    define ZDICT_DEPRECATED(message) [[deprecated(message)]] ZDICTLIB_API
+#  elif (ZDICT_GCC_VERSION >= 405) || defined(__clang__)
+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated(message)))
+#  elif (ZDICT_GCC_VERSION >= 301)
+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated))
+#  elif defined(_MSC_VER)
+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API __declspec(deprecated(message))
+#  else
+#    pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler")
+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API
+#  endif
+#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */
+
+ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead")
+size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,
+                                  const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples);
+
+
+#endif   /* ZDICT_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif   /* DICTBUILDER_H_001 */
diff --git a/Utilities/cmzstd/lib/zstd.h b/Utilities/cmzstd/lib/zstd.h
new file mode 100644
index 0000000..b18fc8a
--- /dev/null
+++ b/Utilities/cmzstd/lib/zstd.h
@@ -0,0 +1,1766 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef ZSTD_H_235446
+#define ZSTD_H_235446
+
+/* ======   Dependency   ======*/
+#include <stddef.h>   /* size_t */
+
+
+/* =====   ZSTDLIB_API : control library symbols visibility   ===== */
+#ifndef ZSTDLIB_VISIBILITY
+#  if defined(__GNUC__) && (__GNUC__ >= 4)
+#    define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default")))
+#  else
+#    define ZSTDLIB_VISIBILITY
+#  endif
+#endif
+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
+#  define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY
+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
+#  define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+#  define ZSTDLIB_API ZSTDLIB_VISIBILITY
+#endif
+
+
+/*******************************************************************************
+  Introduction
+
+  zstd, short for Zstandard, is a fast lossless compression algorithm, targeting
+  real-time compression scenarios at zlib-level and better compression ratios.
+  The zstd compression library provides in-memory compression and decompression
+  functions.
+
+  The library supports regular compression levels from 1 up to ZSTD_maxCLevel(),
+  which is currently 22. Levels >= 20, labeled `--ultra`, should be used with
+  caution, as they require more memory. The library also offers negative
+  compression levels, which extend the range of speed vs. ratio preferences.
+  The lower the level, the faster the speed (at the cost of compression).
+
+  Compression can be done in:
+    - a single step (described as Simple API)
+    - a single step, reusing a context (described as Explicit context)
+    - unbounded multiple steps (described as Streaming compression)
+
+  The compression ratio achievable on small data can be highly improved using
+  a dictionary. Dictionary compression can be performed in:
+    - a single step (described as Simple dictionary API)
+    - a single step, reusing a dictionary (described as Bulk-processing
+      dictionary API)
+
+  Advanced experimental functions can be accessed using
+  `#define ZSTD_STATIC_LINKING_ONLY` before including zstd.h.
+
+  Advanced experimental APIs should never be used with a dynamically-linked
+  library. They are not "stable"; their definitions or signatures may change in
+  the future. Only static linking is allowed.
+*******************************************************************************/
+
+/*------   Version   ------*/
+#define ZSTD_VERSION_MAJOR    1
+#define ZSTD_VERSION_MINOR    3
+#define ZSTD_VERSION_RELEASE  8
+
+#define ZSTD_VERSION_NUMBER  (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
+ZSTDLIB_API unsigned ZSTD_versionNumber(void);   /**< to check runtime library version */
+
+#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE
+#define ZSTD_QUOTE(str) #str
+#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
+#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
+ZSTDLIB_API const char* ZSTD_versionString(void);   /* requires v1.3.0+ */
+
+/***************************************
+*  Default constant
+***************************************/
+#ifndef ZSTD_CLEVEL_DEFAULT
+#  define ZSTD_CLEVEL_DEFAULT 3
+#endif
+
+/***************************************
+*  Simple API
+***************************************/
+/*! ZSTD_compress() :
+ *  Compresses `src` content as a single zstd compressed frame into already allocated `dst`.
+ *  Hint : compression runs faster if `dstCapacity` >=  `ZSTD_compressBound(srcSize)`.
+ *  @return : compressed size written into `dst` (<= `dstCapacity),
+ *            or an error code if it fails (which can be tested using ZSTD_isError()). */
+ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity,
+                            const void* src, size_t srcSize,
+                                  int compressionLevel);
+
+/*! ZSTD_decompress() :
+ *  `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames.
+ *  `dstCapacity` is an upper bound of originalSize to regenerate.
+ *  If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data.
+ *  @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),
+ *            or an errorCode if it fails (which can be tested using ZSTD_isError()). */
+ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
+                              const void* src, size_t compressedSize);
+
+/*! ZSTD_getFrameContentSize() : requires v1.3.0+
+ *  `src` should point to the start of a ZSTD encoded frame.
+ *  `srcSize` must be at least as large as the frame header.
+ *            hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
+ *  @return : - decompressed size of `src` frame content, if known
+ *            - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
+ *            - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small)
+ *   note 1 : a 0 return value means the frame is valid but "empty".
+ *   note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode.
+ *            When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
+ *            In which case, it's necessary to use streaming mode to decompress data.
+ *            Optionally, application can rely on some implicit limit,
+ *            as ZSTD_decompress() only needs an upper bound of decompressed size.
+ *            (For example, data could be necessarily cut into blocks <= 16 KB).
+ *   note 3 : decompressed size is always present when compression is completed using single-pass functions,
+ *            such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict().
+ *   note 4 : decompressed size can be very large (64-bits value),
+ *            potentially larger than what local system can handle as a single memory segment.
+ *            In which case, it's necessary to use streaming mode to decompress data.
+ *   note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified.
+ *            Always ensure return value fits within application's authorized limits.
+ *            Each application can set its own limits.
+ *   note 6 : This function replaces ZSTD_getDecompressedSize() */
+#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
+#define ZSTD_CONTENTSIZE_ERROR   (0ULL - 2)
+ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
+
+/*! ZSTD_getDecompressedSize() :
+ *  NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
+ *  Both functions work the same way, but ZSTD_getDecompressedSize() blends
+ *  "empty", "unknown" and "error" results to the same return value (0),
+ *  while ZSTD_getFrameContentSize() gives them separate return values.
+ * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */
+ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
+
+
+/*======  Helper functions  ======*/
+#define ZSTD_COMPRESSBOUND(srcSize)   ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0))  /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
+ZSTDLIB_API size_t      ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */
+ZSTDLIB_API unsigned    ZSTD_isError(size_t code);          /*!< tells if a `size_t` function result is an error code */
+ZSTDLIB_API const char* ZSTD_getErrorName(size_t code);     /*!< provides readable string from an error code */
+ZSTDLIB_API int         ZSTD_maxCLevel(void);               /*!< maximum compression level available */
+
+
+/***************************************
+*  Explicit context
+***************************************/
+/*= Compression context
+ *  When compressing many times,
+ *  it is recommended to allocate a context just once, and re-use it for each successive compression operation.
+ *  This will make workload friendlier for system's memory.
+ *  Use one context per thread for parallel execution in multi-threaded environments. */
+typedef struct ZSTD_CCtx_s ZSTD_CCtx;
+ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void);
+ZSTDLIB_API size_t     ZSTD_freeCCtx(ZSTD_CCtx* cctx);
+
+/*! ZSTD_compressCCtx() :
+ *  Same as ZSTD_compress(), using an explicit ZSTD_CCtx
+ *  The function will compress at requested compression level,
+ *  ignoring any other parameter */
+ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
+                                     void* dst, size_t dstCapacity,
+                               const void* src, size_t srcSize,
+                                     int compressionLevel);
+
+/*= Decompression context
+ *  When decompressing many times,
+ *  it is recommended to allocate a context only once,
+ *  and re-use it for each successive compression operation.
+ *  This will make workload friendlier for system's memory.
+ *  Use one context per thread for parallel execution. */
+typedef struct ZSTD_DCtx_s ZSTD_DCtx;
+ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void);
+ZSTDLIB_API size_t     ZSTD_freeDCtx(ZSTD_DCtx* dctx);
+
+/*! ZSTD_decompressDCtx() :
+ *  Same as ZSTD_decompress(),
+ *  requires an allocated ZSTD_DCtx.
+ *  Compatible with sticky parameters.
+ */
+ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx,
+                                       void* dst, size_t dstCapacity,
+                                 const void* src, size_t srcSize);
+
+
+/**************************
+*  Simple dictionary API
+***************************/
+/*! ZSTD_compress_usingDict() :
+ *  Compression at an explicit compression level using a Dictionary.
+ *  A dictionary can be any arbitrary data segment (also called a prefix),
+ *  or a buffer with specified information (see dictBuilder/zdict.h).
+ *  Note : This function loads the dictionary, resulting in significant startup delay.
+ *         It's intended for a dictionary used only once.
+ *  Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */
+ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx,
+                                           void* dst, size_t dstCapacity,
+                                     const void* src, size_t srcSize,
+                                     const void* dict,size_t dictSize,
+                                           int compressionLevel);
+
+/*! ZSTD_decompress_usingDict() :
+ *  Decompression using a known Dictionary.
+ *  Dictionary must be identical to the one used during compression.
+ *  Note : This function loads the dictionary, resulting in significant startup delay.
+ *         It's intended for a dictionary used only once.
+ *  Note : When `dict == NULL || dictSize < 8` no dictionary is used. */
+ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
+                                             void* dst, size_t dstCapacity,
+                                       const void* src, size_t srcSize,
+                                       const void* dict,size_t dictSize);
+
+
+/***********************************
+ *  Bulk processing dictionary API
+ **********************************/
+typedef struct ZSTD_CDict_s ZSTD_CDict;
+
+/*! ZSTD_createCDict() :
+ *  When compressing multiple messages / blocks using the same dictionary, it's recommended to load it only once.
+ *  ZSTD_createCDict() will create a digested dictionary, ready to start future compression operations without startup cost.
+ *  ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.
+ * `dictBuffer` can be released after ZSTD_CDict creation, because its content is copied within CDict.
+ *  Consider experimental function `ZSTD_createCDict_byReference()` if you prefer to not duplicate `dictBuffer` content.
+ *  Note : A ZSTD_CDict can be created from an empty dictBuffer, but it is inefficient when used to compress small data. */
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize,
+                                         int compressionLevel);
+
+/*! ZSTD_freeCDict() :
+ *  Function frees memory allocated by ZSTD_createCDict(). */
+ZSTDLIB_API size_t      ZSTD_freeCDict(ZSTD_CDict* CDict);
+
+/*! ZSTD_compress_usingCDict() :
+ *  Compression using a digested Dictionary.
+ *  Recommended when same dictionary is used multiple times.
+ *  Note : compression level is _decided at dictionary creation time_,
+ *     and frame parameters are hardcoded (dictID=yes, contentSize=yes, checksum=no) */
+ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
+                                            void* dst, size_t dstCapacity,
+                                      const void* src, size_t srcSize,
+                                      const ZSTD_CDict* cdict);
+
+
+typedef struct ZSTD_DDict_s ZSTD_DDict;
+
+/*! ZSTD_createDDict() :
+ *  Create a digested dictionary, ready to start decompression operation without startup delay.
+ *  dictBuffer can be released after DDict creation, as its content is copied inside DDict. */
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);
+
+/*! ZSTD_freeDDict() :
+ *  Function frees memory allocated with ZSTD_createDDict() */
+ZSTDLIB_API size_t      ZSTD_freeDDict(ZSTD_DDict* ddict);
+
+/*! ZSTD_decompress_usingDDict() :
+ *  Decompression using a digested Dictionary.
+ *  Recommended when same dictionary is used multiple times. */
+ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
+                                              void* dst, size_t dstCapacity,
+                                        const void* src, size_t srcSize,
+                                        const ZSTD_DDict* ddict);
+
+
+/****************************
+*  Streaming
+****************************/
+
+typedef struct ZSTD_inBuffer_s {
+  const void* src;    /**< start of input buffer */
+  size_t size;        /**< size of input buffer */
+  size_t pos;         /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */
+} ZSTD_inBuffer;
+
+typedef struct ZSTD_outBuffer_s {
+  void*  dst;         /**< start of output buffer */
+  size_t size;        /**< size of output buffer */
+  size_t pos;         /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */
+} ZSTD_outBuffer;
+
+
+
+/*-***********************************************************************
+*  Streaming compression - HowTo
+*
+*  A ZSTD_CStream object is required to track streaming operation.
+*  Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources.
+*  ZSTD_CStream objects can be reused multiple times on consecutive compression operations.
+*  It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory.
+*
+*  For parallel execution, use one separate ZSTD_CStream per thread.
+*
+*  note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing.
+*
+*  Parameters are sticky : when starting a new compression on the same context,
+*  it will re-use the same sticky parameters as previous compression session.
+*  When in doubt, it's recommended to fully initialize the context before usage.
+*  Use ZSTD_initCStream() to set the parameter to a selected compression level.
+*  Use advanced API (ZSTD_CCtx_setParameter(), etc.) to set more specific parameters.
+*
+*  Use ZSTD_compressStream() as many times as necessary to consume input stream.
+*  The function will automatically update both `pos` fields within `input` and `output`.
+*  Note that the function may not consume the entire input,
+*  for example, because the output buffer is already full,
+*  in which case `input.pos < input.size`.
+*  The caller must check if input has been entirely consumed.
+*  If not, the caller must make some room to receive more compressed data,
+*  and then present again remaining input data.
+* @return : a size hint, preferred nb of bytes to use as input for next function call
+*           or an error code, which can be tested using ZSTD_isError().
+*           Note 1 : it's just a hint, to help latency a little, any value will work fine.
+*           Note 2 : size hint is guaranteed to be <= ZSTD_CStreamInSize()
+*
+*  At any moment, it's possible to flush whatever data might remain stuck within internal buffer,
+*  using ZSTD_flushStream(). `output->pos` will be updated.
+*  Note that, if `output->size` is too small, a single invocation of ZSTD_flushStream() might not be enough (return code > 0).
+*  In which case, make some room to receive more compressed data, and call again ZSTD_flushStream().
+*  @return : 0 if internal buffers are entirely flushed,
+*            >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
+*            or an error code, which can be tested using ZSTD_isError().
+*
+*  ZSTD_endStream() instructs to finish a frame.
+*  It will perform a flush and write frame epilogue.
+*  The epilogue is required for decoders to consider a frame completed.
+*  flush() operation is the same, and follows same rules as ZSTD_flushStream().
+*  @return : 0 if frame fully completed and fully flushed,
+*            >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
+*            or an error code, which can be tested using ZSTD_isError().
+*
+* *******************************************************************/
+
+typedef ZSTD_CCtx ZSTD_CStream;  /**< CCtx and CStream are now effectively same object (>= v1.3.0) */
+                                 /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */
+/*===== ZSTD_CStream management functions =====*/
+ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void);
+ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
+
+/*===== Streaming compression functions =====*/
+ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
+ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
+
+ZSTDLIB_API size_t ZSTD_CStreamInSize(void);    /**< recommended size for input buffer */
+ZSTDLIB_API size_t ZSTD_CStreamOutSize(void);   /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */
+
+
+
+/*-***************************************************************************
+*  Streaming decompression - HowTo
+*
+*  A ZSTD_DStream object is required to track streaming operations.
+*  Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources.
+*  ZSTD_DStream objects can be re-used multiple times.
+*
+*  Use ZSTD_initDStream() to start a new decompression operation.
+* @return : recommended first input size
+*  Alternatively, use advanced API to set specific properties.
+*
+*  Use ZSTD_decompressStream() repetitively to consume your input.
+*  The function will update both `pos` fields.
+*  If `input.pos < input.size`, some input has not been consumed.
+*  It's up to the caller to present again remaining data.
+*  The function tries to flush all data decoded immediately, respecting output buffer size.
+*  If `output.pos < output.size`, decoder has flushed everything it could.
+*  But if `output.pos == output.size`, there might be some data left within internal buffers.,
+*  In which case, call ZSTD_decompressStream() again to flush whatever remains in the buffer.
+*  Note : with no additional input provided, amount of data flushed is necessarily <= ZSTD_BLOCKSIZE_MAX.
+* @return : 0 when a frame is completely decoded and fully flushed,
+*        or an error code, which can be tested using ZSTD_isError(),
+*        or any other value > 0, which means there is still some decoding or flushing to do to complete current frame :
+*                                the return value is a suggested next input size (just a hint for better latency)
+*                                that will never request more than the remaining frame size.
+* *******************************************************************************/
+
+typedef ZSTD_DCtx ZSTD_DStream;  /**< DCtx and DStream are now effectively same object (>= v1.3.0) */
+                                 /* For compatibility with versions <= v1.2.0, prefer differentiating them. */
+/*===== ZSTD_DStream management functions =====*/
+ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
+ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
+
+/*===== Streaming decompression functions =====*/
+ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds);
+ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+
+ZSTDLIB_API size_t ZSTD_DStreamInSize(void);    /*!< recommended size for input buffer */
+ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */
+
+#endif  /* ZSTD_H_235446 */
+
+
+
+
+/****************************************************************************************
+ *   ADVANCED AND EXPERIMENTAL FUNCTIONS
+ ****************************************************************************************
+ * The definitions in the following section are considered experimental.
+ * They are provided for advanced scenarios.
+ * They should never be used with a dynamic library, as prototypes may change in the future.
+ * Use them only in association with static linking.
+ * ***************************************************************************************/
+
+#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)
+#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY
+
+
+/****************************************************************************************
+ *   Candidate API for promotion to stable status
+ ****************************************************************************************
+ * The following symbols and constants form the "staging area" :
+ * they are considered to join "stable API" by v1.4.0.
+ * The proposal is written so that it can be made stable "as is",
+ * though it's still possible to suggest improvements.
+ * Staging is in fact last chance for changes,
+ * the API is locked once reaching "stable" status.
+ * ***************************************************************************************/
+
+
+/* ===  Constants   === */
+
+/* all magic numbers are supposed read/written to/from files/memory using little-endian convention */
+#define ZSTD_MAGICNUMBER            0xFD2FB528    /* valid since v0.8.0 */
+#define ZSTD_MAGIC_DICTIONARY       0xEC30A437    /* valid since v0.7.0 */
+#define ZSTD_MAGIC_SKIPPABLE_START  0x184D2A50    /* all 16 values, from 0x184D2A50 to 0x184D2A5F, signal the beginning of a skippable frame */
+#define ZSTD_MAGIC_SKIPPABLE_MASK   0xFFFFFFF0
+
+#define ZSTD_BLOCKSIZELOG_MAX  17
+#define ZSTD_BLOCKSIZE_MAX     (1<<ZSTD_BLOCKSIZELOG_MAX)
+
+
+/* ===   query limits   === */
+
+ZSTDLIB_API int ZSTD_minCLevel(void);  /*!< minimum negative compression level allowed */
+
+
+/* ===   frame size   === */
+
+/*! ZSTD_findFrameCompressedSize() :
+ * `src` should point to the start of a ZSTD frame or skippable frame.
+ * `srcSize` must be >= first frame size
+ * @return : the compressed size of the first frame starting at `src`,
+ *           suitable to pass as `srcSize` to `ZSTD_decompress` or similar,
+ *        or an error code if input is invalid */
+ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
+
+
+/* ===   Memory management   === */
+
+/*! ZSTD_sizeof_*() :
+ *  These functions give the _current_ memory usage of selected object.
+ *  Note that object memory usage can evolve (increase or decrease) over time. */
+ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
+ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
+ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
+ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
+ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
+
+
+/***************************************
+*  Advanced compression API
+***************************************/
+
+/* API design :
+ *   Parameters are pushed one by one into an existing context,
+ *   using ZSTD_CCtx_set*() functions.
+ *   Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame.
+ *   "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` !
+ *   They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()
+ *
+ *   It's possible to reset all parameters to "default" using ZSTD_CCtx_reset().
+ *
+ *   This API supercedes all other "advanced" API entry points in the experimental section.
+ *   In the future, we expect to remove from experimental API entry points which are redundant with this API.
+ */
+
+
+/* Compression strategies, listed from fastest to strongest */
+typedef enum { ZSTD_fast=1,
+               ZSTD_dfast=2,
+               ZSTD_greedy=3,
+               ZSTD_lazy=4,
+               ZSTD_lazy2=5,
+               ZSTD_btlazy2=6,
+               ZSTD_btopt=7,
+               ZSTD_btultra=8,
+               ZSTD_btultra2=9
+               /* note : new strategies _might_ be added in the future.
+                         Only the order (from fast to strong) is guaranteed */
+} ZSTD_strategy;
+
+
+typedef enum {
+
+    /* compression parameters */
+    ZSTD_c_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
+                              * Default level is ZSTD_CLEVEL_DEFAULT==3.
+                              * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT.
+                              * Note 1 : it's possible to pass a negative compression level.
+                              * Note 2 : setting a level sets all default values of other compression parameters */
+    ZSTD_c_windowLog=101,    /* Maximum allowed back-reference distance, expressed as power of 2.
+                              * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
+                              * Special: value 0 means "use default windowLog".
+                              * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT
+                              *       requires explicitly allowing such window size at decompression stage if using streaming. */
+    ZSTD_c_hashLog=102,      /* Size of the initial probe table, as a power of 2.
+                              * Resulting memory usage is (1 << (hashLog+2)).
+                              * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
+                              * Larger tables improve compression ratio of strategies <= dFast,
+                              * and improve speed of strategies > dFast.
+                              * Special: value 0 means "use default hashLog". */
+    ZSTD_c_chainLog=103,     /* Size of the multi-probe search table, as a power of 2.
+                              * Resulting memory usage is (1 << (chainLog+2)).
+                              * Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX.
+                              * Larger tables result in better and slower compression.
+                              * This parameter is useless when using "fast" strategy.
+                              * It's still useful when using "dfast" strategy,
+                              * in which case it defines a secondary probe table.
+                              * Special: value 0 means "use default chainLog". */
+    ZSTD_c_searchLog=104,    /* Number of search attempts, as a power of 2.
+                              * More attempts result in better and slower compression.
+                              * This parameter is useless when using "fast" and "dFast" strategies.
+                              * Special: value 0 means "use default searchLog". */
+    ZSTD_c_minMatch=105,     /* Minimum size of searched matches.
+                              * Note that Zstandard can still find matches of smaller size,
+                              * it just tweaks its search algorithm to look for this size and larger.
+                              * Larger values increase compression and decompression speed, but decrease ratio.
+                              * Must be clamped between ZSTD_MINMATCH_MIN and ZSTD_MINMATCH_MAX.
+                              * Note that currently, for all strategies < btopt, effective minimum is 4.
+                              *                    , for all strategies > fast, effective maximum is 6.
+                              * Special: value 0 means "use default minMatchLength". */
+    ZSTD_c_targetLength=106, /* Impact of this field depends on strategy.
+                              * For strategies btopt, btultra & btultra2:
+                              *     Length of Match considered "good enough" to stop search.
+                              *     Larger values make compression stronger, and slower.
+                              * For strategy fast:
+                              *     Distance between match sampling.
+                              *     Larger values make compression faster, and weaker.
+                              * Special: value 0 means "use default targetLength". */
+    ZSTD_c_strategy=107,     /* See ZSTD_strategy enum definition.
+                              * The higher the value of selected strategy, the more complex it is,
+                              * resulting in stronger and slower compression.
+                              * Special: value 0 means "use default strategy". */
+
+    /* LDM mode parameters */
+    ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching.
+                                     * This parameter is designed to improve compression ratio
+                                     * for large inputs, by finding large matches at long distance.
+                                     * It increases memory usage and window size.
+                                     * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB
+                                     * except when expressly set to a different value. */
+    ZSTD_c_ldmHashLog=161,   /* Size of the table for long distance matching, as a power of 2.
+                              * Larger values increase memory usage and compression ratio,
+                              * but decrease compression speed.
+                              * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
+                              * default: windowlog - 7.
+                              * Special: value 0 means "automatically determine hashlog". */
+    ZSTD_c_ldmMinMatch=162,  /* Minimum match size for long distance matcher.
+                              * Larger/too small values usually decrease compression ratio.
+                              * Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX.
+                              * Special: value 0 means "use default value" (default: 64). */
+    ZSTD_c_ldmBucketSizeLog=163, /* Log size of each bucket in the LDM hash table for collision resolution.
+                              * Larger values improve collision resolution but decrease compression speed.
+                              * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX.
+                              * Special: value 0 means "use default value" (default: 3). */
+    ZSTD_c_ldmHashRateLog=164, /* Frequency of inserting/looking up entries into the LDM hash table.
+                              * Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN).
+                              * Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage.
+                              * Larger values improve compression speed.
+                              * Deviating far from default value will likely result in a compression ratio decrease.
+                              * Special: value 0 means "automatically determine hashRateLog". */
+
+    /* frame parameters */
+    ZSTD_c_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1)
+                              * Content size must be known at the beginning of compression.
+                              * This is automatically the case when using ZSTD_compress2(),
+                              * For streaming variants, content size must be provided with ZSTD_CCtx_setPledgedSrcSize() */
+    ZSTD_c_checksumFlag=201, /* A 32-bits checksum of content is written at end of frame (default:0) */
+    ZSTD_c_dictIDFlag=202,   /* When applicable, dictionary's ID is written into frame header (default:1) */
+
+    /* multi-threading parameters */
+    /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
+     * They return an error otherwise. */
+    ZSTD_c_nbWorkers=400,    /* Select how many threads will be spawned to compress in parallel.
+                              * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() :
+                              * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller,
+                              * while compression work is performed in parallel, within worker threads.
+                              * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end :
+                              *  in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call).
+                              * More workers improve speed, but also increase memory usage.
+                              * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
+    ZSTD_c_jobSize=401,      /* Size of a compression job. This value is enforced only when nbWorkers >= 1.
+                              * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads.
+                              * 0 means default, which is dynamically determined based on compression parameters.
+                              * Job size must be a minimum of overlap size, or 1 MB, whichever is largest.
+                              * The minimum size is automatically and transparently enforced */
+    ZSTD_c_overlapLog=402,   /* Control the overlap size, as a fraction of window size.
+                              * The overlap size is an amount of data reloaded from previous job at the beginning of a new job.
+                              * It helps preserve compression ratio, while each job is compressed in parallel.
+                              * This value is enforced only when nbWorkers >= 1.
+                              * Larger values increase compression ratio, but decrease speed.
+                              * Possible values range from 0 to 9 :
+                              * - 0 means "default" : value will be determined by the library, depending on strategy
+                              * - 1 means "no overlap"
+                              * - 9 means "full overlap", using a full window size.
+                              * Each intermediate rank increases/decreases load size by a factor 2 :
+                              * 9: full window;  8: w/2;  7: w/4;  6: w/8;  5:w/16;  4: w/32;  3:w/64;  2:w/128;  1:no overlap;  0:default
+                              * default value varies between 6 and 9, depending on strategy */
+
+    /* note : additional experimental parameters are also available
+     * within the experimental section of the API.
+     * At the time of this writing, they include :
+     * ZSTD_c_rsyncable
+     * ZSTD_c_format
+     * ZSTD_c_forceMaxWindow
+     * ZSTD_c_forceAttachDict
+     * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
+     * note : never ever use experimentalParam? names directly;
+     *        also, the enums values themselves are unstable and can still change.
+     */
+     ZSTD_c_experimentalParam1=500,
+     ZSTD_c_experimentalParam2=10,
+     ZSTD_c_experimentalParam3=1000,
+     ZSTD_c_experimentalParam4=1001
+} ZSTD_cParameter;
+
+
+typedef struct {
+    size_t error;
+    int lowerBound;
+    int upperBound;
+} ZSTD_bounds;
+
+/*! ZSTD_cParam_getBounds() :
+ *  All parameters must belong to an interval with lower and upper bounds,
+ *  otherwise they will either trigger an error or be automatically clamped.
+ * @return : a structure, ZSTD_bounds, which contains
+ *         - an error status field, which must be tested using ZSTD_isError()
+ *         - lower and upper bounds, both inclusive
+ */
+ZSTDLIB_API ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam);
+
+/*! ZSTD_CCtx_setParameter() :
+ *  Set one compression parameter, selected by enum ZSTD_cParameter.
+ *  All parameters have valid bounds. Bounds can be queried using ZSTD_cParam_getBounds().
+ *  Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter).
+ *  Setting a parameter is generally only possible during frame initialization (before starting compression).
+ *  Exception : when using multi-threading mode (nbWorkers >= 1),
+ *              the following parameters can be updated _during_ compression (within same frame):
+ *              => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
+ *              new parameters will be active for next job only (after a flush()).
+ * @return : an error code (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value);
+
+/*! ZSTD_CCtx_setPledgedSrcSize() :
+ *  Total input data size to be compressed as a single frame.
+ *  Value will be written in frame header, unless if explicitly forbidden using ZSTD_c_contentSizeFlag.
+ *  This value will also be controlled at end of frame, and trigger an error if not respected.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Note 1 : pledgedSrcSize==0 actually means zero, aka an empty frame.
+ *           In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN.
+ *           ZSTD_CONTENTSIZE_UNKNOWN is default value for any new frame.
+ *  Note 2 : pledgedSrcSize is only valid once, for the next frame.
+ *           It's discarded at the end of the frame, and replaced by ZSTD_CONTENTSIZE_UNKNOWN.
+ *  Note 3 : Whenever all input data is provided and consumed in a single round,
+ *           for example with ZSTD_compress2(),
+ *           or invoking immediately ZSTD_compressStream2(,,,ZSTD_e_end),
+ *           this value is automatically overriden by srcSize instead.
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
+
+/*! ZSTD_CCtx_loadDictionary() :
+ *  Create an internal CDict from `dict` buffer.
+ *  Decompression will have to use same dictionary.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary,
+ *           meaning "return to no-dictionary mode".
+ *  Note 1 : Dictionary is sticky, it will be used for all future compressed frames.
+ *           To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters).
+ *  Note 2 : Loading a dictionary involves building tables.
+ *           It's also a CPU consuming operation, with non-negligible impact on latency.
+ *           Tables are dependent on compression parameters, and for this reason,
+ *           compression parameters can no longer be changed after loading a dictionary.
+ *  Note 3 :`dict` content will be copied internally.
+ *           Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead.
+ *           In such a case, dictionary buffer must outlive its users.
+ *  Note 4 : Use ZSTD_CCtx_loadDictionary_advanced()
+ *           to precisely select how dictionary content must be interpreted. */
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_CCtx_refCDict() :
+ *  Reference a prepared dictionary, to be used for all next compressed frames.
+ *  Note that compression parameters are enforced from within CDict,
+ *  and supercede any compression parameter previously set within CCtx.
+ *  The dictionary will remain valid for future compressed frames using same CCtx.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Special : Referencing a NULL CDict means "return to no-dictionary mode".
+ *  Note 1 : Currently, only one dictionary can be managed.
+ *           Referencing a new dictionary effectively "discards" any previous one.
+ *  Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */
+ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
+
+/*! ZSTD_CCtx_refPrefix() :
+ *  Reference a prefix (single-usage dictionary) for next compressed frame.
+ *  A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end).
+ *  Decompression will need same prefix to properly regenerate data.
+ *  Compressing with a prefix is similar in outcome as performing a diff and compressing it,
+ *  but performs much faster, especially during decompression (compression speed is tunable with compression level).
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
+ *  Note 1 : Prefix buffer is referenced. It **must** outlive compression.
+ *           Its content must remain unmodified during compression.
+ *  Note 2 : If the intention is to diff some large src data blob with some prior version of itself,
+ *           ensure that the window size is large enough to contain the entire source.
+ *           See ZSTD_c_windowLog.
+ *  Note 3 : Referencing a prefix involves building tables, which are dependent on compression parameters.
+ *           It's a CPU consuming operation, with non-negligible impact on latency.
+ *           If there is a need to use the same prefix multiple times, consider loadDictionary instead.
+ *  Note 4 : By default, the prefix is interpreted as raw content (ZSTD_dm_rawContent).
+ *           Use experimental ZSTD_CCtx_refPrefix_advanced() to alter dictionary interpretation. */
+ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
+                                 const void* prefix, size_t prefixSize);
+
+
+typedef enum {
+    ZSTD_reset_session_only = 1,
+    ZSTD_reset_parameters = 2,
+    ZSTD_reset_session_and_parameters = 3
+} ZSTD_ResetDirective;
+
+/*! ZSTD_CCtx_reset() :
+ *  There are 2 different things that can be reset, independently or jointly :
+ *  - The session : will stop compressing current frame, and make CCtx ready to start a new one.
+ *                  Useful after an error, or to interrupt any ongoing compression.
+ *                  Any internal data not yet flushed is cancelled.
+ *                  Compression parameters and dictionary remain unchanged.
+ *                  They will be used to compress next frame.
+ *                  Resetting session never fails.
+ *  - The parameters : changes all parameters back to "default".
+ *                  This removes any reference to any dictionary too.
+ *                  Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing)
+ *                  otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError())
+ *  - Both : similar to resetting the session, followed by resetting parameters.
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset);
+
+
+
+/*! ZSTD_compress2() :
+ *  Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API.
+ *  ZSTD_compress2() always starts a new frame.
+ *  Should cctx hold data from a previously unfinished frame, everything about it is forgotten.
+ *  - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
+ *  - The function is always blocking, returns when compression is completed.
+ *  Hint : compression runs faster if `dstCapacity` >=  `ZSTD_compressBound(srcSize)`.
+ * @return : compressed size written into `dst` (<= `dstCapacity),
+ *           or an error code if it fails (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx,
+                                   void* dst, size_t dstCapacity,
+                             const void* src, size_t srcSize);
+
+typedef enum {
+    ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal compression ratio */
+    ZSTD_e_flush=1,    /* flush any data provided so far,
+                        * it creates (at least) one new block, that can be decoded immediately on reception;
+                        * frame will continue: any future data can still reference previously compressed data, improving compression. */
+    ZSTD_e_end=2       /* flush any remaining data _and_ close current frame.
+                        * note that frame is only closed after compressed data is fully flushed (return value == 0).
+                        * After that point, any additional data starts a new frame.
+                        * note : each frame is independent (does not reference any content from previous frame). */
+} ZSTD_EndDirective;
+
+/*! ZSTD_compressStream2() :
+ *  Behaves about the same as ZSTD_compressStream, with additional control on end directive.
+ *  - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
+ *  - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode)
+ *  - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
+ *  - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
+ *  - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller.
+ *  - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available,
+ *                                                  and then immediately returns, just indicating that there is some data remaining to be flushed.
+ *                                                  The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
+ *  - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking.
+ *  - @return provides a minimum amount of data remaining to be flushed from internal buffers
+ *            or an error code, which can be tested using ZSTD_isError().
+ *            if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
+ *            This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers.
+ *            For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed.
+ *  - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
+ *            only ZSTD_e_end or ZSTD_e_flush operations are allowed.
+ *            Before starting a new compression job, or changing compression parameters,
+ *            it is required to fully flush internal buffers.
+ */
+ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
+                                         ZSTD_outBuffer* output,
+                                         ZSTD_inBuffer* input,
+                                         ZSTD_EndDirective endOp);
+
+
+
+/* ============================== */
+/*   Advanced decompression API   */
+/* ============================== */
+
+/* The advanced API pushes parameters one by one into an existing DCtx context.
+ * Parameters are sticky, and remain valid for all following frames
+ * using the same DCtx context.
+ * It's possible to reset parameters to default values using ZSTD_DCtx_reset().
+ * Note : This API is compatible with existing ZSTD_decompressDCtx() and ZSTD_decompressStream().
+ *        Therefore, no new decompression function is necessary.
+ */
+
+
+typedef enum {
+
+    ZSTD_d_windowLogMax=100, /* Select a size limit (in power of 2) beyond which
+                              * the streaming API will refuse to allocate memory buffer
+                              * in order to protect the host from unreasonable memory requirements.
+                              * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode.
+                              * By default, a decompression context accepts window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) */
+
+    /* note : additional experimental parameters are also available
+     * within the experimental section of the API.
+     * At the time of this writing, they include :
+     * ZSTD_c_format
+     * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
+     * note : never ever use experimentalParam? names directly
+     */
+     ZSTD_d_experimentalParam1=1000
+
+} ZSTD_dParameter;
+
+
+/*! ZSTD_dParam_getBounds() :
+ *  All parameters must belong to an interval with lower and upper bounds,
+ *  otherwise they will either trigger an error or be automatically clamped.
+ * @return : a structure, ZSTD_bounds, which contains
+ *         - an error status field, which must be tested using ZSTD_isError()
+ *         - both lower and upper bounds, inclusive
+ */
+ZSTDLIB_API ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam);
+
+/*! ZSTD_DCtx_setParameter() :
+ *  Set one compression parameter, selected by enum ZSTD_dParameter.
+ *  All parameters have valid bounds. Bounds can be queried using ZSTD_dParam_getBounds().
+ *  Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter).
+ *  Setting a parameter is only possible during frame initialization (before starting decompression).
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int value);
+
+
+/*! ZSTD_DCtx_loadDictionary() :
+ *  Create an internal DDict from dict buffer,
+ *  to be used to decompress next frames.
+ *  The dictionary remains valid for all future frames, until explicitly invalidated.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
+ *            meaning "return to no-dictionary mode".
+ *  Note 1 : Loading a dictionary involves building tables,
+ *           which has a non-negligible impact on CPU usage and latency.
+ *           It's recommended to "load once, use many times", to amortize the cost
+ *  Note 2 :`dict` content will be copied internally, so `dict` can be released after loading.
+ *           Use ZSTD_DCtx_loadDictionary_byReference() to reference dictionary content instead.
+ *  Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to take control of
+ *           how dictionary content is loaded and interpreted.
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_DCtx_refDDict() :
+ *  Reference a prepared dictionary, to be used to decompress next frames.
+ *  The dictionary remains active for decompression of future frames using same DCtx.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Note 1 : Currently, only one dictionary can be managed.
+ *           Referencing a new dictionary effectively "discards" any previous one.
+ *  Special: referencing a NULL DDict means "return to no-dictionary mode".
+ *  Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+/*! ZSTD_DCtx_refPrefix() :
+ *  Reference a prefix (single-usage dictionary) to decompress next frame.
+ *  This is the reverse operation of ZSTD_CCtx_refPrefix(),
+ *  and must use the same prefix as the one used during compression.
+ *  Prefix is **only used once**. Reference is discarded at end of frame.
+ *  End of frame is reached when ZSTD_decompressStream() returns 0.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
+ *  Note 2 : Prefix buffer is referenced. It **must** outlive decompression.
+ *           Prefix buffer must remain unmodified up to the end of frame,
+ *           reached when ZSTD_decompressStream() returns 0.
+ *  Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
+ *           Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode (Experimental section)
+ *  Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
+ *           A full dictionary is more costly, as it requires building tables.
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx,
+                                 const void* prefix, size_t prefixSize);
+
+/*! ZSTD_DCtx_reset() :
+ *  Return a DCtx to clean state.
+ *  Session and parameters can be reset jointly or separately.
+ *  Parameters can only be reset when no active frame is being decompressed.
+ * @return : 0, or an error code, which can be tested with ZSTD_isError()
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset);
+
+
+
+/****************************************************************************************
+ *   experimental API (static linking only)
+ ****************************************************************************************
+ * The following symbols and constants
+ * are not planned to join "stable API" status in the near future.
+ * They can still change in future versions.
+ * Some of them are planned to remain in the static_only section indefinitely.
+ * Some of them might be removed in the future (especially when redundant with existing stable functions)
+ * ***************************************************************************************/
+
+#define ZSTD_FRAMEHEADERSIZE_PREFIX 5   /* minimum input size required to query frame header size */
+#define ZSTD_FRAMEHEADERSIZE_MIN    6
+#define ZSTD_FRAMEHEADERSIZE_MAX   18   /* can be useful for static allocation */
+#define ZSTD_SKIPPABLEHEADERSIZE    8
+
+/* compression parameter bounds */
+#define ZSTD_WINDOWLOG_MAX_32    30
+#define ZSTD_WINDOWLOG_MAX_64    31
+#define ZSTD_WINDOWLOG_MAX     ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
+#define ZSTD_WINDOWLOG_MIN       10
+#define ZSTD_HASHLOG_MAX       ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30)
+#define ZSTD_HASHLOG_MIN          6
+#define ZSTD_CHAINLOG_MAX_32     29
+#define ZSTD_CHAINLOG_MAX_64     30
+#define ZSTD_CHAINLOG_MAX      ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64))
+#define ZSTD_CHAINLOG_MIN        ZSTD_HASHLOG_MIN
+#define ZSTD_SEARCHLOG_MAX      (ZSTD_WINDOWLOG_MAX-1)
+#define ZSTD_SEARCHLOG_MIN        1
+#define ZSTD_MINMATCH_MAX         7   /* only for ZSTD_fast, other strategies are limited to 6 */
+#define ZSTD_MINMATCH_MIN         3   /* only for ZSTD_btopt+, faster strategies are limited to 4 */
+#define ZSTD_TARGETLENGTH_MAX    ZSTD_BLOCKSIZE_MAX
+#define ZSTD_TARGETLENGTH_MIN     0   /* note : comparing this constant to an unsigned results in a tautological test */
+#define ZSTD_STRATEGY_MIN        ZSTD_fast
+#define ZSTD_STRATEGY_MAX        ZSTD_btultra2
+
+
+#define ZSTD_OVERLAPLOG_MIN       0
+#define ZSTD_OVERLAPLOG_MAX       9
+
+#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27   /* by default, the streaming decoder will refuse any frame
+                                           * requiring larger than (1<<ZSTD_WINDOWLOG_LIMIT_DEFAULT) window size,
+                                           * to preserve host's memory from unreasonable requirements.
+                                           * This limit can be overriden using ZSTD_DCtx_setParameter(,ZSTD_d_windowLogMax,).
+                                           * The limit does not apply for one-pass decoders (such as ZSTD_decompress()), since no additional memory is allocated */
+
+
+/* LDM parameter bounds */
+#define ZSTD_LDM_HASHLOG_MIN      ZSTD_HASHLOG_MIN
+#define ZSTD_LDM_HASHLOG_MAX      ZSTD_HASHLOG_MAX
+#define ZSTD_LDM_MINMATCH_MIN        4
+#define ZSTD_LDM_MINMATCH_MAX     4096
+#define ZSTD_LDM_BUCKETSIZELOG_MIN   1
+#define ZSTD_LDM_BUCKETSIZELOG_MAX   8
+#define ZSTD_LDM_HASHRATELOG_MIN     0
+#define ZSTD_LDM_HASHRATELOG_MAX (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
+
+/* internal */
+#define ZSTD_HASHLOG3_MAX           17
+
+
+/* ---  Advanced types  --- */
+
+typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
+
+typedef struct {
+    unsigned windowLog;       /**< largest match distance : larger == more compression, more memory needed during decompression */
+    unsigned chainLog;        /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */
+    unsigned hashLog;         /**< dispatch table : larger == faster, more memory */
+    unsigned searchLog;       /**< nb of searches : larger == more compression, slower */
+    unsigned minMatch;        /**< match length searched : larger == faster decompression, sometimes less compression */
+    unsigned targetLength;    /**< acceptable match size for optimal parser (only) : larger == more compression, slower */
+    ZSTD_strategy strategy;   /**< see ZSTD_strategy definition above */
+} ZSTD_compressionParameters;
+
+typedef struct {
+    int contentSizeFlag; /**< 1: content size will be in frame header (when known) */
+    int checksumFlag;    /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */
+    int noDictIDFlag;    /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */
+} ZSTD_frameParameters;
+
+typedef struct {
+    ZSTD_compressionParameters cParams;
+    ZSTD_frameParameters fParams;
+} ZSTD_parameters;
+
+typedef enum {
+    ZSTD_dct_auto = 0,       /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
+    ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
+    ZSTD_dct_fullDict = 2    /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */
+} ZSTD_dictContentType_e;
+
+typedef enum {
+    ZSTD_dlm_byCopy = 0,  /**< Copy dictionary content internally */
+    ZSTD_dlm_byRef = 1,   /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
+} ZSTD_dictLoadMethod_e;
+
+typedef enum {
+    /* Opened question : should we have a format ZSTD_f_auto ?
+     * Today, it would mean exactly the same as ZSTD_f_zstd1.
+     * But, in the future, should several formats become supported,
+     * on the compression side, it would mean "default format".
+     * On the decompression side, it would mean "automatic format detection",
+     * so that ZSTD_f_zstd1 would mean "accept *only* zstd frames".
+     * Since meaning is a little different, another option could be to define different enums for compression and decompression.
+     * This question could be kept for later, when there are actually multiple formats to support,
+     * but there is also the question of pinning enum values, and pinning value `0` is especially important */
+    ZSTD_f_zstd1 = 0,           /* zstd frame format, specified in zstd_compression_format.md (default) */
+    ZSTD_f_zstd1_magicless = 1, /* Variant of zstd frame format, without initial 4-bytes magic number.
+                                 * Useful to save 4 bytes per generated frame.
+                                 * Decoder cannot recognise automatically this format, requiring this instruction. */
+} ZSTD_format_e;
+
+typedef enum {
+    /* Note: this enum and the behavior it controls are effectively internal
+     * implementation details of the compressor. They are expected to continue
+     * to evolve and should be considered only in the context of extremely
+     * advanced performance tuning.
+     *
+     * Zstd currently supports the use of a CDict in two ways:
+     *
+     * - The contents of the CDict can be copied into the working context. This
+     *   means that the compression can search both the dictionary and input
+     *   while operating on a single set of internal tables. This makes
+     *   the compression faster per-byte of input. However, the initial copy of
+     *   the CDict's tables incurs a fixed cost at the beginning of the
+     *   compression. For small compressions (< 8 KB), that copy can dominate
+     *   the cost of the compression.
+     *
+     * - The CDict's tables can be used in-place. In this model, compression is
+     *   slower per input byte, because the compressor has to search two sets of
+     *   tables. However, this model incurs no start-up cost (as long as the
+     *   working context's tables can be reused). For small inputs, this can be
+     *   faster than copying the CDict's tables.
+     *
+     * Zstd has a simple internal heuristic that selects which strategy to use
+     * at the beginning of a compression. However, if experimentation shows that
+     * Zstd is making poor choices, it is possible to override that choice with
+     * this enum.
+     */
+    ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */
+    ZSTD_dictForceAttach   = 1, /* Never copy the dictionary. */
+    ZSTD_dictForceCopy     = 2, /* Always copy the dictionary. */
+} ZSTD_dictAttachPref_e;
+
+
+/***************************************
+*  Frame size functions
+***************************************/
+
+/*! ZSTD_findDecompressedSize() :
+ *  `src` should point the start of a series of ZSTD encoded and/or skippable frames
+ *  `srcSize` must be the _exact_ size of this series
+ *       (i.e. there should be a frame boundary exactly at `srcSize` bytes after `src`)
+ *  @return : - decompressed size of all data in all successive frames
+ *            - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN
+ *            - if an error occurred: ZSTD_CONTENTSIZE_ERROR
+ *
+ *   note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode.
+ *            When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
+ *            In which case, it's necessary to use streaming mode to decompress data.
+ *   note 2 : decompressed size is always present when compression is done with ZSTD_compress()
+ *   note 3 : decompressed size can be very large (64-bits value),
+ *            potentially larger than what local system can handle as a single memory segment.
+ *            In which case, it's necessary to use streaming mode to decompress data.
+ *   note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified.
+ *            Always ensure result fits within application's authorized limits.
+ *            Each application can set its own limits.
+ *   note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to
+ *            read each contained frame header.  This is fast as most of the data is skipped,
+ *            however it does mean that all frame data must be present and valid. */
+ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize);
+
+/*! ZSTD_frameHeaderSize() :
+ *  srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX.
+ * @return : size of the Frame Header,
+ *           or an error code (if srcSize is too small) */
+ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
+
+
+/***************************************
+*  Memory management
+***************************************/
+
+/*! ZSTD_estimate*() :
+ *  These functions make it possible to estimate memory usage
+ *  of a future {D,C}Ctx, before its creation.
+ *  ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one.
+ *  It will also consider src size to be arbitrarily "large", which is worst case.
+ *  If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
+ *  ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
+ *  ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
+ *  Note : CCtx size estimation is only correct for single-threaded compression. */
+ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
+ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
+ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
+ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
+
+/*! ZSTD_estimateCStreamSize() :
+ *  ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
+ *  It will also consider src size to be arbitrarily "large", which is worst case.
+ *  If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
+ *  ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
+ *  ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
+ *  Note : CStream size estimation is only correct for single-threaded compression.
+ *  ZSTD_DStream memory budget depends on window Size.
+ *  This information can be passed manually, using ZSTD_estimateDStreamSize,
+ *  or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
+ *  Note : if streaming is init with function ZSTD_init?Stream_usingDict(),
+ *         an internal ?Dict will be created, which additional size is not estimated here.
+ *         In this case, get total size by adding ZSTD_estimate?DictSize */
+ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
+ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
+ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
+ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
+ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
+
+/*! ZSTD_estimate?DictSize() :
+ *  ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
+ *  ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced().
+ *  Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller.
+ */
+ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
+ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
+
+/*! ZSTD_initStatic*() :
+ *  Initialize an object using a pre-allocated fixed-size buffer.
+ *  workspace: The memory area to emplace the object into.
+ *             Provided pointer *must be 8-bytes aligned*.
+ *             Buffer must outlive object.
+ *  workspaceSize: Use ZSTD_estimate*Size() to determine
+ *                 how large workspace must be to support target scenario.
+ * @return : pointer to object (same address as workspace, just different type),
+ *           or NULL if error (size too small, incorrect alignment, etc.)
+ *  Note : zstd will never resize nor malloc() when using a static buffer.
+ *         If the object requires more memory than available,
+ *         zstd will just error out (typically ZSTD_error_memory_allocation).
+ *  Note 2 : there is no corresponding "free" function.
+ *           Since workspace is allocated externally, it must be freed externally too.
+ *  Note 3 : cParams : use ZSTD_getCParams() to convert a compression level
+ *           into its associated cParams.
+ *  Limitation 1 : currently not compatible with internal dictionary creation, triggered by
+ *                 ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict().
+ *  Limitation 2 : static cctx currently not compatible with multi-threading.
+ *  Limitation 3 : static dctx is incompatible with legacy support.
+ */
+ZSTDLIB_API ZSTD_CCtx*    ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
+ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticCCtx() */
+
+ZSTDLIB_API ZSTD_DCtx*    ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize);
+ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticDCtx() */
+
+ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict(
+                                        void* workspace, size_t workspaceSize,
+                                        const void* dict, size_t dictSize,
+                                        ZSTD_dictLoadMethod_e dictLoadMethod,
+                                        ZSTD_dictContentType_e dictContentType,
+                                        ZSTD_compressionParameters cParams);
+
+ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict(
+                                        void* workspace, size_t workspaceSize,
+                                        const void* dict, size_t dictSize,
+                                        ZSTD_dictLoadMethod_e dictLoadMethod,
+                                        ZSTD_dictContentType_e dictContentType);
+
+
+/*! Custom memory allocation :
+ *  These prototypes make it possible to pass your own allocation/free functions.
+ *  ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below.
+ *  All allocation/free operations will be completed using these custom variants instead of regular <stdlib.h> ones.
+ */
+typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
+typedef void  (*ZSTD_freeFunction) (void* opaque, void* address);
+typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
+static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL };  /**< this constant defers to stdlib's functions */
+
+ZSTDLIB_API ZSTD_CCtx*    ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_DCtx*    ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
+
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
+                                                  ZSTD_dictLoadMethod_e dictLoadMethod,
+                                                  ZSTD_dictContentType_e dictContentType,
+                                                  ZSTD_compressionParameters cParams,
+                                                  ZSTD_customMem customMem);
+
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
+                                                  ZSTD_dictLoadMethod_e dictLoadMethod,
+                                                  ZSTD_dictContentType_e dictContentType,
+                                                  ZSTD_customMem customMem);
+
+
+
+/***************************************
+*  Advanced compression functions
+***************************************/
+
+/*! ZSTD_createCDict_byReference() :
+ *  Create a digested dictionary for compression
+ *  Dictionary content is just referenced, not duplicated.
+ *  As a consequence, `dictBuffer` **must** outlive CDict,
+ *  and its content must remain unmodified throughout the lifetime of CDict. */
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
+
+/*! ZSTD_getCParams() :
+*   @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
+*   `estimatedSrcSize` value is optional, select 0 if not known */
+ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
+
+/*! ZSTD_getParams() :
+*   same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.
+*   All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */
+ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
+
+/*! ZSTD_checkCParams() :
+*   Ensure param values remain within authorized range */
+ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params);
+
+/*! ZSTD_adjustCParams() :
+ *  optimize params for a given `srcSize` and `dictSize`.
+ *  both values are optional, select `0` if unknown. */
+ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize);
+
+/*! ZSTD_compress_advanced() :
+ *  Same as ZSTD_compress_usingDict(), with fine-tune control over compression parameters (by structure) */
+ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
+                                          void* dst, size_t dstCapacity,
+                                    const void* src, size_t srcSize,
+                                    const void* dict,size_t dictSize,
+                                          ZSTD_parameters params);
+
+/*! ZSTD_compress_usingCDict_advanced() :
+ *  Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters */
+ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+                                              void* dst, size_t dstCapacity,
+                                        const void* src, size_t srcSize,
+                                        const ZSTD_CDict* cdict,
+                                              ZSTD_frameParameters fParams);
+
+
+/*! ZSTD_CCtx_loadDictionary_byReference() :
+ *  Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx.
+ *  It saves some memory, but also requires that `dict` outlives its usage within `cctx` */
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_CCtx_loadDictionary_advanced() :
+ *  Same as ZSTD_CCtx_loadDictionary(), but gives finer control over
+ *  how to load the dictionary (by copy ? by reference ?)
+ *  and how to interpret it (automatic ? force raw mode ? full mode only ?) */
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
+
+/*! ZSTD_CCtx_refPrefix_advanced() :
+ *  Same as ZSTD_CCtx_refPrefix(), but gives finer control over
+ *  how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */
+ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
+
+/* ===   experimental parameters   === */
+/* these parameters can be used with ZSTD_setParameter()
+ * they are not guaranteed to remain supported in the future */
+
+ /* Enables rsyncable mode,
+  * which makes compressed files more rsync friendly
+  * by adding periodic synchronization points to the compressed data.
+  * The target average block size is ZSTD_c_jobSize / 2.
+  * It's possible to modify the job size to increase or decrease
+  * the granularity of the synchronization point.
+  * Once the jobSize is smaller than the window size,
+  * it will result in compression ratio degradation.
+  * NOTE 1: rsyncable mode only works when multithreading is enabled.
+  * NOTE 2: rsyncable performs poorly in combination with long range mode,
+  * since it will decrease the effectiveness of synchronization points,
+  * though mileage may vary.
+  * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s.
+  * If the selected compression level is already running significantly slower,
+  * the overall speed won't be significantly impacted.
+  */
+ #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1
+
+/* Select a compression format.
+ * The value must be of type ZSTD_format_e.
+ * See ZSTD_format_e enum definition for details */
+#define ZSTD_c_format ZSTD_c_experimentalParam2
+
+/* Force back-reference distances to remain < windowSize,
+ * even when referencing into Dictionary content (default:0) */
+#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3
+
+/* Controls whether the contents of a CDict
+ * are used in place, or copied into the working context.
+ * Accepts values from the ZSTD_dictAttachPref_e enum.
+ * See the comments on that enum for an explanation of the feature. */
+#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4
+
+/*! ZSTD_CCtx_getParameter() :
+ *  Get the requested compression parameter value, selected by enum ZSTD_cParameter,
+ *  and store it into int* value.
+ * @return : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
+
+
+/*! ZSTD_CCtx_params :
+ *  Quick howto :
+ *  - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
+ *  - ZSTD_CCtxParam_setParameter() : Push parameters one by one into
+ *                                    an existing ZSTD_CCtx_params structure.
+ *                                    This is similar to
+ *                                    ZSTD_CCtx_setParameter().
+ *  - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
+ *                                    an existing CCtx.
+ *                                    These parameters will be applied to
+ *                                    all subsequent frames.
+ *  - ZSTD_compressStream2() : Do compression using the CCtx.
+ *  - ZSTD_freeCCtxParams() : Free the memory.
+ *
+ *  This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
+ *  for static allocation of CCtx for single-threaded compression.
+ */
+ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
+ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
+
+/*! ZSTD_CCtxParams_reset() :
+ *  Reset params to default values.
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params);
+
+/*! ZSTD_CCtxParams_init() :
+ *  Initializes the compression parameters of cctxParams according to
+ *  compression level. All other parameters are reset to their default values.
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel);
+
+/*! ZSTD_CCtxParams_init_advanced() :
+ *  Initializes the compression and frame parameters of cctxParams according to
+ *  params. All other parameters are reset to their default values.
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
+
+/*! ZSTD_CCtxParam_setParameter() :
+ *  Similar to ZSTD_CCtx_setParameter.
+ *  Set one compression parameter, selected by enum ZSTD_cParameter.
+ *  Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value);
+
+/*! ZSTD_CCtxParam_getParameter() :
+ * Similar to ZSTD_CCtx_getParameter.
+ * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
+ * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_CCtxParam_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
+
+/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
+ *  Apply a set of ZSTD_CCtx_params to the compression context.
+ *  This can be done even after compression is started,
+ *    if nbWorkers==0, this will have no impact until a new compression is started.
+ *    if nbWorkers>=1, new parameters will be picked up at next job,
+ *       with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated).
+ */
+ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
+        ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
+
+/*! ZSTD_compressStream2_simpleArgs() :
+ *  Same as ZSTD_compressStream2(),
+ *  but using only integral types as arguments.
+ *  This variant might be helpful for binders from dynamic languages
+ *  which have troubles handling structures containing memory pointers.
+ */
+ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs (
+                            ZSTD_CCtx* cctx,
+                            void* dst, size_t dstCapacity, size_t* dstPos,
+                      const void* src, size_t srcSize, size_t* srcPos,
+                            ZSTD_EndDirective endOp);
+
+
+/***************************************
+*  Advanced decompression functions
+***************************************/
+
+/*! ZSTD_isFrame() :
+ *  Tells if the content of `buffer` starts with a valid Frame Identifier.
+ *  Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
+ *  Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
+ *  Note 3 : Skippable Frame Identifiers are considered valid. */
+ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
+
+/*! ZSTD_createDDict_byReference() :
+ *  Create a digested dictionary, ready to start decompression operation without startup delay.
+ *  Dictionary content is referenced, and therefore stays in dictBuffer.
+ *  It is important that dictBuffer outlives DDict,
+ *  it must remain read accessible throughout the lifetime of DDict */
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
+
+
+/*! ZSTD_getDictID_fromDict() :
+ *  Provides the dictID stored within dictionary.
+ *  if @return == 0, the dictionary is not conformant with Zstandard specification.
+ *  It can still be loaded, but as a content-only dictionary. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
+
+/*! ZSTD_getDictID_fromDDict() :
+ *  Provides the dictID of the dictionary loaded into `ddict`.
+ *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
+
+/*! ZSTD_getDictID_fromFrame() :
+ *  Provides the dictID required to decompressed the frame stored within `src`.
+ *  If @return == 0, the dictID could not be decoded.
+ *  This could for one of the following reasons :
+ *  - The frame does not require a dictionary to be decoded (most common case).
+ *  - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information.
+ *    Note : this use case also happens when using a non-conformant dictionary.
+ *  - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
+ *  - This is not a Zstandard frame.
+ *  When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
+
+/*! ZSTD_DCtx_loadDictionary_byReference() :
+ *  Same as ZSTD_DCtx_loadDictionary(),
+ *  but references `dict` content instead of copying it into `dctx`.
+ *  This saves memory if `dict` remains around.,
+ *  However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */
+ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
+
+/*! ZSTD_DCtx_loadDictionary_advanced() :
+ *  Same as ZSTD_DCtx_loadDictionary(),
+ *  but gives direct control over
+ *  how to load the dictionary (by copy ? by reference ?)
+ *  and how to interpret it (automatic ? force raw mode ? full mode only ?). */
+ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
+
+/*! ZSTD_DCtx_refPrefix_advanced() :
+ *  Same as ZSTD_DCtx_refPrefix(), but gives finer control over
+ *  how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */
+ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
+
+/*! ZSTD_DCtx_setMaxWindowSize() :
+ *  Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
+ *  This protects a decoder context from reserving too much memory for itself (potential attack scenario).
+ *  This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode.
+ *  By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT)
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
+
+/* ZSTD_d_format
+ * experimental parameter,
+ * allowing selection between ZSTD_format_e input compression formats
+ */
+#define ZSTD_d_format ZSTD_d_experimentalParam1
+
+/*! ZSTD_DCtx_setFormat() :
+ *  Instruct the decoder context about what kind of data to decode next.
+ *  This instruction is mandatory to decode data without a fully-formed header,
+ *  such ZSTD_f_zstd1_magicless for example.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError()). */
+ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
+
+/*! ZSTD_decompressStream_simpleArgs() :
+ *  Same as ZSTD_decompressStream(),
+ *  but using only integral types as arguments.
+ *  This can be helpful for binders from dynamic languages
+ *  which have troubles handling structures containing memory pointers.
+ */
+ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
+                            ZSTD_DCtx* dctx,
+                            void* dst, size_t dstCapacity, size_t* dstPos,
+                      const void* src, size_t srcSize, size_t* srcPos);
+
+
+/********************************************************************
+*  Advanced streaming functions
+*  Warning : most of these functions are now redundant with the Advanced API.
+*  Once Advanced API reaches "stable" status,
+*  redundant functions will be deprecated, and then at some point removed.
+********************************************************************/
+
+/*=====   Advanced Streaming compression functions  =====*/
+ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize);   /**< pledgedSrcSize must be correct. If it is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, "0" also disables frame content size field. It may be enabled in the future. */
+ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
+ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
+                                             ZSTD_parameters params, unsigned long long pledgedSrcSize);  /**< pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */
+ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);  /**< note : cdict will just be referenced, and must outlive compression session */
+ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize);  /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters. pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. */
+
+/*! ZSTD_resetCStream() :
+ *  start a new frame, using same parameters from previous frame.
+ *  This is typically useful to skip dictionary loading stage, since it will re-use it in-place.
+ *  Note that zcs must be init at least once before using ZSTD_resetCStream().
+ *  If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
+ *  If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
+ *  For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
+ *  but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
+ * @return : 0, or an error code (which can be tested using ZSTD_isError())
+ */
+ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
+
+
+typedef struct {
+    unsigned long long ingested;   /* nb input bytes read and buffered */
+    unsigned long long consumed;   /* nb input bytes actually compressed */
+    unsigned long long produced;   /* nb of compressed bytes generated and buffered */
+    unsigned long long flushed;    /* nb of compressed bytes flushed : not provided; can be tracked from caller side */
+    unsigned currentJobID;         /* MT only : latest started job nb */
+    unsigned nbActiveWorkers;      /* MT only : nb of workers actively compressing at probe time */
+} ZSTD_frameProgression;
+
+/* ZSTD_getFrameProgression() :
+ * tells how much data has been ingested (read from input)
+ * consumed (input actually compressed) and produced (output) for current frame.
+ * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed.
+ * Aggregates progression inside active worker threads.
+ */
+ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx);
+
+/*! ZSTD_toFlushNow() :
+ *  Tell how many bytes are ready to be flushed immediately.
+ *  Useful for multithreading scenarios (nbWorkers >= 1).
+ *  Probe the oldest active job, defined as oldest job not yet entirely flushed,
+ *  and check its output buffer.
+ * @return : amount of data stored in oldest job and ready to be flushed immediately.
+ *  if @return == 0, it means either :
+ *  + there is no active job (could be checked with ZSTD_frameProgression()), or
+ *  + oldest job is still actively compressing data,
+ *    but everything it has produced has also been flushed so far,
+ *    therefore flush speed is limited by production speed of oldest job
+ *    irrespective of the speed of concurrent (and newer) jobs.
+ */
+ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx);
+
+
+/*=====   Advanced Streaming decompression functions  =====*/
+ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
+ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict is referenced, it must outlive decompression session */
+ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */
+
+
+/*********************************************************************
+*  Buffer-less and synchronous inner streaming functions
+*
+*  This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
+*  But it's also a complex one, with several restrictions, documented below.
+*  Prefer normal streaming API for an easier experience.
+********************************************************************* */
+
+/**
+  Buffer-less streaming compression (synchronous mode)
+
+  A ZSTD_CCtx object is required to track streaming operations.
+  Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
+  ZSTD_CCtx object can be re-used multiple times within successive compression operations.
+
+  Start by initializing a context.
+  Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression,
+  or ZSTD_compressBegin_advanced(), for finer parameter control.
+  It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx()
+
+  Then, consume your input using ZSTD_compressContinue().
+  There are some important considerations to keep in mind when using this advanced function :
+  - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
+  - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
+  - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
+    Worst case evaluation is provided by ZSTD_compressBound().
+    ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
+  - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog).
+    It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks)
+  - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps.
+    In which case, it will "discard" the relevant memory section from its history.
+
+  Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
+  It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
+  Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
+
+  `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
+*/
+
+/*=====   Buffer-less streaming compression functions  =====*/
+ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
+ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
+ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */
+ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize);   /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
+ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**<  note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */
+
+ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+
+
+/*-
+  Buffer-less streaming decompression (synchronous mode)
+
+  A ZSTD_DCtx object is required to track streaming operations.
+  Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
+  A ZSTD_DCtx object can be re-used multiple times.
+
+  First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader().
+  Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough.
+  Data fragment must be large enough to ensure successful decoding.
+ `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
+  @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled.
+           >0 : `srcSize` is too small, please provide at least @result bytes on next attempt.
+           errorCode, which can be tested using ZSTD_isError().
+
+  It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
+  such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`).
+  Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information.
+  As a consequence, check that values remain within valid application range.
+  For example, do not allocate memory blindly, check that `windowSize` is within expectation.
+  Each application can set its own limits, depending on local restrictions.
+  For extended interoperability, it is recommended to support `windowSize` of at least 8 MB.
+
+  ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes.
+  ZSTD_decompressContinue() is very sensitive to contiguity,
+  if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
+  or that previous contiguous segment is large enough to properly handle maximum back-reference distance.
+  There are multiple ways to guarantee this condition.
+
+  The most memory efficient way is to use a round buffer of sufficient size.
+  Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(),
+  which can @return an error code if required value is too large for current system (in 32-bits mode).
+  In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one,
+  up to the moment there is not enough room left in the buffer to guarantee decoding another full block,
+  which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`.
+  At which point, decoding can resume from the beginning of the buffer.
+  Note that already decoded data stored in the buffer should be flushed before being overwritten.
+
+  There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory.
+
+  Finally, if you control the compression process, you can also ignore all buffer size rules,
+  as long as the encoder and decoder progress in "lock-step",
+  aka use exactly the same buffer sizes, break contiguity at the same place, etc.
+
+  Once buffers are setup, start decompression, with ZSTD_decompressBegin().
+  If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict().
+
+  Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
+  ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue().
+  ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail.
+
+ @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
+  It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item.
+  It can also be an error code, which can be tested with ZSTD_isError().
+
+  A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
+  Context can then be reset to start a new decompression.
+
+  Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType().
+  This information is not required to properly decode a frame.
+
+  == Special case : skippable frames ==
+
+  Skippable frames allow integration of user-defined data into a flow of concatenated frames.
+  Skippable frames will be ignored (skipped) by decompressor.
+  The format of skippable frames is as follows :
+  a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
+  b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
+  c) Frame Content - any content (User Data) of length equal to Frame Size
+  For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame.
+  For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.
+*/
+
+/*=====   Buffer-less streaming decompression functions  =====*/
+typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
+typedef struct {
+    unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */
+    unsigned long long windowSize;       /* can be very large, up to <= frameContentSize */
+    unsigned blockSizeMax;
+    ZSTD_frameType_e frameType;          /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */
+    unsigned headerSize;
+    unsigned dictID;
+    unsigned checksumFlag;
+} ZSTD_frameHeader;
+
+/** ZSTD_getFrameHeader() :
+ *  decode Frame Header, or requires larger `srcSize`.
+ * @return : 0, `zfhPtr` is correctly filled,
+ *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ *           or an error code, which can be tested using ZSTD_isError() */
+ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize);   /**< doesn't consume input */
+/*! ZSTD_getFrameHeader_advanced() :
+ *  same as ZSTD_getFrameHeader(),
+ *  with added capability to select a format (like ZSTD_f_zstd1_magicless) */
+ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format);
+ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize);  /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */
+
+ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
+ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+
+/* misc */
+ZSTDLIB_API void   ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
+typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
+ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
+
+
+
+
+/* ============================ */
+/**       Block level API       */
+/* ============================ */
+
+/*!
+    Block functions produce and decode raw zstd blocks, without frame metadata.
+    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
+    User will have to take in charge required information to regenerate data, such as compressed and content sizes.
+
+    A few rules to respect :
+    - Compressing and decompressing require a context structure
+      + Use ZSTD_createCCtx() and ZSTD_createDCtx()
+    - It is necessary to init context before starting
+      + compression : any ZSTD_compressBegin*() variant, including with dictionary
+      + decompression : any ZSTD_decompressBegin*() variant, including with dictionary
+      + copyCCtx() and copyDCtx() can be used too
+    - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
+      + If input is larger than a block size, it's necessary to split input data into multiple blocks
+      + For inputs larger than a single block, really consider using regular ZSTD_compress() instead.
+        Frame metadata is not that costly, and quickly becomes negligible as source size grows larger.
+    - When a block is considered not compressible enough, ZSTD_compressBlock() result will be zero.
+      In which case, nothing is produced into `dst` !
+      + User must test for such outcome and deal directly with uncompressed data
+      + ZSTD_decompressBlock() doesn't accept uncompressed data as input !!!
+      + In case of multiple successive blocks, should some of them be uncompressed,
+        decoder must be informed of their existence in order to follow proper history.
+        Use ZSTD_insertBlock() for such a case.
+*/
+
+/*=====   Raw zstd block functions  =====*/
+ZSTDLIB_API size_t ZSTD_getBlockSize   (const ZSTD_CCtx* cctx);
+ZSTDLIB_API size_t ZSTD_compressBlock  (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_insertBlock    (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize);  /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */
+
+
+#endif   /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/bootstrap b/bootstrap
index 26c5212..d46b8a8 100755
--- a/bootstrap
+++ b/bootstrap
@@ -260,6 +260,7 @@
   cmAddLibraryCommand \
   cmAddSubDirectoryCommand \
   cmAddTestCommand \
+  cmArgumentParser \
   cmBreakCommand \
   cmBuildCommand \
   cmCMakeMinimumRequired \
@@ -268,7 +269,6 @@
   cmCacheManager \
   cmCommand \
   cmCommandArgumentParserHelper \
-  cmCommandArgumentsHelper \
   cmCommands \
   cmCommonTargetGenerator \
   cmComputeComponentGraph \
@@ -302,7 +302,10 @@
   cmExprParserHelper \
   cmExternalMakefileProjectGenerator \
   cmFileCommand \
-  cmFileTimeComparison \
+  cmFileCopier \
+  cmFileInstaller \
+  cmFileTime \
+  cmFileTimeCache \
   cmFindBase \
   cmFindCommon \
   cmFindFileCommand \
@@ -573,6 +576,8 @@
   --no-system-bzip2       use cmake-provided bzip2 library (default)
   --system-liblzma        use system-installed liblzma library
   --no-system-liblzma     use cmake-provided liblzma library (default)
+  --system-zstd           use system-installed zstd library
+  --no-system-zstd        use cmake-provided zstd library (default)
   --system-libarchive     use system-installed libarchive library
   --no-system-libarchive  use cmake-provided libarchive library (default)
   --system-librhash       use system-installed librhash library
@@ -814,10 +819,10 @@
   --init=*) cmake_init_file=`cmake_arg "$1"` ;;
   --system-libs) cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARIES=1" ;;
   --no-system-libs) cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARIES=0" ;;
-  --system-bzip2|--system-curl|--system-expat|--system-jsoncpp|--system-libarchive|--system-librhash|--system-zlib|--system-liblzma|--system-libuv)
+  --system-bzip2|--system-curl|--system-expat|--system-jsoncpp|--system-libarchive|--system-librhash|--system-zlib|--system-liblzma|--system-zstd|--system-libuv)
     lib=`cmake_arg "$1" "--system-"`
     cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=1" ;;
-  --no-system-bzip2|--no-system-curl|--no-system-expat|--no-system-jsoncpp|--no-system-libarchive|--no-system-librhash|--no-system-zlib|--no-system-liblzma|--no-system-libuv)
+  --no-system-bzip2|--no-system-curl|--no-system-expat|--no-system-jsoncpp|--no-system-libarchive|--no-system-librhash|--no-system-zlib|--no-system-liblzma|--no-system-zstd|--no-system-libuv)
     lib=`cmake_arg "$1" "--no-system-"`
     cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=0" ;;
   --qt-gui) cmake_bootstrap_qt_gui="1" ;;