summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/install.rst5
-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/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/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst5
-rw-r--r--Modules/CMakeDetermineCCompiler.cmake5
-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--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-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--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/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/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
47 files changed, 933 insertions, 179 deletions
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/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/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/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/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/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 d439eeb..edd70bd 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 20210113)
+set(CMake_VERSION_PATCH 20210115)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
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/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/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/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)