diff options
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 ] }, |