Browse Source

Merge branch 'master' into ctest-test-changing-labels

Kyle Edwards 4 years ago
parent
commit
d2515f77e1
100 changed files with 1409 additions and 671 deletions
  1. 27 7
      .gitlab-ci.yml
  2. 3 0
      .gitlab/ci/configure_cuda9.2_nvidia.cmake
  3. 1 0
      .gitlab/ci/configure_debian10_aarch64_ninja.cmake
  4. 1 0
      .gitlab/ci/configure_debian10_ninja.cmake
  5. 1 0
      .gitlab/ci/configure_fedora34_makefiles.cmake
  6. 3 0
      .gitlab/ci/configure_hip4.2_radeon.cmake
  7. 5 0
      .gitlab/ci/docker/cuda9.2/Dockerfile
  8. 14 0
      .gitlab/ci/docker/cuda9.2/install_deps.sh
  9. 7 0
      .gitlab/ci/docker/hip4.2/Dockerfile
  10. 13 0
      .gitlab/ci/docker/hip4.2/install_deps.sh
  11. 4 0
      .gitlab/ci/env_cuda9.2_nvidia.sh
  12. 39 0
      .gitlab/os-linux.yml
  13. 2 0
      Auxiliary/vim/syntax/cmake.vim
  14. 7 3
      CMakeLists.txt
  15. 34 13
      Help/command/ctest_test.rst
  16. 9 2
      Help/command/find_package.rst
  17. 2 1
      Help/command/source_group.rst
  18. 11 0
      Help/cpack_gen/rpm.rst
  19. 10 0
      Help/envvar/CMAKE_BUILD_TYPE.rst
  20. 11 0
      Help/envvar/CMAKE_CONFIGURATION_TYPES.rst
  21. 2 0
      Help/manual/cmake-env-variables.7.rst
  22. 3 1
      Help/manual/cmake-packages.7.rst
  23. 2 0
      Help/manual/cmake-properties.7.rst
  24. 3 0
      Help/manual/cmake-variables.7.rst
  25. 2 2
      Help/prop_test/ENVIRONMENT.rst
  26. 33 0
      Help/prop_test/ENVIRONMENT_MODIFICATION.rst
  27. 14 0
      Help/prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES.rst
  28. 15 9
      Help/prop_tgt/LINK_WHAT_YOU_USE.rst
  29. 7 0
      Help/release/dev/0-sample-topic.rst
  30. 5 0
      Help/release/dev/FindPkgConfig-PKG_CONFIG-args.rst
  31. 5 0
      Help/release/dev/LINK_WHAT_USE_USE-configuration.rst
  32. 6 0
      Help/release/dev/UseSWIG-dependencies.rst
  33. 6 0
      Help/release/dev/cpack-rpm-requires-exclude-from.rst
  34. 7 0
      Help/release/dev/ctest-environment-modifications.rst
  35. 7 0
      Help/release/dev/ctest-runtime-labels.rst
  36. 9 0
      Help/release/dev/env-init-configs.rst
  37. 5 0
      Help/release/dev/find_package-required-var.rst
  38. 7 0
      Help/release/dev/msvc-isystem.rst
  39. 5 0
      Help/release/dev/ninja-edit_cache.rst
  40. 5 0
      Help/release/dev/target_compile_features-ignore-disabled-langs.rst
  41. 2 0
      Help/release/index.rst
  42. 9 0
      Help/variable/CMAKE_BUILD_TYPE.rst
  43. 6 0
      Help/variable/CMAKE_CONFIGURATION_TYPES.rst
  44. 2 0
      Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
  45. 9 0
      Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst
  46. 1 1
      Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst
  47. 10 0
      Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst
  48. 14 0
      Help/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName.rst
  49. 8 2
      Modules/CMakeCInformation.cmake
  50. 9 0
      Modules/CMakeCUDAInformation.cmake
  51. 9 0
      Modules/CMakeCXXInformation.cmake
  52. 17 2
      Modules/CMakeDetermineCUDACompiler.cmake
  53. 5 2
      Modules/CMakeDetermineCompilerId.cmake
  54. 48 0
      Modules/CMakeFortranCompilerABI.F90
  55. 9 0
      Modules/CMakeFortranInformation.cmake
  56. 9 0
      Modules/CMakeHIPInformation.cmake
  57. 9 0
      Modules/CMakeOBJCInformation.cmake
  58. 9 0
      Modules/CMakeOBJCXXInformation.cmake
  59. 9 0
      Modules/CMakeSwiftInformation.cmake
  60. 8 1
      Modules/CMakeTestFortranCompiler.cmake
  61. 6 0
      Modules/Compiler/MSVC-C.cmake
  62. 6 0
      Modules/Compiler/MSVC-CXX.cmake
  63. 1 1
      Modules/Compiler/PGI.cmake
  64. 21 16
      Modules/FindBLAS.cmake
  65. 2 2
      Modules/FindCUDAToolkit.cmake
  66. 94 69
      Modules/FindGLUT.cmake
  67. 18 10
      Modules/FindLAPACK.cmake
  68. 51 3
      Modules/FindMPI.cmake
  69. 9 9
      Modules/FindMPI/test_mpi.c
  70. 1 1
      Modules/FindPatch.cmake
  71. 47 5
      Modules/FindPkgConfig.cmake
  72. 4 2
      Modules/Internal/CPack/CPackDeb.cmake
  73. 12 0
      Modules/Internal/CPack/CPackRPM.cmake
  74. 13 0
      Modules/Internal/CPack/NSIS.template.in
  75. 18 7
      Modules/UseSWIG.cmake
  76. 3 36
      Source/CMakeLists.txt
  77. 1 1
      Source/CMakeVersion.cmake
  78. 154 172
      Source/CPack/cmCPackDebGenerator.cxx
  79. 3 2
      Source/CPack/cmCPackDebGenerator.h
  80. 1 1
      Source/CTest/cmCTestMemCheckHandler.cxx
  81. 2 2
      Source/CTest/cmCTestMemCheckHandler.h
  82. 5 0
      Source/CTest/cmCTestMultiProcessHandler.cxx
  83. 171 11
      Source/CTest/cmCTestRunTest.cxx
  84. 2 1
      Source/CTest/cmCTestRunTest.h
  85. 58 138
      Source/CTest/cmCTestTestHandler.cxx
  86. 8 6
      Source/CTest/cmCTestTestHandler.h
  87. 26 0
      Source/CTest/cmCTestTestMeasurementXMLParser.cxx
  88. 21 0
      Source/CTest/cmCTestTestMeasurementXMLParser.h
  89. 41 37
      Source/LexerParser/cmFortranParser.cxx
  90. 4 0
      Source/LexerParser/cmFortranParser.y
  91. 6 9
      Source/QtDialog/QCMake.cxx
  92. 1 10
      Source/cmBinUtilsLinuxELFLinker.cxx
  93. 5 5
      Source/cmCMakePresetsFile.cxx
  94. 1 0
      Source/cmCommonTargetGenerator.h
  95. 0 1
      Source/cmConfigure.cmake.h.in
  96. 14 3
      Source/cmDependsFortran.cxx
  97. 2 1
      Source/cmDependsFortran.h
  98. 17 57
      Source/cmELF.cxx
  99. 3 4
      Source/cmELF.h
  100. 3 3
      Source/cmExportBuildFileGenerator.cxx

+ 27 - 7
.gitlab-ci.yml

@@ -52,7 +52,7 @@ prep:doc-package:
         - .cmake_doc_artifacts
         - .run_only_for_package
 
-.upload:source-package:
+upload:source-package:
     extends:
         - .rsync_upload_binary
         - .run_only_for_package
@@ -70,7 +70,7 @@ build:help:master:
         - .cmake_org_help
         - .run_only_for_continuous_master
 
-.upload:help:master:
+upload:help:master:
     extends:
         - .rsync_upload_help
         - .run_only_for_continuous_master
@@ -86,7 +86,7 @@ build:help:stage:
         - .cmake_org_help
         - .run_only_for_continuous_stage
 
-.upload:help:stage:
+upload:help:stage:
     extends:
         - .rsync_upload_help
         - .run_only_for_continuous_stage
@@ -219,6 +219,16 @@ test:fedora34-makefiles-nospace:
         CMAKE_CI_BUILD_NAME: fedora34_makefiles_nospace
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+test:cuda9.2-nvidia:
+    extends:
+        - .cuda9.2_nvidia
+        - .cmake_test_linux_release
+        - .linux_builder_tags_cuda
+        - .run_dependent
+        - .needs_centos6_x86_64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 test:cuda10.2-nvidia:
     extends:
         - .cuda10.2_nvidia
@@ -238,6 +248,16 @@ test:cuda10.2-clang:
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+test:hip4.2-radeon:
+    extends:
+        - .hip4.2_radeon
+        - .cmake_test_linux_release
+        - .linux_builder_tags_radeon
+        - .run_dependent
+        - .needs_centos6_x86_64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 build:fedora34-ninja:
     extends:
         - .fedora34_ninja
@@ -500,7 +520,7 @@ build:linux-x86_64-package:
     needs:
         - prep:doc-package
 
-.upload:linux-x86_64-package:
+upload:linux-x86_64-package:
     extends:
         - .rsync_upload_binary
         - .run_only_for_package
@@ -524,7 +544,7 @@ build:linux-aarch64-package:
     needs:
         - prep:doc-package
 
-.upload:linux-aarch64-package:
+upload:linux-aarch64-package:
     extends:
         - .rsync_upload_binary
         - .run_only_for_package
@@ -663,7 +683,7 @@ build:macos-package:
     needs:
         - prep:doc-package
 
-.upload:macos-package:
+upload:macos-package:
     extends:
         - .rsync_upload_binary
         - .run_only_for_package
@@ -686,7 +706,7 @@ build:macos10.10-package:
     needs:
         - prep:doc-package
 
-.upload:macos10.10-package:
+upload:macos10.10-package:
     extends:
         - .rsync_upload_binary
         - .run_only_for_package

+ 3 - 0
.gitlab/ci/configure_cuda9.2_nvidia.cmake

@@ -0,0 +1,3 @@
+set(CMake_TEST_CUDA "NVIDIA" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 1 - 0
.gitlab/ci/configure_debian10_aarch64_ninja.cmake

@@ -16,6 +16,7 @@ set(CMake_TEST_FindGDAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindGIF "ON" CACHE BOOL "")
 set(CMake_TEST_FindGit "ON" CACHE BOOL "")
 set(CMake_TEST_FindGLEW "ON" CACHE BOOL "")
+set(CMake_TEST_FindGLUT "ON" CACHE BOOL "")
 set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "")
 set(CMake_TEST_FindGSL "ON" CACHE BOOL "")
 set(CMake_TEST_FindGTest "ON" CACHE BOOL "")

+ 1 - 0
.gitlab/ci/configure_debian10_ninja.cmake

@@ -16,6 +16,7 @@ set(CMake_TEST_FindGDAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindGIF "ON" CACHE BOOL "")
 set(CMake_TEST_FindGit "ON" CACHE BOOL "")
 set(CMake_TEST_FindGLEW "ON" CACHE BOOL "")
+set(CMake_TEST_FindGLUT "ON" CACHE BOOL "")
 set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "")
 set(CMake_TEST_FindGSL "ON" CACHE BOOL "")
 set(CMake_TEST_FindGTest "ON" CACHE BOOL "")

+ 1 - 0
.gitlab/ci/configure_fedora34_makefiles.cmake

@@ -16,6 +16,7 @@ set(CMake_TEST_FindGDAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindGIF "ON" CACHE BOOL "")
 set(CMake_TEST_FindGit "ON" CACHE BOOL "")
 set(CMake_TEST_FindGLEW "ON" CACHE BOOL "")
+set(CMake_TEST_FindGLUT "ON" CACHE BOOL "")
 set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "")
 set(CMake_TEST_FindGSL "ON" CACHE BOOL "")
 set(CMake_TEST_FindGTest "ON" CACHE BOOL "")

+ 3 - 0
.gitlab/ci/configure_hip4.2_radeon.cmake

@@ -0,0 +1,3 @@
+set(CMake_TEST_HIP "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 5 - 0
.gitlab/ci/docker/cuda9.2/Dockerfile

@@ -0,0 +1,5 @@
+FROM nvidia/cuda:9.2-devel-ubuntu16.04
+MAINTAINER Brad King <[email protected]>
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh

+ 14 - 0
.gitlab/ci/docker/cuda9.2/install_deps.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install development tools.
+apt-get install -y \
+    g++ \
+    clang-3.8 \
+    curl \
+    git
+
+apt-get clean

+ 7 - 0
.gitlab/ci/docker/hip4.2/Dockerfile

@@ -0,0 +1,7 @@
+FROM rocm/dev-ubuntu-20.04:4.2
+MAINTAINER Brad King <[email protected]>
+
+ENV PATH="/opt/rocm/bin:$PATH"
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh

+ 13 - 0
.gitlab/ci/docker/hip4.2/install_deps.sh

@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install development tools.
+apt-get install -y --no-install-recommends \
+    g++ \
+    curl \
+    git
+
+apt-get clean

+ 4 - 0
.gitlab/ci/env_cuda9.2_nvidia.sh

@@ -0,0 +1,4 @@
+export CC=/usr/bin/clang-3.8
+export CXX=/usr/bin/clang++-3.8
+export CUDAHOSTCXX=/usr/bin/g++-5
+export CUDACXX=/usr/local/cuda/bin/nvcc

+ 39 - 0
.gitlab/os-linux.yml

@@ -208,6 +208,21 @@
 
 ### CUDA builds
 
+.cuda9.2:
+    image: "kitware/cmake:ci-cuda9.2-x86_64-2021-07-01"
+
+    variables:
+        GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+        CMAKE_ARCH: x86_64
+        CTEST_LABELS: "CUDA"
+
+.cuda9.2_nvidia:
+    extends: .cuda9.2
+
+    variables:
+        CMAKE_CONFIGURATION: cuda9.2_nvidia
+        CMAKE_GENERATOR: "Ninja Multi-Config"
+
 .cuda10.2:
     image: "kitware/cmake:ci-cuda10.2-x86_64-2021-06-16"
 
@@ -230,6 +245,23 @@
         CMAKE_CONFIGURATION: cuda10.2_clang
         CTEST_NO_WARNINGS_ALLOWED: 1
 
+### HIP builds
+
+.hip4.2:
+    image: "kitware/cmake:ci-hip4.2-x86_64-2021-07-09"
+
+    variables:
+        GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+        CMAKE_ARCH: x86_64
+        CTEST_LABELS: "HIP"
+
+.hip4.2_radeon:
+    extends: .hip4.2
+
+    variables:
+        CMAKE_CONFIGURATION: hip4.2_radeon
+        CMAKE_GENERATOR: "Ninja Multi-Config"
+
 ## Tags
 
 .linux_builder_tags:
@@ -262,6 +294,13 @@
         - docker
         - linux
 
+.linux_builder_tags_radeon:
+    tags:
+        - cmake
+        - radeon
+        - docker
+        - linux
+
 .linux_builder_tags_aarch64:
     tags:
         - cmake

+ 2 - 0
Auxiliary/vim/syntax/cmake.vim

@@ -160,6 +160,7 @@ syn keyword cmakeProperty contained
             \ ENABLED_LANGUAGES
             \ ENABLE_EXPORTS
             \ ENVIRONMENT
+            \ ENVIRONMENT_MODIFICATION
             \ EXCLUDE_FROM_ALL
             \ EXCLUDE_FROM_DEFAULT_BUILD
             \ EXPORT_NAME
@@ -2807,6 +2808,7 @@ syn keyword cmakeKWfind_package contained
             \ ABI
             \ BUNDLE
             \ CMAKE_DISABLE_FIND_PACKAGE_
+            \ CMAKE_REQUIRE_FIND_PACKAGE_
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ COMPONENTS
             \ CONFIG

+ 7 - 3
CMakeLists.txt

@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.1...3.19 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.1...3.20 FATAL_ERROR)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
 project(CMake)
@@ -815,8 +815,12 @@ CMAKE_SETUP_TESTING()
 
 if(NOT CMake_TEST_EXTERNAL_CMAKE)
   if(NOT CMake_VERSION_IS_RELEASE)
-    if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
-        NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 4.2)
+    if((CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+        NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 4.2) OR
+       (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND
+        NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 3.0 AND
+        NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC") OR
+       CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
       set(C_FLAGS_LIST -Wcast-align -Werror-implicit-function-declaration -Wchar-subscripts
                        -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security
                        -Wmissing-format-attribute -fno-common -Wundef

+ 34 - 13
Help/command/ctest_test.rst

@@ -190,29 +190,33 @@ Check the `CDash test measurement documentation
 <https://github.com/Kitware/CDash/blob/master/docs/test_measurements.md>`_
 for more information on the types of test measurements that CDash recognizes.
 
+Starting in version 3.22, CTest can parse custom measurements from tags named
+``<CTestMeasurement>`` or ``<CTestMeasurementFile>``. The older names
+``<DartMeasurement>`` and ``<DartMeasurementFile>`` are still supported.
+
 The following example demonstrates how to output a variety of custom test
 measurements.
 
 .. code-block:: c++
 
    std::cout <<
-     "<DartMeasurement type=\"numeric/double\" name=\"score\">28.3</DartMeasurement>"
+     "<CTestMeasurement type=\"numeric/double\" name=\"score\">28.3</CTestMeasurement>"
      << std::endl;
 
    std::cout <<
-     "<DartMeasurement type=\"text/string\" name=\"color\">red</DartMeasurement>"
+     "<CTestMeasurement type=\"text/string\" name=\"color\">red</CTestMeasurement>"
      << std::endl;
 
    std::cout <<
-     "<DartMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</DartMeasurement>"
+     "<CTestMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</CTestMeasurement>"
      << std::endl;
 
    std::cout <<
-     "<DartMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
+     "<CTestMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
      "line 1.\n" <<
      "  \033[31;1m line 2. Bold red, and indented!\033[0;0ml\n" <<
      "line 3. Not bold or indented...\n" <<
-     "</DartMeasurement>" << std::endl;
+     "</CTestMeasurement>" << std::endl;
 
 Image Measurements
 """"""""""""""""""
@@ -222,16 +226,16 @@ The following example demonstrates how to upload test images to CDash.
 .. code-block:: c++
 
    std::cout <<
-     "<DartMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
-     "/dir/to/test_img.jpg</DartMeasurementFile>" << std::endl;
+     "<CTestMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
+     "/dir/to/test_img.jpg</CTestMeasurementFile>" << std::endl;
 
    std::cout <<
-     "<DartMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
-     "/dir/to/valid_img.gif</DartMeasurementFile>" << std::endl;
+     "<CTestMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
+     "/dir/to/valid_img.gif</CTestMeasurementFile>" << std::endl;
 
    std::cout <<
-     "<DartMeasurementFile type=\"image/png\" name=\"AlgoResult\"> <<
-     "/dir/to/img.png</DartMeasurementFile>"
+     "<CTestMeasurementFile type=\"image/png\" name=\"AlgoResult\"> <<
+     "/dir/to/img.png</CTestMeasurementFile>"
      << std::endl;
 
 Images will be displayed together in an interactive comparison mode on CDash
@@ -257,8 +261,10 @@ The following example demonstrates how to upload non-image files to CDash.
 .. code-block:: c++
 
    std::cout <<
-     "<DartMeasurementFile type=\"file\" name=\"MyTestInputData\">" <<
-     "/dir/to/data.csv</DartMeasurementFile>" << std::endl;
+     "<CTestMeasurementFile type=\"file\" name=\"TestInputData1\">" <<
+     "/dir/to/data1.csv</CTestMeasurementFile>\n"                   <<
+     "<CTestMeasurementFile type=\"file\" name=\"TestInputData2\">" <<
+     "/dir/to/data2.csv</CTestMeasurementFile>"                     << std::endl;
 
 If the name of the file to upload is known at configure time, you can use the
 :prop_test:`ATTACHED_FILES` or :prop_test:`ATTACHED_FILES_ON_FAIL` test
@@ -274,3 +280,18 @@ The following example demonstrates how to specify a custom value for the
 
    std::cout <<
      "<CTestDetails>My Custom Details Value</CTestDetails>" << std::endl;
+
+Additional Labels
+"""""""""""""""""
+
+The following example demonstrates how to add additional labels to a test
+at runtime.
+
+.. code-block:: c++
+
+   std::cout <<
+     "<CTestLabel>Custom Label 1</CTestLabel>\n" <<
+     "<CTestLabel>Custom Label 2</CTestLabel>"   << std::endl;
+
+Use the :prop_test:`LABELS` test property instead for labels that can be
+determined at configure time.

+ 9 - 2
Help/command/find_package.rst

@@ -448,8 +448,15 @@ which the file is found.  The :variable:`CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS`
 variable may be set to ``TRUE`` before calling ``find_package`` in order
 to resolve symbolic links and store the real path to the file.
 
-Every non-REQUIRED ``find_package`` call can be disabled by setting the
-:variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable to ``TRUE``.
+Every non-REQUIRED ``find_package`` call can be disabled or made REQUIRED:
+
+* Setting the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable
+  to ``TRUE`` disables the package.
+
+* Setting the :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable
+  to ``TRUE`` makes the package REQUIRED.
+
+Setting both variables to ``TRUE`` simultaneously is an error.
 
 Package File Interface Variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

+ 2 - 1
Help/command/source_group.rst

@@ -22,7 +22,8 @@ The options are:
  CMake will automatically detect, from ``<src>`` files paths, source groups
  it needs to create, to keep structure of source groups analogically to the
  actual files and directories structure in the project. Paths of ``<src>``
- files will be cut to be relative to ``<root>``.
+ files will be cut to be relative to ``<root>``. The command fails if the
+ paths within ``src`` do not start with ``root``.
 
 ``PREFIX``
  .. versionadded:: 3.8

+ 11 - 0
Help/cpack_gen/rpm.rst

@@ -1035,3 +1035,14 @@ Source RPM packaging has its own set of variables:
  example::
 
   set(CPACK_RPM_BUILDREQUIRES "python >= 2.5.0, cmake >= 2.8")
+
+.. VARIABLE:: CPACK_RPM_REQUIRES_EXCLUDE_FROM
+
+ * Mandatory : NO
+ * Default   : -
+
+ May be used to keep the dependency generator from scanning specific files
+ or directories for dependencies.  Note that you can use a regular
+ expression that matches all of the directories or files, for example::
+
+  set(CPACK_RPM_REQUIRES_EXCLUDE_FROM "bin/libqsqloci.*\\.so.*")

+ 10 - 0
Help/envvar/CMAKE_BUILD_TYPE.rst

@@ -0,0 +1,10 @@
+CMAKE_BUILD_TYPE
+----------------
+
+.. versionadded:: 3.22
+
+.. include:: ENV_VAR.txt
+
+The ``CMAKE_BUILD_TYPE`` environment variable specifies a default value
+for the :variable:`CMAKE_BUILD_TYPE` variable when there is no explicit
+configuration given on the first run while creating a new build tree.

+ 11 - 0
Help/envvar/CMAKE_CONFIGURATION_TYPES.rst

@@ -0,0 +1,11 @@
+CMAKE_CONFIGURATION_TYPES
+-------------------------
+
+.. versionadded:: 3.22
+
+.. include:: ENV_VAR.txt
+
+The ``CMAKE_CONFIGURATION_TYPES`` environment variable specifies a
+default value for the :variable:`CMAKE_CONFIGURATION_TYPES` variable
+when there is no explicit configuration given on the first run while
+creating a new build tree.

+ 2 - 0
Help/manual/cmake-env-variables.7.rst

@@ -30,6 +30,8 @@ Environment Variables that Control the Build
 
    /envvar/CMAKE_APPLE_SILICON_PROCESSOR
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
+   /envvar/CMAKE_BUILD_TYPE
+   /envvar/CMAKE_CONFIGURATION_TYPES
    /envvar/CMAKE_CONFIG_TYPE
    /envvar/CMAKE_EXPORT_COMPILE_COMMANDS
    /envvar/CMAKE_GENERATOR

+ 3 - 1
Help/manual/cmake-packages.7.rst

@@ -74,7 +74,9 @@ package.
 
 By setting the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable to
 ``TRUE``, the ``<PackageName>`` package will not be searched, and will always
-be ``NOTFOUND``.
+be ``NOTFOUND``. Likewise, setting the
+:variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` to ``TRUE`` will make the
+package REQUIRED.
 
 .. _`Config File Packages`:
 

+ 2 - 0
Help/manual/cmake-properties.7.rst

@@ -202,6 +202,7 @@ Properties on Targets
    /prop_tgt/EXPORT_NAME
    /prop_tgt/EXPORT_PROPERTIES
    /prop_tgt/FOLDER
+   /prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES
    /prop_tgt/Fortran_FORMAT
    /prop_tgt/Fortran_MODULE_DIRECTORY
    /prop_tgt/Fortran_PREPROCESS
@@ -450,6 +451,7 @@ Properties on Tests
    /prop_test/DEPENDS
    /prop_test/DISABLED
    /prop_test/ENVIRONMENT
+   /prop_test/ENVIRONMENT_MODIFICATION
    /prop_test/FAIL_REGULAR_EXPRESSION
    /prop_test/FIXTURES_CLEANUP
    /prop_test/FIXTURES_REQUIRED

+ 3 - 0
Help/manual/cmake-variables.7.rst

@@ -231,6 +231,7 @@ Variables that Change Behavior
    /variable/CMAKE_PROJECT_INCLUDE_BEFORE
    /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
    /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
+   /variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName
    /variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
    /variable/CMAKE_STAGING_PREFIX
    /variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
@@ -428,6 +429,7 @@ Variables that Control the Build
    /variable/CMAKE_LANG_LINKER_LAUNCHER
    /variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LANG_LINK_LIBRARY_FLAG
+   /variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG
    /variable/CMAKE_LANG_VISIBILITY_PRESET
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG
@@ -438,6 +440,7 @@ Variables that Control the Build
    /variable/CMAKE_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LINK_LIBRARY_FLAG
    /variable/CMAKE_LINK_WHAT_YOU_USE
+   /variable/CMAKE_LINK_WHAT_YOU_USE_CHECK
    /variable/CMAKE_MACOSX_BUNDLE
    /variable/CMAKE_MACOSX_RPATH
    /variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG

+ 2 - 2
Help/prop_test/ENVIRONMENT.rst

@@ -5,5 +5,5 @@ Specify environment variables that should be defined for running a test.
 
 If set to a list of environment variables and values of the form
 ``MYVAR=value`` those environment variables will be defined while running
-the test.  The environment is restored to its previous state after the
-test is done.
+the test.  The environment changes from this property do not affect other
+tests.

+ 33 - 0
Help/prop_test/ENVIRONMENT_MODIFICATION.rst

@@ -0,0 +1,33 @@
+ENVIRONMENT_MODIFICATION
+------------------------
+
+Specify environment variables that should be modified for running a test. Note
+that the operations performed by this property are performed after the
+:prop_test:`ENVIRONMENT` property is already applied.
+
+If set to a list of environment variables and values of the form
+``MYVAR=OP:VALUE``. Entries are considered in the order specified in the
+property's value. The ``OP`` may be one of:
+
+  - ``reset``: Reset to the unmodified value, ignoring all modifications to
+    ``MYVAR`` prior to this entry. Note that this will reset the variable to
+    the value set by :prop_test:`ENVIRONMENT`, if it was set, and otherwise
+    to its state from the rest of the CTest execution.
+  - ``set``: Replaces the current value of ``MYVAR`` with ``VALUE``.
+  - ``unset``: Unsets the current value of ``MYVAR``.
+  - ``string_append``: Appends ``VALUE`` to the current value of ``MYVAR``.
+  - ``string_prepend``: Prepends ``VALUE`` to the current value of ``MYVAR``.
+  - ``path_list_append``: Appends ``VALUE`` to the current value of ``MYVAR``
+    using the platform-specific list separator.
+  - ``path_list_prepend``: Prepends ``VALUE`` to the current value of
+    ``MYVAR`` using the platform-specific list separator.
+  - ``cmake_list_append``: Appends ``VALUE`` to the current value of ``MYVAR``
+    using ``;`` as the separator.
+  - ``cmake_list_prepend``: Prepends ``VALUE`` to the current value of
+    ``MYVAR`` using ``;`` as the separator.
+
+Unrecognized ``OP`` values will result in the test failing before it is
+executed. This is so that future operations may be added without changing
+valid behavior of existing tests.
+
+The environment changes from this property do not affect other tests.

+ 14 - 0
Help/prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES.rst

@@ -0,0 +1,14 @@
+Fortran_BUILDING_INSTRINSIC_MODULES
+-----------------------------------
+
+Instructs the CMake Fortran preprocessor that the target is building
+Fortran intrinsics for building a Fortran compiler.
+
+This property is off by default and should be turned only on projects
+that build a Fortran compiler. It should not be turned on for projects
+that use a Fortran compiler.
+
+Turning this property on will correctly add dependencies for building
+Fortran intrinsic modules whereas turning the property off will ignore
+Fortran intrinsic modules in the dependency graph as they are supplied
+by the compiler itself.

+ 15 - 9
Help/prop_tgt/LINK_WHAT_YOU_USE.rst

@@ -1,16 +1,22 @@
 LINK_WHAT_YOU_USE
----------------------------
+-----------------
 
 .. versionadded:: 3.7
 
-This is a boolean option that when set to ``TRUE`` will automatically run
-``ldd -r -u`` on the target after it is linked. In addition, the linker flag
-``-Wl,--no-as-needed`` will be passed to the target with the link command so
-that all libraries specified on the command line will be linked into the
-target. This will result in the link producing a list of libraries that
-provide no symbols used by this target but are being linked to it.
-This is only applicable to executable and shared library targets and
-will only work when ld and ldd accept the flags used.
+This is a boolean option that, when set to ``TRUE``, will automatically run
+contents of variable :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK` on the target
+after it is linked. In addition, the linker flag specified by variable
+:variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG`  will be passed to the target
+with the link command so that all libraries specified on the command line will
+be linked into the target. This will result in the link producing a list of
+libraries that provide no symbols used by this target but are being linked to
+it.
+
+.. note::
+
+  For now, it is only supported for ``ELF`` platforms and is only applicable to
+  executable and shared or module library targets. This property will be
+  ignored for any other targets and configurations.
 
 This property is initialized by the value of
 the :variable:`CMAKE_LINK_WHAT_YOU_USE` variable if it is set

+ 7 - 0
Help/release/dev/0-sample-topic.rst

@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+  Developers should add similar notes for each topic branch
+  making a noteworthy change.  Each document should be named
+  and titled to match the topic name to avoid merge conflicts.

+ 5 - 0
Help/release/dev/FindPkgConfig-PKG_CONFIG-args.rst

@@ -0,0 +1,5 @@
+FindPkgConfig-PKG_CONFIG-args
+-----------------------------
+
+* The :module:`FindPkgConfig` module gained a :variable:`PKG_CONFIG_ARGN`
+  variable to specify arguments to ``pkg-config`` calls.

+ 5 - 0
Help/release/dev/LINK_WHAT_USE_USE-configuration.rst

@@ -0,0 +1,5 @@
+LINK_WHAT_YOU_USE-configuration
+-------------------------------
+
+* Configuration for :prop_tgt:`LINK_WHAT_YOU_USE` feature is now controlled by
+  ``CMake`` variables and only active for ``ELF`` platforms.

+ 6 - 0
Help/release/dev/UseSWIG-dependencies.rst

@@ -0,0 +1,6 @@
+UseSWIG-dependencies
+--------------------
+
+* :module:`UseSWIG` module gained the capability, for
+  :ref:`Visual Studio Generators` to use `swig` tool to generate implicit
+  dependencies.

+ 6 - 0
Help/release/dev/cpack-rpm-requires-exclude-from.rst

@@ -0,0 +1,6 @@
+cpack-rpm-requires-exclude-from
+-------------------------------
+
+* The :cpack_gen:`CPack RPM Generator` gained the
+  :variable:`CPACK_RPM_REQUIRES_EXCLUDE_FROM` option avoid scanning
+  specific paths for dependencies.

+ 7 - 0
Help/release/dev/ctest-environment-modifications.rst

@@ -0,0 +1,7 @@
+ctest-environment-modifications
+-------------------------------
+
+* :manual:`ctest(1)` learned to be able to modify the environment for a test
+  through the :prop_test:`ENVIRONMENT_MODIFICATION` property. This is allows
+  for updates to environment variables based on the environment present at
+  test time.

+ 7 - 0
Help/release/dev/ctest-runtime-labels.rst

@@ -0,0 +1,7 @@
+ctest-runtime-labels
+--------------------
+
+* :manual:`ctest(1)` learned to recognize labels attached to a test at run time.
+  Previously it was only possible to attach labels to tests at configure time
+  by using the :prop_test:`LABELS` test property.
+  See :ref:`Additional Test Measurements` for more information.

+ 9 - 0
Help/release/dev/env-init-configs.rst

@@ -0,0 +1,9 @@
+env-init-configs
+----------------
+
+* The :envvar:`CMAKE_BUILD_TYPE` environment variable was added to
+  provide a default value for the :variable:`CMAKE_BUILD_TYPE` variable.
+
+* The :envvar:`CMAKE_CONFIGURATION_TYPES` environment variable was added to
+  provide a default value for the :variable:`CMAKE_CONFIGURATION_TYPES`
+  variable.

+ 5 - 0
Help/release/dev/find_package-required-var.rst

@@ -0,0 +1,5 @@
+find_package-required-var
+-------------------------
+
+* The :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable was added
+  to turn a non-REQUIRED :command:`find_package` call into a REQUIRED one.

+ 7 - 0
Help/release/dev/msvc-isystem.rst

@@ -0,0 +1,7 @@
+msvc-isystem
+------------
+
+* The MSVC compilers learned to pass the ``-external:I`` flag for system
+  includes when using the :generator:`Ninja` and :generator:`NMake Makefiles`
+  generators. This became available as of Visual Studio 16.10 (toolchain
+  version 14.29.30037).

+ 5 - 0
Help/release/dev/ninja-edit_cache.rst

@@ -0,0 +1,5 @@
+ninja-edit_cache
+----------------
+
+* The :ref:`Ninja Generators` now implement the ``edit_cache`` target
+  using :manual:`ccmake(1)` if available.

+ 5 - 0
Help/release/dev/target_compile_features-ignore-disabled-langs.rst

@@ -0,0 +1,5 @@
+target_compile_features-ignore-disabled-langs
+---------------------------------------------
+
+* :command:`target_compile_features` learned to ignored features for languages that
+  aren't enabled.

+ 2 - 0
Help/release/index.rst

@@ -7,6 +7,8 @@ CMake Release Notes
   This file should include the adjacent "dev.txt" file
   in development versions but not in release versions.
 
+.. include:: dev.txt
+
 Releases
 ========
 

+ 9 - 0
Help/variable/CMAKE_BUILD_TYPE.rst

@@ -23,3 +23,12 @@ Note that configuration names are case-insensitive.  The value of this
 variable will be the same as it is specified when invoking CMake.
 For instance, if ``-DCMAKE_BUILD_TYPE=ReLeAsE`` is specified, then the
 value of ``CMAKE_BUILD_TYPE`` will be ``ReLeAsE``.
+
+This variable is initialized by the first :command:`project` or
+:command:`enable_language` command called in a project when a new build
+tree is first created.  If the :envvar:`CMAKE_BUILD_TYPE` environment
+variable is set, its value is used.  Otherwise, a toolchain-specific
+default is chosen when a language is enabled.
+
+See :variable:`CMAKE_CONFIGURATION_TYPES` for specifying the configuration
+with multi-config generators.

+ 6 - 0
Help/variable/CMAKE_CONFIGURATION_TYPES.rst

@@ -8,5 +8,11 @@ such as ``Debug``, ``Release``, ``RelWithDebInfo`` etc.  This has reasonable
 defaults on most platforms, but can be extended to provide other build
 types.
 
+This variable is initialized by the first :command:`project` or
+:command:`enable_language` command called in a project when a new build
+tree is first created.  If the :envvar:`CMAKE_CONFIGURATION_TYPES`
+environment variable is set, its value is used.  Otherwise, the default
+value is generator-specific.
+
 See :variable:`CMAKE_BUILD_TYPE` for specifying the configuration with
 single-config generators.

+ 2 - 0
Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst

@@ -14,3 +14,5 @@ the package has already been found in a previous CMake run, the
 variables which have been stored in the cache will still be there.  In
 that case it is recommended to remove the cache variables for this
 package from the cache using the cache editor or :manual:`cmake(1)` ``-U``
+
+See also the :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable.

+ 9 - 0
Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst

@@ -0,0 +1,9 @@
+CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG
+-----------------------------------
+
+.. versionadded:: 3.22
+
+Linker flag to be used to configure linker so that all specified libraries on
+the command line will be linked into the target.
+
+See also variable :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK`.

+ 1 - 1
Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst

@@ -1,5 +1,5 @@
 CMAKE_LINK_WHAT_YOU_USE
----------------------------------
+-----------------------
 
 .. versionadded:: 3.7
 

+ 10 - 0
Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst

@@ -0,0 +1,10 @@
+CMAKE_LINK_WHAT_YOU_USE_CHECK
+-----------------------------
+
+.. versionadded:: 3.22
+
+Defines the command executed after the link step to check libraries usage.
+This check is currently only defined on ``ELF`` platforms with value
+``ldd -u -r``.
+
+See also :variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG` variables.

+ 14 - 0
Help/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName.rst

@@ -0,0 +1,14 @@
+CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>
+----------------------------------------
+
+.. versionadded:: 3.22
+
+Variable for making :command:`find_package` call ``REQUIRED``.
+
+Every non-``REQUIRED`` :command:`find_package` call in a project can be
+turned into ``REQUIRED`` by setting the variable
+``CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>`` to ``TRUE``.
+This can be used to assert assumptions about build environment and to
+ensure the build will fail early if they do not hold.
+
+See also the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable.

+ 8 - 2
Modules/CMakeCInformation.cmake

@@ -91,6 +91,14 @@ if(CMAKE_USER_MAKE_RULES_OVERRIDE_C)
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_C "${_override}")
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_C_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_C_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
 
 # for most systems a module is the same as a shared library
 # so unless the variable CMAKE_MODULE_EXISTS is set just
@@ -196,5 +204,3 @@ if(NOT CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG)
 endif()
 
 set(CMAKE_C_INFORMATION_LOADED 1)
-
-

+ 9 - 0
Modules/CMakeCUDAInformation.cmake

@@ -100,6 +100,15 @@ if(NOT CMAKE_MODULE_EXISTS)
   set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS})
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time

+ 9 - 0
Modules/CMakeCXXInformation.cmake

@@ -193,6 +193,15 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
   endif()
 endforeach()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time

+ 17 - 2
Modules/CMakeDetermineCUDACompiler.cmake

@@ -192,17 +192,31 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
       get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
       get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
     endif()
+
+    if(_CUDA_NVCC_OUT MATCHES "\\#\\$ NVVMIR_LIBRARY_DIR=([^\r\n]*)")
+      get_filename_component(_CUDA_NVVMIR_LIBRARY_DIR "${CMAKE_MATCH_1}" ABSOLUTE)
+
+      #We require the path to end in `/nvvm/libdevice'
+      if(_CUDA_NVVMIR_LIBRARY_DIR MATCHES "nvvm/libdevice$")
+        get_filename_component(_CUDA_NVVMIR_LIBRARY_DIR "${_CUDA_NVVMIR_LIBRARY_DIR}/../.." ABSOLUTE)
+        set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR "${_CUDA_NVVMIR_LIBRARY_DIR}")
+      endif()
+
+      unset(_CUDA_NVVMIR_LIBRARY_DIR)
+      unset(_cuda_nvvmir_dir_name)
+    endif()
     unset(_CUDA_NVCC_OUT)
 
     set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/nvlink${CMAKE_EXECUTABLE_SUFFIX}")
     set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/fatbinary${CMAKE_EXECUTABLE_SUFFIX}")
 
-
     # In a non-scattered installation the following are equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT.
     # We first check for a non-scattered installation to prefer it over a scattered installation.
 
     # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library.
-    if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvvm/libdevice")
+    if(DEFINED CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR)
+      set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR}")
+    elseif(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvvm/libdevice")
       set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
     elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/nvvm/libdevice")
       set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda")
@@ -211,6 +225,7 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
     else()
       message(FATAL_ERROR "Couldn't find CUDA library root.")
     endif()
+    unset(CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR)
 
     # CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT contains the linking stubs necessary for device linking and other low-level library files.
     if(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/nvidia-cuda-toolkit/bin/crt/link.stub")

+ 5 - 2
Modules/CMakeDetermineCompilerId.cmake

@@ -722,7 +722,7 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
   # Check the result of compilation.
   if(CMAKE_${lang}_COMPILER_ID_RESULT
      # Intel Fortran warns and ignores preprocessor lines without /fpp
-     OR CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "Bad # preprocessor line"
+     OR CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "warning #5117: Bad # preprocessor line"
      )
     # Compilation failed.
     set(MSG
@@ -733,7 +733,10 @@ ${CMAKE_${lang}_COMPILER_ID_RESULT}
 ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
 
 ")
-    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
+    # Log the output unless we recognize it as a known-bad case.
+    if(NOT CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "warning #5117: Bad # preprocessor line")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
+    endif()
 
     # Some languages may know the correct/desired set of flags and want to fail right away if they don't work.
     # This is currently only used by CUDA.

+ 48 - 0
Modules/CMakeFortranCompilerABI.F90

@@ -0,0 +1,48 @@
+program CMakeFortranCompilerABI
+
+implicit none
+
+integer :: i(1) = 0
+where (i==0) i=1
+if (any(i/=1)) stop 1
+! showing Fortran 90 syntax is OK
+
+#if 0
+! Address Size
+#endif
+#if defined(_LP64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_IA64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_X64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_AMD64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__x86_64__)
+PRINT *, 'INFO:sizeof_dptr[8]'
+
+#elif defined(_ILP32)
+PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(_M_IX86)
+PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(__i386__)
+PRINT *, 'INFO:sizeof_dptr[4]'
+
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4
+PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 8
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 4
+PRINT *, 'INFO:sizeof_dptr[4]'
+#endif
+
+#if 0
+! Application Binary Interface
+#endif
+#if defined(__ELF__)
+PRINT *, 'INFO:abi[ELF]'
+#endif
+PRINT *, 'ABI Detection'
+end program

+ 9 - 0
Modules/CMakeFortranInformation.cmake

@@ -157,6 +157,15 @@ if(NOT CMAKE_INCLUDE_FLAG_Fortran)
   set(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make.  This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.")
 
 set(CMAKE_Fortran_FLAGS_INIT "$ENV{FFLAGS} ${CMAKE_Fortran_FLAGS_INIT}")

+ 9 - 0
Modules/CMakeHIPInformation.cmake

@@ -68,6 +68,15 @@ if(NOT CMAKE_MODULE_EXISTS)
   set(CMAKE_SHARED_MODULE_CREATE_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_HIP_FLAGS})
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time

+ 9 - 0
Modules/CMakeOBJCInformation.cmake

@@ -91,6 +91,15 @@ if(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC)
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC "${_override}")
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_OBJC_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_OBJC_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 
 # for most systems a module is the same as a shared library
 # so unless the variable CMAKE_MODULE_EXISTS is set just

+ 9 - 0
Modules/CMakeOBJCXXInformation.cmake

@@ -189,6 +189,15 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
   endif()
 endforeach()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_OBJCXX_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_OBJCXX_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time

+ 9 - 0
Modules/CMakeSwiftInformation.cmake

@@ -70,6 +70,15 @@ set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
 set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
 set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 cmake_initialize_per_config_variable(CMAKE_Swift_FLAGS "Swift Compiler Flags")
 
 # NOTE(compnerd) we do not have an object compile rule since we build the objects as part of the link step

+ 8 - 1
Modules/CMakeTestFortranCompiler.cmake

@@ -17,11 +17,18 @@ unset(CMAKE_Fortran_COMPILER_WORKS CACHE)
 
 # Try to identify the ABI and configure it into CMakeFortranCompiler.cmake
 include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
-CMAKE_DETERMINE_COMPILER_ABI(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F)
+CMAKE_DETERMINE_COMPILER_ABI(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F90)
 if(CMAKE_Fortran_ABI_COMPILED)
   # The compiler worked so skip dedicated test below.
   set(CMAKE_Fortran_COMPILER_WORKS TRUE)
+  set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 1)
   message(STATUS "Check for working Fortran compiler: ${CMAKE_Fortran_COMPILER} - skipped")
+else()
+  cmake_determine_compiler_abi(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F)
+  if(CMAKE_Fortran_ABI_COMPILED)
+    set(CMAKE_Fortran_COMPILER_WORKS TRUE)
+    message(STATUS "Check for working Fortran 77 compiler: ${CMAKE_Fortran_COMPILER} - skipped")
+  endif()
 endif()
 
 # This file is used by EnableLanguage in cmGlobalGenerator to

+ 6 - 0
Modules/Compiler/MSVC-C.cmake

@@ -63,3 +63,9 @@ endmacro()
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   set(CMAKE_C_COMPILE_OPTIONS_JMC "-JMC")
 endif()
+
+# The `/external:I` flag was made non-experimental in 19.29.30036.3.
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30036.3)
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-external:I ")
+  set(_CMAKE_INCLUDE_SYSTEM_FLAG_C_WARNING "-external:W0 ")
+endif ()

+ 6 - 0
Modules/Compiler/MSVC-CXX.cmake

@@ -79,3 +79,9 @@ endif()
 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   set(CMAKE_CXX_COMPILE_OPTIONS_JMC "-JMC")
 endif()
+
+# The `/external:I` flag was made non-experimental in 19.29.30036.3.
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30036.3)
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-external:I ")
+  set(_CMAKE_INCLUDE_SYSTEM_FLAG_CXX_WARNING "-external:W0 ")
+endif ()

+ 1 - 1
Modules/Compiler/PGI.cmake

@@ -26,7 +26,7 @@ macro(__compiler_pgi lang)
   endif()
 
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
-  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG ",")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
 
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
   if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le AND (NOT CMAKE_HOST_WIN32 OR CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 16.3))

+ 21 - 16
Modules/FindBLAS.cmake

@@ -386,6 +386,8 @@ if(BLA_VENDOR STREQUAL "All")
       )
   endif()
   if(BLAS_WORKS)
+    # Give a more helpful "found" message
+    set(BLAS_WORKS "implicitly linked")
     set(_blas_fphsa_req_var BLAS_WORKS)
   endif()
 endif()
@@ -439,7 +441,7 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
 
       if(BLA_F95)
         set(BLAS_mkl_SEARCH_SYMBOL "sgemm_f95")
-        set(_LIBRARIES BLAS95_LIBRARIES)
+        set(_BLAS_LIBRARIES BLAS95_LIBRARIES)
         if(WIN32)
           # Find the main file (32-bit or 64-bit)
           set(BLAS_SEARCH_LIBS_WIN_MAIN "")
@@ -501,7 +503,7 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
         endif()
       else()
         set(BLAS_mkl_SEARCH_SYMBOL sgemm)
-        set(_LIBRARIES BLAS_LIBRARIES)
+        set(_BLAS_LIBRARIES BLAS_LIBRARIES)
         if(WIN32)
           # Find the main file (32-bit or 64-bit)
           set(BLAS_SEARCH_LIBS_WIN_MAIN "")
@@ -613,15 +615,15 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
           "lib/${BLAS_mkl_ARCH_NAME}"
           )
 
-      foreach(IT ${BLAS_SEARCH_LIBS})
-        string(REPLACE " " ";" SEARCH_LIBS ${IT})
-        if(NOT ${_LIBRARIES})
+      foreach(_search ${BLAS_SEARCH_LIBS})
+        string(REPLACE " " ";" _search ${_search})
+        if(NOT ${_BLAS_LIBRARIES})
           check_blas_libraries(
-            ${_LIBRARIES}
+            ${_BLAS_LIBRARIES}
             BLAS
             ${BLAS_mkl_SEARCH_SYMBOL}
             ""
-            "${SEARCH_LIBS}"
+            "${_search}"
             "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
             "${BLAS_mkl_MKLROOT}"
             "${BLAS_mkl_LIB_PATH_SUFFIXES}"
@@ -629,6 +631,7 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
         endif()
       endforeach()
 
+      unset(_search)
       unset(BLAS_mkl_ILP_MODE)
       unset(BLAS_mkl_INTFACE)
       unset(BLAS_mkl_THREADING)
@@ -734,14 +737,14 @@ if(BLA_VENDOR MATCHES "Arm" OR BLA_VENDOR STREQUAL "All")
 
    # Check for 64bit Integer support
    if(BLA_VENDOR MATCHES "_ilp64")
-     set(BLAS_armpl_LIB "armpl_ilp64")
+     set(_blas_armpl_lib "armpl_ilp64")
    else()
-     set(BLAS_armpl_LIB "armpl_lp64")
+     set(_blas_armpl_lib "armpl_lp64")
    endif()
 
    # Check for OpenMP support, VIA BLA_VENDOR of Arm_mp or Arm_ipl64_mp
    if(BLA_VENDOR MATCHES "_mp")
-     set(BLAS_armpl_LIB "${BLAS_armpl_LIB}_mp")
+     set(_blas_armpl_lib "${_blas_armpl_lib}_mp")
    endif()
 
    if(NOT BLAS_LIBRARIES)
@@ -750,13 +753,13 @@ if(BLA_VENDOR MATCHES "Arm" OR BLA_VENDOR STREQUAL "All")
       BLAS
       sgemm
       ""
-      "${BLAS_armpl_LIB}"
+      "${_blas_armpl_lib}"
       ""
       ""
       ""
       )
   endif()
-
+  unset(_blas_armpl_lib)
 endif()
 
 # FLAME's blis library? (https://github.com/flame/blis)
@@ -1087,11 +1090,11 @@ endif()
 # Elbrus Math Library?
 if(BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All")
 
-   set(BLAS_EML_LIB "eml")
+   set(_blas_eml_lib "eml")
 
    # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
    if(BLA_VENDOR MATCHES "_mt")
-     set(BLAS_EML_LIB "${BLAS_EML_LIB}_mt")
+     set(_blas_eml_lib "${_blas_eml_lib}_mt")
    endif()
 
    if(NOT BLAS_LIBRARIES)
@@ -1100,13 +1103,13 @@ if(BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All")
       BLAS
       sgemm
       ""
-      "${BLAS_EML_LIB}"
+      "${_blas_eml_lib}"
       ""
       ""
       ""
       )
   endif()
-
+  unset(_blas_eml_lib)
 endif()
 
 # Fujitsu SSL2 Library?
@@ -1163,3 +1166,5 @@ if(NOT BLA_F95)
 endif()
 
 _add_blas_target()
+unset(_blas_fphsa_req_var)
+unset(_BLAS_LIBRARIES)

+ 2 - 2
Modules/FindCUDAToolkit.cmake

@@ -849,9 +849,9 @@ if(CUDAToolkit_FOUND)
     mark_as_advanced(CUDA_${lib_name}_LIBRARY)
 
     if (NOT TARGET CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY)
-      add_library(CUDA::${lib_name} IMPORTED INTERFACE)
+      add_library(CUDA::${lib_name} UNKNOWN IMPORTED)
       target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}")
-      target_link_libraries(CUDA::${lib_name} INTERFACE "${CUDA_${lib_name}_LIBRARY}")
+      set_property(TARGET CUDA::${lib_name} PROPERTY IMPORTED_LOCATION "${CUDA_${lib_name}_LIBRARY}")
       foreach(dep ${arg_DEPS})
         if(TARGET CUDA::${dep})
           target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dep})

+ 94 - 69
Modules/FindGLUT.cmake

@@ -41,8 +41,43 @@ Also defined, but not for general use are:
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 
-if (WIN32)
+function(_add_glut_target_simple)
+  if(TARGET GLUT::GLUT)
+    return()
+  endif()
+  add_library(GLUT::GLUT INTERFACE IMPORTED)
+  if(GLUT_INCLUDE_DIRS)
+    target_include_directories(GLUT::GLUT SYSTEM
+      INTERFACE "${GLUT_INCLUDE_DIRS}")
+  endif()
+  if(GLUT_LIBRARIES)
+    target_link_libraries(GLUT::GLUT INTERFACE ${GLUT_LIBRARIES})
+  endif()
+  if(GLUT_LDFLAGS)
+    target_link_options(GLUT::GLUT INTERFACE ${GLUT_LDFLAGS})
+  endif()
+  if(GLUT_CFLAGS)
+    separate_arguments(GLUT_CFLAGS_SPLIT UNIX_COMMAND "${GLUT_CFLAGS}")
+    target_compile_options(GLUT::GLUT INTERFACE ${GLUT_CFLAGS_SPLIT})
+  endif()
+
+  set_property(TARGET GLUT::GLUT APPEND PROPERTY
+    IMPORTED_LOCATION "${GLUT_glut_LIBRARY}")
+endfunction()
+
+find_package(PkgConfig)
+if(PKG_CONFIG_FOUND)
+  pkg_check_modules(GLUT glut)
+  if(GLUT_FOUND)
+    _add_glut_target_simple()
+    FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_FOUND)
+    return()
+  endif()
+endif()
+
+if(WIN32)
   find_path( GLUT_INCLUDE_DIR NAMES GL/glut.h
     PATHS  ${GLUT_ROOT_PATH}/include )
   find_library( GLUT_glut_LIBRARY_RELEASE NAMES glut glut32 freeglut
@@ -57,85 +92,75 @@ if (WIN32)
     )
   mark_as_advanced(GLUT_glut_LIBRARY_RELEASE GLUT_glut_LIBRARY_DEBUG)
   select_library_configurations(GLUT_glut)
-else ()
-
-  if (APPLE)
-    find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
-    find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX")
-    find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX")
-    mark_as_advanced(GLUT_glut_LIBRARY GLUT_cocoa_LIBRARY)
-
-    if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa)
-      add_library(GLUT::Cocoa UNKNOWN IMPORTED)
-      # Cocoa should always be a Framework, but we check to make sure.
-      if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$")
-        set(_glut_cocoa "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}")
-        if(EXISTS "${_glut_cocoa}.tbd")
-          string(APPEND _glut_cocoa ".tbd")
-        endif()
-        set_target_properties(GLUT::Cocoa PROPERTIES
-          IMPORTED_LOCATION "${_glut_cocoa}")
-      else()
-        set_target_properties(GLUT::Cocoa PROPERTIES
-          IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}")
+elseif(APPLE)
+  find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
+  find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX")
+  find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX")
+  mark_as_advanced(GLUT_glut_LIBRARY GLUT_cocoa_LIBRARY)
+
+  if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa)
+    add_library(GLUT::Cocoa UNKNOWN IMPORTED)
+    # Cocoa should always be a Framework, but we check to make sure.
+    if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$")
+      set(_glut_cocoa "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}")
+      if(EXISTS "${_glut_cocoa}.tbd")
+        string(APPEND _glut_cocoa ".tbd")
       endif()
-    endif()
-  else ()
-
-    if (BEOS)
-
-      set(_GLUT_INC_DIR /boot/develop/headers/os/opengl)
-      set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86)
-
+      set_target_properties(GLUT::Cocoa PROPERTIES
+        IMPORTED_LOCATION "${_glut_cocoa}")
     else()
-
-      find_library( GLUT_Xi_LIBRARY Xi
-        /usr/openwin/lib
-        )
-      mark_as_advanced(GLUT_Xi_LIBRARY)
-
-      find_library( GLUT_Xmu_LIBRARY Xmu
-        /usr/openwin/lib
-        )
-      mark_as_advanced(GLUT_Xmu_LIBRARY)
-
-      if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi)
-        add_library(GLUT::Xi UNKNOWN IMPORTED)
-        set_target_properties(GLUT::Xi PROPERTIES
-          IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}")
-      endif()
-
-      if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu)
-        add_library(GLUT::Xmu UNKNOWN IMPORTED)
-        set_target_properties(GLUT::Xmu PROPERTIES
-          IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}")
-      endif()
-
-    endif ()
-
-    find_path( GLUT_INCLUDE_DIR GL/glut.h
-      /usr/include/GL
-      /usr/openwin/share/include
-      /usr/openwin/include
-      /opt/graphics/OpenGL/include
-      /opt/graphics/OpenGL/contrib/libglut
-      ${_GLUT_INC_DIR}
+      set_target_properties(GLUT::Cocoa PROPERTIES
+        IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}")
+    endif()
+  endif()
+else()
+  if(BEOS)
+    set(_GLUT_INC_DIR /boot/develop/headers/os/opengl)
+    set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86)
+  else()
+    find_library( GLUT_Xi_LIBRARY Xi
+      /usr/openwin/lib
       )
+    mark_as_advanced(GLUT_Xi_LIBRARY)
 
-    find_library( GLUT_glut_LIBRARY glut
+    find_library( GLUT_Xmu_LIBRARY Xmu
       /usr/openwin/lib
-      ${_GLUT_glut_LIB_DIR}
       )
-    mark_as_advanced(GLUT_glut_LIBRARY)
+    mark_as_advanced(GLUT_Xmu_LIBRARY)
 
-    unset(_GLUT_INC_DIR)
-    unset(_GLUT_glut_LIB_DIR)
+    if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi)
+      add_library(GLUT::Xi UNKNOWN IMPORTED)
+      set_target_properties(GLUT::Xi PROPERTIES
+        IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}")
+    endif()
+
+    if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu)
+      add_library(GLUT::Xmu UNKNOWN IMPORTED)
+      set_target_properties(GLUT::Xmu PROPERTIES
+        IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}")
+    endif()
 
   endif ()
 
-endif ()
+  find_path( GLUT_INCLUDE_DIR GL/glut.h
+    /usr/include/GL
+    /usr/openwin/share/include
+    /usr/openwin/include
+    /opt/graphics/OpenGL/include
+    /opt/graphics/OpenGL/contrib/libglut
+    ${_GLUT_INC_DIR}
+    )
+
+  find_library( GLUT_glut_LIBRARY glut
+    /usr/openwin/lib
+    ${_GLUT_glut_LIB_DIR}
+    )
+
+  unset(_GLUT_INC_DIR)
+  unset(_GLUT_glut_LIB_DIR)
+endif()
+mark_as_advanced(GLUT_glut_LIBRARY)
 
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_glut_LIBRARY GLUT_INCLUDE_DIR)
 
 if (GLUT_FOUND)

+ 18 - 10
Modules/FindLAPACK.cmake

@@ -298,7 +298,7 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
 
     if(BLA_F95)
       set(LAPACK_mkl_SEARCH_SYMBOL "cheev_f95")
-      set(_LIBRARIES LAPACK95_LIBRARIES)
+      set(_LAPACK_LIBRARIES LAPACK95_LIBRARIES)
       set(_BLAS_LIBRARIES ${BLAS95_LIBRARIES})
 
       # old
@@ -311,7 +311,7 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
         "mkl_lapack95_${LAPACK_mkl_ILP_MODE}")
     else()
       set(LAPACK_mkl_SEARCH_SYMBOL "cheev")
-      set(_LIBRARIES LAPACK_LIBRARIES)
+      set(_LAPACK_LIBRARIES LAPACK_LIBRARIES)
       set(_BLAS_LIBRARIES ${BLAS_LIBRARIES})
 
       # old and new >= 10.3
@@ -350,10 +350,10 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
         "lib/${LAPACK_mkl_ARCH_NAME}"
         )
 
-    # First try empty lapack libs
-    if(NOT ${_LIBRARIES})
+    # First try empty lapack libs (implicitly linked or automatic from BLAS)
+    if(NOT ${_LAPACK_LIBRARIES})
       check_lapack_libraries(
-        ${_LIBRARIES}
+        ${_LAPACK_LIBRARIES}
         LAPACK
         ${LAPACK_mkl_SEARCH_SYMBOL}
         ""
@@ -363,18 +363,23 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
         "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
         "${_BLAS_LIBRARIES}"
       )
+      if(LAPACK_WORKS AND NOT _BLAS_LIBRARIES)
+        # Give a more helpful "found" message
+        set(LAPACK_WORKS "implicitly linked")
+        set(_lapack_fphsa_req_var LAPACK_WORKS)
+      endif()
     endif()
 
     # Then try the search libs
-    foreach(IT ${LAPACK_SEARCH_LIBS})
-      string(REPLACE " " ";" SEARCH_LIBS ${IT})
-      if(NOT ${_LIBRARIES})
+    foreach(_search ${LAPACK_SEARCH_LIBS})
+      string(REPLACE " " ";" _search ${_search})
+      if(NOT ${_LAPACK_LIBRARIES})
         check_lapack_libraries(
-          ${_LIBRARIES}
+          ${_LAPACK_LIBRARIES}
           LAPACK
           ${LAPACK_mkl_SEARCH_SYMBOL}
           ""
-          "${SEARCH_LIBS}"
+          "${_search}"
           "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
           "${LAPACK_mkl_MKLROOT}"
           "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
@@ -383,6 +388,7 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
       endif()
     endforeach()
 
+    unset(_search)
     unset(LAPACK_mkl_ILP_MODE)
     unset(LAPACK_mkl_SEARCH_SYMBOL)
     unset(LAPACK_mkl_LM)
@@ -646,3 +652,5 @@ if(LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
 endif()
 
 _add_lapack_target()
+unset(_lapack_fphsa_req_var)
+unset(_LAPACK_LIBRARIES)

+ 51 - 3
Modules/FindMPI.cmake

@@ -105,7 +105,7 @@ This module performs a four step search for an MPI implementation:
 
 1. Search for ``MPIEXEC_EXECUTABLE`` and, if found, use its base directory.
 2. Check if the compiler has MPI support built-in. This is the case if the user passed a
-   compiler wrapper as ``CMAKE_<LANG>_COMPILER`` or if they're on a Cray system.
+   compiler wrapper as ``CMAKE_<LANG>_COMPILER`` or if they use Cray system compiler wrappers.
 3. Attempt to find an MPI compiler wrapper and determine the compiler information from it.
 4. Try to find an MPI implementation that does not ship such a wrapper by guessing settings.
    Currently, only Microsoft MPI and MPICH2 on Windows are supported.
@@ -333,6 +333,11 @@ set(_MPI_XL_Fortran_COMPILER_NAMES         mpixlf95   mpixlf95_r mpxlf95 mpxlf95
                                            mpixlf77   mpixlf77_r mpxlf77 mpxlf77_r
                                            mpixlf     mpixlf_r   mpxlf   mpxlf_r)
 
+# Cray Compiler names
+set(_MPI_Cray_C_COMPILER_NAMES             cc)
+set(_MPI_Cray_CXX_COMPILER_NAMES           CC)
+set(_MPI_Cray_Fortran_COMPILER_NAMES       ftn)
+
 # Prepend vendor-specific compiler wrappers to the list. If we don't know the compiler,
 # attempt all of them.
 # By attempting vendor-specific compiler names first, we should avoid situations where the compiler wrapper
@@ -488,6 +493,26 @@ function (_MPI_interrogate_compiler LANG)
     endif()
   endif()
 
+  # Cray compiler wrappers come usually without a separate mpicc/c++/ftn, but offer
+  # --cray-print-opts=...
+  if (NOT MPI_COMPILER_RETURN EQUAL 0)
+    _MPI_check_compiler(${LANG} "--cray-print-opts=cflags"
+                        MPI_COMPILE_CMDLINE MPI_COMPILER_RETURN)
+
+    if (MPI_COMPILER_RETURN EQUAL 0)
+      # Pass --no-as-needed so the mpi library is always linked. Otherwise, the
+      # Cray compiler wrapper puts an --as-needed flag around the mpi library,
+      # and it is not linked unless code directly refers to it.
+      _MPI_check_compiler(${LANG} "--no-as-needed;--cray-print-opts=libs"
+                          MPI_LINK_CMDLINE MPI_COMPILER_RETURN)
+
+      if (NOT MPI_COMPILER_RETURN EQUAL 0)
+        unset(MPI_COMPILE_CMDLINE)
+        unset(MPI_LINK_CMDLINE)
+      endif()
+    endif()
+  endif()
+
   # MPICH, MVAPICH2 and Intel MPI just use "-show". Open MPI also offers this, but the
   # -showme commands are more specialized.
   if (NOT MPI_COMPILER_RETURN EQUAL 0)
@@ -1440,9 +1465,10 @@ foreach(LANG IN ITEMS C CXX Fortran)
   endif()
   if(_MPI_FIND_${LANG})
     if( ${LANG} STREQUAL CXX AND NOT MPICXX IN_LIST MPI_FIND_COMPONENTS )
-      set(MPI_CXX_SKIP_MPICXX FALSE CACHE BOOL "If true, the MPI-2 C++ bindings are disabled using definitions.")
+      option(MPI_CXX_SKIP_MPICXX "If true, the MPI-2 C++ bindings are disabled using definitions." FALSE)
       mark_as_advanced(MPI_CXX_SKIP_MPICXX)
     endif()
+    _MPI_adjust_compile_definitions(${LANG})
     if(NOT (MPI_${LANG}_LIB_NAMES AND (MPI_${LANG}_INCLUDE_PATH OR MPI_${LANG}_INCLUDE_DIRS OR MPI_${LANG}_COMPILER_INCLUDE_DIRS)))
       set(MPI_${LANG}_TRIED_IMPLICIT FALSE)
       set(MPI_${LANG}_WORKS_IMPLICIT FALSE)
@@ -1519,6 +1545,29 @@ foreach(LANG IN ITEMS C CXX Fortran)
           endif()
         endif()
 
+        # We are on a Cray, environment identfier: PE_ENV is set (CRAY), and
+        # have NOT found an mpic++-like compiler wrapper (previous block),
+        # and we do NOT use the Cray cc/CC compiler wrappers as CC/CXX CMake
+        # compiler.
+        # So as a last resort, we now interrogate cc/CC/ftn for MPI flags.
+        if(DEFINED ENV{PE_ENV} AND NOT "${MPI_${LANG}_COMPILER}")
+          set(MPI_PINNED_COMPILER TRUE)
+          find_program(MPI_${LANG}_COMPILER
+            NAMES  ${_MPI_Cray_${LANG}_COMPILER_NAMES}
+            PATH_SUFFIXES bin sbin
+            DOC    "MPI compiler for ${LANG}"
+          )
+
+          # If we haven't made the implicit compiler test yet, perform it now.
+          if(NOT MPI_${LANG}_TRIED_IMPLICIT)
+            _MPI_create_imported_target(${LANG})
+            _MPI_check_lang_works(${LANG} TRUE)
+          endif()
+
+          set(MPI_${LANG}_WORKS_IMPLICIT TRUE)
+          _MPI_interrogate_compiler(${LANG})
+        endif()
+
         if(NOT MPI_PINNED_COMPILER AND NOT MPI_${LANG}_WRAPPER_FOUND)
           # If MPI_PINNED_COMPILER wasn't given, and the MPI compiler we potentially found didn't work, we withdraw it.
           set(MPI_${LANG}_COMPILER "MPI_${LANG}_COMPILER-NOTFOUND" CACHE FILEPATH "MPI compiler for ${LANG}" FORCE)
@@ -1547,7 +1596,6 @@ foreach(LANG IN ITEMS C CXX Fortran)
     endif()
     _MPI_assemble_libraries(${LANG})
 
-    _MPI_adjust_compile_definitions(${LANG})
     # We always create imported targets even if they're empty
     _MPI_create_imported_target(${LANG})
 

+ 9 - 9
Modules/FindMPI/test_mpi.c

@@ -7,15 +7,15 @@
 #endif
 
 #if defined(MPI_VERSION) && defined(MPI_SUBVERSION)
-const char mpiver_str[] = { 'I', 'N',
-                            'F', 'O',
-                            ':', 'M',
-                            'P', 'I',
-                            '-', 'V',
-                            'E', 'R',
-                            '[', ('0' + MPI_VERSION),
-                            '.', ('0' + MPI_SUBVERSION),
-                            ']', '\0' };
+const static char mpiver_str[] = { 'I', 'N',
+                                   'F', 'O',
+                                   ':', 'M',
+                                   'P', 'I',
+                                   '-', 'V',
+                                   'E', 'R',
+                                   '[', ('0' + MPI_VERSION),
+                                   '.', ('0' + MPI_SUBVERSION),
+                                   ']', '\0' };
 #endif
 
 int main(int argc, char* argv[])

+ 1 - 1
Modules/FindPatch.cmake

@@ -43,7 +43,7 @@ endif()
 
 # First search the PATH
 find_program(Patch_EXECUTABLE
-  NAME patch
+  NAMES patch
   PATHS ${_patch_path}
   DOC ${_doc}
   )

+ 47 - 5
Modules/FindPkgConfig.cmake

@@ -15,6 +15,8 @@ following variables will also be set:
   if pkg-config executable was found
 ``PKG_CONFIG_EXECUTABLE``
   pathname of the pkg-config program
+``PKG_CONFIG_ARGN``
+  list of arguments to pass to pkg-config
 ``PKG_CONFIG_VERSION_STRING``
   version of pkg-config (since CMake 2.8.8)
 
@@ -29,13 +31,22 @@ set(PKG_CONFIG_VERSION 1)
 
 # find pkg-config, use PKG_CONFIG if set
 if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL ""))
-  set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable")
+  separate_arguments(PKG_CONFIG_FROM_ENV_SPLIT NATIVE_COMMAND PROGRAM SEPARATE_ARGS "$ENV{PKG_CONFIG}")
+  list(LENGTH PKG_CONFIG_FROM_ENV_SPLIT PKG_CONFIG_FROM_ENV_SPLIT_ARGC)
+  if(PKG_CONFIG_FROM_ENV_SPLIT_ARGC GREATER 0)
+    list(GET PKG_CONFIG_FROM_ENV_SPLIT 0 PKG_CONFIG_FROM_ENV_ARGV0)
+    if(PKG_CONFIG_FROM_ENV_SPLIT_ARGC GREATER 1)
+      list(SUBLIST PKG_CONFIG_FROM_ENV_SPLIT 1 -1 PKG_CONFIG_ARGN)
+    endif()
+    set(PKG_CONFIG_EXECUTABLE "${PKG_CONFIG_FROM_ENV_ARGV0}" CACHE FILEPATH "pkg-config executable")
+  endif()
 endif()
 
 set(PKG_CONFIG_NAMES "pkg-config")
 if(CMAKE_HOST_WIN32)
   list(PREPEND PKG_CONFIG_NAMES "pkg-config.bat")
 endif()
+list(PREPEND PKG_CONFIG_NAMES "pkgconf")
 
 find_program(PKG_CONFIG_EXECUTABLE
   NAMES ${PKG_CONFIG_NAMES}
@@ -43,9 +54,12 @@ find_program(PKG_CONFIG_EXECUTABLE
   DOC "pkg-config executable")
 mark_as_advanced(PKG_CONFIG_EXECUTABLE)
 
+set(PKG_CONFIG_ARGN "${PKG_CONFIG_ARGN}" CACHE STRING "Arguments to supply to pkg-config")
+mark_as_advanced(PKG_CONFIG_ARGN)
+
 set(_PKG_CONFIG_FAILURE_MESSAGE "")
 if (PKG_CONFIG_EXECUTABLE)
-  execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --version
+  execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} ${PKG_CONFIG_ARGN} --version
     OUTPUT_VARIABLE PKG_CONFIG_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE
     ERROR_VARIABLE _PKG_CONFIG_VERSION_ERROR ERROR_STRIP_TRAILING_WHITESPACE
     RESULT_VARIABLE _PKG_CONFIG_VERSION_RESULT
@@ -53,14 +67,18 @@ if (PKG_CONFIG_EXECUTABLE)
 
   if (NOT _PKG_CONFIG_VERSION_RESULT EQUAL 0)
     string(REPLACE "\n" "\n    " _PKG_CONFIG_VERSION_ERROR "      ${_PKG_CONFIG_VERSION_ERROR}")
+    if(PKG_CONFIG_ARGN)
+      string(REPLACE ";" " " PKG_CONFIG_ARGN " ${PKG_CONFIG_ARGN}")
+    endif()
     string(APPEND _PKG_CONFIG_FAILURE_MESSAGE
       "The command\n"
-      "      \"${PKG_CONFIG_EXECUTABLE}\" --version\n"
+      "      \"${PKG_CONFIG_EXECUTABLE}\"${PKG_CONFIG_ARGN} --version\n"
       "    failed with output:\n${PKG_CONFIG_VERSION_STRING}\n"
       "    stderr: \n${_PKG_CONFIG_VERSION_ERROR}\n"
       "    result: \n${_PKG_CONFIG_VERSION_RESULT}"
       )
     set(PKG_CONFIG_EXECUTABLE "")
+    set(PKG_CONFIG_ARGN "")
     unset(PKG_CONFIG_VERSION_STRING)
   endif ()
   unset(_PKG_CONFIG_VERSION_RESULT)
@@ -91,7 +109,7 @@ macro(_pkgconfig_invoke _pkglist _prefix _varname _regexp)
   set(_pkgconfig_invoke_result)
 
   execute_process(
-    COMMAND ${PKG_CONFIG_EXECUTABLE} ${ARGN} ${_pkglist}
+    COMMAND ${PKG_CONFIG_EXECUTABLE} ${PKG_CONFIG_ARGN} ${ARGN} ${_pkglist}
     OUTPUT_VARIABLE _pkgconfig_invoke_result
     RESULT_VARIABLE _pkgconfig_failed
     OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -385,6 +403,14 @@ macro(_pkg_set_path_internal)
     unset(_lib_dirs)
     unset(_pkgconfig_path)
   endif()
+
+  # Tell pkg-config not to strip any -L paths so we can search them all.
+  if(DEFINED ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS})
+    set(_pkgconfig_allow_system_libs_old "$ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS}")
+  else()
+    unset(_pkgconfig_allow_system_libs_old)
+  endif()
+  set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 0)
 endmacro()
 
 macro(_pkg_restore_path_internal)
@@ -392,6 +418,10 @@ macro(_pkg_restore_path_internal)
     # Restore the environment variable
     set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
   endif()
+  if(DEFINED _pkgconfig_allow_system_libs_old)
+    set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} "${_pkgconfig_allow_system_libs_old}")
+    unset(_pkgconfig_allow_system_libs_old)
+  endif()
 
   unset(_extra_paths)
   unset(_pkgconfig_path_old)
@@ -533,7 +563,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
 
       # execute the query
       execute_process(
-        COMMAND ${PKG_CONFIG_EXECUTABLE} ${_pkg_check_modules_exist_query}
+        COMMAND ${PKG_CONFIG_EXECUTABLE} ${PKG_CONFIG_ARGN} ${_pkg_check_modules_exist_query}
         RESULT_VARIABLE _pkgconfig_retval
         ERROR_VARIABLE _pkgconfig_error
         ERROR_STRIP_TRAILING_WHITESPACE)
@@ -892,6 +922,18 @@ Variables Affecting Behavior
   .. versionadded:: 3.1
     The ``PKG_CONFIG`` environment variable can be used as a hint.
 
+.. variable:: PKG_CONFIG_ARGN
+
+  .. versionadded:: 3.22
+
+  This can be set to a list of arguments to additionally pass to pkg-config
+  if needed. If not provided, it will be an empty string, however, if the
+  environment variable ``PKG_CONFIG`` is provided, this will be set to the
+  result of splitting the variable.
+
+  The ``PKG_CONFIG`` environment variable can be used to provide both
+  ``PKG_CONFIG_EXECUTABLE`` and ``PKG_CONFIG_ARGN``
+
 .. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH
 
   .. versionadded:: 3.1

+ 4 - 2
Modules/Internal/CPack/CPackDeb.cmake

@@ -662,10 +662,12 @@ function(cpack_deb_prepare_package_vars)
 
   # add ldconfig call in default postrm and postint
   set(CPACK_ADD_LDCONFIG_CALL 0)
+  # all files in CPACK_DEB_SHARED_OBJECT_FILES have dot at the beginning
+  set(_LDCONF_DEFAULTS "./lib" "./usr/lib")
   foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES)
     get_filename_component(_DIR ${_FILE} DIRECTORY)
-    # all files in CPACK_DEB_SHARED_OBJECT_FILES have dot at the beginning
-    if(_DIR STREQUAL "./lib" OR _DIR STREQUAL "./usr/lib")
+    get_filename_component(_PARENT_DIR ${_DIR} DIRECTORY)
+    if(_DIR IN_LIST _LDCONF_DEFAULTS OR _PARENT_DIR IN_LIST _LDCONF_DEFAULTS)
       set(CPACK_ADD_LDCONFIG_CALL 1)
     endif()
   endforeach()

+ 12 - 0
Modules/Internal/CPack/CPackRPM.cmake

@@ -1162,6 +1162,16 @@ function(cpack_rpm_generate_package)
     set(TMP_RPM_SPEC_INSTALL_POST "%define __spec_install_post ${CPACK_RPM_SPEC_INSTALL_POST}")
   endif()
 
+  # CPACK_RPM_REQUIRES_EXCLUDE_FROM
+  # May be defined to keep the dependency generator from
+  # scanning specific files or directories for deps.
+  if(CPACK_RPM_REQUIRES_EXCLUDE_FROM)
+    if(CPACK_RPM_PACKAGE_DEBUG)
+      message("CPackRPM:Debug: User defined CPACK_RPM_REQUIRES_EXCLUDE_FROM = ${CPACK_RPM_REQUIRES_EXCLUDE_FROM}")
+    endif()
+    set(TMP_RPM_REQUIRES_EXCLUDE_FROM "%global __requires_exclude_from ${CPACK_RPM_REQUIRES_EXCLUDE_FROM}")
+  endif()
+
   # CPACK_RPM_POST_INSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_INSTALL_SCRIPT_FILE)
   # CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_UNINSTALL_SCRIPT_FILE)
   # CPACK_RPM_POST_TRANS_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_TRANS_SCRIPT_FILE)
@@ -1650,6 +1660,7 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 \@FILE_NAME_DEFINE\@
 %define _unpackaged_files_terminate_build 0
 \@TMP_RPM_SPEC_INSTALL_POST\@
+\@TMP_RPM_REQUIRES_EXCLUDE_FROM\@
 \@CPACK_RPM_SPEC_MORE_DEFINE\@
 \@CPACK_RPM_COMPRESSION_TYPE_TMP\@
 
@@ -1784,6 +1795,7 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 \@FILE_NAME_DEFINE\@
 %define _unpackaged_files_terminate_build 0
 \@TMP_RPM_SPEC_INSTALL_POST\@
+\@TMP_RPM_REQUIRES_EXCLUDE_FROM\@
 \@CPACK_RPM_SPEC_MORE_DEFINE\@
 \@CPACK_RPM_COMPRESSION_TYPE_TMP\@
 

+ 13 - 0
Modules/Internal/CPack/NSIS.template.in

@@ -564,21 +564,27 @@ FunctionEnd
 ;Languages
 
   !insertmacro MUI_LANGUAGE "English" ;first language is the default language
+  !insertmacro MUI_LANGUAGE "Afrikaans"
   !insertmacro MUI_LANGUAGE "Albanian"
   !insertmacro MUI_LANGUAGE "Arabic"
+  !insertmacro MUI_LANGUAGE "Asturian"
   !insertmacro MUI_LANGUAGE "Basque"
   !insertmacro MUI_LANGUAGE "Belarusian"
   !insertmacro MUI_LANGUAGE "Bosnian"
   !insertmacro MUI_LANGUAGE "Breton"
   !insertmacro MUI_LANGUAGE "Bulgarian"
+  !insertmacro MUI_LANGUAGE "Catalan"
+  !insertmacro MUI_LANGUAGE "Corsican"
   !insertmacro MUI_LANGUAGE "Croatian"
   !insertmacro MUI_LANGUAGE "Czech"
   !insertmacro MUI_LANGUAGE "Danish"
   !insertmacro MUI_LANGUAGE "Dutch"
+  !insertmacro MUI_LANGUAGE "Esperanto"
   !insertmacro MUI_LANGUAGE "Estonian"
   !insertmacro MUI_LANGUAGE "Farsi"
   !insertmacro MUI_LANGUAGE "Finnish"
   !insertmacro MUI_LANGUAGE "French"
+  !insertmacro MUI_LANGUAGE "Galician"
   !insertmacro MUI_LANGUAGE "German"
   !insertmacro MUI_LANGUAGE "Greek"
   !insertmacro MUI_LANGUAGE "Hebrew"
@@ -597,22 +603,29 @@ FunctionEnd
   !insertmacro MUI_LANGUAGE "Malay"
   !insertmacro MUI_LANGUAGE "Mongolian"
   !insertmacro MUI_LANGUAGE "Norwegian"
+  !insertmacro MUI_LANGUAGE "NorwegianNynorsk"
+  !insertmacro MUI_LANGUAGE "Pashto"
   !insertmacro MUI_LANGUAGE "Polish"
   !insertmacro MUI_LANGUAGE "Portuguese"
   !insertmacro MUI_LANGUAGE "PortugueseBR"
   !insertmacro MUI_LANGUAGE "Romanian"
   !insertmacro MUI_LANGUAGE "Russian"
+  !insertmacro MUI_LANGUAGE "ScotsGaelic"
   !insertmacro MUI_LANGUAGE "Serbian"
   !insertmacro MUI_LANGUAGE "SerbianLatin"
   !insertmacro MUI_LANGUAGE "SimpChinese"
   !insertmacro MUI_LANGUAGE "Slovak"
   !insertmacro MUI_LANGUAGE "Slovenian"
   !insertmacro MUI_LANGUAGE "Spanish"
+  !insertmacro MUI_LANGUAGE "SpanishInternational"
   !insertmacro MUI_LANGUAGE "Swedish"
+  !insertmacro MUI_LANGUAGE "Tatar"
   !insertmacro MUI_LANGUAGE "Thai"
   !insertmacro MUI_LANGUAGE "TradChinese"
   !insertmacro MUI_LANGUAGE "Turkish"
   !insertmacro MUI_LANGUAGE "Ukrainian"
+  !insertmacro MUI_LANGUAGE "Uzbek"
+  !insertmacro MUI_LANGUAGE "Vietnamese"
   !insertmacro MUI_LANGUAGE "Welsh"
 
 ;--------------------------------

+ 18 - 7
Modules/UseSWIG.cmake

@@ -192,12 +192,17 @@ ensure generated files will receive the required settings.
   If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
   itself. This property is only meaningful for
   :ref:`Makefile <Makefile Generators>`,
-  :ref:`Ninja <Ninja Generators>` and :generator:`Xcode` generators. Default
-  value is ``FALSE``.
+  :ref:`Ninja <Ninja Generators>`, :generator:`Xcode`, and
+  :ref:`Visual Studio <Visual Studio Generators>`
+  (:generator:`Visual Studio 11 2012` and above) generators. Default value is
+  ``FALSE``.
 
   .. versionadded:: 3.21
     Added the support of :generator:`Xcode` generator.
 
+  .. versionadded:: 3.22
+    Added the support of :ref:`Visual Studio Generators`.
+
 ``SWIG_MODULE_NAME``
   Specify the actual import name of the module in the target language.
   This is required if it cannot be scanned automatically from source
@@ -342,8 +347,10 @@ as well as ``SWIG``:
   If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
   itself. This variable is only meaningful for
   :ref:`Makefile <Makefile Generators>`,
-  :ref:`Ninja <Ninja Generators>` and :generator:`Xcode` generators. Default
-  value is ``FALSE``.
+  :ref:`Ninja <Ninja Generators>`, :generator:`Xcode`, and
+  :ref:`Visual Studio <Visual Studio Generators>`
+  (:generator:`Visual Studio 11 2012` and above) generators. Default value is
+  ``FALSE``.
 
   Source file property ``USE_SWIG_DEPENDENCIES``, if not defined, will be
   initialized with the value of this variable.
@@ -351,6 +358,9 @@ as well as ``SWIG``:
   .. versionadded:: 3.21
     Added the support of :generator:`Xcode` generator.
 
+  .. versionadded:: 3.22
+    Added the support of :ref:`Visual Studio Generators`.
+
 #]=======================================================================]
 
 cmake_policy(PUSH)
@@ -515,7 +525,7 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
   endif()
 
   set (use_swig_dependencies ${SWIG_USE_SWIG_DEPENDENCIES})
-  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode")
+  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
     get_property(use_swig_dependencies_set SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES SET)
     if (use_swig_dependencies_set)
       get_property(use_swig_dependencies SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES)
@@ -840,8 +850,9 @@ function(SWIG_ADD_LIBRARY name)
     set(SWIG_SOURCE_FILE_EXTENSIONS ".i")
   endif()
 
-  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode")
-    # For Makefiles and Ninja generators, use SWIG generated dependencies
+  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
+    # For Makefiles, Ninja, Xcode and Visual Studio generators,
+    # use SWIG generated dependencies if requested
     if (NOT DEFINED SWIG_USE_SWIG_DEPENDENCIES)
         set (SWIG_USE_SWIG_DEPENDENCIES OFF)
     endif()

+ 3 - 36
Source/CMakeLists.txt

@@ -10,36 +10,6 @@ if (NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
 endif()
 
 include(CheckIncludeFile)
-# Check if we can build support for ELF parsing.
-if(WIN32)
-  set(HAVE_ELF_H 0)
-elseif(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD")
-  CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H)
-else()
-  CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H)
-endif()
-if(HAVE_ELF_H)
-  set(CMake_USE_ELF_PARSER 1)
-elseif(HAIKU)
-  # On Haiku, we need to include elf32.h from the private headers
-  set(CMake_HAIKU_INCLUDE_DIRS
-    /boot/system/develop/headers/private/system
-    /boot/system/develop/headers/private/system/arch/x86
-    )
-
-  set(CMAKE_REQUIRED_INCLUDES ${CMake_HAIKU_INCLUDE_DIRS})
-  CHECK_INCLUDE_FILE("elf32.h" HAVE_ELF32_H)
-  unset(CMAKE_REQUIRED_INCLUDES)
-
-  if(HAVE_ELF32_H)
-    set(CMake_USE_ELF_PARSER 1)
-  else()
-    unset(CMake_HAIKU_INCLUDE_DIRS)
-    set(CMake_USE_ELF_PARSER)
-  endif()
-else()
-  set(CMake_USE_ELF_PARSER)
-endif()
 
 if(NOT CMake_DEFAULT_RECURSION_LIMIT)
   if(DEFINED ENV{DASHBOARD_TEST_FROM_CTEST})
@@ -111,11 +81,6 @@ include_directories(
   ${CMake_HAIKU_INCLUDE_DIRS}
   )
 
-# Check if we can build the ELF parser.
-if(CMake_USE_ELF_PARSER)
-  set(ELF_SRCS cmELF.h cmELF.cxx)
-endif()
-
 # Check if we can build the Mach-O parser.
 if(CMake_USE_MACH_PARSER)
   set(MACH_SRCS cmMachO.h cmMachO.cxx)
@@ -245,7 +210,8 @@ set(SRCS
   cmDocumentationSection.cxx
   cmDynamicLoader.cxx
   cmDynamicLoader.h
-  ${ELF_SRCS}
+  cmELF.h
+  cmELF.cxx
   cmExprParserHelper.cxx
   cmExportBuildAndroidMKGenerator.h
   cmExportBuildAndroidMKGenerator.cxx
@@ -996,6 +962,7 @@ set(CTEST_SRCS cmCTest.cxx
   CTest/cmCTestSubmitHandler.cxx
   CTest/cmCTestTestCommand.cxx
   CTest/cmCTestTestHandler.cxx
+  CTest/cmCTestTestMeasurementXMLParser.cxx
   CTest/cmCTestUpdateCommand.cxx
   CTest/cmCTestUpdateHandler.cxx
   CTest/cmCTestUploadCommand.cxx

+ 1 - 1
Source/CMakeVersion.cmake

@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 21)
-set(CMake_VERSION_PATCH 1)
+set(CMake_VERSION_PATCH 20210728)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 

+ 154 - 172
Source/CPack/cmCPackDebGenerator.cxx

@@ -2,11 +2,12 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCPackDebGenerator.h"
 
-#include <cstdlib>
+#include <algorithm>
 #include <cstring>
 #include <map>
 #include <ostream>
 #include <set>
+#include <stdexcept>
 #include <utility>
 
 #include "cmsys/Glob.hxx"
@@ -54,7 +55,7 @@ private:
   const std::string TopLevelDir;
   const std::string TemporaryDir;
   const char* DebianArchiveType;
-  int NumThreads;
+  long NumThreads;
   const std::map<std::string, std::string> ControlValues;
   const bool GenShLibs;
   const std::string ShLibsFilename;
@@ -98,19 +99,19 @@ DebGenerator::DebGenerator(
     debianCompressionType = "gzip";
   }
 
-  if (!strcmp(debianCompressionType, "lzma")) {
+  if (!std::strcmp(debianCompressionType, "lzma")) {
     this->CompressionSuffix = ".lzma";
     this->TarCompressionType = cmArchiveWrite::CompressLZMA;
-  } else if (!strcmp(debianCompressionType, "xz")) {
+  } else if (!std::strcmp(debianCompressionType, "xz")) {
     this->CompressionSuffix = ".xz";
     this->TarCompressionType = cmArchiveWrite::CompressXZ;
-  } else if (!strcmp(debianCompressionType, "bzip2")) {
+  } else if (!std::strcmp(debianCompressionType, "bzip2")) {
     this->CompressionSuffix = ".bz2";
     this->TarCompressionType = cmArchiveWrite::CompressBZip2;
-  } else if (!strcmp(debianCompressionType, "gzip")) {
+  } else if (!std::strcmp(debianCompressionType, "gzip")) {
     this->CompressionSuffix = ".gz";
     this->TarCompressionType = cmArchiveWrite::CompressGZip;
-  } else if (!strcmp(debianCompressionType, "none")) {
+  } else if (!std::strcmp(debianCompressionType, "none")) {
     this->CompressionSuffix.clear();
     this->TarCompressionType = cmArchiveWrite::CompressNone;
   } else {
@@ -119,16 +120,15 @@ DebGenerator::DebGenerator(
                     << debianCompressionType << std::endl);
   }
 
-  if (numThreads == nullptr) {
-    numThreads = "1";
-  }
-
-  char* endptr;
-  this->NumThreads = static_cast<int>(strtol(numThreads, &endptr, 10));
-  if (numThreads != endptr && *endptr != '\0') {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Unrecognized number of threads: " << numThreads
-                                                     << std::endl);
+  if (numThreads != nullptr) {
+    if (!cmStrToLong(numThreads, &this->NumThreads)) {
+      this->NumThreads = 1;
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Unrecognized number of threads: " << numThreads
+                                                       << std::endl);
+    }
+  } else {
+    this->NumThreads = 1;
   }
 }
 
@@ -187,7 +187,8 @@ bool DebGenerator::generateDataTar() const
     return false;
   }
   cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType,
-                          this->DebianArchiveType, 0, this->NumThreads);
+                          this->DebianArchiveType, 0,
+                          static_cast<int>(this->NumThreads));
   data_tar.Open();
 
   // uid/gid should be the one of the root user, and this root user has
@@ -248,11 +249,15 @@ bool DebGenerator::generateDataTar() const
     // do not recurse because the loop will do it
     if (!data_tar.Add(file, topLevelLength, ".", false)) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Problem adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: " << file << std::endl
-                      << "#error:" << data_tar.GetError() << std::endl);
+                    "Problem adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: "
+                      << file
+                      << "\n"
+                         "#error:"
+                      << data_tar.GetError() << std::endl);
       return false;
     }
   }
@@ -334,11 +339,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
       !control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(),
                        ".")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Error adding file to tar:"
-                    << std::endl
-                    << "#top level directory: " << this->WorkDir << std::endl
-                    << "#file: \"control\" or \"md5sums\"" << std::endl
-                    << "#error:" << control_tar.GetError() << std::endl);
+                  "Error adding file to tar:\n"
+                  "#top level directory: "
+                    << this->WorkDir
+                    << "\n"
+                       "#file: \"control\" or \"md5sums\"\n"
+                       "#error:"
+                    << control_tar.GetError() << std::endl);
     return false;
   }
 
@@ -346,11 +353,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
   if (this->GenShLibs) {
     if (!control_tar.Add(this->ShLibsFilename, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Error adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: \"shlibs\"" << std::endl
-                      << "#error:" << control_tar.GetError() << std::endl);
+                    "Error adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: \"shlibs\"\n"
+                         "#error:"
+                      << control_tar.GetError() << std::endl);
       return false;
     }
   }
@@ -360,11 +369,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     control_tar.SetPermissions(permission755);
     if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Error adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: \"postinst\"" << std::endl
-                      << "#error:" << control_tar.GetError() << std::endl);
+                    "Error adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: \"postinst\"\n"
+                         "#error:"
+                      << control_tar.GetError() << std::endl);
       return false;
     }
     control_tar.SetPermissions(permission644);
@@ -374,11 +385,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     control_tar.SetPermissions(permission755);
     if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Error adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: \"postinst\"" << std::endl
-                      << "#error:" << control_tar.GetError() << std::endl);
+                    "Error adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: \"postinst\"\n"
+                         "#error:"
+                      << control_tar.GetError() << std::endl);
       return false;
     }
     control_tar.SetPermissions(permission644);
@@ -412,11 +425,12 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
       // if we can copy the file, it means it does exist, let's add it:
       if (!cmsys::SystemTools::FileExists(i)) {
         cmCPackLogger(cmCPackLog::LOG_WARNING,
-                      "Adding file to tar:" << std::endl
-                                            << "#top level directory: "
-                                            << this->WorkDir << std::endl
-                                            << "#missing file: " << i
-                                            << std::endl);
+                      "Adding file to tar:\n"
+                      "#top level directory: "
+                        << this->WorkDir
+                        << "\n"
+                           "#missing file: "
+                        << i << std::endl);
       }
 
       if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
@@ -451,17 +465,37 @@ bool DebGenerator::generateDeb() const
       !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
       !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Error creating debian package:"
-                    << std::endl
-                    << "#top level directory: " << this->TopLevelDir
-                    << std::endl
-                    << "#file: " << this->OutputName << std::endl
-                    << "#error:" << deb.GetError() << std::endl);
+                  "Error creating debian package:\n"
+                  "#top level directory: "
+                    << this->TopLevelDir
+                    << "\n"
+                       "#file: "
+                    << this->OutputName
+                    << "\n"
+                       "#error:"
+                    << deb.GetError() << std::endl);
     return false;
   }
   return true;
 }
 
+std::vector<std::string> findFilesIn(const std::string& path)
+{
+  cmsys::Glob gl;
+  std::string findExpr = path + "/*";
+  gl.RecurseOn();
+  gl.SetRecurseListDirs(true);
+  gl.SetRecurseThroughSymlinks(false);
+  if (!gl.FindFiles(findExpr)) {
+    throw std::runtime_error(
+      "Cannot find any files in the installed directory");
+  }
+  std::vector<std::string> files{ gl.GetFiles() };
+  // Sort files so that they have a reproducible order
+  std::sort(files.begin(), files.end());
+  return files;
+}
+
 } // end anonymous namespace
 
 cmCPackDebGenerator::cmCPackDebGenerator() = default;
@@ -480,7 +514,6 @@ int cmCPackDebGenerator::InitializeInternal()
 int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
                                         std::string const& packageName)
 {
-  int retval = 1;
   // Begin the archive for this pack
   std::string localToplevel(initialTopLevel);
   std::string packageFileName(
@@ -507,101 +540,48 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
   if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackDeb.cmake" << std::endl);
-    retval = 0;
-    return retval;
-  }
-
-  { // Isolate globbing of binaries vs. dbgsyms
-    cmsys::Glob gl;
-    std::string findExpr(this->GetOption("GEN_WDIR"));
-    findExpr += "/*";
-    gl.RecurseOn();
-    gl.SetRecurseListDirs(true);
-    gl.SetRecurseThroughSymlinks(false);
-    if (!gl.FindFiles(findExpr)) {
-      cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Cannot find any files in the installed directory"
-                      << std::endl);
-      return 0;
-    }
-    this->packageFiles = gl.GetFiles();
-  }
-
-  int res = this->createDeb();
-  if (res != 1) {
-    retval = 0;
-  }
-  // add the generated package to package file names list
-  packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
-                             this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
-  this->packageFileNames.push_back(std::move(packageFileName));
-
-  if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") &&
-      this->GetOption("GEN_DBGSYMDIR")) {
-    cmsys::Glob gl;
-    std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
-    findExpr += "/*";
-    gl.RecurseOn();
-    gl.SetRecurseListDirs(true);
-    gl.SetRecurseThroughSymlinks(false);
-    if (!gl.FindFiles(findExpr)) {
-      cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Cannot find any files in the installed directory"
-                      << std::endl);
-      return 0;
-    }
-    this->packageFiles = gl.GetFiles();
-
-    res = this->createDbgsymDDeb();
-    if (res != 1) {
-      retval = 0;
-    }
-    // add the generated package to package file names list
-    packageFileName =
-      cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
-               this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"));
-    this->packageFileNames.push_back(std::move(packageFileName));
+    return 0;
   }
 
-  return retval;
+  return this->createDebPackages();
 }
 
 int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
 {
-  int retval = 1;
-  /* Reset package file name list it will be populated during the
-   * component packaging run*/
+  // Reset package file name list it will be populated during the
+  // component packaging run
   this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
+  int retval = 1;
   // The default behavior is to have one package by component group
   // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
-  if (!ignoreGroup) {
-    for (auto const& compG : this->ComponentGroups) {
-      cmCPackLogger(cmCPackLog::LOG_VERBOSE,
-                    "Packaging component group: " << compG.first << std::endl);
-      // Begin the archive for this group
-      retval &= this->PackageOnePack(initialTopLevel, compG.first);
-    }
-    // Handle Orphan components (components not belonging to any groups)
+  if (ignoreGroup) {
+    // CPACK_COMPONENTS_IGNORE_GROUPS is set
+    // We build 1 package per component
     for (auto const& comp : this->Components) {
-      // Does the component belong to a group?
-      if (comp.second.Group == nullptr) {
-        cmCPackLogger(
-          cmCPackLog::LOG_VERBOSE,
-          "Component <"
-            << comp.second.Name
-            << "> does not belong to any group, package it separately."
-            << std::endl);
-        // Begin the archive for this orphan component
-        retval &= this->PackageOnePack(initialTopLevel, comp.first);
-      }
+      retval &= this->PackageOnePack(initialTopLevel, comp.first);
     }
+    return retval;
   }
-  // CPACK_COMPONENTS_IGNORE_GROUPS is set
-  // We build 1 package per component
-  else {
-    for (auto const& comp : this->Components) {
+
+  for (auto const& compG : this->ComponentGroups) {
+    cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+                  "Packaging component group: " << compG.first << std::endl);
+    // Begin the archive for this group
+    retval &= this->PackageOnePack(initialTopLevel, compG.first);
+  }
+  // Handle Orphan components (components not belonging to any groups)
+  for (auto const& comp : this->Components) {
+    // Does the component belong to a group?
+    if (comp.second.Group == nullptr) {
+      cmCPackLogger(
+        cmCPackLog::LOG_VERBOSE,
+        "Component <"
+          << comp.second.Name
+          << "> does not belong to any group, package it separately."
+          << std::endl);
+      // Begin the archive for this orphan component
       retval &= this->PackageOnePack(initialTopLevel, comp.first);
     }
   }
@@ -612,7 +592,6 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
 int cmCPackDebGenerator::PackageComponentsAllInOne(
   const std::string& compInstDirName)
 {
-  int retval = 1;
   /* Reset package file name list it will be populated during the
    * component packaging run*/
   this->packageFileNames.clear();
@@ -655,33 +634,10 @@ int cmCPackDebGenerator::PackageComponentsAllInOne(
   if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackDeb.cmake" << std::endl);
-    retval = 0;
-    return retval;
-  }
-
-  cmsys::Glob gl;
-  std::string findExpr(this->GetOption("GEN_WDIR"));
-  findExpr += "/*";
-  gl.RecurseOn();
-  gl.SetRecurseListDirs(true);
-  gl.SetRecurseThroughSymlinks(false);
-  if (!gl.FindFiles(findExpr)) {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Cannot find any files in the installed directory"
-                    << std::endl);
     return 0;
   }
-  this->packageFiles = gl.GetFiles();
 
-  int res = this->createDeb();
-  if (res != 1) {
-    retval = 0;
-  }
-  // add the generated package to package file names list
-  packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
-                             this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
-  this->packageFileNames.push_back(std::move(packageFileName));
-  return retval;
+  return this->createDebPackages();
 }
 
 int cmCPackDebGenerator::PackageFiles()
@@ -705,7 +661,40 @@ int cmCPackDebGenerator::PackageFiles()
   return this->PackageComponentsAllInOne("");
 }
 
-int cmCPackDebGenerator::createDeb()
+bool cmCPackDebGenerator::createDebPackages()
+{
+  auto make_package = [this](const char* const path,
+                             const char* const output_var,
+                             bool (cmCPackDebGenerator::*creator)()) -> bool {
+    try {
+      this->packageFiles = findFilesIn(path);
+    } catch (const std::runtime_error& ex) {
+      cmCPackLogger(cmCPackLog::LOG_ERROR, ex.what() << std::endl);
+      return false;
+    }
+
+    if ((this->*creator)()) {
+      // add the generated package to package file names list
+      this->packageFileNames.emplace_back(
+        cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
+                 this->GetOption(output_var)));
+      return true;
+    }
+    return false;
+  };
+  bool retval =
+    make_package(this->GetOption("GEN_WDIR"), "GEN_CPACK_OUTPUT_FILE_NAME",
+                 &cmCPackDebGenerator::createDeb);
+  const char* const dbgsymdir_path = this->GetOption("GEN_DBGSYMDIR");
+  if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") && dbgsymdir_path) {
+    retval = make_package(dbgsymdir_path, "GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME",
+                          &cmCPackDebGenerator::createDbgsymDDeb) &&
+      retval;
+  }
+  return int(retval);
+}
+
+bool cmCPackDebGenerator::createDeb()
 {
   std::map<std::string, std::string> controlValues;
 
@@ -829,13 +818,10 @@ int cmCPackDebGenerator::createDeb()
     this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
     this->packageFiles);
 
-  if (!gen.generate()) {
-    return 0;
-  }
-  return 1;
+  return gen.generate();
 }
 
-int cmCPackDebGenerator::createDbgsymDDeb()
+bool cmCPackDebGenerator::createDbgsymDDeb()
 {
   // Packages containing debug symbols follow the same structure as .debs
   // but have different metadata and content.
@@ -875,7 +861,6 @@ int cmCPackDebGenerator::createDbgsymDDeb()
   DebGenerator gen(
     this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
     this->GetOption("GEN_DBGSYMDIR"),
-
     this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
     this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
     this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
@@ -885,10 +870,7 @@ int cmCPackDebGenerator::createDbgsymDDeb()
     this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
     this->packageFiles);
 
-  if (!gen.generate()) {
-    return 0;
-  }
-  return 1;
+  return gen.generate();
 }
 
 bool cmCPackDebGenerator::SupportsComponentInstallation() const

+ 3 - 2
Source/CPack/cmCPackDebGenerator.h

@@ -63,8 +63,9 @@ protected:
     const std::string& componentName) override;
 
 private:
-  int createDeb();
-  int createDbgsymDDeb();
+  bool createDebPackages();
+  bool createDeb();
+  bool createDbgsymDDeb();
 
   std::vector<std::string> packageFiles;
 };

+ 1 - 1
Source/CTest/cmCTestMemCheckHandler.cxx

@@ -305,7 +305,7 @@ int cmCTestMemCheckHandler::GetDefectCount() const
   return this->DefectCount;
 }
 
-void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
+void cmCTestMemCheckHandler::GenerateCTestXML(cmXMLWriter& xml)
 {
   if (!this->CTest->GetProduceXML()) {
     return;

+ 2 - 2
Source/CTest/cmCTestMemCheckHandler.h

@@ -119,9 +119,9 @@ private:
   bool InitializeMemoryChecking();
 
   /**
-   * Generate the Dart compatible output
+   * Generate CTest DynamicAnalysis.xml files
    */
-  void GenerateDartOutput(cmXMLWriter& xml) override;
+  void GenerateCTestXML(cmXMLWriter& xml) override;
 
   std::vector<std::string> CustomPreMemCheck;
   std::vector<std::string> CustomPostMemCheck;

+ 5 - 0
Source/CTest/cmCTestMultiProcessHandler.cxx

@@ -1026,6 +1026,11 @@ static Json::Value DumpCTestProperties(
     properties.append(DumpCTestProperty(
       "ENVIRONMENT", DumpToJsonArray(testProperties.Environment)));
   }
+  if (!testProperties.EnvironmentModification.empty()) {
+    properties.append(DumpCTestProperty(
+      "ENVIRONMENT_MODIFICATION",
+      DumpToJsonArray(testProperties.EnvironmentModification)));
+  }
   if (!testProperties.ErrorRegularExpressions.empty()) {
     properties.append(DumpCTestProperty(
       "FAIL_REGULAR_EXPRESSION",

+ 171 - 11
Source/CTest/cmCTestRunTest.cxx

@@ -2,17 +2,22 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestRunTest.h"
 
+#include <algorithm>
 #include <chrono>
 #include <cstddef> // IWYU pragma: keep
 #include <cstdint>
 #include <cstdio>
 #include <cstring>
+#include <functional>
 #include <iomanip>
 #include <ratio>
 #include <sstream>
 #include <utility>
 
 #include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
 
@@ -44,7 +49,9 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
   // Check for special CTest XML tags in this line of output.
   // If any are found, this line is excluded from ProcessOutput.
   if (!line.empty() && line.find("<CTest") != std::string::npos) {
+    bool ctest_tag_found = false;
     if (this->TestHandler->CustomCompletionStatusRegex.find(line)) {
+      ctest_tag_found = true;
       this->TestResult.CustomCompletionStatus =
         this->TestHandler->CustomCompletionStatusRegex.match(1);
       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -52,6 +59,20 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
                                   << "Test Details changed to '"
                                   << this->TestResult.CustomCompletionStatus
                                   << "'" << std::endl);
+    } else if (this->TestHandler->CustomLabelRegex.find(line)) {
+      ctest_tag_found = true;
+      auto label = this->TestHandler->CustomLabelRegex.match(1);
+      auto& labels = this->TestProperties->Labels;
+      if (std::find(labels.begin(), labels.end(), label) == labels.end()) {
+        labels.push_back(label);
+        std::sort(labels.begin(), labels.end());
+        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+                   this->GetIndex()
+                     << ": "
+                     << "Test Label added: '" << label << "'" << std::endl);
+      }
+    }
+    if (ctest_tag_found) {
       return;
     }
   }
@@ -245,7 +266,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
     *this->TestHandler->LogFile << "Test time = " << buf << std::endl;
   }
 
-  this->DartProcessing();
+  this->ParseOutputForMeasurements();
 
   // if this is doing MemCheck then all the output needs to be put into
   // Output since that is what is parsed by cmCTestMemCheckHandler
@@ -623,6 +644,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
 
   return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
                            &this->TestProperties->Environment,
+                           &this->TestProperties->EnvironmentModification,
                            &this->TestProperties->Affinity);
 }
 
@@ -679,28 +701,45 @@ void cmCTestRunTest::ComputeArguments()
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                this->Index << ":  " << env << std::endl);
   }
+  if (!this->TestProperties->EnvironmentModification.empty()) {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+               this->Index << ": "
+                           << "Environment variable modifications: "
+                           << std::endl);
+  }
+  for (std::string const& envmod :
+       this->TestProperties->EnvironmentModification) {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+               this->Index << ":  " << envmod << std::endl);
+  }
 }
 
-void cmCTestRunTest::DartProcessing()
+void cmCTestRunTest::ParseOutputForMeasurements()
 {
   if (!this->ProcessOutput.empty() &&
-      this->ProcessOutput.find("<DartMeasurement") != std::string::npos) {
-    if (this->TestHandler->DartStuff.find(this->ProcessOutput)) {
-      this->TestResult.DartString = this->TestHandler->DartStuff.match(1);
+      (this->ProcessOutput.find("<DartMeasurement") != std::string::npos ||
+       this->ProcessOutput.find("<CTestMeasurement") != std::string::npos)) {
+    if (this->TestHandler->AllTestMeasurementsRegex.find(
+          this->ProcessOutput)) {
+      this->TestResult.TestMeasurementsOutput =
+        this->TestHandler->AllTestMeasurementsRegex.match(1);
       // keep searching and replacing until none are left
-      while (this->TestHandler->DartStuff1.find(this->ProcessOutput)) {
+      while (this->TestHandler->SingleTestMeasurementRegex.find(
+        this->ProcessOutput)) {
         // replace the exact match for the string
         cmSystemTools::ReplaceString(
-          this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(),
-          "");
+          this->ProcessOutput,
+          this->TestHandler->SingleTestMeasurementRegex.match(1).c_str(), "");
       }
     }
   }
 }
 
-bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
-                                 std::vector<std::string>* environment,
-                                 std::vector<size_t>* affinity)
+bool cmCTestRunTest::ForkProcess(
+  cmDuration testTimeOut, bool explicitTimeout,
+  std::vector<std::string>* environment,
+  std::vector<std::string>* environment_modification,
+  std::vector<size_t>* affinity)
 {
   this->TestProcess->SetId(this->Index);
   this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
@@ -749,6 +788,127 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
     }
   }
 
+  if (environment_modification && !environment_modification->empty()) {
+    std::map<std::string, cm::optional<std::string>> env_application;
+
+#ifdef _WIN32
+    char path_sep = ';';
+#else
+    char path_sep = ':';
+#endif
+
+    auto apply_diff =
+      [&env_application](const std::string& name,
+                         std::function<void(std::string&)> const& apply) {
+        auto entry = env_application.find(name);
+        std::string output;
+        if (entry != env_application.end() && entry->second) {
+          output = *entry->second;
+        }
+        apply(output);
+        entry->second = output;
+      };
+
+    bool err_occurred = false;
+
+    for (auto const& envmod : *environment_modification) {
+      // Split on `=`
+      auto const eq_loc = envmod.find_first_of('=');
+      if (eq_loc == std::string::npos) {
+        cmCTestLog(this->CTest, ERROR_MESSAGE,
+                   "Error: Missing `=` after the variable name in: "
+                     << envmod << std::endl);
+        err_occurred = true;
+        continue;
+      }
+      auto const name = envmod.substr(0, eq_loc);
+
+      // Split value on `:`
+      auto const op_value_start = eq_loc + 1;
+      auto const colon_loc = envmod.find_first_of(':', op_value_start);
+      if (colon_loc == std::string::npos) {
+        cmCTestLog(this->CTest, ERROR_MESSAGE,
+                   "Error: Missing `:` after the operation in: " << envmod
+                                                                 << std::endl);
+        err_occurred = true;
+        continue;
+      }
+      auto const op =
+        envmod.substr(op_value_start, colon_loc - op_value_start);
+
+      auto const value_start = colon_loc + 1;
+      auto const value = envmod.substr(value_start);
+
+      // Determine what to do with the operation.
+      if (op == "reset"_s) {
+        auto entry = env_application.find(name);
+        if (entry != env_application.end()) {
+          env_application.erase(entry);
+        }
+      } else if (op == "set"_s) {
+        env_application[name] = value;
+      } else if (op == "unset"_s) {
+        env_application[name] = {};
+      } else if (op == "string_append"_s) {
+        apply_diff(name, [&value](std::string& output) { output += value; });
+      } else if (op == "string_prepend"_s) {
+        apply_diff(name,
+                   [&value](std::string& output) { output.insert(0, value); });
+      } else if (op == "path_list_append"_s) {
+        apply_diff(name, [&value, path_sep](std::string& output) {
+          if (!output.empty()) {
+            output += path_sep;
+          }
+          output += value;
+        });
+      } else if (op == "path_list_prepend"_s) {
+        apply_diff(name, [&value, path_sep](std::string& output) {
+          if (!output.empty()) {
+            output.insert(output.begin(), path_sep);
+          }
+          output.insert(0, value);
+        });
+      } else if (op == "cmake_list_append"_s) {
+        apply_diff(name, [&value](std::string& output) {
+          if (!output.empty()) {
+            output += ';';
+          }
+          output += value;
+        });
+      } else if (op == "cmake_list_prepend"_s) {
+        apply_diff(name, [&value](std::string& output) {
+          if (!output.empty()) {
+            output.insert(output.begin(), ';');
+          }
+          output.insert(0, value);
+        });
+      } else {
+        cmCTestLog(this->CTest, ERROR_MESSAGE,
+                   "Error: Unrecognized environment manipulation argument: "
+                     << op << std::endl);
+        err_occurred = true;
+        continue;
+      }
+    }
+
+    if (err_occurred) {
+      return false;
+    }
+
+    for (auto const& env_apply : env_application) {
+      if (env_apply.second) {
+        auto const env_update =
+          cmStrCat(env_apply.first, '=', *env_apply.second);
+        cmSystemTools::PutEnv(env_update);
+        envMeasurement << env_update << std::endl;
+      } else {
+        cmSystemTools::UnsetEnv(env_apply.first.c_str());
+        // Signify that this variable is being actively unset
+        envMeasurement << "#" << env_apply.first << "=" << std::endl;
+      }
+    }
+  }
+
   if (this->UseAllocatedResources) {
     std::vector<std::string> envLog;
     this->SetupResourcesEnvironment(&envLog);

+ 2 - 1
Source/CTest/cmCTestRunTest.h

@@ -109,10 +109,11 @@ public:
 
 private:
   bool NeedsToRepeat();
-  void DartProcessing();
+  void ParseOutputForMeasurements();
   void ExeNotFound(std::string exe);
   bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
                    std::vector<std::string>* environment,
+                   std::vector<std::string>* environment_modification,
                    std::vector<size_t>* affinity);
   void WriteLogOutputTop(size_t completed, size_t total);
   // Run post processing of the process output for MemCheck

+ 58 - 138
Source/CTest/cmCTestTestHandler.cxx

@@ -32,6 +32,7 @@
 #include "cmCTest.h"
 #include "cmCTestMultiProcessHandler.h"
 #include "cmCTestResourceGroupsLexerHelper.h"
+#include "cmCTestTestMeasurementXMLParser.h"
 #include "cmDuration.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratedFileStream.h"
@@ -303,15 +304,24 @@ cmCTestTestHandler::cmCTestTestHandler()
   // Support for JUnit XML output.
   this->JUnitXMLFileName = "";
 
-  // regex to detect <DartMeasurement>...</DartMeasurement>
-  this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
-  // regex to detect each individual <DartMeasurement>...</DartMeasurement>
-  this->DartStuff1.compile(
-    "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
+  // Regular expressions to scan test output for custom measurements.
 
-  // regex to detect <CTestDetails>...</CTestDetails>
+  // Capture the whole section of test output from the first opening
+  // <(CTest|Dart)Measurement*> tag to the last </(CTest|Dart)Measurement*>
+  // closing tag.
+  this->AllTestMeasurementsRegex.compile(
+    "(<(CTest|Dart)Measurement.*/(CTest|Dart)Measurement[a-zA-Z]*>)");
+
+  // Capture a single <(CTest|Dart)Measurement*> XML element.
+  this->SingleTestMeasurementRegex.compile(
+    "(<(CTest|Dart)Measurement[^<]*</(CTest|Dart)Measurement[a-zA-Z]*>)");
+
+  // Capture content from <CTestDetails>...</CTestDetails>
   this->CustomCompletionStatusRegex.compile(
     "<CTestDetails>(.*)</CTestDetails>");
+
+  // Capture content from <CTestLabel>...</CTestLabel>
+  this->CustomLabelRegex.compile("<CTestLabel>(.*)</CTestLabel>");
 }
 
 void cmCTestTestHandler::Initialize()
@@ -692,7 +702,7 @@ bool cmCTestTestHandler::GenerateXML()
       return false;
     }
     cmXMLWriter xml(xmlfile);
-    this->GenerateDartOutput(xml);
+    this->GenerateCTestXML(xml);
   }
 
   return true;
@@ -1400,7 +1410,7 @@ void cmCTestTestHandler::GenerateTestCommand(
 {
 }
 
-void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
+void cmCTestTestHandler::GenerateCTestXML(cmXMLWriter& xml)
 {
   if (!this->CTest->GetProduceXML()) {
     return;
@@ -1436,7 +1446,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
         xml.Element("Value", result.ReturnValue);
         xml.EndElement(); // NamedMeasurement
       }
-      this->GenerateRegressionImages(xml, result.DartString);
+      this->RecordCustomTestMeasurements(xml, result.TestMeasurementsOutput);
       xml.StartElement("NamedMeasurement");
       xml.Attribute("type", "numeric/double");
       xml.Attribute("name", "Execution Time");
@@ -1976,124 +1986,48 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
   }
 }
 
-// Just for convenience
-#define SPACE_REGEX "[ \t\r\n]"
-void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
-                                                  const std::string& dart)
-{
-  cmsys::RegularExpression twoattributes(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurement>");
-  cmsys::RegularExpression threeattributes(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurement>");
-  cmsys::RegularExpression fourattributes(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurement>");
-  cmsys::RegularExpression cdatastart(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>" SPACE_REGEX "*<!\\[CDATA\\[");
-  cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>");
-  cmsys::RegularExpression measurementfile(
-    "<DartMeasurementFile" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurementFile>");
-
-  bool done = false;
-  std::string cxml = dart;
-  while (!done) {
-    if (twoattributes.find(cxml)) {
-      xml.StartElement("NamedMeasurement");
-      xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2));
-      xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4));
-      xml.Element("Value", twoattributes.match(5));
-      xml.EndElement();
-      cxml.erase(twoattributes.start(),
-                 twoattributes.end() - twoattributes.start());
-    } else if (threeattributes.find(cxml)) {
-      xml.StartElement("NamedMeasurement");
-      xml.Attribute(threeattributes.match(1).c_str(),
-                    threeattributes.match(2));
-      xml.Attribute(threeattributes.match(3).c_str(),
-                    threeattributes.match(4));
-      xml.Attribute(threeattributes.match(5).c_str(),
-                    threeattributes.match(6));
-      xml.Element("Value", twoattributes.match(7));
-      xml.EndElement();
-      cxml.erase(threeattributes.start(),
-                 threeattributes.end() - threeattributes.start());
-    } else if (fourattributes.find(cxml)) {
+void cmCTestTestHandler::RecordCustomTestMeasurements(cmXMLWriter& xml,
+                                                      std::string content)
+{
+  while (this->SingleTestMeasurementRegex.find(content)) {
+    // Extract regex match from content and parse it as an XML element.
+    auto measurement_str = this->SingleTestMeasurementRegex.match(1);
+    auto parser = cmCTestTestMeasurementXMLParser();
+    parser.Parse(measurement_str.c_str());
+
+    if (parser.ElementName == "CTestMeasurement" ||
+        parser.ElementName == "DartMeasurement") {
       xml.StartElement("NamedMeasurement");
-      xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2));
-      xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4));
-      xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6));
-      xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8));
-      xml.Element("Value", twoattributes.match(9));
+      xml.Attribute("type", parser.MeasurementType);
+      xml.Attribute("name", parser.MeasurementName);
+      xml.Element("Value", parser.CharacterData);
       xml.EndElement();
-      cxml.erase(fourattributes.start(),
-                 fourattributes.end() - fourattributes.start());
-    } else if (cdatastart.find(cxml) && cdataend.find(cxml)) {
-      xml.StartElement("NamedMeasurement");
-      xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2));
-      xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4));
-      xml.StartElement("Value");
-      xml.CData(
-        cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end()));
-      xml.EndElement(); // Value
-      xml.EndElement(); // NamedMeasurement
-      cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start());
-    } else if (measurementfile.find(cxml)) {
-      const std::string& filename =
-        cmCTest::CleanString(measurementfile.match(5));
-      if (cmSystemTools::FileExists(filename)) {
+    } else if (parser.ElementName == "CTestMeasurementFile" ||
+               parser.ElementName == "DartMeasurementFile") {
+      const std::string& filename = cmCTest::CleanString(parser.CharacterData);
+      if (!cmSystemTools::FileExists(filename)) {
+        xml.StartElement("NamedMeasurement");
+        xml.Attribute("name", parser.MeasurementName);
+        xml.Attribute("text", "text/string");
+        xml.Element("Value", "File " + filename + " not found");
+        xml.EndElement();
+        cmCTestOptionalLog(
+          this->CTest, HANDLER_OUTPUT,
+          "File \"" << filename << "\" not found." << std::endl, this->Quiet);
+      } else {
         long len = cmSystemTools::FileLength(filename);
-        std::string k1 = measurementfile.match(1);
-        std::string v1 = measurementfile.match(2);
-        std::string k2 = measurementfile.match(3);
-        std::string v2 = measurementfile.match(4);
         if (len == 0) {
-          if (cmSystemTools::LowerCase(k1) == "type") {
-            v1 = "text/string";
-          }
-          if (cmSystemTools::LowerCase(k2) == "type") {
-            v2 = "text/string";
-          }
-
           xml.StartElement("NamedMeasurement");
-          xml.Attribute(k1.c_str(), v1);
-          xml.Attribute(k2.c_str(), v2);
+          xml.Attribute("name", parser.MeasurementName);
+          xml.Attribute("type", "text/string");
           xml.Attribute("encoding", "none");
           xml.Element("Value", "Image " + filename + " is empty");
           xml.EndElement();
         } else {
-          std::string type;
-          std::string name;
-          if (cmSystemTools::LowerCase(k1) == "type") {
-            type = v1;
-          } else if (cmSystemTools::LowerCase(k2) == "type") {
-            type = v2;
-          }
-          if (cmSystemTools::LowerCase(k1) == "name") {
-            name = v1;
-          } else if (cmSystemTools::LowerCase(k2) == "name") {
-            name = v2;
-          }
-          if (type == "file") {
+          if (parser.MeasurementType == "file") {
             // Treat this measurement like an "ATTACHED_FILE" when the type
             // is explicitly "file" (not an image).
-            this->AttachFile(xml, filename, name);
+            this->AttachFile(xml, filename, parser.MeasurementName);
           } else {
             cmsys::ifstream ifs(filename.c_str(),
                                 std::ios::in
@@ -2110,10 +2044,8 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
                                              encoded_buffer.get(), 1);
 
             xml.StartElement("NamedMeasurement");
-            xml.Attribute(measurementfile.match(1).c_str(),
-                          measurementfile.match(2));
-            xml.Attribute(measurementfile.match(3).c_str(),
-                          measurementfile.match(4));
+            xml.Attribute("name", parser.MeasurementName);
+            xml.Attribute("type", parser.MeasurementType);
             xml.Attribute("encoding", "base64");
             std::ostringstream ostr;
             for (size_t cc = 0; cc < rlen; cc++) {
@@ -2126,25 +2058,11 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
             xml.EndElement(); // NamedMeasurement
           }
         }
-      } else {
-        int idx = 4;
-        if (measurementfile.match(1) == "name") {
-          idx = 2;
-        }
-        xml.StartElement("NamedMeasurement");
-        xml.Attribute("name", measurementfile.match(idx));
-        xml.Attribute("text", "text/string");
-        xml.Element("Value", "File " + filename + " not found");
-        xml.EndElement();
-        cmCTestOptionalLog(
-          this->CTest, HANDLER_OUTPUT,
-          "File \"" << filename << "\" not found." << std::endl, this->Quiet);
       }
-      cxml.erase(measurementfile.start(),
-                 measurementfile.end() - measurementfile.start());
-    } else {
-      done = true;
     }
+
+    // Remove this element from content.
+    cmSystemTools::ReplaceString(content, measurement_str.c_str(), "");
   }
 }
 
@@ -2247,7 +2165,7 @@ bool cmCTestTestHandler::SetTestsProperties(
 
             // Ensure we have complete triples otherwise the data is corrupt.
             if (triples.size() % 3 == 0) {
-              cmState state;
+              cmState state(cmState::Unknown);
               rt.Backtrace = cmListFileBacktrace(state.CreateBaseSnapshot());
 
               // the first entry represents the top of the trace so we need to
@@ -2327,6 +2245,8 @@ bool cmCTestTestHandler::SetTestsProperties(
             cmExpandList(val, rt.Depends);
           } else if (key == "ENVIRONMENT"_s) {
             cmExpandList(val, rt.Environment);
+          } else if (key == "ENVIRONMENT_MODIFICATION"_s) {
+            cmExpandList(val, rt.EnvironmentModification);
           } else if (key == "LABELS"_s) {
             std::vector<std::string> Labels = cmExpandedList(val);
             rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());

+ 8 - 6
Source/CTest/cmCTestTestHandler.h

@@ -151,6 +151,7 @@ public:
     // return code of test which will mark test as "not run"
     int SkipReturnCode;
     std::vector<std::string> Environment;
+    std::vector<std::string> EnvironmentModification;
     std::vector<std::string> Labels;
     std::set<std::string> LockedResources;
     std::set<std::string> FixturesSetup;
@@ -177,7 +178,7 @@ public:
     std::string CompletionStatus;
     std::string CustomCompletionStatus;
     std::string Output;
-    std::string DartString;
+    std::string TestMeasurementsOutput;
     int TestCount;
     cmCTestTestProperties* Properties;
   };
@@ -276,9 +277,9 @@ public:
 
 private:
   /**
-   * Generate the Dart compatible output
+   * Write test results in CTest's Test.xml format
    */
-  virtual void GenerateDartOutput(cmXMLWriter& xml);
+  virtual void GenerateCTestXML(cmXMLWriter& xml);
 
   /**
    * Write test results in JUnit XML format
@@ -348,8 +349,7 @@ private:
   cmCTestResourceSpec ResourceSpec;
   std::string ResourceSpecFile;
 
-  void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart);
-  cmsys::RegularExpression DartStuff1;
+  void RecordCustomTestMeasurements(cmXMLWriter& xml, std::string content);
   void CheckLabelFilter(cmCTestTestProperties& it);
   void CheckLabelFilterExclude(cmCTestTestProperties& it);
   void CheckLabelFilterInclude(cmCTestTestProperties& it);
@@ -358,8 +358,10 @@ private:
   bool UseUnion;
   ListOfTests TestList;
   size_t TotalNumberOfTests;
-  cmsys::RegularExpression DartStuff;
+  cmsys::RegularExpression AllTestMeasurementsRegex;
+  cmsys::RegularExpression SingleTestMeasurementRegex;
   cmsys::RegularExpression CustomCompletionStatusRegex;
+  cmsys::RegularExpression CustomLabelRegex;
 
   std::ostream* LogFile;
 

+ 26 - 0
Source/CTest/cmCTestTestMeasurementXMLParser.cxx

@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmCTestTestMeasurementXMLParser.h"
+
+#include <cstring>
+
+void cmCTestTestMeasurementXMLParser::StartElement(const std::string& name,
+                                                   const char** attributes)
+{
+  this->CharacterData.clear();
+  this->ElementName = name;
+  for (const char** attr = attributes; *attr; attr += 2) {
+    if (strcmp(attr[0], "name") == 0) {
+      this->MeasurementName = attr[1];
+    } else if (strcmp(attr[0], "type") == 0) {
+      this->MeasurementType = attr[1];
+    }
+  }
+}
+
+void cmCTestTestMeasurementXMLParser::CharacterDataHandler(const char* data,
+                                                           int length)
+{
+  this->CharacterData.append(data, length);
+}

+ 21 - 0
Source/CTest/cmCTestTestMeasurementXMLParser.h

@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include <string>
+
+#include "cmXMLParser.h"
+
+class cmCTestTestMeasurementXMLParser : public cmXMLParser
+{
+public:
+  cmCTestTestMeasurementXMLParser() {}
+  std::string CharacterData;
+  std::string ElementName;
+  std::string MeasurementName;
+  std::string MeasurementType;
+
+protected:
+  void StartElement(const std::string& name, const char** atts) override;
+  void EndElement(const std::string& /*name*/) override {}
+  void CharacterDataHandler(const char* data, int length) override;
+};

+ 41 - 37
Source/LexerParser/cmFortranParser.cxx

@@ -600,12 +600,12 @@ static const yytype_int8 yytranslate[] =
 static const yytype_uint8 yyrline[] =
 {
        0,   101,   101,   101,   104,   108,   113,   122,   128,   135,
-     140,   144,   149,   157,   162,   167,   172,   177,   182,   187,
-     192,   197,   201,   205,   209,   213,   214,   219,   219,   219,
-     220,   220,   221,   221,   222,   222,   223,   223,   224,   224,
-     225,   225,   226,   226,   227,   227,   228,   228,   231,   232,
-     233,   234,   235,   236,   237,   238,   239,   240,   241,   242,
-     243,   244,   245,   246,   247
+     140,   144,   149,   161,   166,   171,   176,   181,   186,   191,
+     196,   201,   205,   209,   213,   217,   218,   223,   223,   223,
+     224,   224,   225,   225,   226,   226,   227,   227,   228,   228,
+     229,   229,   230,   230,   231,   231,   232,   232,   235,   236,
+     237,   238,   239,   240,   241,   242,   243,   244,   245,   246,
+     247,   248,   249,   250,   251
 };
 #endif
 
@@ -1747,142 +1747,146 @@ yyreduce:
       cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
       cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
     }
+    if (cmsysString_strcasecmp((yyvsp[-4].string), "intrinsic") == 0) {
+      cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+      cmFortranParser_RuleUseIntrinsic(parser, (yyvsp[-2].string));
+    }
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1754 "cmFortranParser.cxx"
+#line 1758 "cmFortranParser.cxx"
     break;
 
   case 13: /* stmt: INCLUDE STRING other EOSTMT  */
-#line 157 "cmFortranParser.y"
+#line 161 "cmFortranParser.y"
                               {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1764 "cmFortranParser.cxx"
+#line 1768 "cmFortranParser.cxx"
     break;
 
   case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT  */
-#line 162 "cmFortranParser.y"
+#line 166 "cmFortranParser.y"
                                          {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1774 "cmFortranParser.cxx"
+#line 1778 "cmFortranParser.cxx"
     break;
 
   case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT  */
-#line 167 "cmFortranParser.y"
+#line 171 "cmFortranParser.y"
                                  {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1784 "cmFortranParser.cxx"
+#line 1788 "cmFortranParser.cxx"
     break;
 
   case 16: /* stmt: include STRING other EOSTMT  */
-#line 172 "cmFortranParser.y"
+#line 176 "cmFortranParser.y"
                               {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1794 "cmFortranParser.cxx"
+#line 1798 "cmFortranParser.cxx"
     break;
 
   case 17: /* stmt: define WORD other EOSTMT  */
-#line 177 "cmFortranParser.y"
+#line 181 "cmFortranParser.y"
                            {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1804 "cmFortranParser.cxx"
+#line 1808 "cmFortranParser.cxx"
     break;
 
   case 18: /* stmt: undef WORD other EOSTMT  */
-#line 182 "cmFortranParser.y"
+#line 186 "cmFortranParser.y"
                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1814 "cmFortranParser.cxx"
+#line 1818 "cmFortranParser.cxx"
     break;
 
   case 19: /* stmt: ifdef WORD other EOSTMT  */
-#line 187 "cmFortranParser.y"
+#line 191 "cmFortranParser.y"
                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1824 "cmFortranParser.cxx"
+#line 1828 "cmFortranParser.cxx"
     break;
 
   case 20: /* stmt: ifndef WORD other EOSTMT  */
-#line 192 "cmFortranParser.y"
+#line 196 "cmFortranParser.y"
                            {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1834 "cmFortranParser.cxx"
+#line 1838 "cmFortranParser.cxx"
     break;
 
   case 21: /* stmt: if other EOSTMT  */
-#line 197 "cmFortranParser.y"
+#line 201 "cmFortranParser.y"
                   {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIf(parser);
   }
-#line 1843 "cmFortranParser.cxx"
+#line 1847 "cmFortranParser.cxx"
     break;
 
   case 22: /* stmt: elif other EOSTMT  */
-#line 201 "cmFortranParser.y"
+#line 205 "cmFortranParser.y"
                     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElif(parser);
   }
-#line 1852 "cmFortranParser.cxx"
+#line 1856 "cmFortranParser.cxx"
     break;
 
   case 23: /* stmt: else other EOSTMT  */
-#line 205 "cmFortranParser.y"
+#line 209 "cmFortranParser.y"
                     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElse(parser);
   }
-#line 1861 "cmFortranParser.cxx"
+#line 1865 "cmFortranParser.cxx"
     break;
 
   case 24: /* stmt: endif other EOSTMT  */
-#line 209 "cmFortranParser.y"
+#line 213 "cmFortranParser.y"
                      {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleEndif(parser);
   }
-#line 1870 "cmFortranParser.cxx"
+#line 1874 "cmFortranParser.cxx"
     break;
 
   case 48: /* misc_code: WORD  */
-#line 231 "cmFortranParser.y"
+#line 235 "cmFortranParser.y"
                       { free ((yyvsp[0].string)); }
-#line 1876 "cmFortranParser.cxx"
+#line 1880 "cmFortranParser.cxx"
     break;
 
   case 55: /* misc_code: STRING  */
-#line 238 "cmFortranParser.y"
+#line 242 "cmFortranParser.y"
                       { free ((yyvsp[0].string)); }
-#line 1882 "cmFortranParser.cxx"
+#line 1886 "cmFortranParser.cxx"
     break;
 
 
-#line 1886 "cmFortranParser.cxx"
+#line 1890 "cmFortranParser.cxx"
 
       default: break;
     }
@@ -2107,6 +2111,6 @@ yyreturn:
   return yyresult;
 }
 
-#line 250 "cmFortranParser.y"
+#line 254 "cmFortranParser.y"
 
 /* End of grammar */

+ 4 - 0
Source/LexerParser/cmFortranParser.y

@@ -151,6 +151,10 @@ stmt:
       cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
       cmFortranParser_RuleUse(parser, $5);
     }
+    if (cmsysString_strcasecmp($3, "intrinsic") == 0) {
+      cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+      cmFortranParser_RuleUseIntrinsic(parser, $5);
+    }
     free($3);
     free($5);
   }

+ 6 - 9
Source/QtDialog/QCMake.cxx

@@ -550,17 +550,14 @@ void QCMake::loadPresets()
     }
 
     QCMakePreset preset;
-    preset.name = std::move(QString::fromLocal8Bit(p.Name.data()));
-    preset.displayName =
-      std::move(QString::fromLocal8Bit(p.DisplayName.data()));
-    preset.description =
-      std::move(QString::fromLocal8Bit(p.Description.data()));
-    preset.generator = std::move(QString::fromLocal8Bit(p.Generator.data()));
-    preset.architecture =
-      std::move(QString::fromLocal8Bit(p.Architecture.data()));
+    preset.name = QString::fromLocal8Bit(p.Name.data());
+    preset.displayName = QString::fromLocal8Bit(p.DisplayName.data());
+    preset.description = QString::fromLocal8Bit(p.Description.data());
+    preset.generator = QString::fromLocal8Bit(p.Generator.data());
+    preset.architecture = QString::fromLocal8Bit(p.Architecture.data());
     preset.setArchitecture = !p.ArchitectureStrategy ||
       p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
-    preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
+    preset.toolset = QString::fromLocal8Bit(p.Toolset.data());
     preset.setToolset = !p.ToolsetStrategy ||
       p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
     preset.enabled = it.Expanded && it.Expanded->ConditionResult &&

+ 1 - 10
Source/cmBinUtilsLinuxELFLinker.cxx

@@ -11,6 +11,7 @@
 #include <cmsys/RegularExpression.hxx>
 
 #include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
+#include "cmELF.h"
 #include "cmLDConfigLDConfigTool.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -18,10 +19,6 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
-#ifdef CMake_USE_ELF_PARSER
-#  include "cmELF.h"
-#endif
-
 static std::string ReplaceOrigin(const std::string& rpath,
                                  const std::string& origin)
 {
@@ -91,7 +88,6 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
 {
   std::vector<std::string> parentRpaths;
 
-#ifdef CMake_USE_ELF_PARSER
   cmELF elf(file.c_str());
   if (!elf) {
     return false;
@@ -106,7 +102,6 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
       this->Machine = elf.GetMachine();
     }
   }
-#endif
 
   return this->ScanDependencies(file, parentRpaths);
 }
@@ -175,15 +170,11 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
 namespace {
 bool FileHasArchitecture(const char* filename, std::uint16_t machine)
 {
-#ifdef CMake_USE_ELF_PARSER
   cmELF elf(filename);
   if (!elf) {
     return false;
   }
   return machine == 0 || machine == elf.GetMachine();
-#else
-  return true;
-#endif
 }
 }
 

+ 5 - 5
Source/cmCMakePresetsFile.cxx

@@ -78,7 +78,8 @@ void InheritVector(std::vector<T>& child, const std::vector<T>& parent)
 template <class T>
 ReadFileResult VisitPreset(
   T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
-  std::map<std::string, CycleStatus> cycleStatus, int version)
+  std::map<std::string, CycleStatus> cycleStatus,
+  const cmCMakePresetsFile& file)
 {
   switch (cycleStatus[preset.Name]) {
     case CycleStatus::InProgress:
@@ -108,7 +109,7 @@ ReadFileResult VisitPreset(
       return ReadFileResult::USER_PRESET_INHERITANCE;
     }
 
-    auto result = VisitPreset(parentPreset, presets, cycleStatus, version);
+    auto result = VisitPreset(parentPreset, presets, cycleStatus, file);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
@@ -128,7 +129,7 @@ ReadFileResult VisitPreset(
     preset.ConditionEvaluator.reset();
   }
 
-  CHECK_OK(preset.VisitPresetAfterInherit(version))
+  CHECK_OK(preset.VisitPresetAfterInherit(file.GetVersion(preset)))
 
   cycleStatus[preset.Name] = CycleStatus::Verified;
   return ReadFileResult::READ_OK;
@@ -146,8 +147,7 @@ ReadFileResult ComputePresetInheritance(
 
   for (auto& it : presets) {
     auto& preset = it.second.Unexpanded;
-    auto result =
-      VisitPreset<T>(preset, presets, cycleStatus, file.GetVersion(preset));
+    auto result = VisitPreset<T>(preset, presets, cycleStatus, file);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }

+ 1 - 0
Source/cmCommonTargetGenerator.h

@@ -40,6 +40,7 @@ protected:
   cmLocalCommonGenerator* LocalCommonGenerator;
   cmGlobalCommonGenerator* GlobalCommonGenerator;
   std::vector<std::string> ConfigNames;
+  bool UseLWYU = false;
 
   void AppendFortranFormatFlags(std::string& flags,
                                 cmSourceFile const& source);

+ 0 - 1
Source/cmConfigure.cmake.h.in

@@ -16,7 +16,6 @@
 
 #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
 #cmakedefine HAVE_UNSETENV
-#cmakedefine CMake_USE_ELF_PARSER
 #cmakedefine CMake_USE_MACH_PARSER
 #cmakedefine CMake_USE_XCOFF_PARSER
 #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@

+ 14 - 3
Source/cmDependsFortran.cxx

@@ -163,12 +163,17 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
     mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory();
   }
 
+  bool building_intrinsics =
+    !mf->GetSafeDefinition("CMAKE_Fortran_TARGET_BUILDING_INSTRINSIC_MODULES")
+       .empty();
+
   // Actually write dependencies to the streams.
   using ObjectInfoMap = cmDependsFortranInternals::ObjectInfoMap;
   ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
   for (auto const& i : objInfo) {
     if (!this->WriteDependenciesReal(i.first, i.second, mod_dir, stamp_dir,
-                                     makeDepends, internalDepends)) {
+                                     makeDepends, internalDepends,
+                                     building_intrinsics)) {
       return false;
     }
   }
@@ -307,7 +312,8 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
                                              std::string const& mod_dir,
                                              std::string const& stamp_dir,
                                              std::ostream& makeDepends,
-                                             std::ostream& internalDepends)
+                                             std::ostream& internalDepends,
+                                             bool buildingIntrinsics)
 {
   // Get the source file for this object.
   std::string const& src = info.Source;
@@ -339,8 +345,13 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
     makeDepends << '\n';
   }
 
+  std::set<std::string> req = info.Requires;
+  if (buildingIntrinsics) {
+    req.insert(info.Intrinsics.begin(), info.Intrinsics.end());
+  }
+
   // Write module requirements to the output stream.
-  for (std::string const& i : info.Requires) {
+  for (std::string const& i : req) {
     // Require only modules not provided in the same source.
     if (info.Provides.find(i) != info.Provides.cend()) {
       continue;

+ 2 - 1
Source/cmDependsFortran.h

@@ -72,7 +72,8 @@ protected:
                              std::string const& mod_dir,
                              std::string const& stamp_dir,
                              std::ostream& makeDepends,
-                             std::ostream& internalDepends);
+                             std::ostream& internalDepends,
+                             bool buildingIntrinsics);
 
   // The source file from which to start scanning.
   std::string SourceFile;

+ 17 - 57
Source/cmELF.cxx

@@ -17,41 +17,9 @@
 
 #include "cmsys/FStream.hxx"
 
-// Include the ELF format information system header.
-#if defined(__OpenBSD__)
-#  include <elf_abi.h>
-#elif defined(__HAIKU__)
-#  include <elf32.h>
-#  include <elf64.h>
-using Elf32_Ehdr = struct Elf32_Ehdr;
-using Elf32_Shdr = struct Elf32_Shdr;
-using Elf32_Sym = struct Elf32_Sym;
-using Elf32_Rel = struct Elf32_Rel;
-using Elf32_Rela = struct Elf32_Rela;
-#  define ELFMAG0 0x7F
-#  define ELFMAG1 'E'
-#  define ELFMAG2 'L'
-#  define ELFMAG3 'F'
-#  define ET_NONE 0
-#  define ET_REL 1
-#  define ET_EXEC 2
-#  define ET_DYN 3
-#  define ET_CORE 4
-#  define EM_386 3
-#  define EM_SPARC 2
-#  define EM_PPC 20
-#else
-#  include <elf.h>
-#endif
-#if defined(__sun)
-#  include <sys/link.h> // For dynamic section information
-#endif
-#ifdef _SCO_DS
-#  include <link.h> // For DT_SONAME etc.
-#endif
-#ifndef DT_RUNPATH
-#  define DT_RUNPATH 29
-#endif
+#include "cmelf/elf32.h"
+#include "cmelf/elf64.h"
+#include "cmelf/elf_common.h"
 
 // Low-level byte swapping implementation.
 template <size_t s>
@@ -145,6 +113,7 @@ public:
   virtual std::vector<char> EncodeDynamicEntries(
     const cmELF::DynamicEntryList&) = 0;
   virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0;
+  virtual bool IsMips() const = 0;
   virtual void PrintInfo(std::ostream& os) const = 0;
 
   // Lookup the SONAME in the DYNAMIC section.
@@ -218,7 +187,6 @@ struct cmELFTypes32
 };
 
 // Configure the implementation template for 64-bit ELF files.
-#ifndef _SCO_DS
 struct cmELFTypes64
 {
   using ELF_Ehdr = Elf64_Ehdr;
@@ -228,7 +196,6 @@ struct cmELFTypes64
   using tagtype = ::uint64_t;
   static const char* GetName() { return "64-bit"; }
 };
-#endif
 
 // Parser implementation template.
 template <class Types>
@@ -262,6 +229,8 @@ public:
   // Lookup a string from the dynamic section with the given tag.
   StringEntry const* GetDynamicSectionString(unsigned int tag) override;
 
+  bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
+
   // Print information about the ELF file.
   void PrintInfo(std::ostream& os) const override
   {
@@ -345,16 +314,12 @@ private:
         eti == ET_CORE) {
       return true;
     }
-#if defined(ET_LOOS) && defined(ET_HIOS)
     if (eti >= ET_LOOS && eti <= ET_HIOS) {
       return true;
     }
-#endif
-#if defined(ET_LOPROC) && defined(ET_HIPROC)
     if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
       return true;
     }
-#endif
     return false;
   }
 
@@ -465,18 +430,14 @@ cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
       break;
     default: {
       unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
-#if defined(ET_LOOS) && defined(ET_HIOS)
       if (eti >= ET_LOOS && eti <= ET_HIOS) {
         this->ELFType = cmELF::FileTypeSpecificOS;
         break;
       }
-#endif
-#if defined(ET_LOPROC) && defined(ET_HIPROC)
       if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
         this->ELFType = cmELF::FileTypeSpecificProc;
         break;
       }
-#endif
       std::ostringstream e;
       e << "Unknown ELF file type " << eti;
       this->SetErrorMessage(e.str().c_str());
@@ -681,17 +642,12 @@ cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
 
 const long cmELF::TagRPath = DT_RPATH;
 const long cmELF::TagRunPath = DT_RUNPATH;
-
-#ifdef DT_MIPS_RLD_MAP_REL
 const long cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL;
-#else
-const long cmELF::TagMipsRldMapRel = 0;
-#endif
 
 cmELF::cmELF(const char* fname)
 {
   // Try to open the file.
-  auto fin = cm::make_unique<cmsys::ifstream>(fname);
+  auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary);
 
   // Quit now if the file could not be opened.
   if (!fin || !*fin) {
@@ -736,15 +692,11 @@ cmELF::cmELF(const char* fname)
     // 32-bit ELF
     this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>(
       this, std::move(fin), order);
-  }
-#ifndef _SCO_DS
-  else if (ident[EI_CLASS] == ELFCLASS64) {
+  } else if (ident[EI_CLASS] == ELFCLASS64) {
     // 64-bit ELF
     this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>(
       this, std::move(fin), order);
-  }
-#endif
-  else {
+  } else {
     this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
     return;
   }
@@ -846,6 +798,14 @@ cmELF::StringEntry const* cmELF::GetRunPath()
   return nullptr;
 }
 
+bool cmELF::IsMIPS() const
+{
+  if (this->Valid()) {
+    return this->Internal->IsMips();
+  }
+  return false;
+}
+
 void cmELF::PrintInfo(std::ostream& os) const
 {
   if (this->Valid()) {

+ 3 - 4
Source/cmELF.h

@@ -11,10 +11,6 @@
 #include <utility>
 #include <vector>
 
-#if !defined(CMake_USE_ELF_PARSER)
-#  error "This file may be included only if CMake_USE_ELF_PARSER is enabled."
-#endif
-
 class cmELFInternal;
 
 /** \class cmELF
@@ -102,6 +98,9 @@ public:
   /** Get the RUNPATH field if any.  */
   StringEntry const* GetRunPath();
 
+  /** Returns true if the ELF file targets a MIPS CPU.  */
+  bool IsMIPS() const;
+
   /** Print human-readable information about the ELF file.  */
   void PrintInfo(std::ostream& os) const;
 

+ 3 - 3
Source/cmExportBuildFileGenerator.cxx

@@ -254,7 +254,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
 
 void cmExportBuildFileGenerator::HandleMissingTarget(
   std::string& link_libs, std::vector<std::string>& missingTargets,
-  cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+  cmGeneratorTarget const* depender, cmGeneratorTarget* dependee)
 {
   // The target is not in the export.
   if (!this->AppendMode) {
@@ -321,7 +321,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
 }
 
 void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
-  cmGeneratorTarget* depender, cmGeneratorTarget* dependee,
+  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
   std::vector<std::string> const& exportFiles)
 {
   std::ostringstream e;
@@ -344,7 +344,7 @@ void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
 }
 
 std::string cmExportBuildFileGenerator::InstallNameDir(
-  cmGeneratorTarget* target, const std::string& config)
+  cmGeneratorTarget const* target, const std::string& config)
 {
   std::string install_name_dir;
 

Some files were not shown because too many files changed in this diff