diff options
291 files changed, 4043 insertions, 1225 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f4ebb02..c4c14bf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,9 +12,9 @@ include: - local: .gitlab/upload.yml stages: + - prep - build - test - - package - test-ext - upload @@ -34,6 +34,35 @@ stages: # - dependency/needs jobs for required jobs ################################################################################ +# Prep jobs + +prep:source: + extends: + - .linux_prep_source + - .cmake_prep_source_linux + - .linux_builder_tags + - .cmake_release_artifacts + - .run_only_for_package + +prep:doc: + extends: + - .fedora31_sphinx_package + - .cmake_prep_doc_linux + - .linux_builder_tags_qt + - .cmake_doc_artifacts + - .run_only_for_package + +upload:source: + extends: + - .rsync_upload + - .run_only_for_package + dependencies: + - prep:source + needs: + - prep:source + variables: + RSYNC_DESTINATION: dev + # Lint builds build:debian10-iwyu: @@ -56,14 +85,9 @@ build:fedora31-sphinx: - .cmake_build_linux - .linux_builder_tags_qt - .run_automatically - -build:fedora31-sphinx-package: - extends: - - .fedora31_sphinx_package - - .cmake_build_linux - - .linux_builder_tags_qt - - .cmake_doc_artifacts - - .run_only_for_package + variables: + CMAKE_CI_JOB_CONTINUOUS: "true" + CMAKE_CI_JOB_HELP: "true" # Linux builds @@ -80,7 +104,7 @@ test:fedora31-makefiles: - .fedora31_makefiles - .cmake_test_linux_package - .linux_builder_tags_qt - - .run_automatically + - .run_dependent dependencies: - build:centos6-release needs: @@ -91,7 +115,7 @@ test:cuda10.2-nvidia: - .cuda10.2_nvidia - .cmake_test_linux_package - .linux_builder_tags_cuda - - .run_automatically + - .run_dependent dependencies: - build:centos6-release needs: @@ -111,7 +135,7 @@ test:fedora31-ninja: - .cmake_test_linux - .linux_builder_tags_x11 - .cmake_test_artifacts - - .run_automatically + - .run_dependent dependencies: - build:fedora31-ninja needs: @@ -122,7 +146,7 @@ test:fedora31-ninja-multi: - .fedora31_ninja_multi - .cmake_test_linux_external - .linux_builder_tags_qt - - .run_automatically + - .run_dependent dependencies: - test:fedora31-ninja needs: @@ -144,7 +168,7 @@ test:macos-ninja: - .cmake_test_macos - .cmake_test_artifacts - .macos_builder_tags - - .run_automatically + - .run_dependent dependencies: - build:macos-ninja needs: @@ -163,7 +187,7 @@ test:macos-makefiles: - .macos_makefiles - .cmake_test_macos - .macos_builder_tags - - .run_automatically + - .run_dependent dependencies: - build:macos-makefiles needs: @@ -174,13 +198,13 @@ test:macos-xcode: - .macos_xcode - .cmake_test_macos_external - .macos_builder_ext_tags - - .run_automatically + - .run_dependent dependencies: - test:macos-ninja needs: - test:macos-ninja -package:macos: +build:macos-package: extends: - .macos_package - .cmake_build_macos_package @@ -188,18 +212,18 @@ package:macos: - .macos_builder_tags_package - .run_only_for_package dependencies: - - build:fedora31-sphinx-package + - prep:doc needs: - - build:fedora31-sphinx-package + - prep:doc upload:macos: extends: - .rsync_upload - .run_only_for_package dependencies: - - package:macos + - build:macos-package needs: - - package:macos + - build:macos-package variables: RSYNC_DESTINATION: dev @@ -219,7 +243,7 @@ test:windows-vs2019-x64-ninja: - .cmake_test_windows - .windows_builder_tags - .cmake_test_artifacts - - .run_automatically + - .run_dependent dependencies: - build:windows-vs2019-x64-ninja needs: @@ -230,7 +254,7 @@ test:windows-vs2019-x64: - .windows_vs2019_x64 - .cmake_test_windows_external - .windows_builder_ext_tags - - .run_automatically + - .run_dependent dependencies: - test:windows-vs2019-x64-ninja needs: diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml index f1c0c7e..1c24003 100644 --- a/.gitlab/artifacts.yml +++ b/.gitlab/artifacts.yml @@ -74,6 +74,9 @@ # Any packages made. - build/cmake-*-Linux-x86_64.* - build/cmake-*-Darwin-x86_64.* + # Any source packages made. + - build/cmake-*.tar.gz + - build/cmake-*.zip .cmake_test_artifacts: artifacts: diff --git a/.gitlab/ci/cmake_version.cmake b/.gitlab/ci/cmake_version.cmake new file mode 100644 index 0000000..ef9f7f2 --- /dev/null +++ b/.gitlab/ci/cmake_version.cmake @@ -0,0 +1,3 @@ +get_filename_component(CMake_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE) +include("${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake") +message(STATUS ${CMake_VERSION}) diff --git a/.gitlab/ci/cmake_version.sh b/.gitlab/ci/cmake_version.sh new file mode 100755 index 0000000..03b1614 --- /dev/null +++ b/.gitlab/ci/cmake_version.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +cmake -P "${BASH_SOURCE%/*}/cmake_version.cmake" | cut -d ' ' -f 2 diff --git a/.gitlab/ci/configure_fedora31_ninja.cmake b/.gitlab/ci/configure_fedora31_ninja.cmake index 2743412..ea429c1 100644 --- a/.gitlab/ci/configure_fedora31_ninja.cmake +++ b/.gitlab/ci/configure_fedora31_ninja.cmake @@ -1,3 +1,7 @@ set(CMake_TEST_ISPC "ON" CACHE STRING "") set(CMake_TEST_GUI "ON" CACHE BOOL "") + +# Cover compilation with C++11 only and not higher standards. +set(CMAKE_CXX_STANDARD "11" CACHE STRING "") + include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora31_common.cmake") diff --git a/.gitlab/ci/ctest_test.cmake b/.gitlab/ci/ctest_test.cmake index 569139d..08ef18f 100644 --- a/.gitlab/ci/ctest_test.cmake +++ b/.gitlab/ci/ctest_test.cmake @@ -10,6 +10,11 @@ ctest_start(APPEND) include(ProcessorCount) ProcessorCount(nproc) +if (NOT "$ENV{CTEST_MAX_PARALLELISM}" STREQUAL "") + if (nproc GREATER "$ENV{CTEST_MAX_PARALLELISM}") + set(nproc "$ENV{CTEST_MAX_PARALLELISM}") + endif () +endif () include("${CMAKE_CURRENT_LIST_DIR}/ctest_exclusions.cmake") ctest_test( diff --git a/.gitlab/ci/gitlab_ci.cmake b/.gitlab/ci/gitlab_ci.cmake index 7bd9300..7e5a7ab 100644 --- a/.gitlab/ci/gitlab_ci.cmake +++ b/.gitlab/ci/gitlab_ci.cmake @@ -49,6 +49,12 @@ endif () set(ctest_track "Experimental") if (NOT "$ENV{CI_MERGE_REQUEST_ID}" STREQUAL "") set(ctest_track "merge-requests") +elseif (NOT "$ENV{CMAKE_CI_PROJECT_CONTINUOUS_BRANCH}" STREQUAL "" AND "$ENV{CMAKE_CI_PROJECT_CONTINUOUS_BRANCH}" STREQUAL "$ENV{CI_COMMIT_BRANCH}" AND NOT "$ENV{CMAKE_CI_JOB_CONTINUOUS}" STREQUAL "") + if (NOT "$ENV{CMAKE_CI_JOB_HELP}" STREQUAL "") + set(ctest_track "Continuous Help") + else() + set(ctest_track "Continuous") + endif() elseif ("$ENV{CI_PROJECT_PATH}" STREQUAL "cmake/cmake") if ("$ENV{CI_COMMIT_REF_NAME}" STREQUAL "master") set(ctest_track "master") diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index 75f8156..74b2de7 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -11,6 +11,12 @@ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" LAUNCHER: "scl enable devtoolset-6 rh-python36 --" +.linux_prep_source: + image: "fedora:32" + + variables: + GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" + ### Debian .debian10: @@ -143,6 +149,29 @@ - cmake --version - ninja --version +.cmake_prep_source_linux: + stage: prep + + script: + - *before_script_linux + - dnf install --setopt=install_weak_deps=False -y git-core + - v="$(.gitlab/ci/cmake_version.sh)" + - mkdir -p build/ + - git archive --format=tgz "--prefix=cmake-$v/" -o "build/cmake-$v.tar.gz" HEAD + - git -c core.autocrlf=true -c core.eol=crlf archive --format=zip --prefix="cmake-$v/" -o "build/cmake-$v.zip" HEAD + + interruptible: true + +.cmake_prep_doc_linux: + stage: prep + + script: + - *before_script_linux + - "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_configure.cmake" + - "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_build.cmake" + + interruptible: true + .cmake_build_linux: stage: build diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml index 96ec264..a500d36 100644 --- a/.gitlab/os-macos.yml +++ b/.gitlab/os-macos.yml @@ -8,6 +8,8 @@ # TODO: Factor this out so that each job selects the Xcode version to # use so that different versions can be tested in a single pipeline. DEVELOPER_DIR: "/Applications/Xcode-11.7.app/Contents/Developer" + # Avoid conflicting with other projects running on the same machine. + SCCACHE_SERVER_PORT: 4227 ### Build and test @@ -109,7 +111,7 @@ interruptible: true .cmake_build_macos_package: - stage: package + stage: build script: - *before_script_macos diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml index 63b8758..61a2018 100644 --- a/.gitlab/os-windows.yml +++ b/.gitlab/os-windows.yml @@ -5,6 +5,8 @@ .windows: variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake ci ext\\$CI_CONCURRENT_ID" + # Avoid conflicting with other projects running on the same machine. + SCCACHE_SERVER_PORT: 4227 ### Build and test diff --git a/.gitlab/rules.yml b/.gitlab/rules.yml index 1803e79..1edfd97 100644 --- a/.gitlab/rules.yml +++ b/.gitlab/rules.yml @@ -4,6 +4,9 @@ rules: - if: '$CMAKE_CI_PACKAGE == "true"' when: never + - if: '($CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != "" && $CI_COMMIT_BRANCH == $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true")' + when: delayed + start_in: 5 minutes - if: '$CI_MERGE_REQUEST_ID' when: manual - if: '$CI_PROJECT_PATH == "cmake/cmake"' @@ -15,6 +18,18 @@ rules: - if: '$CMAKE_CI_PACKAGE == "true"' when: never + - if: '($CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != "" && $CI_COMMIT_BRANCH == $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true")' + when: on_success + - if: '$CI_MERGE_REQUEST_ID' + when: on_success + - if: '$CI_PROJECT_PATH == "cmake/cmake"' + when: on_success + - when: never + +.run_dependent: + rules: + - if: '$CMAKE_CI_PACKAGE == "true"' + when: never - if: '$CI_MERGE_REQUEST_ID' when: on_success - if: '$CI_PROJECT_PATH == "cmake/cmake"' diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst index 9e98d79..00e1a69 100644 --- a/Help/command/cmake_language.rst +++ b/Help/command/cmake_language.rst @@ -10,8 +10,9 @@ Synopsis .. parsed-literal:: - cmake_language(`CALL`_ <command> [<args>...]) + cmake_language(`CALL`_ <command> [<arg>...]) cmake_language(`EVAL`_ CODE <code>...) + cmake_language(`DEFER`_ <options>... CALL <command> [<arg>...]) Introduction ^^^^^^^^^^^^ @@ -28,7 +29,7 @@ Calling Commands .. code-block:: cmake - cmake_language(CALL <command> [<args>...]) + cmake_language(CALL <command> [<arg>...]) Calls the named ``<command>`` with the given arguments (if any). For example, the code: @@ -99,3 +100,121 @@ is equivalent to ) include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake) + +Deferring Calls +^^^^^^^^^^^^^^^ + +.. versionadded:: 3.19 + +.. _DEFER: + +.. code-block:: cmake + + cmake_language(DEFER <options>... CALL <command> [<arg>...]) + +Schedules a call to the named ``<command>`` with the given arguments (if any) +to occur at a later time. By default, deferred calls are executed as if +written at the end of the current directory's ``CMakeLists.txt`` file, +except that they run even after a :command:`return` call. Variable +references in arguments are evaluated at the time the deferred call is +executed. + +The options are: + +``DIRECTORY <dir>`` + Schedule the call for the end of the given directory instead of the + current directory. The ``<dir>`` may reference either a source + directory or its corresponding binary directory. Relative paths are + treated as relative to the current source directory. + + The given directory must be known to CMake, being either the top-level + directory or one added by :command:`add_subdirectory`. Furthermore, + the given directory must not yet be finished processing. This means + it can be the current directory or one of its ancestors. + +``ID <id>`` + Specify an identification for the deferred call. + The id may not be empty and may not begin in a capital letter ``A-Z``. + The id may begin in a ``_`` only if it was generated by another call + that used ``ID_VAR`` to get the id. + +``ID_VAR <var>`` + Sepcify a variable in which to store the identification for the + deferred call. If ``ID <id>`` is not given, a new identification + will be generated starting in a ``_``. + +The currently scheduled list of deferred calls may be retrieved: + +.. code-block:: cmake + + cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>) + +This will store in ``<var>`` a :ref:`Semicolon-separated list <CMake Language +Lists>` of deferred call ids. + +Details of a specific call may be retrieved from its id: + +.. code-block:: cmake + + cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>) + +This will store in ``<var>`` a :ref:`Semicolon-separated list <CMake Language +Lists>` in which the first element is the name of the command to be +called, and the remaining elements are its unevaluated arguments (any +contained ``;`` characters are included literally and cannot be distinguished +from multiple arguments). If multiple calls are scheduled with the same id, +this retrieves the first one. If no call is scheduled with the given id, +this stores an empty string in the variable. + +Deferred calls may be canceled by their id: + +.. code-block:: cmake + + cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...) + +This cancels all deferred calls matching any of the given ids. +Unknown ids are silently ignored. + +Deferred Call Examples +"""""""""""""""""""""" + +For example, the code: + +.. code-block:: cmake + + cmake_language(DEFER CALL message "${deferred_message}") + cmake_language(DEFER ID_VAR id CALL message "Cancelled Message") + cmake_language(DEFER CANCEL_CALL ${id}) + message("Immediate Message") + set(deferred_message "Deferred Message") + +prints:: + + Immediate Message + Deferred Message + +The ``Cancelled Message`` is never printed because its command is +cancelled. The ``deferred_message`` variable reference is not evaluated +until the call site, so it can be set after the deferred call is scheduled. + +In order to evaluate variable references immediately when scheduling a +deferred call, wrap it using ``cmake_language(EVAL)``. However, note that +arguments will be re-evaluated in the deferred call, though that can be +avoided by using bracket arguments. For example: + +.. code-block:: cmake + + set(deferred_message "Deferred Message 1") + set(re_evaluated [[${deferred_message}]]) + cmake_language(EVAL CODE " + cmake_language(DEFER CALL message [[${deferred_message}]]) + cmake_language(DEFER CALL message \"${re_evaluated}\") + ") + message("Immediate Message") + set(deferred_message "Deferred Message 2") + +also prints:: + + Immediate Message + Deferred Message 1 + Deferred Message 2 diff --git a/Help/command/return.rst b/Help/command/return.rst index 830992c..ec009d8 100644 --- a/Help/command/return.rst +++ b/Help/command/return.rst @@ -12,6 +12,7 @@ encountered in an included file (via :command:`include` or :command:`find_package`), it causes processing of the current file to stop and control is returned to the including file. If it is encountered in a file which is not included by another file, e.g. a ``CMakeLists.txt``, +deferred calls scheduled by :command:`cmake_language(DEFER)` are invoked and control is returned to the parent directory if there is one. If return is called in a function, control is returned to the caller of the function. diff --git a/Help/guide/importing-exporting/index.rst b/Help/guide/importing-exporting/index.rst index b0cfb71..2e6e06d 100644 --- a/Help/guide/importing-exporting/index.rst +++ b/Help/guide/importing-exporting/index.rst @@ -1,10 +1,13 @@ -Importing and Exporting Targets -******************************* +Importing and Exporting Guide +***************************** .. only:: html .. contents:: +Introduction +============ + In this guide, we will present the concept of :prop_tgt:`IMPORTED` targets and demonstrate how to import existing executable or library files from disk into a CMake project. We will then show how CMake supports exporting targets diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst index 665d123..4b09e53 100644 --- a/Help/guide/tutorial/index.rst +++ b/Help/guide/tutorial/index.rst @@ -5,6 +5,9 @@ CMake Tutorial .. contents:: +Introduction +============ + The CMake tutorial provides a step-by-step guide that covers common build system issues that CMake helps address. Seeing how various topics all work together in an example project can be very helpful. The tutorial diff --git a/Help/manual/VS-Choose-Arch.png b/Help/guide/user-interaction/VS-Choose-Arch.png Binary files differindex 816b0f4..816b0f4 100644 --- a/Help/manual/VS-Choose-Arch.png +++ b/Help/guide/user-interaction/VS-Choose-Arch.png diff --git a/Help/guide/user-interaction/index.rst b/Help/guide/user-interaction/index.rst index c724b6f..2d8ed29 100644 --- a/Help/guide/user-interaction/index.rst +++ b/Help/guide/user-interaction/index.rst @@ -85,7 +85,7 @@ The source and binary directories must first be populated. It is always advised to use different directories for the source and the build. -.. image:: /guide/user-interaction/GUI-Source-Binary.png +.. image:: GUI-Source-Binary.png :alt: Choosing source and binary directories Generating a Buildsystem @@ -246,19 +246,19 @@ Choosing a generator in cmake-gui The "Configure" button triggers a new dialog to select the CMake generator to use. -.. image:: /guide/user-interaction/GUI-Configure-Dialog.png +.. image:: GUI-Configure-Dialog.png :alt: Configuring a generator All generators available on the command line are also available in :manual:`cmake-gui(1)`. -.. image:: /guide/user-interaction/GUI-Choose-Generator.png +.. image:: GUI-Choose-Generator.png :alt: Choosing a generator When choosing a Visual Studio generator, further options are available to set an architecture to generate for. -.. image:: /manual/VS-Choose-Arch.png +.. image:: VS-Choose-Arch.png :alt: Choosing an architecture for Visual Studio generators .. _`Setting Build Variables`: @@ -359,7 +359,7 @@ Variables may be set in the cmake-gui using the "Add Entry" button. This triggers a new dialog to set the value of the variable. -.. image:: /guide/user-interaction/GUI-Add-Entry.png +.. image:: GUI-Add-Entry.png :alt: Editing a cache entry The main view of the :manual:`cmake-gui(1)` user interface diff --git a/Help/guide/using-dependencies/index.rst b/Help/guide/using-dependencies/index.rst index 6fdcc55..f4d7845 100644 --- a/Help/guide/using-dependencies/index.rst +++ b/Help/guide/using-dependencies/index.rst @@ -31,7 +31,7 @@ See the :guide:`User Interaction Guide` for more about setting cache entries. Libraries providing Config-file packages ----------------------------------------- +======================================== The most convenient way for a third-party to provide library binaries for use with CMake is to provide @@ -115,7 +115,7 @@ file, such as ``/opt/somepackage/lib/cmake/SomePackage/`` in the above example. Imported Targets from Packages ------------------------------- +============================== A third-party package which provides config-file packages may also provide :ref:`Imported targets`. These will be diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index d364198..14af149 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -45,6 +45,7 @@ These modules are loaded using the :command:`include` command. /module/CheckOBJCXXSourceRuns /module/CheckPIESupported /module/CheckPrototypeDefinition + /module/CheckCompilerFlag /module/CheckSourceCompiles /module/CheckSourceRuns /module/CheckStructHasMember diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index c5e0aae..9850116 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -295,6 +295,11 @@ Options ``line`` The line in ``file`` of the function call. + ``defer`` + Optional member that is present when the function call was deferred + by :command:`cmake_language(DEFER)`. If present, its value is a + string containing the deferred call ``<id>``. + ``cmd`` The name of the function that was called. @@ -317,7 +322,7 @@ Options { "version": { "major": 1, - "minor": 0 + "minor": 1 } } diff --git a/Help/module/CheckCompilerFlag.rst b/Help/module/CheckCompilerFlag.rst new file mode 100644 index 0000000..bcf19a8 --- /dev/null +++ b/Help/module/CheckCompilerFlag.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckCompilerFlag.cmake diff --git a/Help/release/dev/FindPython-version_range.rst b/Help/release/dev/FindPython-version_range.rst new file mode 100644 index 0000000..06318b4 --- /dev/null +++ b/Help/release/dev/FindPython-version_range.rst @@ -0,0 +1,5 @@ +FindPython-version_range +------------------------ + +* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython` + modules gained the capability to manage a version range. diff --git a/Help/release/dev/check-source-modules.rst b/Help/release/dev/check-source-modules.rst index 9a7785a..e6cccbe 100644 --- a/Help/release/dev/check-source-modules.rst +++ b/Help/release/dev/check-source-modules.rst @@ -8,3 +8,7 @@ check-source-modules * The :module:`CheckSourceRuns` module has been added to generalize :module:`CheckCSourceRuns` and :module:`CheckCXXSourceRuns` to more languages. + +* The :module:`CheckCompilerFlag` module has been added to + generalize :module:`CheckCCompilerFlag` and + :module:`CheckCXXCompilerFlag` to more languages. diff --git a/Help/release/dev/cmake-gui-environment.rst b/Help/release/dev/cmake-gui-environment.rst new file mode 100644 index 0000000..1c8485e --- /dev/null +++ b/Help/release/dev/cmake-gui-environment.rst @@ -0,0 +1,4 @@ +cmake-gui-environment +--------------------- + +* The :manual:`CMake GUI <cmake-gui(1)>` now has an environment variable editor. diff --git a/Help/release/dev/cmake_language-DEFER.rst b/Help/release/dev/cmake_language-DEFER.rst new file mode 100644 index 0000000..8bd0ee9 --- /dev/null +++ b/Help/release/dev/cmake_language-DEFER.rst @@ -0,0 +1,5 @@ +cmake_language-DEFER +-------------------- + +* The :command:`cmake_language` command gained a ``DEFER`` mode to + schedule command calls to occur at the end of processing a directory. diff --git a/Help/variable/CMAKE_CURRENT_LIST_LINE.rst b/Help/variable/CMAKE_CURRENT_LIST_LINE.rst index 60e8e26..7f839c2 100644 --- a/Help/variable/CMAKE_CURRENT_LIST_LINE.rst +++ b/Help/variable/CMAKE_CURRENT_LIST_LINE.rst @@ -5,3 +5,7 @@ The line number of the current file being processed. This is the line number of the file currently being processed by cmake. + +If CMake is currently processing deferred calls scheduled by +the :command:`cmake_language(DEFER)` command, this variable +evaluates to ``DEFERRED`` instead of a specific line number. diff --git a/Help/variable/CMAKE_LANG_COMPILER_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ID.rst index c495b71..99ff015 100644 --- a/Help/variable/CMAKE_LANG_COMPILER_ID.rst +++ b/Help/variable/CMAKE_LANG_COMPILER_ID.rst @@ -26,6 +26,7 @@ include: IAR = IAR Systems (iar.com) Intel = Intel Compiler (intel.com) IntelDPCPP = Intel DPCPP Compiler (intel.com) + IntelClang = Intel Clang Compiler (intel.com) MSVC = Microsoft Visual Studio (microsoft.com) NVIDIA = NVIDIA CUDA Compiler (nvidia.com) OpenWatcom = Open Watcom (openwatcom.org) diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake index 176e768..26fb381 100644 --- a/Modules/CMakeCompilerIdDetection.cmake +++ b/Modules/CMakeCompilerIdDetection.cmake @@ -79,6 +79,7 @@ function(compiler_id_detection outvar lang) AppleClang ARMClang IntelDPCPP + IntelClang Clang GNU MSVC diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index 6f665a6..649b6f7 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -77,10 +77,14 @@ function(GetDefaultWindowsPrefixBase var) # if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)") set(arch_hint "x64") + elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64") + set(arch_hint "x64") elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM64") set(arch_hint "ARM64") elseif("${CMAKE_GENERATOR}" MATCHES "ARM") set(arch_hint "ARM") + elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM") + set(arch_hint "ARM") elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") set(arch_hint "x64") elseif("$ENV{LIB}" MATCHES "(amd64|ia64)") diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake index b3da82d..d530191 100644 --- a/Modules/CMakeOBJCInformation.cmake +++ b/Modules/CMakeOBJCInformation.cmake @@ -170,7 +170,7 @@ endif() # compile an Objective-C file into an object file if(NOT CMAKE_OBJC_COMPILE_OBJECT) set(CMAKE_OBJC_COMPILE_OBJECT - "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x objective-c -o <OBJECT> -c <SOURCE>") + "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> -x objective-c <FLAGS> -o <OBJECT> -c <SOURCE>") endif() if(NOT CMAKE_OBJC_LINK_EXECUTABLE) diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake index 4be9762..7a3b9d7 100644 --- a/Modules/CMakeOBJCXXInformation.cmake +++ b/Modules/CMakeOBJCXXInformation.cmake @@ -263,7 +263,7 @@ endif() # compile an Objective-C++ file into an object file if(NOT CMAKE_OBJCXX_COMPILE_OBJECT) set(CMAKE_OBJCXX_COMPILE_OBJECT - "<CMAKE_OBJCXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>") + "<CMAKE_OBJCXX_COMPILER> <DEFINES> <INCLUDES> -x objective-c++ <FLAGS> -o <OBJECT> -c <SOURCE>") endif() if(NOT CMAKE_OBJCXX_LINK_EXECUTABLE) diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake index 1452b51..f835f29 100644 --- a/Modules/CheckCCompilerFlag.cmake +++ b/Modules/CheckCCompilerFlag.cmake @@ -34,24 +34,8 @@ effect or even a specific one is beyond the scope of this module. include_guard(GLOBAL) include(CheckCSourceCompiles) -include(CMakeCheckCompilerFlagCommonPatterns) - -function(check_c_compiler_flag _flag _var) - set(CMAKE_REQUIRED_DEFINITIONS "${_flag}") - - # Normalize locale during test compilation. - set(_locale_vars LC_ALL LC_MESSAGES LANG) - foreach(v IN LISTS _locale_vars) - set(_locale_vars_saved_${v} "$ENV{${v}}") - set(ENV{${v}} C) - endforeach() - check_compiler_flag_common_patterns(_common_patterns) - check_c_source_compiles("int main(void) { return 0; }" ${_var} - # Some compilers do not fail with a bad flag - FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU - ${_common_patterns} - ) - foreach(v IN LISTS _locale_vars) - set(ENV{${v}} ${_locale_vars_saved_${v}}) - endforeach() -endfunction() +include(CheckCompilerFlag) + +macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT) + check_compiler_flag(C "${_FLAG}" ${_RESULT}) +endmacro () diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake index 544e9ac..ce49ae3 100644 --- a/Modules/CheckCXXCompilerFlag.cmake +++ b/Modules/CheckCXXCompilerFlag.cmake @@ -34,24 +34,8 @@ effect or even a specific one is beyond the scope of this module. include_guard(GLOBAL) include(CheckCXXSourceCompiles) -include(CMakeCheckCompilerFlagCommonPatterns) - -function(check_cxx_compiler_flag _flag _var) - set(CMAKE_REQUIRED_DEFINITIONS "${_flag}") - - # Normalize locale during test compilation. - set(_locale_vars LC_ALL LC_MESSAGES LANG) - foreach(v IN LISTS _locale_vars) - set(_locale_vars_saved_${v} "$ENV{${v}}") - set(ENV{${v}} C) - endforeach() - check_compiler_flag_common_patterns(_common_patterns) - check_cxx_source_compiles("int main() { return 0; }" ${_var} - # Some compilers do not fail with a bad flag - FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU - ${_common_patterns} - ) - foreach(v IN LISTS _locale_vars) - set(ENV{${v}} ${_locale_vars_saved_${v}}) - endforeach() -endfunction() +include(CheckCompilerFlag) + +macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT) + check_compiler_flag(CXX "${_FLAG}" ${_RESULT}) +endmacro () diff --git a/Modules/CheckCompilerFlag.cmake b/Modules/CheckCompilerFlag.cmake new file mode 100644 index 0000000..9223009 --- /dev/null +++ b/Modules/CheckCompilerFlag.cmake @@ -0,0 +1,105 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckCompilerFlag +--------------------- + +.. versionadded:: 3.19 + +Check whether the compiler supports a given flag. + +.. command:: check_compiler_flag + + .. code-block:: cmake + + check_compiler_flag(<lang> <flag> <var>) + +Check that the ``<flag>`` is accepted by the compiler without a diagnostic. +Stores the result in an internal cache entry named ``<var>``. + +This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable +and calls the ``check_source_compiles(<LANG>`` function from the +:module:`CheckSourceCompiles` module. See documentation of that +module for a listing of variables that can otherwise modify the build. + +A positive result from this check indicates only that the compiler did not +issue a diagnostic message when given the flag. Whether the flag has any +effect or even a specific one is beyond the scope of this module. + +.. note:: + Since the :command:`try_compile` command forwards flags from variables + like :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags + in such variables may cause a false negative for this check. +#]=======================================================================] + +include_guard(GLOBAL) +include(CheckSourceCompiles) +include(CMakeCheckCompilerFlagCommonPatterns) + +cmake_policy(PUSH) +cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced +cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST + +function(CHECK_COMPILER_FLAG _lang _flag _var) + + if(_lang STREQUAL C) + set(_lang_src "int main(void) { return 0; }") + set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for C") + elseif(_lang STREQUAL CXX) + set(_lang_src "int main() { return 0; }") + set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for C\\+\\+") + elseif(_lang STREQUAL Fortran) + set(_lang_src " program test\n stop\n end program") + set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Fortran") + elseif(_lang STREQUAL OBJC) + set(_lang_src [=[ +#ifndef __OBJC__ +# error "Not an Objective-C compiler" +#endif +int main(void) { return 0; }]=]) + set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang + elseif(_lang STREQUAL OBJCXX) + set(_lang_src [=[ +#ifndef __OBJC__ +# error "Not an Objective-C++ compiler" +#endif +int main(void) { return 0; }]=]) + set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\+\\+" # GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang + else() + message (SEND_ERROR "check_compiler_flag: ${_lang}: unknown language.") + return() + endif() + + get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES) + if (NOT _lang IN_LIST _supported_languages) + message (SEND_ERROR "check_compiler_flag: ${_lang}: needs to be enabled before use.") + return() + endif() + + set(CMAKE_REQUIRED_DEFINITIONS ${_flag}) + + # Normalize locale during test compilation. + set(_locale_vars LC_ALL LC_MESSAGES LANG) + foreach(v IN LISTS _locale_vars) + set(_locale_vars_saved_${v} "$ENV{${v}}") + set(ENV{${v}} C) + endforeach() + + check_compiler_flag_common_patterns(_common_patterns) + check_source_compiles(${_lang} + "${_lang_src}" + ${_var} + ${_lang_fail_regex} + ${_common_patterns} + ) + + foreach(v IN LISTS _locale_vars) + set(ENV{${v}} ${_locale_vars_saved_${v}}) + endforeach() + set(${_var} "${${_var}}" PARENT_SCOPE) +endfunction () + +cmake_policy(POP) diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake index b8fac97..0f5cf9a 100644 --- a/Modules/CheckFortranCompilerFlag.cmake +++ b/Modules/CheckFortranCompilerFlag.cmake @@ -36,30 +36,8 @@ effect or even a specific one is beyond the scope of this module. include_guard(GLOBAL) include(CheckFortranSourceCompiles) -include(CMakeCheckCompilerFlagCommonPatterns) +include(CheckCompilerFlag) -macro (CHECK_Fortran_COMPILER_FLAG _FLAG _RESULT) - set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") - set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") - - # Normalize locale during test compilation. - set(_CheckFortranCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) - foreach(v ${_CheckFortranCompilerFlag_LOCALE_VARS}) - set(_CheckFortranCompilerFlag_SAVED_${v} "$ENV{${v}}") - set(ENV{${v}} C) - endforeach() - CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckFortranCompilerFlag_COMMON_PATTERNS) - CHECK_Fortran_SOURCE_COMPILES(" program test\n stop\n end program" ${_RESULT} - # Some compilers do not fail with a bad flag - FAIL_REGEX "command line option .* is valid for .* but not for Fortran" # GNU - ${_CheckFortranCompilerFlag_COMMON_PATTERNS} - ) - foreach(v ${_CheckFortranCompilerFlag_LOCALE_VARS}) - set(ENV{${v}} ${_CheckFortranCompilerFlag_SAVED_${v}}) - unset(_CheckFortranCompilerFlag_SAVED_${v}) - endforeach() - unset(_CheckFortranCompilerFlag_LOCALE_VARS) - unset(_CheckFortranCompilerFlag_COMMON_PATTERNS) - - set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") +macro (CHECK_FORTRAN_COMPILER_FLAG _FLAG _RESULT) + check_compiler_flag(Fortran "${_FLAG}" ${_RESULT}) endmacro () diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake index a98f429..df9d724 100644 --- a/Modules/CheckOBJCCompilerFlag.cmake +++ b/Modules/CheckOBJCCompilerFlag.cmake @@ -36,31 +36,8 @@ effect or even a specific one is beyond the scope of this module. include_guard(GLOBAL) include(CheckOBJCSourceCompiles) -include(CMakeCheckCompilerFlagCommonPatterns) +include(CheckCompilerFlag) macro (CHECK_OBJC_COMPILER_FLAG _FLAG _RESULT) - set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") - set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") - - # Normalize locale during test compilation. - set(_CheckOBJCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) - foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS}) - set(_CheckOBJCCompilerFlag_SAVED_${v} "$ENV{${v}}") - set(ENV{${v}} OBJC) - endforeach() - CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCCompilerFlag_COMMON_PATTERNS) - CHECK_OBJC_SOURCE_COMPILES("#ifndef __OBJC__\n# error \"Not an Objective-C compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT} - # Some compilers do not fail with a bad flag - FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU - FAIL_REGEX "argument unused during compilation: .*" # Clang - ${_CheckOBJCCompilerFlag_COMMON_PATTERNS} - ) - foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS}) - set(ENV{${v}} ${_CheckOBJCCompilerFlag_SAVED_${v}}) - unset(_CheckOBJCCompilerFlag_SAVED_${v}) - endforeach() - unset(_CheckOBJCCompilerFlag_LOCALE_VARS) - unset(_CheckOBJCCompilerFlag_COMMON_PATTERNS) - - set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") + check_compiler_flag(OBJC "${_FLAG}" ${_RESULT}) endmacro () diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake index 7944ab0..6e01bcc 100644 --- a/Modules/CheckOBJCXXCompilerFlag.cmake +++ b/Modules/CheckOBJCXXCompilerFlag.cmake @@ -36,31 +36,8 @@ effect or even a specific one is beyond the scope of this module. include_guard(GLOBAL) include(CheckOBJCXXSourceCompiles) -include(CMakeCheckCompilerFlagCommonPatterns) +include(CheckCompilerFlag) macro (CHECK_OBJCXX_COMPILER_FLAG _FLAG _RESULT) - set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") - set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") - - # Normalize locale during test compilation. - set(_CheckOBJCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) - foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS}) - set(_CheckOBJCXXCompilerFlag_SAVED_${v} "$ENV{${v}}") - set(ENV{${v}} OBJCXX) - endforeach() - CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS) - CHECK_OBJCXX_SOURCE_COMPILES("#ifndef __OBJC__\n# error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT} - # Some compilers do not fail with a bad flag - FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\\\+\\\\+" # GNU - FAIL_REGEX "argument unused during compilation: .*" # Clang - ${_CheckOBJCXXCompilerFlag_COMMON_PATTERNS} - ) - foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS}) - set(ENV{${v}} ${_CheckOBJCXXCompilerFlag_SAVED_${v}}) - unset(_CheckOBJCXXCompilerFlag_SAVED_${v}) - endforeach() - unset(_CheckOBJCXXCompilerFlag_LOCALE_VARS) - unset(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS) - - set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") + check_compiler_flag(OBJCXX "${_FLAG}" ${_RESULT}) endmacro () diff --git a/Modules/Compiler/IntelClang-DetermineCompiler.cmake b/Modules/Compiler/IntelClang-DetermineCompiler.cmake new file mode 100644 index 0000000..3544be3 --- /dev/null +++ b/Modules/Compiler/IntelClang-DetermineCompiler.cmake @@ -0,0 +1,7 @@ + +set(_compiler_id_pp_test "defined(__clang__) && defined(__INTEL_CLANG_COMPILER)") + +include("${CMAKE_CURRENT_LIST_DIR}/Clang-DetermineCompilerInternal.cmake") + +string(APPEND _compiler_id_version_compute " +# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__INTEL_CLANG_COMPILER)") diff --git a/Modules/FindCUDA/select_compute_arch.cmake b/Modules/FindCUDA/select_compute_arch.cmake index c11725d..9351288 100644 --- a/Modules/FindCUDA/select_compute_arch.cmake +++ b/Modules/FindCUDA/select_compute_arch.cmake @@ -7,7 +7,7 @@ # ARCH_AND_PTX : NAME | NUM.NUM | NUM.NUM(NUM.NUM) | NUM.NUM+PTX # NAME: Fermi Kepler Maxwell Kepler+Tegra Kepler+Tesla Maxwell+Tegra Pascal Volta Turing Ampere # NUM: Any number. Only those pairs are currently accepted by NVCC though: -# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 7.0 7.2 7.5 8.0 +# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 7.0 7.2 7.5 8.0 8.6 # Returns LIST of flags to be added to CUDA_NVCC_FLAGS in ${out_variable} # Additionally, sets ${out_variable}_readable to the resulting numeric list # Example: @@ -82,16 +82,26 @@ if(CUDA_VERSION VERSION_GREATER_EQUAL "10.0") list(APPEND CUDA_ALL_GPU_ARCHITECTURES "7.5") if(CUDA_VERSION VERSION_LESS "11.0") - set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0") list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.5+PTX") + set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0") endif() endif() if(CUDA_VERSION VERSION_GREATER_EQUAL "11.0") list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Ampere") - list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0" "8.0+PTX") + list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0") list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.0") + if(CUDA_VERSION VERSION_LESS "11.1") + list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0+PTX") + set(CUDA_LIMIT_GPU_ARCHITECTURE "8.6") + endif() +endif() + +if(CUDA_VERSION VERSION_GREATER_EQUAL "11.1") + list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.6" "8.6+PTX") + list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.6") + if(CUDA_VERSION VERSION_LESS "12.0") set(CUDA_LIMIT_GPU_ARCHITECTURE "9.0") endif() diff --git a/Modules/FindJNI.cmake b/Modules/FindJNI.cmake index eff815d..bbca952 100644 --- a/Modules/FindJNI.cmake +++ b/Modules/FindJNI.cmake @@ -60,7 +60,7 @@ macro(java_append_library_directories _var) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") set(_java_libarch "i386") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64") - set(_java_libarch "arm64") + set(_java_libarch "arm64" "aarch64") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^alpha") set(_java_libarch "alpha") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake index 4d252bc..7af0171 100644 --- a/Modules/FindPackageHandleStandardArgs.cmake +++ b/Modules/FindPackageHandleStandardArgs.cmake @@ -294,16 +294,12 @@ function(FIND_PACKAGE_CHECK_VERSION version result) unset (version_msg) if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE) - if (${package}_FIND_VERSION_MIN VERSION_GREATER ${package}_FIND_VERSION_MAX - OR (${package}_FIND_VERSION_MIN VERSION_EQUAL ${package}_FIND_VERSION_MAX - AND ${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE")) - set (version_msg "Found unsuitable version \"${version}\", required range is empty (\"${${package}_FIND_VERSION_RANGE}\")") - elseif ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" - AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN) + if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" + AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN) AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX) OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" - AND version VERSION_LESS ${package}_FIND_VERSION_MAX))) + AND version VERSION_LESS ${package}_FIND_VERSION_MAX))) set (version_ok TRUE) set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")") else() @@ -531,7 +527,7 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) else() set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE) endif() - find_package_check_version (${_FOUND_VERSION} VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG + find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG ${FPCV_HANDLE_VERSION_RANGE}) else() # if the package was not found, but a version was given, add that to the output: diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake index 93827d8..2ad2c7e 100644 --- a/Modules/FindPkgConfig.cmake +++ b/Modules/FindPkgConfig.cmake @@ -31,7 +31,13 @@ set(PKG_CONFIG_VERSION 1) if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL "")) set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable") endif() -find_program(PKG_CONFIG_EXECUTABLE NAMES pkg-config DOC "pkg-config executable") + +set(PKG_CONFIG_NAMES "pkg-config") +if(CMAKE_HOST_WIN32) + list(PREPEND PKG_CONFIG_NAMES "pkg-config.bat") +endif() + +find_program(PKG_CONFIG_EXECUTABLE NAMES ${PKG_CONFIG_NAMES} DOC "pkg-config executable") mark_as_advanced(PKG_CONFIG_EXECUTABLE) set(_PKG_CONFIG_FAILURE_MESSAGE "") @@ -47,7 +53,9 @@ if (PKG_CONFIG_EXECUTABLE) string(APPEND _PKG_CONFIG_FAILURE_MESSAGE "The command\n" " \"${PKG_CONFIG_EXECUTABLE}\" --version\n" - " failed with output\n${_PKG_CONFIG_VERSION_ERROR}" + " 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 "") unset(PKG_CONFIG_VERSION_STRING) diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake index 584f64d..2d13f48 100644 --- a/Modules/FindPython.cmake +++ b/Modules/FindPython.cmake @@ -10,6 +10,10 @@ FindPython Find Python interpreter, compiler and development environment (include directories and libraries). +When a version is requested, it can be specified as a simple value or as a +range. For a detailed description of version range usage and capabilities, +refer to the :command:`find_package` command. + The following components are supported: * ``Interpreter``: search for Python interpreter. @@ -387,13 +391,39 @@ module suffix will include the ``Python_SOABI`` value, if any. #]=======================================================================] -set (_PYTHON_PREFIX Python) +cmake_policy(PUSH) +# numbers and boolean constants +cmake_policy (SET CMP0012 NEW) -if (DEFINED Python_FIND_VERSION) + +set (_PYTHON_PREFIX Python) +unset (_Python_REQUIRED_VERSION_MAJOR) +unset (_Python_REQUIRED_VERSIONS) + +if (Python_FIND_VERSION_RANGE) + # compute list of major versions + foreach (_Python_MAJOR IN ITEMS 3 2) + if (_Python_MAJOR VERSION_GREATER_EQUAL Python_FIND_VERSION_MIN_MAJOR + AND ((Python_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND _Python_MAJOR VERSION_LESS_EQUAL Python_FIND_VERSION_MAX) + OR (Python_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND _Python_MAJOR VERSION_LESS Python_FIND_VERSION_MAX))) + list (APPEND _Python_REQUIRED_VERSIONS ${_Python_MAJOR}) + endif() + endforeach() + list (LENGTH _Python_REQUIRED_VERSIONS _Python_VERSION_COUNT) + if (_Python_VERSION_COUNT EQUAL 0) + unset (_Python_REQUIRED_VERSIONS) + elseif (_Python_VERSION_COUNT EQUAL 1) + set (_Python_REQUIRED_VERSION_MAJOR ${_Python_REQUIRED_VERSIONS}) + endif() +elseif (DEFINED Python_FIND_VERSION) set (_Python_REQUIRED_VERSION_MAJOR ${Python_FIND_VERSION_MAJOR}) +else() + set (_Python_REQUIRED_VERSIONS 3 2) +endif() +if (_Python_REQUIRED_VERSION_MAJOR) include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake) -else() +elseif (_Python_REQUIRED_VERSIONS) # iterate over versions in quiet and NOT required modes to avoid multiple # "Found" messages and prematurally failure. set (_Python_QUIETLY ${Python_FIND_QUIETLY}) @@ -401,7 +431,6 @@ else() set (Python_FIND_QUIETLY TRUE) set (Python_FIND_REQUIRED FALSE) - set (_Python_REQUIRED_VERSIONS 3 2) set (_Python_REQUIRED_VERSION_LAST 2) unset (_Python_INPUT_VARS) @@ -435,10 +464,21 @@ else() set (Python_FIND_REQUIRED ${_Python_REQUIRED}) if (Python_FIND_REQUIRED OR NOT Python_FIND_QUIETLY) # call again validation command to get "Found" or error message - find_package_handle_standard_args (Python HANDLE_COMPONENTS + find_package_handle_standard_args (Python HANDLE_COMPONENTS HANDLE_VERSION_RANGE REQUIRED_VARS ${_Python_REQUIRED_VARS} VERSION_VAR Python_VERSION) endif() +else() + # supported versions not in the specified range. Call final check + if (NOT Python_FIND_COMPONENTS) + set (Python_FIND_COMPONENTS Interpreter) + set (Python_FIND_REQUIRED_Interpreter TRUE) + endif() + + include (${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + find_package_handle_standard_args (Python HANDLE_COMPONENTS HANDLE_VERSION_RANGE + VERSION_VAR Python_VERSION + REASON_FAILURE_MESSAGE "Version range specified \"${Python_FIND_VERSION_RANGE}\" does not include supported versions") endif() if (COMMAND __Python_add_library) @@ -448,3 +488,5 @@ if (COMMAND __Python_add_library) endif() unset (_PYTHON_PREFIX) + +cmake_policy(POP) diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake index c8225c4..41b55ee 100644 --- a/Modules/FindPython/Support.cmake +++ b/Modules/FindPython/Support.cmake @@ -31,6 +31,7 @@ endif() get_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE) +include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake) # # helper commands @@ -674,12 +675,7 @@ function (_PYTHON_VALIDATE_INTERPRETER) return() endif() - cmake_parse_arguments (PARSE_ARGV 0 _PVI "EXACT;CHECK_EXISTS" "" "") - if (_PVI_UNPARSED_ARGUMENTS) - set (expected_version "${_PVI_UNPARSED_ARGUMENTS}") - else() - unset (expected_version) - endif() + cmake_parse_arguments (PARSE_ARGV 0 _PVI "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}") # interpreter does not exist anymore @@ -710,50 +706,69 @@ function (_PYTHON_VALIDATE_INTERPRETER) endif() endif() - get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME) + if (_PVI_IN_RANGE OR _PVI_VERSION) + # retrieve full version + execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (result) + # interpreter is not usable + set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") + return() + endif() - if (expected_version) - if (NOT python_name STREQUAL "python${expected_version}${abi}${CMAKE_EXECUTABLE_SUFFIX}") - # compute number of components for version - string (REGEX REPLACE "[^.]" "" dots "${expected_version}") - # add one dot because there is one dot less than there are components + if (_PVI_VERSION) + # check against specified version + ## compute number of components for version + string (REGEX REPLACE "[^.]" "" dots "${_PVI_VERSION}") + ## add one dot because there is one dot less than there are components string (LENGTH "${dots}." count) if (count GREATER 3) set (count 3) endif() + set (version_regex "^[0-9]+") + if (count EQUAL 3) + string (APPEND version_regex "\\.[0-9]+\\.[0-9]+") + elseif (count EQUAL 2) + string (APPEND version_regex "\\.[0-9]+") + endif() + # extract needed range + string (REGEX MATCH "${version_regex}" version "${version}") - # executable found must have a specific version - execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:${count}]]))" - RESULT_VARIABLE result - OUTPUT_VARIABLE version - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (result) - # interpreter is not usable - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) + if (_PVI_EXACT AND NOT version VERSION_EQUAL _PVI_VERSION) + # interpreter has wrong version + set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") + return() else() - if (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version) - # interpreter has wrong version + # check that version is OK + string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") + string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVI_VERSION}") + if (NOT major_version VERSION_EQUAL expected_major_version + OR NOT version VERSION_GREATER_EQUAL _PVI_VERSION) set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - else() - # check that version is OK - string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") - string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${expected_version}") - if (NOT major_version VERSION_EQUAL expected_major_version - OR NOT version VERSION_GREATER_EQUAL expected_version) - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - endif() + return() endif() endif() - if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) + endif() + + if (_PVI_IN_RANGE) + # check if version is in the requested range + find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE) + if (NOT in_range) + # interpreter has invalid version + set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() endif() else() + get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME) if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}") # executable found do not have version in name # ensure major version is OK @@ -805,15 +820,7 @@ function (_PYTHON_VALIDATE_COMPILER) return() endif() - cmake_parse_arguments (PARSE_ARGV 0 _PVC "EXACT;CHECK_EXISTS" "" "") - if (_PVC_UNPARSED_ARGUMENTS) - set (major_version FALSE) - set (expected_version "${_PVC_UNPARSED_ARGUMENTS}") - else() - set (major_version TRUE) - set (expected_version "${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}") - set (_PVC_EXACT TRUE) - endif() + cmake_parse_arguments (PARSE_ARGV 0 _PVC "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}") # Compiler does not exist anymore @@ -826,19 +833,7 @@ function (_PYTHON_VALIDATE_COMPILER) # retrieve python environment version from compiler set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") - if (major_version) - # check only major version - file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write(str(sys.version_info[0]))") - else() - # compute number of components for version - string (REGEX REPLACE "[^.]" "" dots "${expected_version}") - # add one dot because there is one dot less than there are components - string (LENGTH "${dots}." count) - if (count GREATER 3) - set (count 3) - endif() - file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:${count}]]))\n") - endif() + file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n") execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_COMPILER}" ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS} /target:exe /embed "${working_dir}/version.py" @@ -858,11 +853,64 @@ function (_PYTHON_VALIDATE_COMPILER) # compiler is not usable set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") - elseif ((_PVC_EXACT AND NOT version VERSION_EQUAL expected_version) - OR NOT version VERSION_GREATER_EQUAL expected_version) - # Compiler has wrong version - set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) - set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") + return() + endif() + + if (_PVC_VERSION OR _PVC_IN_RANGE) + if (_PVC_VERSION) + # check against specified version + ## compute number of components for version + string (REGEX REPLACE "[^.]" "" dots "${_PVC_VERSION}") + ## add one dot because there is one dot less than there are components + string (LENGTH "${dots}." count) + if (count GREATER 3) + set (count 3) + endif() + set (version_regex "^[0-9]+") + if (count EQUAL 3) + string (APPEND version_regex "\\.[0-9]+\\.[0-9]+") + elseif (count EQUAL 2) + string (APPEND version_regex "\\.[0-9]+") + endif() + # extract needed range + string (REGEX MATCH "${version_regex}" version "${version}") + + if (_PVC_EXACT AND NOT version VERSION_EQUAL _PVC_VERSION) + # interpreter has wrong version + set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") + return() + else() + # check that version is OK + string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") + string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVC_VERSION}") + if (NOT major_version VERSION_EQUAL expected_major_version + OR NOT version VERSION_GREATER_EQUAL _PVC_VERSION) + set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") + return() + endif() + endif() + endif() + + if (_PVC_IN_RANGE) + # check if version is in the requested range + find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE) + if (NOT in_range) + # interpreter has invalid version + set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") + return() + endif() + endif() + else() + string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") + if (NOT major_version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + # Compiler has wrong major version + set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong major version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") + return() + endif() endif() endfunction() @@ -873,12 +921,7 @@ function (_PYTHON_VALIDATE_LIBRARY) return() endif() - cmake_parse_arguments (PARSE_ARGV 0 _PVL "EXACT;CHECK_EXISTS" "" "") - if (_PVL_UNPARSED_ARGUMENTS) - set (expected_version ${_PVL_UNPARSED_ARGUMENTS}) - else() - unset (expected_version) - endif() + cmake_parse_arguments (PARSE_ARGV 0 _PVL "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") # library does not exist anymore @@ -899,13 +942,25 @@ function (_PYTHON_VALIDATE_LIBRARY) set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") else() - if (expected_version) - # library have only major.minor information - string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${expected_version}") - if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version)) - # library has wrong version - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") + if (_PVL_VERSION OR _PVL_IN_RANGE) + if (_PVL_VERSION) + # library have only major.minor information + string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${_PVL_VERSION}") + if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version)) + # library has wrong version + set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") + endif() + endif() + + if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND _PVL_IN_RANGE) + # check if library version is in the requested range + find_package_check_version ("${lib_VERSION}" in_range HANDLE_VERSION_RANGE) + if (NOT in_range) + # library has wrong version + set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") + endif() endif() else() if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) @@ -932,12 +987,7 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR) return() endif() - cmake_parse_arguments (PARSE_ARGV 0 _PVID "EXACT;CHECK_EXISTS" "" "") - if (_PVID_UNPARSED_ARGUMENTS) - set (expected_version ${_PVID_UNPARSED_ARGUMENTS}) - else() - unset (expected_version) - endif() + cmake_parse_arguments (PARSE_ARGV 0 _PVID "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") # include file does not exist anymore @@ -954,11 +1004,23 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR) set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") else() - if (expected_version) - if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version)) - # include dir has wrong version - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") + if (_PVID_VERSION OR _PVID_IN_RANGE) + if (_PVID_VERSION) + if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version)) + # include dir has wrong version + set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") + endif() + endif() + + if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND PVID_IN_RANGE) + # check if include dir is in the request range + find_package_check_version ("${inc_VERSION}" in_range HANDLE_VERSION_RANGE) + if (NOT in_range) + # include dir has wrong version + set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) + set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") + endif() endif() else() if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) @@ -1020,13 +1082,27 @@ function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module) endfunction() -# If major version is specified, it must be the same as internal major version -if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR - AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") +if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + # range must include internal major version + if (${_PYTHON_PREFIX}_FIND_VERSION_MIN_MAJOR VERSION_GREATER _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR + OR ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" + AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" + AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR))) + _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong version range specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_RANGE}\", but expected version range must include major version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") - cmake_policy(POP) - return() + cmake_policy(POP) + return() + endif() +else() + if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR + AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + # If major version is specified, it must be the same as internal major version + _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") + + cmake_policy(POP) + return() + endif() endif() @@ -1070,18 +1146,32 @@ list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS}) unset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT) -if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT) - if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT "EXACT") - set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}) - else() - unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) - # add all compatible versions - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) - if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL "${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}") - list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) - endif() - endforeach() +if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) + if ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" + AND _${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MIN) + AND ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" + AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MAX) + OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" + AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS ${_PYTHON_PREFIX}_FIND_VERSION_MAX))) + list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) + endif() + endforeach() +else() + if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1) + if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) + set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT "EXACT") + set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}) + else() + unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) + # add all compatible versions + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) + if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL "${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}") + list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) + endif() + endforeach() + endif() endif() endif() @@ -1300,14 +1390,26 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module) string (MD5 signature "${signature}") if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - _python_validate_library (${${_PYTHON_PREFIX}_FIND_VERSION} - ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT} - CHECK_EXISTS) + if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) + _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) + elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + _python_validate_library (IN_RANGE CHECK_EXISTS) + elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) + _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) + else() + _python_validate_library (CHECK_EXISTS) + endif() endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - _python_validate_include_dir (${${_PYTHON_PREFIX}_FIND_VERSION} - ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT} - CHECK_EXISTS) + if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) + _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) + elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + _python_validate_include_dir (IN_RANGE CHECK_EXISTS) + elseif (${_PYTHON_PREFIX}_FIND_VERSION) + _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) + else() + _python_validate_include_dir (CHECK_EXISTS) + endif() endif() else() if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) @@ -1384,9 +1486,13 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE) # check version validity if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) + _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) + elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + _python_validate_interpreter (IN_RANGE CHECK_EXISTS) + elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) + _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) else() - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) + _python_validate_interpreter (CHECK_EXISTS) endif() else() unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE) @@ -1410,6 +1516,13 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) # Registry Paths _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) + set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) + elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) + list (APPEND VERSION ${${_PYTHON_PREFIX}_FIND_VERSION}) + endif() + while (TRUE) # Virtual environments handling if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") @@ -1424,7 +1537,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1445,7 +1558,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1460,7 +1573,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1474,7 +1587,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1483,7 +1596,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1496,7 +1609,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1509,7 +1622,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1519,6 +1632,11 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) endwhile() else() # look-up for various versions and locations + set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT) + if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) + endif() + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX INTERPRETER) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INTERPRETER) @@ -1538,7 +1656,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1573,7 +1691,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_CMAKE_SYSTEM_PATH) endif() - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1586,7 +1704,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1599,7 +1717,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1624,7 +1742,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_DEFAULT_PATH) endif() - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() @@ -1825,9 +1943,13 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE) # check version validity if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) + _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) + elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + _python_validate_compiler (IN_RANGE CHECK_EXISTS) + elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) + _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) else() - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) + _python_validate_compiler (CHECK_EXISTS) endif() else() unset (_${_PYTHON_PREFIX}_COMPILER CACHE) @@ -1862,6 +1984,13 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) + set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) + elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) + list (APPEND VERSION ${${_PYTHON_PREFIX}_FIND_VERSION}) + endif() + while (TRUE) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") @@ -1875,7 +2004,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1890,7 +2019,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1904,7 +2033,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1914,7 +2043,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1927,7 +2056,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) + _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1940,6 +2069,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) + _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1949,6 +2079,11 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) endwhile() else() # try using root dir and registry + set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT) + if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) + list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) + endif() + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES IMPLEMENTATIONS IronPython @@ -1979,7 +2114,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -1994,7 +2129,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -2008,7 +2143,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -2021,7 +2156,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -2034,7 +2169,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) + _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() @@ -2054,6 +2189,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) + _python_validate_compiler () endif() endif() @@ -2754,7 +2890,6 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS if (_${_PYTHON_PREFIX}_INCLUDE_DIR) # retrieve version from header file _python_get_version (INCLUDE PREFIX _${_PYTHON_PREFIX}_INC_) - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) if ("${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL _${_PYTHON_PREFIX}_VERSION) @@ -2980,10 +3115,10 @@ foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development endif() endforeach() -include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake) find_package_handle_standard_args (${_PYTHON_PREFIX} REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS} VERSION_VAR ${_PYTHON_PREFIX}_VERSION + HANDLE_VERSION_RANGE HANDLE_COMPONENTS REASON_FAILURE_MESSAGE "${_${_PYTHON_PREFIX}_REASON_FAILURE}") diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake index 1c75011..97e376d 100644 --- a/Modules/FindPython2.cmake +++ b/Modules/FindPython2.cmake @@ -10,6 +10,10 @@ FindPython2 Find Python 2 interpreter, compiler and development environment (include directories and libraries). +When a version is requested, it can be specified as a simple value or as a +range. For a detailed description of version range usage and capabilities, +refer to the :command:`find_package` command. + The following components are supported: * ``Interpreter``: search for Python 2 interpreter diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake index e6e9f04..266b50a 100644 --- a/Modules/FindPython3.cmake +++ b/Modules/FindPython3.cmake @@ -10,6 +10,10 @@ FindPython3 Find Python 3 interpreter, compiler and development environment (include directories and libraries). +When a version is requested, it can be specified as a simple value or as a +range. For a detailed description of version range usage and capabilities, +refer to the :command:`find_package` command. + The following components are supported: * ``Interpreter``: search for Python 3 interpreter diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1be424a..d0d9459 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -946,6 +946,7 @@ set(CTEST_SRCS cmCTest.cxx CTest/cmCTestResourceAllocator.cxx CTest/cmCTestResourceSpec.cxx CTest/cmCTestLaunch.cxx + CTest/cmCTestLaunchReporter.cxx CTest/cmCTestMemCheckCommand.cxx CTest/cmCTestMemCheckHandler.cxx CTest/cmCTestMultiProcessHandler.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 571d4b5..ce9646d 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 18) -set(CMake_VERSION_PATCH 20200927) +set(CMake_VERSION_PATCH 20201001) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 9997548..bb700eba 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -14,6 +14,7 @@ #include "cmsys/Process.h" #include "cmCTest.h" +#include "cmCTestLaunchReporter.h" #include "cmDuration.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" @@ -887,15 +888,28 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command, if (*retVal) { // If there was an error running command, report that on the // dashboard. - cmCTestBuildErrorWarning errorwarning; - errorwarning.LogLine = 1; - errorwarning.Text = cmStrCat( - "*** WARNING non-zero return value in ctest from: ", argv[0]); - errorwarning.PreContext.clear(); - errorwarning.PostContext.clear(); - errorwarning.Error = false; - this->ErrorsAndWarnings.push_back(std::move(errorwarning)); - this->TotalWarnings++; + if (this->UseCTestLaunch) { + cmCTestLaunchReporter reporter; + reporter.RealArgs = args; + reporter.ComputeFileNames(); + reporter.ExitCode = *retVal; + reporter.Process = cp; + // Use temporary BuildLog file to populate this error for CDash. + ofs.flush(); + reporter.LogOut = this->LogFileNames["Build"]; + reporter.LogOut += ".tmp"; + reporter.WriteXML(); + } else { + cmCTestBuildErrorWarning errorwarning; + errorwarning.LogLine = 1; + errorwarning.Text = cmStrCat( + "*** WARNING non-zero return value in ctest from: ", argv[0]); + errorwarning.PreContext.clear(); + errorwarning.PostContext.clear(); + errorwarning.Error = false; + this->ErrorsAndWarnings.push_back(std::move(errorwarning)); + this->TotalWarnings++; + } } } } else if (result == cmsysProcess_State_Exception) { diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx index a71f550..91818bb 100644 --- a/Source/CTest/cmCTestGenericHandler.cxx +++ b/Source/CTest/cmCTestGenericHandler.cxx @@ -6,6 +6,7 @@ #include <utility> #include "cmCTest.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmCTestGenericHandler::cmCTestGenericHandler() @@ -122,6 +123,8 @@ bool cmCTestGenericHandler::StartLogFile(const char* name, ostr << "_" << this->CTest->GetCurrentTag(); } ostr << ".log"; + this->LogFileNames[name] = + cmStrCat(this->CTest->GetBinaryDir(), "/Testing/Temporary/", ostr.str()); if (!this->CTest->OpenOutputFile("Temporary", ostr.str(), xofs)) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create log file: " << ostr.str() << std::endl); diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h index 591d9cd..89d7596 100644 --- a/Source/CTest/cmCTestGenericHandler.h +++ b/Source/CTest/cmCTestGenericHandler.h @@ -100,6 +100,7 @@ protected: cmCTest* CTest; t_StringToString Options; t_StringToString PersistentOptions; + t_StringToString LogFileNames; cmCTestCommand* Command; int SubmitIndex; diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 647f5ff..b9ed033 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestLaunch.h" -#include <cstdlib> #include <cstring> #include <iostream> @@ -10,8 +9,7 @@ #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" -#include "cmCryptoHash.h" -#include "cmGeneratedFileStream.h" +#include "cmCTestLaunchReporter.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmProcessOutput.h" @@ -19,7 +17,6 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmXMLWriter.h" #include "cmake.h" #ifdef _WIN32 @@ -30,16 +27,14 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv) { - this->Passthru = true; this->Process = nullptr; - this->ExitCode = 1; - this->CWD = cmSystemTools::GetCurrentWorkingDirectory(); if (!this->ParseArguments(argc, argv)) { return; } - this->ComputeFileNames(); + this->Reporter.RealArgs = this->RealArgs; + this->Reporter.ComputeFileNames(); this->ScrapeRulesLoaded = false; this->HaveOut = false; @@ -50,10 +45,6 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv) cmCTestLaunch::~cmCTestLaunch() { cmsysProcess_Delete(this->Process); - if (!this->Passthru) { - cmSystemTools::RemoveFile(this->LogOut); - cmSystemTools::RemoveFile(this->LogErr); - } } bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) @@ -93,28 +84,28 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) } else if (strcmp(arg, "--filter-prefix") == 0) { doing = DoingFilterPrefix; } else if (doing == DoingOutput) { - this->OptionOutput = arg; + this->Reporter.OptionOutput = arg; doing = DoingNone; } else if (doing == DoingSource) { - this->OptionSource = arg; + this->Reporter.OptionSource = arg; doing = DoingNone; } else if (doing == DoingLanguage) { - this->OptionLanguage = arg; - if (this->OptionLanguage == "CXX") { - this->OptionLanguage = "C++"; + this->Reporter.OptionLanguage = arg; + if (this->Reporter.OptionLanguage == "CXX") { + this->Reporter.OptionLanguage = "C++"; } doing = DoingNone; } else if (doing == DoingTargetName) { - this->OptionTargetName = arg; + this->Reporter.OptionTargetName = arg; doing = DoingNone; } else if (doing == DoingTargetType) { - this->OptionTargetType = arg; + this->Reporter.OptionTargetType = arg; doing = DoingNone; } else if (doing == DoingBuildDir) { - this->OptionBuildDir = arg; + this->Reporter.OptionBuildDir = arg; doing = DoingNone; } else if (doing == DoingFilterPrefix) { - this->OptionFilterPrefix = arg; + this->Reporter.OptionFilterPrefix = arg; doing = DoingNone; } } @@ -150,42 +141,11 @@ void cmCTestLaunch::HandleRealArg(const char* arg) this->RealArgs.emplace_back(arg); } -void cmCTestLaunch::ComputeFileNames() -{ - // We just passthru the behavior of the real command unless the - // CTEST_LAUNCH_LOGS environment variable is set. - const char* d = getenv("CTEST_LAUNCH_LOGS"); - if (!(d && *d)) { - return; - } - this->Passthru = false; - - // The environment variable specifies the directory into which we - // generate build logs. - this->LogDir = d; - cmSystemTools::ConvertToUnixSlashes(this->LogDir); - this->LogDir += "/"; - - // We hash the input command working dir and command line to obtain - // a repeatable and (probably) unique name for log files. - cmCryptoHash md5(cmCryptoHash::AlgoMD5); - md5.Initialize(); - md5.Append(this->CWD); - for (std::string const& realArg : this->RealArgs) { - md5.Append(realArg); - } - this->LogHash = md5.FinalizeHex(); - - // We store stdout and stderr in temporary log files. - this->LogOut = cmStrCat(this->LogDir, "launch-", this->LogHash, "-out.txt"); - this->LogErr = cmStrCat(this->LogDir, "launch-", this->LogHash, "-err.txt"); -} - void cmCTestLaunch::RunChild() { // Ignore noopt make rules if (this->RealArgs.empty() || this->RealArgs[0] == ":") { - this->ExitCode = 0; + this->Reporter.ExitCode = 0; return; } @@ -195,14 +155,14 @@ void cmCTestLaunch::RunChild() cmsys::ofstream fout; cmsys::ofstream ferr; - if (this->Passthru) { + if (this->Reporter.Passthru) { // In passthru mode we just share the output pipes. cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1); cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1); } else { // In full mode we record the child output pipes to log files. - fout.open(this->LogOut.c_str(), std::ios::out | std::ios::binary); - ferr.open(this->LogErr.c_str(), std::ios::out | std::ios::binary); + fout.open(this->Reporter.LogOut.c_str(), std::ios::out | std::ios::binary); + ferr.open(this->Reporter.LogErr.c_str(), std::ios::out | std::ios::binary); } #ifdef _WIN32 @@ -216,7 +176,7 @@ void cmCTestLaunch::RunChild() cmsysProcess_Execute(cp); // Record child stdout and stderr if necessary. - if (!this->Passthru) { + if (!this->Reporter.Passthru) { char* data = nullptr; int length = 0; cmProcessOutput processOutput; @@ -248,7 +208,7 @@ void cmCTestLaunch::RunChild() // Wait for the real command to finish. cmsysProcess_WaitForExit(cp, nullptr); - this->ExitCode = cmsysProcess_GetExitValue(cp); + this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp); } int cmCTestLaunch::Run() @@ -261,255 +221,31 @@ int cmCTestLaunch::Run() this->RunChild(); if (this->CheckResults()) { - return this->ExitCode; + return this->Reporter.ExitCode; } this->LoadConfig(); - this->WriteXML(); - - return this->ExitCode; -} - -void cmCTestLaunch::LoadLabels() -{ - if (this->OptionBuildDir.empty() || this->OptionTargetName.empty()) { - return; - } - - // Labels are listed in per-target files. - std::string fname = cmStrCat(this->OptionBuildDir, "/CMakeFiles/", - this->OptionTargetName, ".dir/Labels.txt"); - - // We are interested in per-target labels for this source file. - std::string source = this->OptionSource; - cmSystemTools::ConvertToUnixSlashes(source); - - // Load the labels file. - cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); - if (!fin) { - return; - } - bool inTarget = true; - bool inSource = false; - std::string line; - while (cmSystemTools::GetLineFromStream(fin, line)) { - if (line.empty() || line[0] == '#') { - // Ignore blank and comment lines. - continue; - } - if (line[0] == ' ') { - // Label lines appear indented by one space. - if (inTarget || inSource) { - this->Labels.insert(line.substr(1)); - } - } else if (!this->OptionSource.empty() && !inSource) { - // Non-indented lines specify a source file name. The first one - // is the end of the target-wide labels. Use labels following a - // matching source. - inTarget = false; - inSource = this->SourceMatches(line, source); - } else { - return; - } - } -} - -bool cmCTestLaunch::SourceMatches(std::string const& lhs, - std::string const& rhs) -{ - // TODO: Case sensitivity, UseRelativePaths, etc. Note that both - // paths in the comparison get generated by CMake. This is done for - // every source in the target, so it should be efficient (cannot use - // cmSystemTools::IsSameFile). - return lhs == rhs; -} - -bool cmCTestLaunch::IsError() const -{ - return this->ExitCode != 0; -} - -void cmCTestLaunch::WriteXML() -{ - // Name the xml file. - std::string logXML = - cmStrCat(this->LogDir, this->IsError() ? "error-" : "warning-", - this->LogHash, ".xml"); - - // Use cmGeneratedFileStream to atomically create the report file. - cmGeneratedFileStream fxml(logXML); - cmXMLWriter xml(fxml, 2); - cmXMLElement e2(xml, "Failure"); - e2.Attribute("type", this->IsError() ? "Error" : "Warning"); - this->WriteXMLAction(e2); - this->WriteXMLCommand(e2); - this->WriteXMLResult(e2); - this->WriteXMLLabels(e2); -} - -void cmCTestLaunch::WriteXMLAction(cmXMLElement& e2) -{ - e2.Comment("Meta-information about the build action"); - cmXMLElement e3(e2, "Action"); - - // TargetName - if (!this->OptionTargetName.empty()) { - e3.Element("TargetName", this->OptionTargetName); - } - - // Language - if (!this->OptionLanguage.empty()) { - e3.Element("Language", this->OptionLanguage); - } - - // SourceFile - if (!this->OptionSource.empty()) { - std::string source = this->OptionSource; - cmSystemTools::ConvertToUnixSlashes(source); - - // If file is in source tree use its relative location. - if (cmSystemTools::FileIsFullPath(this->SourceDir) && - cmSystemTools::FileIsFullPath(source) && - cmSystemTools::IsSubDirectory(source, this->SourceDir)) { - source = cmSystemTools::RelativePath(this->SourceDir, source); - } - - e3.Element("SourceFile", source); - } - - // OutputFile - if (!this->OptionOutput.empty()) { - e3.Element("OutputFile", this->OptionOutput); - } - - // OutputType - const char* outputType = nullptr; - if (!this->OptionTargetType.empty()) { - if (this->OptionTargetType == "EXECUTABLE") { - outputType = "executable"; - } else if (this->OptionTargetType == "SHARED_LIBRARY") { - outputType = "shared library"; - } else if (this->OptionTargetType == "MODULE_LIBRARY") { - outputType = "module library"; - } else if (this->OptionTargetType == "STATIC_LIBRARY") { - outputType = "static library"; - } - } else if (!this->OptionSource.empty()) { - outputType = "object file"; - } - if (outputType) { - e3.Element("OutputType", outputType); - } -} - -void cmCTestLaunch::WriteXMLCommand(cmXMLElement& e2) -{ - e2.Comment("Details of command"); - cmXMLElement e3(e2, "Command"); - if (!this->CWD.empty()) { - e3.Element("WorkingDirectory", this->CWD); - } - for (std::string const& realArg : this->RealArgs) { - e3.Element("Argument", realArg); - } -} - -void cmCTestLaunch::WriteXMLResult(cmXMLElement& e2) -{ - e2.Comment("Result of command"); - cmXMLElement e3(e2, "Result"); - - // StdOut - this->DumpFileToXML(e3, "StdOut", this->LogOut); - - // StdErr - this->DumpFileToXML(e3, "StdErr", this->LogErr); - - // ExitCondition - cmXMLElement e4(e3, "ExitCondition"); - cmsysProcess* cp = this->Process; - switch (cmsysProcess_GetState(cp)) { - case cmsysProcess_State_Starting: - e4.Content("No process has been executed"); - break; - case cmsysProcess_State_Executing: - e4.Content("The process is still executing"); - break; - case cmsysProcess_State_Disowned: - e4.Content("Disowned"); - break; - case cmsysProcess_State_Killed: - e4.Content("Killed by parent"); - break; - - case cmsysProcess_State_Expired: - e4.Content("Killed when timeout expired"); - break; - case cmsysProcess_State_Exited: - e4.Content(this->ExitCode); - break; - case cmsysProcess_State_Exception: - e4.Content("Terminated abnormally: "); - e4.Content(cmsysProcess_GetExceptionString(cp)); - break; - case cmsysProcess_State_Error: - e4.Content("Error administrating child process: "); - e4.Content(cmsysProcess_GetErrorString(cp)); - break; - } -} + this->Reporter.Process = this->Process; + this->Reporter.WriteXML(); -void cmCTestLaunch::WriteXMLLabels(cmXMLElement& e2) -{ - this->LoadLabels(); - if (!this->Labels.empty()) { - e2.Comment("Interested parties"); - cmXMLElement e3(e2, "Labels"); - for (std::string const& label : this->Labels) { - e3.Element("Label", label); - } - } -} - -void cmCTestLaunch::DumpFileToXML(cmXMLElement& e3, const char* tag, - std::string const& fname) -{ - cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); - - std::string line; - const char* sep = ""; - - cmXMLElement e4(e3, tag); - while (cmSystemTools::GetLineFromStream(fin, line)) { - if (MatchesFilterPrefix(line)) { - continue; - } - if (this->Match(line, this->RegexWarningSuppress)) { - line = cmStrCat("[CTest: warning suppressed] ", line); - } else if (this->Match(line, this->RegexWarning)) { - line = cmStrCat("[CTest: warning matched] ", line); - } - e4.Content(sep); - e4.Content(line); - sep = "\n"; - } + return this->Reporter.ExitCode; } bool cmCTestLaunch::CheckResults() { // Skip XML in passthru mode. - if (this->Passthru) { + if (this->Reporter.Passthru) { return true; } // We always report failure for error conditions. - if (this->IsError()) { + if (this->Reporter.IsError()) { return false; } // Scrape the output logs to look for warnings. - if ((this->HaveErr && this->ScrapeLog(this->LogErr)) || - (this->HaveOut && this->ScrapeLog(this->LogOut))) { + if ((this->HaveErr && this->ScrapeLog(this->Reporter.LogErr)) || + (this->HaveOut && this->ScrapeLog(this->Reporter.LogOut))) { return false; } return true; @@ -522,22 +258,17 @@ void cmCTestLaunch::LoadScrapeRules() } this->ScrapeRulesLoaded = true; - // Common compiler warning formats. These are much simpler than the - // full log-scraping expressions because we do not need to extract - // file and line information. - this->RegexWarning.emplace_back("(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]"); - this->RegexWarning.emplace_back("(^|[ :])[Rr][Ee][Mm][Aa][Rr][Kk]"); - this->RegexWarning.emplace_back("(^|[ :])[Nn][Oo][Tt][Ee]"); - // Load custom match rules given to us by CTest. - this->LoadScrapeRules("Warning", this->RegexWarning); - this->LoadScrapeRules("WarningSuppress", this->RegexWarningSuppress); + this->LoadScrapeRules("Warning", this->Reporter.RegexWarning); + this->LoadScrapeRules("WarningSuppress", + this->Reporter.RegexWarningSuppress); } void cmCTestLaunch::LoadScrapeRules( const char* purpose, std::vector<cmsys::RegularExpression>& regexps) { - std::string fname = cmStrCat(this->LogDir, "Custom", purpose, ".txt"); + std::string fname = + cmStrCat(this->Reporter.LogDir, "Custom", purpose, ".txt"); cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); std::string line; cmsys::RegularExpression rex; @@ -557,35 +288,18 @@ bool cmCTestLaunch::ScrapeLog(std::string const& fname) cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); std::string line; while (cmSystemTools::GetLineFromStream(fin, line)) { - if (MatchesFilterPrefix(line)) { + if (this->Reporter.MatchesFilterPrefix(line)) { continue; } - if (this->Match(line, this->RegexWarning) && - !this->Match(line, this->RegexWarningSuppress)) { + if (this->Reporter.Match(line, this->Reporter.RegexWarning) && + !this->Reporter.Match(line, this->Reporter.RegexWarningSuppress)) { return true; } } return false; } -bool cmCTestLaunch::Match(std::string const& line, - std::vector<cmsys::RegularExpression>& regexps) -{ - for (cmsys::RegularExpression& r : regexps) { - if (r.find(line)) { - return true; - } - } - return false; -} - -bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const -{ - return !this->OptionFilterPrefix.empty() && - cmHasPrefix(line, this->OptionFilterPrefix); -} - int cmCTestLaunch::Main(int argc, const char* const argv[]) { if (argc == 2) { @@ -605,9 +319,10 @@ void cmCTestLaunch::LoadConfig() cm.GetCurrentSnapshot().SetDefaultDefinitions(); cmGlobalGenerator gg(&cm); cmMakefile mf(&gg, cm.GetCurrentSnapshot()); - std::string fname = cmStrCat(this->LogDir, "CTestLaunchConfig.cmake"); + std::string fname = + cmStrCat(this->Reporter.LogDir, "CTestLaunchConfig.cmake"); if (cmSystemTools::FileExists(fname) && mf.ReadListFile(fname)) { - this->SourceDir = mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY"); - cmSystemTools::ConvertToUnixSlashes(this->SourceDir); + this->Reporter.SourceDir = mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY"); + cmSystemTools::ConvertToUnixSlashes(this->Reporter.SourceDir); } } diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index 33ff82c..d18f66d 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -4,13 +4,14 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <set> #include <string> #include <vector> -#include "cmsys/RegularExpression.hxx" +#include "cmCTestLaunchReporter.h" -class cmXMLElement; +namespace cmsys { +class RegularExpression; +} /** \class cmCTestLaunch * \brief Launcher for make rules to report results for ctest @@ -35,70 +36,36 @@ private: int Run(); void RunChild(); - // Methods to check the result of the real command. - bool IsError() const; + // Method to check the result of the real command. bool CheckResults(); - // Launcher options specified before the real command. - std::string OptionOutput; - std::string OptionSource; - std::string OptionLanguage; - std::string OptionTargetName; - std::string OptionTargetType; - std::string OptionBuildDir; - std::string OptionFilterPrefix; + // Parse out launcher-specific options specified before the real command. bool ParseArguments(int argc, const char* const* argv); // The real command line appearing after launcher arguments. int RealArgC; const char* const* RealArgV; - std::string CWD; // The real command line after response file expansion. std::vector<std::string> RealArgs; void HandleRealArg(const char* arg); - // A hash of the real command line is unique and unlikely to collide. - std::string LogHash; - void ComputeFileNames(); - - bool Passthru; struct cmsysProcess_s* Process; - int ExitCode; - // Temporary log files for stdout and stderr of real command. - std::string LogDir; - std::string LogOut; - std::string LogErr; + // Whether or not any data have been written to stdout or stderr. bool HaveOut; bool HaveErr; - // Labels associated with the build rule. - std::set<std::string> Labels; - void LoadLabels(); - bool SourceMatches(std::string const& lhs, std::string const& rhs); - - // Regular expressions to match warnings and their exceptions. + // Load custom rules to match warnings and their exceptions. bool ScrapeRulesLoaded; - std::vector<cmsys::RegularExpression> RegexWarning; - std::vector<cmsys::RegularExpression> RegexWarningSuppress; void LoadScrapeRules(); void LoadScrapeRules(const char* purpose, std::vector<cmsys::RegularExpression>& regexps); bool ScrapeLog(std::string const& fname); - bool Match(std::string const& line, - std::vector<cmsys::RegularExpression>& regexps); - bool MatchesFilterPrefix(std::string const& line) const; - - // Methods to generate the xml fragment. - void WriteXML(); - void WriteXMLAction(cmXMLElement&); - void WriteXMLCommand(cmXMLElement&); - void WriteXMLResult(cmXMLElement&); - void WriteXMLLabels(cmXMLElement&); - void DumpFileToXML(cmXMLElement&, const char* tag, std::string const& fname); + + // Helper class to generate the xml fragment. + cmCTestLaunchReporter Reporter; // Configuration void LoadConfig(); - std::string SourceDir; }; diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx new file mode 100644 index 0000000..6ec7d0e --- /dev/null +++ b/Source/CTest/cmCTestLaunchReporter.cxx @@ -0,0 +1,316 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCTestLaunchReporter.h" + +#include "cmsys/FStream.hxx" +#include "cmsys/Process.h" +#include "cmsys/RegularExpression.hxx" + +#include "cmCryptoHash.h" +#include "cmGeneratedFileStream.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmXMLWriter.h" + +#ifdef _WIN32 +# include <fcntl.h> // for _O_BINARY +# include <io.h> // for _setmode +# include <stdio.h> // for std{out,err} and fileno +#endif + +cmCTestLaunchReporter::cmCTestLaunchReporter() +{ + this->Passthru = true; + this->ExitCode = 1; + this->CWD = cmSystemTools::GetCurrentWorkingDirectory(); + + this->ComputeFileNames(); + + // Common compiler warning formats. These are much simpler than the + // full log-scraping expressions because we do not need to extract + // file and line information. + this->RegexWarning.emplace_back("(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]"); + this->RegexWarning.emplace_back("(^|[ :])[Rr][Ee][Mm][Aa][Rr][Kk]"); + this->RegexWarning.emplace_back("(^|[ :])[Nn][Oo][Tt][Ee]"); +} + +cmCTestLaunchReporter::~cmCTestLaunchReporter() +{ + if (!this->Passthru) { + cmSystemTools::RemoveFile(this->LogOut); + cmSystemTools::RemoveFile(this->LogErr); + } +} + +void cmCTestLaunchReporter::ComputeFileNames() +{ + // We just passthru the behavior of the real command unless the + // CTEST_LAUNCH_LOGS environment variable is set. + std::string d; + if (!cmSystemTools::GetEnv("CTEST_LAUNCH_LOGS", d) || d.empty()) { + return; + } + this->Passthru = false; + + // The environment variable specifies the directory into which we + // generate build logs. + this->LogDir = d; + cmSystemTools::ConvertToUnixSlashes(this->LogDir); + this->LogDir += "/"; + + // We hash the input command working dir and command line to obtain + // a repeatable and (probably) unique name for log files. + cmCryptoHash md5(cmCryptoHash::AlgoMD5); + md5.Initialize(); + md5.Append(this->CWD); + for (std::string const& realArg : this->RealArgs) { + md5.Append(realArg); + } + this->LogHash = md5.FinalizeHex(); + + // We store stdout and stderr in temporary log files. + this->LogOut = cmStrCat(this->LogDir, "launch-", this->LogHash, "-out.txt"); + this->LogErr = cmStrCat(this->LogDir, "launch-", this->LogHash, "-err.txt"); +} + +void cmCTestLaunchReporter::LoadLabels() +{ + if (this->OptionBuildDir.empty() || this->OptionTargetName.empty()) { + return; + } + + // Labels are listed in per-target files. + std::string fname = cmStrCat(this->OptionBuildDir, "/CMakeFiles/", + this->OptionTargetName, ".dir/Labels.txt"); + + // We are interested in per-target labels for this source file. + std::string source = this->OptionSource; + cmSystemTools::ConvertToUnixSlashes(source); + + // Load the labels file. + cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); + if (!fin) { + return; + } + bool inTarget = true; + bool inSource = false; + std::string line; + while (cmSystemTools::GetLineFromStream(fin, line)) { + if (line.empty() || line[0] == '#') { + // Ignore blank and comment lines. + continue; + } + if (line[0] == ' ') { + // Label lines appear indented by one space. + if (inTarget || inSource) { + this->Labels.insert(line.substr(1)); + } + } else if (!this->OptionSource.empty() && !inSource) { + // Non-indented lines specify a source file name. The first one + // is the end of the target-wide labels. Use labels following a + // matching source. + inTarget = false; + inSource = this->SourceMatches(line, source); + } else { + return; + } + } +} + +bool cmCTestLaunchReporter::SourceMatches(std::string const& lhs, + std::string const& rhs) +{ + // TODO: Case sensitivity, UseRelativePaths, etc. Note that both + // paths in the comparison get generated by CMake. This is done for + // every source in the target, so it should be efficient (cannot use + // cmSystemTools::IsSameFile). + return lhs == rhs; +} + +bool cmCTestLaunchReporter::IsError() const +{ + return this->ExitCode != 0; +} + +void cmCTestLaunchReporter::WriteXML() +{ + // Name the xml file. + std::string logXML = + cmStrCat(this->LogDir, this->IsError() ? "error-" : "warning-", + this->LogHash, ".xml"); + + // Use cmGeneratedFileStream to atomically create the report file. + cmGeneratedFileStream fxml(logXML); + cmXMLWriter xml(fxml, 2); + cmXMLElement e2(xml, "Failure"); + e2.Attribute("type", this->IsError() ? "Error" : "Warning"); + this->WriteXMLAction(e2); + this->WriteXMLCommand(e2); + this->WriteXMLResult(e2); + this->WriteXMLLabels(e2); +} + +void cmCTestLaunchReporter::WriteXMLAction(cmXMLElement& e2) +{ + e2.Comment("Meta-information about the build action"); + cmXMLElement e3(e2, "Action"); + + // TargetName + if (!this->OptionTargetName.empty()) { + e3.Element("TargetName", this->OptionTargetName); + } + + // Language + if (!this->OptionLanguage.empty()) { + e3.Element("Language", this->OptionLanguage); + } + + // SourceFile + if (!this->OptionSource.empty()) { + std::string source = this->OptionSource; + cmSystemTools::ConvertToUnixSlashes(source); + + // If file is in source tree use its relative location. + if (cmSystemTools::FileIsFullPath(this->SourceDir) && + cmSystemTools::FileIsFullPath(source) && + cmSystemTools::IsSubDirectory(source, this->SourceDir)) { + source = cmSystemTools::RelativePath(this->SourceDir, source); + } + + e3.Element("SourceFile", source); + } + + // OutputFile + if (!this->OptionOutput.empty()) { + e3.Element("OutputFile", this->OptionOutput); + } + + // OutputType + const char* outputType = nullptr; + if (!this->OptionTargetType.empty()) { + if (this->OptionTargetType == "EXECUTABLE") { + outputType = "executable"; + } else if (this->OptionTargetType == "SHARED_LIBRARY") { + outputType = "shared library"; + } else if (this->OptionTargetType == "MODULE_LIBRARY") { + outputType = "module library"; + } else if (this->OptionTargetType == "STATIC_LIBRARY") { + outputType = "static library"; + } + } else if (!this->OptionSource.empty()) { + outputType = "object file"; + } + if (outputType) { + e3.Element("OutputType", outputType); + } +} + +void cmCTestLaunchReporter::WriteXMLCommand(cmXMLElement& e2) +{ + e2.Comment("Details of command"); + cmXMLElement e3(e2, "Command"); + if (!this->CWD.empty()) { + e3.Element("WorkingDirectory", this->CWD); + } + for (std::string const& realArg : this->RealArgs) { + e3.Element("Argument", realArg); + } +} + +void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2) +{ + e2.Comment("Result of command"); + cmXMLElement e3(e2, "Result"); + + // StdOut + this->DumpFileToXML(e3, "StdOut", this->LogOut); + + // StdErr + this->DumpFileToXML(e3, "StdErr", this->LogErr); + + // ExitCondition + cmXMLElement e4(e3, "ExitCondition"); + cmsysProcess* cp = this->Process; + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Starting: + e4.Content("No process has been executed"); + break; + case cmsysProcess_State_Executing: + e4.Content("The process is still executing"); + break; + case cmsysProcess_State_Disowned: + e4.Content("Disowned"); + break; + case cmsysProcess_State_Killed: + e4.Content("Killed by parent"); + break; + + case cmsysProcess_State_Expired: + e4.Content("Killed when timeout expired"); + break; + case cmsysProcess_State_Exited: + e4.Content(this->ExitCode); + break; + case cmsysProcess_State_Exception: + e4.Content("Terminated abnormally: "); + e4.Content(cmsysProcess_GetExceptionString(cp)); + break; + case cmsysProcess_State_Error: + e4.Content("Error administrating child process: "); + e4.Content(cmsysProcess_GetErrorString(cp)); + break; + } +} + +void cmCTestLaunchReporter::WriteXMLLabels(cmXMLElement& e2) +{ + this->LoadLabels(); + if (!this->Labels.empty()) { + e2.Comment("Interested parties"); + cmXMLElement e3(e2, "Labels"); + for (std::string const& label : this->Labels) { + e3.Element("Label", label); + } + } +} + +void cmCTestLaunchReporter::DumpFileToXML(cmXMLElement& e3, const char* tag, + std::string const& fname) +{ + cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); + + std::string line; + const char* sep = ""; + + cmXMLElement e4(e3, tag); + while (cmSystemTools::GetLineFromStream(fin, line)) { + if (MatchesFilterPrefix(line)) { + continue; + } + if (this->Match(line, this->RegexWarningSuppress)) { + line = cmStrCat("[CTest: warning suppressed] ", line); + } else if (this->Match(line, this->RegexWarning)) { + line = cmStrCat("[CTest: warning matched] ", line); + } + e4.Content(sep); + e4.Content(line); + sep = "\n"; + } +} + +bool cmCTestLaunchReporter::Match( + std::string const& line, std::vector<cmsys::RegularExpression>& regexps) +{ + for (cmsys::RegularExpression& r : regexps) { + if (r.find(line)) { + return true; + } + } + return false; +} + +bool cmCTestLaunchReporter::MatchesFilterPrefix(std::string const& line) const +{ + return !this->OptionFilterPrefix.empty() && + cmHasPrefix(line, this->OptionFilterPrefix); +} diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h new file mode 100644 index 0000000..675a878 --- /dev/null +++ b/Source/CTest/cmCTestLaunchReporter.h @@ -0,0 +1,81 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <set> +#include <string> +#include <vector> + +#include "cmsys/RegularExpression.hxx" + +class cmXMLElement; + +/** \class cmCTestLaunchReporter + * \brief Generate CTest XML output for the 'ctest --launch' tool. + */ +class cmCTestLaunchReporter +{ +public: + // Initialize the launcher from its command line. + cmCTestLaunchReporter(); + ~cmCTestLaunchReporter(); + + cmCTestLaunchReporter(const cmCTestLaunchReporter&) = delete; + cmCTestLaunchReporter& operator=(const cmCTestLaunchReporter&) = delete; + + // Methods to check the result of the real command. + bool IsError() const; + + // Launcher options specified before the real command. + std::string OptionOutput; + std::string OptionSource; + std::string OptionLanguage; + std::string OptionTargetName; + std::string OptionTargetType; + std::string OptionBuildDir; + std::string OptionFilterPrefix; + + // The real command line appearing after launcher arguments. + std::string CWD; + + // The real command line after response file expansion. + std::vector<std::string> RealArgs; + + // A hash of the real command line is unique and unlikely to collide. + std::string LogHash; + void ComputeFileNames(); + + bool Passthru; + struct cmsysProcess_s* Process; + int ExitCode; + + // Temporary log files for stdout and stderr of real command. + std::string LogDir; + std::string LogOut; + std::string LogErr; + + // Labels associated with the build rule. + std::set<std::string> Labels; + void LoadLabels(); + bool SourceMatches(std::string const& lhs, std::string const& rhs); + + // Regular expressions to match warnings and their exceptions. + std::vector<cmsys::RegularExpression> RegexWarning; + std::vector<cmsys::RegularExpression> RegexWarningSuppress; + bool Match(std::string const& line, + std::vector<cmsys::RegularExpression>& regexps); + bool MatchesFilterPrefix(std::string const& line) const; + + // Methods to generate the xml fragment. + void WriteXML(); + void WriteXMLAction(cmXMLElement&); + void WriteXMLCommand(cmXMLElement&); + void WriteXMLResult(cmXMLElement&); + void WriteXMLLabels(cmXMLElement&); + void DumpFileToXML(cmXMLElement&, const char* tag, std::string const& fname); + + // Configuration + std::string SourceDir; +}; diff --git a/Source/QtDialog/AddCacheEntry.cxx b/Source/QtDialog/AddCacheEntry.cxx index f5e0777..1075895 100644 --- a/Source/QtDialog/AddCacheEntry.cxx +++ b/Source/QtDialog/AddCacheEntry.cxx @@ -40,8 +40,10 @@ AddCacheEntry::AddCacheEntry(QWidget* p, const QStringList& varNames, AddCacheEntry::setTabOrder(string, this->Description); QCompleter* completer = new QCompleter(this->VarNames, this); this->Name->setCompleter(completer); - connect(completer, SIGNAL(activated(const QString&)), this, - SLOT(onCompletionActivated(const QString&))); + connect( + completer, + static_cast<void (QCompleter::*)(const QString&)>(&QCompleter::activated), + this, &AddCacheEntry::onCompletionActivated); } QString AddCacheEntry::name() const diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 0ec012c..5fd0e89 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -84,6 +84,8 @@ set(SRCS CMakeSetupDialog.cxx CMakeSetupDialog.h Compilers.h + EnvironmentDialog.cxx + EnvironmentDialog.h FirstConfigure.cxx FirstConfigure.h QCMake.cxx @@ -102,6 +104,7 @@ qt5_wrap_ui(UI_SRCS Compilers.ui CrossCompiler.ui AddCacheEntry.ui + EnvironmentDialog.ui RegexExplorer.ui WarningMessagesDialog.ui ) @@ -109,6 +112,7 @@ qt5_wrap_cpp(MOC_SRCS AddCacheEntry.h Compilers.h CMakeSetupDialog.h + EnvironmentDialog.h FirstConfigure.h QCMake.h QCMakeCacheView.h diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index fcc8408..a904b94 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -16,6 +16,7 @@ #include <QMenuBar> #include <QMessageBox> #include <QMimeData> +#include <QProcessEnvironment> #include <QProgressBar> #include <QSettings> #include <QShortcut> @@ -35,6 +36,7 @@ #include "cmVersion.h" #include "AddCacheEntry.h" +#include "EnvironmentDialog.h" #include "FirstConfigure.h" #include "RegexExplorer.h" #include "WarningMessagesDialog.h" @@ -103,76 +105,87 @@ CMakeSetupDialog::CMakeSetupDialog() QMenu* FileMenu = this->menuBar()->addMenu(tr("&File")); this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache")); - QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)), this, - SLOT(doReloadCache())); + QObject::connect(this->ReloadCacheAction, &QAction::triggered, this, + &CMakeSetupDialog::doReloadCache); this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache")); - QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)), this, - SLOT(doDeleteCache())); + QObject::connect(this->DeleteCacheAction, &QAction::triggered, this, + &CMakeSetupDialog::doDeleteCache); this->ExitAction = FileMenu->addAction(tr("E&xit")); - this->ExitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); - QObject::connect(this->ExitAction, SIGNAL(triggered(bool)), this, - SLOT(close())); + QObject::connect(this->ExitAction, &QAction::triggered, this, + &CMakeSetupDialog::close); + this->ExitAction->setShortcut(QKeySequence::Quit); QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools")); this->ConfigureAction = ToolsMenu->addAction(tr("&Configure")); + QObject::connect(this->ConfigureAction, &QAction::triggered, this, + &CMakeSetupDialog::doConfigure); // prevent merging with Preferences menu item on macOS this->ConfigureAction->setMenuRole(QAction::NoRole); - QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)), this, - SLOT(doConfigure())); this->GenerateAction = ToolsMenu->addAction(tr("&Generate")); - QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)), this, - SLOT(doGenerate())); - QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes")); - QObject::connect(showChangesAction, SIGNAL(triggered(bool)), this, - SLOT(showUserChanges())); + QObject::connect(this->GenerateAction, &QAction::triggered, this, + &CMakeSetupDialog::doGenerate); + auto* a = ToolsMenu->addAction(tr("&Show My Changes")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::showUserChanges); #if defined(Q_WS_MAC) || defined(Q_OS_MAC) this->InstallForCommandLineAction = ToolsMenu->addAction(tr("&How to Install For Command Line Use")); - QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)), - this, SLOT(doInstallForCommandLine())); + QObject::connect(this->InstallForCommandLineAction, &QAction::triggered, + this, &CMakeSetupDialog::doInstallForCommandLine); #endif ToolsMenu->addSeparator(); - ToolsMenu->addAction(tr("Regular Expression Explorer..."), this, - SLOT(doRegexExplorerDialog())); + a = ToolsMenu->addAction(tr("Regular Expression Explorer...")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doRegexExplorerDialog); ToolsMenu->addSeparator(); - ToolsMenu->addAction(tr("&Find in Output..."), this, - SLOT(doOutputFindDialog()), QKeySequence::Find); - ToolsMenu->addAction(tr("Find Next"), this, SLOT(doOutputFindNext()), - QKeySequence::FindNext); - ToolsMenu->addAction(tr("Find Previous"), this, SLOT(doOutputFindPrev()), - QKeySequence::FindPrevious); - ToolsMenu->addAction(tr("Goto Next Error"), this, SLOT(doOutputErrorNext()), - QKeySequence(Qt::Key_F8)); // in Visual Studio - new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Period), this, - SLOT(doOutputErrorNext())); // in Eclipse + a = ToolsMenu->addAction(tr("&Find in Output...")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputFindDialog); + a->setShortcut(QKeySequence::Find); + a = ToolsMenu->addAction(tr("Find Next")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputFindNext); + a->setShortcut(QKeySequence::FindNext); + a = ToolsMenu->addAction(tr("Find Previous")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputFindPrev); + a->setShortcut(QKeySequence::FindPrevious); + a = ToolsMenu->addAction(tr("Goto Next Error")); // in Visual Studio + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputErrorNext); + a->setShortcut(QKeySequence(Qt::Key_F8)); + auto* s = new QShortcut(this); + s->setKey(QKeySequence(Qt::CTRL + Qt::Key_Period)); + QObject::connect(s, &QShortcut::activated, this, + &CMakeSetupDialog::doOutputErrorNext); // in Eclipse QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options")); - OptionsMenu->addAction(tr("Warning Messages..."), this, - SLOT(doWarningMessagesDialog())); + a = OptionsMenu->addAction(tr("Warning Messages...")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doWarningMessagesDialog); this->WarnUninitializedAction = OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)")); this->WarnUninitializedAction->setCheckable(true); QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output")); debugAction->setCheckable(true); - QObject::connect(debugAction, SIGNAL(toggled(bool)), this, - SLOT(setDebugOutput(bool))); + QObject::connect(debugAction, &QAction::toggled, this, + &CMakeSetupDialog::setDebugOutput); OptionsMenu->addSeparator(); - QAction* expandAction = - OptionsMenu->addAction(tr("&Expand Grouped Entries")); - QObject::connect(expandAction, SIGNAL(triggered(bool)), this->CacheValues, - SLOT(expandAll())); - QAction* collapseAction = - OptionsMenu->addAction(tr("&Collapse Grouped Entries")); - QObject::connect(collapseAction, SIGNAL(triggered(bool)), this->CacheValues, - SLOT(collapseAll())); + a = OptionsMenu->addAction(tr("&Expand Grouped Entries")); + QObject::connect(a, &QAction::triggered, this->CacheValues, + &QCMakeCacheView::expandAll); + a = OptionsMenu->addAction(tr("&Collapse Grouped Entries")); + QObject::connect(a, &QAction::triggered, this->CacheValues, + &QCMakeCacheView::collapseAll); QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help")); - QAction* a = HelpMenu->addAction(tr("About")); - QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doAbout())); + a = HelpMenu->addAction(tr("About")); + QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doAbout); a = HelpMenu->addAction(tr("Help")); - QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doHelp())); + QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doHelp); + a->setShortcut(QKeySequence::HelpContents); this->setAcceptDrops(true); @@ -189,16 +202,16 @@ CMakeSetupDialog::CMakeSetupDialog() this->ErrorFormat.setForeground(QBrush(Qt::red)); this->Output->setContextMenuPolicy(Qt::CustomContextMenu); - connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)), - this, SLOT(doOutputContextMenu(const QPoint&))); + connect(this->Output, &QTextEdit::customContextMenuRequested, this, + &CMakeSetupDialog::doOutputContextMenu); // disable open project button this->OpenProjectButton->setDisabled(true); // start the cmake worker thread this->CMakeThread = new QCMakeThread(this); - QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), this, - SLOT(initialize()), Qt::QueuedConnection); + QObject::connect(this->CMakeThread, &QCMakeThread::cmakeInitialized, this, + &CMakeSetupDialog::initialize, Qt::QueuedConnection); this->CMakeThread->start(); this->enterState(ReadyConfigure); @@ -211,82 +224,82 @@ void CMakeSetupDialog::initialize() { // now the cmake worker thread is running, lets make our connections to it QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(propertiesChanged(const QCMakePropertyList&)), - this->CacheValues->cacheModel(), - SLOT(setProperties(const QCMakePropertyList&))); + &QCMake::propertiesChanged, this->CacheValues->cacheModel(), + &QCMakeCacheModel::setProperties); - QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)), this, - SLOT(doConfigure())); + QObject::connect(this->ConfigureButton, &QPushButton::clicked, this, + &CMakeSetupDialog::doConfigure); - QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(configureDone(int)), this, SLOT(exitLoop(int))); - QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(generateDone(int)), this, SLOT(exitLoop(int))); + QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::configureDone, + this, &CMakeSetupDialog::exitLoop); + QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::generateDone, + this, &CMakeSetupDialog::exitLoop); - QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), this, - SLOT(doGenerate())); - QObject::connect(this->OpenProjectButton, SIGNAL(clicked(bool)), this, - SLOT(doOpenProject())); + QObject::connect(this->GenerateButton, &QPushButton::clicked, this, + &CMakeSetupDialog::doGenerate); + QObject::connect(this->OpenProjectButton, &QPushButton::clicked, this, + &CMakeSetupDialog::doOpenProject); - QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)), - this, SLOT(doSourceBrowse())); - QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)), - this, SLOT(doBinaryBrowse())); + QObject::connect(this->BrowseSourceDirectoryButton, &QPushButton::clicked, + this, &CMakeSetupDialog::doSourceBrowse); + QObject::connect(this->BrowseBinaryDirectoryButton, &QPushButton::clicked, + this, &CMakeSetupDialog::doBinaryBrowse); - QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)), - this, SLOT(onBinaryDirectoryChanged(QString))); - QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)), this, - SLOT(onSourceDirectoryChanged(QString))); + QObject::connect(this->BinaryDirectory, &QComboBox::editTextChanged, this, + &CMakeSetupDialog::onBinaryDirectoryChanged); + QObject::connect(this->SourceDirectory, &QLineEdit::textChanged, this, + &CMakeSetupDialog::onSourceDirectoryChanged); QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(sourceDirChanged(QString)), this, - SLOT(updateSourceDirectory(QString))); + &QCMake::sourceDirChanged, this, + &CMakeSetupDialog::updateSourceDirectory); QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(binaryDirChanged(QString)), this, - SLOT(updateBinaryDirectory(QString))); + &QCMake::binaryDirChanged, this, + &CMakeSetupDialog::updateBinaryDirectory); QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(progressChanged(QString, float)), this, - SLOT(showProgress(QString, float))); + &QCMake::progressChanged, this, + &CMakeSetupDialog::showProgress); - QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(errorMessage(QString)), this, SLOT(error(QString))); + QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::errorMessage, + this, &CMakeSetupDialog::error); - QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(outputMessage(QString)), this, - SLOT(message(QString))); + QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::outputMessage, + this, &CMakeSetupDialog::message); - QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(openPossible(bool)), this->OpenProjectButton, - SLOT(setEnabled(bool))); + QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::openPossible, + this->OpenProjectButton, &CMakeSetupDialog::setEnabled); - QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)), this, - SLOT(setGroupedView(bool))); - QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)), this, - SLOT(setAdvancedView(bool))); - QObject::connect(this->Search, SIGNAL(textChanged(QString)), this, - SLOT(setSearchFilter(QString))); + QObject::connect(this->groupedCheck, &QCheckBox::toggled, this, + &CMakeSetupDialog::setGroupedView); + QObject::connect(this->advancedCheck, &QCheckBox::toggled, this, + &CMakeSetupDialog::setAdvancedView); + QObject::connect(this->Search, &QLineEdit::textChanged, this, + &CMakeSetupDialog::setSearchFilter); QObject::connect(this->CMakeThread->cmakeInstance(), - SIGNAL(generatorChanged(QString)), this, - SLOT(updateGeneratorLabel(QString))); + &QCMake::generatorChanged, this, + &CMakeSetupDialog::updateGeneratorLabel); this->updateGeneratorLabel(QString()); QObject::connect(this->CacheValues->cacheModel(), - SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, - SLOT(setCacheModified())); + &QCMakeCacheModel::dataChanged, this, + &CMakeSetupDialog::setCacheModified); QObject::connect(this->CacheValues->selectionModel(), - SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(selectionChanged())); - QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)), this, - SLOT(removeSelectedCacheEntries())); - QObject::connect(this->AddEntry, SIGNAL(clicked(bool)), this, - SLOT(addCacheEntry())); - - QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)), + &QItemSelectionModel::selectionChanged, this, + &CMakeSetupDialog::selectionChanged); + QObject::connect(this->RemoveEntry, &QToolButton::clicked, this, + &CMakeSetupDialog::removeSelectedCacheEntries); + QObject::connect(this->AddEntry, &QToolButton::clicked, this, + &CMakeSetupDialog::addCacheEntry); + + QObject::connect(this->Environment, &QToolButton::clicked, this, + &CMakeSetupDialog::editEnvironment); + + QObject::connect(this->WarnUninitializedAction, &QAction::triggered, this->CMakeThread->cmakeInstance(), - SLOT(setWarnUninitializedMode(bool))); + &QCMake::setWarnUninitializedMode); if (!this->SourceDirectory->text().isEmpty() || !this->BinaryDirectory->lineEdit()->text().isEmpty()) { @@ -445,7 +458,8 @@ void CMakeSetupDialog::doInstallForCommandLine() lab->setTextInteractionFlags(Qt::TextSelectableByMouse); QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog); - QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); + QObject::connect(btns, &QDialogButtonBox::accepted, &dialog, + &QDialog::accept); l->addWidget(btns); dialog.exec(); } @@ -602,7 +616,8 @@ void CMakeSetupDialog::doHelp() lab->setWordWrap(true); QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog); - QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); + QObject::connect(btns, &QDialogButtonBox::accepted, &dialog, + &QDialog::accept); l->addWidget(lab); l->addWidget(btns); dialog.exec(); @@ -732,6 +747,7 @@ void CMakeSetupDialog::setEnabledState(bool enabled) this->ConfigureAction->setEnabled(enabled); this->AddEntry->setEnabled(enabled); this->RemoveEntry->setEnabled(false); // let selection re-enable it + this->Environment->setEnabled(enabled); } bool CMakeSetupDialog::setupFirstConfigure() @@ -891,7 +907,8 @@ void CMakeSetupDialog::doAbout() lab->setWordWrap(true); QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog); - QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); + QObject::connect(btns, &QDialogButtonBox::accepted, &dialog, + &QDialog::accept); l->addWidget(btns); dialog.exec(); } @@ -1064,6 +1081,17 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s) } } +void CMakeSetupDialog::editEnvironment() +{ + EnvironmentDialog dialog(this->CMakeThread->cmakeInstance()->environment(), + this); + if (dialog.exec() == QDialog::Accepted) { + QMetaObject::invokeMethod( + this->CMakeThread->cmakeInstance(), "setEnvironment", + Q_ARG(QProcessEnvironment, dialog.environment())); + } +} + void CMakeSetupDialog::addCacheEntry() { QDialog dialog(this); @@ -1074,8 +1102,10 @@ void CMakeSetupDialog::addCacheEntry() new AddCacheEntry(&dialog, this->AddVariableNames, this->AddVariableTypes); QDialogButtonBox* btns = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); - QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); - QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject())); + QObject::connect(btns, &QDialogButtonBox::accepted, &dialog, + &QDialog::accept); + QObject::connect(btns, &QDialogButtonBox::rejected, &dialog, + &QDialog::reject); l->addWidget(w); l->addStretch(); l->addWidget(btns); @@ -1153,7 +1183,8 @@ void CMakeSetupDialog::showUserChanges() l->addWidget(textedit); QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog); - QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept())); + QObject::connect(btns, &QDialogButtonBox::rejected, &dialog, + &QDialog::accept); l->addWidget(btns); QString command; @@ -1207,15 +1238,23 @@ void CMakeSetupDialog::doOutputContextMenu(QPoint pt) std::unique_ptr<QMenu> menu(this->Output->createStandardContextMenu()); menu->addSeparator(); - menu->addAction(tr("Find..."), this, SLOT(doOutputFindDialog()), - QKeySequence::Find); - menu->addAction(tr("Find Next"), this, SLOT(doOutputFindNext()), - QKeySequence::FindNext); - menu->addAction(tr("Find Previous"), this, SLOT(doOutputFindPrev()), - QKeySequence::FindPrevious); + auto* a = menu->addAction(tr("Find...")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputFindDialog); + a->setShortcut(QKeySequence::Find); + a = menu->addAction(tr("Find Next")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputFindNext); + a->setShortcut(QKeySequence::FindNext); + a = menu->addAction(tr("Find Previous")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputFindPrev); + a->setShortcut(QKeySequence::FindPrevious); menu->addSeparator(); - menu->addAction(tr("Goto Next Error"), this, SLOT(doOutputErrorNext()), - QKeySequence(Qt::Key_F8)); + a = menu->addAction(tr("Goto Next Error")); + QObject::connect(a, &QAction::triggered, this, + &CMakeSetupDialog::doOutputErrorNext); + a->setShortcut(QKeySequence(Qt::Key_F8)); menu->exec(this->Output->mapToGlobal(pt)); } diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index eba0b1e..d752ef2 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -65,6 +65,7 @@ protected slots: void setCacheModified(); void removeSelectedCacheEntries(); void selectionChanged(); + void editEnvironment(); void addCacheEntry(); void startSearch(); void setDebugOutput(bool); diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui index dc22a29..5feee91 100644 --- a/Source/QtDialog/CMakeSetupDialog.ui +++ b/Source/QtDialog/CMakeSetupDialog.ui @@ -11,7 +11,16 @@ </rect> </property> <layout class="QGridLayout"> - <property name="margin"> + <property name="leftMargin"> + <number>9</number> + </property> + <property name="topMargin"> + <number>9</number> + </property> + <property name="rightMargin"> + <number>9</number> + </property> + <property name="bottomMargin"> <number>9</number> </property> <property name="spacing"> @@ -19,7 +28,16 @@ </property> <item row="0" column="0"> <layout class="QGridLayout"> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <property name="spacing"> @@ -90,7 +108,16 @@ <property name="spacing"> <number>6</number> </property> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item> @@ -98,7 +125,16 @@ <property name="spacing"> <number>6</number> </property> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item> @@ -191,6 +227,13 @@ </property> </widget> </item> + <item> + <widget class="QPushButton" name="Environment"> + <property name="text"> + <string>E&nvironment...</string> + </property> + </widget> + </item> </layout> </item> <item> @@ -224,7 +267,16 @@ <property name="spacing"> <number>6</number> </property> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item> @@ -241,13 +293,13 @@ </property> </widget> </item> - <item> - <widget class="QPushButton" name="OpenProjectButton"> - <property name="text"> - <string>Open &Project</string> - </property> - </widget> - </item> + <item> + <widget class="QPushButton" name="OpenProjectButton"> + <property name="text"> + <string>Open &Project</string> + </property> + </widget> + </item> <item> <widget class="QLabel" name="Generator"> <property name="text"> diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx new file mode 100644 index 0000000..846456c --- /dev/null +++ b/Source/QtDialog/EnvironmentDialog.cxx @@ -0,0 +1,194 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "EnvironmentDialog.h" + +#include <QDialogButtonBox> +#include <QGridLayout> +#include <QItemSelectionModel> +#include <QLabel> +#include <QLineEdit> +#include <QMessageBox> +#include <QStandardItem> + +EnvironmentItemModel::EnvironmentItemModel( + const QProcessEnvironment& environment, QObject* parent) + : QStandardItemModel(parent) +{ + this->clear(); + for (auto const& key : environment.keys()) { + auto value = environment.value(key); + this->appendVariable(key, value); + } +} + +QProcessEnvironment EnvironmentItemModel::environment() const +{ + QProcessEnvironment env; + for (int i = 0; i < this->rowCount(); ++i) { + auto name = this->data(this->index(i, 0), Qt::DisplayRole).toString(); + auto value = this->data(this->index(i, 1), Qt::DisplayRole).toString(); + env.insert(name, value); + } + return env; +} + +void EnvironmentItemModel::clear() +{ + this->QStandardItemModel::clear(); + + QStringList labels; + labels << tr("Name") << tr("Value"); + this->setHorizontalHeaderLabels(labels); +} + +QModelIndex EnvironmentItemModel::buddy(const QModelIndex& index) const +{ + if (index.column() == 0) { + return this->index(index.row(), index.column() + 1, index.parent()); + } + return index; +} + +void EnvironmentItemModel::appendVariable(const QString& key, + const QString& value) +{ + this->insertVariable(this->rowCount(), key, value); +} + +void EnvironmentItemModel::insertVariable(int row, const QString& key, + const QString& value) +{ + for (int i = 0; i < this->rowCount(); ++i) { + if (this->data(this->index(i, 0), Qt::DisplayRole) == key) { + this->setData(this->index(i, 1), value, Qt::DisplayRole); + return; + } + } + + auto* keyItem = new QStandardItem(key); + auto* valueItem = new QStandardItem(value); + this->insertRow(row, { keyItem, valueItem }); +} + +EnvironmentSearchFilter::EnvironmentSearchFilter(QObject* parent) + : QSortFilterProxyModel(parent) +{ +} + +bool EnvironmentSearchFilter::filterAcceptsRow(int row, + const QModelIndex& parent) const +{ + auto* model = this->sourceModel(); + auto key = + model->data(model->index(row, 0, parent), Qt::DisplayRole).toString(); + return key.contains(this->filterRegExp()); +} + +EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment, + QWidget* parent) + : QDialog(parent) +{ + this->setupUi(this); + + this->RemoveEntry->setEnabled(false); + + this->m_model = new EnvironmentItemModel(environment, this); + this->m_filter = new EnvironmentSearchFilter(this); + this->m_filter->setSourceModel(this->m_model); + this->Environment->setModel(this->m_filter); + + this->Environment->setUniformRowHeights(true); + this->Environment->setRootIsDecorated(false); + this->Environment->setSelectionMode(QAbstractItemView::ExtendedSelection); + this->Environment->setSelectionBehavior(QAbstractItemView::SelectRows); + + QObject::connect(this->AddEntry, &QToolButton::clicked, this, + &EnvironmentDialog::addEntry); + QObject::connect(this->RemoveEntry, &QToolButton::clicked, this, + &EnvironmentDialog::removeSelectedEntries); + QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter, + &EnvironmentSearchFilter::setFilterFixedString); + QObject::connect(this->Environment->selectionModel(), + &QItemSelectionModel::selectionChanged, this, + &EnvironmentDialog::selectionChanged); +} + +QProcessEnvironment EnvironmentDialog::environment() const +{ + return this->m_model->environment(); +} + +void EnvironmentDialog::addEntry() +{ + // Build the dialog manually because it's simple enough + QDialog dialog(this); + dialog.setWindowTitle("Add Environment Variable"); + + auto* layout = new QGridLayout; + dialog.setLayout(layout); + + auto* nameLabel = new QLabel; + nameLabel->setText("Name:"); + layout->addWidget(nameLabel, 0, 0); + + auto* nameEdit = new QLineEdit; + nameEdit->setObjectName("name"); + layout->addWidget(nameEdit, 0, 1); + + auto* valueLabel = new QLabel; + valueLabel->setText("Value:"); + layout->addWidget(valueLabel, 1, 0); + + auto* valueEdit = new QLineEdit; + valueEdit->setObjectName("value"); + layout->addWidget(valueEdit, 1, 1); + + auto* buttons = new QDialogButtonBox; + buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QObject::connect( + buttons, &QDialogButtonBox::accepted, &dialog, + [this, &dialog, nameEdit]() { + auto text = nameEdit->text(); + if (text.isEmpty()) { + QMessageBox::critical(&dialog, "Error", "Name must be non-empty."); + return; + } + + auto* model = this->Environment->model(); + for (int i = 0; i < model->rowCount(); ++i) { + if (model->data(model->index(i, 0), Qt::DisplayRole) == text) { + QMessageBox::critical( + &dialog, "Error", + tr("Environment variable \"%1\" already exists.").arg(text)); + return; + } + } + + dialog.accept(); + }); + QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog, + &QDialog::reject); + layout->addWidget(buttons, 2, 0, 1, 2); + + if (dialog.exec() == QDialog::Accepted) { + this->m_model->insertVariable(0, nameEdit->text(), valueEdit->text()); + } +} + +void EnvironmentDialog::removeSelectedEntries() +{ + QModelIndexList idxs = this->Environment->selectionModel()->selectedRows(); + QList<QPersistentModelIndex> pidxs; + foreach (QModelIndex const& i, idxs) { + pidxs.append(i); + } + foreach (QPersistentModelIndex const& pi, pidxs) { + this->Environment->model()->removeRow(pi.row(), pi.parent()); + } +} + +void EnvironmentDialog::selectionChanged() +{ + auto selected = this->Environment->selectionModel()->selectedRows(); + this->RemoveEntry->setEnabled(!selected.isEmpty()); +} diff --git a/Source/QtDialog/EnvironmentDialog.h b/Source/QtDialog/EnvironmentDialog.h new file mode 100644 index 0000000..6aae798 --- /dev/null +++ b/Source/QtDialog/EnvironmentDialog.h @@ -0,0 +1,59 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <QDialog> +#include <QObject> +#include <QProcessEnvironment> +#include <QSortFilterProxyModel> +#include <QStandardItemModel> + +#include "ui_EnvironmentDialog.h" + +class EnvironmentItemModel : public QStandardItemModel +{ + Q_OBJECT +public: + EnvironmentItemModel(const QProcessEnvironment& environment, + QObject* parent = nullptr); + + QProcessEnvironment environment() const; + void clear(); + + QModelIndex buddy(const QModelIndex& index) const override; + +public slots: + void appendVariable(const QString& key, const QString& value); + void insertVariable(int row, const QString& key, const QString& value); +}; + +class EnvironmentSearchFilter : public QSortFilterProxyModel +{ + Q_OBJECT +public: + EnvironmentSearchFilter(QObject* parent = nullptr); + +protected: + bool filterAcceptsRow(int row, const QModelIndex& parent) const override; +}; + +class EnvironmentDialog + : public QDialog + , public Ui::EnvironmentDialog +{ + Q_OBJECT +public: + EnvironmentDialog(const QProcessEnvironment& environment, + QWidget* parent = nullptr); + + QProcessEnvironment environment() const; + +protected slots: + void addEntry(); + void removeSelectedEntries(); + void selectionChanged(); + +private: + EnvironmentItemModel* m_model; + EnvironmentSearchFilter* m_filter; +}; diff --git a/Source/QtDialog/EnvironmentDialog.ui b/Source/QtDialog/EnvironmentDialog.ui new file mode 100644 index 0000000..dea7624 --- /dev/null +++ b/Source/QtDialog/EnvironmentDialog.ui @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>EnvironmentDialog</class> + <widget class="QDialog" name="EnvironmentDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Environment Editor</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>S&earch:</string> + </property> + <property name="buddy"> + <cstring>Search</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="Search"/> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>12</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="AddEntry"> + <property name="text"> + <string>&Add Entry</string> + </property> + <property name="icon"> + <iconset resource="CMakeSetup.qrc"> + <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="RemoveEntry"> + <property name="text"> + <string>&Remove Entry</string> + </property> + <property name="icon"> + <iconset resource="CMakeSetup.qrc"> + <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QTreeView" name="Environment"/> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="CMakeSetup.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>EnvironmentDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>EnvironmentDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx index 3c24b9b..918f137 100644 --- a/Source/QtDialog/FirstConfigure.cxx +++ b/Source/QtDialog/FirstConfigure.cxx @@ -47,17 +47,18 @@ StartCompilerSetup::StartCompilerSetup(QString defaultGeneratorPlatform, this->CompilerSetupOptions[0]->setChecked(true); - QObject::connect(this->CompilerSetupOptions[0], SIGNAL(toggled(bool)), this, - SLOT(onSelectionChanged(bool))); - QObject::connect(this->CompilerSetupOptions[1], SIGNAL(toggled(bool)), this, - SLOT(onSelectionChanged(bool))); - QObject::connect(this->CompilerSetupOptions[2], SIGNAL(toggled(bool)), this, - SLOT(onSelectionChanged(bool))); - QObject::connect(this->CompilerSetupOptions[3], SIGNAL(toggled(bool)), this, - SLOT(onSelectionChanged(bool))); - QObject::connect(this->GeneratorOptions, - SIGNAL(currentIndexChanged(QString const&)), this, - SLOT(onGeneratorChanged(QString const&))); + QObject::connect(this->CompilerSetupOptions[0], &QRadioButton::toggled, this, + &StartCompilerSetup::onSelectionChanged); + QObject::connect(this->CompilerSetupOptions[1], &QRadioButton::toggled, this, + &StartCompilerSetup::onSelectionChanged); + QObject::connect(this->CompilerSetupOptions[2], &QRadioButton::toggled, this, + &StartCompilerSetup::onSelectionChanged); + QObject::connect(this->CompilerSetupOptions[3], &QRadioButton::toggled, this, + &StartCompilerSetup::onSelectionChanged); + QObject::connect( + this->GeneratorOptions, + static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), + this, &StartCompilerSetup::onGeneratorChanged); } QFrame* StartCompilerSetup::CreateToolsetWidgets() @@ -186,8 +187,10 @@ void StartCompilerSetup::onSelectionChanged(bool on) } } -void StartCompilerSetup::onGeneratorChanged(QString const& name) +void StartCompilerSetup::onGeneratorChanged(int index) { + QString name = this->GeneratorOptions->itemText(index); + // Display the generator platform for the generators supporting it if (GeneratorsSupportingPlatform.contains(name)) { @@ -458,9 +461,9 @@ FirstConfigure::FirstConfigure() this->mStartCompilerSetupPage = new StartCompilerSetup( env_generator_platform, env_generator_toolset, this); this->setPage(Start, this->mStartCompilerSetupPage); - QObject::connect(this->mStartCompilerSetupPage, SIGNAL(selectionChanged()), - this, SLOT(restart())); - + QObject::connect(this->mStartCompilerSetupPage, + &StartCompilerSetup::selectionChanged, this, + &FirstConfigure::restart); this->mNativeCompilerSetupPage = new NativeCompilerSetup(this); this->setPage(NativeSetup, this->mNativeCompilerSetupPage); diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h index 4c757da..ca5f52e 100644 --- a/Source/QtDialog/FirstConfigure.h +++ b/Source/QtDialog/FirstConfigure.h @@ -49,7 +49,7 @@ signals: protected slots: void onSelectionChanged(bool); - void onGeneratorChanged(QString const& name); + void onGeneratorChanged(int index); protected: QComboBox* GeneratorOptions; diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index 6090256..974c545 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -19,10 +19,12 @@ QCMake::QCMake(QObject* p) : QObject(p) + , Environment(QProcessEnvironment::systemEnvironment()) { this->WarnUninitializedMode = false; qRegisterMetaType<QCMakeProperty>(); qRegisterMetaType<QCMakePropertyList>(); + qRegisterMetaType<QProcessEnvironment>(); cmSystemTools::DisableRunCommandOutput(); cmSystemTools::SetRunCommandHideConsole(true); @@ -151,34 +153,46 @@ void QCMake::setToolset(const QString& toolset) } } +void QCMake::setEnvironment(const QProcessEnvironment& environment) +{ + this->Environment = environment; +} + void QCMake::configure() { + int err; + { + cmSystemTools::SaveRestoreEnvironment restoreEnv; + this->setUpEnvironment(); + #ifdef Q_OS_WIN - UINT lastErrorMode = SetErrorMode(0); + UINT lastErrorMode = SetErrorMode(0); #endif - this->CMakeInstance->SetHomeDirectory( - this->SourceDirectory.toLocal8Bit().data()); - this->CMakeInstance->SetHomeOutputDirectory( - this->BinaryDirectory.toLocal8Bit().data()); - this->CMakeInstance->SetGlobalGenerator( - this->CMakeInstance->CreateGlobalGenerator( - this->Generator.toLocal8Bit().data())); - this->CMakeInstance->SetGeneratorPlatform( - this->Platform.toLocal8Bit().data()); - this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data()); - this->CMakeInstance->LoadCache(); - this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode); - this->CMakeInstance->PreLoadCMakeFiles(); - - InterruptFlag = 0; - cmSystemTools::ResetErrorOccuredFlag(); - - int err = this->CMakeInstance->Configure(); + this->CMakeInstance->SetHomeDirectory( + this->SourceDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetHomeOutputDirectory( + this->BinaryDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetGlobalGenerator( + this->CMakeInstance->CreateGlobalGenerator( + this->Generator.toLocal8Bit().data())); + this->CMakeInstance->SetGeneratorPlatform( + this->Platform.toLocal8Bit().data()); + this->CMakeInstance->SetGeneratorToolset( + this->Toolset.toLocal8Bit().data()); + this->CMakeInstance->LoadCache(); + this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode); + this->CMakeInstance->PreLoadCMakeFiles(); + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + err = this->CMakeInstance->Configure(); #ifdef Q_OS_WIN - SetErrorMode(lastErrorMode); + SetErrorMode(lastErrorMode); #endif + } emit this->propertiesChanged(this->properties()); emit this->configureDone(err); @@ -186,18 +200,24 @@ void QCMake::configure() void QCMake::generate() { + int err; + { + cmSystemTools::SaveRestoreEnvironment restoreEnv; + this->setUpEnvironment(); + #ifdef Q_OS_WIN - UINT lastErrorMode = SetErrorMode(0); + UINT lastErrorMode = SetErrorMode(0); #endif - InterruptFlag = 0; - cmSystemTools::ResetErrorOccuredFlag(); + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); - int err = this->CMakeInstance->Generate(); + err = this->CMakeInstance->Generate(); #ifdef Q_OS_WIN - SetErrorMode(lastErrorMode); + SetErrorMode(lastErrorMode); #endif + } emit this->generateDone(err); checkOpenPossible(); @@ -373,6 +393,18 @@ void QCMake::stderrCallback(std::string const& msg) QCoreApplication::processEvents(); } +void QCMake::setUpEnvironment() const +{ + auto env = QProcessEnvironment::systemEnvironment(); + for (auto const& key : env.keys()) { + cmSystemTools::UnsetEnv(key.toLocal8Bit().data()); + } + + for (auto const& var : this->Environment.toStringList()) { + cmSystemTools::PutEnv(var.toLocal8Bit().data()); + } +} + QString QCMake::binaryDirectory() const { return this->BinaryDirectory; @@ -388,6 +420,11 @@ QString QCMake::generator() const return this->Generator; } +QProcessEnvironment QCMake::environment() const +{ + return this->Environment; +} + std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const { return AvailableGenerators; diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index e87660b..f569951 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -18,6 +18,7 @@ #include <QList> #include <QMetaType> #include <QObject> +#include <QProcessEnvironment> #include <QString> #include <QStringList> #include <QVariant> @@ -55,6 +56,7 @@ using QCMakePropertyList = QList<QCMakeProperty>; // allow QVariant to be a property or list of properties Q_DECLARE_METATYPE(QCMakeProperty) Q_DECLARE_METATYPE(QCMakePropertyList) +Q_DECLARE_METATYPE(QProcessEnvironment) /// Qt API for CMake library. /// Wrapper like class allows for easier integration with @@ -78,6 +80,8 @@ public slots: void setPlatform(const QString& platform); /// set the desired generator to use void setToolset(const QString& toolset); + /// set the configure and generate environment + void setEnvironment(const QProcessEnvironment& environment); /// do the configure step void configure(); /// generate the files @@ -125,6 +129,8 @@ public: QString sourceDirectory() const; /// get the current generator QString generator() const; + /// get the configure and generate environment + QProcessEnvironment environment() const; /// get the available generators std::vector<cmake::GeneratorInfo> const& availableGenerators() const; /// get whether to do debug output @@ -170,6 +176,7 @@ protected: void messageCallback(std::string const& msg, const char* title); void stdoutCallback(std::string const& msg); void stderrCallback(std::string const& msg); + void setUpEnvironment() const; bool WarnUninitializedMode; QString SourceDirectory; @@ -180,4 +187,5 @@ protected: std::vector<cmake::GeneratorInfo> AvailableGenerators; QString CMakeExecutable; QAtomicInt InterruptFlag; + QProcessEnvironment Environment; }; diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index 3bf4409..4f4b218 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -576,15 +576,15 @@ QWidget* QCMakeCacheModelDelegate::createEditor( if (type == QCMakeProperty::PATH) { QCMakePathEditor* editor = new QCMakePathEditor(p, var.data(Qt::DisplayRole).toString()); - QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this, - SLOT(setFileDialogFlag(bool))); + QObject::connect(editor, &QCMakePathEditor::fileDialogExists, this, + &QCMakeCacheModelDelegate::setFileDialogFlag); return editor; } if (type == QCMakeProperty::FILEPATH) { QCMakeFilePathEditor* editor = new QCMakeFilePathEditor(p, var.data(Qt::DisplayRole).toString()); - QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this, - SLOT(setFileDialogFlag(bool))); + QObject::connect(editor, &QCMakePathEditor::fileDialogExists, this, + &QCMakeCacheModelDelegate::setFileDialogFlag); return editor; } if (type == QCMakeProperty::STRING && diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx index d16ea58..1fc839f 100644 --- a/Source/QtDialog/QCMakeWidgets.cxx +++ b/Source/QtDialog/QCMakeWidgets.cxx @@ -17,8 +17,8 @@ QCMakeFileEditor::QCMakeFileEditor(QWidget* p, QString var) this->ToolButton = new QToolButton(this); this->ToolButton->setText("..."); this->ToolButton->setCursor(QCursor(Qt::ArrowCursor)); - QObject::connect(this->ToolButton, SIGNAL(clicked(bool)), this, - SLOT(chooseFile())); + QObject::connect(this->ToolButton, &QToolButton::clicked, this, + &QCMakeFileEditor::chooseFile); } QCMakeFilePathEditor::QCMakeFilePathEditor(QWidget* p, const QString& var) diff --git a/Source/QtDialog/WarningMessagesDialog.cxx b/Source/QtDialog/WarningMessagesDialog.cxx index f608a84..1fcf2b1 100644 --- a/Source/QtDialog/WarningMessagesDialog.cxx +++ b/Source/QtDialog/WarningMessagesDialog.cxx @@ -26,18 +26,22 @@ void WarningMessagesDialog::setInitialValues() void WarningMessagesDialog::setupSignals() { - QObject::connect(this->buttonBox, SIGNAL(accepted()), this, - SLOT(doAccept())); + QObject::connect(this->buttonBox, &QDialogButtonBox::accepted, this, + &WarningMessagesDialog::doAccept); - QObject::connect(this->suppressDeveloperWarnings, SIGNAL(stateChanged(int)), - this, SLOT(doSuppressDeveloperWarningsChanged(int))); - QObject::connect(this->suppressDeprecatedWarnings, SIGNAL(stateChanged(int)), - this, SLOT(doSuppressDeprecatedWarningsChanged(int))); + QObject::connect(this->suppressDeveloperWarnings, &QCheckBox::stateChanged, + this, + &WarningMessagesDialog::doSuppressDeveloperWarningsChanged); + QObject::connect( + this->suppressDeprecatedWarnings, &QCheckBox::stateChanged, this, + &WarningMessagesDialog::doSuppressDeprecatedWarningsChanged); - QObject::connect(this->developerWarningsAsErrors, SIGNAL(stateChanged(int)), - this, SLOT(doDeveloperWarningsAsErrorsChanged(int))); - QObject::connect(this->deprecatedWarningsAsErrors, SIGNAL(stateChanged(int)), - this, SLOT(doDeprecatedWarningsAsErrorsChanged(int))); + QObject::connect(this->developerWarningsAsErrors, &QCheckBox::stateChanged, + this, + &WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged); + QObject::connect( + this->deprecatedWarningsAsErrors, &QCheckBox::stateChanged, this, + &WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged); } void WarningMessagesDialog::doAccept() diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index eb9269f..9277c20 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -7,11 +7,14 @@ #include <cstddef> #include <memory> #include <string> +#include <utility> +#include <cm/optional> #include <cm/string_view> #include <cmext/string_view> #include "cmExecutionStatus.h" +#include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmRange.h" @@ -19,6 +22,14 @@ #include "cmSystemTools.h" namespace { + +bool FatalError(cmExecutionStatus& status, std::string const& error) +{ + status.SetError(error); + cmSystemTools::SetFatalErrorOccured(); + return false; +} + std::array<cm::static_string_view, 12> InvalidCommands{ { // clang-format off "function"_s, "endfunction"_s, @@ -28,110 +39,327 @@ std::array<cm::static_string_view, 12> InvalidCommands{ "foreach"_s, "endforeach"_s } // clang-format on }; -} -bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, - cmExecutionStatus& status) +std::array<cm::static_string_view, 1> InvalidDeferCommands{ + { + // clang-format off + "return"_s, + } // clang-format on +}; + +struct Defer +{ + std::string Id; + std::string IdVar; + cmMakefile* Directory = nullptr; +}; + +bool cmCMakeLanguageCommandCALL(std::vector<cmListFileArgument> const& args, + std::string const& callCommand, + size_t startArg, cm::optional<Defer> defer, + cmExecutionStatus& status) { - if (args.empty()) { - status.SetError("called with incorrect number of arguments"); - return false; + // ensure specified command is valid + // start/end flow control commands are not allowed + auto cmd = cmSystemTools::LowerCase(callCommand); + if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) != + InvalidCommands.cend()) { + return FatalError(status, + cmStrCat("invalid command specified: "_s, callCommand)); + } + if (defer && + std::find(InvalidDeferCommands.cbegin(), InvalidDeferCommands.cend(), + cmd) != InvalidDeferCommands.cend()) { + return FatalError(status, + cmStrCat("invalid command specified: "_s, callCommand)); } cmMakefile& makefile = status.GetMakefile(); - cmListFileContext context = makefile.GetExecutionContext(); + cmListFileContext context = makefile.GetBacktrace().Top(); - bool result = false; + cmListFileFunction func; + func.Name = callCommand; + func.Line = context.Line; - std::vector<std::string> dispatchExpandedArgs; - std::vector<cmListFileArgument> dispatchArgs; - dispatchArgs.emplace_back(args[0]); - makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs); + // The rest of the arguments are passed to the function call above + for (size_t i = startArg; i < args.size(); ++i) { + cmListFileArgument lfarg; + lfarg.Delim = args[i].Delim; + lfarg.Line = context.Line; + lfarg.Value = args[i].Value; + func.Arguments.emplace_back(lfarg); + } - if (dispatchExpandedArgs.empty()) { - status.SetError("called with incorrect number of arguments"); - return false; + if (defer) { + if (defer->Id.empty()) { + defer->Id = makefile.NewDeferId(); + } + if (!defer->IdVar.empty()) { + makefile.AddDefinition(defer->IdVar, defer->Id); + } + cmMakefile* deferMakefile = + defer->Directory ? defer->Directory : &makefile; + if (!deferMakefile->DeferCall(defer->Id, context.FilePath, func)) { + return FatalError( + status, + cmStrCat("DEFER CALL may not be scheduled in directory:\n "_s, + deferMakefile->GetCurrentBinaryDirectory(), + "\nat this time."_s)); + } + return true; } + return makefile.ExecuteCommand(func, status); +} - if (dispatchExpandedArgs[0] == "CALL") { - if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) || - dispatchExpandedArgs.size() > 2) { - status.SetError("called with incorrect number of arguments"); - return false; +bool cmCMakeLanguageCommandDEFER(Defer const& defer, + std::vector<std::string> const& args, + size_t arg, cmExecutionStatus& status) +{ + cmMakefile* deferMakefile = + defer.Directory ? defer.Directory : &status.GetMakefile(); + if (args[arg] == "CANCEL_CALL"_s) { + ++arg; // Consume CANCEL_CALL. + auto ids = cmMakeRange(args).advance(arg); + for (std::string const& id : ids) { + if (id[0] >= 'A' && id[0] <= 'Z') { + return FatalError( + status, cmStrCat("DEFER CANCEL_CALL unknown argument:\n "_s, id)); + } + if (!deferMakefile->DeferCancelCall(id)) { + return FatalError( + status, + cmStrCat("DEFER CANCEL_CALL may not update directory:\n "_s, + deferMakefile->GetCurrentBinaryDirectory(), + "\nat this time."_s)); + } + } + return true; + } + if (args[arg] == "GET_CALL_IDS"_s) { + ++arg; // Consume GET_CALL_IDS. + if (arg == args.size()) { + return FatalError(status, "DEFER GET_CALL_IDS missing output variable"); + } + std::string const& var = args[arg++]; + if (arg != args.size()) { + return FatalError(status, "DEFER GET_CALL_IDS given too many arguments"); + } + cm::optional<std::string> ids = deferMakefile->DeferGetCallIds(); + if (!ids) { + return FatalError( + status, + cmStrCat("DEFER GET_CALL_IDS may not access directory:\n "_s, + deferMakefile->GetCurrentBinaryDirectory(), + "\nat this time."_s)); + } + status.GetMakefile().AddDefinition(var, *ids); + return true; + } + if (args[arg] == "GET_CALL"_s) { + ++arg; // Consume GET_CALL. + if (arg == args.size()) { + return FatalError(status, "DEFER GET_CALL missing id"); + } + std::string const& id = args[arg++]; + if (arg == args.size()) { + return FatalError(status, "DEFER GET_CALL missing output variable"); + } + std::string const& var = args[arg++]; + if (arg != args.size()) { + return FatalError(status, "DEFER GET_CALL given too many arguments"); + } + if (id.empty()) { + return FatalError(status, "DEFER GET_CALL id may not be empty"); + } + if (id[0] >= 'A' && id[0] <= 'Z') { + return FatalError(status, + cmStrCat("DEFER GET_CALL unknown argument:\n "_s, id)); + } + cm::optional<std::string> call = deferMakefile->DeferGetCall(id); + if (!call) { + return FatalError( + status, + cmStrCat("DEFER GET_CALL may not access directory:\n "_s, + deferMakefile->GetCurrentBinaryDirectory(), + "\nat this time."_s)); } + status.GetMakefile().AddDefinition(var, *call); + return true; + } + return FatalError(status, + cmStrCat("DEFER operation unknown: "_s, args[arg])); +} - // First argument is the name of the function to call - std::string callCommand; - size_t startArg; - if (dispatchExpandedArgs.size() == 1) { - std::vector<std::string> functionExpandedArg; - std::vector<cmListFileArgument> functionArg; - functionArg.emplace_back(args[1]); - makefile.ExpandArguments(functionArg, functionExpandedArg); +bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status) +{ + cmMakefile& makefile = status.GetMakefile(); + cmListFileContext context = makefile.GetBacktrace().Top(); + std::vector<std::string> expandedArgs; + makefile.ExpandArguments(args, expandedArgs); - if (functionExpandedArg.size() != 1) { - status.SetError("called with incorrect number of arguments"); - return false; - } + if (expandedArgs.size() < 2) { + return FatalError(status, "called with incorrect number of arguments"); + } - callCommand = functionExpandedArg[0]; - startArg = 2; - } else { - callCommand = dispatchExpandedArgs[1]; - startArg = 1; + if (expandedArgs[1] != "CODE") { + auto code_iter = + std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE"); + if (code_iter == expandedArgs.end()) { + return FatalError(status, "called without CODE argument"); } + return FatalError( + status, + "called with unsupported arguments between EVAL and CODE arguments"); + } - // ensure specified command is valid - // start/end flow control commands are not allowed - auto cmd = cmSystemTools::LowerCase(callCommand); - if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) != - InvalidCommands.cend()) { - status.SetError(cmStrCat("invalid command specified: "_s, callCommand)); - return false; - } + const std::string code = + cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " "); + return makefile.ReadListFileAsString( + code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL")); +} +} - cmListFileFunction func; - func.Name = callCommand; - func.Line = context.Line; +bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status) +{ + std::vector<std::string> expArgs; + size_t rawArg = 0; + size_t expArg = 0; - // The rest of the arguments are passed to the function call above - for (size_t i = startArg; i < args.size(); ++i) { - cmListFileArgument lfarg; - lfarg.Delim = args[i].Delim; - lfarg.Line = context.Line; - lfarg.Value = args[i].Value; - func.Arguments.emplace_back(lfarg); + // Helper to consume and expand one raw argument at a time. + auto moreArgs = [&]() -> bool { + while (expArg >= expArgs.size()) { + if (rawArg >= args.size()) { + return false; + } + std::vector<cmListFileArgument> tmpArg; + tmpArg.emplace_back(args[rawArg++]); + status.GetMakefile().ExpandArguments(tmpArg, expArgs); } + return true; + }; + auto finishArgs = [&]() { + std::vector<cmListFileArgument> tmpArgs(args.begin() + rawArg, args.end()); + status.GetMakefile().ExpandArguments(tmpArgs, expArgs); + rawArg = args.size(); + }; - result = makefile.ExecuteCommand(func, status); - } else if (dispatchExpandedArgs[0] == "EVAL") { - std::vector<std::string> expandedArgs; - makefile.ExpandArguments(args, expandedArgs); + if (!moreArgs()) { + return FatalError(status, "called with incorrect number of arguments"); + } + + cm::optional<Defer> maybeDefer; + if (expArgs[expArg] == "DEFER"_s) { + ++expArg; // Consume "DEFER". - if (expandedArgs.size() < 2) { - status.SetError("called with incorrect number of arguments"); - return false; + if (!moreArgs()) { + return FatalError(status, "DEFER requires at least one argument"); } - if (expandedArgs[1] != "CODE") { - auto code_iter = - std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE"); - if (code_iter == expandedArgs.end()) { - status.SetError("called without CODE argument"); + Defer defer; + + // Process optional arguments. + while (moreArgs()) { + if (expArgs[expArg] == "CALL"_s) { + break; + } + if (expArgs[expArg] == "CANCEL_CALL"_s || + expArgs[expArg] == "GET_CALL_IDS"_s || + expArgs[expArg] == "GET_CALL"_s) { + if (!defer.Id.empty() || !defer.IdVar.empty()) { + return FatalError(status, + cmStrCat("DEFER "_s, expArgs[expArg], + " does not accept ID or ID_VAR."_s)); + } + finishArgs(); + return cmCMakeLanguageCommandDEFER(defer, expArgs, expArg, status); + } + if (expArgs[expArg] == "DIRECTORY"_s) { + ++expArg; // Consume "DIRECTORY". + if (defer.Directory) { + return FatalError(status, + "DEFER given multiple DIRECTORY arguments"); + } + if (!moreArgs()) { + return FatalError(status, "DEFER DIRECTORY missing value"); + } + std::string dir = expArgs[expArg++]; + if (dir.empty()) { + return FatalError(status, "DEFER DIRECTORY may not be empty"); + } + dir = cmSystemTools::CollapseFullPath( + dir, status.GetMakefile().GetCurrentSourceDirectory()); + defer.Directory = + status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir); + if (!defer.Directory) { + return FatalError(status, + cmStrCat("DEFER DIRECTORY:\n "_s, dir, + "\nis not known. "_s, + "It may not have been processed yet."_s)); + } + } else if (expArgs[expArg] == "ID"_s) { + ++expArg; // Consume "ID". + if (!defer.Id.empty()) { + return FatalError(status, "DEFER given multiple ID arguments"); + } + if (!moreArgs()) { + return FatalError(status, "DEFER ID missing value"); + } + defer.Id = expArgs[expArg++]; + if (defer.Id.empty()) { + return FatalError(status, "DEFER ID may not be empty"); + } + if (defer.Id[0] >= 'A' && defer.Id[0] <= 'Z') { + return FatalError(status, "DEFER ID may not start in A-Z."); + } + } else if (expArgs[expArg] == "ID_VAR"_s) { + ++expArg; // Consume "ID_VAR". + if (!defer.IdVar.empty()) { + return FatalError(status, "DEFER given multiple ID_VAR arguments"); + } + if (!moreArgs()) { + return FatalError(status, "DEFER ID_VAR missing variable name"); + } + defer.IdVar = expArgs[expArg++]; + if (defer.IdVar.empty()) { + return FatalError(status, "DEFER ID_VAR may not be empty"); + } } else { - status.SetError( - "called with unsupported arguments between EVAL and CODE arguments"); + return FatalError( + status, cmStrCat("DEFER unknown option:\n "_s, expArgs[expArg])); } - return false; } - const std::string code = - cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " "); - result = makefile.ReadListFileAsString( - code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL")); - } else { - status.SetError("called with unknown meta-operation"); + if (!(moreArgs() && expArgs[expArg] == "CALL"_s)) { + return FatalError(status, "DEFER must be followed by a CALL argument"); + } + + maybeDefer = std::move(defer); + } + + if (expArgs[expArg] == "CALL") { + ++expArg; // Consume "CALL". + + // CALL requires a command name. + if (!moreArgs()) { + return FatalError(status, "CALL missing command name"); + } + std::string const& callCommand = expArgs[expArg++]; + + // CALL accepts no further expanded arguments. + if (expArg != expArgs.size()) { + return FatalError(status, "CALL command's arguments must be literal"); + } + + // Run the CALL. + return cmCMakeLanguageCommandCALL(args, callCommand, rawArg, + std::move(maybeDefer), status); + } + + if (expArgs[expArg] == "EVAL") { + return cmCMakeLanguageCommandEVAL(args, status); } - return result; + return FatalError(status, "called with unknown meta-operation"); } diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index e3d014e..d4f5022 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -8,8 +8,11 @@ #include <utility> #include <cm/memory> +#include <cm/optional> +#include <cmext/string_view> #include "cmCommandArgumentLexer.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmProperty.h" #include "cmState.h" @@ -91,7 +94,14 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) return nullptr; } if (this->FileLine >= 0 && strcmp(var, "CMAKE_CURRENT_LIST_LINE") == 0) { - return this->AddString(std::to_string(this->FileLine)); + std::string line; + cmListFileContext const& top = this->Makefile->GetBacktrace().Top(); + if (top.DeferId) { + line = cmStrCat("DEFERRED:"_s, *top.DeferId); + } else { + line = std::to_string(this->FileLine); + } + return this->AddString(line); } cmProp value = this->Makefile->GetDefinition(var); if (!value) { diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 7ada8d8..14f10bd74 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -56,10 +56,8 @@ static std::string const keyVERSION_LESS = "VERSION_LESS"; static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"; cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, - cmListFileContext context, cmListFileBacktrace bt) : Makefile(makefile) - , ExecutionContext(std::move(context)) , Backtrace(std::move(bt)) , Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)) , Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054)) @@ -147,8 +145,7 @@ cmProp cmConditionEvaluator::GetDefinitionIfUnquoted( if (def && argument.WasQuoted() && this->Policy54Status == cmPolicies::WARN) { - if (!this->Makefile.HasCMP0054AlreadyBeenReported( - this->ExecutionContext)) { + if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) { std::ostringstream e; e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n"; e << "Quoted variables like \"" << argument.GetValue() @@ -191,8 +188,7 @@ bool cmConditionEvaluator::IsKeyword(std::string const& keyword, if (isKeyword && argument.WasQuoted() && this->Policy54Status == cmPolicies::WARN) { - if (!this->Makefile.HasCMP0054AlreadyBeenReported( - this->ExecutionContext)) { + if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) { std::ostringstream e; e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n"; e << "Quoted keywords like \"" << argument.GetValue() diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h index a4cedff..cf00ede 100644 --- a/Source/cmConditionEvaluator.h +++ b/Source/cmConditionEvaluator.h @@ -21,8 +21,7 @@ class cmConditionEvaluator public: using cmArgumentList = std::list<cmExpandedCommandArgument>; - cmConditionEvaluator(cmMakefile& makefile, cmListFileContext context, - cmListFileBacktrace bt); + cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt); // this is a shared function for both If and Else to determine if the // arguments were valid, and if so, was the response true. If there is @@ -79,7 +78,6 @@ private: MessageType& status); cmMakefile& Makefile; - cmListFileContext ExecutionContext; cmListFileBacktrace Backtrace; cmPolicies::PolicyStatus Policy12Status; cmPolicies::PolicyStatus Policy54Status; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 3e265a0..1c7e4b1 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -446,13 +446,13 @@ bool cmExtraSublimeTextGenerator::Open(const std::string& bindir, const std::string& projectName, bool dryRun) { - const char* sublExecutable = + cmProp sublExecutable = this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition( "CMAKE_SUBLIMETEXT_EXECUTABLE"); if (!sublExecutable) { return false; } - if (cmIsNOTFOUND(sublExecutable)) { + if (cmIsNOTFOUND(*sublExecutable)) { return false; } @@ -462,5 +462,5 @@ bool cmExtraSublimeTextGenerator::Open(const std::string& bindir, } return cmSystemTools::RunSingleCommand( - { sublExecutable, "--project", filename }); + { *sublExecutable, "--project", filename }); } diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 51137b3..c988b59 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -426,7 +426,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) // fill various parts of version specification if (!this->VersionComplete.empty()) { if (!versionRegex.find(this->VersionComplete)) { - this->SetError("called with invalid version specification"); + this->SetError("called with invalid version specification."); return false; } @@ -440,6 +440,19 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) } } + if (!this->VersionRange.empty()) { + // version range must not be empty + if ((this->VersionRangeMax == VERSION_ENDPOINT_INCLUDED && + cmSystemTools::VersionCompareGreater(this->Version, + this->VersionMax)) || + (this->VersionRangeMax == VERSION_ENDPOINT_EXCLUDED && + cmSystemTools::VersionCompareGreaterEq(this->Version, + this->VersionMax))) { + this->SetError("specified version range is empty."); + return false; + } + } + if (this->VersionExact && !this->VersionRange.empty()) { this->SetError("EXACT cannot be specified with a version range."); return false; @@ -1971,6 +1984,9 @@ cmFileListGeneratorBase* cmFileListGeneratorBase::SetNext( bool cmFileListGeneratorBase::Consider(std::string const& fullPath, cmFileList& listing) { + if (!cmSystemTools::FileIsDirectory(fullPath)) { + return false; + } if (this->Next) { return this->Next->Search(fullPath + "/", listing); } @@ -2225,10 +2241,8 @@ private: // Look for directories among the matches. for (std::string const& f : files) { - if (cmSystemTools::FileIsDirectory(f)) { - if (this->Consider(f, lister)) { - return true; - } + if (this->Consider(f, lister)) { + return true; } } return false; diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index b6f58bd..46bd057 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -147,8 +147,7 @@ bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, cmMakefile& mf) const { std::vector<std::string> expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments, - this->GetStartingContext().FilePath.c_str()); + mf.ExpandArguments(lff.Arguments, expandedArguments); return expandedArguments.empty() || expandedArguments.front() == this->Args.front(); } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 8589ab1..859fa6a 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -516,9 +516,8 @@ std::string cmGeneratorTarget::GetFilePrefix( const std::string& config, cmStateEnums::ArtifactType artifact) const { if (this->IsImported()) { - const char* prefix = this->GetFilePrefixInternal(config, artifact); - - return prefix ? prefix : std::string(); + cmProp prefix = this->GetFilePrefixInternal(config, artifact); + return prefix ? *prefix : std::string(); } std::string prefix; @@ -531,9 +530,8 @@ std::string cmGeneratorTarget::GetFileSuffix( const std::string& config, cmStateEnums::ArtifactType artifact) const { if (this->IsImported()) { - const char* suffix = this->GetFileSuffixInternal(config, artifact); - - return suffix ? suffix : std::string(); + cmProp suffix = this->GetFileSuffixInternal(config, artifact); + return suffix ? *suffix : std::string(); } std::string prefix; @@ -587,7 +585,7 @@ std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( return postfix ? *postfix : std::string(); } -const char* cmGeneratorTarget::GetFilePrefixInternal( +cmProp cmGeneratorTarget::GetFilePrefixInternal( std::string const& config, cmStateEnums::ArtifactType artifact, const std::string& language) const { @@ -623,8 +621,8 @@ const char* cmGeneratorTarget::GetFilePrefixInternal( if (!targetPrefix) { const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact); - if (!language.empty() && prefixVar && *prefixVar) { - std::string langPrefix = prefixVar + std::string("_") + language; + if (!language.empty() && cmNonempty(prefixVar)) { + std::string langPrefix = cmStrCat(prefixVar, "_", language); targetPrefix = this->Makefile->GetDefinition(langPrefix); } @@ -635,9 +633,10 @@ const char* cmGeneratorTarget::GetFilePrefixInternal( } } - return targetPrefix ? targetPrefix->c_str() : nullptr; + return targetPrefix; } -const char* cmGeneratorTarget::GetFileSuffixInternal( + +cmProp cmGeneratorTarget::GetFileSuffixInternal( std::string const& config, cmStateEnums::ArtifactType artifact, const std::string& language) const { @@ -673,8 +672,8 @@ const char* cmGeneratorTarget::GetFileSuffixInternal( if (!targetSuffix) { const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact); - if (!language.empty() && suffixVar && *suffixVar) { - std::string langSuffix = suffixVar + std::string("_") + language; + if (!language.empty() && cmNonempty(suffixVar)) { + std::string langSuffix = cmStrCat(suffixVar, "_", language); targetSuffix = this->Makefile->GetDefinition(langSuffix); } @@ -685,7 +684,7 @@ const char* cmGeneratorTarget::GetFileSuffixInternal( } } - return targetSuffix ? targetSuffix->c_str() : nullptr; + return targetSuffix; } void cmGeneratorTarget::ClearSourcesCache() @@ -1195,8 +1194,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( config_upper = cmSystemTools::UpperCase(config); } - using IncludeCacheType = std::map<std::string, std::vector<std::string>>; - auto iter = this->SystemIncludesCache.find(config_upper); + std::string key = cmStrCat(config_upper, "/", language); + auto iter = this->SystemIncludesCache.find(key); if (iter == this->SystemIncludesCache.end()) { cmGeneratorExpressionDAGChecker dagChecker( @@ -1224,8 +1223,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( std::sort(result.begin(), result.end()); result.erase(std::unique(result.begin(), result.end()), result.end()); - IncludeCacheType::value_type entry(config_upper, result); - iter = this->SystemIncludesCache.insert(entry).first; + iter = this->SystemIncludesCache.emplace(key, result).first; } return std::binary_search(iter->second.begin(), iter->second.end(), dir); @@ -1248,8 +1246,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( bool& maybeInterfaceProp = i->second; // If this target itself has a non-empty property value, we are done. - cmProp p = this->GetProperty(prop); - maybeInterfaceProp = cmNonempty(p); + maybeInterfaceProp = cmNonempty(this->GetProperty(prop)); // Otherwise, recurse to interface dependencies. if (!maybeInterfaceProp) { @@ -4943,8 +4940,8 @@ void cmGeneratorTarget::GetFullNameInternal( // retrieve prefix and suffix std::string ll = this->GetLinkerLanguage(config); - const char* targetPrefix = this->GetFilePrefixInternal(config, artifact, ll); - const char* targetSuffix = this->GetFileSuffixInternal(config, artifact, ll); + cmProp targetPrefix = this->GetFilePrefixInternal(config, artifact, ll); + cmProp targetSuffix = this->GetFileSuffixInternal(config, artifact, ll); // The implib option is only allowed for shared libraries, module // libraries, and executables. @@ -4962,18 +4959,18 @@ void cmGeneratorTarget::GetFullNameInternal( if (this->IsFrameworkOnApple()) { fw_prefix = cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/'); - targetPrefix = fw_prefix.c_str(); + targetPrefix = &fw_prefix; targetSuffix = nullptr; } if (this->IsCFBundleOnApple()) { fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/'); - targetPrefix = fw_prefix.c_str(); + targetPrefix = &fw_prefix; targetSuffix = nullptr; } // Begin the final name with the prefix. - outPrefix = targetPrefix ? targetPrefix : ""; + outPrefix = targetPrefix ? *targetPrefix : ""; // Append the target name or property-specified name. outBase += this->GetOutputName(config, artifact); @@ -4984,7 +4981,7 @@ void cmGeneratorTarget::GetFullNameInternal( // EXECUTABLE_SUFFIX attribute. if (this->IsFrameworkOnApple() && GetGlobalGenerator()->GetName() == "Xcode") { - targetSuffix = configPostfix.c_str(); + targetSuffix = &configPostfix; } else { outBase += configPostfix; } @@ -5000,7 +4997,7 @@ void cmGeneratorTarget::GetFullNameInternal( } // Append the suffix. - outSuffix = targetSuffix ? targetSuffix : ""; + outSuffix = targetSuffix ? *targetSuffix : ""; } std::string cmGeneratorTarget::GetLinkerLanguage( diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 8e0def7..e5fa892 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -849,6 +849,8 @@ private: mutable std::set<std::string> VisitedConfigsForObjects; mutable std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; + + // "config/language" is the key mutable std::map<std::string, std::vector<std::string>> SystemIncludesCache; mutable std::string ExportMacro; @@ -861,12 +863,12 @@ private: bool NeedImportLibraryName(std::string const& config) const; - const char* GetFilePrefixInternal(std::string const& config, - cmStateEnums::ArtifactType artifact, - const std::string& language = "") const; - const char* GetFileSuffixInternal(std::string const& config, - cmStateEnums::ArtifactType artifact, - const std::string& language = "") const; + cmProp GetFilePrefixInternal(std::string const& config, + cmStateEnums::ArtifactType artifact, + const std::string& language = "") const; + cmProp GetFileSuffixInternal(std::string const& config, + cmStateEnums::ArtifactType artifact, + const std::string& language = "") const; std::string GetFullNameInternal(const std::string& config, cmStateEnums::ArtifactType artifact) const; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 86b01bc..1197db6 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -15,6 +15,7 @@ #include <cm/memory> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -197,12 +198,12 @@ std::string cmGlobalGenerator::SelectMakeProgram( { std::string makeProgram = inMakeProgram; if (cmIsOff(makeProgram)) { - const char* makeProgramCSTR = + cmProp makeProgramCSTR = this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM"); if (cmIsOff(makeProgramCSTR)) { makeProgram = makeDefault; } else { - makeProgram = makeProgramCSTR; + makeProgram = *makeProgramCSTR; } if (cmIsOff(makeProgram) && !makeProgram.empty()) { makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND"; @@ -1211,6 +1212,7 @@ void cmGlobalGenerator::Configure() { this->FirstTimeProgress = 0.0f; this->ClearGeneratorMembers(); + this->NextDeferId = 0; cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot(); @@ -2153,10 +2155,11 @@ void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen, { this->SetConfiguredFilesPath(gen); this->TryCompileOuterMakefile = mf; - const char* make = + cmProp make = gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM"); - this->GetCMakeInstance()->AddCacheEntry( - "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH); + this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", cmToCStr(make), + "make program", + cmStateEnums::FILEPATH); // copy the enabled languages this->GetCMakeInstance()->GetState()->SetEnabledLanguages( gen->GetCMakeInstance()->GetState()->GetEnabledLanguages()); @@ -3255,6 +3258,11 @@ const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir) return i->second; } +std::string cmGlobalGenerator::NewDeferId() +{ + return cmStrCat("__"_s, std::to_string(this->NextDeferId++)); +} + void cmGlobalGenerator::ProcessEvaluationFiles() { std::vector<std::string> generatedFiles; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 478028e..b532a43 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -508,6 +508,8 @@ public: std::string const& GetRealPath(std::string const& dir); + std::string NewDeferId(); + protected: // for a project collect all its targets by following depend // information, and also collect all the targets @@ -633,6 +635,9 @@ private: std::map<std::string, int> LanguageToLinkerPreference; std::map<std::string, std::string> LanguageToOriginalSharedLibFlags; + // Deferral id generation. + size_t NextDeferId = 0; + // Record hashes for rules and outputs. struct RuleHash { diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index cbaf0ab..c08c9cf 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -3,7 +3,6 @@ #include "cmGlobalGhsMultiGenerator.h" #include <algorithm> -#include <cstring> #include <map> #include <ostream> #include <utility> @@ -335,23 +334,23 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout, fout << "# Top Level Project File\n"; // Specify BSP option if supplied by user - const char* bspName = + cmProp bspName = this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME"); if (!cmIsOff(bspName)) { - fout << " -bsp " << bspName << '\n'; + fout << " -bsp " << *bspName << '\n'; } // Specify OS DIR if supplied by user // -- not all platforms require this entry in the project file if (!cmIsOff(this->OsDir)) { - const char* osDirOption = + cmProp osDirOption = this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION"); std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/'); fout << " "; if (cmIsOff(osDirOption)) { fout << ""; } else { - fout << osDirOption; + fout << *osDirOption; } fout << "\"" << this->OsDir << "\"\n"; } @@ -565,9 +564,9 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand( { GeneratedMakeCommand makeCommand = {}; std::string gbuild; - if (const char* gbuildCached = + if (cmProp gbuildCached = this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) { - gbuild = gbuildCached; + gbuild = *gbuildCached; } makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild)); @@ -618,11 +617,10 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout, cmLocalGenerator* root) { fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n'; - char const* ghsGpjMacros = + cmProp ghsGpjMacros = this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS"); - if (nullptr != ghsGpjMacros) { - std::vector<std::string> expandedList = - cmExpandedList(std::string(ghsGpjMacros)); + if (ghsGpjMacros) { + std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros); for (std::string const& arg : expandedList) { fout << "macro " << arg << '\n'; } @@ -634,17 +632,17 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( { /* set primary target */ std::string tgt; - const char* t = + cmProp t = this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET"); if (cmNonempty(t)) { - tgt = t; + tgt = *t; this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET"); } else { - const char* a = + cmProp a = this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM"); - const char* p = + cmProp p = this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM"); - tgt = cmStrCat((a ? a : ""), '_', (p ? p : ""), ".tgt"); + tgt = cmStrCat((a ? *a : ""), '_', (p ? *p : ""), ".tgt"); } /* clang-format off */ @@ -655,11 +653,11 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( << "/CMakeFiles/custom_target.bod" << '\n'; /* clang-format on */ - char const* const customization = + cmProp const customization = this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION"); - if (nullptr != customization && strlen(customization) > 0) { + if (cmNonempty(customization)) { fout << "customization=" - << cmGlobalGhsMultiGenerator::TrimQuotes(customization) << '\n'; + << cmGlobalGhsMultiGenerator::TrimQuotes(*customization) << '\n'; this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION"); } } diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 37a77fa..2c934e1 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -104,8 +104,8 @@ std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const cmStateEnums::INTERNAL); } } - const char* edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND"); - return edit_cmd ? edit_cmd : ""; + cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND"); + return edit_cmd ? *edit_cmd : std::string(); } void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory( diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 84cfaeb..6267205 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -625,9 +625,9 @@ std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend( std::string cmGlobalVisualStudio7Generator::GetGUID(std::string const& name) { std::string const& guidStoreName = name + "_GUID_CMAKE"; - if (const char* storedGUID = + if (cmProp storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName)) { - return std::string(storedGUID); + return *storedGUID; } // Compute a GUID that is deterministic but unique to the build tree. std::string input = diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index b57bdbc..b78f0a0 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -3140,11 +3140,10 @@ std::string cmGlobalXCodeGenerator::GetOrCreateId(const std::string& name, const std::string& id) { std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE"); - const char* storedGUID = - this->CMakeInstance->GetCacheDefinition(guidStoreName); + cmProp storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName); if (storedGUID) { - return storedGUID; + return *storedGUID; } this->CMakeInstance->AddCacheEntry(guidStoreName, id.c_str(), diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 5808f90..fc257b1 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -75,10 +75,12 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, if (scopeDepth == 0 && func.Name.Lower == "else") { if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); + cmListFileBacktrace elseBT = mf.GetBacktrace().Push( + cmListFileContext{ func.Name.Original, + this->GetStartingContext().FilePath, func.Line }); mf.GetCMakeInstance()->IssueMessage( MessageType::FATAL_ERROR, - "A duplicate ELSE command was found inside an IF block.", bt); + "A duplicate ELSE command was found inside an IF block.", elseBT); cmSystemTools::SetFatalErrorOccured(); return true; } @@ -93,11 +95,12 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, mf.PrintCommandTrace(func); } } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { + cmListFileBacktrace elseifBT = mf.GetBacktrace().Push(cmListFileContext{ + func.Name.Original, this->GetStartingContext().FilePath, func.Line }); if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); mf.GetCMakeInstance()->IssueMessage( MessageType::FATAL_ERROR, - "An ELSEIF command was found after an ELSE command.", bt); + "An ELSEIF command was found after an ELSE command.", elseifBT); cmSystemTools::SetFatalErrorOccured(); return true; } @@ -117,12 +120,7 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, MessageType messType; - cmListFileContext conditionContext = - cmListFileContext::FromCommandContext( - func, this->GetStartingContext().FilePath); - - cmConditionEvaluator conditionEvaluator(mf, conditionContext, - mf.GetBacktrace(func)); + cmConditionEvaluator conditionEvaluator(mf, elseifBT); bool isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, messType); @@ -130,8 +128,7 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, if (!errorString.empty()) { std::string err = cmStrCat(cmIfCommandError(expandedArguments), errorString); - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage(messType, err, bt); + mf.GetCMakeInstance()->IssueMessage(messType, err, elseifBT); if (messType == MessageType::FATAL_ERROR) { cmSystemTools::SetFatalErrorOccured(); return true; @@ -178,8 +175,7 @@ bool cmIfCommand(std::vector<cmListFileArgument> const& args, MessageType status; - cmConditionEvaluator conditionEvaluator( - makefile, makefile.GetExecutionContext(), makefile.GetBacktrace()); + cmConditionEvaluator conditionEvaluator(makefile, makefile.GetBacktrace()); bool isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, status); diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 7ebb02f..d678b56 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -446,7 +446,8 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const cmStateSnapshot bottom = this->GetBottom(); for (Entry const* cur = this->TopEntry->Parent.get(); !cur->IsBottom(); cur = cur->Parent.get()) { - if (cur->Context.Name.empty()) { + if (cur->Context.Name.empty() && + cur->Context.Line != cmListFileContext::DeferPlaceholderLine) { // Skip this whole-file scope. When we get here we already will // have printed a more-specific context within the file. continue; @@ -483,11 +484,13 @@ bool cmListFileBacktrace::Empty() const std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) { os << lfc.FilePath; - if (lfc.Line) { + if (lfc.Line > 0) { os << ":" << lfc.Line; if (!lfc.Name.empty()) { os << " (" << lfc.Name << ")"; } + } else if (lfc.Line == cmListFileContext::DeferPlaceholderLine) { + os << ":DEFERRED"; } return os; } diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index c9556ab..5617536 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -11,6 +11,8 @@ #include <utility> #include <vector> +#include <cm/optional> + #include "cmStateSnapshot.h" /** \class cmListFileCache @@ -72,14 +74,26 @@ public: std::string Name; std::string FilePath; long Line = 0; + static long const DeferPlaceholderLine = -1; + cm::optional<std::string> DeferId; + + cmListFileContext() = default; + cmListFileContext(std::string name, std::string filePath, long line) + : Name(std::move(name)) + , FilePath(std::move(filePath)) + , Line(line) + { + } - static cmListFileContext FromCommandContext(cmCommandContext const& lfcc, - std::string const& fileName) + static cmListFileContext FromCommandContext( + cmCommandContext const& lfcc, std::string const& fileName, + cm::optional<std::string> deferId = {}) { cmListFileContext lfc; lfc.FilePath = fileName; lfc.Line = lfcc.Line; lfc.Name = lfcc.Name.Original; + lfc.DeferId = std::move(deferId); return lfc; } }; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 504268e..fdf8307 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1081,11 +1081,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( if (stackVal) { fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"\n"; } - temp = cmStrCat( - target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact), - '/', targetNames.ImportLibrary); - fout << "\t\t\t\tImportLibrary=\"" - << this->ConvertToXMLOutputPathSingle(temp) << "\""; + if (!targetNames.ImportLibrary.empty()) { + temp = cmStrCat(target->GetDirectory( + configName, cmStateEnums::ImportLibraryArtifact), + '/', targetNames.ImportLibrary); + fout << "\t\t\t\tImportLibrary=\"" + << this->ConvertToXMLOutputPathSingle(temp) << "\""; + } if (this->FortranProject) { fout << "\n\t\t\t\tLinkDLL=\"true\""; } diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index c88b343..91a600e 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -157,8 +157,7 @@ bool cmMacroFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, cmMakefile& mf) const { std::vector<std::string> expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments, - this->GetStartingContext().FilePath.c_str()); + mf.ExpandArguments(lff.Arguments, expandedArguments); return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index d77c4af..ac3a193 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -16,6 +16,7 @@ #include <cm/iterator> #include <cm/memory> #include <cm/optional> +#include <cm/type_traits> // IWYU pragma: keep #include <cm/vector> #include <cmext/algorithm> #include <cmext/string_view> @@ -274,31 +275,14 @@ cmListFileBacktrace cmMakefile::GetBacktrace() const return this->Backtrace; } -cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const -{ - cmListFileContext lfc; - lfc.Name = cc.Name.Original; - lfc.Line = cc.Line; - lfc.FilePath = this->StateSnapshot.GetExecutionListFile(); - return this->Backtrace.Push(lfc); -} - -cmListFileContext cmMakefile::GetExecutionContext() const -{ - cmListFileContext const& cur = this->Backtrace.Top(); - cmListFileContext lfc; - lfc.Name = cur.Name; - lfc.Line = cur.Line; - lfc.FilePath = this->StateSnapshot.GetExecutionListFile(); - return lfc; -} - -void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const +void cmMakefile::PrintCommandTrace( + cmListFileFunction const& lff, + cm::optional<std::string> const& deferId) const { // Check if current file in the list of requested to trace... std::vector<std::string> const& trace_only_this_files = this->GetCMakeInstance()->GetTraceSources(); - std::string const& full_path = this->GetExecutionFilePath(); + std::string const& full_path = this->GetBacktrace().Top().FilePath; std::string const& only_filename = cmSystemTools::GetFilenameName(full_path); bool trace = trace_only_this_files.empty(); if (!trace) { @@ -341,6 +325,9 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const builder["indentation"] = ""; val["file"] = full_path; val["line"] = static_cast<Json::Value::Int64>(lff.Line); + if (deferId) { + val["defer"] = *deferId; + } val["cmd"] = lff.Name.Original; val["args"] = Json::Value(Json::arrayValue); for (std::string const& arg : args) { @@ -354,8 +341,11 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const break; } case cmake::TraceFormat::TRACE_HUMAN: - msg << full_path << "(" << lff.Line << "): "; - msg << lff.Name.Original << "("; + msg << full_path << "(" << lff.Line << "):"; + if (deferId) { + msg << "DEFERRED:" << *deferId << ":"; + } + msg << " " << lff.Name.Original << "("; for (std::string const& arg : args) { msg << arg << " "; @@ -380,11 +370,12 @@ class cmMakefileCall { public: cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff, - cmExecutionStatus& status) + cm::optional<std::string> deferId, cmExecutionStatus& status) : Makefile(mf) { cmListFileContext const& lfc = cmListFileContext::FromCommandContext( - lff, this->Makefile->StateSnapshot.GetExecutionListFile()); + lff, this->Makefile->StateSnapshot.GetExecutionListFile(), + std::move(deferId)); this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc); ++this->Makefile->RecursionDepth; this->Makefile->ExecutionStatusStack.push_back(&status); @@ -421,7 +412,8 @@ void cmMakefile::OnExecuteCommand(std::function<void()> callback) } bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, - cmExecutionStatus& status) + cmExecutionStatus& status, + cm::optional<std::string> deferId) { bool result = true; @@ -436,7 +428,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, } // Place this call on the call stack. - cmMakefileCall stack_manager(this, lff, status); + cmMakefileCall stack_manager(this, lff, std::move(deferId), status); static_cast<void>(stack_manager); // Check for maximum recursion depth. @@ -464,7 +456,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, if (!cmSystemTools::GetFatalErrorOccured()) { // if trace is enabled, print out invoke information if (this->GetCMakeInstance()->GetTrace()) { - this->PrintCommandTrace(lff); + this->PrintCommandTrace(lff, this->Backtrace.Top().DeferId); } // Try invoking the command. bool invokeSucceeded = command(lff.Arguments, status); @@ -597,7 +589,7 @@ void cmMakefile::IncludeScope::EnforceCMP0011() std::ostringstream w; w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0011) << "\n" << "The included script\n " - << this->Makefile->GetExecutionFilePath() << "\n" + << this->Makefile->GetBacktrace().Top().FilePath << "\n" << "affects policy settings. " << "CMake is implying the NO_POLICY_SCOPE option for compatibility, " << "so the effects are applied to the including context."; @@ -610,7 +602,7 @@ void cmMakefile::IncludeScope::EnforceCMP0011() /* clang-format off */ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n" << "The included script\n " - << this->Makefile->GetExecutionFilePath() << "\n" + << this->Makefile->GetBacktrace().Top().FilePath << "\n" << "affects policy settings, so it requires this policy to be set."; /* clang-format on */ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); @@ -641,7 +633,7 @@ bool cmMakefile::ReadDependentFile(const std::string& filename, return false; } - this->ReadListFile(listFile, filenametoread); + this->RunListFile(listFile, filenametoread); if (cmSystemTools::GetFatalErrorOccured()) { incScope.Quiet(); } @@ -682,6 +674,53 @@ private: bool ReportError; }; +class cmMakefile::DeferScope +{ +public: + DeferScope(cmMakefile* mf, std::string const& deferredInFile) + : Makefile(mf) + { + cmListFileContext lfc; + lfc.Line = cmListFileContext::DeferPlaceholderLine; + lfc.FilePath = deferredInFile; + this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc); + this->Makefile->DeferRunning = true; + } + + ~DeferScope() + { + this->Makefile->DeferRunning = false; + this->Makefile->Backtrace = this->Makefile->Backtrace.Pop(); + } + + DeferScope(const DeferScope&) = delete; + DeferScope& operator=(const DeferScope&) = delete; + +private: + cmMakefile* Makefile; +}; + +class cmMakefile::DeferCallScope +{ +public: + DeferCallScope(cmMakefile* mf, std::string const& deferredFromFile) + : Makefile(mf) + { + this->Makefile->StateSnapshot = + this->Makefile->GetState()->CreateDeferCallSnapshot( + this->Makefile->StateSnapshot, deferredFromFile); + assert(this->Makefile->StateSnapshot.IsValid()); + } + + ~DeferCallScope() { this->Makefile->PopSnapshot(); } + + DeferCallScope(const DeferCallScope&) = delete; + DeferCallScope& operator=(const DeferCallScope&) = delete; + +private: + cmMakefile* Makefile; +}; + bool cmMakefile::ReadListFile(const std::string& filename) { std::string filenametoread = cmSystemTools::CollapseFullPath( @@ -695,7 +734,7 @@ bool cmMakefile::ReadListFile(const std::string& filename) return false; } - this->ReadListFile(listFile, filenametoread); + this->RunListFile(listFile, filenametoread); if (cmSystemTools::GetFatalErrorOccured()) { scope.Quiet(); } @@ -716,15 +755,16 @@ bool cmMakefile::ReadListFileAsString(const std::string& content, return false; } - this->ReadListFile(listFile, filenametoread); + this->RunListFile(listFile, filenametoread); if (cmSystemTools::GetFatalErrorOccured()) { scope.Quiet(); } return true; } -void cmMakefile::ReadListFile(cmListFile const& listFile, - std::string const& filenametoread) +void cmMakefile::RunListFile(cmListFile const& listFile, + std::string const& filenametoread, + DeferCommands* defer) { // add this list file to the list of dependencies this->ListFiles.push_back(filenametoread); @@ -755,6 +795,33 @@ void cmMakefile::ReadListFile(cmListFile const& listFile, } } + // Run any deferred commands. + if (defer) { + // Add a backtrace level indicating calls are deferred. + DeferScope scope(this, filenametoread); + + // Iterate by index in case one deferred call schedules another. + // NOLINTNEXTLINE(modernize-loop-convert) + for (size_t i = 0; i < defer->Commands.size(); ++i) { + DeferCommand& d = defer->Commands[i]; + if (d.Id.empty()) { + // Cancelled. + continue; + } + // Mark as executed. + std::string id = std::move(d.Id); + + // The deferred call may have come from another file. + DeferCallScope callScope(this, d.FilePath); + + cmExecutionStatus status(*this); + this->ExecuteCommand(d.Command, status, std::move(id)); + if (cmSystemTools::GetFatalErrorOccured()) { + break; + } + } + } + this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile); this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", @@ -1697,7 +1764,9 @@ void cmMakefile::Configure() } } - this->ReadListFile(listFile, currentStart); + this->Defer = cm::make_unique<DeferCommands>(); + this->RunListFile(listFile, currentStart, this->Defer.get()); + this->Defer.reset(); if (cmSystemTools::GetFatalErrorOccured()) { scope.Quiet(); } @@ -1772,6 +1841,13 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath, const std::string& binPath, bool excludeFromAll, bool immediate) { + if (this->DeferRunning) { + this->IssueMessage( + MessageType::FATAL_ERROR, + "Subdirectories may not be created during deferred execution."); + return; + } + // Make sure the binary directory is unique. if (!this->EnforceUniqueDir(srcPath, binPath)) { return; @@ -2979,6 +3055,68 @@ void cmMakefile::SetRecursionDepth(int recursionDepth) this->RecursionDepth = recursionDepth; } +std::string cmMakefile::NewDeferId() +{ + return this->GetGlobalGenerator()->NewDeferId(); +} + +bool cmMakefile::DeferCall(std::string id, std::string file, + cmListFileFunction lff) +{ + if (!this->Defer) { + return false; + } + this->Defer->Commands.emplace_back( + DeferCommand{ std::move(id), std::move(file), std::move(lff) }); + return true; +} + +bool cmMakefile::DeferCancelCall(std::string const& id) +{ + if (!this->Defer) { + return false; + } + for (DeferCommand& dc : this->Defer->Commands) { + if (dc.Id == id) { + dc.Id.clear(); + } + } + return true; +} + +cm::optional<std::string> cmMakefile::DeferGetCallIds() const +{ + cm::optional<std::string> ids; + if (this->Defer) { + ids = cmJoin( + cmMakeRange(this->Defer->Commands) + .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); }) + .transform( + [](DeferCommand const& dc) -> std::string const& { return dc.Id; }), + ";"); + } + return ids; +} + +cm::optional<std::string> cmMakefile::DeferGetCall(std::string const& id) const +{ + cm::optional<std::string> call; + if (this->Defer) { + std::string tmp; + for (DeferCommand const& dc : this->Defer->Commands) { + if (dc.Id == id) { + tmp = dc.Command.Name.Original; + for (cmListFileArgument const& arg : dc.Command.Arguments) { + tmp = cmStrCat(tmp, ';', arg.Value); + } + break; + } + } + call = std::move(tmp); + } + return call; +} + MessageType cmMakefile::ExpandVariablesInStringNew( std::string& errorstr, std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly, const char* filename, long line, @@ -3016,7 +3154,12 @@ MessageType cmMakefile::ExpandVariablesInStringNew( switch (var.domain) { case NORMAL: if (filename && lookup == lineVar) { - varresult = std::to_string(line); + cmListFileContext const& top = this->Backtrace.Top(); + if (top.DeferId) { + varresult = cmStrCat("DEFERRED:"_s, *top.DeferId); + } else { + varresult = std::to_string(line); + } } else { value = this->GetDefinition(lookup); } @@ -3347,20 +3490,10 @@ bool cmMakefile::IsLoopBlock() const return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0; } -std::string const& cmMakefile::GetExecutionFilePath() const -{ - assert(this->StateSnapshot.IsValid()); - return this->StateSnapshot.GetExecutionListFile(); -} - bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs, - std::vector<std::string>& outArgs, - const char* filename) const + std::vector<std::string>& outArgs) const { - if (!filename) { - auto const& efp = this->GetExecutionFilePath(); - filename = efp.c_str(); - } + std::string const& filename = this->GetBacktrace().Top().FilePath; std::string value; outArgs.reserve(inArgs.size()); for (cmListFileArgument const& i : inArgs) { @@ -3371,8 +3504,8 @@ bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs, } // Expand the variables in the argument. value = i.Value; - this->ExpandVariablesInString(value, false, false, false, filename, i.Line, - false, false); + this->ExpandVariablesInString(value, false, false, false, filename.c_str(), + i.Line, false, false); // If the argument is quoted, it should be one argument. // Otherwise, it may be a list of arguments. @@ -3387,12 +3520,9 @@ bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs, bool cmMakefile::ExpandArguments( std::vector<cmListFileArgument> const& inArgs, - std::vector<cmExpandedCommandArgument>& outArgs, const char* filename) const + std::vector<cmExpandedCommandArgument>& outArgs) const { - if (!filename) { - auto const& efp = this->GetExecutionFilePath(); - filename = efp.c_str(); - } + std::string const& filename = this->GetBacktrace().Top().FilePath; std::string value; outArgs.reserve(inArgs.size()); for (cmListFileArgument const& i : inArgs) { @@ -3403,8 +3533,8 @@ bool cmMakefile::ExpandArguments( } // Expand the variables in the argument. value = i.Value; - this->ExpandVariablesInString(value, false, false, false, filename, i.Line, - false, false); + this->ExpandVariablesInString(value, false, false, false, filename.c_str(), + i.Line, false, false); // If the argument is quoted, it should be one argument. // Otherwise, it may be a list of arguments. @@ -3424,7 +3554,7 @@ void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb) { if (!this->ExecutionStatusStack.empty()) { // Record the context in which the blocker is created. - fb->SetStartingContext(this->GetExecutionContext()); + fb->SetStartingContext(this->Backtrace.Top()); } this->FunctionBlockers.push(std::move(fb)); @@ -3593,6 +3723,12 @@ void cmMakefile::AddTargetObject(std::string const& tgtName, void cmMakefile::EnableLanguage(std::vector<std::string> const& lang, bool optional) { + if (this->DeferRunning) { + this->IssueMessage( + MessageType::FATAL_ERROR, + "Languages may not be enabled during deferred execution."); + return; + } if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) { this->AddDefinition("CMAKE_CFG_INTDIR", def); } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 0a6e6e2..c7940fb 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -15,6 +15,7 @@ #include <unordered_map> #include <vector> +#include <cm/optional> #include <cm/string_view> #include "cmsys/RegularExpression.hxx" @@ -640,8 +641,6 @@ public: * Get the current context backtrace. */ cmListFileBacktrace GetBacktrace() const; - cmListFileBacktrace GetBacktrace(cmCommandContext const& lfc) const; - cmListFileContext GetExecutionContext() const; /** * Get the vector of files created by this makefile @@ -697,7 +696,8 @@ public: /** * Print a command's invocation */ - void PrintCommandTrace(const cmListFileFunction& lff) const; + void PrintCommandTrace(cmListFileFunction const& lff, + cm::optional<std::string> const& deferId = {}) const; /** * Set a callback that is invoked whenever ExecuteCommand is called. @@ -708,8 +708,8 @@ public: * Execute a single CMake command. Returns true if the command * succeeded or false if it failed. */ - bool ExecuteCommand(const cmListFileFunction& lff, - cmExecutionStatus& status); + bool ExecuteCommand(const cmListFileFunction& lff, cmExecutionStatus& status, + cm::optional<std::string> deferId = {}); //! Enable support for named language, if nil then all languages are /// enabled. @@ -734,12 +734,9 @@ public: * variable replacement and list expansion. */ bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs, - std::vector<std::string>& outArgs, - const char* filename = nullptr) const; - + std::vector<std::string>& outArgs) const; bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs, - std::vector<cmExpandedCommandArgument>& outArgs, - const char* filename = nullptr) const; + std::vector<cmExpandedCommandArgument>& outArgs) const; /** * Get the instance @@ -942,8 +939,6 @@ public: const char* GetDefineFlagsCMP0059() const; - std::string const& GetExecutionFilePath() const; - void EnforceDirectoryLevelRules() const; void AddEvaluationFile( @@ -972,6 +967,12 @@ public: int GetRecursionDepth() const; void SetRecursionDepth(int recursionDepth); + std::string NewDeferId(); + bool DeferCall(std::string id, std::string fileName, cmListFileFunction lff); + bool DeferCancelCall(std::string const& id); + cm::optional<std::string> DeferGetCallIds() const; + cm::optional<std::string> DeferGetCall(std::string const& id) const; + protected: // add link libraries and directories to the target void AddGlobalLinkInformation(cmTarget& target); @@ -1033,10 +1034,25 @@ private: cmListFileBacktrace Backtrace; int RecursionDepth; + struct DeferCommand + { + // Id is empty for an already-executed or cancelled operation. + std::string Id; + std::string FilePath; + cmListFileFunction Command; + }; + struct DeferCommands + { + std::vector<DeferCommand> Commands; + }; + std::unique_ptr<DeferCommands> Defer; + bool DeferRunning = false; + void DoGenerate(cmLocalGenerator& lg); - void ReadListFile(cmListFile const& listFile, - const std::string& filenametoread); + void RunListFile(cmListFile const& listFile, + const std::string& filenametoread, + DeferCommands* defer = nullptr); bool ParseDefineFlag(std::string const& definition, bool remove); @@ -1087,6 +1103,12 @@ private: class ListFileScope; friend class ListFileScope; + class DeferScope; + friend class DeferScope; + + class DeferCallScope; + friend class DeferCallScope; + class BuildsystemFileScope; friend class BuildsystemFileScope; diff --git a/Source/cmState.cxx b/Source/cmState.cxx index e96c82f..d5ac9ae 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -837,6 +837,21 @@ cmStateSnapshot cmState::CreateBuildsystemDirectorySnapshot( return snapshot; } +cmStateSnapshot cmState::CreateDeferCallSnapshot( + cmStateSnapshot const& originSnapshot, std::string const& fileName) +{ + cmStateDetail::PositionType pos = + this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position); + pos->SnapshotType = cmStateEnums::DeferCallType; + pos->Keep = false; + pos->ExecutionListFile = this->ExecutionListFiles.Push( + originSnapshot.Position->ExecutionListFile, fileName); + assert(originSnapshot.Position->Vars.IsValid()); + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->PolicyScope = originSnapshot.Position->Policies; + return { this, pos }; +} + cmStateSnapshot cmState::CreateFunctionCallSnapshot( cmStateSnapshot const& originSnapshot, std::string const& fileName) { diff --git a/Source/cmState.h b/Source/cmState.h index dc3ba65..2aa57e0 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -55,6 +55,8 @@ public: cmStateSnapshot CreateBaseSnapshot(); cmStateSnapshot CreateBuildsystemDirectorySnapshot( cmStateSnapshot const& originSnapshot); + cmStateSnapshot CreateDeferCallSnapshot( + cmStateSnapshot const& originSnapshot, std::string const& fileName); cmStateSnapshot CreateFunctionCallSnapshot( cmStateSnapshot const& originSnapshot, std::string const& fileName); cmStateSnapshot CreateMacroCallSnapshot( diff --git a/Source/cmStateTypes.h b/Source/cmStateTypes.h index b8c1cca..010d7e3 100644 --- a/Source/cmStateTypes.h +++ b/Source/cmStateTypes.h @@ -18,6 +18,7 @@ enum SnapshotType { BaseType, BuildsystemDirectoryType, + DeferCallType, FunctionCallType, MacroCallType, IncludeFileType, diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index fbf4ceb..1e625a4 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -5,7 +5,8 @@ // POSIX APIs are needed # define _POSIX_C_SOURCE 200809L #endif -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__QNX__) // For isascii # define _XOPEN_SOURCE 700 #endif diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 7db2c46..aecc18e 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -10,6 +10,7 @@ #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" @@ -386,7 +387,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState, ? cmTarget::KeywordTLLSignature : cmTarget::PlainTLLSignature; if (!this->Target->PushTLLCommandTrace( - sig, this->Makefile.GetExecutionContext())) { + sig, this->Makefile.GetBacktrace().Top())) { std::ostringstream e; const char* modal = nullptr; MessageType messageType = MessageType::AUTHOR_WARNING; diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index bd6bb3d..67f7e11 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -5,7 +5,8 @@ // POSIX APIs are needed # define _POSIX_C_SOURCE 200809L #endif -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__QNX__) // For isascii # define _XOPEN_SOURCE 700 #endif diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 326ab15..413166e 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2869,6 +2869,23 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); } + // Add C-specific flags expressible in a ClCompile meant for C++. + if (langForClCompile == "CXX") { + std::set<std::string> languages; + this->GeneratorTarget->GetLanguages(languages, configName); + if (languages.count("C")) { + std::string flagsC; + this->LocalGenerator->AddCompileOptions(flagsC, this->GeneratorTarget, + "C", configName); + Options optC(this->LocalGenerator, Options::Compiler, + gg->GetClFlagTable()); + optC.Parse(flagsC); + if (const char* stdC = optC.GetFlag("LanguageStandard_C")) { + clOptions.AddFlag("LanguageStandard_C", stdC); + } + } + } + // Add a definition for the configuration name. std::string configDefine = cmStrCat("CMAKE_INTDIR=\"", configName, '"'); clOptions.AddDefine(configDefine); @@ -3775,12 +3792,14 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::string pdb = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config), '/', targetNames.PDB); - std::string imLib = - cmStrCat(this->GeneratorTarget->GetDirectory( - config, cmStateEnums::ImportLibraryArtifact), - '/', targetNames.ImportLibrary); + if (!targetNames.ImportLibrary.empty()) { + std::string imLib = + cmStrCat(this->GeneratorTarget->GetDirectory( + config, cmStateEnums::ImportLibraryArtifact), + '/', targetNames.ImportLibrary); - linkOptions.AddFlag("ImportLibrary", imLib); + linkOptions.AddFlag("ImportLibrary", imLib); + } linkOptions.AddFlag("ProgramDataBaseFile", pdb); // A Windows Runtime component uses internal .NET metadata, diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 0d8e894..2c7a8a7 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -17,6 +17,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSystemTools.h" +#include "cmake.h" class cmWhileFunctionBlocker : public cmFunctionBlocker { @@ -66,14 +67,9 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, mf.ExpandArguments(this->Args, expandedArguments); MessageType messageType; - cmListFileContext execContext = this->GetStartingContext(); - - cmCommandContext commandContext; - commandContext.Line = execContext.Line; - commandContext.Name = execContext.Name; - - cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), - mf.GetBacktrace(commandContext)); + cmListFileBacktrace whileBT = + mf.GetBacktrace().Push(this->GetStartingContext()); + cmConditionEvaluator conditionEvaluator(mf, whileBT); bool isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); @@ -90,7 +86,7 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, err += "("; err += errorString; err += ")."; - mf.IssueMessage(messageType, err); + mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT); if (messageType == MessageType::FATAL_ERROR) { cmSystemTools::SetFatalErrorOccured(); return true; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index bca938e..dc06fae 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -983,7 +983,7 @@ void cmake::PrintTraceFormatVersion() Json::StreamWriterBuilder builder; builder["indentation"] = ""; version["major"] = 1; - version["minor"] = 0; + version["minor"] = 1; val["version"] = version; msg = Json::writeString(builder, val); #endif @@ -2000,10 +2000,9 @@ std::string cmake::StripExtension(const std::string& file) const return file; } -const char* cmake::GetCacheDefinition(const std::string& name) const +cmProp cmake::GetCacheDefinition(const std::string& name) const { - cmProp p = this->State->GetInitializedCacheValue(name); - return p ? p->c_str() : nullptr; + return this->State->GetInitializedCacheValue(name); } void cmake::AddScriptingCommands() diff --git a/Source/cmake.h b/Source/cmake.h index 44c35c2..63635cb 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -299,7 +299,7 @@ public: /** * Given a variable name, return its value (as a string). */ - const char* GetCacheDefinition(const std::string&) const; + cmProp GetCacheDefinition(const std::string&) const; //! Add an entry into the cache void AddCacheEntry(const std::string& key, const char* value, const char* helpString, int type); diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx index 4f74eba..fb4e380 100644 --- a/Source/kwsys/RegularExpression.cxx +++ b/Source/kwsys/RegularExpression.cxx @@ -359,7 +359,7 @@ bool RegularExpression::compile(const char* exp) this->regmatch.clear(); // Small enough for pointer-storage convention? - if (comp.regsize >= 32767L) { // Probably could be 65535L. + if (comp.regsize >= 65535L) { // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), printf("RegularExpression::compile(): Expression too big.\n"); return false; diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json index 95b9d14..7c2d291 100644 --- a/Templates/MSBuild/FlagTables/v142_CL.json +++ b/Templates/MSBuild/FlagTables/v142_CL.json @@ -455,6 +455,20 @@ "flags": [] }, { + "name": "LanguageStandard_C", + "switch": "std:c11", + "comment": "ISO C11 Standard", + "value": "stdc11", + "flags": [] + }, + { + "name": "LanguageStandard_C", + "switch": "std:c17", + "comment": "ISO C17 (2018) Standard", + "value": "stdc17", + "flags": [] + }, + { "name": "PrecompiledHeader", "switch": "Yc", "comment": "Create", diff --git a/Tests/CMakeGUI/CMakeGUITest.cmake b/Tests/CMakeGUI/CMakeGUITest.cmake index 3d8c27e..b60ec35 100644 --- a/Tests/CMakeGUI/CMakeGUITest.cmake +++ b/Tests/CMakeGUI/CMakeGUITest.cmake @@ -109,3 +109,12 @@ run_cmake_gui_test(sourceBinaryArgs:noExistConfigExists ARGS "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExistConfigExists/noexist" ) + +run_cmake_gui_test(simpleConfigure:success) +run_cmake_gui_test(simpleConfigure:fail) + +unset(ENV{ADDED_VARIABLE}) +set(ENV{KEPT_VARIABLE} "Kept variable") +set(ENV{CHANGED_VARIABLE} "This variable will be changed") +set(ENV{REMOVED_VARIABLE} "Removed variable") +run_cmake_gui_test(environment) diff --git a/Tests/CMakeGUI/CMakeGUITest.cxx b/Tests/CMakeGUI/CMakeGUITest.cxx index a7a5d17..80ea08d 100644 --- a/Tests/CMakeGUI/CMakeGUITest.cxx +++ b/Tests/CMakeGUI/CMakeGUITest.cxx @@ -2,8 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "CMakeGUITest.h" +#include "QCMake.h" #include <QApplication> #include <QEventLoop> +#include <QMessageBox> #include <QSettings> #include <QString> #include <QStringList> @@ -13,6 +15,9 @@ #include "CMakeSetupDialog.h" +#include "CatchShow.h" +#include "FirstConfigure.h" + namespace { void loopSleep(int msecs = 100) { @@ -28,6 +33,44 @@ CMakeGUITest::CMakeGUITest(CMakeSetupDialog* window, QObject* parent) { } +void CMakeGUITest::tryConfigure(int expectedResult, int timeout) +{ + auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance(); + + bool done = false; + CatchShow catchConfigure; + catchConfigure.setCallback<FirstConfigure>([&done](FirstConfigure* dialog) { + if (done) { + return; + } + done = true; + + dialog->findChild<StartCompilerSetup*>()->setCurrentGenerator( + CMAKE_GENERATOR); + dialog->accept(); + }); + + CatchShow catchMessages; + catchMessages.setCallback<QMessageBox>([](QMessageBox* box) { + if (box->text().contains("Build directory does not exist")) { + box->accept(); + } + + if (box->text().contains("Error in configuration process")) { + box->accept(); + } + }); + + QSignalSpy configureDoneSpy(cmake, &QCMake::configureDone); + QVERIFY(configureDoneSpy.isValid()); + QMetaObject::invokeMethod( + this->m_window, [this]() { this->m_window->ConfigureButton->click(); }, + Qt::QueuedConnection); + QVERIFY(configureDoneSpy.wait(timeout)); + + QCOMPARE(configureDoneSpy, { { expectedResult } }); +} + void CMakeGUITest::sourceBinaryArgs() { QFETCH(QString, sourceDir); @@ -68,6 +111,67 @@ void CMakeGUITest::sourceBinaryArgs_data() << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfigExists/build"; } +void CMakeGUITest::simpleConfigure() +{ + QFETCH(QString, sourceDir); + QFETCH(QString, binaryDir); + QFETCH(int, expectedResult); + + this->m_window->SourceDirectory->setText(sourceDir); + this->m_window->BinaryDirectory->setCurrentText(binaryDir); + + // Wait a bit for everything to update + loopSleep(); + + this->tryConfigure(expectedResult, 1000); +} + +void CMakeGUITest::simpleConfigure_data() +{ + QTest::addColumn<QString>("sourceDir"); + QTest::addColumn<QString>("binaryDir"); + QTest::addColumn<int>("expectedResult"); + + QTest::newRow("success") << CMakeGUITest_BINARY_DIR + "/simpleConfigure-success/src" + << CMakeGUITest_BINARY_DIR + "/simpleConfigure-success/build" + << 0; + QTest::newRow("fail") << CMakeGUITest_BINARY_DIR "/simpleConfigure-fail/src" + << CMakeGUITest_BINARY_DIR + "/simpleConfigure-fail/build" + << -1; +} + +void CMakeGUITest::environment() +{ + auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance(); + + this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR + "/environment/src"); + this->m_window->BinaryDirectory->setCurrentText(CMakeGUITest_BINARY_DIR + "/environment/build"); + + // We are already testing EnvironmentDialog, so just trust that it's + // connected correctly and modify the environment directly. + auto env = cmake->environment(); + env.insert("ADDED_VARIABLE", "Added variable"); + env.insert("CHANGED_VARIABLE", "Changed variable"); + env.remove("REMOVED_VARIABLE"); + cmake->setEnvironment(env); + + // Wait a bit for everything to update + loopSleep(); + + this->tryConfigure(); + + auto penv = QProcessEnvironment::systemEnvironment(); + QVERIFY(!penv.contains("ADDED_VARIABLE")); + QCOMPARE(penv.value("KEPT_VARIABLE"), "Kept variable"); + QCOMPARE(penv.value("CHANGED_VARIABLE"), "This variable will be changed"); + QCOMPARE(penv.value("REMOVED_VARIABLE"), "Removed variable"); +} + void SetupDefaultQSettings() { QSettings::setDefaultFormat(QSettings::IniFormat); diff --git a/Tests/CMakeGUI/CMakeGUITest.h b/Tests/CMakeGUI/CMakeGUITest.h index 55a885b..891cf62 100644 --- a/Tests/CMakeGUI/CMakeGUITest.h +++ b/Tests/CMakeGUI/CMakeGUITest.h @@ -15,7 +15,12 @@ public: private: CMakeSetupDialog* m_window = nullptr; + void tryConfigure(int expectedResult = 0, int timeout = 60000); + private slots: void sourceBinaryArgs(); void sourceBinaryArgs_data(); + void simpleConfigure(); + void simpleConfigure_data(); + void environment(); }; diff --git a/Tests/CMakeGUI/CMakeLists.txt b/Tests/CMakeGUI/CMakeLists.txt index 2a2ee1a..c6bc88a 100644 --- a/Tests/CMakeGUI/CMakeLists.txt +++ b/Tests/CMakeGUI/CMakeLists.txt @@ -10,13 +10,24 @@ include_directories( set(MOC_SRCS) qt5_wrap_cpp(MOC_SRCS + CatchShow.h + ) +add_library(CMakeGUITestLib STATIC ${MOC_SRCS} + CatchShow.cxx + CatchShow.h + ) +target_link_libraries(CMakeGUITestLib Qt5::Core Qt5::Gui Qt5::Widgets) + +set(MOC_SRCS) +qt5_wrap_cpp(MOC_SRCS CMakeGUITest.h ) add_executable(CMakeGUITest CMakeGUITest.cxx ${MOC_SRCS}) -target_link_libraries(CMakeGUITest CMakeGUIMainLib Qt5::Core Qt5::Test Qt5::Widgets) +target_link_libraries(CMakeGUITest CMakeGUIMainLib CMakeGUITestLib Qt5::Core Qt5::Test Qt5::Widgets) target_compile_definitions(CMakeGUITest PRIVATE "CMakeGUITest_SOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" "CMakeGUITest_BINARY_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\"" + "CMAKE_GENERATOR=\"${CMAKE_GENERATOR}\"" ) add_test(NAME CMakeGUI COMMAND ${CMAKE_CMAKE_COMMAND} @@ -35,11 +46,25 @@ function(add_cmake_gui_lib_test name) ${_t_MOC_SOURCES} ) add_executable(${name} ${_t_SOURCES} ${MOC_SRCS}) - target_link_libraries(${name} CMakeGUILib Qt5::Core Qt5::Test Qt5::Widgets) + target_link_libraries(${name} CMakeGUILib CMakeGUITestLib Qt5::Core Qt5::Test Qt5::Widgets) add_test(NAME "CMakeGUILib.${name}" COMMAND ${name}) endfunction() +add_cmake_gui_lib_test(CatchShow + SOURCES + CatchShowTest.cxx + CatchShowTest.h + MOC_SOURCES + CatchShowTest.h + ) +add_cmake_gui_lib_test(EnvironmentDialog + SOURCES + EnvironmentDialogTest.cxx + EnvironmentDialogTest.h + MOC_SOURCES + EnvironmentDialogTest.h + ) add_cmake_gui_lib_test(QCMakeCacheModel SOURCES QCMakeCacheModelTest.cxx diff --git a/Tests/CMakeGUI/CatchShow.cxx b/Tests/CMakeGUI/CatchShow.cxx new file mode 100644 index 0000000..aee2d9d --- /dev/null +++ b/Tests/CMakeGUI/CatchShow.cxx @@ -0,0 +1,25 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "CatchShow.h" + +#include <QCoreApplication> + +CatchShow::CatchShow(QObject* parent) + : QObject(parent) +{ + QCoreApplication::instance()->installEventFilter(this); +} + +bool CatchShow::eventFilter(QObject* obj, QEvent* event) +{ + if (this->m_callback && event->type() == QEvent::Show) { + this->m_callback(obj); + } + + return this->QObject::eventFilter(obj, event); +} + +int CatchShow::count() const +{ + return this->m_count; +} diff --git a/Tests/CMakeGUI/CatchShow.h b/Tests/CMakeGUI/CatchShow.h new file mode 100644 index 0000000..0254c15 --- /dev/null +++ b/Tests/CMakeGUI/CatchShow.h @@ -0,0 +1,41 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <functional> +#include <memory> + +#include <QObject> +#include <QWidget> + +class CatchShow : public QObject +{ + Q_OBJECT +public: + CatchShow(QObject* parent = nullptr); + + template <typename T, typename F> + void setCallback(F&& func); + bool eventFilter(QObject* obj, QEvent* event) override; + int count() const; + +private: + std::function<void(QObject* obj)> m_callback; + int m_count = 0; +}; + +template <typename T, typename F> +void CatchShow::setCallback(F&& func) +{ + this->m_callback = [this, func](QObject* obj) { + auto* d = qobject_cast<T*>(obj); + if (d) { + QMetaObject::invokeMethod(obj, + [this, func, d]() { + ++this->m_count; + func(d); + }, + Qt::QueuedConnection); + } + }; +} diff --git a/Tests/CMakeGUI/CatchShowTest.cxx b/Tests/CMakeGUI/CatchShowTest.cxx new file mode 100644 index 0000000..acea8ea --- /dev/null +++ b/Tests/CMakeGUI/CatchShowTest.cxx @@ -0,0 +1,49 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "CatchShowTest.h" + +#include <QMessageBox> +#include <QtTest> + +#include "CatchShow.h" + +CatchShowTest::CatchShowTest(QObject* parent) + : QObject(parent) +{ +} + +void CatchShowTest::catchShow() +{ + bool have = false; + CatchShow catcher; + catcher.setCallback<QMessageBox>([&have](QMessageBox* box) { + have = true; + box->accept(); + }); + + QCOMPARE(catcher.count(), 0); + QCOMPARE(have, false); + + { + QDialog dialog; + dialog.show(); + QCOMPARE(catcher.count(), 0); + QCOMPARE(have, false); + } + + { + have = false; + QMessageBox::critical(nullptr, "Error", "This is an error"); + QCOMPARE(catcher.count(), 1); + QCOMPARE(have, true); + } + + { + have = false; + QMessageBox::information(nullptr, "Info", "This is information"); + QCOMPARE(catcher.count(), 2); + QCOMPARE(have, true); + } +} + +QTEST_MAIN(CatchShowTest) diff --git a/Tests/CMakeGUI/CatchShowTest.h b/Tests/CMakeGUI/CatchShowTest.h new file mode 100644 index 0000000..6da2163 --- /dev/null +++ b/Tests/CMakeGUI/CatchShowTest.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <QObject> + +class CatchShowTest : public QObject +{ + Q_OBJECT +public: + CatchShowTest(QObject* parent = nullptr); + +private slots: + void catchShow(); +}; diff --git a/Tests/CMakeGUI/EnvironmentDialogTest.cxx b/Tests/CMakeGUI/EnvironmentDialogTest.cxx new file mode 100644 index 0000000..9ec4996 --- /dev/null +++ b/Tests/CMakeGUI/EnvironmentDialogTest.cxx @@ -0,0 +1,142 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "EnvironmentDialogTest.h" + +#include <QDialogButtonBox> +#include <QMessageBox> +#include <QObject> +#include <QPushButton> +#include <QString> +#include <QtTest> + +#include "CatchShow.h" +#include "EnvironmentDialog.h" + +EnvironmentDialogTest::EnvironmentDialogTest(QObject* parent) + : QObject(parent) +{ +} + +void EnvironmentDialogTest::environmentDialog() +{ + CatchShow catcher; + catcher.setCallback<QMessageBox>([](QMessageBox* box) { box->accept(); }); + + QProcessEnvironment env; + env.insert("DELETED_VARIABLE_1", "Deleted variable 1"); + env.insert("DELETED_VARIABLE_2", "Deleted variable 2"); + env.insert("KEPT_VARIABLE", "Kept variable"); + env.insert("CHANGED_VARIABLE", "This will be changed"); + + EnvironmentDialog dialog(env); + + { + QStringList expected{ + "CHANGED_VARIABLE=This will be changed", + "DELETED_VARIABLE_1=Deleted variable 1", + "DELETED_VARIABLE_2=Deleted variable 2", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + QCOMPARE(catcher.count(), 0); + } + + { + CatchShow catcher2; + bool done = false; + catcher2.setCallback<QDialog>([&catcher, &done](QDialog* box) { + if (done) { + return; + } + done = true; + + auto name = box->findChild<QLineEdit*>("name"); + auto value = box->findChild<QLineEdit*>("value"); + auto acceptReject = box->findChild<QDialogButtonBox*>(); + + name->setText(""); + value->setText(""); + acceptReject->button(QDialogButtonBox::Ok)->click(); + QCOMPARE(catcher.count(), 1); + + name->setText("KEPT_VARIABLE"); + value->setText(""); + acceptReject->button(QDialogButtonBox::Ok)->click(); + QCOMPARE(catcher.count(), 2); + + name->setText("ADDED_VARIABLE"); + value->setText("Added variable"); + acceptReject->button(QDialogButtonBox::Ok)->click(); + QCOMPARE(catcher.count(), 2); + }); + dialog.AddEntry->click(); + + QStringList expected{ + "ADDED_VARIABLE=Added variable", + "CHANGED_VARIABLE=This will be changed", + "DELETED_VARIABLE_1=Deleted variable 1", + "DELETED_VARIABLE_2=Deleted variable 2", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + QCOMPARE(catcher.count(), 2); + QVERIFY(done); + } + + { + CatchShow catcher2; + bool done = false; + catcher2.setCallback<QDialog>([&done](QDialog* box) { + if (done) { + return; + } + done = true; + + auto name = box->findChild<QLineEdit*>("name"); + auto value = box->findChild<QLineEdit*>("value"); + auto acceptReject = box->findChild<QDialogButtonBox*>(); + + name->setText("DISCARDED_VARIABLE"); + value->setText("Discarded variable"); + acceptReject->button(QDialogButtonBox::Cancel)->click(); + }); + dialog.AddEntry->click(); + + QStringList expected{ + "ADDED_VARIABLE=Added variable", + "CHANGED_VARIABLE=This will be changed", + "DELETED_VARIABLE_1=Deleted variable 1", + "DELETED_VARIABLE_2=Deleted variable 2", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + QCOMPARE(catcher.count(), 2); + QVERIFY(done); + } + + { + auto* model = dialog.Environment->model(); + auto* selectionModel = dialog.Environment->selectionModel(); + for (int i = 0; i < model->rowCount(); ++i) { + auto index1 = model->index(i, 0); + auto index2 = model->buddy(index1); + auto name = model->data(index1, Qt::DisplayRole).toString(); + if (name == "DELETED_VARIABLE_1" || name == "DELETED_VARIABLE_2") { + selectionModel->select(index1, QItemSelectionModel::Select); + selectionModel->select(index2, QItemSelectionModel::Select); + } else if (name == "CHANGED_VARIABLE") { + model->setData(index2, "Changed variable", Qt::DisplayRole); + } + } + dialog.RemoveEntry->click(); + + QStringList expected{ + "ADDED_VARIABLE=Added variable", + "CHANGED_VARIABLE=Changed variable", + "KEPT_VARIABLE=Kept variable", + }; + QCOMPARE(dialog.environment().toStringList(), expected); + } +} + +QTEST_MAIN(EnvironmentDialogTest) diff --git a/Tests/CMakeGUI/EnvironmentDialogTest.h b/Tests/CMakeGUI/EnvironmentDialogTest.h new file mode 100644 index 0000000..bcba2c5 --- /dev/null +++ b/Tests/CMakeGUI/EnvironmentDialogTest.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <QObject> + +class EnvironmentDialogTest : public QObject +{ + Q_OBJECT +public: + EnvironmentDialogTest(QObject* parent = nullptr); + +private slots: + void environmentDialog(); +}; diff --git a/Tests/CMakeGUI/environment/CMakeLists.txt.in b/Tests/CMakeGUI/environment/CMakeLists.txt.in new file mode 100644 index 0000000..1eeeb85 --- /dev/null +++ b/Tests/CMakeGUI/environment/CMakeLists.txt.in @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.18) +project(environment NONE) + +if(NOT "$ENV{KEPT_VARIABLE}" STREQUAL "Kept variable") + message(SEND_ERROR "KEPT_VARIABLE is \"$ENV{KEPT_VARIABLE}\", should be \"Kept variable\"") +endif() + +if(NOT "$ENV{ADDED_VARIABLE}" STREQUAL "Added variable") + message(SEND_ERROR "ADDED_VARIABLE is \"$ENV{ADDED_VARIABLE}\", should be \"Added variable\"") +endif() + +if(NOT "$ENV{CHANGED_VARIABLE}" STREQUAL "Changed variable") + message(SEND_ERROR "CHANGED_VARIABLE is \"$ENV{CHANGED_VARIABLE}\", should be \"Changed variable\"") +endif() + +if(DEFINED ENV{REMOVED_VARIABLE}) + message(SEND_ERROR "REMOVED_VARIABLE should not be defined") +endif() diff --git a/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in b/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in new file mode 100644 index 0000000..dc55064 --- /dev/null +++ b/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.18) +project(simpleConfigure-fail NONE) + +message(STATUS "This is a failed configure") +message(FATAL_ERROR "Error") diff --git a/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in b/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in new file mode 100644 index 0000000..fc42c00 --- /dev/null +++ b/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.18) +project(simpleConfigure-success NONE) + +message(STATUS "This is a successful configure") diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt index fdfa36e..44484c3 100644 --- a/Tests/FindPython/CMakeLists.txt +++ b/Tests/FindPython/CMakeLists.txt @@ -243,6 +243,87 @@ if(CMake_TEST_FindPython) --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> ) + add_test(NAME FindPython.Python3.VersionRange.LOCATION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python3.VersionRange.LOCATION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python3 -DPython_REQUESTED_VERSION=3 + -DPython3_FIND_STRATEGY=LOCATION + ) + add_test(NAME FindPython.Python3.VersionRange.VERSION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python3.VersionRange.VERSION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python3 -DPython_REQUESTED_VERSION=3 + -DPython3_FIND_STRATEGY=VERSION + ) + add_test(NAME FindPython.Python2.VersionRange.LOCATION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.LOCATION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2 + -DPython2_FIND_STRATEGY=LOCATION + ) + add_test(NAME FindPython.Python2.VersionRange.VERSION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.VERSION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2 + -DPython2_FIND_STRATEGY=VERSION + ) + add_test(NAME FindPython.Python.V2.VersionRange.LOCATION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.LOCATION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2 + -DPython_FIND_STRATEGY=LOCATION + ) + add_test(NAME FindPython.Python.V2.VersionRange.VERSION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.VERSION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2 + -DPython_FIND_STRATEGY=VERSION + ) + add_test(NAME FindPython.Python.V3.VersionRange.LOCATION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.VersionRange.LOCATION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=3 + -DPython_FIND_STRATEGY=LOCATION + ) + add_test(NAME FindPython.Python.V3.VersionRange.VERSION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.VersionRange.VERSION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=3 + -DPython_FIND_STRATEGY=VERSION + ) + add_test(NAME FindPython.MultiplePackages COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> --build-and-test @@ -492,6 +573,29 @@ if(CMake_TEST_FindPython_IronPython) --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> ) + + add_test(NAME FindPython.IronPython2.VersionRange.LOCATION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/IronPython2.VersionRange.LOCATION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2 + -DPython2_FIND_IMPLEMENTATIONS=IronPython + -DPython2_FIND_STRATEGY=LOCATION + ) + add_test(NAME FindPython.IronPython2.VersionRange.VERSION COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange" + "${CMake_BINARY_DIR}/Tests/FindPython/IronPython2.VersionRange.VERSION" + ${build_generator_args} + --build-project TestVersionRange + --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2 + -DPython2_FIND_IMPLEMENTATIONS=IronPython + -DPython2_FIND_STRATEGY=VERSION + ) endif() if(CMake_TEST_FindPython_PyPy) diff --git a/Tests/FindPython/VersionRange/CMakeLists.txt b/Tests/FindPython/VersionRange/CMakeLists.txt new file mode 100644 index 0000000..0d946f5 --- /dev/null +++ b/Tests/FindPython/VersionRange/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required (VERSION 3.18...3.19) + +project (TestVersionRange LANGUAGES NONE) + + +find_package (${Python} ${Python_REQUESTED_VERSION} EXACT COMPONENTS Interpreter) +if (NOT ${Python}_FOUND) + message (FATAL_ERROR "Failed to find ${Python} ${Python_REQUESTED_VERSION}") +endif() + +if (Python_REQUESTED_VERSION VERSION_LESS 3.0) + set (IN_VERSION_RANGE 2.0...<3.0) + set (OUT_VERSION_RANGE 2.0...<${${Python}_VERSION}) +else() + set (IN_VERSION_RANGE 3.0...<4.0) + set (OUT_VERSION_RANGE 3.0...<${${Python}_VERSION}) +endif() + +function (FIND_PYTHON EXPECTED_VERSION) + unset (_${Python}_EXECUTABLE CACHE) + unset (_${Python}_LIBRARY_RELEASE CACHE) + unset (_${Python}_INCLUDE_DIR CACHE) + unset (${Python}_FOUND) + + find_package (${ARGN}) + + if (EXPECTED_VERSION STREQUAL "NONE") + if (${Python}_FOUND) + message (SEND_ERROR "Unexpectedly found version: ${${Python}_VERSION} for ${ARGN}") + endif() + return() + endif() + + if (NOT ${Python}_FOUND) + message (SEND_ERROR "Not found: ${ARGN}") + elseif (NOT ${Python}_VERSION VERSION_EQUAL EXPECTED_VERSION) + message (SEND_ERROR "Wrong version: ${${Python}_VERSION} for ${ARGN}") + endif() +endfunction() + +find_python (${${Python}_VERSION} ${Python} ${IN_VERSION_RANGE} COMPONENTS Interpreter) +if (${Python}_FIND_IMPLEMENTATIONS STREQUAL "IronPython") + find_python (${${Python}_VERSION} ${Python} ${IN_VERSION_RANGE} COMPONENTS Compiler) +else() + find_python (${${Python}_VERSION} ${Python} ${IN_VERSION_RANGE} COMPONENTS Development) +endif() + +find_python ("NONE" ${Python} ${OUT_VERSION_RANGE} COMPONENTS Interpreter) +if (${Python}_FIND_IMPLEMENTATIONS STREQUAL "IronPython") + find_python ("NONE" ${Python} ${OUT_VERSION_RANGE} COMPONENTS Compiler) +else() + find_python ("NONE" ${Python} ${OUT_VERSION_RANGE} COMPONENTS Development) +endif() + +find_python ("NONE" ${Python} 5...6 COMPONENTS Interpreter) diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt index eb08676..1f5b664 100644 --- a/Tests/IncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/CMakeLists.txt @@ -17,6 +17,7 @@ if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREA endif() if (run_sys_includes_test) add_subdirectory(SystemIncludeDirectories) + add_subdirectory(SystemIncludeDirectoriesPerLang) endif() endif() diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt new file mode 100644 index 0000000..70dfa01 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.17 FATAL_ERROR) + +project(SystemIncludeDirectoriesPerLang) + +add_library(c_interface INTERFACE) +set_target_properties(c_interface PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>" + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>" +) +target_compile_options(c_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Werror=unused-variable>") + +add_library(cxx_interface INTERFACE) +set_target_properties(cxx_interface PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>" + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>" +) +target_compile_options(cxx_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang>:-Werror=unused-variable>") + +# The C header must come before the C++ header for this test to smoke out the +# failure. The order of sources is how CMake determines the include cache +# and we need it to cache on the 'bad' language first +add_executable(consume_multi_lang_includes main.c smoke_out_includes.cxx) +target_link_libraries(consume_multi_lang_includes PRIVATE c_interface cxx_interface) diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h new file mode 100644 index 0000000..8dcd226 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h @@ -0,0 +1,10 @@ + +// Generate a warning in here + +int function_that_generates_warning(int x) +{ + int y = x; + int z = 2; + y -= x; + return y; +} diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx new file mode 100644 index 0000000..dbfc557 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx @@ -0,0 +1,7 @@ + +#include <header.h> + +int empty_func() +{ + return function_that_generates_warning(4); +} diff --git a/Tests/ObjCXX/CMakeLists.txt b/Tests/ObjCXX/CMakeLists.txt index a2a907a..cf03771 100644 --- a/Tests/ObjCXX/CMakeLists.txt +++ b/Tests/ObjCXX/CMakeLists.txt @@ -2,3 +2,4 @@ ADD_TEST_MACRO(ObjCXX.ObjC++ ObjC++) ADD_TEST_MACRO(ObjCXX.simple-build-test simple-build-test) ADD_TEST_MACRO(ObjCXX.cxx-file-extension-test cxx-file-extension-test) ADD_TEST_MACRO(ObjCXX.objcxx-file-extension-test objcxx-file-extension-test) +ADD_TEST_MACRO(ObjCXX.cxx-as-objcxx cxx-as-objcxx) diff --git a/Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt b/Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt new file mode 100644 index 0000000..23f6891 --- /dev/null +++ b/Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.18) +project(cxx-as-objcxx LANGUAGES OBJCXX) + +add_executable(cxx-as-objcxx main.cpp) +set_source_files_properties(main.cpp PROPERTIES LANGUAGE OBJCXX) diff --git a/Tests/ObjCXX/cxx-as-objcxx/main.cpp b/Tests/ObjCXX/cxx-as-objcxx/main.cpp new file mode 100644 index 0000000..701c567 --- /dev/null +++ b/Tests/ObjCXX/cxx-as-objcxx/main.cpp @@ -0,0 +1,6 @@ +#import <Foundation/Foundation.h> + +int main(int argc, char* argv[]) +{ + return 0; +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index c97a959..c70eb75 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -311,7 +311,11 @@ add_RunCMake_test(cmake_parse_arguments) add_RunCMake_test(cmake_path) add_RunCMake_test(continue) add_executable(color_warning color_warning.c) -add_RunCMake_test(ctest_build -DCOLOR_WARNING=$<TARGET_FILE:color_warning>) +add_executable(fake_build_command fake_build_command.c) +add_RunCMake_test(ctest_build + -DCOLOR_WARNING=$<TARGET_FILE:color_warning> + -DFAKE_BUILD_COMMAND_EXE=$<TARGET_FILE:fake_build_command> +) add_RunCMake_test(ctest_cmake_error) add_RunCMake_test(ctest_configure) if(COVERAGE_COMMAND) diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py index e617b76..1ee005e 100755 --- a/Tests/RunCMake/CommandLine/trace-json-v1-check.py +++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py @@ -56,7 +56,7 @@ with open(trace_file, 'r') as fp: assert sorted(vers.keys()) == ['version'] assert sorted(vers['version'].keys()) == ['major', 'minor'] assert vers['version']['major'] == 1 - assert vers['version']['minor'] == 0 + assert vers['version']['minor'] == 1 for i in fp.readlines(): line = json.loads(i) diff --git a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake index e4b8700..28b8570 100644 --- a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake +++ b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake @@ -61,8 +61,6 @@ set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DPse run_cmake(range_ignored) set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DPseudoRange_VERSION=2.0") run_cmake(range_no-range) -run_cmake(range_empty-1) -run_cmake(range_empty-2) run_cmake(range_1-3) run_cmake(range_1-2-include) run_cmake(range_1-2-exclude) diff --git a/Tests/RunCMake/FPHSA/range_empty-1-stderr.txt b/Tests/RunCMake/FPHSA/range_empty-1-stderr.txt deleted file mode 100644 index e1c741a..0000000 --- a/Tests/RunCMake/FPHSA/range_empty-1-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\): - Could NOT find PseudoRange: Found unsuitable version "2\.0", required range - is empty \("3\.0\.\.\.2\.0"\) \(found TRUE\) -Call Stack \(most recent call first\): - .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(_FPHSA_FAILURE_MESSAGE\) - FindPseudoRange.cmake:[0-9]+ \(find_package_handle_standard_args\) diff --git a/Tests/RunCMake/FPHSA/range_empty-1.cmake b/Tests/RunCMake/FPHSA/range_empty-1.cmake deleted file mode 100644 index c510d7d..0000000 --- a/Tests/RunCMake/FPHSA/range_empty-1.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(PseudoRange 3.0...2.0 REQUIRED) diff --git a/Tests/RunCMake/FPHSA/range_empty-2-stderr.txt b/Tests/RunCMake/FPHSA/range_empty-2-stderr.txt deleted file mode 100644 index ee0e79a..0000000 --- a/Tests/RunCMake/FPHSA/range_empty-2-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\): - Could NOT find PseudoRange: Found unsuitable version "2\.0", required range - is empty \("2\.0\.\.\.<2.0"\) \(found TRUE\) -Call Stack \(most recent call first\): - .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(_FPHSA_FAILURE_MESSAGE\) - FindPseudoRange.cmake:[0-9]+ \(find_package_handle_standard_args\) diff --git a/Tests/RunCMake/FPHSA/range_empty-2.cmake b/Tests/RunCMake/FPHSA/range_empty-2.cmake deleted file mode 100644 index 3ce90e8..0000000 --- a/Tests/RunCMake/FPHSA/range_empty-2.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(PseudoRange 2.0...<2.0 REQUIRED) diff --git a/Tests/RunCMake/VS10Project/LanguageStandard-check.cmake b/Tests/RunCMake/VS10Project/LanguageStandard-check.cmake new file mode 100644 index 0000000..85e2858 --- /dev/null +++ b/Tests/RunCMake/VS10Project/LanguageStandard-check.cmake @@ -0,0 +1,23 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(found_LanguageStandard_stdcpp17 0) +set(found_LanguageStandard_C_stdc11 0) +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "<LanguageStandard>stdcpp17</LanguageStandard>") + set(found_LanguageStandard_stdcpp17 1) + endif() + if(line MATCHES "<LanguageStandard_C>stdc11</LanguageStandard_C>") + set(found_LanguageStandard_C_stdc11 1) + endif() +endforeach() +if(NOT found_LanguageStandard_stdcpp17) + string(APPEND RunCMake_TEST_FAILED "LanguageStandard stdcpp17 not found in\n ${vcProjectFile}\n") +endif() +if(NOT found_LanguageStandard_C_stdc11) + string(APPEND RunCMake_TEST_FAILED "LanguageStandard_C stdc11 not found in\n ${vcProjectFile}\n") +endif() diff --git a/Tests/RunCMake/VS10Project/LanguageStandard.cmake b/Tests/RunCMake/VS10Project/LanguageStandard.cmake new file mode 100644 index 0000000..f8b62e2 --- /dev/null +++ b/Tests/RunCMake/VS10Project/LanguageStandard.cmake @@ -0,0 +1,5 @@ +enable_language(C) +enable_language(CXX) + +add_library(foo empty.c empty.cxx) +target_compile_features(foo PRIVATE c_std_11 cxx_std_17) diff --git a/Tests/RunCMake/VS10Project/NoImpLib-check.cmake b/Tests/RunCMake/VS10Project/NoImpLib-check.cmake new file mode 100644 index 0000000..50722b2 --- /dev/null +++ b/Tests/RunCMake/VS10Project/NoImpLib-check.cmake @@ -0,0 +1,23 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(found_ImportLibrary 0) +set(found_TargetExt_dll 0) +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "<ImportLibrary>") + set(found_ImportLibrary 1) + endif() + if(line MATCHES "<TargetExt[^\n]*\\.dll") + set(found_TargetExt_dll 1) + endif() +endforeach() +if(found_ImportLibrary) + string(APPEND RunCMake_TEST_FAILED "ImportLibrary incorrectly found in\n ${vcProjectFile}\n") +endif() +if(NOT found_TargetExt_dll) + string(APPEND RunCMake_TEST_FAILED "TargetExt not found in\n ${vcProjectFile}\n") +endif() diff --git a/Tests/RunCMake/VS10Project/NoImpLib.cmake b/Tests/RunCMake/VS10Project/NoImpLib.cmake new file mode 100644 index 0000000..2c11eac --- /dev/null +++ b/Tests/RunCMake/VS10Project/NoImpLib.cmake @@ -0,0 +1,3 @@ +enable_language(C) +set(CMAKE_IMPORT_LIBRARY_SUFFIX "") +add_library(foo SHARED empty.c) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index e9f251a..133dacc 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -3,10 +3,15 @@ cmake_policy(SET CMP0057 NEW) include(RunCMake) cmake_policy(SET CMP0054 NEW) +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27) + run_cmake(LanguageStandard) +endif() + run_cmake(VsCsharpSourceGroup) run_cmake(VsCSharpCompilerOpts) run_cmake(ExplicitCMakeLists) run_cmake(InterfaceLibSources) +run_cmake(NoImpLib) run_cmake(RuntimeLibrary) run_cmake(SourceGroupCMakeLists) run_cmake(SourceGroupTreeCMakeLists) diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index 34fc26e..62163ac 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake @@ -108,11 +108,6 @@ XcodeRemoveExcessiveISystem() # Isolate device tests from host architecture selection. unset(ENV{CMAKE_OSX_ARCHITECTURES}) -if(XCODE_VERSION VERSION_GREATER_EQUAL 12) - # FIXME: Restore device tests and fix them for the Xcode "new build system" - return() -endif() - # Use a single build tree for a few tests without cleaning. if(NOT XCODE_VERSION VERSION_LESS 5) @@ -142,8 +137,8 @@ if(NOT XCODE_VERSION VERSION_LESS 5) file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) - run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) - run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) + run_cmake_command(XcodeBundles-build-macOS ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install-macOS ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -159,8 +154,8 @@ if(NOT XCODE_VERSION VERSION_LESS 5) file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) - run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) - run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) + run_cmake_command(XcodeBundles-build-iOS ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install-iOS ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -178,8 +173,8 @@ if(NOT XCODE_VERSION VERSION_LESS 7) file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) - run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) - run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) + run_cmake_command(XcodeBundles-build-watchOS ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install-watchOS ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -197,8 +192,8 @@ if(NOT XCODE_VERSION VERSION_LESS 7.1) file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) - run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) - run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) + run_cmake_command(XcodeBundles-build-tvOS ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install-tvOS ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -211,7 +206,7 @@ if(NOT XCODE_VERSION VERSION_LESS 7) unset(RunCMake_TEST_OPTIONS) endif() -if(NOT XCODE_VERSION VERSION_LESS 6) +if(XCODE_VERSION VERSION_GREATER_EQUAL 6 AND XCODE_VERSION VERSION_LESS 12) # XcodeIOSInstallCombined set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeIOSInstallCombined-build) set(RunCMake_TEST_NO_CLEAN 1) diff --git a/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake b/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake deleted file mode 100644 index 8bee6f2..0000000 --- a/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake +++ /dev/null @@ -1,2 +0,0 @@ - -cmake_language(CALL ${COMMAND}) diff --git a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake index 5fb93c8..6480b2e 100644 --- a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake @@ -2,7 +2,16 @@ include(RunCMake) run_cmake(no_parameters) run_cmake(unknown_meta_operation) -run_cmake(call_invalid_command) +foreach(command IN ITEMS + "function" "ENDFUNCTION" + "macro" "endMACRO" + "if" "elseif" "else" "endif" + "while" "endwhile" + "foreach" "endforeach" + ) + message(STATUS "Running call_invalid_command for ${command}...") + run_cmake_with_options(call_invalid_command -Dcommand=${command}) +endforeach() run_cmake(call_valid_command) run_cmake(call_double_evaluation) run_cmake(call_expanded_command) @@ -23,3 +32,53 @@ run_cmake(eval_message_fatal_error) run_cmake(eval_no_code) run_cmake(eval_no_parameters) run_cmake(eval_variable_outside_message) +run_cmake(defer_call) +run_cmake(defer_call_add_subdirectory) +run_cmake(defer_call_enable_language) +run_cmake(defer_call_ids) +foreach(command IN ITEMS + "function" "endfunction" + "macro" "endmacro" + "if" "elseif" "else" "endif" + "while" "endwhile" + "foreach" "endforeach" + "return" + ) + message(STATUS "Running defer_call_invalid_command for ${command}...") + run_cmake_with_options(defer_call_invalid_command -Dcommand=${command}) +endforeach() +run_cmake(defer_call_invalid_directory) +run_cmake(defer_call_error) +run_cmake(defer_call_missing_directory) +run_cmake(defer_call_policy_PUSH) +run_cmake(defer_call_syntax_error) +run_cmake_with_options(defer_call_trace --trace-expand) +run_cmake_with_options(defer_call_trace_json --trace --trace-format=json-v1) +run_cmake(defer_cancel_call_unknown_argument) +run_cmake(defer_cancel_call_invalid_directory) +run_cmake(defer_cancel_call_id) +run_cmake(defer_cancel_call_id_var) +run_cmake(defer_directory_empty) +run_cmake(defer_directory_missing) +run_cmake(defer_directory_multiple) +run_cmake(defer_id_empty) +run_cmake(defer_id_missing) +run_cmake(defer_id_multiple) +run_cmake(defer_id_var_empty) +run_cmake(defer_id_var_missing) +run_cmake(defer_id_var_multiple) +run_cmake(defer_get_call_ids_missing_var) +run_cmake(defer_get_call_ids_too_many_args) +run_cmake(defer_get_call_ids_invalid_directory) +run_cmake(defer_get_call_ids_id) +run_cmake(defer_get_call_ids_id_var) +run_cmake(defer_get_call_missing_id) +run_cmake(defer_get_call_missing_var) +run_cmake(defer_get_call_too_many_args) +run_cmake(defer_get_call_id_empty) +run_cmake(defer_get_call_unknown_argument) +run_cmake(defer_get_call_id) +run_cmake(defer_get_call_id_var) +run_cmake(defer_missing_arg) +run_cmake(defer_missing_call) +run_cmake(defer_unknown_option) diff --git a/Tests/RunCMake/cmake_language/call_expand_command_name.cmake b/Tests/RunCMake/cmake_language/call_expand_command_name.cmake index e03bb1f..f74d303 100644 --- a/Tests/RunCMake/cmake_language/call_expand_command_name.cmake +++ b/Tests/RunCMake/cmake_language/call_expand_command_name.cmake @@ -1,2 +1,2 @@ set (my_call "CALL") -cmake_language (${my_call} message "OK!") +cmake_language (${my_call} ${empty} message "OK!") diff --git a/Tests/RunCMake/cmake_language/call_expanded_command.cmake b/Tests/RunCMake/cmake_language/call_expanded_command.cmake index e76e612..c52468d 100644 --- a/Tests/RunCMake/cmake_language/call_expanded_command.cmake +++ b/Tests/RunCMake/cmake_language/call_expanded_command.cmake @@ -3,4 +3,4 @@ function (itsok) endfunction() set (cmd CALL itsok) -cmake_language (${cmd}) +cmake_language (${empty} ${cmd}) diff --git a/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt b/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt index e87e9bc..82411d2 100644 --- a/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt +++ b/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt @@ -1,4 +1,4 @@ CMake Error at call_expanded_command_and_arguments.cmake:2 \(cmake_language\): - cmake_language called with incorrect number of arguments + cmake_language CALL command's arguments must be literal Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/FPHSA/range_empty-2-result.txt b/Tests/RunCMake/cmake_language/call_invalid_command-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/FPHSA/range_empty-2-result.txt +++ b/Tests/RunCMake/cmake_language/call_invalid_command-result.txt diff --git a/Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt b/Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt new file mode 100644 index 0000000..4439842 --- /dev/null +++ b/Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at call_invalid_command.cmake:1 \(cmake_language\): + cmake_language invalid command specified: [A-Za-z_]+ +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/call_invalid_command.cmake b/Tests/RunCMake/cmake_language/call_invalid_command.cmake index 585aad4..f213895 100644 --- a/Tests/RunCMake/cmake_language/call_invalid_command.cmake +++ b/Tests/RunCMake/cmake_language/call_invalid_command.cmake @@ -1,14 +1 @@ - -foreach (command IN ITEMS "function" "ENDFUNCTION" - "macro" "endMACRO" - "if" "elseif" "else" "endif" - "while" "endwhile" - "foreach" "endforeach") - execute_process(COMMAND "${CMAKE_COMMAND}" -DCOMMAND=${command} - -P "${CMAKE_CURRENT_SOURCE_DIR}/CallInvalidCommand.cmake" - OUTPUT_QUIET ERROR_QUIET - RESULT_VARIABLE result) - if (NOT result) - message (SEND_ERROR "cmake_language(CALL ${command}) unexpectedly successful.") - endif() -endforeach() +cmake_language(CALL ${command}) diff --git a/Tests/RunCMake/cmake_language/call_message.cmake b/Tests/RunCMake/cmake_language/call_message.cmake index 31aefdf..3b98c80 100644 --- a/Tests/RunCMake/cmake_language/call_message.cmake +++ b/Tests/RunCMake/cmake_language/call_message.cmake @@ -1 +1 @@ -cmake_language(CALL message WORKS!) +cmake_language(CALL ${empty} message WORKS!) diff --git a/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt b/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt index 9e2c08f..f6a0458 100644 --- a/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt +++ b/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt @@ -1,2 +1,2 @@ CMake Error at call_no_parameters.cmake:1 \(cmake_language\): - cmake_language called with incorrect number of arguments + cmake_language CALL missing command name diff --git a/Tests/RunCMake/cmake_language/defer_call-stderr.txt b/Tests/RunCMake/cmake_language/defer_call-stderr.txt new file mode 100644 index 0000000..7e8d8ca --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call-stderr.txt @@ -0,0 +1,15 @@ +^CMake Deprecation Warning at defer_call/CMakeLists.txt:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0053 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. ++ +CMake Warning at defer_call/CMakeLists.txt:3 \(message\): + Double-Deferred Warning In Subdirectory: + + '[^']*/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt:DEFERRED:id3' +Call Stack \(most recent call first\): + defer_call/CMakeLists.txt:DEFERRED$ diff --git a/Tests/RunCMake/cmake_language/defer_call-stdout.txt b/Tests/RunCMake/cmake_language/defer_call-stdout.txt new file mode 100644 index 0000000..fcf9f29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call-stdout.txt @@ -0,0 +1,8 @@ +-- Immediate Message In Subdirectory: ids='__0;__1' +-- Deferred Message In Subdirectory: '[^']*/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt:DEFERRED:id1' +-- Deferred Message In Included File: '[^']*/Tests/RunCMake/cmake_language/defer_call/include.cmake:1' +-- Immediate Message: ids='__0;__1;__2;__3;__4' +-- First Deferred Message +-- Deferred Message From Subdirectory +-- Deferred Message: ids='__4;__5' +-- Final Deferred Message diff --git a/Tests/RunCMake/cmake_language/defer_call.cmake b/Tests/RunCMake/cmake_language/defer_call.cmake new file mode 100644 index 0000000..2e9595f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call.cmake @@ -0,0 +1,12 @@ +set(message_command "message") +set(final_message "This should not be printed because variable evaluation is deferred too.") +cmake_language(DEFER CALL ${message_command} STATUS "First Deferred Message") +add_subdirectory(defer_call) +cmake_language(DEFER CALL cmake_language DEFER CALL "${final_message_command}" STATUS "${final_message}") +cmake_language(DEFER CALL cmake_language DEFER GET_CALL_IDS ids) +cmake_language(DEFER CALL cmake_language EVAL CODE [[message(STATUS "Deferred Message: ids='${ids}'")]]) +cmake_language(DEFER GET_CALL_IDS ids) +message(STATUS "Immediate Message: ids='${ids}'") +set(final_message_command "message") +set(final_message "Final Deferred Message") +set(subdir_message "Deferred Message From Subdirectory") diff --git a/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt new file mode 100644 index 0000000..544b9f4 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_policy(SET CMP0053 OLD) +cmake_language(DEFER ID id1 CALL message STATUS "Deferred Message In Subdirectory: '${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}'") +cmake_language(DEFER ID id2 CALL + cmake_language DEFER ID id3 CALL + message WARNING "Double-Deferred Warning In Subdirectory:\n '${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}'") +cmake_language(DEFER ID id4 CALL include "${CMAKE_CURRENT_LIST_DIR}/include.cmake") + +set(subdir_message "This should not be printed because variable evaluation is in deferred scope.") +cmake_language(DEFER DIRECTORY .. CALL message STATUS "${subdir_message}") +cmake_language(DEFER DIRECTORY .. GET_CALL_IDS ids) +message(STATUS "Immediate Message In Subdirectory: ids='${ids}'") diff --git a/Tests/RunCMake/cmake_language/defer_call/include.cmake b/Tests/RunCMake/cmake_language/defer_call/include.cmake new file mode 100644 index 0000000..272c61b --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call/include.cmake @@ -0,0 +1 @@ +message(STATUS "Deferred Message In Included File: '${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}'") diff --git a/Tests/RunCMake/FPHSA/range_empty-1-result.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/FPHSA/range_empty-1-result.txt +++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt diff --git a/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt new file mode 100644 index 0000000..ec20b8f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_call_add_subdirectory.cmake:1 \(add_subdirectory\): + Subdirectories may not be created during deferred execution. +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED ++ +CMake Error at defer_call_add_subdirectory.cmake:2 \(subdirs\): + Subdirectories may not be created during deferred execution. +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED$ diff --git a/Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake new file mode 100644 index 0000000..6b7ee63 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake @@ -0,0 +1,2 @@ +cmake_language(DEFER CALL add_subdirectory defer_call_add_subdirectory) +cmake_language(DEFER CALL subdirs defer_call_add_subdirectory) diff --git a/Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt diff --git a/Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt b/Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt new file mode 100644 index 0000000..65a0b99 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_call_enable_language.cmake:1 \(enable_language\): + Languages may not be enabled during deferred execution. +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED ++ +CMake Error at defer_call_enable_language.cmake:2 \(project\): + Languages may not be enabled during deferred execution. +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED$ diff --git a/Tests/RunCMake/cmake_language/defer_call_enable_language.cmake b/Tests/RunCMake/cmake_language/defer_call_enable_language.cmake new file mode 100644 index 0000000..eb43f80 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_enable_language.cmake @@ -0,0 +1,2 @@ +cmake_language(DEFER CALL enable_language C) +cmake_language(DEFER CALL project foo C) diff --git a/Tests/RunCMake/cmake_language/defer_call_error-result.txt b/Tests/RunCMake/cmake_language/defer_call_error-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_error-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_error-stderr.txt new file mode 100644 index 0000000..63ce145 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_error-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_call_error.cmake:2 \(message\): + Deferred Error +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED ++ +CMake Error at defer_call_error/CMakeLists.txt:2 \(message\): + Deferred Error from Subdirectory +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED$ diff --git a/Tests/RunCMake/cmake_language/defer_call_error.cmake b/Tests/RunCMake/cmake_language/defer_call_error.cmake new file mode 100644 index 0000000..083e82a --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_error.cmake @@ -0,0 +1,3 @@ +# Error message backtrace points here but call stack shows DEFERRED execution. +cmake_language(DEFER CALL message SEND_ERROR "Deferred Error") +add_subdirectory(defer_call_error) diff --git a/Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt new file mode 100644 index 0000000..0acac69 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt @@ -0,0 +1,2 @@ +# Error message backtrace points here but call stack shows DEFERRED execution in parent. +cmake_language(DEFER DIRECTORY .. CALL message SEND_ERROR "Deferred Error from Subdirectory") diff --git a/Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt b/Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt new file mode 100644 index 0000000..2fd194d --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt @@ -0,0 +1,13 @@ +-- Immediate Message: ids='message0;getCallIds1;messageIds1;cancelCall;getCallIds2;messageIds2;toBeCancelled;message3' +-- Immediate Message: message0='message;STATUS;First Deferred Message' +-- Immediate Message: getCallIds1='cmake_language;DEFER;GET_CALL_IDS;ids' +-- Immediate Message: messageIds1='cmake_language;EVAL;CODE;message\(STATUS "Deferred Message: ids='\${ids}'"\)' +-- Immediate Message: cancelCall='cmake_language;DEFER;CANCEL_CALL;toBeCancelled' +-- Immediate Message: getCallIds2='cmake_language;DEFER;GET_CALL_IDS;ids' +-- Immediate Message: messageIds2='cmake_language;EVAL;CODE;message\(STATUS "Deferred Message: ids='\${ids}'"\)' +-- Immediate Message: toBeCancelled='message;STATUS;Cancelled Message' +-- Immediate Message: message3='message;STATUS;Final Deferred Message' +-- First Deferred Message +-- Deferred Message: ids='messageIds1;cancelCall;getCallIds2;messageIds2;toBeCancelled;message3' +-- Deferred Message: ids='messageIds2;message3' +-- Final Deferred Message diff --git a/Tests/RunCMake/cmake_language/defer_call_ids.cmake b/Tests/RunCMake/cmake_language/defer_call_ids.cmake new file mode 100644 index 0000000..2874894 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_ids.cmake @@ -0,0 +1,14 @@ +cmake_language(DEFER ID message0 CALL message STATUS "First Deferred Message") +cmake_language(DEFER ID getCallIds1 CALL cmake_language DEFER GET_CALL_IDS ids) +cmake_language(DEFER ID messageIds1 CALL cmake_language EVAL CODE [[message(STATUS "Deferred Message: ids='${ids}'")]]) +cmake_language(DEFER ID cancelCall CALL cmake_language DEFER CANCEL_CALL toBeCancelled) +cmake_language(DEFER ID getCallIds2 CALL cmake_language DEFER GET_CALL_IDS ids) +cmake_language(DEFER ID messageIds2 CALL cmake_language EVAL CODE [[message(STATUS "Deferred Message: ids='${ids}'")]]) +cmake_language(DEFER ID toBeCancelled CALL message STATUS "Cancelled Message") +cmake_language(DEFER ID message3 CALL message STATUS "Final Deferred Message") +cmake_language(DEFER GET_CALL_IDS ids) +message(STATUS "Immediate Message: ids='${ids}'") +foreach(id ${ids}) + cmake_language(DEFER GET_CALL ${id} call) + message(STATUS "Immediate Message: ${id}='${call}'") +endforeach() diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt new file mode 100644 index 0000000..4cdbf0c --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_call_invalid_command.cmake:1 \(cmake_language\): + cmake_language invalid command specified: [A-Za-z_]+ +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake b/Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake new file mode 100644 index 0000000..d6cc936 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake @@ -0,0 +1 @@ +cmake_language(DEFER CALL ${command}) diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt new file mode 100644 index 0000000..afe9a0e --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_call_invalid_directory.cmake:2 \(cmake_language\): + cmake_language DEFER CALL may not be scheduled in directory: + + [^ +]*/Tests/RunCMake/cmake_language/defer_call_invalid_directory-build/defer_call_invalid_directory + + at this time. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake b/Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake new file mode 100644 index 0000000..cc1eb8d --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake @@ -0,0 +1,2 @@ +add_subdirectory(defer_call_invalid_directory) +cmake_language(DEFER DIRECTORY defer_call_invalid_directory CALL message "Should not be allowed.") diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt diff --git a/Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt b/Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt new file mode 100644 index 0000000..db4f90e --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_call_missing_directory.cmake:1 \(cmake_language\): + cmake_language DEFER DIRECTORY: + + [^ +]*/Tests/RunCMake/cmake_language/does_not_exist + + is not known. It may not have been processed yet. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake b/Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake new file mode 100644 index 0000000..01f4c40 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake @@ -0,0 +1 @@ +cmake_language(DEFER DIRECTORY does_not_exist CALL message "Should not be allowed.") diff --git a/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt new file mode 100644 index 0000000..923be13 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error at CMakeLists.txt:DEFERRED: + cmake_policy PUSH without matching POP$ diff --git a/Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake new file mode 100644 index 0000000..66cb760 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake @@ -0,0 +1 @@ +cmake_language(DEFER CALL cmake_policy PUSH) diff --git a/Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt b/Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt new file mode 100644 index 0000000..80db4aa --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt @@ -0,0 +1,13 @@ +^CMake Error at defer_call_syntax_error.cmake:2 \(message\): + Syntax error in cmake code at + + [^ +]*/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake:2 + + when parsing string + + Deferred \\X Error + + Invalid character escape '\\X'. +Call Stack \(most recent call first\): + CMakeLists.txt:DEFERRED$ diff --git a/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake b/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake new file mode 100644 index 0000000..c3c044b --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake @@ -0,0 +1,2 @@ +# Argument syntax error evaluated at deferred call site. +cmake_language(DEFER CALL message "Deferred \X Error") diff --git a/Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt new file mode 100644 index 0000000..b61b236 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt @@ -0,0 +1,8 @@ +[^ +]*/Tests/RunCMake/cmake_language/defer_call_trace.cmake\(2\): cmake_language\(DEFER CALL message Deferred Message \) +[^ +]*/Tests/RunCMake/cmake_language/defer_call_trace.cmake\(3\): message\(Immediate Message \) +Immediate Message +[^ +]*/Tests/RunCMake/cmake_language/defer_call_trace.cmake\(2\):DEFERRED:__0: message\(Deferred Message \) +Deferred Message$ diff --git a/Tests/RunCMake/cmake_language/defer_call_trace.cmake b/Tests/RunCMake/cmake_language/defer_call_trace.cmake new file mode 100644 index 0000000..5ed383f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_trace.cmake @@ -0,0 +1,3 @@ +# The --trace and --trace-expand output point here for deferred call. +cmake_language(DEFER CALL message "Deferred Message") +message("Immediate Message") diff --git a/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt new file mode 100644 index 0000000..647beb0 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt @@ -0,0 +1,5 @@ +{"args":\["DEFER","CALL","message","Deferred Message"\],"cmd":"cmake_language","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"line":2,"time":[0-9.]+} +{"args":\["Immediate Message"\],"cmd":"message","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"line":3,"time":[0-9.]+} +Immediate Message +{"args":\["Deferred Message"],"cmd":"message","defer":"__0","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":1,"line":2,"time":[0-9.]+} +Deferred Message$ diff --git a/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake b/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake new file mode 100644 index 0000000..5ed383f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake @@ -0,0 +1,3 @@ +# The --trace and --trace-expand output point here for deferred call. +cmake_language(DEFER CALL message "Deferred Message") +message("Immediate Message") diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt new file mode 100644 index 0000000..8a13c0d --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_cancel_call_id.cmake:1 \(cmake_language\): + cmake_language DEFER CANCEL_CALL does not accept ID or ID_VAR. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake new file mode 100644 index 0000000..6e5b5c8 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID id CANCEL_CALL) diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt new file mode 100644 index 0000000..5783c50 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_cancel_call_id_var.cmake:1 \(cmake_language\): + cmake_language DEFER CANCEL_CALL does not accept ID or ID_VAR. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake new file mode 100644 index 0000000..9f75221 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID_VAR id_var CANCEL_CALL) diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt new file mode 100644 index 0000000..cacbf9a --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_cancel_call_invalid_directory.cmake:2 \(cmake_language\): + cmake_language DEFER CANCEL_CALL may not update directory: + + [^ +]*/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-build/defer_cancel_call_invalid_directory + + at this time. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake new file mode 100644 index 0000000..29a8fc2 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake @@ -0,0 +1,2 @@ +add_subdirectory(defer_cancel_call_invalid_directory) +cmake_language(DEFER DIRECTORY defer_cancel_call_invalid_directory CANCEL_CALL _) diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt new file mode 100644 index 0000000..eb8f2b9 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at defer_cancel_call_unknown_argument.cmake:1 \(cmake_language\): + cmake_language DEFER CANCEL_CALL unknown argument: + + UNKNOWN +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake new file mode 100644 index 0000000..fbc6309 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake @@ -0,0 +1 @@ +cmake_language(DEFER CANCEL_CALL UNKNOWN) diff --git a/Tests/RunCMake/cmake_language/defer_directory_empty-result.txt b/Tests/RunCMake/cmake_language/defer_directory_empty-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_empty-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt new file mode 100644 index 0000000..587dfa9 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_directory_empty.cmake:1 \(cmake_language\): + cmake_language DEFER DIRECTORY may not be empty +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_directory_empty.cmake b/Tests/RunCMake/cmake_language/defer_directory_empty.cmake new file mode 100644 index 0000000..f4e4553 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_empty.cmake @@ -0,0 +1 @@ +cmake_language(DEFER DIRECTORY "") diff --git a/Tests/RunCMake/cmake_language/defer_directory_missing-result.txt b/Tests/RunCMake/cmake_language/defer_directory_missing-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_missing-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt b/Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt new file mode 100644 index 0000000..1db8e99 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_directory_missing.cmake:1 \(cmake_language\): + cmake_language DEFER DIRECTORY missing value +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_directory_missing.cmake b/Tests/RunCMake/cmake_language/defer_directory_missing.cmake new file mode 100644 index 0000000..fbdb177 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_missing.cmake @@ -0,0 +1 @@ +cmake_language(DEFER DIRECTORY) diff --git a/Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt b/Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt b/Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt new file mode 100644 index 0000000..f4d09b9 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_directory_multiple.cmake:1 \(cmake_language\): + cmake_language DEFER given multiple DIRECTORY arguments +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_directory_multiple.cmake b/Tests/RunCMake/cmake_language/defer_directory_multiple.cmake new file mode 100644 index 0000000..baf037b --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_directory_multiple.cmake @@ -0,0 +1 @@ +cmake_language(DEFER DIRECTORY . DIRECTORY x CALL message "Should not be allowed.") diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_id-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt new file mode 100644 index 0000000..e161a5f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_id.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL does not accept ID or ID_VAR. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id.cmake b/Tests/RunCMake/cmake_language/defer_get_call_id.cmake new file mode 100644 index 0000000..7a395ea --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID id GET_CALL) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt new file mode 100644 index 0000000..c7c534b --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_id_empty.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL id may not be empty +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake b/Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake new file mode 100644 index 0000000..4f39f2d --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL "" var) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt new file mode 100644 index 0000000..2cfd942 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_id_var.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL does not accept ID or ID_VAR. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake new file mode 100644 index 0000000..ade0815 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID_VAR id_var GET_CALL) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt new file mode 100644 index 0000000..072ee45 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_ids_id.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL_IDS does not accept ID or ID_VAR. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake new file mode 100644 index 0000000..4eb2555 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID id GET_CALL_IDS) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt new file mode 100644 index 0000000..e4a288c --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_ids_id_var.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL_IDS does not accept ID or ID_VAR. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake new file mode 100644 index 0000000..c27de79 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID_VAR id_var GET_CALL_IDS) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt new file mode 100644 index 0000000..edebe32 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at defer_get_call_ids_invalid_directory.cmake:2 \(cmake_language\): + cmake_language DEFER GET_CALL_IDS may not access directory: + + [^ +]*/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-build/defer_get_call_ids_invalid_directory + + at this time. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake new file mode 100644 index 0000000..81f098e --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake @@ -0,0 +1,2 @@ +add_subdirectory(defer_get_call_ids_invalid_directory) +cmake_language(DEFER DIRECTORY defer_get_call_ids_invalid_directory GET_CALL_IDS var) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt new file mode 100644 index 0000000..a2951cf --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_ids_missing_var.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL_IDS missing output variable +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake new file mode 100644 index 0000000..b171f04 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL_IDS) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt new file mode 100644 index 0000000..5691519 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_ids_too_many_args.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL_IDS given too many arguments +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake new file mode 100644 index 0000000..0158684 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL_IDS var extra) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt new file mode 100644 index 0000000..081aa95 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_missing_id.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL missing id +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake b/Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake new file mode 100644 index 0000000..0542abc --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt new file mode 100644 index 0000000..1b2641f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_missing_var.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL missing output variable +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake new file mode 100644 index 0000000..7916d29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL id) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt new file mode 100644 index 0000000..b6ee2d6 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_get_call_too_many_args.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL given too many arguments +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake new file mode 100644 index 0000000..ed65779 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL id var extra) diff --git a/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt new file mode 100644 index 0000000..ac16596 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at defer_get_call_unknown_argument.cmake:1 \(cmake_language\): + cmake_language DEFER GET_CALL unknown argument: + + UNKNOWN +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake new file mode 100644 index 0000000..d0caa39 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake @@ -0,0 +1 @@ +cmake_language(DEFER GET_CALL UNKNOWN var) diff --git a/Tests/RunCMake/cmake_language/defer_id_empty-result.txt b/Tests/RunCMake/cmake_language/defer_id_empty-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_empty-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt new file mode 100644 index 0000000..1e7f772 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_id_empty.cmake:1 \(cmake_language\): + cmake_language DEFER ID may not be empty +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_id_empty.cmake b/Tests/RunCMake/cmake_language/defer_id_empty.cmake new file mode 100644 index 0000000..326762c --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_empty.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID "") diff --git a/Tests/RunCMake/cmake_language/defer_id_missing-result.txt b/Tests/RunCMake/cmake_language/defer_id_missing-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_missing-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt new file mode 100644 index 0000000..cef5f0e --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_id_missing.cmake:1 \(cmake_language\): + cmake_language DEFER ID missing value +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_id_missing.cmake b/Tests/RunCMake/cmake_language/defer_id_missing.cmake new file mode 100644 index 0000000..4de687d --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_missing.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID) diff --git a/Tests/RunCMake/cmake_language/defer_id_multiple-result.txt b/Tests/RunCMake/cmake_language/defer_id_multiple-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_multiple-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt new file mode 100644 index 0000000..1725521 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_id_multiple.cmake:1 \(cmake_language\): + cmake_language DEFER given multiple ID arguments +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_id_multiple.cmake b/Tests/RunCMake/cmake_language/defer_id_multiple.cmake new file mode 100644 index 0000000..69187af --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_multiple.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID a ID b CALL message "Should not be allowed.") diff --git a/Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt b/Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt new file mode 100644 index 0000000..bb5cd43 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_id_var_empty.cmake:1 \(cmake_language\): + cmake_language DEFER ID_VAR may not be empty +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_id_var_empty.cmake b/Tests/RunCMake/cmake_language/defer_id_var_empty.cmake new file mode 100644 index 0000000..c7198f5 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_empty.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID_VAR "") diff --git a/Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt b/Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt new file mode 100644 index 0000000..f4e0d6e --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_id_var_missing.cmake:1 \(cmake_language\): + cmake_language DEFER ID_VAR missing variable name +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_id_var_missing.cmake b/Tests/RunCMake/cmake_language/defer_id_var_missing.cmake new file mode 100644 index 0000000..359d149 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_missing.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID_VAR) diff --git a/Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt b/Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt new file mode 100644 index 0000000..4368b06 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_id_var_multiple.cmake:1 \(cmake_language\): + cmake_language DEFER given multiple ID_VAR arguments +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake b/Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake new file mode 100644 index 0000000..665ea94 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake @@ -0,0 +1 @@ +cmake_language(DEFER ID_VAR a ID_VAR b CALL message "Should not be allowed.") diff --git a/Tests/RunCMake/cmake_language/defer_missing_arg-result.txt b/Tests/RunCMake/cmake_language/defer_missing_arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_missing_arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt b/Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt new file mode 100644 index 0000000..3e656cd --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_missing_arg.cmake:1 \(cmake_language\): + cmake_language DEFER requires at least one argument +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_missing_arg.cmake b/Tests/RunCMake/cmake_language/defer_missing_arg.cmake new file mode 100644 index 0000000..737a8c8 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_missing_arg.cmake @@ -0,0 +1 @@ +cmake_language(DEFER) diff --git a/Tests/RunCMake/cmake_language/defer_missing_call-result.txt b/Tests/RunCMake/cmake_language/defer_missing_call-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_missing_call-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt b/Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt new file mode 100644 index 0000000..7eeef76 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at defer_missing_call.cmake:1 \(cmake_language\): + cmake_language DEFER must be followed by a CALL argument +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_missing_call.cmake b/Tests/RunCMake/cmake_language/defer_missing_call.cmake new file mode 100644 index 0000000..0b330ef --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_missing_call.cmake @@ -0,0 +1 @@ +cmake_language(DEFER DIRECTORY .) diff --git a/Tests/RunCMake/cmake_language/defer_unknown_option-result.txt b/Tests/RunCMake/cmake_language/defer_unknown_option-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_unknown_option-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt b/Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt new file mode 100644 index 0000000..95d87c6 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at defer_unknown_option.cmake:1 \(cmake_language\): + cmake_language DEFER unknown option: + + UNKNOWN +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/cmake_language/defer_unknown_option.cmake b/Tests/RunCMake/cmake_language/defer_unknown_option.cmake new file mode 100644 index 0000000..876b3f1 --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_unknown_option.cmake @@ -0,0 +1 @@ +cmake_language(DEFER UNKNOWN) diff --git a/Tests/RunCMake/cmake_language/no_parameters-stderr.txt b/Tests/RunCMake/cmake_language/no_parameters-stderr.txt index 194bbe3..1862c77 100644 --- a/Tests/RunCMake/cmake_language/no_parameters-stderr.txt +++ b/Tests/RunCMake/cmake_language/no_parameters-stderr.txt @@ -1,2 +1,2 @@ CMake Error at no_parameters.cmake:1 \(cmake_language\): - cmake_language called with incorrect number of arguments + cmake_language CALL missing command name diff --git a/Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake b/Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake new file mode 100644 index 0000000..feac3ce --- /dev/null +++ b/Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake @@ -0,0 +1,12 @@ +file(GLOB build_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Build.xml") +if(build_xml_file) + file(READ "${build_xml_file}" build_xml LIMIT 4096) + if(NOT build_xml MATCHES [[this command failed]]) + string(REPLACE "\n" "\n " build_xml " ${build_xml}") + set(RunCMake_TEST_FAILED + "Build.xml does not have expected error message:\n${build_xml}" + ) + endif() +else() + set(RunCMake_TEST_FAILED "Build.xml not found") +endif() diff --git a/Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt b/Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt b/Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt new file mode 100644 index 0000000..bbe9410 --- /dev/null +++ b/Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt @@ -0,0 +1 @@ +^Error\(s\) when building project diff --git a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake index b2e562a..072fbac 100644 --- a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake @@ -48,8 +48,12 @@ function(run_BuildChangeId) endfunction() run_BuildChangeId() -set(RunCMake_USE_LAUNCHERS FALSE) set(RunCMake_USE_CUSTOM_BUILD_COMMAND TRUE) +set(RunCMake_BUILD_COMMAND "${FAKE_BUILD_COMMAND_EXE}") +run_ctest(BuildCommandFailure) +unset(RunCMake_BUILD_COMMAND) + +set(RunCMake_USE_LAUNCHERS FALSE) set(RunCMake_BUILD_COMMAND "${COLOR_WARNING}") run_ctest(IgnoreColor) unset(RunCMake_BUILD_COMMAND) diff --git a/Tests/RunCMake/fake_build_command.c b/Tests/RunCMake/fake_build_command.c new file mode 100644 index 0000000..d87335b --- /dev/null +++ b/Tests/RunCMake/fake_build_command.c @@ -0,0 +1,6 @@ +#include <stdio.h> +int main(void) +{ + printf("this command failed\n"); + return 1; +} diff --git a/Tests/RunCMake/find_package/EmptyVersionRange-result.txt b/Tests/RunCMake/find_package/EmptyVersionRange-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/find_package/EmptyVersionRange-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt b/Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt new file mode 100644 index 0000000..9c00b96 --- /dev/null +++ b/Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt @@ -0,0 +1,10 @@ +CMake Error at EmptyVersionRange.cmake:[0-9]+ \(find_package\): + find_package specified version range is empty. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) + + +CMake Error at EmptyVersionRange.cmake:[0-9]+ \(find_package\): + find_package specified version range is empty. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/find_package/EmptyVersionRange.cmake b/Tests/RunCMake/find_package/EmptyVersionRange.cmake new file mode 100644 index 0000000..553e297 --- /dev/null +++ b/Tests/RunCMake/find_package/EmptyVersionRange.cmake @@ -0,0 +1,3 @@ +find_package(VersionRange 2.3...1.2) + +find_package(VersionRange 2.3...<2.3) diff --git a/Tests/RunCMake/find_package/FindVersionRange.cmake b/Tests/RunCMake/find_package/FindVersionRange.cmake index ff84e93..27e5b90 100644 --- a/Tests/RunCMake/find_package/FindVersionRange.cmake +++ b/Tests/RunCMake/find_package/FindVersionRange.cmake @@ -3,19 +3,19 @@ if (NOT VersionRange_FIND_VERSION_COMPLETE STREQUAL VersionRange_SPECIFIED_VERSI message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_COMPLETE: ${VersionRange_FIND_VERSION_COMPLETE}") endif() -if (NOT VersionRange_FIND_VERSION VERSION_EQUAL "1.2.3.4") +if (NOT VersionRange_FIND_VERSION VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION: ${VersionRange_FIND_VERSION}") endif() -if (NOT VersionRange_FIND_VERSION_MAJOR VERSION_EQUAL "1") +if (NOT VersionRange_FIND_VERSION_MAJOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MAJOR) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MAJOR: ${VersionRange_FIND_VERSION_MAJOR}") endif() -if (NOT VersionRange_FIND_VERSION_MINOR VERSION_EQUAL "2") +if (NOT VersionRange_FIND_VERSION_MINOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MINOR) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MINOR: ${VersionRange_FIND_VERSION_MINOR}") endif() -if (NOT VersionRange_FIND_VERSION_PATCH VERSION_EQUAL "3") +if (NOT VersionRange_FIND_VERSION_PATCH VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_PATCH) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_PATCH: ${VersionRange_FIND_VERSION_PATCH}") endif() -if (NOT VersionRange_FIND_VERSION_TWEAK VERSION_EQUAL "4") +if (NOT VersionRange_FIND_VERSION_TWEAK VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_TWEAK) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_TWEAK: ${VersionRange_FIND_VERSION_TWEAK}") endif() @@ -35,19 +35,19 @@ else() endif() endif() -if (NOT VersionRange_FIND_VERSION_MIN VERSION_EQUAL "1.2.3.4") - message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN: ${VersionRange_FIND_VERSION}") +if (NOT VersionRange_FIND_VERSION_MIN VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN) + message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN: ${VersionRange_FIND_VERSION_MIN}") endif() -if (NOT VersionRange_FIND_VERSION_MIN_MAJOR VERSION_EQUAL "1") +if (NOT VersionRange_FIND_VERSION_MIN_MAJOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MAJOR) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_MAJOR: ${VersionRange_FIND_VERSION_MIN_MAJOR}") endif() -if (NOT VersionRange_FIND_VERSION_MIN_MINOR VERSION_EQUAL "2") +if (NOT VersionRange_FIND_VERSION_MIN_MINOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MINOR) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_MINOR: ${VersionRange_FIND_VERSION_MIN_MINOR}") endif() -if (NOT VersionRange_FIND_VERSION_MIN_PATCH VERSION_EQUAL "3") +if (NOT VersionRange_FIND_VERSION_MIN_PATCH VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_PATCH) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_PATCH: ${VersionRange_FIND_VERSION_MIN_PATCH}") endif() -if (NOT VersionRange_FIND_VERSION_MIN_TWEAK VERSION_EQUAL "4") +if (NOT VersionRange_FIND_VERSION_MIN_TWEAK VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_TWEAK) message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_TWEAK: ${VersionRange_FIND_VERSION_MIN_TWEAK}") endif() diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake index 7755a70..a899f46 100644 --- a/Tests/RunCMake/find_package/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake @@ -30,10 +30,12 @@ run_cmake(CMP0084-OLD) run_cmake(CMP0084-WARN) run_cmake(CMP0084-NEW) run_cmake(WrongVersionRange) +run_cmake(EmptyVersionRange) run_cmake(VersionRangeWithEXACT) run_cmake(VersionRange) run_cmake(VersionRange2) run_cmake(VersionRange3) +run_cmake(VersionRange4) run_cmake(VersionRangeConfig) run_cmake(VersionRangeConfig2) run_cmake(VersionRangeConfigStd) diff --git a/Tests/RunCMake/find_package/VersionRange.cmake b/Tests/RunCMake/find_package/VersionRange.cmake index b3d8950..30b88a8 100644 --- a/Tests/RunCMake/find_package/VersionRange.cmake +++ b/Tests/RunCMake/find_package/VersionRange.cmake @@ -3,6 +3,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") set (VersionRange_SPECIFIED_VERSION_COMPLETE 1.2.3.4...5.6.7.8) set (VersionRange_SPECIFIED_VERSION_RANGE 1.2.3.4...5.6.7.8) +set (VersionRange_SPECIFIED_VERSION_MIN 1.2.3.4) +set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 1) +set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 2) +set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 3) +set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 4) set (VersionRange_SPECIFIED_VERSION_MAX 5.6.7.8) set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 5) set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 6) diff --git a/Tests/RunCMake/find_package/VersionRange2.cmake b/Tests/RunCMake/find_package/VersionRange2.cmake index d0e685b..9adcc64 100644 --- a/Tests/RunCMake/find_package/VersionRange2.cmake +++ b/Tests/RunCMake/find_package/VersionRange2.cmake @@ -3,6 +3,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") set (VersionRange_SPECIFIED_VERSION_COMPLETE 1.2.3.4...<5.6.7.8) set (VersionRange_SPECIFIED_VERSION_RANGE 1.2.3.4...<5.6.7.8) +set (VersionRange_SPECIFIED_VERSION_MIN 1.2.3.4) +set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 1) +set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 2) +set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 3) +set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 4) set (VersionRange_SPECIFIED_VERSION_MAX 5.6.7.8) set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 5) set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 6) diff --git a/Tests/RunCMake/find_package/VersionRange3.cmake b/Tests/RunCMake/find_package/VersionRange3.cmake index 76eef1d..41efac4 100644 --- a/Tests/RunCMake/find_package/VersionRange3.cmake +++ b/Tests/RunCMake/find_package/VersionRange3.cmake @@ -5,6 +5,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") set (VersionRange_SPECIFIED_VERSION_COMPLETE 1.2.3.4...<2.3.4.5) set (VersionRange_SPECIFIED_VERSION_RANGE 1.2.3.4...<2.3.4.5) +set (VersionRange_SPECIFIED_VERSION_MIN 1.2.3.4) +set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 1) +set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 2) +set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 3) +set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 4) set (VersionRange_SPECIFIED_VERSION_MAX 2.3.4.5) set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 2) set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 3) diff --git a/Tests/RunCMake/find_package/VersionRange4.cmake b/Tests/RunCMake/find_package/VersionRange4.cmake new file mode 100644 index 0000000..0953d04 --- /dev/null +++ b/Tests/RunCMake/find_package/VersionRange4.cmake @@ -0,0 +1,39 @@ + +# show the effect of the exclusion or inclusion of the upper endpoint + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") + +set (VersionRange_SPECIFIED_VERSION_COMPLETE 2.3.4.5...2.3.4.5) +set (VersionRange_SPECIFIED_VERSION_RANGE 2.3.4.5...2.3.4.5) +set (VersionRange_SPECIFIED_VERSION_MIN 2.3.4.5) +set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 2) +set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 3) +set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 4) +set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 5) +set (VersionRange_SPECIFIED_VERSION_MAX 2.3.4.5) +set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 2) +set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 3) +set (VersionRange_SPECIFIED_VERSION_MAX_PATCH 4) +set (VersionRange_SPECIFIED_VERSION_MAX_TWEAK 5) + +find_package (VersionRange ${VersionRange_SPECIFIED_VERSION_RANGE}) + +if (NOT VersionRange_FOUND) + message (FATAL_ERROR "Package VersionRange not found.") +endif() + +if (NOT VersionRange_VERSION VERSION_EQUAL "2.3.4.5") + message (SEND_ERROR "Wrong version : ${VersionRange_VERSION}") +endif() +if (NOT VersionRange_VERSION_MAJOR VERSION_EQUAL "2") + message (SEND_ERROR "Wrong major version : ${VersionRange_VERSION_MAJOR}") +endif() +if (NOT VersionRange_VERSION_MINOR VERSION_EQUAL "3") + message (SEND_ERROR "Wrong minor version : ${VersionRange_VERSION_MINOR}") +endif() +if (NOT VersionRange_VERSION_PATCH VERSION_EQUAL "4") + message (SEND_ERROR "Wrong patch version : ${VersionRange_VERSION_PATCH}") +endif() +if (NOT VersionRange_VERSION_TWEAK VERSION_EQUAL "5") + message (SEND_ERROR "Wrong tweak version : ${VersionRange_VERSION_TWEAK}") +endif() diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index 7625cf6..92d2411 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -336,6 +336,24 @@ if(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") ) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "QNX") + list(APPEND uv_headers + include/uv/posix.h + ) + list(APPEND uv_defines + _XOPEN_SOURCE=700 + ) + list(APPEND uv_sources + src/unix/posix-hrtime.c + src/unix/posix-poll.c + src/unix/no-fsevents.c + src/unix/no-proctitle.c + ) + list(APPEND uv_libraries + socket + ) +endif() + include_directories( ${uv_includes} ${KWSYS_HEADER_ROOT} @@ -1675,6 +1675,10 @@ else uv_c_flags="${uv_c_flags} -D__EXTENSIONS__ -D_XOPEN_SOURCE=600" libs="${libs} -lkstat -lnsl -lsendfile -lsocket -lrt" ;; + *QNX*) + uv_c_flags="${uv_c_flags} -D_XOPEN_SOURCE=700" + libs="${libs} -lsocket" + ;; esac fi if test "x${bootstrap_system_libuv}" = "x"; then |