summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/cmake_path.rst1060
-rw-r--r--Help/command/if.rst54
-rw-r--r--Help/command/install.rst5
-rw-r--r--Help/generator/Ninja Multi-Config.rst31
-rw-r--r--Help/guide/tutorial/index.rst67
-rw-r--r--Help/manual/cmake-developer.7.rst136
-rw-r--r--Help/manual/cmake-file-api.7.rst157
-rw-r--r--Help/manual/cmake-presets.7.rst459
-rw-r--r--Help/release/dev/cuda-nvcc-ccache-symlink.rst9
-rw-r--r--Help/release/dev/external-project-configure-handled-by-build.rst8
-rw-r--r--Help/release/dev/install-files-rename-genex.rst5
-rw-r--r--Help/variable/CMAKE_CUDA_ARCHITECTURES.rst15
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst5
-rw-r--r--Modules/CMakeDetermineCCompiler.cmake5
-rw-r--r--Modules/CMakeDetermineCUDACompiler.cmake15
-rw-r--r--Modules/CMakeDetermineCXXCompiler.cmake3
-rw-r--r--Modules/CMakeFindBinUtils.cmake96
-rw-r--r--Modules/Compiler/Clang-FindBinUtils.cmake8
-rw-r--r--Modules/ExternalProject.cmake56
-rw-r--r--Modules/FindCUDA.cmake15
-rw-r--r--Modules/FindCUDAToolkit.cmake14
-rw-r--r--Modules/FindHDF5.cmake74
-rw-r--r--Modules/FindJPEG.cmake2
-rw-r--r--Modules/FindLAPACK.cmake58
-rw-r--r--Modules/InstallRequiredSystemLibraries.cmake2
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx12
-rw-r--r--Source/QtDialog/CMakeLists.txt5
-rw-r--r--Source/cmCMakePath.cxx3
-rw-r--r--Source/cmCMakePathCommand.cxx18
-rw-r--r--Source/cmFileAPI.cxx63
-rw-r--r--Source/cmFileAPI.h5
-rw-r--r--Source/cmFileAPIToolchains.cxx151
-rw-r--r--Source/cmFileAPIToolchains.h12
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx2
-rw-r--r--Source/cmInstallFilesGenerator.cxx14
-rw-r--r--Source/cmInstallFilesGenerator.h1
-rw-r--r--Source/cmListCommand.cxx7
-rw-r--r--Source/cmLocalNinjaGenerator.cxx13
-rw-r--r--Source/cmLocalNinjaGenerator.h3
-rw-r--r--Source/cmMakefile.cxx2
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx20
-rw-r--r--Tests/CMakeLists.txt15
-rw-r--r--Tests/CMakeTestMultipleConfigures/RunCMake.cmake165
-rw-r--r--Tests/CMakeTests/ListTest.cmake.in3
-rw-r--r--Tests/Fuzzing/README.rst8
-rw-r--r--Tests/Fuzzing/xml_parser_fuzzer.cc27
-rw-r--r--Tests/IncludeDirectories/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/CommandLine/E_capabilities-stdout.txt2
-rw-r--r--Tests/RunCMake/CommandLine/trace-expand.cmake1
-rw-r--r--Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake19
-rw-r--r--Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake28
-rw-r--r--Tests/RunCMake/ExternalProject/RunCMakeTest.cmake30
-rw-r--r--Tests/RunCMake/FileAPI/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake10
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-check.py86
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1.cmake22
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt2
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/cmake_path/HASH.cmake5
-rw-r--r--Tests/RunCMake/cmake_path/IS_PREFIX.cmake5
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-bad-result.txt1
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt6
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-bad.cmake4
-rw-r--r--Tests/RunCMake/install/FILES-RENAME.cmake4
-rw-r--r--Tests/RunCMake/install/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake5
-rw-r--r--Tests/RunCMake/list/RunCMakeTest.cmake1
77 files changed, 1966 insertions, 1238 deletions
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst
index 2d37ae0..5d2d7eb 100644
--- a/Help/command/cmake_path.rst
+++ b/Help/command/cmake_path.rst
@@ -3,109 +3,32 @@ cmake_path
.. versionadded:: 3.20
-Filesystem path manipulation command.
-
-This command is dedicated to the manipulation of objects of type path which
-represent paths on a filesystem. Only syntactic aspects of paths are handled:
-the pathname may represent a non-existing path or even one that is not allowed
-to exist on the current file system or OS.
-
-For operations involving the filesystem, have a look at the :command:`file`
+This command is for the manipulation of paths. Only syntactic aspects of
+paths are handled, there is no interaction of any kind with any underlying
+file system. The path may represent a non-existing path or even one that
+is not allowed to exist on the current file system or platform.
+For operations that do interact with the filesystem, see the :command:`file`
command.
-The path name has the following syntax:
-
-1. ``root-name`` (optional): identifies the root on a filesystem with multiple
- roots (such as ``"C:"`` or ``"//myserver"``).
-
-2. ``root-directory`` (optional): a directory separator that, if present, marks
- this path as absolute. If it is missing (and the first element other than
- the ``root-name`` is a ``item-name``), then the path is relative.
-
-Zero or more of the following:
-
-3. ``item-name``: sequence of characters that aren't directory separators. This
- name may identify a file, a hard link, a symbolic link, or a directory. Two
- special ``item-names`` are recognized:
-
- * ``dot``: the item name consisting of a single dot character ``.`` is a
- directory name that refers to the current directory.
-
- * ``dot-dot``: the item name consisting of two dot characters ``..`` is a
- directory name that refers to the parent directory.
-
-4. ``directory-separator``: the forward slash character ``/``. If this
- character is repeated, it is treated as a single directory separator:
- ``/usr///////lib`` is the same as ``/usr/lib``.
-
-.. _FILENAME_DEF:
-
-A path has a filename if it does not ends with a ``directory-separator``. The
-filename is the last ``item-name`` of the path.
-
-.. _EXTENSION_DEF:
-
-A :ref:`filename <FILENAME_DEF>` can have an extension. By default, the
-extension is defined as the sub-string beginning at the leftmost period
-(including the period) and until the end of the pathname. When the option
-``LAST_ONLY`` is specified, the extension is the sub-string beginning at the
-rightmost period.
-
-The following exceptions apply:
-
- * If the first character in the :ref:`filename <FILENAME_DEF>` is a period,
- that period is ignored (a filename like ``".profile"`` is not treated as an
- extension).
-
- * If the pathname is either ``.`` or ``..``.
-
.. note::
- ``cmake_path`` command handles paths in the format of the build system, not
- the target system. So this is not generally applicable to the target system
- in cross-compiling environment.
-
-For all commands, ``<path-var>`` placeholder expect a variable name. An error
-will be raised if the variable does not exist, except for `SET`_ and `APPEND`_
-sub-commands. ``<input>`` placeholder expect a string literal.
-``[<input>...]`` placeholder expect zero or more arguments. ``<out-var>``
-placeholder expect a variable name.
-
-.. note::
-
- ``cmake_path`` command does not support list of paths. The ``<path-var>``
- placeholder must store only one path name.
-
-To initialize a path variable, three possibilities can be used:
-
-1. :command:`set` command.
-2. :ref:`cmake_path(SET) <SET>` command. Mainly used to build a
- path variable from a native path.
-3. :ref:`cmake_path(APPEND) <APPEND>` command. Can be used to build a path from
- already available path fragments.
-
- .. code-block:: cmake
-
- # To build the path "${CMAKE_CURRENT_SOURCE_DIR}/data"
-
- set (path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
-
- cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")
-
- cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")
-
-`Modification`_ and `Generation`_ sub-commands store the result in-place or in
-the variable specified by ``OUTPUT_VARIABLE`` option. All other sub-commands
-store the result in the required ``<out-var>`` variable.
-
-Sub-commands supporting ``NORMALIZE`` option will :ref:`normalize <NORMAL_PATH>`
-the path.
+ The ``cmake_path`` command handles paths in the format of the build system
+ (i.e. the host platform), not the target system. When cross-compiling,
+ if the path contains elements that are not representable on the host
+ platform (e.g. a drive letter when the host is not Windows), the results
+ will be unpredictable.
Synopsis
^^^^^^^^
.. parsed-literal::
+ `Conventions`_
+
+ `Path Structure And Terminology`_
+
+ `Normalization`_
+
`Decomposition`_
cmake_path(`GET`_ <path-var> :ref:`ROOT_NAME <GET_ROOT_NAME>` <out-var>)
cmake_path(`GET`_ <path-var> :ref:`ROOT_DIRECTORY <GET_ROOT_DIRECTORY>` <out-var>)
@@ -116,32 +39,6 @@ Synopsis
cmake_path(`GET`_ <path-var> :ref:`RELATIVE_PATH <GET_RELATIVE_PATH>` <out-var>)
cmake_path(`GET`_ <path-var> :ref:`PARENT_PATH <GET_PARENT_PATH>` <out-var>)
- `Modification`_
- cmake_path(`SET`_ <path-var> [NORMALIZE] <input>)
- cmake_path(`APPEND`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
- cmake_path(`APPEND_STRING`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
- cmake_path(`REMOVE_FILENAME`_ <path-var> [OUTPUT_VARIABLE <out-var>])
- cmake_path(`REPLACE_FILENAME`_ <path-var> <input> [OUTPUT_VARIABLE <out-var>])
- cmake_path(`REMOVE_EXTENSION`_ <path-var> [LAST_ONLY]
- [OUTPUT_VARIABLE <out-var>])
- cmake_path(`REPLACE_EXTENSION`_ <path-var> [LAST_ONLY] <input>
- [OUTPUT_VARIABLE <out-var>])
-
- `Generation`_
- cmake_path(`NORMAL_PATH`_ <path-var> [OUTPUT_VARIABLE <out-var>])
- cmake_path(`RELATIVE_PATH`_ <path-var> [BASE_DIRECTORY <input>]
- [OUTPUT_VARIABLE <out-var>])
- cmake_path(`ABSOLUTE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
- [OUTPUT_VARIABLE <out-var>])
-
- `Conversion`_
- cmake_path(`NATIVE_PATH`_ <path-var> [NORMALIZE] <out-var>)
- cmake_path(`CONVERT`_ <input> `TO_CMAKE_PATH_LIST`_ <out-var>)
- cmake_path(`CONVERT`_ <input> `TO_NATIVE_PATH_LIST`_ <out-var>)
-
- `Comparison`_
- cmake_path(`COMPARE`_ <input1> <OP> <input2> <out-var>)
-
`Query`_
cmake_path(`HAS_ROOT_NAME`_ <path-var> <out-var>)
cmake_path(`HAS_ROOT_DIRECTORY`_ <path-var> <out-var>)
@@ -154,664 +51,755 @@ Synopsis
cmake_path(`IS_ABSOLUTE`_ <path-var> <out-var>)
cmake_path(`IS_RELATIVE`_ <path-var> <out-var>)
cmake_path(`IS_PREFIX`_ <path-var> <input> [NORMALIZE] <out-var>)
+ cmake_path(`COMPARE`_ <input1> <OP> <input2> <out-var>)
- `Hashing`_
- cmake_path(`HASH`_ <path-var> [NORMALIZE] <out-var>)
-
-Decomposition
-^^^^^^^^^^^^^
-
-.. _GET:
-.. _GET_ROOT_NAME:
-
-.. code-block:: cmake
-
- cmake_path(GET <path-var> ROOT_NAME <out-var>)
-
-Returns the root name of the path. If the path does not include a root name,
-returns an empty path.
-
-.. note::
-
- Only ``Windows`` system has the concept of ``root-name``, so on all other
- systems, it is always an empty path.
-
-For example:
-
- .. code-block:: cmake
-
- set (path "c:/a")
- cmake_path (GET path ROOT_NAME output)
- message ("Root name is \"${output}\"")
+ `Modification`_
+ cmake_path(:ref:`SET <cmake_path-SET>` <path-var> [NORMALIZE] <input>)
+ cmake_path(`APPEND`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`APPEND_STRING`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REMOVE_FILENAME`_ <path-var> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REPLACE_FILENAME`_ <path-var> <input> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REMOVE_EXTENSION`_ <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REPLACE_EXTENSION`_ <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>])
- Will display::
+ `Generation`_
+ cmake_path(`NORMAL_PATH`_ <path-var> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`RELATIVE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`ABSOLUTE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>])
- Root name is "c:"
+ `Native Conversion`_
+ cmake_path(`NATIVE_PATH`_ <path-var> [NORMALIZE] <out-var>)
+ cmake_path(`CONVERT`_ <input> `TO_CMAKE_PATH_LIST`_ <out-var>)
+ cmake_path(`CONVERT`_ <input> `TO_NATIVE_PATH_LIST`_ <out-var>)
-.. _GET_ROOT_DIRECTORY:
+ `Hashing`_
+ cmake_path(`HASH`_ <path-var> <out-var>)
-.. code-block:: cmake
+Conventions
+^^^^^^^^^^^
- cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
+The following conventions are used in this command's documentation:
-Returns the root directory of the path. If the path does not include a root
-directory, returns an empty path.
+``<path-var>``
+ Always the name of a variable. For commands that expect a ``<path-var>``
+ as input, the variable must exist and it is expected to hold a single path.
-For example:
+``<input>``
+ A string literal which may contain a path, path fragment, or multiple paths
+ with a special separator depending on the command. See the description of
+ each command to see how this is interpreted.
- .. code-block:: cmake
+``<input>...``
+ Zero or more string literal arguments.
- set (path "c:/a")
- cmake_path (GET path ROOT_DIRECTORY output)
- message ("Root directory is \"${output}\"")
+``<out-var>``
+ The name of a variable into which the result of a command will be written.
- Will display::
- Root directory is "/"
+Path Structure And Terminology
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. _GET_ROOT_PATH:
+A path has the following structure (all components are optional, with some
+constraints):
-.. code-block:: cmake
+::
- cmake_path(GET <path-var> ROOT_PATH <out-var>)
+ root-name root-directory-separator (item-name directory-separator)* filename
-Returns the root path of the path. If the path does not include a root path,
-returns an empty path.
+``root-name``
+ Identifies the root on a filesystem with multiple roots (such as ``"C:"``
+ or ``"//myserver"``). It is optional.
-Effectively, returns the following: ``root-name root-directory``.
+``root-directory-separator``
+ A directory separator that, if present, indicates that this path is
+ absolute. If it is missing and the first element other than the
+ ``root-name`` is an ``item-name``, then the path is relative.
-For example:
+``item-name``
+ A sequence of characters that aren't directory separators. This name may
+ identify a file, a hard link, a symbolic link, or a directory. Two special
+ cases are recognized:
- .. code-block:: cmake
+ * The item name consisting of a single dot character ``.`` is a
+ directory name that refers to the current directory.
- set (path "c:/a")
- cmake_path (GET path ROOT_PATH output)
- message ("Root path is \"${output}\"")
+ * The item name consisting of two dot characters ``..`` is a
+ directory name that refers to the parent directory.
- Will display::
+ The ``(...)*`` pattern shown above is to indicate that there can be zero
+ or more item names, with multiple items separated by a
+ ``directory-separator``. The ``()*`` characters are not part of the path.
- Root path is "c:/"
+``directory-separator``
+ The only recognized directory separator is a forward slash character ``/``.
+ If this character is repeated, it is treated as a single directory
+ separator. In other words, ``/usr///////lib`` is the same as ``/usr/lib``.
-.. _GET_FILENAME:
+.. _FILENAME_DEF:
+.. _EXTENSION_DEF:
+.. _STEM_DEF:
-.. code-block:: cmake
+``filename``
+ A path has a ``filename`` if it does not end with a ``directory-separator``.
+ The ``filename`` is effectively the last ``item-name`` of the path, so it
+ can also be a hard link, symbolic link or a directory.
- cmake_path(GET <path-var> FILENAME <out-var>)
+ A ``filename`` can have an *extension*. By default, the extension is
+ defined as the sub-string beginning at the left-most period (including
+ the period) and until the end of the ``filename``. In commands that
+ accept a ``LAST_ONLY`` keyword, ``LAST_ONLY`` changes the interpretation
+ to the sub-string beginning at the right-most period.
-Returns the :ref:`filename <FILENAME_DEF>` component of the path. If the path
-ends with a ``directory-separator``, there is no filename, so returns an empty
-path.
+ The following exceptions apply to the above interpretation:
-For example:
+ * If the first character in the ``filename`` is a period, that period is
+ ignored (i.e. a ``filename`` like ``".profile"`` is treated as having
+ no extension).
- .. code-block:: cmake
+ * If the ``filename`` is either ``.`` or ``..``, it has no extension.
- set (path "/a")
- cmake_path (GET path FILENAME output)
- message ("First filename is \"${output}\"")
+ The *stem* is the part of the ``filename`` before the extension.
- set (path "/a/")
- cmake_path (GET path FILENAME output)
- message ("Second filename is \"${output}\"")
+Some commands refer to a ``root-path``. This is the concatenation of
+``root-name`` and ``root-directory``, either or both of which can be empty.
- Will display::
- First filename is "a"
- Second filename is ""
+Creating A Path Variable
+^^^^^^^^^^^^^^^^^^^^^^^^
-.. _GET_EXTENSION:
+While a path can be created with care using an ordinary :command:`set`
+command, it is recommended to use :ref:`cmake_path(SET) <cmake_path-SET>`
+instead, as it automatically converts the path to the required form where
+required. The :ref:`cmake_path(APPEND) <APPEND>` subcommand may
+be another suitable alternative where a path needs to be constructed by
+joining fragments. The following example compares the three methods for
+constructing the same path:
.. code-block:: cmake
- cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
-
-Returns the :ref:`extension <EXTENSION_DEF>` of the filename component.
-
-If the :ref:`filename <FILENAME_DEF>` component of the path contains a period
-(``.``), and is not one of the special filesystem elements ``dot`` or
-``dot-dot``, then the :ref:`extension <EXTENSION_DEF>` is returned.
+ set(path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
-For example:
+ cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")
- .. code-block:: cmake
+ cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")
- set (path "name.ext1.ext2")
- cmake_path (GET path EXTENSION result)
- message ("Full extension is \"${result}\"")
- cmake_path (GET path EXTENSION LAST_ONLY result)
- message ("Last extension is \"${result}\"")
+`Modification`_ and `Generation`_ sub-commands can either store the result
+in-place, or in a separate variable named after an ``OUTPUT_VARIABLE``
+keyword. All other sub-commands store the result in a mandatory ``<out-var>``
+variable.
- Will display::
+.. _Normalization:
- Full extension is ".ext1.ext2"
- Last extension is ".ext2"
+Normalization
+^^^^^^^^^^^^^
-The following exceptions apply:
+Some sub-commands support *normalizing* a path. The algorithm used to
+normalize a path is as follows:
+
+1. If the path is empty, stop (the normalized form of an empty path is
+ also an empty path).
+2. Replace each ``directory-separator``, which may consist of multiple
+ separators, with a single ``/`` (``/a///b --> /a/b``).
+3. Remove each solitary period (``.``) and any immediately following
+ ``directory-separator`` (``/a/./b/. --> /a/b``).
+4. Remove each ``item-name`` (other than ``..``) that is immediately
+ followed by a ``directory-separator`` and a ``..``, along with any
+ immediately following ``directory-separator`` (``/a/b/../c --> a/c``).
+5. If there is a ``root-directory``, remove any ``..`` and any
+ ``directory-separators`` immediately following them. The parent of the
+ root directory is treated as still the root directory (``/../a --> /a``).
+6. If the last ``item-name`` is ``..``, remove any trailing
+ ``directory-separator`` (``../ --> ..``).
+7. If the path is empty by this stage, add a ``dot`` (normal form of ``./``
+ is ``.``).
- * If the first character in the filename is a period, that period is ignored
- (a filename like ``".profile"`` is not treated as an extension).
- * If the pathname is either ``.`` or ``..``, or if
- :ref:`filename <FILENAME_DEF>` component does not contain the ``.``
- character, then an empty path is returned.
+Decomposition
+^^^^^^^^^^^^^
+.. _GET:
+.. _GET_ROOT_NAME:
+.. _GET_ROOT_DIRECTORY:
+.. _GET_ROOT_PATH:
+.. _GET_FILENAME:
+.. _GET_EXTENSION:
.. _GET_STEM:
-.. code-block:: cmake
+The following forms of the ``GET`` subcommand each retrieve a different
+component or group of components from a path.
+`Path Structure And Terminology`_ defines the meaning of each path component.
+
+::
+ cmake_path(GET <path-var> ROOT_NAME <out-var>)
+ cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
+ cmake_path(GET <path-var> ROOT_PATH <out-var>)
+ cmake_path(GET <path-var> FILENAME <out-var>)
+ cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
-Returns the :ref:`filename <FILENAME_DEF>` component of the path stripped of
-its :ref:`extension <EXTENSION_DEF>`.
+If a requested component is not present in the path, an empty string will be
+stored in ``<out-var>``. For example, only Windows systems have the concept
+of a ``root-name``, so when the host machine is non-Windows, the ``ROOT_NAME``
+subcommand will always return an empty string.
-For Example:
- .. code-block:: cmake
+Root examples
+"""""""""""""
- set (path "name.ext1.ext2")
- cmake_path (GET path STEM result)
- message ("Filename without the extension is \"${result}\"")
- cmake_path (GET path STEM LAST_ONLY result)
- message ("Filename whiteout the last extension is \"${result}\"")
+.. code-block:: cmake
- Will display::
+ set(path "c:/a")
- Filename without the extension is "name"
- Filename without the last extension is "name.ext1"
+ cmake_path(GET path ROOT_NAME rootName)
+ cmake_path(GET path ROOT_DIRECTORY rootDir)
+ cmake_path(GET path ROOT_PATH rootPath)
-The following exceptions apply:
+ message("Root name is \"${rootName}\"")
+ message("Root directory is \"${rootDir}\"")
+ message("Root path is \"${rootPath}\"")
- * If the first character in the filename is a period, that period is ignored
- (a filename like ``".profile"`` is not treated as an extension).
+::
- * If the filename is one of the special filesystem components ``dot`` or
- ``dot-dot``, or if it has no periods, the function returns the entire
- :ref:`filename <FILENAME_DEF>` component.
+ Root name is "c:"
+ Root directory is "/"
+ Root path is "c:/"
-.. _GET_RELATIVE_PATH:
+Filename examples
+"""""""""""""""""
.. code-block:: cmake
- cmake_path(GET <path-var> RELATIVE_PATH <out-var>)
-
-Returns path relative to ``root-path``, that is, a pathname composed of
-every component of ``<path-var>`` after ``root-path``. If ``<path-var>`` is
-an empty path, returns an empty path.
+ set(path "/a/b")
+ cmake_path(GET path FILENAME filename)
+ message("First filename is \"${filename}\"")
-For Example:
+ # Trailing slash means filename is empty
+ set(path "/a/b/")
+ cmake_path(GET path FILENAME filename)
+ message("Second filename is \"${filename}\"")
- .. code-block:: cmake
+::
- set (path "/a/b")
- cmake_path (GET path RELATIVE_PATH result)
- message ("Relative path is \"${result}\"")
+ First filename is "b"
+ Second filename is ""
- set (path "/")
- cmake_path (GET path RELATIVE_PATH result)
- message ("Relative path is \"${result}\"")
+Extension and stem examples
+"""""""""""""""""""""""""""
- Will display::
+.. code-block:: cmake
- Relative path is "a/b"
- Relative path is ""
+ set(path "name.ext1.ext2")
-.. _GET_PARENT_PATH:
+ cmake_path(GET path EXTENSION fullExt)
+ cmake_path(GET path STEM fullStem)
+ message("Full extension is \"${fullExt}\"")
+ message("Full stem is \"${fullStem}\"")
-.. code-block:: cmake
+ # Effect of LAST_ONLY
+ cmake_path(GET path EXTENSION LAST_ONLY lastExt)
+ cmake_path(GET path STEM LAST_ONLY lastStem)
+ message("Last extension is \"${lastExt}\"")
+ message("Last stem is \"${lastStem}\"")
- cmake_path(GET <path-var> PARENT_PATH <out-var>)
+ # Special cases
+ set(dotPath "/a/.")
+ set(dotDotPath "/a/..")
+ set(someMorePath "/a/.some.more")
+ cmake_path(GET dotPath EXTENSION dotExt)
+ cmake_path(GET dotPath STEM dotStem)
+ cmake_path(GET dotDotPath EXTENSION dotDotExt)
+ cmake_path(GET dotDotPath STEM dotDotStem)
+ cmake_path(GET dotMorePath EXTENSION someMoreExt)
+ cmake_path(GET dotMorePath STEM someMoreStem)
+ message("Dot extension is \"${dotExt}\"")
+ message("Dot stem is \"${dotStem}\"")
+ message("Dot-dot extension is \"${dotDotExt}\"")
+ message("Dot-dot stem is \"${dotDotStem}\"")
+ message(".some.more extension is \"${someMoreExt}\"")
+ message(".some.more stem is \"${someMoreStem}\"")
-Returns the path to the parent directory.
+::
-If `HAS_RELATIVE_PATH`_ sub-command returns false, the result is a copy of
-``<path-var>``. Otherwise, the result is ``<path-var>`` with one fewer element.
+ Full extension is ".ext1.ext2"
+ Full stem is "name"
+ Last extension is ".ext2"
+ Last stem is "name.ext1"
+ Dot extension is ""
+ Dot stem is "."
+ Dot-dot extension is ""
+ Dot-dot stem is ".."
+ .some.more extension is ".more"
+ .some.more stem is ".some"
-For Example:
- .. code-block:: cmake
+Relative paths
+""""""""""""""
- set (path "c:/a/b")
- cmake_path (GET path PARENT_PATH result)
- message ("Parent path is \"${result}\"")
+Two other forms of the ``GET`` subcommand interpret a path and return
+another path derived from it.
- set (path "c:/")
- cmake_path (GET path PARENT_PATH result)
- message ("Parent path is \"${result}\"")
+.. _GET_RELATIVE_PATH:
- Will display::
+::
- Parent path is "c:/a"
- Relative path is "c:/"
+ cmake_path(GET <path-var> RELATIVE_PATH <out-var>)
-Modification
-^^^^^^^^^^^^
+Returns the path with any ``root-name`` and ``root-directory-separator``
+removed. This leaves just the part of the path relative to the root
+directory (or put another way, every component of ``<path-var>`` after
+``root-path``). If ``<path-var>`` is an empty path, it returns an empty
+path.
-.. _cmake_path-SET:
-.. _SET:
+For example:
.. code-block:: cmake
- cmake_path(SET <path-var> [NORMALIZE] <input>)
-
-Assign the ``<input>`` path to ``<path-var>``. Moreover, if ``<input>`` is a
-native path, it is converted into cmake-style path with forward-slashes
-(``/``). On Windows, the long filename marker is taken into account.
+ set(path "/a/b")
+ cmake_path(GET path RELATIVE_PATH result)
+ message("Relative path is \"${result}\"")
-When ``NORMALIZE`` option is specified, the path is :ref:`normalized
-<NORMAL_PATH>` before the conversion.
+ set(path "/")
+ cmake_path(GET path RELATIVE_PATH result)
+ message("Relative path is \"${result}\"")
-For Example:
+Output::
- .. code-block:: cmake
+ Relative path is "a/b"
+ Relative path is ""
- set (native_path "c:\\a\\b/..\\c")
- cmake_path (SET path "${native_path}")
- message ("CMake path is \"${path}\"")
+.. _GET_PARENT_PATH:
- cmake_path (SET path NORMALIZE "${native_path}")
- message ("Normalized CMake path is \"${path}\"")
+The other form returns the parent of the path::
- Will display::
+ cmake_path(GET <path-var> PARENT_PATH <out-var>)
- CMake path is "c:/a/b/../c"
- Normalized CMake path is "c:/a/c"
+If the `HAS_RELATIVE_PATH`_ sub-command returns false, the result is a
+copy of ``<path-var>``. Otherwise, the result is ``<path-var>`` with
+one fewer element.
-.. _APPEND:
+For example:
.. code-block:: cmake
- cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+ set(path "c:/a/b")
+ cmake_path(GET path PARENT_PATH result)
+ message("Parent path is \"${result}\"")
-Append all the ``<input>`` arguments to the ``<path-var>`` using ``/`` as
-``directory-separator``.
-
-For each ``<input>`` argument, the following algorithm (pseudo-code) applies:
+ set(path "c:/")
+ cmake_path(GET path PARENT_PATH result)
+ message("Parent path is \"${result}\"")
- .. code-block:: cmake
+Output::
- # <path> is the contents of <path-var>
+ Parent path is "c:/a"
+ Relative path is "c:/"
- IF (<input>.is_absolute() OR
- (<input>.has_root_name() AND
- NOT <input>.root_name() STREQUAL <path>.root_name()))
- replaces <path> with <input>
- RETURN()
- ENDIF()
+Query
+^^^^^
- IF (<input>.has_root_directory())
- remove any root-directory and the entire relative path from <path>
- ELSEIF (<path>.has_filename() OR
- (NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
- appends directory-separator to <path>
- ENDIF()
+Most of the ``GET`` subcommands also have corresponding ``HAS_...``
+subcommands which can be used to discover whether a particular path
+component is present. `Path Structure And Terminology`_ defines the
+meaning of each path component.
- appends <input> omitting any root-name to <path>
+.. _HAS_ROOT_NAME:
+.. _HAS_ROOT_DIRECTORY:
+.. _HAS_ROOT_PATH:
+.. _HAS_FILENAME:
+.. _HAS_EXTENSION:
+.. _HAS_STEM:
-.. _APPEND_STRING:
+::
-.. code-block:: cmake
+ cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
+ cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
+ cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
+ cmake_path(HAS_FILENAME <path-var> <out-var>)
+ cmake_path(HAS_EXTENSION <path-var> <out-var>)
+ cmake_path(HAS_STEM <path-var> <out-var>)
- cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+Each of the above follows the predictable pattern of setting ``<out-var>``
+to true if the path has the associated component, or false otherwise.
+In the case of ``HAS_ROOT_PATH``, a true result will only be returned if
+at least one of ``root-name`` or ``root-directory`` is non-empty.
-Append all the ``<input>`` arguments to the ``<path-var>`` without
-``directory-separator``.
+.. _HAS_RELATIVE_PATH:
-.. _REMOVE_FILENAME:
+::
-.. code-block:: cmake
+ cmake_path(HAS_RELATIVE_PATH <path-var> <out-var>)
- cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
+A relative path in this context means everything after the ``root-path``,
+if present. This command sets ``<out-var>`` to true if there is at least
+one ``item-name`` or ``filename`` in the path.
-Removes the :ref:`filename <FILENAME_DEF>` component (as returned by
-:ref:`GET ... FILENAME <GET_FILENAME>`) from ``<path-var>``.
+.. _HAS_PARENT_PATH:
-After this function returns, if change is done in-place, `HAS_FILENAME`_
-returns false for ``<path-var>``.
+::
-For Example:
+ cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
- .. code-block:: cmake
+This command sets ``<out-var>`` to true if ``<path-var>`` has parent path.
+Note that the root directory is also considered to have a parent, which
+will be itself. The result is true except if the path consists of just a
+:ref:`filename <FILENAME_DEF>`.
- set (path "/a/b")
- cmake_path (REMOVE_FILENAME path)
- message ("First path is \"${path}\"")
+.. _IS_ABSOLUTE:
- cmake_path (REMOVE_FILENAME path)
- message ("Second path is \"${result}\"")
+::
- Will display::
+ cmake_path(IS_ABSOLUTE <path-var> <out-var>)
- First path is "/a/"
- Second path is "/a/"
+Sets ``<out-var>`` to true if ``<path-var>`` is absolute. An absolute path
+is a path that unambiguously identifies the location of a file without
+reference to an additional starting location. On Windows, this means the
+path must have both a ``root-name`` and a ``root-directory-separator`` to be
+considered absolute. On other platforms, just a ``root-directory-separator``
+is sufficient. Note that this means on Windows, ``IS_ABSOLUTE`` can be
+false while ``HAS_ROOT_DIRECTORY`` can be true.
-.. _REPLACE_FILENAME:
+.. _IS_RELATIVE:
-.. code-block:: cmake
+::
- cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(IS_RELATIVE <path-var> <out-var>)
-Replaces the :ref:`filename <FILENAME_DEF>` component from ``<path-var>`` with
-``<input>``.
+This will store the opposite of ``IS_ABSOLUTE`` in ``<out-var>``.
-If ``<path-var>`` has no filename component (`HAS_FILENAME`_ returns false),
-the path is unchanged.
+.. _IS_PREFIX:
-Equivalent to the following:
+::
- .. code-block:: cmake
+ cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
- cmake_path(HAS_FILENAME path has_filename)
- if (has_filename)
- cmake_path(REMOVE_FILENAME path)
- cmake_path(APPEND path "replacement");
- endif()
+Checks if ``<path-var>`` is the prefix of ``<input>``.
-.. _REMOVE_EXTENSION:
+When the ``NORMALIZE`` option is specified, ``<path-var>`` and ``<input>``
+are :ref:`normalized <Normalization>` before the check.
.. code-block:: cmake
- cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
- [OUTPUT_VARIABLE <out-var>])
+ set(path "/a/b/c/d")
+ cmake_path(IS_PREFIX path "/a/b" result) # result = true
+ cmake_path(IS_PREFIX path "/x/y/z" result) # result = false
-Removes the :ref:`extension <EXTENSION_DEF>`, if any, from ``<path-var>``.
+ set(path "/a/b")
+ cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE result) # result = true
-.. _REPLACE_EXTENSION:
+.. _COMPARE:
-.. code-block:: cmake
+::
- cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
- [OUTPUT_VARIABLE <out-var>])
+ cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
+ cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
-Replaces the :ref:`extension <EXTENSION_DEF>` with ``<input>``.
+Compares the lexical representations of two paths provided as string literals.
+No normalization is performed on either path. Equality is determined
+according to the following pseudo-code logic:
- 1. If ``<path-var>`` has an :ref:`extension <EXTENSION_DEF>`
- (`HAS_EXTENSION`_ is true), it is removed.
- 2. A ``dot`` character is appended to ``<path-var>``, if ``<input>`` is not
- empty or does not begin with a ``dot`` character.
- 3. ``<input>`` is appended as if `APPEND_STRING`_ was used.
+::
+ if(NOT <input1>.root_name() STREQUAL <input2>.root_name())
+ return FALSE
-Equivalent to the following:
+ if(<input1>.has_root_directory() XOR <input2>.has_root_directory())
+ return FALSE
- .. code-block:: cmake
+ Return FALSE if a relative portion of <input1> is not lexicographically
+ equal to the relative portion of <input2>. This comparison is performed path
+ component-wise. If all of the components compare equal, then return TRUE.
- cmake_path(REMOVE_EXTENSION path)
- if (NOT "input" MATCHES "^\\.")
- cmake_path(APPEND_STRING path ".")
- endif()
- cmake_path(APPEND_STRING path "input");
+.. note::
+ Unlike most other ``cmake_path()`` subcommands, the ``COMPARE`` subcommand
+ takes literal strings as input, not the names of variables.
-Generation
-^^^^^^^^^^
-.. _NORMAL_PATH:
+Modification
+^^^^^^^^^^^^
-.. code-block:: cmake
+.. _cmake_path-SET:
- cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
+::
-Normalize ``<path-var>``.
+ cmake_path(SET <path-var> [NORMALIZE] <input>)
-A path can be normalized by following this algorithm:
+Assign the ``<input>`` path to ``<path-var>``. If ``<input>`` is a native
+path, it is converted into a cmake-style path with forward-slashes
+(``/``). On Windows, the long filename marker is taken into account.
- 1. If the path is empty, stop (normal form of an empty path is an empty
- path).
- 2. Replace each ``directory-separator`` (which may consist of multiple
- separators) with a single ``/``.
- 3. Replace each ``directory-separator`` character in the ``root-name`` with
- ``/``.
- 4. Remove each ``dot`` and any immediately following ``directory-separator``.
- 5. Remove each non-dot-dot filename immediately followed by a
- ``directory-separator`` and a ``dot-dot``, along with any immediately
- following ``directory-separator``.
- 6. If there is ``root-directory``, remove all ``dot-dots`` and any
- ``directory-separators`` immediately following them.
- 7. If the last filename is ``dot-dot``, remove any trailing
- ``directory-separator``.
- 8. If the path is empty, add a ``dot`` (normal form of ``./`` is ``.``).
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
-.. _cmake_path-RELATIVE_PATH:
-.. _RELATIVE_PATH:
+For example:
.. code-block:: cmake
- cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
- [OUTPUT_VARIABLE <out-var>])
-
-Returns ``<path-var>`` made relative to ``BASE_DIRECTORY`` argument. If
-``BASE_DIRECTORY`` is not specified, the default base directory will be
-:variable:`CMAKE_CURRENT_SOURCE_DIR`.
-
-For reference, the algorithm used to compute the relative path is described
-`here <https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal>`_.
-
-.. _ABSOLUTE_PATH:
+ set(native_path "c:\\a\\b/..\\c")
+ cmake_path(SET path "${native_path}")
+ message("CMake path is \"${path}\"")
-.. code-block:: cmake
+ cmake_path(SET path NORMALIZE "${native_path}")
+ message("Normalized CMake path is \"${path}\"")
- cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
- [OUTPUT_VARIABLE <out-var>])
+Output::
-If ``<path-var>`` is a relative path (`IS_RELATIVE`_ is true), it is evaluated
-relative to the given base directory specified by ``BASE_DIRECTORY`` option.
+ CMake path is "c:/a/b/../c"
+ Normalized CMake path is "c:/a/c"
-If ``BASE_DIRECTORY`` is not specifired, the default base directory will be
-:variable:`CMAKE_CURRENT_SOURCE_DIR`.
+.. _APPEND:
-When ``NORMALIZE`` option is specified, the path is :ref:`normalized
-<NORMAL_PATH>` after the path computation.
+::
-Because ``cmake_path`` does not access to the filesystem, symbolic links are
-not resolved. To compute a real path, use :command:`file(REAL_PATH)`
-command.
+ cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
-Conversion
-^^^^^^^^^^
+Append all the ``<input>`` arguments to the ``<path-var>`` using ``/`` as
+the ``directory-separator``. Depending on the ``<input>``, the previous
+contents of ``<path-var>`` may be discarded. For each ``<input>`` argument,
+the following algorithm (pseudo-code) applies:
-.. _cmake_path-NATIVE_PATH:
-.. _NATIVE_PATH:
+::
-.. code-block:: cmake
+ # <path> is the contents of <path-var>
- cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
+ if(<input>.is_absolute() OR
+ (<input>.has_root_name() AND
+ NOT <input>.root_name() STREQUAL <path>.root_name()))
+ replace <path> with <input>
+ return()
+ endif()
-Converts a cmake-style ``<path-var>`` into a native
-path with platform-specific slashes (``\`` on Windows and ``/`` elsewhere).
+ if(<input>.has_root_directory())
+ remove any root-directory and the entire relative path from <path>
+ elseif(<path>.has_filename() OR
+ (NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
+ append directory-separator to <path>
+ endif()
-When ``NORMALIZE`` option is specified, the path is :ref:`normalized
-<NORMAL_PATH>` before the conversion.
+ append <input> omitting any root-name to <path>
-.. _CONVERT:
-.. _cmake_path-TO_CMAKE_PATH_LIST:
-.. _TO_CMAKE_PATH_LIST:
+.. _APPEND_STRING:
-.. code-block:: cmake
+::
- cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
+ cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
-Converts a native ``<input>`` path into cmake-style path with forward-slashes
-(``/``). On Windows, the long filename marker is taken into account. The input
-can be a single path or a system search path like ``$ENV{PATH}``. A search
-path will be converted to a cmake-style list separated by ``;`` characters. The
-result of the conversion is stored in the ``<out-var>`` variable.
+Append all the ``<input>`` arguments to the ``<path-var>`` without adding any
+``directory-separator``.
-When ``NORMALIZE`` option is specified, the path is :ref:`normalized
-<NORMAL_PATH>` before the conversion.
+.. _REMOVE_FILENAME:
-.. _cmake_path-TO_NATIVE_PATH_LIST:
-.. _TO_NATIVE_PATH_LIST:
+::
-.. code-block:: cmake
+ cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
- cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
+Removes the :ref:`filename <FILENAME_DEF>` component (as returned by
+:ref:`GET ... FILENAME <GET_FILENAME>`) from ``<path-var>``. After removal,
+any trailing ``directory-separator`` is left alone, if present.
-Converts a cmake-style ``<input>`` path into a native path with
-platform-specific slashes (``\`` on Windows and ``/`` elsewhere). The input can
-be a single path or a cmake-style list. A list will be converted into a native
-search path. The result of the conversion is stored in the ``<out-var>``
-variable.
+If ``OUTPUT_VARIABLE`` is not given, then after this function returns,
+`HAS_FILENAME`_ returns false for ``<path-var>``.
-When ``NORMALIZE`` option is specified, the path is :ref:`normalized
-<NORMAL_PATH>` before the conversion.
+For example:
-For Example:
+.. code-block:: cmake
- .. code-block:: cmake
+ set(path "/a/b")
+ cmake_path(REMOVE_FILENAME path)
+ message("First path is \"${path}\"")
- set (paths "/a/b/c" "/x/y/z")
- cmake_path (CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
- message ("Native path list is \"${native_paths}\"")
+ # filename is now already empty, the following removes nothing
+ cmake_path(REMOVE_FILENAME path)
+ message("Second path is \"${result}\"")
- Will display, on Windows::
+Output::
- Native path list is "\a\b\c;\x\y\z"
+ First path is "/a/"
+ Second path is "/a/"
- And on the all other systems::
+.. _REPLACE_FILENAME:
- Native path list is "/a/b/c:/x/y/z"
+::
-Comparison
-^^^^^^^^^^
+ cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
-.. _COMPARE:
+Replaces the :ref:`filename <FILENAME_DEF>` component from ``<path-var>``
+with ``<input>``. If ``<path-var>`` has no filename component (i.e.
+`HAS_FILENAME`_ returns false), the path is unchanged. The operation is
+equivalent to the following:
.. code-block:: cmake
- cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
- cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
+ cmake_path(HAS_FILENAME path has_filename)
+ if(has_filename)
+ cmake_path(REMOVE_FILENAME path)
+ cmake_path(APPEND path input);
+ endif()
-Compares the lexical representations of the path and another path.
+.. _REMOVE_EXTENSION:
-For testing equality, the following algorithm (pseudo-code) apply:
+::
- .. code-block:: cmake
+ cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
+ [OUTPUT_VARIABLE <out-var>])
- IF (NOT <input1>.root_name() STREQUAL <input2>.root_name())
- returns FALSE
- ELSEIF (<input1>.has_root_directory() XOR <input2>.has_root_directory())
- returns FALSE
- ENDIF()
+Removes the :ref:`extension <EXTENSION_DEF>`, if any, from ``<path-var>``.
- returns TRUE or FALSE if the relative portion of <input1> is
- lexicographically equal or not to the relative portion of <input2>.
- Comparison is performed path component-wise
+.. _REPLACE_EXTENSION:
-Query
-^^^^^
+::
-.. _HAS_ROOT_NAME:
+ cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
+ [OUTPUT_VARIABLE <out-var>])
+
+Replaces the :ref:`extension <EXTENSION_DEF>` with ``<input>``. Its effect
+is equivalent to the following:
.. code-block:: cmake
- cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
+ cmake_path(REMOVE_EXTENSION path)
+ if(NOT "input" MATCHES "^\\.")
+ cmake_path(APPEND_STRING path ".")
+ endif()
+ cmake_path(APPEND_STRING path "input")
-Checks if ``<path-var>`` has ``root-name``.
-.. _HAS_ROOT_DIRECTORY:
+Generation
+^^^^^^^^^^
-.. code-block:: cmake
+.. _NORMAL_PATH:
- cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
+::
-Checks if ``<path-var>`` has ``root-directory``.
+ cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
-.. _HAS_ROOT_PATH:
+Normalize ``<path-var>`` according the steps described in :ref:`Normalization`.
-.. code-block:: cmake
+.. _cmake_path-RELATIVE_PATH:
+.. _RELATIVE_PATH:
- cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
+::
-Checks if ``<path-var>`` has root path.
+ cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
+ [OUTPUT_VARIABLE <out-var>])
-Effectively, checks if ``<path-var>`` has ``root-name`` and ``root-directory``.
+Modifies ``<path-var>`` to make it relative to the ``BASE_DIRECTORY`` argument.
+If ``BASE_DIRECTORY`` is not specified, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
-.. _HAS_FILENAME:
+For reference, the algorithm used to compute the relative path is the same
+as that used by C++
+`std::filesystem::path::lexically_relative
+<https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal>`_.
-.. code-block:: cmake
+.. _ABSOLUTE_PATH:
- cmake_path(HAS_FILENAME <path-var> <out-var>)
+::
-Checks if ``<path-var>`` has a :ref:`filename <FILENAME_DEF>`.
+ cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
+ [OUTPUT_VARIABLE <out-var>])
-.. _HAS_EXTENSION:
+If ``<path-var>`` is a relative path (`IS_RELATIVE`_ is true), it is evaluated
+relative to the given base directory specified by ``BASE_DIRECTORY`` option.
+If ``BASE_DIRECTORY`` is not specified, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
-.. code-block:: cmake
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` after the path computation.
- cmake_path(HAS_EXTENSION <path-var> <out-var>)
+Because ``cmake_path()`` does not access the filesystem, symbolic links are
+not resolved. To compute a real path with symbolic links resolved, use the
+:command:`file(REAL_PATH)` command instead.
-Checks if ``<path-var>`` has an :ref:`extension <EXTENSION_DEF>`. If the first
-character in the filename is a period, it is not treated as an extension (for
-example ".profile").
+Native Conversion
+^^^^^^^^^^^^^^^^^
-.. _HAS_STEM:
+For commands in this section, *native* refers to the host platform, not the
+target platform when cross-compiling.
-.. code-block:: cmake
+.. _cmake_path-NATIVE_PATH:
+.. _NATIVE_PATH:
- cmake_path(HAS_STEM <path-var> <out-var>)
+::
-Checks if ``<path-var>`` has stem (:ref:`GET ... STEM <GET_STEM>` returns a non
-empty path).
+ cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
-.. _HAS_RELATIVE_PATH:
+Converts a cmake-style ``<path-var>`` into a native path with
+platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
-.. code-block:: cmake
-
- cmake_path(HAS_RELATIVE_PATH <path-var> <out-var>)
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
-Checks if ``<path-var>`` has relative path (`GET_RELATIVE_PATH`_ returns a
-non-empty path).
+.. _CONVERT:
+.. _cmake_path-TO_CMAKE_PATH_LIST:
+.. _TO_CMAKE_PATH_LIST:
-.. _HAS_PARENT_PATH:
+::
-.. code-block:: cmake
+ cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
- cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
+Converts a native ``<input>`` path into a cmake-style path with forward
+slashes (``/``). On Windows hosts, the long filename marker is taken into
+account. The input can be a single path or a system search path like
+``$ENV{PATH}``. A search path will be converted to a cmake-style list
+separated by ``;`` characters (on non-Windows platforms, this essentially
+means ``:`` separators are replaced with ``;``). The result of the
+conversion is stored in the ``<out-var>`` variable.
-Checks if ``<path-var>`` has parent path. The result is true except if the path
-is only composed of a :ref:`filename <FILENAME_DEF>`.
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
-.. _IS_ABSOLUTE:
+.. note::
+ Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
+ takes a literal string as input, not the name of a variable.
-.. code-block:: cmake
+.. _cmake_path-TO_NATIVE_PATH_LIST:
+.. _TO_NATIVE_PATH_LIST:
- cmake_path(IS_ABSOLUTE <path-var> <out-var>)
+::
-Checks if ``<path-var>`` is absolute.
+ cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
-An absolute path is a path that unambiguously identifies the location of a file
-without reference to an additional starting location.
+Converts a cmake-style ``<input>`` path into a native path with
+platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
+The input can be a single path or a cmake-style list. A list will be
+converted into a native search path (``;``-separated on Windows,
+``:``-separated on other platforms). The result of the conversion is
+stored in the ``<out-var>`` variable.
-.. _IS_RELATIVE:
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
-.. code-block:: cmake
+.. note::
+ Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
+ takes a literal string as input, not the name of a variable.
- cmake_path(IS_RELATIVE <path-var> <out-var>)
+For example:
-Checks if path is relative (i.e. not :ref:`absolute <IS_ABSOLUTE>`).
+.. code-block:: cmake
-.. _IS_PREFIX:
+ set(paths "/a/b/c" "/x/y/z")
+ cmake_path(CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
+ message("Native path list is \"${native_paths}\"")
-.. code-block:: cmake
+Output on Windows::
- cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
+ Native path list is "\a\b\c;\x\y\z"
-Checks if ``<path-var>`` is the prefix of ``<input>``.
+Output on all other platforms::
-When ``NORMALIZE`` option is specified, the paths are :ref:`normalized
-<NORMAL_PATH>` before the check.
+ Native path list is "/a/b/c:/x/y/z"
Hashing
^^^^^^^
.. _HASH:
-.. code-block:: cmake
-
- cmake_path(HASH <path-var> [NORMALIZE] <out-var>)
+::
-Compute hash value of ``<path-var>`` such that if for two paths (``p1`` and
-``p2``) are equal (:ref:`COMPARE ... EQUAL <COMPARE>`) then hash value of p1 is
-equal to hash value of p2.
+ cmake_path(HASH <path-var> <out-var>)
-When ``NORMALIZE`` option is specified, the paths are :ref:`normalized
-<NORMAL_PATH>` before the check.
+Compute a hash value of ``<path-var>`` such that for two paths ``p1`` and
+``p2`` that compare equal (:ref:`COMPARE ... EQUAL <COMPARE>`), the hash
+value of ``p1`` is equal to the hash value of ``p2``. The path is always
+:ref:`normalized <Normalization>` before the hash is computed.
diff --git a/Help/command/if.rst b/Help/command/if.rst
index 72d328d..c51d2bc 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -47,7 +47,8 @@ as ``EXISTS``, ``COMMAND``, and ``DEFINED``. Then binary tests such as
and ``MATCHES``. Then the boolean operators in the order ``NOT``, ``AND``,
and finally ``OR``.
-Possible conditions are:
+Basic Expressions
+"""""""""""""""""
``if(<constant>)``
True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``,
@@ -62,6 +63,9 @@ Possible conditions are:
True if given a variable that is defined to a value that is not a false
constant. False otherwise. (Note macro arguments are not variables.)
+Logic Operators
+"""""""""""""""
+
``if(NOT <condition>)``
True if the condition is not true.
@@ -71,6 +75,15 @@ Possible conditions are:
``if(<cond1> OR <cond2>)``
True if either condition would be considered true individually.
+``if((condition) AND (condition OR (condition)))``
+ The conditions inside the parenthesis are evaluated first and then
+ the remaining condition is evaluated as in the other examples.
+ Where there are nested parenthesis the innermost are evaluated as part
+ of evaluating the condition that contains them.
+
+Existence Checks
+""""""""""""""""
+
``if(COMMAND command-name)``
True if the given name is a command, macro or function that can be
invoked.
@@ -89,6 +102,21 @@ Possible conditions are:
True if the given name is an existing test name created by the
:command:`add_test` command.
+``if(DEFINED <name>|CACHE{<name>}|ENV{<name>})``
+ True if a variable, cache variable or environment variable
+ with given ``<name>`` is defined. The value of the variable
+ does not matter. Note that macro arguments are not variables.
+
+ .. versionadded:: 3.14
+ Added support for ``CACHE{<name>}`` variables.
+
+``if(<variable|string> IN_LIST <variable>)``
+ .. versionadded:: 3.3
+ True if the given element is contained in the named list variable.
+
+File Operations
+"""""""""""""""
+
``if(EXISTS path-to-file-or-directory)``
True if the named file or directory exists. Behavior is well-defined
only for full paths. Resolves symbolic links, i.e. if the named file or
@@ -114,6 +142,9 @@ Possible conditions are:
``if(IS_ABSOLUTE path)``
True if the given path is an absolute path.
+Comparisons
+"""""""""""
+
``if(<variable|string> MATCHES regex)``
True if the given string or variable's value matches the given regular
condition. See :ref:`Regex Specification` for regex format.
@@ -165,6 +196,9 @@ Possible conditions are:
True if the given string or variable's value is lexicographically greater
than or equal to the string or variable on the right.
+Version Comparisons
+"""""""""""""""""""
+
``if(<variable|string> VERSION_LESS <variable|string>)``
Component-wise integer version number comparison (version format is
``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero).
@@ -197,24 +231,6 @@ Possible conditions are:
Any non-integer version component or non-integer trailing part of a version
component effectively truncates the string at that point.
-``if(<variable|string> IN_LIST <variable>)``
- .. versionadded:: 3.3
- True if the given element is contained in the named list variable.
-
-``if(DEFINED <name>|CACHE{<name>}|ENV{<name>})``
- True if a variable, cache variable or environment variable
- with given ``<name>`` is defined. The value of the variable
- does not matter. Note that macro arguments are not variables.
-
- .. versionadded:: 3.14
- Added support for ``CACHE{<name>}`` variables.
-
-``if((condition) AND (condition OR (condition)))``
- The conditions inside the parenthesis are evaluated first and then
- the remaining condition is evaluated as in the previous examples.
- Where there are nested parenthesis the innermost are evaluated as part
- of evaluating the condition that contains them.
-
Variable Expansion
^^^^^^^^^^^^^^^^^^
diff --git a/Help/command/install.rst b/Help/command/install.rst
index bd8da39..35207f4 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -473,6 +473,11 @@ this advice while installing headers to a project-specific subdirectory:
use "generator expressions" with the syntax ``$<...>``. See the
:manual:`cmake-generator-expressions(7)` manual for available expressions.
+.. versionadded:: 3.20
+ An install rename given as a ``RENAME`` argument may
+ use "generator expressions" with the syntax ``$<...>``. See the
+ :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
Installing Directories
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
index d1df42b..8901192 100644
--- a/Help/generator/Ninja Multi-Config.rst
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -130,3 +130,34 @@ output config using the ``Release`` command config. The ``Release`` build of
the ``generator`` target is called with ``Debug.txt Debug Release`` as
arguments. The command depends on the ``Release`` builds of ``tgt1`` and
``tgt4``, and the ``Debug`` builds of ``tgt2`` and ``tgt3``.
+
+``PRE_BUILD``, ``PRE_LINK``, and ``POST_BUILD`` custom commands for targets
+only get run in their "native" configuration (the ``Release`` configuration in
+the ``build-Release.ninja`` file) unless they have no ``BYPRODUCTS`` or their
+``BYPRODUCTS`` are unique per config. Consider the following example:
+
+.. code-block:: cmake
+
+ add_executable(exe main.c)
+ add_custom_command(
+ TARGET exe
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running no-byproduct command"
+ )
+ add_custom_command(
+ TARGET exe
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running separate-byproduct command for $<CONFIG>"
+ BYPRODUCTS $<CONFIG>.txt
+ )
+ add_custom_command(
+ TARGET exe
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running common-byproduct command for $<CONFIG>"
+ BYPRODUCTS exe.txt
+ )
+
+In this example, if you build ``exe:Debug`` in ``build-Release.ninja``, the
+first and second custom commands get run, since their byproducts are unique
+per-config, but the last custom command does not. However, if you build
+``exe:Release`` in ``build-Release.ninja``, all three custom commands get run.
diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst
index 00fa39a..94753d5 100644
--- a/Help/guide/tutorial/index.rst
+++ b/Help/guide/tutorial/index.rst
@@ -414,27 +414,23 @@ tutorial assume that they are not common.
If the platform has ``log`` and ``exp`` then we will use them to compute the
square root in the ``mysqrt`` function. We first test for the availability of
-these functions using the :module:`CheckSymbolExists` module in the top-level
-``CMakeLists.txt``. On some platforms, we will need to link to the m library.
-If ``log`` and ``exp`` are not initially found, require the m library and try
-again.
-
-We're going to use the new defines in ``TutorialConfig.h.in``, so be sure to
-set them before that file is configured.
+these functions using the :module:`CheckSymbolExists` module in
+``MathFunctions/CMakeLists.txt``. On some platforms, we will need to link to
+the m library. If ``log`` and ``exp`` are not initially found, require the m
+library and try again.
.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
:language: cmake
:start-after: # does this system provide the log and exp functions?
:end-before: # add compile definitions
-Now let's add these defines to ``TutorialConfig.h.in`` so that we can use them
-from ``mysqrt.cxx``:
-
-.. code-block:: console
+If available, use :command:`target_compile_definitions` to specify
+``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions.
- // does the platform provide exp and log functions?
- #cmakedefine HAVE_LOG
- #cmakedefine HAVE_EXP
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # add compile definitions
+ :end-before: # install rules
If ``log`` and ``exp`` are available on the system, then we will use them to
compute the square root in the ``mysqrt`` function. Add the following code to
@@ -456,51 +452,8 @@ Run the :manual:`cmake <cmake(1)>` executable or the
:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
with your chosen build tool and run the Tutorial executable.
-You will notice that we're not using ``log`` and ``exp``, even if we think they
-should be available. We should realize quickly that we have forgotten to
-include ``TutorialConfig.h`` in ``mysqrt.cxx``.
-
-We will also need to update ``MathFunctions/CMakeLists.txt`` so ``mysqrt.cxx``
-knows where this file is located:
-
-.. code-block:: cmake
-
- target_include_directories(MathFunctions
- INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
- PRIVATE ${CMAKE_BINARY_DIR}
- )
-
-After making this update, go ahead and build the project again and run the
-built Tutorial executable. If ``log`` and ``exp`` are still not being used,
-open the generated ``TutorialConfig.h`` file from the build directory. Maybe
-they aren't available on the current system?
-
Which function gives better results now, sqrt or mysqrt?
-Specify Compile Definition
---------------------------
-
-Is there a better place for us to save the ``HAVE_LOG`` and ``HAVE_EXP`` values
-other than in ``TutorialConfig.h``? Let's try to use
-:command:`target_compile_definitions`.
-
-First, remove the defines from ``TutorialConfig.h.in``. We no longer need to
-include ``TutorialConfig.h`` from ``mysqrt.cxx`` or the extra include in
-``MathFunctions/CMakeLists.txt``.
-
-Next, we can move the check for ``HAVE_LOG`` and ``HAVE_EXP`` to
-``MathFunctions/CMakeLists.txt`` and then specify those values as ``PRIVATE``
-compile definitions.
-
-.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
- :language: cmake
- :start-after: # does this system provide the log and exp functions?
- :end-before: # install rules
-
-After making these updates, go ahead and build the project again. Run the
-built Tutorial executable and verify that the results are same as earlier in
-this step.
-
Adding a Custom Command and Generated File (Step 6)
===================================================
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst
index 85ed935..af9a8ab 100644
--- a/Help/manual/cmake-developer.7.rst
+++ b/Help/manual/cmake-developer.7.rst
@@ -23,15 +23,14 @@ in turn link to developer guides for CMake itself.
Find Modules
============
-A "find module" is a ``Find<PackageName>.cmake`` file to be loaded
-by the :command:`find_package` command when invoked for ``<PackageName>``.
+A "find module" is a ``Find<PackageName>.cmake`` file to be loaded by the
+:command:`find_package` command when invoked for ``<PackageName>``.
-The primary task of a find module is to determine whether a package
-exists on the system, set the ``<PackageName>_FOUND`` variable to reflect
-this and provide any variables, macros and imported targets required to
-use the package. A find module is useful in cases where an upstream
-library does not provide a
-:ref:`config file package <Config File Packages>`.
+The primary task of a find module is to determine whether a package is
+available, set the ``<PackageName>_FOUND`` variable to reflect this and
+provide any variables, macros and imported targets required to use the
+package. A find module is useful in cases where an upstream library does
+not provide a :ref:`config file package <Config File Packages>`.
The traditional approach is to use variables for everything, including
libraries and executables: see the `Standard Variable Names`_ section
@@ -91,55 +90,92 @@ Standard Variable Names
For a ``FindXxx.cmake`` module that takes the approach of setting
variables (either instead of or in addition to creating imported
targets), the following variable names should be used to keep things
-consistent between find modules. Note that all variables start with
-``Xxx_`` to make sure they do not interfere with other find modules; the
-same consideration applies to macros, functions and imported targets.
+consistent between Find modules. Note that all variables start with
+``Xxx_``, which (unless otherwise noted) must match exactly the name
+of the ``FindXxx.cmake`` file, including upper/lowercase.
+This prefix on the variable names ensures that they do not conflict with
+variables of other Find modules. The same pattern should also be followed
+for any macros, functions and imported targets defined by the Find module.
``Xxx_INCLUDE_DIRS``
The final set of include directories listed in one variable for use by
- client code. This should not be a cache entry.
+ client code. This should not be a cache entry (note that this also means
+ this variable should not be used as the result variable of a
+ :command:`find_path` command - see ``Xxx_INCLUDE_DIR`` below for that).
``Xxx_LIBRARIES``
- The libraries to link against to use Xxx. These should include full
- paths. This should not be a cache entry.
+ The libraries to use with the module. These may be CMake targets, full
+ absolute paths to a library binary or the name of a library that the
+ linker must find in its search path. This should not be a cache entry
+ (note that this also means this variable should not be used as the
+ result variable of a :command:`find_library` command - see
+ ``Xxx_LIBRARY`` below for that).
``Xxx_DEFINITIONS``
- Definitions to use when compiling code that uses Xxx. This really
- shouldn't include options such as ``-DHAS_JPEG`` that a client
+ The compile definitions to use when compiling code that uses the module.
+ This really shouldn't include options such as ``-DHAS_JPEG`` that a client
source-code file uses to decide whether to ``#include <jpeg.h>``
``Xxx_EXECUTABLE``
- Where to find the Xxx tool.
-
-``Xxx_Yyy_EXECUTABLE``
- Where to find the Yyy tool that comes with Xxx.
+ The full absolute path to an executable. In this case, ``Xxx`` might not
+ be the name of the module, it might be the name of the tool (usually
+ converted to all uppercase), assuming that tool has such a well-known name
+ that it is unlikely that another tool with the same name exists. It would
+ be appropriate to use this as the result variable of a
+ :command:`find_program` command.
+
+``Xxx_YYY_EXECUTABLE``
+ Similar to ``Xxx_EXECUTABLE`` except here the ``Xxx`` is always the module
+ name and ``YYY`` is the tool name (again, usually fully uppercase).
+ Prefer this form if the tool name is not very widely known or has the
+ potential to clash with another tool. For greater consistency, also
+ prefer this form if the module provides more than one executable.
``Xxx_LIBRARY_DIRS``
Optionally, the final set of library directories listed in one
- variable for use by client code. This should not be a cache entry.
+ variable for use by client code. This should not be a cache entry.
``Xxx_ROOT_DIR``
- Where to find the base directory of Xxx.
-
-``Xxx_VERSION_Yy``
- Expect Version Yy if true. Make sure at most one of these is ever true.
-
-``Xxx_WRAP_Yy``
- If False, do not try to use the relevant CMake wrapping command.
+ Where to find the base directory of the module.
+
+``Xxx_VERSION_VV``
+ Variables of this form specify whether the ``Xxx`` module being provided
+ is version ``VV`` of the module. There should not be more than one
+ variable of this form set to true for a given module. For example, a
+ module ``Barry`` might have evolved over many years and gone through a
+ number of different major versions. Version 3 of the ``Barry`` module
+ might set the variable ``Barry_VERSION_3`` to true, whereas an older
+ version of the module might set ``Barry_VERSION_2`` to true instead.
+ It would be an error for both ``Barry_VERSION_3`` and ``Barry_VERSION_2``
+ to both be set to true.
+
+``Xxx_WRAP_YY``
+ When a variable of this form is set to false, it indicates that the
+ relevant wrapping command should not be used. The wrapping command
+ depends on the module, it may be implied by the module name or it might
+ be specified by the ``YY`` part of the variable.
``Xxx_Yy_FOUND``
- If False, optional Yy part of Xxx system is not available.
+ For variables of this form, ``Yy`` is the name of a component for the
+ module. It should match exactly one of the valid component names that
+ may be passed to the :command:`find_package` command for the module.
+ If a variable of this form is set to false, it means that the ``Yy``
+ component of module ``Xxx`` was not found or is not available.
+ Variables of this form would typically be used for optional components
+ so that the caller can check whether an optional component is available.
``Xxx_FOUND``
- Set to false, or undefined, if we haven't found, or don't want to use
- Xxx.
+ When the :command:`find_package` command returns to the caller, this
+ variable will be set to true if the module was deemed to have been found
+ successfully.
``Xxx_NOT_FOUND_MESSAGE``
Should be set by config-files in the case that it has set
``Xxx_FOUND`` to FALSE. The contained message will be printed by the
:command:`find_package` command and by
- ``find_package_handle_standard_args()`` to inform the user about the
- problem.
+ :command:`find_package_handle_standard_args` to inform the user about the
+ problem. Use this instead of calling :command:`message` directly to
+ report a reason for failing to find the module or package.
``Xxx_RUNTIME_LIBRARY_DIRS``
Optionally, the runtime library search path for use when running an
@@ -160,23 +196,36 @@ same consideration applies to macros, functions and imported targets.
``Xxx_VERSION_PATCH``
The patch version of the package found, if any.
-The following names should not usually be used in CMakeLists.txt files, but
-are typically cache variables for users to edit and control the
-behaviour of find modules (like entering the path to a library manually)
+The following names should not usually be used in ``CMakeLists.txt`` files.
+They are intended for use by Find modules to specify and cache the locations
+of specific files or directories. Users are typically able to set and edit
+these variables to control the behavior of Find modules (like entering the
+path to a library manually):
``Xxx_LIBRARY``
- The path of the Xxx library (as used with :command:`find_library`, for
- example).
+ The path of the library. Use this form only when the module provides a
+ single library. It is appropriate to use this as the result variable
+ in a :command:`find_library` command.
``Xxx_Yy_LIBRARY``
- The path of the Yy library that is part of the Xxx system. It may or
- may not be required to use Xxx.
+ The path of library ``Yy`` provided by the module ``Xxx``. Use this form
+ when the module provides more than one library or where other modules may
+ also provide a library of the same name. It is also appropriate to use
+ this form as the result variable in a :command:`find_library` command.
``Xxx_INCLUDE_DIR``
- Where to find headers for using the Xxx library.
+ When the module provides only a single library, this variable can be used
+ to specify where to find headers for using the library (or more accurately,
+ the path that consumers of the library should add to their header search
+ path). It would be appropriate to use this as the result variable in a
+ :command:`find_path` command.
``Xxx_Yy_INCLUDE_DIR``
- Where to find headers for using the Yy library of the Xxx system.
+ If the module provides more than one library or where other modules may
+ also provide a library of the same name, this form is recommended for
+ specifying where to find headers for using library ``Yy`` provided by
+ the module. Again, it would be appropriate to use this as the result
+ variable in a :command:`find_path` command.
To prevent users being overwhelmed with settings to configure, try to
keep as many options as possible out of the cache, leaving at least one
@@ -185,7 +234,8 @@ not-found library (e.g. ``Xxx_ROOT_DIR``). For the same reason, mark
most cache options as advanced. For packages which provide both debug
and release binaries, it is common to create cache variables with a
``_LIBRARY_<CONFIG>`` suffix, such as ``Foo_LIBRARY_RELEASE`` and
-``Foo_LIBRARY_DEBUG``.
+``Foo_LIBRARY_DEBUG``. The :module:`SelectLibraryConfigurations` module
+can be helpful for such cases.
While these are the standard variable names, you should provide
backwards compatibility for any old names that were actually in use.
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 6876e1c..89739b7 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -1154,3 +1154,160 @@ The members specific to ``cmakeFiles`` objects are:
``isCMake``
Optional member that is present with boolean value ``true``
if the path specifies a file in the CMake installation.
+
+Object Kind "toolchains"
+------------------------
+
+The ``toolchains`` object kind lists properties of the toolchains used during
+the build. These include the language, compiler path, ID, and version.
+
+There is only one ``toolchains`` object major version, version 1.
+
+"toolchains" version 1
+^^^^^^^^^^^^^^^^^^^^^^
+
+``toolchains`` object version 1 is a JSON object:
+
+.. code-block:: json
+
+ {
+ "kind": "toolchains",
+ "version": { "major": 1, "minor": 0 },
+ "toolchains": [
+ {
+ "language": "C",
+ "compiler": {
+ "path": "/usr/bin/cc",
+ "id": "GNU",
+ "version": "9.3.0",
+ "implicit": {
+ "includeDirectories": [
+ "/usr/lib/gcc/x86_64-linux-gnu/9/include",
+ "/usr/local/include",
+ "/usr/include/x86_64-linux-gnu",
+ "/usr/include"
+ ],
+ "linkDirectories": [
+ "/usr/lib/gcc/x86_64-linux-gnu/9",
+ "/usr/lib/x86_64-linux-gnu",
+ "/usr/lib",
+ "/lib/x86_64-linux-gnu",
+ "/lib"
+ ],
+ "linkFrameworkDirectories": [],
+ "linkLibraries": [ "gcc", "gcc_s", "c", "gcc", "gcc_s" ]
+ }
+ },
+ "sourceFileExtensions": [ "c", "m" ]
+ },
+ {
+ "language": "CXX",
+ "compiler": {
+ "path": "/usr/bin/c++",
+ "id": "GNU",
+ "version": "9.3.0",
+ "implicit": {
+ "includeDirectories": [
+ "/usr/include/c++/9",
+ "/usr/include/x86_64-linux-gnu/c++/9",
+ "/usr/include/c++/9/backward",
+ "/usr/lib/gcc/x86_64-linux-gnu/9/include",
+ "/usr/local/include",
+ "/usr/include/x86_64-linux-gnu",
+ "/usr/include"
+ ],
+ "linkDirectories": [
+ "/usr/lib/gcc/x86_64-linux-gnu/9",
+ "/usr/lib/x86_64-linux-gnu",
+ "/usr/lib",
+ "/lib/x86_64-linux-gnu",
+ "/lib"
+ ],
+ "linkFrameworkDirectories": [],
+ "linkLibraries": [
+ "stdc++", "m", "gcc_s", "gcc", "c", "gcc_s", "gcc"
+ ]
+ }
+ },
+ "sourceFileExtensions": [
+ "C", "M", "c++", "cc", "cpp", "cxx", "mm", "CPP"
+ ]
+ }
+ ]
+ }
+
+The members specific to ``toolchains`` objects are:
+
+``toolchains``
+ A JSON array whose entries are each a JSON object specifying a toolchain
+ associated with a particular language. The members of each entry are:
+
+ ``language``
+ A JSON string specifying the toolchain language, like C or CXX. Language
+ names are the same as langauge names that can be passed to the
+ :command:`project` command. Because CMake only supports a single toolchain
+ per language, this field can be used as a key.
+
+ ``compiler``
+ A JSON object containing members:
+
+ ``path``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
+ language. Its value is a JSON string holding the path to the compiler.
+
+ ``id``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER_ID` variable is defined for the current
+ language. Its value is a JSON string holding the ID (GNU, MSVC, etc.) of
+ the compiler.
+
+ ``version``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable is defined for the
+ current language. Its value is a JSON string holding the version of the
+ compiler.
+
+ ``target``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER_TARGET` variable is defined for the
+ current language. Its value is a JSON string holding the cross-compiling
+ target of the compiler.
+
+ ``implicit``
+ A JSON object containing members:
+
+ ``includeDirectories``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES` variable is
+ defined for the current language. Its value is a JSON array of JSON
+ strings where each string holds a path to an implicit include
+ directory for the compiler.
+
+ ``linkDirectories``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES` variable is
+ defined for the current language. Its value is a JSON array of JSON
+ strings where each string holds a path to an implicit link directory
+ for the compiler.
+
+ ``linkFrameworkDirectories``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` variable
+ is defined for the current language. Its value is a JSON array of JSON
+ strings where each string holds a path to an implicit link framework
+ directory for the compiler.
+
+ ``linkLibraries``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES` variable is defined
+ for the current language. Its value is a JSON array of JSON strings
+ where each string holds a path to an implicit link library for the
+ compiler.
+
+ ``sourceFileExtensions``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS` variable is defined for
+ the current language. Its value is a JSON array of JSON strings where each
+ each string holds a file extension (without the leading dot) for the
+ language.
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index 6f137c4..3ab0a62 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/Help/manual/cmake-presets.7.rst
@@ -29,337 +29,344 @@ is using Git, ``CMakePresets.json`` may be tracked, and
Format
======
- The files are a JSON document with an object as the root:
+The files are a JSON document with an object as the root:
- .. literalinclude:: presets/example.json
- :language: json
+.. literalinclude:: presets/example.json
+ :language: json
- The root object recognizes the following fields:
+The root object recognizes the following fields:
- ``version``
+``version``
- A required integer representing the version of the JSON schema. Currently,
- the only supported version is 1.
+ A required integer representing the version of the JSON schema. Currently,
+ the only supported version is 1.
- ``cmakeMinimumRequired``
+``cmakeMinimumRequired``
- An optional object representing the minimum version of CMake needed to
- build this project. This object consists of the following fields:
+ An optional object representing the minimum version of CMake needed to
+ build this project. This object consists of the following fields:
- ``major``
+ ``major``
- An optional integer representing the major version.
+ An optional integer representing the major version.
- ``minor``
+ ``minor``
- An optional integer representing the minor version.
+ An optional integer representing the minor version.
- ``patch``
+ ``patch``
- An optional integer representing the patch version.
+ An optional integer representing the patch version.
- ``vendor``
+``vendor``
- An optional map containing vendor-specific information. CMake does not
- interpret the contents of this field except to verify that it is a map if
- it does exist. However, the keys should be a vendor-specific domain name
- followed by a ``/``-separated path. For example, the Example IDE 1.0 could
- use ``example.com/ExampleIDE/1.0``. The value of each field can be anything
- desired by the vendor, though will typically be a map.
+ An optional map containing vendor-specific information. CMake does not
+ interpret the contents of this field except to verify that it is a map if
+ it does exist. However, the keys should be a vendor-specific domain name
+ followed by a ``/``-separated path. For example, the Example IDE 1.0 could
+ use ``example.com/ExampleIDE/1.0``. The value of each field can be anything
+ desired by the vendor, though will typically be a map.
- ``configurePresets``
+``configurePresets``
- An optional array of configure preset objects. Each preset may contain the
- following fields:
+ An optional array of `Configure Preset`_ objects.
- ``name``
+Configure Preset
+^^^^^^^^^^^^^^^^
- A required string representing the machine-friendly name of the preset.
- This identifier is used in the ``--preset`` argument. There must not be
- two presets in the union of ``CMakePresets.json`` and
- ``CMakeUserPresets.json`` in the same directory with the same name.
+Each entry of the ``configurePresets`` array is a JSON object
+that may contain the following fields:
- ``hidden``
+``name``
- An optional boolean specifying whether or not a preset should be hidden.
- If a preset is hidden, it cannot be used in the ``--preset=`` argument,
- will not show up in the :manual:`CMake GUI <cmake-gui(1)>`, and does not
- have to have a valid ``generator`` or ``binaryDir``, even from
- inheritance. ``hidden`` presets are intended to be used as a base for
- other presets to inherit via the ``inherits`` field.
+ A required string representing the machine-friendly name of the preset.
+ This identifier is used in the ``--preset`` argument. There must not be
+ two presets in the union of ``CMakePresets.json`` and
+ ``CMakeUserPresets.json`` in the same directory with the same name.
- ``inherits``
+``hidden``
- An optional array of strings representing the names of presets to inherit
- from. The preset will inherit all of the fields from the ``inherits``
- presets by default (except ``name``, ``hidden``, ``inherits``,
- ``description``, and ``displayName``), but can override them as
- desired. If multiple ``inherits`` presets provide conflicting values for
- the same field, the earlier preset in the ``inherits`` list will be
- preferred. Presets in ``CMakePresets.json`` may not inherit from presets
- in ``CMakeUserPresets.json``.
+ An optional boolean specifying whether or not a preset should be hidden.
+ If a preset is hidden, it cannot be used in the ``--preset=`` argument,
+ will not show up in the :manual:`CMake GUI <cmake-gui(1)>`, and does not
+ have to have a valid ``generator`` or ``binaryDir``, even from
+ inheritance. ``hidden`` presets are intended to be used as a base for
+ other presets to inherit via the ``inherits`` field.
- This field can also be a string, which is equivalent to an array
- containing one string.
+``inherits``
- ``vendor``
+ An optional array of strings representing the names of presets to inherit
+ from. The preset will inherit all of the fields from the ``inherits``
+ presets by default (except ``name``, ``hidden``, ``inherits``,
+ ``description``, and ``displayName``), but can override them as
+ desired. If multiple ``inherits`` presets provide conflicting values for
+ the same field, the earlier preset in the ``inherits`` list will be
+ preferred. Presets in ``CMakePresets.json`` may not inherit from presets
+ in ``CMakeUserPresets.json``.
- An optional map containing vendor-specific information. CMake does not
- interpret the contents of this field except to verify that it is a map
- if it does exist. However, it should follow the same conventions as the
- root-level ``vendor`` field. If vendors use their own per-preset
- ``vendor`` field, they should implement inheritance in a sensible manner
- when appropriate.
+ This field can also be a string, which is equivalent to an array
+ containing one string.
- ``displayName``
+``vendor``
- An optional string with a human-friendly name of the preset.
+ An optional map containing vendor-specific information. CMake does not
+ interpret the contents of this field except to verify that it is a map
+ if it does exist. However, it should follow the same conventions as the
+ root-level ``vendor`` field. If vendors use their own per-preset
+ ``vendor`` field, they should implement inheritance in a sensible manner
+ when appropriate.
- ``description``
+``displayName``
- An optional string with a human-friendly description of the preset.
+ An optional string with a human-friendly name of the preset.
- ``generator``
+``description``
- An optional string representing the generator to use for the preset. If
- ``generator`` is not specified, it must be inherited from the
- ``inherits`` preset (unless this preset is ``hidden``).
+ An optional string with a human-friendly description of the preset.
- Note that for Visual Studio generators, unlike in the command line ``-G``
- argument, you cannot include the platform name in the generator name. Use
- the ``architecture`` field instead.
+``generator``
- ``architecture``
- ``toolset``
+ An optional string representing the generator to use for the preset. If
+ ``generator`` is not specified, it must be inherited from the
+ ``inherits`` preset (unless this preset is ``hidden``).
- Optional fields representing the platform and toolset, respectively, for
- generators that support them. Each may be either a string or an object
- with the following fields:
+ Note that for Visual Studio generators, unlike in the command line ``-G``
+ argument, you cannot include the platform name in the generator name. Use
+ the ``architecture`` field instead.
- ``value``
+``architecture``, ``toolset``
- An optional string representing the value.
+ Optional fields representing the platform and toolset, respectively, for
+ generators that support them. Each may be either a string or an object
+ with the following fields:
- ``strategy``
+ ``value``
- An optional string telling CMake how to handle the ``architecture`` or
- ``toolset`` field. Valid values are:
+ An optional string representing the value.
- ``"set"``
+ ``strategy``
- Set the respective value. This will result in an error for generators
- that do not support the respective field.
+ An optional string telling CMake how to handle the ``architecture`` or
+ ``toolset`` field. Valid values are:
- ``"external"``
+ ``"set"``
- Do not set the value, even if the generator supports it. This is
- useful if, for example, a preset uses the Ninja generator, and an IDE
- knows how to set up the Visual C++ environment from the
- ``architecture`` and ``toolset`` fields. In that case, CMake will
- ignore the field, but the IDE can use them to set up the environment
- before invoking CMake.
+ Set the respective value. This will result in an error for generators
+ that do not support the respective field.
- ``binaryDir``
+ ``"external"``
- An optional string representing the path to the output binary directory.
- This field supports macro expansion. If a relative path is specified, it
- is calculated relative to the source directory. If ``binaryDir`` is not
- specified, it must be inherited from the ``inherits`` preset (unless this
- preset is ``hidden``).
+ Do not set the value, even if the generator supports it. This is
+ useful if, for example, a preset uses the Ninja generator, and an IDE
+ knows how to set up the Visual C++ environment from the
+ ``architecture`` and ``toolset`` fields. In that case, CMake will
+ ignore the field, but the IDE can use them to set up the environment
+ before invoking CMake.
- ``cmakeExecutable``
+``binaryDir``
- An optional string representing the path to the CMake executable to use
- for this preset. This is reserved for use by IDEs, and is not used by
- CMake itself. IDEs that use this field should expand any macros in it.
+ An optional string representing the path to the output binary directory.
+ This field supports `macro expansion`_. If a relative path is specified,
+ it is calculated relative to the source directory. If ``binaryDir`` is not
+ specified, it must be inherited from the ``inherits`` preset (unless this
+ preset is ``hidden``).
- ``cacheVariables``
+``cmakeExecutable``
- An optional map of cache variables. The key is the variable name (which
- may not be an empty string), and the value is either ``null``, a boolean
- (which is equivalent to a value of ``"TRUE"`` or ``"FALSE"`` and a type
- of ``BOOL``), a string representing the value of the variable (which
- supports macro expansion), or an object with the following fields:
+ An optional string representing the path to the CMake executable to use
+ for this preset. This is reserved for use by IDEs, and is not used by
+ CMake itself. IDEs that use this field should expand any macros in it.
- ``type``
+``cacheVariables``
- An optional string representing the type of the variable.
+ An optional map of cache variables. The key is the variable name (which
+ may not be an empty string), and the value is either ``null``, a boolean
+ (which is equivalent to a value of ``"TRUE"`` or ``"FALSE"`` and a type
+ of ``BOOL``), a string representing the value of the variable (which
+ supports `macro expansion`_), or an object with the following fields:
- ``value``
+ ``type``
- A required string or boolean representing the value of the variable.
- A boolean is equivalent to ``"TRUE"`` or ``"FALSE"``. This field
- supports macro expansion.
+ An optional string representing the type of the variable.
- Cache variables are inherited through the ``inherits`` field, and the
- preset's variables will be the union of its own ``cacheVariables`` and
- the ``cacheVariables`` from all its parents. If multiple presets in this
- union define the same variable, the standard rules of ``inherits`` are
- applied. Setting a variable to ``null`` causes it to not be set, even if
- a value was inherited from another preset.
+ ``value``
- ``environment``
+ A required string or boolean representing the value of the variable.
+ A boolean is equivalent to ``"TRUE"`` or ``"FALSE"``. This field
+ supports `macro expansion`_.
- An optional map of environment variables. The key is the variable name
- (which may not be an empty string), and the value is either ``null`` or
- a string representing the value of the variable. Each variable is set
- regardless of whether or not a value was given to it by the process's
- environment. This field supports macro expansion, and environment
- variables in this map may reference each other, and may be listed in any
- order, as long as such references do not cause a cycle (for example,
- if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+ Cache variables are inherited through the ``inherits`` field, and the
+ preset's variables will be the union of its own ``cacheVariables`` and
+ the ``cacheVariables`` from all its parents. If multiple presets in this
+ union define the same variable, the standard rules of ``inherits`` are
+ applied. Setting a variable to ``null`` causes it to not be set, even if
+ a value was inherited from another preset.
- Environment variables are inherited through the ``inherits`` field, and
- the preset's environment will be the union of its own ``environment`` and
- the ``environment`` from all its parents. If multiple presets in this
- union define the same variable, the standard rules of ``inherits`` are
- applied. Setting a variable to ``null`` causes it to not be set, even if
- a value was inherited from another preset.
+``environment``
- ``warnings``
+ An optional map of environment variables. The key is the variable name
+ (which may not be an empty string), and the value is either ``null`` or
+ a string representing the value of the variable. Each variable is set
+ regardless of whether or not a value was given to it by the process's
+ environment. This field supports `macro expansion`_, and environment
+ variables in this map may reference each other, and may be listed in any
+ order, as long as such references do not cause a cycle (for example,
+ if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
- An optional object specifying the warnings to enable. The object may
- contain the following fields:
+ Environment variables are inherited through the ``inherits`` field, and
+ the preset's environment will be the union of its own ``environment`` and
+ the ``environment`` from all its parents. If multiple presets in this
+ union define the same variable, the standard rules of ``inherits`` are
+ applied. Setting a variable to ``null`` causes it to not be set, even if
+ a value was inherited from another preset.
- ``dev``
+``warnings``
- An optional boolean. Equivalent to passing ``-Wdev`` or ``-Wno-dev``
- on the command line. This may not be set to ``false`` if ``errors.dev``
- is set to ``true``.
+ An optional object specifying the warnings to enable. The object may
+ contain the following fields:
- ``deprecated``
+ ``dev``
- An optional boolean. Equivalent to passing ``-Wdeprecated`` or
- ``-Wno-deprecated`` on the command line. This may not be set to
- ``false`` if ``errors.deprecated`` is set to ``true``.
+ An optional boolean. Equivalent to passing ``-Wdev`` or ``-Wno-dev``
+ on the command line. This may not be set to ``false`` if ``errors.dev``
+ is set to ``true``.
- ``uninitialized``
+ ``deprecated``
- An optional boolean. Setting this to ``true`` is equivalent to passing
- ``--warn-uninitialized`` on the command line.
+ An optional boolean. Equivalent to passing ``-Wdeprecated`` or
+ ``-Wno-deprecated`` on the command line. This may not be set to
+ ``false`` if ``errors.deprecated`` is set to ``true``.
- ``unusedCli``
+ ``uninitialized``
- An optional boolean. Setting this to ``false`` is equivalent to passing
- ``--no-warn-unused-cli`` on the command line.
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--warn-uninitialized`` on the command line.
- ``systemVars``
+ ``unusedCli``
- An optional boolean. Setting this to ``true`` is equivalent to passing
- ``--check-system-vars`` on the command line.
+ An optional boolean. Setting this to ``false`` is equivalent to passing
+ ``--no-warn-unused-cli`` on the command line.
- ``errors``
+ ``systemVars``
- An optional object specifying the errors to enable. The object may
- contain the following fields:
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--check-system-vars`` on the command line.
- ``dev``
+``errors``
- An optional boolean. Equivalent to passing ``-Werror=dev`` or
- ``-Wno-error=dev`` on the command line. This may not be set to ``true``
- if ``warnings.dev`` is set to ``false``.
+ An optional object specifying the errors to enable. The object may
+ contain the following fields:
- ``deprecated``
+ ``dev``
- An optional boolean. Equivalent to passing ``-Werror=deprecated`` or
- ``-Wno-error=deprecated`` on the command line. This may not be set to
- ``true`` if ``warnings.deprecated`` is set to ``false``.
+ An optional boolean. Equivalent to passing ``-Werror=dev`` or
+ ``-Wno-error=dev`` on the command line. This may not be set to ``true``
+ if ``warnings.dev`` is set to ``false``.
- ``debug``
+ ``deprecated``
- An optional object specifying debug options. The object may contain the
- following fields:
+ An optional boolean. Equivalent to passing ``-Werror=deprecated`` or
+ ``-Wno-error=deprecated`` on the command line. This may not be set to
+ ``true`` if ``warnings.deprecated`` is set to ``false``.
- ``output``
+``debug``
- An optional boolean. Setting this to ``true`` is equivalent to passing
- ``--debug-output`` on the command line.
+ An optional object specifying debug options. The object may contain the
+ following fields:
- ``tryCompile``
+ ``output``
- An optional boolean. Setting this to ``true`` is equivalent to passing
- ``--debug-trycompile`` on the command line.
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--debug-output`` on the command line.
- ``find``
+ ``tryCompile``
- An optional boolean. Setting this to ``true`` is equivalent to passing
- ``--debug-find`` on the command line.
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--debug-trycompile`` on the command line.
- As mentioned above, some fields support macro expansion. Macros are
- recognized in the form ``$<macro-namespace>{<macro-name>}``. All macros are
- evaluated in the context of the preset being used, even if the macro is in a
- field that was inherited from another preset. For example, if the ``Base``
- preset sets variable ``PRESET_NAME`` to ``${presetName}``, and the
- ``Derived`` preset inherits from ``Base``, ``PRESET_NAME`` will be set to
- ``Derived``.
+ ``find``
- It is an error to not put a closing brace at the end of a macro name. For
- example, ``${sourceDir`` is invalid. A dollar sign (``$``) followed by
- anything other than a left curly brace (``{``) with a possible namespace is
- interpreted as a literal dollar sign.
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--debug-find`` on the command line.
- Recognized macros include:
+Macro Expansion
+^^^^^^^^^^^^^^^
- ``${sourceDir}``
+As mentioned above, some fields support macro expansion. Macros are
+recognized in the form ``$<macro-namespace>{<macro-name>}``. All macros are
+evaluated in the context of the preset being used, even if the macro is in a
+field that was inherited from another preset. For example, if the ``Base``
+preset sets variable ``PRESET_NAME`` to ``${presetName}``, and the
+``Derived`` preset inherits from ``Base``, ``PRESET_NAME`` will be set to
+``Derived``.
- Path to the project source directory.
+It is an error to not put a closing brace at the end of a macro name. For
+example, ``${sourceDir`` is invalid. A dollar sign (``$``) followed by
+anything other than a left curly brace (``{``) with a possible namespace is
+interpreted as a literal dollar sign.
- ``${sourceParentDir}``
+Recognized macros include:
- Path to the project source directory's parent directory.
+``${sourceDir}``
- ``${sourceDirName}``
+ Path to the project source directory.
- The last filename component of ``${sourceDir}``. For example, if
- ``${sourceDir}`` is ``/path/to/source``, this would be ``source``.
+``${sourceParentDir}``
- ``${presetName}``
+ Path to the project source directory's parent directory.
- Name specified in the preset's ``name`` field.
+``${sourceDirName}``
- ``${generator}``
+ The last filename component of ``${sourceDir}``. For example, if
+ ``${sourceDir}`` is ``/path/to/source``, this would be ``source``.
- Generator specified in the preset's ``generator`` field.
+``${presetName}``
- ``${dollar}``
+ Name specified in the preset's ``name`` field.
- A literal dollar sign (``$``).
+``${generator}``
- ``$env{<variable-name>}``
+ Generator specified in the preset's ``generator`` field.
- Environment variable with name ``<variable-name>``. The variable name may
- not be an empty string. If the variable is defined in the ``environment``
- field, that value is used instead of the value from the parent environment.
- If the environment variable is not defined, this evaluates as an empty
- string.
+``${dollar}``
- Note that while Windows environment variable names are case-insensitive,
- variable names within a preset are still case-sensitive. This may lead to
- unexpected results when using inconsistent casing. For best results, keep
- the casing of environment variable names consistent.
+ A literal dollar sign (``$``).
- ``$penv{<variable-name>}``
+``$env{<variable-name>}``
- Similar to ``$env{<variable-name>}``, except that the value only comes from
- the parent environment, and never from the ``environment`` field. This
- allows you to prepend or append values to existing environment variables.
- For example, setting ``PATH`` to ``/path/to/ninja/bin:$penv{PATH}`` will
- prepend ``/path/to/ninja/bin`` to the ``PATH`` environment variable. This
- is needed because ``$env{<variable-name>}`` does not allow circular
- references.
+ Environment variable with name ``<variable-name>``. The variable name may
+ not be an empty string. If the variable is defined in the ``environment``
+ field, that value is used instead of the value from the parent environment.
+ If the environment variable is not defined, this evaluates as an empty
+ string.
- ``$vendor{<macro-name>}``
+ Note that while Windows environment variable names are case-insensitive,
+ variable names within a preset are still case-sensitive. This may lead to
+ unexpected results when using inconsistent casing. For best results, keep
+ the casing of environment variable names consistent.
- An extension point for vendors to insert their own macros. CMake will not
- be able to use presets which have a ``$vendor{<macro-name>}`` macro, and
- effectively ignores such presets. However, it will still be able to use
- other presets from the same file.
+``$penv{<variable-name>}``
- CMake does not make any attempt to interpret ``$vendor{<macro-name>}``
- macros. However, to avoid name collisions, IDE vendors should prefix
- ``<macro-name>`` with a very short (preferably <= 4 characters) vendor
- identifier prefix, followed by a ``.``, followed by the macro name. For
- example, the Example IDE could have ``$vendor{xide.ideInstallDir}``.
+ Similar to ``$env{<variable-name>}``, except that the value only comes from
+ the parent environment, and never from the ``environment`` field. This
+ allows you to prepend or append values to existing environment variables.
+ For example, setting ``PATH`` to ``/path/to/ninja/bin:$penv{PATH}`` will
+ prepend ``/path/to/ninja/bin`` to the ``PATH`` environment variable. This
+ is needed because ``$env{<variable-name>}`` does not allow circular
+ references.
+
+``$vendor{<macro-name>}``
+
+ An extension point for vendors to insert their own macros. CMake will not
+ be able to use presets which have a ``$vendor{<macro-name>}`` macro, and
+ effectively ignores such presets. However, it will still be able to use
+ other presets from the same file.
+
+ CMake does not make any attempt to interpret ``$vendor{<macro-name>}``
+ macros. However, to avoid name collisions, IDE vendors should prefix
+ ``<macro-name>`` with a very short (preferably <= 4 characters) vendor
+ identifier prefix, followed by a ``.``, followed by the macro name. For
+ example, the Example IDE could have ``$vendor{xide.ideInstallDir}``.
Schema
======
diff --git a/Help/release/dev/cuda-nvcc-ccache-symlink.rst b/Help/release/dev/cuda-nvcc-ccache-symlink.rst
new file mode 100644
index 0000000..4d38047
--- /dev/null
+++ b/Help/release/dev/cuda-nvcc-ccache-symlink.rst
@@ -0,0 +1,9 @@
+cuda-nvcc-ccache-symlink
+------------------------
+
+* ``CUDA`` language support now works when ``nvcc`` is a symbolic link,
+ for example due to a ``ccache`` or ``colornvcc`` wrapper script.
+
+* The :module:`FindCUDAToolkit` module gained support for finding CUDA
+ toolkits when ``nvcc`` is a symbolic link,
+ for example due to a ``ccache`` or ``colornvcc`` wrapper script.
diff --git a/Help/release/dev/external-project-configure-handled-by-build.rst b/Help/release/dev/external-project-configure-handled-by-build.rst
new file mode 100644
index 0000000..4a1fac8
--- /dev/null
+++ b/Help/release/dev/external-project-configure-handled-by-build.rst
@@ -0,0 +1,8 @@
+external-project-configure-handled-by-build
+-------------------------------------------
+
+* The :module:`ExternalProject` function ``ExternalProject_Add`` learned a new
+ ``CONFIGURE_HANDLED_BY_BUILD`` option to have subsequent runs of the configure
+ step be triggered by the build step when an external project dependency
+ rebuilds instead of always rerunning the configure step when an external
+ project dependency rebuilds.
diff --git a/Help/release/dev/install-files-rename-genex.rst b/Help/release/dev/install-files-rename-genex.rst
new file mode 100644
index 0000000..f735e24
--- /dev/null
+++ b/Help/release/dev/install-files-rename-genex.rst
@@ -0,0 +1,5 @@
+install-files-rename-genex
+--------------------------
+
+* The :command:`install(FILES)` command ``RENAME`` option learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst b/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst
index 7f7e679..d885516 100644
--- a/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst
+++ b/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst
@@ -18,3 +18,18 @@ and compiler versions.
This variable is used to initialize the :prop_tgt:`CUDA_ARCHITECTURES` property
on all targets. See the target property for additional information.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION)
+
+ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
+ set(CMAKE_CUDA_ARCHITECTURES 75)
+ endif()
+
+ project(example LANGUAGES CUDA)
+
+``CMAKE_CUDA_ARCHITECTURES`` will default to ``75`` unless overridden by the user.
diff --git a/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst b/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
index 6cd51fa..b6fee2e 100644
--- a/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
@@ -5,3 +5,8 @@ CTEST_MEMORYCHECK_SANITIZER_OPTIONS
Specify the CTest ``MemoryCheckSanitizerOptions`` setting
in a :manual:`ctest(1)` dashboard client script.
+
+CTest prepends correct sanitizer options ``*_OPTIONS``
+environment variable to executed command. CTests adds
+its own ``log_path`` to sanitizer options, don't provide your
+own ``log_path``.
diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake
index ae3abe9..ab33b40 100644
--- a/Modules/CMakeDetermineCCompiler.cmake
+++ b/Modules/CMakeDetermineCCompiler.cmake
@@ -161,9 +161,10 @@ if (NOT _CMAKE_TOOLCHAIN_PREFIX)
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]+)*)?(-[^.]+)?(\\.exe)?$")
+ if (COMPILER_BASENAME MATCHES "^(.+-)?(clang|g?cc)(-cl)?(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
- set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
+ set(_CMAKE_TOOLCHAIN_SUFFIX ${CMAKE_MATCH_4})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_6})
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(CMAKE_C_COMPILER_TARGET)
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_C_COMPILER_TARGET}-)
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 578729c..c77fc3a 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -172,7 +172,20 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
endif()
endif()
- get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
+ # If NVCC is a symlink due to a wrapper script (e.g. ccache or colornvcc), then invoke it to find the
+ # real non-scattered toolkit.
+ if(IS_SYMLINK ${_CUDA_NVCC_EXECUTABLE})
+ execute_process(COMMAND ${_CUDA_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda" ERROR_VARIABLE NVCC_ERR)
+ if(NVCC_ERR MATCHES " _HERE_=([^\r\n]*)")
+ set(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "Could not execute nvcc with -v.")
+ endif()
+ unset(NVCC_ERR)
+ else()
+ get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
+ endif()
+
set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvlink${CMAKE_EXECUTABLE_SUFFIX}")
set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/fatbinary${CMAKE_EXECUTABLE_SUFFIX}")
get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake
index 905eb25..7283bc2 100644
--- a/Modules/CMakeDetermineCXXCompiler.cmake
+++ b/Modules/CMakeDetermineCXXCompiler.cmake
@@ -160,8 +160,9 @@ if (NOT _CMAKE_TOOLCHAIN_PREFIX)
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]+)*)?(-[^.]+)?(\\.exe)?$")
+ if (COMPILER_BASENAME MATCHES "^(.+-)?(clang\\+\\+|g\\+\\+|clang-cl)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_TOOLCHAIN_SUFFIX ${CMAKE_MATCH_3})
set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if(CMAKE_CXX_COMPILER_TARGET)
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
index d81fd11..ff178f6 100644
--- a/Modules/CMakeFindBinUtils.cmake
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -70,17 +70,18 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
OR (CMAKE_GENERATOR MATCHES "Visual Studio"
AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android"))
+ set(_CMAKE_LINKER_NAMES "link")
+ set(_CMAKE_AR_NAMES "lib")
+ set(_CMAKE_MT_NAMES "mt")
if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang")
- find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm llvm-nm HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- set(_CMAKE_ADDITIONAL_LINKER_NAMES "lld-link")
- set(_CMAKE_ADDITIONAL_AR_NAMES "llvm-lib")
+ set(_CMAKE_NM_NAMES "llvm-nm" "nm")
+ list(APPEND _CMAKE_AR_NAMES "lib" "llvm-lib")
+ list(APPEND _CMAKE_MT_NAMES "mt" "llvm-mt")
+ list(APPEND _CMAKE_LINKER_NAMES "lld-link")
+ list(APPEND _CMAKE_TOOL_VARS NM)
endif()
- find_program(CMAKE_LINKER NAMES ${_CMAKE_ADDITIONAL_LINKER_NAMES} link HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_AR NAMES ${_CMAKE_ADDITIONAL_AR_NAMES} lib HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_MT NAMES mt HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-
- list(APPEND _CMAKE_TOOL_VARS LINKER MT)
+ list(APPEND _CMAKE_TOOL_VARS LINKER MT AR)
# in all other cases search for ar, ranlib, etc.
else()
@@ -92,55 +93,54 @@ else()
endif()
if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
- set(_CMAKE_ADDITIONAL_AR_NAMES "llvm-ar")
- set(_CMAKE_ADDITIONAL_RANLIB_NAMES "llvm-ranlib")
- set(_CMAKE_ADDITIONAL_STRIP_NAMES "llvm-strip")
if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC")
- set(_CMAKE_ADDITIONAL_LINKER_NAMES "lld-link")
+ set(_CMAKE_LINKER_NAMES "lld-link")
else()
- set(_CMAKE_ADDITIONAL_LINKER_NAMES "ld.lld")
+ set(_CMAKE_LINKER_NAMES "ld.lld")
endif()
- set(_CMAKE_ADDITIONAL_NM_NAMES "llvm-nm")
- set(_CMAKE_ADDITIONAL_OBJDUMP_NAMES "llvm-objdump")
- set(_CMAKE_ADDITIONAL_OBJCOPY_NAMES "llvm-objcopy")
- set(_CMAKE_ADDITIONAL_READELF_NAMES "llvm-readelf")
- set(_CMAKE_ADDITIONAL_DLLTOOL_NAMES "llvm-dlltool")
- set(_CMAKE_ADDITIONAL_ADDR2LINE_NAMES "llvm-addr2line")
+ list(APPEND _CMAKE_AR_NAMES "llvm-ar")
+ list(APPEND _CMAKE_NM_NAMES "llvm-nm")
+ list(APPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
+ list(APPEND _CMAKE_OBJCOPY_NAMES "llvm-objcopy")
+ list(APPEND _CMAKE_READELF_NAMES "llvm-readelf")
+ list(APPEND _CMAKE_DLLTOOL_NAMES "llvm-dlltool")
+ list(APPEND _CMAKE_ADDR2LINE_NAMES "llvm-addr2line")
endif()
- if(NOT CMAKE_CROSSCOMPILING AND NOT "${_CMAKE_TOOLCHAIN_PREFIX}" STREQUAL "")
- list(APPEND _CMAKE_ADDITIONAL_AR_NAMES "ar")
- list(APPEND _CMAKE_ADDITIONAL_RANLIB_NAMES "ranlib")
- list(APPEND _CMAKE_ADDITIONAL_STRIP_NAMES "strip")
- list(APPEND _CMAKE_ADDITIONAL_LINKER_NAMES "ld")
- list(APPEND _CMAKE_ADDITIONAL_NM_NAMES "nm")
- list(APPEND _CMAKE_ADDITIONAL_OBJDUMP_NAMES "objdump")
- list(APPEND _CMAKE_ADDITIONAL_OBJCOPY_NAMES "objcopy")
- list(APPEND _CMAKE_ADDITIONAL_READELF_NAMES "readelf")
- list(APPEND _CMAKE_ADDITIONAL_DLLTOOL_NAMES "dlltool")
- list(APPEND _CMAKE_ADDITIONAL_ADDR2LINE_NAMES "addr2line")
- endif()
+ list(APPEND _CMAKE_AR_NAMES "ar")
+ list(APPEND _CMAKE_RANLIB_NAMES "ranlib")
+ list(APPEND _CMAKE_STRIP_NAMES "strip")
+ list(APPEND _CMAKE_LINKER_NAMES "ld")
+ list(APPEND _CMAKE_NM_NAMES "nm")
+ list(APPEND _CMAKE_OBJDUMP_NAMES "objdump")
+ list(APPEND _CMAKE_OBJCOPY_NAMES "objcopy")
+ list(APPEND _CMAKE_READELF_NAMES "readelf")
+ list(APPEND _CMAKE_DLLTOOL_NAMES "dlltool")
+ list(APPEND _CMAKE_ADDR2LINE_NAMES "addr2line")
+
+ list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
+endif()
- find_program(CMAKE_AR NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ar${_CMAKE_TOOLCHAIN_SUFFIX} ${_CMAKE_ADDITIONAL_AR_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+foreach(TOOL IN LISTS _CMAKE_TOOL_VARS)
+ foreach(NAME IN LISTS _CMAKE_${TOOL}_NAMES)
+ if(NOT _CMAKE_TOOLCHAIN_PREFIX STREQUAL "")
+ if(NOT _CMAKE_TOOLCHAIN_SUFFIX STREQUAL "")
+ list(PREPEND _CMAKE_${TOOL}_NAMES ${NAME}${_CMAKE_TOOLCHAIN_SUFFIX})
+ endif()
+ list(PREPEND _CMAKE_${TOOL}_NAMES ${_CMAKE_TOOLCHAIN_PREFIX}${NAME})
+ endif()
+ if(NOT _CMAKE_TOOLCHAIN_SUFFIX STREQUAL "")
+ list(PREPEND _CMAKE_${TOOL}_NAMES ${_CMAKE_TOOLCHAIN_PREFIX}${NAME}${_CMAKE_TOOLCHAIN_SUFFIX})
+ endif()
+ endforeach()
+ find_program(CMAKE_${TOOL} NAMES ${_CMAKE_${TOOL}_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+endforeach()
- find_program(CMAKE_RANLIB NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ranlib ${_CMAKE_ADDITIONAL_RANLIB_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- if(NOT CMAKE_RANLIB)
+if(NOT CMAKE_RANLIB)
set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib")
- endif()
-
-
- find_program(CMAKE_STRIP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}strip${_CMAKE_TOOLCHAIN_SUFFIX} ${_CMAKE_ADDITIONAL_STRIP_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_LINKER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ld ${_CMAKE_ADDITIONAL_LINKER_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm ${_CMAKE_ADDITIONAL_NM_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_OBJDUMP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objdump ${_CMAKE_ADDITIONAL_OBJDUMP_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_OBJCOPY NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objcopy ${_CMAKE_ADDITIONAL_OBJCOPY_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_READELF NAMES ${_CMAKE_TOOLCHAIN_PREFIX}readelf ${_CMAKE_ADDITIONAL_READELF_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_DLLTOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}dlltool ${_CMAKE_ADDITIONAL_DLLTOOL_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
- find_program(CMAKE_ADDR2LINE NAMES ${_CMAKE_TOOLCHAIN_PREFIX}addr2line ${_CMAKE_ADDITIONAL_ADDR2LINE_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-
- list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
endif()
+
if(CMAKE_PLATFORM_HAS_INSTALLNAME)
find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
@@ -157,7 +157,7 @@ foreach(var IN LISTS _CMAKE_TOOL_VARS)
if(_CMAKE_TOOL_CACHED)
mark_as_advanced(CMAKE_${var})
endif()
- unset(_CMAKE_ADDITIONAL_${var}_NAMES)
+ unset(_CMAKE_${var}_NAMES)
endforeach()
unset(_CMAKE_TOOL_VARS)
unset(_CMAKE_TOOL_CACHED)
diff --git a/Modules/Compiler/Clang-FindBinUtils.cmake b/Modules/Compiler/Clang-FindBinUtils.cmake
index b852660..e6c469a 100644
--- a/Modules/Compiler/Clang-FindBinUtils.cmake
+++ b/Modules/Compiler/Clang-FindBinUtils.cmake
@@ -2,6 +2,12 @@ if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL
message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
endif()
+# Ubuntu:
+# * /usr/bin/llvm-ar-9
+# * /usr/bin/llvm-ranlib-9
+string(REGEX MATCH "^([0-9]+)" __version_x
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}")
+
# Debian:
# * /usr/bin/llvm-ar-4.0
# * /usr/bin/llvm-ranlib-4.0
@@ -19,6 +25,7 @@ set(__clang_hints ${__clang_hint_1} ${__clang_hint_2})
# http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ar.1.html
find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
"${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar-${__version_x}"
"${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar"
HINTS ${__clang_hints}
DOC "LLVM archiver"
@@ -28,6 +35,7 @@ mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR)
# http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ranlib.1.html
find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
"${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib-${__version_x}"
"${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib"
HINTS ${__clang_hints}
DOC "Generate index for LLVM archive"
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 28d21c1..3307bc6 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -543,6 +543,18 @@ External Project Definition
When ``BUILD_IN_SOURCE`` option is enabled, the ``BUILD_COMMAND``
is used to point to an alternative directory within the source tree.
+ ``CONFIGURE_HANDLED_BY_BUILD <bool>``
+ .. versionadded:: 3.20
+
+ Enabling this option relaxes the dependencies of the configure step on
+ other external projects to order-only. This means the configure step will
+ be executed after its external project dependencies are built but it will
+ not be marked dirty when one of its external project dependencies is
+ rebuilt. This option can be enabled when the build step is smart enough
+ to figure out if the configure step needs to be rerun. CMake and Meson are
+ examples of build systems whose build step is smart enough to know if the
+ configure step needs to be rerun.
+
**Build Step Options:**
If the configure step assumed the external project uses CMake as its build
system, the build step will also. Otherwise, the build step will assume a
@@ -3083,6 +3095,23 @@ function(_ep_add_patch_command name)
)
endfunction()
+function(_ep_get_file_deps var name)
+ set(file_deps)
+
+ get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+ foreach(dep IN LISTS deps)
+ get_property(dep_type TARGET ${dep} PROPERTY TYPE)
+ if(dep_type STREQUAL "UTILITY")
+ get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
+ if(is_ep)
+ _ep_get_step_stampfile(${dep} "done" done_stamp_file)
+ list(APPEND file_deps ${done_stamp_file})
+ endif()
+ endif()
+ endforeach()
+
+ set("${var}" "${file_deps}" PARENT_SCOPE)
+endfunction()
function(_ep_extract_configure_command var name)
get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
@@ -3191,19 +3220,13 @@ endfunction()
function(_ep_add_configure_command name)
ExternalProject_Get_Property(${name} binary_dir tmp_dir)
- # Depend on other external projects (file-level).
set(file_deps)
- get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
- foreach(dep IN LISTS deps)
- get_property(dep_type TARGET ${dep} PROPERTY TYPE)
- if(dep_type STREQUAL "UTILITY")
- get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
- if(is_ep)
- _ep_get_step_stampfile(${dep} "done" done_stamp_file)
- list(APPEND file_deps ${done_stamp_file})
- endif()
- endif()
- endforeach()
+ get_property(configure_handled_by_build TARGET ${name}
+ PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+ if(NOT configure_handled_by_build)
+ # Depend on other external projects (file-level)
+ _ep_get_file_deps(file_deps ${name})
+ endif()
_ep_extract_configure_command(cmd ${name})
@@ -3254,6 +3277,14 @@ endfunction()
function(_ep_add_build_command name)
ExternalProject_Get_Property(${name} binary_dir)
+ set(file_deps)
+ get_property(configure_handled_by_build TARGET ${name}
+ PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+ if(configure_handled_by_build)
+ # Depend on other external projects (file-level)
+ _ep_get_file_deps(file_deps ${name})
+ endif()
+
get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
if(cmd_set)
get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
@@ -3296,6 +3327,7 @@ function(_ep_add_build_command name)
BYPRODUCTS \${build_byproducts}
WORKING_DIRECTORY \${binary_dir}
DEPENDEES configure
+ DEPENDS \${file_deps}
ALWAYS \${always}
${log}
${uses_terminal}
diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake
index 6daf81d..240f0a5 100644
--- a/Modules/FindCUDA.cmake
+++ b/Modules/FindCUDA.cmake
@@ -834,7 +834,20 @@ if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING)
)
if (CUDA_TOOLKIT_ROOT_DIR_NVCC)
- get_filename_component(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY)
+ # If NVCC is a symlink due to a wrapper script (e.g. ccache or colornvcc), then invoke it to find the
+ # real non-scattered toolkit.
+ if(IS_SYMLINK ${CUDA_TOOLKIT_ROOT_DIR_NVCC})
+ execute_process(COMMAND ${CUDA_TOOLKIT_ROOT_DIR_NVCC} "-v" "__cmake_determine_cuda" ERROR_VARIABLE NVCC_ERR)
+ if(NVCC_ERR MATCHES " _HERE_=([^\r\n]*)")
+ set(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "Could not execute nvcc with -v.")
+ endif()
+ unset(NVCC_ERR)
+ else()
+ get_filename_component(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY)
+ endif()
+
get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR}" DIRECTORY CACHE)
string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR})
# We need to force this back into the cache.
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 61e264b..0d80c80 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -519,7 +519,19 @@ else()
endif()
if(CUDAToolkit_NVCC_EXECUTABLE)
- get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
+ # If NVCC is a symlink due to a wrapper script (e.g. ccache or colornvcc), then invoke it to find the
+ # real non-scattered toolkit.
+ if(IS_SYMLINK ${CUDAToolkit_NVCC_EXECUTABLE})
+ execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda" ERROR_VARIABLE NVCC_ERR)
+ if(NVCC_ERR MATCHES " _HERE_=([^\r\n]*)")
+ set(CUDAToolkit_BIN_DIR "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "Could not execute nvcc with -v.")
+ endif()
+ unset(NVCC_ERR)
+ else()
+ get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
+ endif()
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
mark_as_advanced(CUDAToolkit_BIN_DIR)
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index 05696ae..a69a585 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -116,15 +116,22 @@ also be defined. With all components enabled, the following variables will be d
With all components enabled, the following targets will be defined:
-::
-
- ``hdf5::hdf5``
- ``hdf5::hdf5_hl_cpp``
- ``hdf5::hdf5_fortran``
- ``hdf5::hdf5_hl``
- ``hdf5::hdf5_hl_cpp``
- ``hdf5::hdf5_hl_fortran``
- ``hdf5::h5diff``
+``HDF5::HDF5``
+ All detected ``HDF5_LIBRARIES``.
+``hdf5::hdf5``
+ C library.
+``hdf5::hdf5_cpp``
+ C++ library.
+``hdf5::hdf5_fortran``
+ Fortran library.
+``hdf5::hdf5_hl``
+ High-level C library.
+``hdf5::hdf5_hl_cpp``
+ High-level C++ library.
+``hdf5::hdf5_hl_fortran``
+ High-level Fortran library.
+``hdf5::h5diff``
+ ``h5diff`` executable.
Hints
^^^^^
@@ -206,22 +213,6 @@ else()
set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc)
endif()
-# We may have picked up some duplicates in various lists during the above
-# process for the language bindings (both the C and C++ bindings depend on
-# libz for example). Remove the duplicates. It appears that the default
-# CMake behavior is to remove duplicates from the end of a list. However,
-# for link lines, this is incorrect since unresolved symbols are searched
-# for down the link line. Therefore, we reverse the list, remove the
-# duplicates, and then reverse it again to get the duplicates removed from
-# the beginning.
-macro(_HDF5_remove_duplicates_from_beginning _list_name)
- if(${_list_name})
- list(REVERSE ${_list_name})
- list(REMOVE_DUPLICATES ${_list_name})
- list(REVERSE ${_list_name})
- endif()
-endmacro()
-
# Test first if the current compilers automatically wrap HDF5
function(_HDF5_test_regular_compiler_C success version is_parallel)
set(scratch_directory
@@ -724,10 +715,8 @@ if(NOT HDF5_FOUND)
endif()
set(HDF5_${_lang}_FOUND TRUE)
- _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_DEFINITIONS)
- _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_INCLUDE_DIRS)
- _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_LIBRARIES)
- _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_HL_LIBRARIES)
+ list(REMOVE_DUPLICATES HDF5_${_lang}_DEFINITIONS)
+ list(REMOVE_DUPLICATES HDF5_${_lang}_INCLUDE_DIRS)
else()
set(_HDF5_NEED_TO_SEARCH TRUE)
endif()
@@ -780,10 +769,8 @@ elseif(NOT HDF5_FOUND AND NOT _HDF5_NEED_TO_SEARCH)
endif()
endif()
endforeach()
- _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS)
- _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS)
- _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES)
- _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES)
+ list(REMOVE_DUPLICATES HDF5_DEFINITIONS)
+ list(REMOVE_DUPLICATES HDF5_INCLUDE_DIRS)
set(HDF5_FOUND TRUE)
set(HDF5_REQUIRED_VARS HDF5_LIBRARIES)
if(HDF5_FIND_HL)
@@ -923,10 +910,8 @@ if( NOT HDF5_FOUND )
set(HDF5_HL_FOUND TRUE)
endif()
- _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS)
- _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS)
- _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES)
- _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES)
+ list(REMOVE_DUPLICATES HDF5_DEFINITIONS)
+ list(REMOVE_DUPLICATES HDF5_INCLUDE_DIRS)
# If the HDF5 include directory was found, open H5pubconf.h to determine if
# HDF5 was compiled with parallel IO support
@@ -1147,6 +1132,21 @@ if (HDF5_FIND_DEBUG)
message(STATUS "HDF5_${_lang}_HL_LIBRARY: ${HDF5_${_lang}_HL_LIBRARY}")
message(STATUS "HDF5_${_lang}_HL_LIBRARIES: ${HDF5_${_lang}_HL_LIBRARIES}")
endforeach()
+ message(STATUS "Defined targets (if any):")
+ foreach(_lang IN ITEMS "" "_cpp" "_fortran")
+ foreach(_hl IN ITEMS "" "_hl")
+ foreach(_prefix IN ITEMS "hdf5::" "")
+ foreach(_suffix IN ITEMS "-static" "-shared" "")
+ set (_target ${_prefix}hdf5${_hl}${_lang}${_suffix})
+ if (TARGET ${_target})
+ message(STATUS "... ${_target}")
+ else()
+ #message(STATUS "... ${_target} does not exist")
+ endif()
+ endforeach()
+ endforeach()
+ endforeach()
+ endforeach()
endif()
unset(_lang)
unset(_HDF5_NEED_TO_SEARCH)
diff --git a/Modules/FindJPEG.cmake b/Modules/FindJPEG.cmake
index 3f243de..add2486 100644
--- a/Modules/FindJPEG.cmake
+++ b/Modules/FindJPEG.cmake
@@ -58,7 +58,7 @@ Obsolete variables
find_path(JPEG_INCLUDE_DIR jpeglib.h)
-set(jpeg_names ${JPEG_NAMES} jpeg jpeg-static libjpeg libjpeg-static)
+set(jpeg_names ${JPEG_NAMES} jpeg jpeg-static libjpeg libjpeg-static turbojpeg turbojpeg-static)
foreach(name ${jpeg_names})
list(APPEND jpeg_names_debug "${name}d")
endforeach()
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index d5af5da..45e4be7 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -72,6 +72,12 @@ The following variables may be set to influence this module's behavior:
``BLA_F95``
if ``ON`` tries to find the BLAS95/LAPACK95 interfaces
+``BLA_PREFER_PKGCONFIG``
+ .. versionadded:: 3.20
+
+ if set ``pkg-config`` will be used to search for a LAPACK library first
+ and if one is found that is preferred
+
Imported targets
^^^^^^^^^^^^^^^^
@@ -121,6 +127,26 @@ endif()
include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+function(_add_lapack_target)
+ if(LAPACK_FOUND AND NOT TARGET LAPACK::LAPACK)
+ add_library(LAPACK::LAPACK INTERFACE IMPORTED)
+ set(_lapack_libs "${LAPACK_LIBRARIES}")
+ if(_lapack_libs AND TARGET BLAS::BLAS)
+ # remove the ${BLAS_LIBRARIES} from the interface and replace it
+ # with the BLAS::BLAS target
+ list(REMOVE_ITEM _lapack_libs "${BLAS_LIBRARIES}")
+ list(APPEND _lapack_libs BLAS::BLAS)
+ endif()
+
+ if(_lapack_libs)
+ set_target_properties(LAPACK::LAPACK PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${_lapack_libs}"
+ )
+ endif()
+ unset(_lapack_libs)
+ endif()
+endfunction()
+
macro(_lapack_find_library_setup)
cmake_push_check_state()
set(CMAKE_REQUIRED_QUIET ${LAPACK_FIND_QUIETLY})
@@ -265,6 +291,21 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
_lapack_find_dependency(BLAS)
endif()
+# Search with pkg-config if specified
+if(BLA_PREFER_PKGCONFIG)
+ find_package(PkgConfig)
+ pkg_check_modules(PKGC_LAPACK lapack)
+ if(PKGC_LAPACK_FOUND)
+ set(LAPACK_FOUND TRUE)
+ set(LAPACK_LIBRARIES "${PKGC_LAPACK_LINK_LIBRARIES}")
+ if (BLAS_LIBRARIES)
+ list(APPEND LAPACK_LIBRARIES "${BLAS_LIBRARIES}")
+ endif()
+ _add_lapack_target()
+ return()
+ endif()
+endif()
+
# Search for different LAPACK distributions if BLAS is found
if(NOT LAPACK_NOT_FOUND_MESSAGE)
set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
@@ -585,21 +626,6 @@ if(LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
set(LAPACK_LIBRARIES "")
endif()
-if(LAPACK_FOUND AND NOT TARGET LAPACK::LAPACK)
- add_library(LAPACK::LAPACK INTERFACE IMPORTED)
- set(_lapack_libs "${LAPACK_LIBRARIES}")
- if(_lapack_libs AND TARGET BLAS::BLAS)
- # remove the ${BLAS_LIBRARIES} from the interface and replace it
- # with the BLAS::BLAS target
- list(REMOVE_ITEM _lapack_libs "${BLAS_LIBRARIES}")
- endif()
-
- if(_lapack_libs)
- set_target_properties(LAPACK::LAPACK PROPERTIES
- INTERFACE_LINK_LIBRARIES "${_lapack_libs}"
- )
- endif()
- unset(_lapack_libs)
-endif()
+_add_lapack_target()
_lapack_find_library_teardown()
diff --git a/Modules/InstallRequiredSystemLibraries.cmake b/Modules/InstallRequiredSystemLibraries.cmake
index c34b819..6ecdb9c 100644
--- a/Modules/InstallRequiredSystemLibraries.cmake
+++ b/Modules/InstallRequiredSystemLibraries.cmake
@@ -299,6 +299,7 @@ if(MSVC)
foreach(crt
"${MSVC_CRT_DIR}/msvcp${v}_1.dll"
"${MSVC_CRT_DIR}/msvcp${v}_2.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}_atomic_wait.dll"
"${MSVC_CRT_DIR}/msvcp${v}_codecvt_ids.dll"
"${MSVC_CRT_DIR}/vcruntime${v}_1.dll"
)
@@ -327,6 +328,7 @@ if(MSVC)
foreach(crt
"${MSVC_CRT_DIR}/msvcp${v}_1d.dll"
"${MSVC_CRT_DIR}/msvcp${v}_2d.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}d_atomic_wait.dll"
"${MSVC_CRT_DIR}/msvcp${v}d_codecvt_ids.dll"
"${MSVC_CRT_DIR}/vcruntime${v}_1d.dll"
)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index c5b67c0..dca94ee 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -268,6 +268,8 @@ set(SRCS
cmFileAPICodemodel.h
cmFileAPICMakeFiles.cxx
cmFileAPICMakeFiles.h
+ cmFileAPIToolchains.cxx
+ cmFileAPIToolchains.h
cmFileCopier.cxx
cmFileCopier.h
cmFileInstaller.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index a5cf411..241c1c3 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 19)
-set(CMake_VERSION_PATCH 20210112)
+set(CMake_VERSION_PATCH 20210118)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 8a30dc0..6e8091b 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -1364,9 +1364,15 @@ void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
}
}
if (this->LogWithPID) {
- cmSystemTools::RemoveFile(ofile);
- cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Remove: " << ofile << "\n", this->Quiet);
+ auto pos = ofile.find_last_of('.');
+ if (pos != std::string::npos) {
+ auto ofileWithoutPid = ofile.substr(0, pos);
+ cmSystemTools::RenameFile(ofile, ofileWithoutPid);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Renaming: " << ofile << " to: " << ofileWithoutPid
+ << "\n",
+ this->Quiet);
+ }
}
}
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index d8f89d6..0c263bb 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -213,6 +213,7 @@ else()
qt_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS})
qt_add_resources(QRC_BUILT_SRCS ${QRC_SRCS})
endif()
+add_library(CMakeGUIQRCLib OBJECT ${QRC_BUILT_SRCS})
if (FALSE) # CMake's bootstrap binary does not support automoc
set(CMAKE_AUTOMOC 1)
@@ -221,8 +222,7 @@ if (FALSE) # CMake's bootstrap binary does not support automoc
else ()
list(APPEND SRCS
${UI_BUILT_SRCS}
- ${MOC_BUILT_SRCS}
- ${QRC_BUILT_SRCS})
+ ${MOC_BUILT_SRCS})
endif ()
if(USE_LGPL)
@@ -246,6 +246,7 @@ target_link_libraries(CMakeGUIMainLib PUBLIC CMakeGUILib)
add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx ${MANIFEST_FILE})
target_link_libraries(cmake-gui CMakeGUIMainLib Qt${INSTALLED_QT_VERSION}::Core)
+target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeGUIQRCLib>)
if(WIN32)
target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeVersion> CMakeSetup.rc)
endif()
diff --git a/Source/cmCMakePath.cxx b/Source/cmCMakePath.cxx
index b8215df..73321c6 100644
--- a/Source/cmCMakePath.cxx
+++ b/Source/cmCMakePath.cxx
@@ -88,7 +88,8 @@ bool cmCMakePath::IsPrefix(const cmCMakePath& path) const
++prefix_it;
++path_it;
}
- return prefix_it == prefix_end;
+ return (prefix_it == prefix_end) ||
+ (prefix_it->empty() && path_it != path_end);
}
std::string cmCMakePath::FormatPath(std::string path, format fmt)
diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx
index e9bf84a..5662a2f 100644
--- a/Source/cmCMakePathCommand.cxx
+++ b/Source/cmCMakePathCommand.cxx
@@ -929,17 +929,8 @@ bool HandleIsPrefixCommand(std::vector<std::string> const& args,
bool HandleHashCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- if (args.size() < 3 || args.size() > 4) {
- status.SetError("HASH must be called with two or three arguments.");
- return false;
- }
-
- static NormalizeParser const parser;
-
- const auto arguments = parser.Parse(args);
-
- if (parser.GetInputs().size() != 1) {
- status.SetError("HASH called with unexpected arguments.");
+ if (args.size() != 3) {
+ status.SetError("HASH must be called with two arguments.");
return false;
}
@@ -948,15 +939,14 @@ bool HandleHashCommand(std::vector<std::string> const& args,
return false;
}
- const auto& output = parser.GetInputs().front();
+ const auto& output = args[2];
if (output.empty()) {
status.SetError("Invalid name for output variable.");
return false;
}
- auto hash = hash_value(arguments.Normalize ? cmCMakePath(inputPath).Normal()
- : cmCMakePath(inputPath));
+ auto hash = hash_value(cmCMakePath(inputPath).Normal());
std::ostringstream out;
out << std::setbase(16) << hash;
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index c2ab2f1..d2a9bec 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -18,6 +18,7 @@
#include "cmFileAPICMakeFiles.h"
#include "cmFileAPICache.h"
#include "cmFileAPICodemodel.h"
+#include "cmFileAPIToolchains.h"
#include "cmGlobalGenerator.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -262,6 +263,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
objects.push_back(o);
return true;
}
+ if (kindName == ObjectKindName(ObjectKind::Toolchains)) {
+ Object o;
+ o.Kind = ObjectKind::Toolchains;
+ if (verStr == "v1") {
+ o.Version = 1;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
Object o;
o.Kind = ObjectKind::InternalTest;
@@ -402,6 +414,7 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
"codemodel", //
"cache", //
"cmakeFiles", //
+ "toolchains", //
"__test" //
};
return objectKindNames[size_t(kind)];
@@ -435,6 +448,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
case ObjectKind::CMakeFiles:
value = this->BuildCMakeFiles(object);
break;
+ case ObjectKind::Toolchains:
+ value = this->BuildToolchains(object);
+ break;
case ObjectKind::InternalTest:
value = this->BuildInternalTest(object);
break;
@@ -491,6 +507,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
r.Kind = ObjectKind::Cache;
} else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) {
r.Kind = ObjectKind::CMakeFiles;
+ } else if (kindName == this->ObjectKindName(ObjectKind::Toolchains)) {
+ r.Kind = ObjectKind::Toolchains;
} else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
r.Kind = ObjectKind::InternalTest;
} else {
@@ -518,6 +536,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
case ObjectKind::CMakeFiles:
this->BuildClientRequestCMakeFiles(r, versions);
break;
+ case ObjectKind::Toolchains:
+ this->BuildClientRequestToolchains(r, versions);
+ break;
case ObjectKind::InternalTest:
this->BuildClientRequestInternalTest(r, versions);
break;
@@ -765,6 +786,40 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
return cmakeFiles;
}
+// The "toolchains" object kind.
+
+static unsigned int const ToolchainsV1Minor = 0;
+
+void cmFileAPI::BuildClientRequestToolchains(
+ ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+ // Select a known version from those requested.
+ for (RequestVersion const& v : versions) {
+ if ((v.Major == 1 && v.Minor <= ToolchainsV1Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildToolchains(Object const& object)
+{
+ Json::Value toolchains = cmFileAPIToolchainsDump(*this, object.Version);
+ toolchains["kind"] = this->ObjectKindName(object.Kind);
+
+ Json::Value& version = toolchains["version"];
+ if (object.Version == 1) {
+ version = BuildVersion(1, ToolchainsV1Minor);
+ } else {
+ return toolchains; // should be unreachable
+ }
+
+ return toolchains;
+}
+
// The "__test" object kind is for internal testing of CMake.
static unsigned int const InternalTestV1Minor = 3;
@@ -828,5 +883,13 @@ Json::Value cmFileAPI::ReportCapabilities()
requests.append(std::move(request)); // NOLINT(*)
}
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::Toolchains);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(1, ToolchainsV1Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
return capabilities;
}
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
index 086a92a..22302b4 100644
--- a/Source/cmFileAPI.h
+++ b/Source/cmFileAPI.h
@@ -56,6 +56,7 @@ private:
CodeModel,
Cache,
CMakeFiles,
+ Toolchains,
InternalTest
};
@@ -200,6 +201,10 @@ private:
ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildCMakeFiles(Object const& object);
+ void BuildClientRequestToolchains(
+ ClientRequest& r, std::vector<RequestVersion> const& versions);
+ Json::Value BuildToolchains(Object const& object);
+
void BuildClientRequestInternalTest(
ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildInternalTest(Object const& object);
diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx
new file mode 100644
index 0000000..722c114
--- /dev/null
+++ b/Source/cmFileAPIToolchains.cxx
@@ -0,0 +1,151 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPIToolchains.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm3p/json/value.h>
+
+#include "cmFileAPI.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+namespace {
+
+struct ToolchainVariable
+{
+ std::string ObjectKey;
+ std::string VariableSuffix;
+ bool IsList;
+};
+
+class Toolchains
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+
+ static const std::vector<ToolchainVariable> CompilerVariables;
+ static const std::vector<ToolchainVariable> CompilerImplicitVariables;
+ static const ToolchainVariable SourceFileExtensionsVariable;
+
+ Json::Value DumpToolchains();
+ Json::Value DumpToolchain(std::string const& lang);
+ Json::Value DumpToolchainVariables(
+ cmMakefile const* mf, std::string const& lang,
+ std::vector<ToolchainVariable> const& variables);
+ void DumpToolchainVariable(cmMakefile const* mf, Json::Value& object,
+ std::string const& lang,
+ ToolchainVariable const& variable);
+
+public:
+ Toolchains(cmFileAPI& fileAPI, unsigned long version);
+ Json::Value Dump();
+};
+
+const std::vector<ToolchainVariable> Toolchains::CompilerVariables{
+ { "path", "COMPILER", false },
+ { "id", "COMPILER_ID", false },
+ { "version", "COMPILER_VERSION", false },
+ { "target", "COMPILER_TARGET", false },
+};
+
+const std::vector<ToolchainVariable> Toolchains::CompilerImplicitVariables{
+ { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true },
+ { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true },
+ { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true },
+ { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true },
+};
+
+const ToolchainVariable Toolchains::SourceFileExtensionsVariable{
+ "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true
+};
+
+Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned long version)
+ : FileAPI(fileAPI)
+ , Version(version)
+{
+ static_cast<void>(this->Version);
+}
+
+Json::Value Toolchains::Dump()
+{
+ Json::Value toolchains = Json::objectValue;
+ toolchains["toolchains"] = this->DumpToolchains();
+ return toolchains;
+}
+
+Json::Value Toolchains::DumpToolchains()
+{
+ Json::Value toolchains = Json::arrayValue;
+
+ for (std::string const& lang :
+ this->FileAPI.GetCMakeInstance()->GetState()->GetEnabledLanguages()) {
+ toolchains.append(this->DumpToolchain(lang));
+ }
+
+ return toolchains;
+}
+
+Json::Value Toolchains::DumpToolchain(std::string const& lang)
+{
+ const auto& mf =
+ this->FileAPI.GetCMakeInstance()->GetGlobalGenerator()->GetMakefiles()[0];
+ Json::Value toolchain = Json::objectValue;
+ toolchain["language"] = lang;
+ toolchain["compiler"] =
+ this->DumpToolchainVariables(mf.get(), lang, CompilerVariables);
+ toolchain["compiler"]["implicit"] =
+ this->DumpToolchainVariables(mf.get(), lang, CompilerImplicitVariables);
+ this->DumpToolchainVariable(mf.get(), toolchain, lang,
+ SourceFileExtensionsVariable);
+ return toolchain;
+}
+
+Json::Value Toolchains::DumpToolchainVariables(
+ cmMakefile const* mf, std::string const& lang,
+ std::vector<ToolchainVariable> const& variables)
+{
+ Json::Value object = Json::objectValue;
+ for (const auto& variable : variables) {
+ this->DumpToolchainVariable(mf, object, lang, variable);
+ }
+ return object;
+}
+
+void Toolchains::DumpToolchainVariable(cmMakefile const* mf,
+ Json::Value& object,
+ std::string const& lang,
+ ToolchainVariable const& variable)
+{
+ std::string const variableName =
+ cmStrCat("CMAKE_", lang, "_", variable.VariableSuffix);
+
+ if (variable.IsList) {
+ std::vector<std::string> values;
+ if (mf->GetDefExpandList(variableName, values)) {
+ Json::Value jsonArray = Json::arrayValue;
+ for (std::string const& value : values) {
+ jsonArray.append(value);
+ }
+ object[variable.ObjectKey] = jsonArray;
+ }
+ } else {
+ cmProp def = mf->GetDefinition(variableName);
+ if (def) {
+ object[variable.ObjectKey] = *def;
+ }
+ }
+}
+}
+
+Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, unsigned long version)
+{
+ Toolchains toolchains(fileAPI, version);
+ return toolchains.Dump();
+}
diff --git a/Source/cmFileAPIToolchains.h b/Source/cmFileAPIToolchains.h
new file mode 100644
index 0000000..c188807
--- /dev/null
+++ b/Source/cmFileAPIToolchains.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cm3p/json/value.h>
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI,
+ unsigned long version);
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index c4bec23..36f583f 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -21,6 +21,8 @@ cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm)
this->PassMakeflags = true;
this->UnixCD = false;
this->MakeSilentFlag = "/nologo";
+ // nmake breaks on '!' in long-line dependencies
+ this->ToolSupportsLongLineDependencies = false;
}
void cmGlobalNMakeMakefileGenerator::EnableLanguage(
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index c45000d..0a353e4 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -25,10 +25,14 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
, Programs(programs)
, Optional(optional)
{
- // We need per-config actions if the destination has generator expressions.
+ // We need per-config actions if the destination and rename have generator
+ // expressions.
if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) {
this->ActionsPerConfig = true;
}
+ if (cmGeneratorExpression::Find(this->Rename) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ }
// We need per-config actions if any directories have generator expressions.
if (!this->ActionsPerConfig) {
@@ -56,6 +60,12 @@ std::string cmInstallFilesGenerator::GetDestination(
this->LocalGenerator, config);
}
+std::string cmInstallFilesGenerator::GetRename(std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Rename, this->LocalGenerator,
+ config);
+}
+
void cmInstallFilesGenerator::AddFilesInstallRule(
std::ostream& os, std::string const& config, Indent indent,
std::vector<std::string> const& files)
@@ -66,7 +76,7 @@ void cmInstallFilesGenerator::AddFilesInstallRule(
os, this->GetDestination(config),
(this->Programs ? cmInstallType_PROGRAMS : cmInstallType_FILES), files,
this->Optional, this->FilePermissions.c_str(), no_dir_permissions,
- this->Rename.c_str(), nullptr, indent);
+ this->GetRename(config).c_str(), nullptr, indent);
}
void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
index b5a1ef4..66145f4 100644
--- a/Source/cmInstallFilesGenerator.h
+++ b/Source/cmInstallFilesGenerator.h
@@ -31,6 +31,7 @@ public:
bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
+ std::string GetRename(std::string const& config) const;
protected:
void GenerateScriptActions(std::ostream& os, Indent indent) override;
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 53c871b..fdddb45 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -422,9 +422,10 @@ bool HandleJoinCommand(std::vector<std::string> const& args,
bool HandleRemoveItemCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- if (args.size() < 3) {
- status.SetError("sub-command REMOVE_ITEM requires two or more arguments.");
- return false;
+ assert(args.size() >= 2);
+
+ if (args.size() == 2) {
+ return true;
}
const std::string& listName = args[1];
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 5a747e5..7229101 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -693,13 +693,11 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
}
}
-namespace {
-bool HasUniqueByproducts(cmLocalGenerator& lg,
- std::vector<std::string> const& byproducts,
- cmListFileBacktrace const& bt)
+bool cmLocalNinjaGenerator::HasUniqueByproducts(
+ std::vector<std::string> const& byproducts, cmListFileBacktrace const& bt)
{
std::vector<std::string> configs =
- lg.GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
cmGeneratorExpression ge(bt);
for (std::string const& p : byproducts) {
if (cmGeneratorExpression::Find(p) == std::string::npos) {
@@ -709,7 +707,7 @@ bool HasUniqueByproducts(cmLocalGenerator& lg,
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
for (std::string const& config : configs) {
for (std::string const& b :
- lg.ExpandCustomCommandOutputPaths(*cge, config)) {
+ this->ExpandCustomCommandOutputPaths(*cge, config)) {
if (!seen.insert(b).second) {
return false;
}
@@ -719,6 +717,7 @@ bool HasUniqueByproducts(cmLocalGenerator& lg,
return true;
}
+namespace {
bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs)
{
std::set<std::string> allOutputs;
@@ -746,7 +745,7 @@ std::string cmLocalNinjaGenerator::CreateUtilityOutput(
// In Ninja Multi-Config, we can only produce cross-config utility
// commands if all byproducts are per-config.
if (!this->GetGlobalGenerator()->IsMultiConfig() ||
- !HasUniqueByproducts(*this, byproducts, bt)) {
+ !this->HasUniqueByproducts(byproducts, bt)) {
return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts,
bt);
}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index 87d5e53..5b850f3 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -86,6 +86,9 @@ public:
cmNinjaDeps& ninjaDeps,
const std::string& config);
+ bool HasUniqueByproducts(std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt);
+
protected:
std::string ConvertToIncludeReference(
std::string const& path,
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index e4c8e4b..cea20ad 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -303,7 +303,7 @@ void cmMakefile::PrintCommandTrace(
args.reserve(lff.Arguments().size());
for (cmListFileArgument const& arg : lff.Arguments()) {
- if (expand) {
+ if (expand && arg.Delim != cmListFileArgument::Bracket) {
temp = arg.Value;
this->ExpandVariablesInString(temp);
args.push_back(temp);
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 620b8ff..49e5e4c 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -12,6 +12,7 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cm/vector>
#include "cmComputeLinkInformation.h"
@@ -1238,14 +1239,17 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
std::vector<std::string> preLinkCmdLines;
std::vector<std::string> postBuildCmdLines;
- if (config == fileConfig) {
- std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
- &preLinkCmdLines,
- &postBuildCmdLines };
-
- for (unsigned i = 0; i != 3; ++i) {
- for (cmCustomCommand const& cc : *cmdLists[i]) {
- cmCustomCommandGenerator ccg(cc, config, this->GetLocalGenerator());
+ std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
+ &preLinkCmdLines,
+ &postBuildCmdLines };
+
+ for (unsigned i = 0; i != 3; ++i) {
+ for (cmCustomCommand const& cc : *cmdLists[i]) {
+ if (config == fileConfig ||
+ this->GetLocalGenerator()->HasUniqueByproducts(cc.GetByproducts(),
+ cc.GetBacktrace())) {
+ cmCustomCommandGenerator ccg(cc, fileConfig, this->GetLocalGenerator(),
+ true, config);
localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
std::transform(ccByproducts.begin(), ccByproducts.end(),
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 74fca5c..5948911 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1279,21 +1279,6 @@ if(BUILD_TESTING)
set_property(TEST CMakeTestAllGenerators PROPERTY RUN_SERIAL 1)
endif()
- if(NOT DEFINED CTEST_RUN_CMakeTestMultipleConfigures)
- set(CTEST_RUN_CMakeTestMultipleConfigures ON)
- endif()
-
- if(CTEST_RUN_CMakeTestMultipleConfigures)
- add_test(CMakeTestMultipleConfigures ${CMAKE_CMAKE_COMMAND}
- -D dir=${CMake_BINARY_DIR}/Tests/CMakeTestMultipleConfigures
- -D gen=${CMAKE_GENERATOR}
- -D CMake_SOURCE_DIR=${CMake_SOURCE_DIR}
- -P ${CMake_SOURCE_DIR}/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
- )
- list(APPEND TEST_BUILD_DIRS
- "${CMake_BINARY_DIR}/Tests/CMakeTestMultipleConfigures")
- endif()
-
if(NOT CMake_TEST_EXTERNAL_CMAKE)
add_test(LoadedCommandOneConfig ${CMAKE_CTEST_COMMAND}
--build-and-test
diff --git a/Tests/CMakeTestMultipleConfigures/RunCMake.cmake b/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
deleted file mode 100644
index a79bfcb..0000000
--- a/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
+++ /dev/null
@@ -1,165 +0,0 @@
-if(NOT DEFINED CMake_SOURCE_DIR)
- message(FATAL_ERROR "CMake_SOURCE_DIR not defined")
-endif()
-
-if(NOT DEFINED dir)
- message(FATAL_ERROR "dir not defined")
-endif()
-
-if(NOT DEFINED gen)
- message(FATAL_ERROR "gen not defined")
-endif()
-
-# Call cmake once to get a baseline/reference output build tree: "Build".
-# Then call cmake N more times, each time making a copy of the entire
-# build tree after cmake is done configuring/generating. At the end,
-# analyze the diffs in the generated build trees. Expect no diffs.
-#
-message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
-
-set(N 7)
-
-# First setup source and binary trees:
-#
-execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
- ${dir}/Source
-)
-
-execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
- ${dir}/Build
-)
-
-execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
- ${CMake_SOURCE_DIR}/Tests/CTestTest/SmallAndFast
- ${dir}/Source
-)
-
-execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
- ${dir}/Build
-)
-
-# Patch SmallAndFast to build a .cxx executable too:
-#
-execute_process(COMMAND ${CMAKE_COMMAND} -E copy
- ${dir}/Source/echoargs.c
- ${dir}/Source/echoargs.cxx
-)
-file(APPEND "${dir}/Source/CMakeLists.txt" "\nadd_executable(echoargsCXX echoargs.cxx)\n")
-
-# Loop N times, saving a copy of the configured/generated build tree each time:
-#
-foreach(i RANGE 1 ${N})
- # Equivalent sequence of shell commands:
- #
- message(STATUS "${i}: cd Build && cmake -G \"${gen}\" ../Source && cd .. && cp -r Build b${i}")
-
- # Run cmake:
- #
- execute_process(COMMAND ${CMAKE_COMMAND} -G ${gen} ../Source
- RESULT_VARIABLE result
- OUTPUT_VARIABLE stdout
- ERROR_VARIABLE stderr
- WORKING_DIRECTORY ${dir}/Build
- )
-
- message(STATUS "result='${result}'")
- message(STATUS "stdout='${stdout}'")
- message(STATUS "stderr='${stderr}'")
- message(STATUS "")
-
- # Save this iteration of the Build directory:
- #
- execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
- ${dir}/b${i}
- )
- execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
- ${dir}/Build
- ${dir}/b${i}
- RESULT_VARIABLE result
- OUTPUT_VARIABLE stdout
- ERROR_VARIABLE stderr
- )
-
- message(STATUS "result='${result}'")
- message(STATUS "stdout='${stdout}'")
- message(STATUS "stderr='${stderr}'")
- message(STATUS "")
-endforeach()
-
-
-# Function to analyze diffs between two directories.
-# Set DIFF_EXECUTABLE before calling if 'diff' is available.
-#
-function(analyze_directory_diffs d1 d2 diff_count_var)
- set(diffs 0)
-
- message(STATUS "Analyzing directory diffs between:")
- message(STATUS " d1='${d1}'")
- message(STATUS " d2='${d2}'")
-
- if(NOT "${d1}" STREQUAL "" AND NOT "${d2}" STREQUAL "")
- message(STATUS "info: analyzing directories")
-
- file(GLOB_RECURSE files1 RELATIVE "${d1}" "${d1}/*")
- file(GLOB_RECURSE files2 RELATIVE "${d2}" "${d2}/*")
-
- if("${files1}" STREQUAL "${files2}")
- message(STATUS "info: file lists the same")
- #message(STATUS " files='${files1}'")
-
- foreach(f ${files1})
- execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
- ${d1}/${f}
- ${d2}/${f}
- RESULT_VARIABLE result
- OUTPUT_VARIABLE stdout
- ERROR_VARIABLE stderr
- )
- if(result STREQUAL 0)
- #message(STATUS "info: file '${f}' the same")
- else()
- math(EXPR diffs "${diffs} + 1")
- message(STATUS "warning: file '${f}' differs from d1 to d2")
- file(READ "${d1}/${f}" f1contents)
- message(STATUS "contents of file '${d1}/${f}'
-[===[${f1contents}]===]")
- file(READ "${d2}/${f}" f2contents)
- message(STATUS "contents of file '${d2}/${f}'
-[===[${f2contents}]===]")
- if(DIFF_EXECUTABLE)
- message(STATUS "diff of files '${d1}/${f}' '${d2}/${f}'")
- message(STATUS "[====[")
- execute_process(COMMAND ${DIFF_EXECUTABLE} "${d1}/${f}" "${d2}/${f}")
- message(STATUS "]====]")
- endif()
- endif()
- endforeach()
- else()
- math(EXPR diffs "${diffs} + 1")
- message(STATUS "warning: file *lists* differ - some files exist in d1/not-d2 or not-d1/d2...")
- message(STATUS " files1='${files1}'")
- message(STATUS " files2='${files2}'")
- endif()
- endif()
-
- set(${diff_count_var} ${diffs} PARENT_SCOPE)
-endfunction()
-
-
-# Analyze diffs between b1:b2, b2:b3, b3:b4, b4:b5 ... bN-1:bN.
-# Expect no diffs.
-#
-find_program(DIFF_EXECUTABLE diff)
-set(total_diffs 0)
-
-foreach(i RANGE 2 ${N})
- math(EXPR prev "${i} - 1")
- set(count 0)
- analyze_directory_diffs(${dir}/b${prev} ${dir}/b${i} count)
- message(STATUS "diff count='${count}'")
- message(STATUS "")
- math(EXPR total_diffs "${total_diffs} + ${count}")
-endforeach()
-
-message(STATUS "CMAKE_COMMAND='${CMAKE_COMMAND}'")
-message(STATUS "total_diffs='${total_diffs}'")
diff --git a/Tests/CMakeTests/ListTest.cmake.in b/Tests/CMakeTests/ListTest.cmake.in
index 785f41d..76737e5 100644
--- a/Tests/CMakeTests/ListTest.cmake.in
+++ b/Tests/CMakeTests/ListTest.cmake.in
@@ -142,9 +142,8 @@ set(Find-List-Only-STDERR "three")
set(Insert-List-Only-STDERR "at least three")
set(Length-List-Only-STDERR "two")
set(Remove_At-List-Only-STDERR "at least two")
-set(Remove_Item-List-Only-STDERR "two or more")
-foreach(cmd IN ITEMS Find Get Insert Length Remove_At Remove_Item)
+foreach(cmd IN ITEMS Find Get Insert Length Remove_At)
string(TOUPPER ${cmd} cmd_upper)
set(${cmd}-List-Only-RESULT 1)
set(${cmd}-List-Only-STDERR ".*CMake Error at List-${cmd}-List-Only.cmake:1 \\(list\\):.*list sub-command ${cmd_upper} requires ${${cmd}-List-Only-STDERR} arguments.*")
diff --git a/Tests/Fuzzing/README.rst b/Tests/Fuzzing/README.rst
new file mode 100644
index 0000000..a869f9c
--- /dev/null
+++ b/Tests/Fuzzing/README.rst
@@ -0,0 +1,8 @@
+The fuzzers in this directory are run continuously through OSS-fuzz.
+All fuzzers are implemented by way of the `libFuzzer engine`_.
+
+The link to the OSS-fuzz integration can be found here: (pending)
+All email addresses in the `project.yaml` file on OSS-fuzz will have access
+to detailed bug reports and will be notified via email if/when bugs are found.
+
+.. _`libFuzzer Engine`: https://llvm.org/docs/LibFuzzer.html
diff --git a/Tests/Fuzzing/xml_parser_fuzzer.cc b/Tests/Fuzzing/xml_parser_fuzzer.cc
new file mode 100644
index 0000000..1faa918
--- /dev/null
+++ b/Tests/Fuzzing/xml_parser_fuzzer.cc
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cmXMLParser.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ char test_file[] = "libfuzzer.xml";
+
+ FILE* fp = fopen(test_file, "wb");
+ if (!fp)
+ return 0;
+ fwrite(data, size, 1, fp);
+ fclose(fp);
+
+ cmXMLParser parser;
+ if (!parser.ParseFile(test_file)) {
+ return 1;
+ }
+
+ remove(test_file);
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index d980a52..d4c19c7 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -67,13 +67,7 @@ else()
endif()
# Test escaping of special characters in include directory paths.
-set(special_chars "~@&{}()'")
-if(NOT (CMAKE_GENERATOR STREQUAL "NMake Makefiles" AND
- "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" AND
- "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 13.0))
- # NMake from VS 6 mistakes '!' in a path after a line continuation for a directive.
- string(APPEND special_chars "!")
-endif()
+set(special_chars "~@&{}()!'")
if(NOT CMAKE_GENERATOR MATCHES "(Unix|MinGW|MSYS) Makefiles")
# when compiler is used for dependencies, special characters for make are not escaped
string(APPEND special_chars "%")
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index a8b6584..c76c92d 100644
--- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -1 +1 @@
-^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
+^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
diff --git a/Tests/RunCMake/CommandLine/trace-expand.cmake b/Tests/RunCMake/CommandLine/trace-expand.cmake
index e69de29..24da02a 100644
--- a/Tests/RunCMake/CommandLine/trace-expand.cmake
+++ b/Tests/RunCMake/CommandLine/trace-expand.cmake
@@ -0,0 +1 @@
+set(a [[\B]])
diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
new file mode 100644
index 0000000..887da0f
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
@@ -0,0 +1,19 @@
+file(TIMESTAMP "${STAMP_DIR}/proj1-configure" PROJ1_CONFIGURE_TIMESTAMP_AFTER "%s")
+# When BUILD_ALWAYS is set, the build stamp is never created.
+file(TIMESTAMP "${STAMP_DIR}/proj2-configure" PROJ2_CONFIGURE_TIMESTAMP_AFTER "%s")
+file(TIMESTAMP "${STAMP_DIR}/proj2-build" PROJ2_BUILD_TIMESTAMP_AFTER "%s")
+
+if(NOT PROJ1_CONFIGURE_TIMESTAMP_BEFORE EQUAL PROJ1_CONFIGURE_TIMESTAMP_AFTER)
+ set(RunCMake_TEST_FAILED "Unexpected rebuild of proj1 configure step (${PROJ1_CONFIGURE_TIMESTAMP_BEFORE} != ${PROJ1_CONFIGURE_TIMESTAMP_AFTER})")
+ return()
+endif()
+
+if(NOT PROJ2_CONFIGURE_TIMESTAMP_BEFORE EQUAL PROJ2_CONFIGURE_TIMESTAMP_AFTER)
+ set(RunCMake_TEST_FAILED "Unexpected rebuild of proj2 configure step (${PROJ2_CONFIGURE_TIMESTAMP_BEFORE} != ${PROJ2_CONFIGURE_TIMESTAMP_AFTER})")
+ return()
+endif()
+
+if(PROJ2_BUILD_TIMESTAMP_BEFORE EQUAL PROJ2_BUILD_TIMESTAMP_AFTER)
+ set(RunCMake_TEST_FAILED "proj2 build step did not rebuild (${PROJ2_BUILD_TIMESTAMP_BEFORE} != ${PROJ2_BUILD_TIMESTAMP_AFTER})")
+ return()
+endif()
diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake
new file mode 100644
index 0000000..c86a60e
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake
@@ -0,0 +1,28 @@
+include(ExternalProject)
+
+# Given this setup, on the first build, both configure steps and both build
+# steps will run. On a noop rebuild, only the build steps will run. Without
+# CONFIGURE_HANDLED_BY_BUILD, the configure step of proj2 would also run on a
+# noop rebuild.
+
+ExternalProject_Add(proj1
+ DOWNLOAD_COMMAND ""
+ SOURCE_DIR ""
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something"
+ # file(TIMESTAMP) gives back the timestamp in seconds so we sleep a second to
+ # make sure we get a different timestamp on the stamp file
+ BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1
+ INSTALL_COMMAND ""
+ BUILD_ALWAYS ON
+ STAMP_DIR "stamp"
+)
+ExternalProject_Add(proj2
+ DOWNLOAD_COMMAND ""
+ SOURCE_DIR ""
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something"
+ BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1
+ INSTALL_COMMAND ""
+ CONFIGURE_HANDLED_BY_BUILD ON
+ DEPENDS proj1
+ STAMP_DIR "stamp"
+)
diff --git a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
index 598671f..22b8d24 100644
--- a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
@@ -151,3 +151,33 @@ endif()
if(doSubstitutionTest)
__ep_test_with_build(Substitutions)
endif()
+
+function(__ep_test_CONFIGURE_HANDLED_BY_BUILD)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CONFIGURE_HANDLED_BY_BUILD-build)
+ run_cmake(CONFIGURE_HANDLED_BY_BUILD)
+
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(BUILD_CONFIG --config Debug)
+ set(STAMP_DIR "${RunCMake_TEST_BINARY_DIR}/stamp/Debug")
+ else()
+ set(BUILD_CONFIG "")
+ set(STAMP_DIR "${RunCMake_TEST_BINARY_DIR}/stamp")
+ endif()
+
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(CONFIGURE_HANDLED_BY_BUILD-build ${CMAKE_COMMAND} --build . ${BUILD_CONFIG})
+
+ # Calculate timestamps before rebuilding so we can compare before and after in
+ # CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
+
+ file(TIMESTAMP "${STAMP_DIR}/proj1-configure" PROJ1_CONFIGURE_TIMESTAMP_BEFORE "%s")
+ # When BUILD_ALWAYS is set, the build stamp is never created.
+ file(TIMESTAMP "${STAMP_DIR}/proj2-configure" PROJ2_CONFIGURE_TIMESTAMP_BEFORE "%s")
+ file(TIMESTAMP "${STAMP_DIR}/proj2-build" PROJ2_BUILD_TIMESTAMP_BEFORE "%s")
+
+ run_cmake_command(CONFIGURE_HANDLED_BY_BUILD-rebuild ${CMAKE_COMMAND} --build . ${BUILD_CONFIG})
+endfunction()
+
+if(NOT RunCMake_GENERATOR MATCHES "Visual Studio 9 ")
+ __ep_test_CONFIGURE_HANDLED_BY_BUILD()
+endif()
diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index 2bb2765..ae3d179 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -24,6 +24,7 @@ function(check_python case)
file(GLOB index ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply/index-*.json)
execute_process(
COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/${case}-check.py" "${index}" "${CMAKE_CXX_COMPILER_ID}"
+ "${RunCMake_TEST_BINARY_DIR}"
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_VARIABLE output
@@ -62,3 +63,4 @@ endfunction()
run_object(codemodel-v2)
run_object(cache-v2)
run_object(cmakeFiles-v1)
+run_object(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
new file mode 100644
index 0000000..ce38461
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+ query
+ query/client-foo
+ query/client-foo/query.json
+ reply
+ reply/index-[0-9.T-]+.json
+ reply/toolchains-v1-[0-9a-f]+.json
+ )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake
new file mode 100644
index 0000000..ca62edf
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake
@@ -0,0 +1,4 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
+{ "requests": [ { "kind": "toolchains", "version" : 1 } ] }
+]])
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake
new file mode 100644
index 0000000..4676dd8
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+ query
+ query/client-foo
+ query/client-foo/toolchains-v1
+ reply
+ reply/index-[0-9.T-]+.json
+ reply/toolchains-v1-[0-9a-f]+.json
+ )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake
new file mode 100644
index 0000000..7edff93
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/toolchains-v1" "")
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake
new file mode 100644
index 0000000..8e83758
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake
@@ -0,0 +1,10 @@
+set(expect
+ query
+ query/toolchains-v1
+ reply
+ reply/index-[0-9.T-]+.json
+ reply/toolchains-v1-[0-9a-f]+.json
+ )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake
new file mode 100644
index 0000000..2db73a1
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/toolchains-v1" "")
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-check.py b/Tests/RunCMake/FileAPI/toolchains-v1-check.py
new file mode 100644
index 0000000..a0e50c2
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-check.py
@@ -0,0 +1,86 @@
+from check_index import *
+import os
+
+class ExpectedVar(object):
+ def __init__(self, name):
+ self.name = name
+
+class ExpectedList(object):
+ def __init__(self, name):
+ self.name = name
+
+EXPECTED_TOOLCHAIN = {
+ "language": "CXX",
+ "compiler": {
+ "path": ExpectedVar("CMAKE_CXX_COMPILER"),
+ "id": ExpectedVar("CMAKE_CXX_COMPILER_ID"),
+ "version": ExpectedVar("CMAKE_CXX_COMPILER_VERSION"),
+ "target": ExpectedVar("CMAKE_CXX_COMPILER_TARGET"),
+ "implicit": {
+ "includeDirectories": \
+ ExpectedList("CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES"),
+ "linkDirectories": \
+ ExpectedList("CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES"),
+ "linkFrameworkDirectories": \
+ ExpectedList(
+ "CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"),
+ "linkLibraries": \
+ ExpectedList("CMAKE_CXX_IMPLICIT_LINK_LIBRARIES"),
+ }
+ },
+ "sourceFileExtensions": \
+ ExpectedList("CMAKE_CXX_SOURCE_FILE_EXTENSIONS"),
+}
+
+def check_objects(o):
+ assert is_list(o)
+ assert len(o) == 1
+ check_index_object(o[0], "toolchains", 1, 0, check_object_toolchains)
+
+def check_object_toolchains(o):
+ assert sorted(o.keys()) == ["kind", "toolchains", "version"]
+ # The "kind" and "version" members are handled by check_index_object.
+ toolchains = o["toolchains"]
+ assert is_list(toolchains)
+
+ # Other platform-specific toolchains may exist (like RC on Windows).
+ has_cxx_toolchain = False
+ for toolchain in toolchains:
+ assert is_dict(toolchain)
+ assert "language" in toolchain
+ if toolchain["language"] == "CXX":
+ check_object_toolchain(toolchain, EXPECTED_TOOLCHAIN)
+ has_cxx_toolchain = True
+
+ assert has_cxx_toolchain
+
+def check_object_toolchain(o, expected):
+ expected_keys = [
+ key for (key, value) in expected.items()
+ if is_string(value) or is_dict(value)
+ or (type(value) in (ExpectedVar, ExpectedList)
+ and variables[value.name]["defined"])]
+ assert sorted(o.keys()) == sorted(expected_keys)
+
+ for key in expected_keys:
+ value = expected[key]
+ if is_string(value):
+ assert o[key] == value
+ elif is_dict(value):
+ check_object_toolchain(o[key], value)
+ elif type(value) == ExpectedVar:
+ assert o[key] == variables[value.name]["value"]
+ elif type(value) == ExpectedList:
+ expected_items = filter(
+ None, variables[value.name]["value"].split(";"))
+ check_list_match(lambda a, b: a == b, o[key], expected_items)
+ else:
+ assert False
+
+with open(os.path.join(sys.argv[3], "toolchain_variables.json")) as f:
+ variables = json.load(f)
+
+assert is_dict(variables)
+assert is_dict(index)
+assert sorted(index.keys()) == ["cmake", "objects", "reply"]
+check_objects(index["objects"])
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1.cmake b/Tests/RunCMake/FileAPI/toolchains-v1.cmake
new file mode 100644
index 0000000..367aade
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1.cmake
@@ -0,0 +1,22 @@
+enable_language(CXX)
+
+set(variable_suffixes
+ COMPILER COMPILER_ID COMPILER_VERSION COMPILER_TARGET
+ IMPLICIT_INCLUDE_DIRECTORIES IMPLICIT_LINK_DIRECTORIES
+ IMPLICIT_LINK_FRAMEWORK_DIRECTORIES IMPLICIT_LINK_LIBRARIES
+ SOURCE_FILE_EXTENSIONS)
+set(language CXX)
+set(json "{}")
+
+foreach(variable_suffix ${variable_suffixes})
+ set(variable "CMAKE_${language}_${variable_suffix}")
+ string(JSON json SET "${json}" "${variable}" "{}")
+ if(DEFINED "${variable}")
+ string(JSON json SET "${json}" "${variable}" "defined" "true")
+ string(JSON json SET "${json}" "${variable}" "value" "\"${${variable}}\"")
+ else()
+ string(JSON json SET "${json}" "${variable}" "defined" "false")
+ endif()
+endforeach()
+
+file(WRITE ${CMAKE_BINARY_DIR}/toolchain_variables.json "${json}")
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt
new file mode 100644
index 0000000..fad923a
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt
@@ -0,0 +1,2 @@
+Running post-build command with Debug
+Generating Debug\.txt
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt
new file mode 100644
index 0000000..485a52c
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt
@@ -0,0 +1,3 @@
+Running post-build command with Release
+Generating out\.txt with Release
+Generating Release\.txt
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake b/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake
new file mode 100644
index 0000000..5fcff74
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_executable(Exe main.c)
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Running post-build command with $<CONFIG>")
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating out.txt with $<CONFIG>" BYPRODUCTS out.txt)
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating $<CONFIG>.txt" BYPRODUCTS $<CONFIG>.txt)
diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
index dc2db57..480d628 100644
--- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
@@ -187,6 +187,12 @@ run_ninja(SimpleCrossConfigs clean-all-in-release-graph build-Release.ninja clea
run_cmake_build(SimpleCrossConfigs all-all-in-release-graph Release all:all)
run_cmake_build(SimpleCrossConfigs all-relwithdebinfo-in-release-graph Release all:RelWithDebInfo)
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostBuild-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(PostBuild)
+run_cmake_build(PostBuild release Release Exe)
+run_cmake_build(PostBuild debug-in-release-graph Release Exe:Debug)
+
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Framework-build)
set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
run_cmake_configure(Framework)
diff --git a/Tests/RunCMake/cmake_path/HASH.cmake b/Tests/RunCMake/cmake_path/HASH.cmake
index dfcf2b2..eb04f7f 100644
--- a/Tests/RunCMake/cmake_path/HASH.cmake
+++ b/Tests/RunCMake/cmake_path/HASH.cmake
@@ -14,11 +14,6 @@ set (path1 "a///b/c/../d")
cmake_path(HASH path1 hash1)
set (path2 "a/b////d")
cmake_path(HASH path2 hash2)
-if (hash1 STREQUAL hash2)
- list (APPEND errors "'hash values equal for '${path1}' and '${path2}'")
-endif()
-cmake_path(HASH path1 hash1 NORMALIZE)
-cmake_path(HASH path2 NORMALIZE hash2)
if (NOT hash1 STREQUAL hash2)
list (APPEND errors "'hash values not equal for '${path1}' and '${path2}'")
endif()
diff --git a/Tests/RunCMake/cmake_path/IS_PREFIX.cmake b/Tests/RunCMake/cmake_path/IS_PREFIX.cmake
index 53da93b..9160dab 100644
--- a/Tests/RunCMake/cmake_path/IS_PREFIX.cmake
+++ b/Tests/RunCMake/cmake_path/IS_PREFIX.cmake
@@ -18,5 +18,10 @@ if (NOT output)
list (APPEND errors "'${path} is not prefix of 'a/b/d/e'")
endif()
+set(path "/a/b/..")
+cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE output)
+if (NOT output)
+ list (APPEND errors "'${path} is not prefix of '/a/c/../b'")
+endif()
check_errors (IS_PREFIX ${errors})
diff --git a/Tests/RunCMake/install/FILES-RENAME-all-check.cmake b/Tests/RunCMake/install/FILES-RENAME-all-check.cmake
new file mode 100644
index 0000000..7e9b103
--- /dev/null
+++ b/Tests/RunCMake/install/FILES-RENAME-all-check.cmake
@@ -0,0 +1 @@
+check_installed([[^src;src/script_Debug\.ps]])
diff --git a/Tests/RunCMake/install/FILES-RENAME-bad-result.txt b/Tests/RunCMake/install/FILES-RENAME-bad-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/FILES-RENAME-bad-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt b/Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt
new file mode 100644
index 0000000..9844158
--- /dev/null
+++ b/Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<NOTAGENEX>
+
+ Expression did not evaluate to a known generator expression
diff --git a/Tests/RunCMake/install/FILES-RENAME-bad.cmake b/Tests/RunCMake/install/FILES-RENAME-bad.cmake
new file mode 100644
index 0000000..5be0bb2
--- /dev/null
+++ b/Tests/RunCMake/install/FILES-RENAME-bad.cmake
@@ -0,0 +1,4 @@
+install(FILES empty.c
+ DESTINATION mybin
+ RENAME $<NOTAGENEX>
+ )
diff --git a/Tests/RunCMake/install/FILES-RENAME.cmake b/Tests/RunCMake/install/FILES-RENAME.cmake
new file mode 100644
index 0000000..5896e64
--- /dev/null
+++ b/Tests/RunCMake/install/FILES-RENAME.cmake
@@ -0,0 +1,4 @@
+install(FILES script.bat
+ DESTINATION src
+ RENAME script_$<CONFIG>.ps
+ )
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index d64d88b..b067b3a 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -74,6 +74,7 @@ run_cmake(SkipInstallRulesNoWarning2)
run_cmake(DIRECTORY-DIRECTORY-bad)
run_cmake(DIRECTORY-DESTINATION-bad)
run_cmake(FILES-DESTINATION-bad)
+run_cmake(FILES-RENAME-bad)
run_cmake(TARGETS-DESTINATION-bad)
run_cmake(EXPORT-OldIFace)
run_cmake(EXPORT-UnknownExport)
@@ -91,6 +92,10 @@ run_cmake(TARGETS-NAMELINK_COMPONENT-bad-exc)
run_cmake(FILES-DESTINATION-TYPE)
run_cmake(DIRECTORY-DESTINATION-TYPE)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug")
+run_install_test(FILES-RENAME)
+unset(RunCMake_TEST_OPTIONS)
+
if(APPLE)
run_cmake(TARGETS-Apple-Defaults)
endif()
diff --git a/Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake b/Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake
new file mode 100644
index 0000000..f69c024
--- /dev/null
+++ b/Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake
@@ -0,0 +1,5 @@
+set(ls "a" "b" "c")
+list(REMOVE_ITEM ls alpha)
+if (NOT ls STREQUAL "a;b;c")
+ message(FATAL_ERROR "list(REMOVE_ITEM) modified for empty item")
+endif ()
diff --git a/Tests/RunCMake/list/RunCMakeTest.cmake b/Tests/RunCMake/list/RunCMakeTest.cmake
index b4a91bc..c11891c 100644
--- a/Tests/RunCMake/list/RunCMakeTest.cmake
+++ b/Tests/RunCMake/list/RunCMakeTest.cmake
@@ -30,6 +30,7 @@ run_cmake(FILTER-NotList)
run_cmake(REMOVE_AT-NotList)
run_cmake(REMOVE_DUPLICATES-NotList)
run_cmake(REMOVE_ITEM-NotList)
+run_cmake(REMOVE_ITEM-NoItemArg)
run_cmake(REVERSE-NotList)
run_cmake(SORT-NotList)