summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/configure_hip5.5_radeon.cmake (renamed from .gitlab/ci/configure_hip4.2_radeon.cmake)0
-rw-r--r--.gitlab/ci/docker/hip4.2/Dockerfile7
-rwxr-xr-x.gitlab/ci/docker/hip4.2/install_deps.sh13
-rw-r--r--.gitlab/ci/docker/hip5.5/Dockerfile28
-rw-r--r--.gitlab/ci/docker/hip5.5/deps_packages.lst4
-rw-r--r--.gitlab/ci/docker/hip5.5/docker-clean0
-rw-r--r--.gitlab/ci/docker/hip5.5/dpkg-exclude21
-rwxr-xr-x.gitlab/ci/docker/hip5.5/install_deps.sh5
-rw-r--r--.gitlab/os-linux.yml10
-rw-r--r--Help/command/cmake_file_api.rst78
-rw-r--r--Help/manual/cmake-commands.7.rst1
-rw-r--r--Help/manual/cmake-file-api.7.rst6
-rw-r--r--Help/manual/cmake-properties.7.rst2
-rw-r--r--Help/prop_test/TIMEOUT.rst3
-rw-r--r--Help/prop_test/TIMEOUT_AFTER_MATCH.rst2
-rw-r--r--Help/prop_test/TIMEOUT_SIGNAL_GRACE_PERIOD.rst14
-rw-r--r--Help/prop_test/TIMEOUT_SIGNAL_NAME.rst41
-rw-r--r--Help/release/dev/ctest-timeout-signal.rst7
-rw-r--r--Help/release/dev/file-api-query-command.rst6
-rw-r--r--Modules/FindOpenACC.cmake4
-rw-r--r--Modules/FindPython.cmake24
-rw-r--r--Modules/FindPython/Support.cmake12
-rw-r--r--Modules/FindPython2.cmake20
-rw-r--r--Modules/FindPython3.cmake24
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx7
-rw-r--r--Source/CTest/cmCTestRunTest.cxx36
-rw-r--r--Source/CTest/cmCTestRunTest.h11
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx61
-rw-r--r--Source/CTest/cmCTestTestHandler.h15
-rw-r--r--Source/CTest/cmProcess.cxx23
-rw-r--r--Source/CTest/cmProcess.h18
-rw-r--r--Source/cmCommands.cxx3
-rw-r--r--Source/cmFileAPI.cxx42
-rw-r--r--Source/cmFileAPI.h33
-rw-r--r--Source/cmFileAPICommand.cxx170
-rw-r--r--Source/cmFileAPICommand.h13
-rw-r--r--Source/cmLocalGenerator.cxx11
-rw-r--r--Source/cmUVProcessChain.cxx248
-rw-r--r--Source/cmUVProcessChain.h13
-rw-r--r--Source/cmake.h4
-rw-r--r--Tests/CMakeLib/testUVProcessChain.cxx70
-rw-r--r--Tests/CMakeLib/testUVProcessChainHelper.cxx9
-rw-r--r--Tests/RunCMake/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake29
-rw-r--r--Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt5
-rw-r--r--Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt4
-rw-r--r--Tests/RunCMake/CTestTimeout/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake58
-rw-r--r--Tests/RunCMake/CTestTimeout/Signal-check.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeout/Signal-stdout.txt6
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt3
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt3
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt6
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt3
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt4
-rw-r--r--Tests/RunCMake/CTestTimeout/TestTimeout.c47
-rw-r--r--Tests/RunCMake/FileAPI/ProjectQueryBad-result.txt1
-rw-r--r--Tests/RunCMake/FileAPI/ProjectQueryBad-stderr.txt36
-rw-r--r--Tests/RunCMake/FileAPI/ProjectQueryBad.cmake42
-rw-r--r--Tests/RunCMake/FileAPI/ProjectQueryGood-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/ProjectQueryGood.cmake8
-rw-r--r--Tests/RunCMake/FileAPI/RunCMakeTest.cmake2
-rw-r--r--Utilities/IWYU/mapping.imp2
75 files changed, 1352 insertions, 129 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6e0d01a..297afda 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -314,9 +314,9 @@ t:cuda11.8-minimal-ninja:
variables:
CMAKE_CI_NO_MR: "true"
-t:hip4.2-radeon:
+t:hip5.5-radeon:
extends:
- - .hip4.2_radeon
+ - .hip5.5_radeon
- .cmake_test_linux_release
- .linux_x86_64_tags_radeon
- .run_dependent
diff --git a/.gitlab/ci/configure_hip4.2_radeon.cmake b/.gitlab/ci/configure_hip5.5_radeon.cmake
index 58036b0..58036b0 100644
--- a/.gitlab/ci/configure_hip4.2_radeon.cmake
+++ b/.gitlab/ci/configure_hip5.5_radeon.cmake
diff --git a/.gitlab/ci/docker/hip4.2/Dockerfile b/.gitlab/ci/docker/hip4.2/Dockerfile
deleted file mode 100644
index 563e94f..0000000
--- a/.gitlab/ci/docker/hip4.2/Dockerfile
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM rocm/dev-ubuntu-20.04:4.2
-MAINTAINER Brad King <brad.king@kitware.com>
-
-ENV PATH="/opt/rocm/bin:$PATH"
-
-COPY install_deps.sh /root/install_deps.sh
-RUN sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/hip4.2/install_deps.sh b/.gitlab/ci/docker/hip4.2/install_deps.sh
deleted file mode 100755
index 2b45bc9..0000000
--- a/.gitlab/ci/docker/hip4.2/install_deps.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-
-set -e
-
-apt-get update
-
-# Install development tools.
-apt-get install -y --no-install-recommends \
- g++ \
- curl \
- git
-
-apt-get clean
diff --git a/.gitlab/ci/docker/hip5.5/Dockerfile b/.gitlab/ci/docker/hip5.5/Dockerfile
new file mode 100644
index 0000000..2deb3c6
--- /dev/null
+++ b/.gitlab/ci/docker/hip5.5/Dockerfile
@@ -0,0 +1,28 @@
+# syntax=docker/dockerfile:1
+
+ARG BASE_IMAGE=rocm/dev-ubuntu-22.04:5.5
+
+FROM ${BASE_IMAGE} AS apt-cache
+# Populate APT cache w/ the fresh metadata and prefetch packages.
+# Use an empty `docker-clean` file to "hide" the image-provided
+# file to disallow removing packages after `apt-get` operations.
+RUN --mount=type=tmpfs,target=/var/log \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ apt-get update \
+ && apt-get --download-only -y install $(grep -h '^[^#]\+$' /root/*.lst)
+
+FROM ${BASE_IMAGE}
+MAINTAINER Brad King <brad.king@kitware.com>
+
+ENV PATH="/opt/rocm/bin:$PATH"
+
+RUN --mount=type=bind,source=install_deps.sh,target=/root/install_deps.sh \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ --mount=type=bind,source=dpkg-exclude,target=/etc/dpkg/dpkg.cfg.d/exclude \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=cache,from=apt-cache,source=/var/lib/apt/lists,target=/var/lib/apt/lists \
+ --mount=type=cache,from=apt-cache,source=/var/cache/apt,target=/var/cache/apt,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/hip5.5/deps_packages.lst b/.gitlab/ci/docker/hip5.5/deps_packages.lst
new file mode 100644
index 0000000..9847925
--- /dev/null
+++ b/.gitlab/ci/docker/hip5.5/deps_packages.lst
@@ -0,0 +1,4 @@
+# Install development tools.
+g++
+curl
+git
diff --git a/.gitlab/ci/docker/hip5.5/docker-clean b/.gitlab/ci/docker/hip5.5/docker-clean
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.gitlab/ci/docker/hip5.5/docker-clean
diff --git a/.gitlab/ci/docker/hip5.5/dpkg-exclude b/.gitlab/ci/docker/hip5.5/dpkg-exclude
new file mode 100644
index 0000000..60b6565
--- /dev/null
+++ b/.gitlab/ci/docker/hip5.5/dpkg-exclude
@@ -0,0 +1,21 @@
+# Drop all man pages
+path-exclude=/usr/share/man/*
+
+# Drop all info pages
+path-exclude=/usr/share/info/*
+
+# Drop all README files except from the some packages
+path-exclude=/usr/**/*README*
+path-include=/usr/share/devscripts/templates/README.mk-build-deps
+path-include=/usr/share/equivs/template/debian/README.Debian.in
+
+# Drop all translations
+path-exclude=/usr/share/locale/*/LC_MESSAGES/*.mo
+
+# Drop all documentation ...
+path-exclude=/usr/share/doc/*
+path-exclude=/usr/share/doc-base/*
+path-exclude=/usr/share/gtk-doc/*
+
+# Per package excludes
+path-exclude=/usr/share/gnupg/help.*.txt
diff --git a/.gitlab/ci/docker/hip5.5/install_deps.sh b/.gitlab/ci/docker/hip5.5/install_deps.sh
new file mode 100755
index 0000000..d1c8aed
--- /dev/null
+++ b/.gitlab/ci/docker/hip5.5/install_deps.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -e
+
+apt-get install -y $(grep '^[^#]\+$' /root/deps_packages.lst)
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index f4cc401..79217ee 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -344,19 +344,19 @@
### HIP builds
-.hip4.2:
- image: "kitware/cmake:ci-hip4.2-x86_64-2021-07-09"
+.hip5.5:
+ image: "kitware/cmake:ci-hip5.5-x86_64-2023-06-01"
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
CMAKE_ARCH: x86_64
CTEST_LABELS: "HIP"
-.hip4.2_radeon:
- extends: .hip4.2
+.hip5.5_radeon:
+ extends: .hip5.5
variables:
- CMAKE_CONFIGURATION: hip4.2_radeon
+ CMAKE_CONFIGURATION: hip5.5_radeon
CMAKE_GENERATOR: "Ninja Multi-Config"
### C++ modules
diff --git a/Help/command/cmake_file_api.rst b/Help/command/cmake_file_api.rst
new file mode 100644
index 0000000..e7ee7e7
--- /dev/null
+++ b/Help/command/cmake_file_api.rst
@@ -0,0 +1,78 @@
+cmake_file_api
+--------------
+
+.. versionadded:: 3.27
+
+Enables interacting with the :manual:`CMake file API <cmake-file-api(7)>`.
+
+.. signature::
+ cmake_file_api(QUERY ...)
+
+ The ``QUERY`` subcommand adds a file API query for the current CMake
+ invocation.
+
+ .. code-block:: cmake
+
+ cmake_file_api(
+ QUERY
+ API_VERSION <version>
+ [CODEMODEL <versions>...]
+ [CACHE <versions>...]
+ [CMAKEFILES <versions>...]
+ [TOOLCHAINS <versions>...]
+ )
+
+ The ``API_VERSION`` must always be given. Currently, the only supported
+ value for ``<version>`` is 1. See :ref:`file-api v1` for details of the
+ reply content and location.
+
+ Each of the optional keywords ``CODEMODEL``, ``CACHE``, ``CMAKEFILES`` and
+ ``TOOLCHAINS`` correspond to one of the object kinds that can be requested
+ by the project. The ``configureLog`` object kind cannot be set with this
+ command, since it must be set before CMake starts reading the top level
+ ``CMakeLists.txt`` file.
+
+ For each of the optional keywords, the ``<versions>`` list must contain one
+ or more version values of the form ``major`` or ``major.minor``, where
+ ``major`` and ``minor`` are integers. Projects should list the versions they
+ accept in their preferred order, as only the first supported value from the
+ list will be selected. The command will ignore versions with a ``major``
+ version higher than any major version it supports for that object kind.
+ It will raise an error if it encounters an invalid version number, or if none
+ of the requested versions is supported.
+
+ For each type of object kind requested, a query equivalent to a shared,
+ stateless query will be added internally. No query file will be created in
+ the file system. The reply *will* be written to the file system at
+ generation time.
+
+ It is not an error to add a query for the same thing more than once, whether
+ from query files or from multiple calls to ``cmake_file_api(QUERY)``.
+ The final set of queries will be a merged combination of all queries
+ specified on disk and queries submitted by the project.
+
+Example
+^^^^^^^
+
+A project may want to use replies from the file API at build time to implement
+some form of verification task. Instead of relying on something outside of
+CMake to create a query file, the project can use ``cmake_file_api(QUERY)``
+to request the required information for the current run. It can then create
+a custom command to run at build time, knowing that the requested information
+should always be available.
+
+.. code-block:: cmake
+
+ cmake_file_api(
+ QUERY
+ API_VERSION 1
+ CODEMODEL 2.3
+ TOOLCHAINS 1
+ )
+
+ add_custom_target(verify_project
+ COMMAND ${CMAKE_COMMAND}
+ -D BUILD_DIR=${CMAKE_BINARY_DIR}
+ -D CONFIG=$<CONFIG>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/verify_project.cmake
+ )
diff --git a/Help/manual/cmake-commands.7.rst b/Help/manual/cmake-commands.7.rst
index 0f35632..bd678b7 100644
--- a/Help/manual/cmake-commands.7.rst
+++ b/Help/manual/cmake-commands.7.rst
@@ -87,6 +87,7 @@ These commands are available only in CMake projects.
/command/add_test
/command/aux_source_directory
/command/build_command
+ /command/cmake_file_api
/command/create_test_sourcelist
/command/define_property
/command/enable_language
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 0bdb419..5f16a8b 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -23,6 +23,12 @@ of files within the API directory. API file layout versioning is
orthogonal to the versioning of `Object Kinds`_ used in replies.
This version of CMake supports only one API version, `API v1`_.
+.. versionadded:: 3.27
+ Projects may also submit queries for the current run using the
+ :command:`cmake_file_api` command.
+
+.. _`file-api v1`:
+
API v1
======
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index e17d472..4df0547 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -516,6 +516,8 @@ Properties on Tests
/prop_test/SKIP_RETURN_CODE
/prop_test/TIMEOUT
/prop_test/TIMEOUT_AFTER_MATCH
+ /prop_test/TIMEOUT_SIGNAL_GRACE_PERIOD
+ /prop_test/TIMEOUT_SIGNAL_NAME
/prop_test/WILL_FAIL
/prop_test/WORKING_DIRECTORY
diff --git a/Help/prop_test/TIMEOUT.rst b/Help/prop_test/TIMEOUT.rst
index 385539b..175c0fb 100644
--- a/Help/prop_test/TIMEOUT.rst
+++ b/Help/prop_test/TIMEOUT.rst
@@ -10,3 +10,6 @@ setting takes precedence over :variable:`CTEST_TEST_TIMEOUT`.
An explicit ``0`` value means the test has no timeout, except as
necessary to honor :option:`ctest --stop-time`.
+
+See also :prop_test:`TIMEOUT_AFTER_MATCH` and
+:prop_test:`TIMEOUT_SIGNAL_NAME`.
diff --git a/Help/prop_test/TIMEOUT_AFTER_MATCH.rst b/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
index aa17590..edee2ef 100644
--- a/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
+++ b/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
@@ -39,3 +39,5 @@ If the required resource can be controlled by CTest you should use
:prop_test:`RESOURCE_LOCK` instead of ``TIMEOUT_AFTER_MATCH``.
This property should be used when only the test itself can determine
when its required resources are available.
+
+See also :prop_test:`TIMEOUT_SIGNAL_NAME`.
diff --git a/Help/prop_test/TIMEOUT_SIGNAL_GRACE_PERIOD.rst b/Help/prop_test/TIMEOUT_SIGNAL_GRACE_PERIOD.rst
new file mode 100644
index 0000000..858be5d
--- /dev/null
+++ b/Help/prop_test/TIMEOUT_SIGNAL_GRACE_PERIOD.rst
@@ -0,0 +1,14 @@
+TIMEOUT_SIGNAL_GRACE_PERIOD
+---------------------------
+
+.. versionadded:: 3.27
+
+If the :prop_test:`TIMEOUT_SIGNAL_NAME` test property is set, this property
+specifies the number of seconds to wait for a test process to terminate after
+sending the custom signal. Otherwise, this property has no meaning.
+
+The grace period may be any real value greater than ``0.0``, but not greater
+than ``60.0``. If this property is not set, the default is ``1.0`` second.
+
+This is available only on platforms supporting POSIX signals.
+It is not available on Windows.
diff --git a/Help/prop_test/TIMEOUT_SIGNAL_NAME.rst b/Help/prop_test/TIMEOUT_SIGNAL_NAME.rst
new file mode 100644
index 0000000..6294d27
--- /dev/null
+++ b/Help/prop_test/TIMEOUT_SIGNAL_NAME.rst
@@ -0,0 +1,41 @@
+TIMEOUT_SIGNAL_NAME
+-------------------
+
+.. versionadded:: 3.27
+
+Specify a custom signal to send to a test process when its timeout is reached.
+This is available only on platforms supporting POSIX signals.
+It is not available on Windows.
+
+The name must be one of the following:
+
+ ``SIGINT``
+ Interrupt.
+
+ ``SIGQUIT``
+ Quit.
+
+ ``SIGTERM``
+ Terminate.
+
+ ``SIGUSR1``
+ User defined signal 1.
+
+ ``SIGUSR2``
+ User defined signal 2.
+
+The custom signal is sent to the test process to give it a chance
+to exit gracefully during a grace period:
+
+* If the test process created any children, it is responsible for
+ terminating them too.
+
+* The grace period length is determined by the
+ :prop_test:`TIMEOUT_SIGNAL_GRACE_PERIOD` test property.
+
+* If the test process does not terminate before the grace period ends,
+ :manual:`ctest(1)` will force termination of its entire process tree
+ via ``SIGSTOP`` and ``SIGKILL``.
+
+See also :variable:`CTEST_TEST_TIMEOUT`,
+:prop_test:`TIMEOUT`, and :prop_test:`TIMEOUT_AFTER_MATCH`.
diff --git a/Help/release/dev/ctest-timeout-signal.rst b/Help/release/dev/ctest-timeout-signal.rst
new file mode 100644
index 0000000..f182429
--- /dev/null
+++ b/Help/release/dev/ctest-timeout-signal.rst
@@ -0,0 +1,7 @@
+ctest-timeout-signal
+--------------------
+
+* The :prop_test:`TIMEOUT_SIGNAL_NAME` and
+ :prop_test:`TIMEOUT_SIGNAL_GRACE_PERIOD` test properties were added
+ to specify a POSIX signal to send to a test process when its timeout
+ is reached.
diff --git a/Help/release/dev/file-api-query-command.rst b/Help/release/dev/file-api-query-command.rst
new file mode 100644
index 0000000..66ae7d9
--- /dev/null
+++ b/Help/release/dev/file-api-query-command.rst
@@ -0,0 +1,6 @@
+file-api-query-command
+----------------------
+
+* The :command:`cmake_file_api` command was added, enabling projects to
+ add :manual:`CMake file API <cmake-file-api(7)>` queries for the current
+ CMake run.
diff --git a/Modules/FindOpenACC.cmake b/Modules/FindOpenACC.cmake
index 00e42b8..436f5ea 100644
--- a/Modules/FindOpenACC.cmake
+++ b/Modules/FindOpenACC.cmake
@@ -294,9 +294,9 @@ foreach (LANG IN ITEMS C CXX Fortran)
endif()
if(OpenACC_${LANG}_FLAGS)
set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
- INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${OpenACC_${LANG}_OPTIONS}>")
+ INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:SHELL:${OpenACC_${LANG}_FLAGS}>")
set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
- INTERFACE_LINK_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${OpenACC_${LANG}_OPTIONS}>")
+ INTERFACE_LINK_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:SHELL:${OpenACC_${LANG}_FLAGS}>")
unset(_OpenACC_${LANG}_OPTIONS)
endif()
endforeach()
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index e6f44e0..19b6c2a 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -125,38 +125,28 @@ This module will set the following variables in your project
``Python_STDLIB``
Standard platform independent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``
- or else ``sysconfig.get_path('stdlib')``.
+ Information returned by ``sysconfig.get_path('stdlib')``.
``Python_STDARCH``
Standard platform dependent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``
- or else ``sysconfig.get_path('platstdlib')``.
+ Information returned by ``sysconfig.get_path('platstdlib')``.
``Python_SITELIB``
Third-party platform independent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``
- or else ``sysconfig.get_path('purelib')``.
+ Information returned by ``sysconfig.get_path('purelib')``.
``Python_SITEARCH``
Third-party platform dependent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
- or else ``sysconfig.get_path('platlib')``.
+ Information returned by ``sysconfig.get_path('platlib')``.
``Python_SOABI``
.. versionadded:: 3.17
Extension suffix for modules.
- Information computed from ``distutils.sysconfig.get_config_var('EXT_SUFFIX')``
- or ``distutils.sysconfig.get_config_var('SOABI')`` or
- ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is
- not available, ``sysconfig.get_config_var('EXT_SUFFIX')`` or
- ``sysconfig.get_config_var('SOABI')`` are used.
+ Information computed from ``sysconfig.get_config_var('EXT_SUFFIX')`` or
+ ``sysconfig.get_config_var('SOABI')`` or
+ ``python3-config --extension-suffix``.
``Python_SOSABI``
.. versionadded:: 3.26
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 7f35e07..76d4a9b 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -500,7 +500,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
if (_${_PYTHON_PREFIX}_EXECUTABLE AND NOT CMAKE_CROSSCOMPILING)
if (NAME STREQUAL "PREFIX")
- execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))"
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))\nexcept Exception:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _values
ERROR_QUIET
@@ -517,7 +517,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
set (_scheme "posix_prefix")
endif()
execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))"
+ "import sys\ntry:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))\nexcept Exception:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _values
ERROR_QUIET
@@ -530,7 +530,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
elseif (NAME STREQUAL "SOABI")
# first step: compute SOABI form EXT_SUFFIX config variable
execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')\nexcept Exception:\n import sysconfig;sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')"
+ "import sys\ntry:\n import sysconfig\n sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')\nexcept Exception:\n from distutils import sysconfig;sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _values
ERROR_QUIET
@@ -551,7 +551,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
# second step: use SOABI or SO config variables as fallback
if (NOT _values)
execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))\nexcept Exception:\n import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))"
+ "import sys\ntry:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))\nexcept Exception:\n from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _soabi
ERROR_QUIET
@@ -592,7 +592,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
set (config_flag "LIBPL")
endif()
execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
+ "import sys\ntry:\n import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _values
ERROR_QUIET
@@ -2197,7 +2197,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
# retrieve various package installation directories
execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))"
+ "import sys\ntry:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))\nexcept Exception:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
ERROR_QUIET)
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index 0575ea5..4c7ab5c 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -112,27 +112,23 @@ This module will set the following variables in your project
``Python2_STDLIB``
Standard platform independent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``
- or else ``sysconfig.get_path('stdlib')``.
+ Information returned by ``sysconfig.get_path('stdlib')`` or else
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``.
``Python2_STDARCH``
Standard platform dependent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``
- or else ``sysconfig.get_path('platstdlib')``.
+ Information returned by ``sysconfig.get_path('platstdlib')`` or else
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``.
``Python2_SITELIB``
Third-party platform independent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``
- or else ``sysconfig.get_path('purelib')``.
+ Information returned by ``sysconfig.get_path('purelib')`` or else
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``.
``Python2_SITEARCH``
Third-party platform dependent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
- or else ``sysconfig.get_path('platlib')``.
+ Information returned by ``sysconfig.get_path('platlib')`` or else
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``.
``Python2_Compiler_FOUND``
System has the Python 2 compiler.
``Python2_COMPILER``
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index 18929b2..901565b 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -126,38 +126,28 @@ This module will set the following variables in your project
``Python3_STDLIB``
Standard platform independent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``
- or else ``sysconfig.get_path('stdlib')``.
+ Information returned by ``sysconfig.get_path('stdlib')``.
``Python3_STDARCH``
Standard platform dependent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``
- or else ``sysconfig.get_path('platstdlib')``.
+ Information returned by ``sysconfig.get_path('platstdlib')``.
``Python3_SITELIB``
Third-party platform independent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``
- or else ``sysconfig.get_path('purelib')``.
+ Information returned by ``sysconfig.get_path('purelib')``.
``Python3_SITEARCH``
Third-party platform dependent installation directory.
- Information returned by
- ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
- or else ``sysconfig.get_path('platlib')``.
+ Information returned by ``sysconfig.get_path('platlib')``.
``Python3_SOABI``
.. versionadded:: 3.17
Extension suffix for modules.
- Information computed from ``distutils.sysconfig.get_config_var('EXT_SUFFIX')``
- or ``distutils.sysconfig.get_config_var('SOABI')`` or
- ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is
- not available, ``sysconfig.get_config_var('EXT_SUFFIX')`` or
- ``sysconfig.get_config_var('SOABI')`` are used.
+ Information computed from ``sysconfig.get_config_var('EXT_SUFFIX')`` or
+ ``sysconfig.get_config_var('SOABI')`` or
+ ``python3-config --extension-suffix``.
``Python3_SOSABI``
.. versionadded:: 3.26
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index bcaf890..b01e1e7 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -232,6 +232,8 @@ add_library(
cmFileAPIConfigureLog.h
cmFileAPICMakeFiles.cxx
cmFileAPICMakeFiles.h
+ cmFileAPICommand.cxx
+ cmFileAPICommand.h
cmFileAPIToolchains.cxx
cmFileAPIToolchains.h
cmFileCopier.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index ab19633..c29a09e 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 26)
-set(CMake_VERSION_PATCH 20230604)
+set(CMake_VERSION_PATCH 20230606)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 44eccb2..7d22a87 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -634,8 +634,9 @@ void cmCTestMultiProcessHandler::FinishTestProcess(
int test = runner->GetIndex();
auto* properties = runner->GetTestProperties();
- bool testResult = runner->EndTest(this->Completed, this->Total, started);
- if (runner->TimedOutForStopTime()) {
+ cmCTestRunTest::EndTestResult testResult =
+ runner->EndTest(this->Completed, this->Total, started);
+ if (testResult.StopTimePassed) {
this->SetStopTimePassed();
}
if (started) {
@@ -646,7 +647,7 @@ void cmCTestMultiProcessHandler::FinishTestProcess(
}
}
- if (testResult) {
+ if (testResult.Passed) {
this->Passed->push_back(properties->Name);
} else if (!properties->Disabled) {
this->Failed->push_back(properties->Name);
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index cd2b230..9b62183 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -95,16 +95,15 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
}
}
-bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
+cmCTestRunTest::EndTestResult cmCTestRunTest::EndTest(size_t completed,
+ size_t total,
+ bool started)
{
this->WriteLogOutputTop(completed, total);
std::string reason;
bool passed = true;
cmProcess::State res =
started ? this->TestProcess->GetProcessStatus() : cmProcess::State::Error;
- if (res != cmProcess::State::Expired) {
- this->TimeoutIsForStopTime = false;
- }
std::int64_t retVal = this->TestProcess->GetExitValue();
bool forceFail = false;
bool forceSkip = false;
@@ -182,6 +181,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
}
} else if (res == cmProcess::State::Expired) {
outputStream << "***Timeout ";
+ if (this->TestProperties->TimeoutSignal &&
+ this->TestProcess->GetTerminationStyle() ==
+ cmProcess::Termination::Custom) {
+ outputStream << "(" << this->TestProperties->TimeoutSignal->Name << ") ";
+ }
this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
outputTestErrorsToConsole =
this->CTest->GetOutputTestOutputOnTestFailure();
@@ -344,8 +348,15 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
if (!this->NeedsToRepeat()) {
this->TestHandler->TestResults.push_back(this->TestResult);
}
+ cmCTestRunTest::EndTestResult testResult;
+ testResult.Passed = passed || skipped;
+ if (res == cmProcess::State::Expired &&
+ this->TestProcess->GetTimeoutReason() ==
+ cmProcess::TimeoutReason::StopTime) {
+ testResult.StopTimePassed = true;
+ }
this->TestProcess.reset();
- return passed || skipped;
+ return testResult;
}
bool cmCTestRunTest::StartAgain(std::unique_ptr<cmCTestRunTest> runner,
@@ -534,6 +545,19 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
this->TestResult.Name = this->TestProperties->Name;
this->TestResult.Path = this->TestProperties->Directory;
+ // Reject invalid test properties.
+ if (this->TestProperties->Error) {
+ std::string const& msg = *this->TestProperties->Error;
+ *this->TestHandler->LogFile << msg << std::endl;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, msg << std::endl);
+ this->TestResult.CompletionStatus = "Invalid Test Properties";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ this->TestResult.Output = msg;
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+ return false;
+ }
+
// Return immediately if test is disabled
if (this->TestProperties->Disabled) {
this->TestResult.CompletionStatus = "Disabled";
@@ -772,8 +796,8 @@ bool cmCTestRunTest::ForkProcess()
timeRemaining = cmDuration::zero();
}
if (!timeout || timeRemaining < *timeout) {
- this->TimeoutIsForStopTime = true;
timeout = timeRemaining;
+ this->TestProcess->SetTimeoutReason(cmProcess::TimeoutReason::StopTime);
}
if (timeout) {
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 6a507f4..fed7296 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -71,10 +71,16 @@ public:
std::string const& output,
std::string const& detail);
+ struct EndTestResult
+ {
+ bool Passed = false;
+ bool StopTimePassed = false;
+ };
+
// launch the test process, return whether it started correctly
bool StartTest(size_t completed, size_t total);
// capture and report the test results
- bool EndTest(size_t completed, size_t total, bool started);
+ EndTestResult EndTest(size_t completed, size_t total, bool started);
// Called by ctest -N to log the command string
void ComputeArguments();
@@ -90,8 +96,6 @@ public:
void FinalizeTest(bool started = true);
- bool TimedOutForStopTime() const { return this->TimeoutIsForStopTime; }
-
void SetUseAllocatedResources(bool use)
{
this->UseAllocatedResources = use;
@@ -120,7 +124,6 @@ private:
std::string GetTestPrefix(size_t completed, size_t total) const;
cmCTestTestHandler::cmCTestTestProperties* TestProperties;
- bool TimeoutIsForStopTime = false;
// Pointer back to the "parent"; the handler that invoked this test run
cmCTestTestHandler* TestHandler;
cmCTest* CTest;
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 7764f2b..6b02a5e 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -17,6 +17,10 @@
#include <sstream>
#include <utility>
+#ifndef _WIN32
+# include <csignal>
+#endif
+
#include <cm/memory>
#include <cm/string_view>
#include <cmext/algorithm>
@@ -2171,6 +2175,16 @@ void cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length,
}
}
+void cmCTestTestHandler::cmCTestTestProperties::AppendError(
+ cm::string_view err)
+{
+ if (this->Error) {
+ *this->Error = cmStrCat(*this->Error, '\n', err);
+ } else {
+ this->Error = err;
+ }
+}
+
bool cmCTestTestHandler::SetTestsProperties(
const std::vector<std::string>& args)
{
@@ -2247,6 +2261,53 @@ bool cmCTestTestHandler::SetTestsProperties(
rt.FixturesRequired.insert(lval.begin(), lval.end());
} else if (key == "TIMEOUT"_s) {
rt.Timeout = cmDuration(atof(val.c_str()));
+ } else if (key == "TIMEOUT_SIGNAL_NAME"_s) {
+#ifdef _WIN32
+ rt.AppendError("TIMEOUT_SIGNAL_NAME is not supported on Windows.");
+#else
+ std::string const& signalName = val;
+ Signal s;
+ if (signalName == "SIGINT"_s) {
+ s.Number = SIGINT;
+ } else if (signalName == "SIGQUIT"_s) {
+ s.Number = SIGQUIT;
+ } else if (signalName == "SIGTERM"_s) {
+ s.Number = SIGTERM;
+ } else if (signalName == "SIGUSR1"_s) {
+ s.Number = SIGUSR1;
+ } else if (signalName == "SIGUSR2"_s) {
+ s.Number = SIGUSR2;
+ }
+ if (s.Number) {
+ s.Name = signalName;
+ rt.TimeoutSignal = std::move(s);
+ } else {
+ rt.AppendError(cmStrCat("TIMEOUT_SIGNAL_NAME \"", signalName,
+ "\" not supported on this platform."));
+ }
+#endif
+ } else if (key == "TIMEOUT_SIGNAL_GRACE_PERIOD"_s) {
+#ifdef _WIN32
+ rt.AppendError(
+ "TIMEOUT_SIGNAL_GRACE_PERIOD is not supported on Windows.");
+#else
+ std::string const& gracePeriod = val;
+ static cmDuration minGracePeriod{ 0 };
+ static cmDuration maxGracePeriod{ 60 };
+ cmDuration gp = cmDuration(atof(gracePeriod.c_str()));
+ if (gp <= minGracePeriod) {
+ rt.AppendError(cmStrCat("TIMEOUT_SIGNAL_GRACE_PERIOD \"",
+ gracePeriod, "\" is not greater than \"",
+ minGracePeriod.count(), "\" seconds."));
+ } else if (gp > maxGracePeriod) {
+ rt.AppendError(cmStrCat("TIMEOUT_SIGNAL_GRACE_PERIOD \"",
+ gracePeriod,
+ "\" is not less than the maximum of \"",
+ maxGracePeriod.count(), "\" seconds."));
+ } else {
+ rt.TimeoutGracePeriod = gp;
+ }
+#endif
} else if (key == "COST"_s) {
rt.Cost = static_cast<float>(atof(val.c_str()));
} else if (key == "REQUIRED_FILES"_s) {
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index b7c0faf..315a5b7 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -15,6 +15,7 @@
#include <vector>
#include <cm/optional>
+#include <cm/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -119,12 +120,16 @@ public:
bool operator!=(const cmCTestTestResourceRequirement& other) const;
};
- // NOTE: This struct is Saved/Restored
- // in cmCTestTestHandler, if you add to this class
- // then you must add the new members to that code or
- // ctest -j N will break for that feature
+ struct Signal
+ {
+ int Number = 0;
+ std::string Name;
+ };
+
struct cmCTestTestProperties
{
+ void AppendError(cm::string_view err);
+ cm::optional<std::string> Error;
std::string Name;
std::string Directory;
std::vector<std::string> Args;
@@ -148,6 +153,8 @@ public:
int PreviousRuns = 0;
bool RunSerial = false;
cm::optional<cmDuration> Timeout;
+ cm::optional<Signal> TimeoutSignal;
+ cm::optional<cmDuration> TimeoutGracePeriod;
cmDuration AlternateTimeout;
int Index = 0;
// Requested number of process slots
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 780d626..269b92c 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -13,6 +13,7 @@
#include "cmCTest.h"
#include "cmCTestRunTest.h"
+#include "cmCTestTestHandler.h"
#include "cmGetPipes.h"
#include "cmStringAlgorithms.h"
#if defined(_WIN32)
@@ -274,7 +275,29 @@ void cmProcess::OnTimeoutCB(uv_timer_t* timer)
void cmProcess::OnTimeout()
{
+ bool const wasExecuting = this->ProcessState == cmProcess::State::Executing;
this->ProcessState = cmProcess::State::Expired;
+
+ // If the test process is still executing normally, and we timed out because
+ // the test timeout was reached, send the custom timeout signal, if any.
+ if (wasExecuting && this->TimeoutReason_ == TimeoutReason::Normal) {
+ cmCTestTestHandler::cmCTestTestProperties* p =
+ this->Runner->GetTestProperties();
+ if (p->TimeoutSignal) {
+ this->TerminationStyle = Termination::Custom;
+ uv_process_kill(this->Process, p->TimeoutSignal->Number);
+ if (p->TimeoutGracePeriod) {
+ this->Timeout = *p->TimeoutGracePeriod;
+ } else {
+ static const cmDuration defaultGracePeriod{ 1.0 };
+ this->Timeout = defaultGracePeriod;
+ }
+ this->StartTimer();
+ return;
+ }
+ }
+
+ this->TerminationStyle = Termination::Forced;
bool const was_still_reading = !this->ReadHandleClosed;
if (!this->ReadHandleClosed) {
this->ReadHandleClosed = true;
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 1578687..dc755eb 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -41,6 +41,14 @@ public:
// Return true if the process starts
bool StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity);
+ enum class TimeoutReason
+ {
+ Normal,
+ StopTime,
+ };
+ void SetTimeoutReason(TimeoutReason r) { this->TimeoutReason_ = r; }
+ TimeoutReason GetTimeoutReason() const { return this->TimeoutReason_; }
+
enum class State
{
Starting,
@@ -77,8 +85,17 @@ public:
return std::move(this->Runner);
}
+ enum class Termination
+ {
+ Normal,
+ Custom,
+ Forced,
+ };
+ Termination GetTerminationStyle() const { return this->TerminationStyle; }
+
private:
cm::optional<cmDuration> Timeout;
+ TimeoutReason TimeoutReason_ = TimeoutReason::Normal;
std::chrono::steady_clock::time_point StartTime;
cmDuration TotalTime;
bool ReadHandleClosed = false;
@@ -128,4 +145,5 @@ private:
std::vector<const char*> ProcessArgs;
int Id;
int64_t ExitValue;
+ Termination TerminationStyle = Termination::Normal;
};
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 27f2156..ae83b2e 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -97,6 +97,7 @@
# include "cmExportCommand.h"
# include "cmExportLibraryDependenciesCommand.h"
# include "cmFLTKWrapUICommand.h"
+# include "cmFileAPICommand.h"
# include "cmIncludeExternalMSProjectCommand.h"
# include "cmInstallProgramsCommand.h"
# include "cmLinkLibrariesCommand.h"
@@ -293,6 +294,7 @@ void GetProjectCommands(cmState* state)
state->AddBuiltinCommand("qt_wrap_ui", cmQTWrapUICommand);
state->AddBuiltinCommand("remove_definitions", cmRemoveDefinitionsCommand);
state->AddBuiltinCommand("source_group", cmSourceGroupCommand);
+ state->AddBuiltinCommand("cmake_file_api", cmFileAPICommand);
state->AddDisallowedCommand(
"export_library_dependencies", cmExportLibraryDependenciesCommand,
@@ -333,6 +335,7 @@ void GetProjectCommandsInScriptMode(cmState* state)
CM_UNEXPECTED_PROJECT_COMMAND("add_test");
CM_UNEXPECTED_PROJECT_COMMAND("aux_source_directory");
CM_UNEXPECTED_PROJECT_COMMAND("build_command");
+ CM_UNEXPECTED_PROJECT_COMMAND("cmake_file_api");
CM_UNEXPECTED_PROJECT_COMMAND("create_test_sourcelist");
CM_UNEXPECTED_PROJECT_COMMAND("define_property");
CM_UNEXPECTED_PROJECT_COMMAND("enable_language");
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 8b98916..8abb5a8 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -978,3 +978,45 @@ Json::Value cmFileAPI::ReportCapabilities()
return capabilities;
}
+
+bool cmFileAPI::AddProjectQuery(cmFileAPI::ObjectKind kind,
+ unsigned majorVersion, unsigned minorVersion)
+{
+ switch (kind) {
+ case ObjectKind::CodeModel:
+ if (majorVersion != 2 || minorVersion > CodeModelV2Minor) {
+ return false;
+ }
+ break;
+ case ObjectKind::Cache:
+ if (majorVersion != 2 || minorVersion > CacheV2Minor) {
+ return false;
+ }
+ break;
+ case ObjectKind::CMakeFiles:
+ if (majorVersion != 1 || minorVersion > CMakeFilesV1Minor) {
+ return false;
+ }
+ break;
+ case ObjectKind::Toolchains:
+ if (majorVersion != 1 || minorVersion > ToolchainsV1Minor) {
+ return false;
+ }
+ break;
+ // These cannot be requested by the project
+ case ObjectKind::ConfigureLog:
+ case ObjectKind::InternalTest:
+ return false;
+ }
+
+ Object query;
+ query.Kind = kind;
+ query.Version = majorVersion;
+ if (std::find(this->TopQuery.Known.begin(), this->TopQuery.Known.end(),
+ query) == this->TopQuery.Known.end()) {
+ this->TopQuery.Known.emplace_back(query);
+ this->QueryExists = true;
+ }
+
+ return true;
+}
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
index 6d7678f..1c13d7b 100644
--- a/Source/cmFileAPI.h
+++ b/Source/cmFileAPI.h
@@ -41,6 +41,20 @@ public:
/** Report file-api capabilities for cmake -E capabilities. */
static Json::Value ReportCapabilities();
+ // Keep in sync with ObjectKindName.
+ enum class ObjectKind
+ {
+ CodeModel,
+ ConfigureLog,
+ Cache,
+ CMakeFiles,
+ Toolchains,
+ InternalTest
+ };
+
+ bool AddProjectQuery(ObjectKind kind, unsigned majorVersion,
+ unsigned minorVersion);
+
private:
cmake* CMakeInstance;
@@ -53,17 +67,6 @@ private:
static std::vector<std::string> LoadDir(std::string const& dir);
void RemoveOldReplyFiles();
- // Keep in sync with ObjectKindName.
- enum class ObjectKind
- {
- CodeModel,
- ConfigureLog,
- Cache,
- CMakeFiles,
- Toolchains,
- InternalTest
- };
-
/** Identify one object kind and major version. */
struct Object
{
@@ -76,6 +79,14 @@ private:
}
return l.Version < r.Version;
}
+ friend bool operator==(Object const& l, Object const& r)
+ {
+ return l.Kind == r.Kind && l.Version == r.Version;
+ }
+ friend bool operator!=(Object const& l, Object const& r)
+ {
+ return !(l == r);
+ }
};
/** Represent content of a query directory. */
diff --git a/Source/cmFileAPICommand.cxx b/Source/cmFileAPICommand.cxx
new file mode 100644
index 0000000..d051c9c
--- /dev/null
+++ b/Source/cmFileAPICommand.cxx
@@ -0,0 +1,170 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPICommand.h"
+
+#include <algorithm>
+#include <array>
+#include <cctype>
+#include <cstdlib>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
+#include "cmExecutionStatus.h"
+#include "cmFileAPI.h"
+#include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSubcommandTable.h"
+#include "cmake.h"
+
+namespace {
+
+bool isCharDigit(char ch)
+{
+ return std::isdigit(static_cast<unsigned char>(ch));
+}
+
+std::string processObjectKindVersions(cmFileAPI& fileApi,
+ cmFileAPI::ObjectKind objectKind,
+ cm::string_view keyword,
+ const std::vector<std::string>& versions)
+{
+ // The "versions" vector is empty only when the keyword was not present.
+ // It is an error to provide the keyword with no versions after it, and that
+ // is enforced by the argument parser before we get here.
+ if (versions.empty()) {
+ return {};
+ }
+
+ // The first supported version listed is what we use
+ for (const std::string& ver : versions) {
+ const char* vStart = ver.c_str();
+ int majorVersion = std::atoi(vStart);
+ int minorVersion = 0;
+ std::string::size_type pos = ver.find('.');
+ if (pos != std::string::npos) {
+ vStart += pos + 1;
+ minorVersion = std::atoi(vStart);
+ }
+ if (majorVersion < 1 || minorVersion < 0) {
+ return cmStrCat("Given a malformed version \"", ver, "\" for ", keyword,
+ ".");
+ }
+ if (fileApi.AddProjectQuery(objectKind,
+ static_cast<unsigned>(majorVersion),
+ static_cast<unsigned>(minorVersion))) {
+ return {};
+ }
+ }
+ return cmStrCat("None of the specified ", keyword,
+ " versions is supported by this version of CMake.");
+}
+
+bool handleQueryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("QUERY subcommand called without required arguments.");
+ return false;
+ }
+
+ struct Arguments : public ArgumentParser::ParseResult
+ {
+ ArgumentParser::NonEmpty<std::string> ApiVersion;
+ ArgumentParser::NonEmpty<std::vector<std::string>> CodeModelVersions;
+ ArgumentParser::NonEmpty<std::vector<std::string>> CacheVersions;
+ ArgumentParser::NonEmpty<std::vector<std::string>> CMakeFilesVersions;
+ ArgumentParser::NonEmpty<std::vector<std::string>> ToolchainsVersions;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("API_VERSION"_s, &Arguments::ApiVersion)
+ .Bind("CODEMODEL"_s, &Arguments::CodeModelVersions)
+ .Bind("CACHE"_s, &Arguments::CacheVersions)
+ .Bind("CMAKEFILES"_s, &Arguments::CMakeFilesVersions)
+ .Bind("TOOLCHAINS"_s, &Arguments::ToolchainsVersions);
+
+ std::vector<std::string> unparsedArguments;
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments);
+
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
+ }
+ if (!unparsedArguments.empty()) {
+ status.SetError("QUERY subcommand given unknown argument \"" +
+ unparsedArguments.front() + "\".");
+ return false;
+ }
+
+ if (!std::all_of(arguments.ApiVersion.begin(), arguments.ApiVersion.end(),
+ isCharDigit)) {
+ status.SetError("QUERY subcommand given a non-integer API_VERSION.");
+ return false;
+ }
+ const int apiVersion = std::atoi(arguments.ApiVersion.c_str());
+ if (apiVersion != 1) {
+ status.SetError(
+ cmStrCat("QUERY subcommand given an unsupported API_VERSION \"",
+ arguments.ApiVersion,
+ "\" (the only currently supported version is 1)."));
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ cmake* cmi = mf.GetCMakeInstance();
+ cmFileAPI* fileApi = cmi->GetFileAPI();
+
+ // We want to check all keywords and report all errors, not just the first.
+ // Record each result rather than short-circuiting on the first error.
+
+ // NOTE: Double braces are needed here for compilers that don't implement the
+ // CWG 1270 revision to C++11.
+ std::array<std::string, 4> errors{
+ { processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::CodeModel,
+ "CODEMODEL"_s, arguments.CodeModelVersions),
+ processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::Cache,
+ "CACHE"_s, arguments.CacheVersions),
+ processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::CMakeFiles,
+ "CMAKEFILES"_s, arguments.CMakeFilesVersions),
+ processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::Toolchains,
+ "TOOLCHAINS"_s, arguments.ToolchainsVersions) }
+ };
+
+ if (!std::all_of(errors.begin(), errors.end(),
+ [](const std::string& s) -> bool { return s.empty(); })) {
+ std::string message("QUERY subcommand was given invalid arguments:");
+ for (const std::string& s : errors) {
+ if (!s.empty()) {
+ message = cmStrCat(message, "\n ", s);
+ }
+ }
+ status.SetError(message);
+ return false;
+ }
+
+ return true;
+}
+
+}
+
+bool cmFileAPICommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("must be called with arguments.");
+ return false;
+ }
+
+ // clang-format off
+ static cmSubcommandTable const subcommand{
+ { "QUERY"_s, handleQueryCommand }
+ };
+ // clang-format on
+
+ return subcommand(args[0], args, status);
+}
diff --git a/Source/cmFileAPICommand.h b/Source/cmFileAPICommand.h
new file mode 100644
index 0000000..28a4571
--- /dev/null
+++ b/Source/cmFileAPICommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmFileAPICommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 63b2043..7ad4023 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1201,6 +1201,17 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) {
cmSystemTools::ConvertToUnixSlashes(impDirVec[i]);
}
+
+ // The CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES are computed using
+ // try_compile in CMAKE_DETERMINE_COMPILER_ABI, but the implicit include
+ // directories are not known during that try_compile. This can be a
+ // problem when the HIP runtime include path is /usr/include because the
+ // runtime include path is always added to the userDirs and the compiler
+ // includes standard library headers via "__clang_hip_runtime_wrapper.h".
+ if (lang == "HIP" && impDirVec.size() == impDirVecOldSize &&
+ !cm::contains(impDirVec, "/usr/include")) {
+ implicitExclude.emplace("/usr/include");
+ }
}
// The Platform/UnixPaths module used to hard-code /usr/include for C, CXX,
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
index c2bb11e..ed5f38b 100644
--- a/Source/cmUVProcessChain.cxx
+++ b/Source/cmUVProcessChain.cxx
@@ -1,10 +1,16 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConfigure.h"
+
#include "cmUVProcessChain.h"
+#include <array>
#include <cassert>
+#include <csignal>
+#include <cstdio>
#include <istream> // IWYU pragma: keep
#include <iterator>
+#include <type_traits>
#include <utility>
#include <cm/memory>
@@ -425,3 +431,245 @@ bool cmUVProcessChain::Finished() const
{
return this->Data->ProcessesCompleted >= this->Data->Processes.size();
}
+
+std::pair<cmUVProcessChain::ExceptionCode, std::string>
+cmUVProcessChain::Status::GetException() const
+{
+#ifdef _WIN32
+ if ((this->ExitStatus & 0xF0000000) == 0xC0000000) {
+ // Child terminated due to exceptional behavior.
+ switch (this->ExitStatus) {
+ case STATUS_CONTROL_C_EXIT:
+ return std::make_pair(ExceptionCode::Interrupt, "User interrupt");
+
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point exception (denormal operand)");
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ return std::make_pair(ExceptionCode::Numerical, "Divide-by-zero");
+ case STATUS_FLOAT_INEXACT_RESULT:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point exception (inexact result)");
+ case STATUS_FLOAT_INVALID_OPERATION:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Invalid floating-point operation");
+ case STATUS_FLOAT_OVERFLOW:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point overflow");
+ case STATUS_FLOAT_STACK_CHECK:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point stack check failed");
+ case STATUS_FLOAT_UNDERFLOW:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point underflow");
+# ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+ case STATUS_FLOAT_MULTIPLE_FAULTS:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point exception (multiple faults)");
+# endif
+# ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+ case STATUS_FLOAT_MULTIPLE_TRAPS:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point exception (multiple traps)");
+# endif
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Integer divide-by-zero");
+ case STATUS_INTEGER_OVERFLOW:
+ return std::make_pair(ExceptionCode::Numerical, "Integer overflow");
+
+ case STATUS_DATATYPE_MISALIGNMENT:
+ return std::make_pair(ExceptionCode::Fault, "Datatype misalignment");
+ case STATUS_ACCESS_VIOLATION:
+ return std::make_pair(ExceptionCode::Fault, "Access violation");
+ case STATUS_IN_PAGE_ERROR:
+ return std::make_pair(ExceptionCode::Fault, "In-page error");
+ case STATUS_INVALID_HANDLE:
+ return std::make_pair(ExceptionCode::Fault, "Invalid handle");
+ case STATUS_NONCONTINUABLE_EXCEPTION:
+ return std::make_pair(ExceptionCode::Fault,
+ "Noncontinuable exception");
+ case STATUS_INVALID_DISPOSITION:
+ return std::make_pair(ExceptionCode::Fault, "Invalid disposition");
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ return std::make_pair(ExceptionCode::Fault, "Array bounds exceeded");
+ case STATUS_STACK_OVERFLOW:
+ return std::make_pair(ExceptionCode::Fault, "Stack overflow");
+
+ case STATUS_ILLEGAL_INSTRUCTION:
+ return std::make_pair(ExceptionCode::Illegal, "Illegal instruction");
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ return std::make_pair(ExceptionCode::Illegal,
+ "Privileged instruction");
+
+ case STATUS_NO_MEMORY:
+ default: {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "Exit code 0x%x\n",
+ static_cast<unsigned int>(this->ExitStatus));
+ return std::make_pair(ExceptionCode::Other, buf);
+ }
+ }
+ }
+ return std::make_pair(ExceptionCode::None, "");
+#else
+ if (this->TermSignal) {
+ switch (this->TermSignal) {
+# ifdef SIGSEGV
+ case SIGSEGV:
+ return std::make_pair(ExceptionCode::Fault, "Segmentation fault");
+# endif
+# ifdef SIGBUS
+# if !defined(SIGSEGV) || SIGBUS != SIGSEGV
+ case SIGBUS:
+ return std::make_pair(ExceptionCode::Fault, "Bus error");
+# endif
+# endif
+# ifdef SIGFPE
+ case SIGFPE:
+ return std::make_pair(ExceptionCode::Numerical,
+ "Floating-point exception");
+# endif
+# ifdef SIGILL
+ case SIGILL:
+ return std::make_pair(ExceptionCode::Illegal, "Illegal instruction");
+# endif
+# ifdef SIGINT
+ case SIGINT:
+ return std::make_pair(ExceptionCode::Interrupt, "User interrupt");
+# endif
+# ifdef SIGABRT
+ case SIGABRT:
+ return std::make_pair(ExceptionCode::Other, "Subprocess aborted");
+# endif
+# ifdef SIGKILL
+ case SIGKILL:
+ return std::make_pair(ExceptionCode::Other, "Subprocess killed");
+# endif
+# ifdef SIGTERM
+ case SIGTERM:
+ return std::make_pair(ExceptionCode::Other, "Subprocess terminated");
+# endif
+# ifdef SIGHUP
+ case SIGHUP:
+ return std::make_pair(ExceptionCode::Other, "SIGHUP");
+# endif
+# ifdef SIGQUIT
+ case SIGQUIT:
+ return std::make_pair(ExceptionCode::Other, "SIGQUIT");
+# endif
+# ifdef SIGTRAP
+ case SIGTRAP:
+ return std::make_pair(ExceptionCode::Other, "SIGTRAP");
+# endif
+# ifdef SIGIOT
+# if !defined(SIGABRT) || SIGIOT != SIGABRT
+ case SIGIOT:
+ return std::make_pair(ExceptionCode::Other, "SIGIOT");
+# endif
+# endif
+# ifdef SIGUSR1
+ case SIGUSR1:
+ return std::make_pair(ExceptionCode::Other, "SIGUSR1");
+# endif
+# ifdef SIGUSR2
+ case SIGUSR2:
+ return std::make_pair(ExceptionCode::Other, "SIGUSR2");
+# endif
+# ifdef SIGPIPE
+ case SIGPIPE:
+ return std::make_pair(ExceptionCode::Other, "SIGPIPE");
+# endif
+# ifdef SIGALRM
+ case SIGALRM:
+ return std::make_pair(ExceptionCode::Other, "SIGALRM");
+# endif
+# ifdef SIGSTKFLT
+ case SIGSTKFLT:
+ return std::make_pair(ExceptionCode::Other, "SIGSTKFLT");
+# endif
+# ifdef SIGCHLD
+ case SIGCHLD:
+ return std::make_pair(ExceptionCode::Other, "SIGCHLD");
+# elif defined(SIGCLD)
+ case SIGCLD:
+ return std::make_pair(ExceptionCode::Other, "SIGCLD");
+# endif
+# ifdef SIGCONT
+ case SIGCONT:
+ return std::make_pair(ExceptionCode::Other, "SIGCONT");
+# endif
+# ifdef SIGSTOP
+ case SIGSTOP:
+ return std::make_pair(ExceptionCode::Other, "SIGSTOP");
+# endif
+# ifdef SIGTSTP
+ case SIGTSTP:
+ return std::make_pair(ExceptionCode::Other, "SIGTSTP");
+# endif
+# ifdef SIGTTIN
+ case SIGTTIN:
+ return std::make_pair(ExceptionCode::Other, "SIGTTIN");
+# endif
+# ifdef SIGTTOU
+ case SIGTTOU:
+ return std::make_pair(ExceptionCode::Other, "SIGTTOU");
+# endif
+# ifdef SIGURG
+ case SIGURG:
+ return std::make_pair(ExceptionCode::Other, "SIGURG");
+# endif
+# ifdef SIGXCPU
+ case SIGXCPU:
+ return std::make_pair(ExceptionCode::Other, "SIGXCPU");
+# endif
+# ifdef SIGXFSZ
+ case SIGXFSZ:
+ return std::make_pair(ExceptionCode::Other, "SIGXFSZ");
+# endif
+# ifdef SIGVTALRM
+ case SIGVTALRM:
+ return std::make_pair(ExceptionCode::Other, "SIGVTALRM");
+# endif
+# ifdef SIGPROF
+ case SIGPROF:
+ return std::make_pair(ExceptionCode::Other, "SIGPROF");
+# endif
+# ifdef SIGWINCH
+ case SIGWINCH:
+ return std::make_pair(ExceptionCode::Other, "SIGWINCH");
+# endif
+# ifdef SIGPOLL
+ case SIGPOLL:
+ return std::make_pair(ExceptionCode::Other, "SIGPOLL");
+# endif
+# ifdef SIGIO
+# if !defined(SIGPOLL) || SIGIO != SIGPOLL
+ case SIGIO:
+ return std::make_pair(ExceptionCode::Other, "SIGIO");
+# endif
+# endif
+# ifdef SIGPWR
+ case SIGPWR:
+ return std::make_pair(ExceptionCode::Other, "SIGPWR");
+# endif
+# ifdef SIGSYS
+ case SIGSYS:
+ return std::make_pair(ExceptionCode::Other, "SIGSYS");
+# endif
+# ifdef SIGUNUSED
+# if !defined(SIGSYS) || SIGUNUSED != SIGSYS
+ case SIGUNUSED:
+ return std::make_pair(ExceptionCode::Other, "SIGUNUSED");
+# endif
+# endif
+ default: {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "Signal %d", this->TermSignal);
+ return std::make_pair(ExceptionCode::Other, buf);
+ }
+ }
+ }
+ return std::make_pair(ExceptionCode::None, "");
+#endif
+}
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
index 9e4558e..f92742f 100644
--- a/Source/cmUVProcessChain.h
+++ b/Source/cmUVProcessChain.h
@@ -8,6 +8,7 @@
#include <iosfwd>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include <cm3p/uv.h>
@@ -66,10 +67,22 @@ private:
class cmUVProcessChain
{
public:
+ enum class ExceptionCode
+ {
+ None,
+ Fault,
+ Illegal,
+ Interrupt,
+ Numerical,
+ Other,
+ };
+
struct Status
{
int64_t ExitStatus;
int TermSignal;
+
+ std::pair<ExceptionCode, std::string> GetException() const;
};
cmUVProcessChain(const cmUVProcessChain& other) = delete;
diff --git a/Source/cmake.h b/Source/cmake.h
index 2f5ea24..156d061 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -635,6 +635,10 @@ public:
void UnwatchUnusedCli(const std::string& var);
void WatchUnusedCli(const std::string& var);
+#if !defined(CMAKE_BOOTSTRAP)
+ cmFileAPI* GetFileAPI() const { return this->FileAPI.get(); }
+#endif
+
cmState* GetState() const { return this->State.get(); }
void SetCurrentSnapshot(cmStateSnapshot const& snapshot)
{
diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx
index ce6cd6d..7027689 100644
--- a/Tests/CMakeLib/testUVProcessChain.cxx
+++ b/Tests/CMakeLib/testUVProcessChain.cxx
@@ -4,6 +4,8 @@
#include <iostream>
#include <sstream>
#include <string>
+#include <type_traits>
+#include <utility>
#include <vector>
#include <cm/memory>
@@ -22,30 +24,62 @@ struct ExpectedStatus
bool MatchExitStatus;
bool MatchTermSignal;
cmUVProcessChain::Status Status;
+ cmUVProcessChain::ExceptionCode ExceptionCode;
+ std::string ExceptionString;
};
static const std::vector<ExpectedStatus> status1 = {
- { false, false, false, { 0, 0 } },
- { false, false, false, { 0, 0 } },
- { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
+ { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
+ { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
};
static const std::vector<ExpectedStatus> status2 = {
- { true, true, true, { 0, 0 } },
- { false, false, false, { 0, 0 } },
- { false, false, false, { 0, 0 } },
+ { true, true, true, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
+ { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
+ { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
};
static const std::vector<ExpectedStatus> status3 = {
- { true, true, true, { 0, 0 } },
- { true, true, true, { 1, 0 } },
+ { true, true, true, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
+ { true, true, true, { 1, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
#ifdef _WIN32
- { true, true, true, { 2, 0 } },
+ { true,
+ true,
+ true,
+ { STATUS_ACCESS_VIOLATION, 0 },
+ cmUVProcessChain::ExceptionCode::Fault,
+ "Access violation" },
#else
- { true, false, true, { 0, SIGABRT } },
+ { true,
+ false,
+ true,
+ { 0, SIGABRT },
+ cmUVProcessChain::ExceptionCode::Other,
+ "Subprocess aborted" },
#endif
};
+static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
+{
+ switch (code) {
+ case cmUVProcessChain::ExceptionCode::None:
+ return "None";
+ case cmUVProcessChain::ExceptionCode::Fault:
+ return "Fault";
+ case cmUVProcessChain::ExceptionCode::Illegal:
+ return "Illegal";
+ case cmUVProcessChain::ExceptionCode::Interrupt:
+ return "Interrupt";
+ case cmUVProcessChain::ExceptionCode::Numerical:
+ return "Numerical";
+ case cmUVProcessChain::ExceptionCode::Other:
+ return "Other";
+ default:
+ return "";
+ }
+}
+
bool operator==(const cmUVProcessChain::Status* actual,
const ExpectedStatus& expected)
{
@@ -62,6 +96,11 @@ bool operator==(const cmUVProcessChain::Status* actual,
expected.Status.TermSignal != actual->TermSignal) {
return false;
}
+ if (expected.Finished &&
+ std::make_pair(expected.ExceptionCode, expected.ExceptionString) !=
+ actual->GetException()) {
+ return false;
+ }
return true;
}
@@ -116,6 +155,11 @@ static void printResults(
<< printExpected(e.MatchExitStatus, e.Status.ExitStatus)
<< ", TermSignal: "
<< printExpected(e.MatchTermSignal, e.Status.TermSignal)
+ << ", ExceptionCode: "
+ << printExpected(e.Finished,
+ ExceptionCodeToString(e.ExceptionCode))
+ << ", ExceptionString: \""
+ << printExpected(e.Finished, e.ExceptionString) << '"'
<< std::endl;
} else {
std::cout << " null" << std::endl;
@@ -124,8 +168,12 @@ static void printResults(
std::cout << "Actual:" << std::endl;
for (auto const& a : actual) {
if (a) {
+ auto exception = a->GetException();
std::cout << " ExitStatus: " << a->ExitStatus
- << ", TermSignal: " << a->TermSignal << std::endl;
+ << ", TermSignal: " << a->TermSignal << ", ExceptionCode: "
+ << ExceptionCodeToString(exception.first)
+ << ", ExceptionString: \"" << exception.second << '"'
+ << std::endl;
} else {
std::cout << " null" << std::endl;
}
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
index 82dafd2..99743e7 100644
--- a/Tests/CMakeLib/testUVProcessChainHelper.cxx
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -7,6 +7,10 @@
#include <string>
#include <thread>
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
#include "cmSystemTools.h"
static std::string getStdin()
@@ -61,10 +65,9 @@ int main(int argc, char** argv)
}
// On Windows, the exit code of abort() is different between debug and
- // release builds, and does not yield a term_signal in libuv in either
- // case. For the sake of simplicity, we just return another non-zero code.
+ // release builds. Instead, simulate an access violation.
#ifdef _WIN32
- return 2;
+ return STATUS_ACCESS_VIOLATION;
#else
std::abort();
#endif
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 3997a74..d4f3341 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -865,6 +865,12 @@ add_RunCMake_test(CrosscompilingEmulator
-DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator>
-DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>
-DPSEUDO_EMULATOR_CUSTOM_COMMAND_ARG=$<TARGET_FILE:pseudo_emulator_custom_command_arg>)
+
+add_executable(pseudo_tidy pseudo_tidy.c)
+add_executable(pseudo_iwyu pseudo_iwyu.c)
+add_executable(pseudo_cpplint pseudo_cpplint.c)
+add_executable(pseudo_cppcheck pseudo_cppcheck.c)
+
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
if(UNIX AND NOT CYGWIN)
execute_process(COMMAND ldd --help
@@ -875,10 +881,6 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
add_RunCMake_test(LinkWhatYouUse)
endif()
endif()
- add_executable(pseudo_tidy pseudo_tidy.c)
- add_executable(pseudo_iwyu pseudo_iwyu.c)
- add_executable(pseudo_cpplint pseudo_cpplint.c)
- add_executable(pseudo_cppcheck pseudo_cppcheck.c)
add_RunCMake_test(ClangTidy -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>)
add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
add_RunCMake_test(Cpplint -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>)
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index bda260a..c90d543 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -479,3 +479,32 @@ set_tests_properties(test5 PROPERTIES SKIP_REGULAR_EXPRESSION \"please skip\")
run_cmake_command(output-junit ${CMAKE_CTEST_COMMAND} --output-junit "${RunCMake_TEST_BINARY_DIR}/junit.xml")
endfunction()
run_output_junit()
+
+if(WIN32)
+ block()
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TimeoutSignalWindows)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
+add_test(test1 \"${CMAKE_COMMAND}\" -E true)
+set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_NAME SIGUSR1)
+set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 1)
+")
+ run_cmake_command(TimeoutSignalWindows ${CMAKE_CTEST_COMMAND})
+ endblock()
+else()
+ block()
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TimeoutSignalBad)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
+add_test(test1 \"${CMAKE_COMMAND}\" -E true)
+set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_NAME NOTASIG)
+set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 0)
+set_tests_properties(test1 PROPERTIES TIMEOUT_SIGNAL_GRACE_PERIOD 1000)
+")
+ run_cmake_command(TimeoutSignalBad ${CMAKE_CTEST_COMMAND})
+ endblock()
+endif()
diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt
new file mode 100644
index 0000000..ba4235d
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stderr.txt
@@ -0,0 +1 @@
+Errors while running CTest
diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt
new file mode 100644
index 0000000..e848dcf
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalBad-stdout.txt
@@ -0,0 +1,5 @@
+ Start 1: test1
+TIMEOUT_SIGNAL_NAME "NOTASIG" not supported on this platform\.
+TIMEOUT_SIGNAL_GRACE_PERIOD "0" is not greater than "0" seconds\.
+TIMEOUT_SIGNAL_GRACE_PERIOD "1000" is not less than the maximum of "60" seconds\.
+1/1 Test #1: test1 ............................\*\*\*Not Run +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt
new file mode 100644
index 0000000..ba4235d
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stderr.txt
@@ -0,0 +1 @@
+Errors while running CTest
diff --git a/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt
new file mode 100644
index 0000000..295ace5
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/TimeoutSignalWindows-stdout.txt
@@ -0,0 +1,4 @@
+ Start 1: test1
+TIMEOUT_SIGNAL_NAME is not supported on Windows\.
+TIMEOUT_SIGNAL_GRACE_PERIOD is not supported on Windows\.
+1/1 Test #1: test1 ............................\*\*\*Not Run +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in b/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in
index ee3323c..1045d1a 100644
--- a/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in
+++ b/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in
@@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.16)
project(CTestTest@CASE_NAME@ C)
include(CTest)
+if(CMAKE_C_COMPILER_ID STREQUAL "SunPro" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.14)
+ set(CMAKE_C_STANDARD 99)
+endif()
+
add_executable(TestTimeout TestTimeout.c)
if(NOT DEFINED TIMEOUT)
diff --git a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
index a4080e3..6caeef1 100644
--- a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
@@ -13,12 +13,68 @@ endfunction()
run_ctest_timeout(Basic)
-if(UNIX)
+if(WIN32)
+ string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+ set_tests_properties(TestTimeout PROPERTIES
+ TIMEOUT_SIGNAL_NAME SIGUSR1
+ TIMEOUT_SIGNAL_GRACE_PERIOD 1.2
+ )
+]])
+ run_ctest_timeout(SignalWindows)
+ unset(CASE_CMAKELISTS_SUFFIX_CODE)
+
+else()
string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
target_compile_definitions(TestTimeout PRIVATE FORK)
]])
run_ctest_timeout(Fork)
unset(CASE_CMAKELISTS_SUFFIX_CODE)
+
+ string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+ target_compile_definitions(TestTimeout PRIVATE SIGNAL)
+ set_tests_properties(TestTimeout PROPERTIES
+ TIMEOUT_SIGNAL_NAME SIGUSR1
+ TIMEOUT_SIGNAL_GRACE_PERIOD 1.2
+ )
+]])
+ run_ctest_timeout(Signal)
+ unset(CASE_CMAKELISTS_SUFFIX_CODE)
+
+ string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+ target_compile_definitions(TestTimeout PRIVATE SIGNAL SIGNAL_IGNORE=1)
+ set_tests_properties(TestTimeout PROPERTIES
+ TIMEOUT_SIGNAL_NAME SIGUSR1
+ # Use default TIMEOUT_SIGNAL_GRACE_PERIOD of 1.
+ )
+]])
+ run_ctest_timeout(SignalIgnore)
+ unset(CASE_CMAKELISTS_SUFFIX_CODE)
+
+ string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+ set_tests_properties(TestTimeout PROPERTIES
+ TIMEOUT_SIGNAL_NAME NOTASIG
+ )
+]])
+ run_ctest_timeout(SignalUnknown)
+ unset(CASE_CMAKELISTS_SUFFIX_CODE)
+
+ string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+ set_tests_properties(TestTimeout PROPERTIES
+ TIMEOUT_SIGNAL_NAME SIGUSR1
+ TIMEOUT_SIGNAL_GRACE_PERIOD -1
+ )
+]])
+ run_ctest_timeout(SignalGraceLow)
+ unset(CASE_CMAKELISTS_SUFFIX_CODE)
+
+ string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+ set_tests_properties(TestTimeout PROPERTIES
+ TIMEOUT_SIGNAL_NAME SIGUSR1
+ TIMEOUT_SIGNAL_GRACE_PERIOD 1000
+ )
+]])
+ run_ctest_timeout(SignalGraceHigh)
+ unset(CASE_CMAKELISTS_SUFFIX_CODE)
endif()
block()
diff --git a/Tests/RunCMake/CTestTimeout/Signal-check.cmake b/Tests/RunCMake/CTestTimeout/Signal-check.cmake
new file mode 100644
index 0000000..bee5ac7
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/Signal-check.cmake
@@ -0,0 +1,11 @@
+file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(NOT test_xml)
+ set(RunCMake_TEST_FAILED "Test.xml not found.")
+ return()
+endif()
+
+file(READ "${test_xml}" test_xml_content)
+if(NOT test_xml_content MATCHES "SIGUSR1")
+ set(RunCMake_TEST_FAILED "Test output does not mention SIGUSR1.")
+ return()
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/Signal-stdout.txt b/Tests/RunCMake/CTestTimeout/Signal-stdout.txt
new file mode 100644
index 0000000..6cb5d0c
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/Signal-stdout.txt
@@ -0,0 +1,6 @@
+Test project [^
+]*/Tests/RunCMake/CTestTimeout/Signal-build
+ Start 1: TestTimeout
+1/1 Test #1: TestTimeout ......................\*\*\*Timeout \(SIGUSR1\) +[1-9][0-9.]* sec
++
+0% tests passed, 1 tests failed out of 1
diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake
new file mode 100644
index 0000000..96dabc8
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-check.cmake
@@ -0,0 +1,11 @@
+file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(NOT test_xml)
+ set(RunCMake_TEST_FAILED "Test.xml not found.")
+ return()
+endif()
+
+file(READ "${test_xml}" test_xml_content)
+if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_GRACE_PERIOD \"1000\" is not less than the maximum of \"60\" seconds\\.")
+ set(RunCMake_TEST_FAILED "Test output does not have expected error message.")
+ return()
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt
new file mode 100644
index 0000000..fc965c0
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalGraceHigh-stdout.txt
@@ -0,0 +1,3 @@
+ Start 1: TestTimeout
+TIMEOUT_SIGNAL_GRACE_PERIOD "1000" is not less than the maximum of "60" seconds\.
+1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake b/Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake
new file mode 100644
index 0000000..c4b01e5
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalGraceLow-check.cmake
@@ -0,0 +1,11 @@
+file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(NOT test_xml)
+ set(RunCMake_TEST_FAILED "Test.xml not found.")
+ return()
+endif()
+
+file(READ "${test_xml}" test_xml_content)
+if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_GRACE_PERIOD \"-1\" is not greater than \"0\" seconds\\.")
+ set(RunCMake_TEST_FAILED "Test output does not have expected error message.")
+ return()
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt
new file mode 100644
index 0000000..097cab6
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalGraceLow-stdout.txt
@@ -0,0 +1,3 @@
+ Start 1: TestTimeout
+TIMEOUT_SIGNAL_GRACE_PERIOD "-1" is not greater than "0" seconds.
+1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake b/Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake
new file mode 100644
index 0000000..e408764
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalIgnore-check.cmake
@@ -0,0 +1,11 @@
+file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(NOT test_xml)
+ set(RunCMake_TEST_FAILED "Test.xml not found.")
+ return()
+endif()
+
+file(READ "${test_xml}" test_xml_content)
+if(NOT test_xml_content MATCHES "EINTR")
+ set(RunCMake_TEST_FAILED "Test output does not mention EINTR.")
+ return()
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt
new file mode 100644
index 0000000..de97df4
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalIgnore-stdout.txt
@@ -0,0 +1,6 @@
+Test project [^
+]*/Tests/RunCMake/CTestTimeout/SignalIgnore-build
+ Start 1: TestTimeout
+1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[1-9][0-9.]* sec
++
+0% tests passed, 1 tests failed out of 1
diff --git a/Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake b/Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake
new file mode 100644
index 0000000..d024934
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalUnknown-check.cmake
@@ -0,0 +1,11 @@
+file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(NOT test_xml)
+ set(RunCMake_TEST_FAILED "Test.xml not found.")
+ return()
+endif()
+
+file(READ "${test_xml}" test_xml_content)
+if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_NAME \"NOTASIG\" not supported on this platform\\.")
+ set(RunCMake_TEST_FAILED "Test output does not have expected error message.")
+ return()
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt
new file mode 100644
index 0000000..33a133f
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalUnknown-stdout.txt
@@ -0,0 +1,3 @@
+ Start 1: TestTimeout
+TIMEOUT_SIGNAL_NAME "NOTASIG" not supported on this platform\.
+1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake b/Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake
new file mode 100644
index 0000000..1bf7f8a
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalWindows-check.cmake
@@ -0,0 +1,11 @@
+file(GLOB test_xml "${RunCMake_TEST_BINARY_DIR}/Testing/*/Test.xml")
+if(NOT test_xml)
+ set(RunCMake_TEST_FAILED "Test.xml not found.")
+ return()
+endif()
+
+file(READ "${test_xml}" test_xml_content)
+if(NOT test_xml_content MATCHES "TIMEOUT_SIGNAL_NAME is not supported on Windows\\.")
+ set(RunCMake_TEST_FAILED "Test output does not have expected error message.")
+ return()
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt b/Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt
new file mode 100644
index 0000000..6911015
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/SignalWindows-stdout.txt
@@ -0,0 +1,4 @@
+ Start 1: TestTimeout
+TIMEOUT_SIGNAL_GRACE_PERIOD is not supported on Windows\.
+TIMEOUT_SIGNAL_NAME is not supported on Windows\.
+1/1 Test #1: TestTimeout ......................\*\*\*Not Run +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestTimeout/TestTimeout.c b/Tests/RunCMake/CTestTimeout/TestTimeout.c
index 0d534fc..425548c 100644
--- a/Tests/RunCMake/CTestTimeout/TestTimeout.c
+++ b/Tests/RunCMake/CTestTimeout/TestTimeout.c
@@ -1,3 +1,8 @@
+#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OpenBSD__)
+/* NOLINTNEXTLINE(bugprone-reserved-identifier) */
+# define _XOPEN_SOURCE 600
+#endif
+
#if defined(_WIN32)
# include <windows.h>
#else
@@ -7,6 +12,19 @@
#include <stdio.h>
+#ifdef SIGNAL
+# include <errno.h>
+# include <signal.h>
+# include <string.h>
+
+static unsigned int signal_count;
+static void signal_handler(int signum)
+{
+ (void)signum;
+ ++signal_count;
+}
+#endif
+
int main(void)
{
#ifdef FORK
@@ -16,10 +34,39 @@ int main(void)
}
#endif
+#ifdef SIGNAL
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = signal_handler;
+ while ((sigaction(SIGUSR1, &sa, NULL) < 0) && (errno == EINTR))
+ ;
+#endif
+
#if defined(_WIN32)
Sleep((TIMEOUT + 4) * 1000);
+#elif defined(SIGNAL_IGNORE)
+# if defined(__CYGWIN__) || defined(__sun__)
+# define ERRNO_IS_EINTR (errno == EINTR || errno == 0)
+# else
+# define ERRNO_IS_EINTR (errno == EINTR)
+# endif
+ {
+ unsigned int timeLeft = (TIMEOUT + 4 + SIGNAL_IGNORE);
+ while ((timeLeft = sleep(timeLeft), timeLeft > 0 && ERRNO_IS_EINTR)) {
+ printf("EINTR: timeLeft=%u\n", timeLeft);
+ fflush(stdout);
+ }
+ }
#else
sleep((TIMEOUT + 4));
#endif
+
+#ifdef SIGNAL
+ if (signal_count > 0) {
+ printf("SIGUSR1: count=%u\n", signal_count);
+ fflush(stdout);
+ }
+#endif
+
return 0;
}
diff --git a/Tests/RunCMake/FileAPI/ProjectQueryBad-result.txt b/Tests/RunCMake/FileAPI/ProjectQueryBad-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/ProjectQueryBad-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/FileAPI/ProjectQueryBad-stderr.txt b/Tests/RunCMake/FileAPI/ProjectQueryBad-stderr.txt
new file mode 100644
index 0000000..84eff98
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/ProjectQueryBad-stderr.txt
@@ -0,0 +1,36 @@
+Non-query check
+CMake Error at ProjectQueryBad\.cmake:[0-9]+ \(cmake_file_api\):
+ cmake_file_api does not recognize sub-command NOT_A_QUERY
+.*
+Invalid API version checks
+CMake Error at ProjectQueryBad\.cmake:[0-9]+ \(cmake_file_api\):
+ cmake_file_api QUERY subcommand given an unsupported API_VERSION "2" \(the
+ only currently supported version is 1\)\.
+.*
+CMake Error at ProjectQueryBad\.cmake:[0-9]+ \(cmake_file_api\):
+ cmake_file_api QUERY subcommand given a non-integer API_VERSION\.
+.*
+Invalid version numbers check
+CMake Error at ProjectQueryBad\.cmake:[0-9]+ \(cmake_file_api\):
+ cmake_file_api QUERY subcommand was given invalid arguments:
+
+ Given a malformed version "nope" for CODEMODEL\.
+ Given a malformed version "-2" for CACHE\.
+ Given a malformed version "\.8" for CMAKEFILES\.
+ Given a malformed version "0\.1" for TOOLCHAINS\.
+.*
+Requested versions too high check
+CMake Error at ProjectQueryBad\.cmake:[0-9]+ \(cmake_file_api\):
+ cmake_file_api QUERY subcommand was given invalid arguments:
+
+ None of the specified CODEMODEL versions is supported by this version of CMake\.
+ None of the specified CACHE versions is supported by this version of CMake\.
+ None of the specified CMAKEFILES versions is supported by this version of CMake\.
+ None of the specified TOOLCHAINS versions is supported by this version of CMake\.
+.*
+Requested versions too low check
+CMake Error at ProjectQueryBad\.cmake:[0-9]+ \(cmake_file_api\):
+ cmake_file_api QUERY subcommand was given invalid arguments:
+
+ None of the specified CODEMODEL versions is supported by this version of CMake\.
+ None of the specified CACHE versions is supported by this version of CMake\.
diff --git a/Tests/RunCMake/FileAPI/ProjectQueryBad.cmake b/Tests/RunCMake/FileAPI/ProjectQueryBad.cmake
new file mode 100644
index 0000000..3a06105
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/ProjectQueryBad.cmake
@@ -0,0 +1,42 @@
+# All of these should fail. Execution does continue though, so we should see
+# the error output from each one. There is no observable effect of the command
+# during the configure phase, so it isn't critical to end processing on the
+# first failure. Allowing execution to proceed may allow the project to see
+# other potential errors before ultimately halting. That behavior is generally
+# desirable, and the multiple failing calls here will confirm that we retain
+# that behavior.
+
+message(NOTICE "Non-query check")
+cmake_file_api(NOT_A_QUERY)
+
+message(NOTICE "Invalid API version checks")
+cmake_file_api(QUERY API_VERSION 2)
+cmake_file_api(QUERY API_VERSION nah)
+
+message(NOTICE "Invalid version numbers check")
+cmake_file_api(
+ QUERY
+ API_VERSION 1
+ CODEMODEL nope
+ CACHE -2
+ CMAKEFILES .8
+ TOOLCHAINS 2 0.1
+)
+
+message(NOTICE "Requested versions too high check")
+cmake_file_api(
+ QUERY
+ API_VERSION 1
+ CODEMODEL 3
+ CACHE 3
+ CMAKEFILES 2
+ TOOLCHAINS 1.1
+)
+
+message(NOTICE "Requested versions too low check")
+cmake_file_api(
+ QUERY
+ API_VERSION 1
+ CODEMODEL 1
+ CACHE 1
+)
diff --git a/Tests/RunCMake/FileAPI/ProjectQueryGood-check.cmake b/Tests/RunCMake/FileAPI/ProjectQueryGood-check.cmake
new file mode 100644
index 0000000..46d3f77
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/ProjectQueryGood-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+ reply
+ reply/cache-v2-[0-9a-f]+.json
+ reply/cmakeFiles-v1-[0-9a-f]+.json
+ reply/codemodel-v2-[0-9a-f]+.json
+ .*reply/index-[0-9.T-]+.json
+ .*reply/toolchains-v1-[0-9a-f]+.json
+)
+
+# Only need to check for existence. Other tests check the reply contents.
+check_api("^${expect}$")
diff --git a/Tests/RunCMake/FileAPI/ProjectQueryGood.cmake b/Tests/RunCMake/FileAPI/ProjectQueryGood.cmake
new file mode 100644
index 0000000..da0f3ce
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/ProjectQueryGood.cmake
@@ -0,0 +1,8 @@
+cmake_file_api(
+ QUERY
+ API_VERSION 1
+ CODEMODEL 3 2.1
+ CACHE 3.2 2
+ CMAKEFILES 3 2 1.0
+ TOOLCHAINS 3 2 1
+)
diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index c768d18..81926af 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -52,6 +52,8 @@ run_cmake(ClientStateless)
run_cmake(MixedStateless)
run_cmake(DuplicateStateless)
run_cmake(ClientStateful)
+run_cmake(ProjectQueryGood)
+run_cmake(ProjectQueryBad)
function(run_object object)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${object}-build)
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 6c12ada..0f03c33 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -22,6 +22,7 @@
# HACK: check whether this can be removed with next iwyu release.
{ include: [ "<bits/cxxabi_forced.h>", private, "<ctime>", public ] },
+ { include: [ "<bits/chrono.h>", private, "<chrono>", public ] },
{ include: [ "<bits/exception.h>", private, "<exception>", public ] },
{ include: [ "<bits/shared_ptr.h>", private, "<memory>", public ] },
{ include: [ "<bits/std_function.h>", private, "<functional>", public ] },
@@ -101,6 +102,7 @@
{ symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1000> > >::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "__gnu_cxx::__enable_if<true, bool>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::remove_reference<std::basic_string<char, std::char_traits<char>, std::allocator<char> > &>::type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::remove_reference<cmCTestTestHandler::Signal &>::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::remove_reference<Defer &>::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::remove_reference<dap::StoppedEvent &>::type", private, "\"cmConfigure.h\"", public ] },