From e8b0359a4318bb682c96e527de7ed7f5be02c38f Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 21 Sep 2020 13:51:35 -0400 Subject: cmake_language: Add signature to DEFER calls to later times Fixes: #19575 --- Help/command/cmake_language.rst | 119 +++++++++++ Help/command/return.rst | 1 + Help/manual/cmake.1.rst | 7 +- Help/release/dev/cmake_language-DEFER.rst | 5 + Help/variable/CMAKE_CURRENT_LIST_LINE.rst | 4 + Source/cmCMakeLanguageCommand.cxx | 220 ++++++++++++++++++++- Source/cmCommandArgumentParserHelper.cxx | 12 +- Source/cmGlobalGenerator.cxx | 7 + Source/cmGlobalGenerator.h | 5 + Source/cmListFileCache.cxx | 7 +- Source/cmListFileCache.h | 10 +- Source/cmMakefile.cxx | 190 ++++++++++++++++-- Source/cmMakefile.h | 37 +++- Source/cmState.cxx | 15 ++ Source/cmState.h | 2 + Source/cmStateTypes.h | 1 + Source/cmake.cxx | 2 +- Tests/RunCMake/CommandLine/trace-json-v1-check.py | 2 +- Tests/RunCMake/cmake_language/RunCMakeTest.cmake | 50 +++++ .../RunCMake/cmake_language/defer_call-stderr.txt | 15 ++ .../RunCMake/cmake_language/defer_call-stdout.txt | 8 + Tests/RunCMake/cmake_language/defer_call.cmake | 12 ++ .../cmake_language/defer_call/CMakeLists.txt | 11 ++ .../cmake_language/defer_call/include.cmake | 1 + .../defer_call_add_subdirectory-result.txt | 1 + .../defer_call_add_subdirectory-stderr.txt | 9 + .../defer_call_add_subdirectory.cmake | 2 + .../defer_call_add_subdirectory/CMakeLists.txt | 0 .../defer_call_enable_language-result.txt | 1 + .../defer_call_enable_language-stderr.txt | 9 + .../defer_call_enable_language.cmake | 2 + .../cmake_language/defer_call_error-result.txt | 1 + .../cmake_language/defer_call_error-stderr.txt | 9 + .../RunCMake/cmake_language/defer_call_error.cmake | 3 + .../cmake_language/defer_call_error/CMakeLists.txt | 2 + .../cmake_language/defer_call_ids-stdout.txt | 13 ++ Tests/RunCMake/cmake_language/defer_call_ids.cmake | 14 ++ .../defer_call_invalid_command-result.txt | 1 + .../defer_call_invalid_command-stderr.txt | 4 + .../defer_call_invalid_command.cmake | 1 + .../defer_call_invalid_directory-result.txt | 1 + .../defer_call_invalid_directory-stderr.txt | 9 + .../defer_call_invalid_directory.cmake | 2 + .../defer_call_invalid_directory/CMakeLists.txt | 0 .../defer_call_missing_directory-result.txt | 1 + .../defer_call_missing_directory-stderr.txt | 9 + .../defer_call_missing_directory.cmake | 1 + .../defer_call_policy_PUSH-result.txt | 1 + .../defer_call_policy_PUSH-stderr.txt | 2 + .../cmake_language/defer_call_policy_PUSH.cmake | 1 + .../defer_call_syntax_error-result.txt | 1 + .../defer_call_syntax_error-stderr.txt | 13 ++ .../cmake_language/defer_call_syntax_error.cmake | 2 + .../cmake_language/defer_call_trace-stderr.txt | 8 + .../RunCMake/cmake_language/defer_call_trace.cmake | 3 + .../defer_call_trace_json-stderr.txt | 5 + .../cmake_language/defer_call_trace_json.cmake | 3 + .../cmake_language/defer_cancel_call_id-result.txt | 1 + .../cmake_language/defer_cancel_call_id-stderr.txt | 4 + .../cmake_language/defer_cancel_call_id.cmake | 1 + .../defer_cancel_call_id_var-result.txt | 1 + .../defer_cancel_call_id_var-stderr.txt | 4 + .../cmake_language/defer_cancel_call_id_var.cmake | 1 + .../defer_cancel_call_invalid_directory-result.txt | 1 + .../defer_cancel_call_invalid_directory-stderr.txt | 9 + .../defer_cancel_call_invalid_directory.cmake | 2 + .../CMakeLists.txt | 0 .../defer_cancel_call_unknown_argument-result.txt | 1 + .../defer_cancel_call_unknown_argument-stderr.txt | 6 + .../defer_cancel_call_unknown_argument.cmake | 1 + .../defer_directory_empty-result.txt | 1 + .../defer_directory_empty-stderr.txt | 4 + .../cmake_language/defer_directory_empty.cmake | 1 + .../defer_directory_missing-result.txt | 1 + .../defer_directory_missing-stderr.txt | 4 + .../cmake_language/defer_directory_missing.cmake | 1 + .../defer_directory_multiple-result.txt | 1 + .../defer_directory_multiple-stderr.txt | 4 + .../cmake_language/defer_directory_multiple.cmake | 1 + .../cmake_language/defer_get_call_id-result.txt | 1 + .../cmake_language/defer_get_call_id-stderr.txt | 4 + .../cmake_language/defer_get_call_id.cmake | 1 + .../defer_get_call_id_empty-result.txt | 1 + .../defer_get_call_id_empty-stderr.txt | 4 + .../cmake_language/defer_get_call_id_empty.cmake | 1 + .../defer_get_call_id_var-result.txt | 1 + .../defer_get_call_id_var-stderr.txt | 4 + .../cmake_language/defer_get_call_id_var.cmake | 1 + .../defer_get_call_ids_id-result.txt | 1 + .../defer_get_call_ids_id-stderr.txt | 4 + .../cmake_language/defer_get_call_ids_id.cmake | 1 + .../defer_get_call_ids_id_var-result.txt | 1 + .../defer_get_call_ids_id_var-stderr.txt | 4 + .../cmake_language/defer_get_call_ids_id_var.cmake | 1 + ...defer_get_call_ids_invalid_directory-result.txt | 1 + ...defer_get_call_ids_invalid_directory-stderr.txt | 9 + .../defer_get_call_ids_invalid_directory.cmake | 2 + .../CMakeLists.txt | 0 .../defer_get_call_ids_missing_var-result.txt | 1 + .../defer_get_call_ids_missing_var-stderr.txt | 4 + .../defer_get_call_ids_missing_var.cmake | 1 + .../defer_get_call_ids_too_many_args-result.txt | 1 + .../defer_get_call_ids_too_many_args-stderr.txt | 4 + .../defer_get_call_ids_too_many_args.cmake | 1 + .../defer_get_call_missing_id-result.txt | 1 + .../defer_get_call_missing_id-stderr.txt | 4 + .../cmake_language/defer_get_call_missing_id.cmake | 1 + .../defer_get_call_missing_var-result.txt | 1 + .../defer_get_call_missing_var-stderr.txt | 4 + .../defer_get_call_missing_var.cmake | 1 + .../defer_get_call_too_many_args-result.txt | 1 + .../defer_get_call_too_many_args-stderr.txt | 4 + .../defer_get_call_too_many_args.cmake | 1 + .../defer_get_call_unknown_argument-result.txt | 1 + .../defer_get_call_unknown_argument-stderr.txt | 6 + .../defer_get_call_unknown_argument.cmake | 1 + .../cmake_language/defer_id_empty-result.txt | 1 + .../cmake_language/defer_id_empty-stderr.txt | 4 + Tests/RunCMake/cmake_language/defer_id_empty.cmake | 1 + .../cmake_language/defer_id_missing-result.txt | 1 + .../cmake_language/defer_id_missing-stderr.txt | 4 + .../RunCMake/cmake_language/defer_id_missing.cmake | 1 + .../cmake_language/defer_id_multiple-result.txt | 1 + .../cmake_language/defer_id_multiple-stderr.txt | 4 + .../cmake_language/defer_id_multiple.cmake | 1 + .../cmake_language/defer_id_var_empty-result.txt | 1 + .../cmake_language/defer_id_var_empty-stderr.txt | 4 + .../cmake_language/defer_id_var_empty.cmake | 1 + .../cmake_language/defer_id_var_missing-result.txt | 1 + .../cmake_language/defer_id_var_missing-stderr.txt | 4 + .../cmake_language/defer_id_var_missing.cmake | 1 + .../defer_id_var_multiple-result.txt | 1 + .../defer_id_var_multiple-stderr.txt | 4 + .../cmake_language/defer_id_var_multiple.cmake | 1 + .../cmake_language/defer_missing_arg-result.txt | 1 + .../cmake_language/defer_missing_arg-stderr.txt | 4 + .../cmake_language/defer_missing_arg.cmake | 1 + .../cmake_language/defer_missing_call-result.txt | 1 + .../cmake_language/defer_missing_call-stderr.txt | 4 + .../cmake_language/defer_missing_call.cmake | 1 + .../cmake_language/defer_unknown_option-result.txt | 1 + .../cmake_language/defer_unknown_option-stderr.txt | 6 + .../cmake_language/defer_unknown_option.cmake | 1 + 143 files changed, 1038 insertions(+), 25 deletions(-) create mode 100644 Help/release/dev/cmake_language-DEFER.rst create mode 100644 Tests/RunCMake/cmake_language/defer_call-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call/include.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_enable_language.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_error-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_error-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_error.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_ids.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_trace.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_call_trace_json.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_directory_empty-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_directory_empty.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_directory_missing-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_directory_missing.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_directory_multiple.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_id_empty-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_empty.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_id_missing-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_missing.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_id_multiple-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_multiple.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_empty.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_missing.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_missing_arg-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_missing_arg.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_missing_call-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_missing_call.cmake create mode 100644 Tests/RunCMake/cmake_language/defer_unknown_option-result.txt create mode 100644 Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt create mode 100644 Tests/RunCMake/cmake_language/defer_unknown_option.cmake diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst index 9ce5a6f..00e1a69 100644 --- a/Help/command/cmake_language.rst +++ b/Help/command/cmake_language.rst @@ -12,6 +12,7 @@ Synopsis cmake_language(`CALL`_ [...]) cmake_language(`EVAL`_ CODE ...) + cmake_language(`DEFER`_ ... CALL [...]) Introduction ^^^^^^^^^^^^ @@ -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 ... CALL [...]) + +Schedules a call to the named ```` 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 `` + Schedule the call for the end of the given directory instead of the + current directory. The ```` 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 `` + 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 `` + Sepcify a variable in which to store the identification for the + deferred call. If ``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 ] GET_CALL_IDS ) + +This will store in ```` a :ref:`Semicolon-separated list ` of deferred call ids. + +Details of a specific call may be retrieved from its id: + +.. code-block:: cmake + + cmake_language(DEFER [DIRECTORY ] GET_CALL ) + +This will store in ```` a :ref:`Semicolon-separated list ` 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 ] CANCEL_CALL ...) + +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/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 ````. + ``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/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/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index d92ca28..9277c20 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -7,11 +7,14 @@ #include #include #include +#include +#include #include #include #include "cmExecutionStatus.h" +#include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmRange.h" @@ -37,9 +40,24 @@ std::array InvalidCommands{ } // clang-format on }; +std::array InvalidDeferCommands{ + { + // clang-format off + "return"_s, + } // clang-format on +}; + +struct Defer +{ + std::string Id; + std::string IdVar; + cmMakefile* Directory = nullptr; +}; + bool cmCMakeLanguageCommandCALL(std::vector const& args, std::string const& callCommand, - size_t startArg, cmExecutionStatus& status) + size_t startArg, cm::optional defer, + cmExecutionStatus& status) { // ensure specified command is valid // start/end flow control commands are not allowed @@ -49,6 +67,12 @@ bool cmCMakeLanguageCommandCALL(std::vector const& args, 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.GetBacktrace().Top(); @@ -66,9 +90,106 @@ bool cmCMakeLanguageCommandCALL(std::vector const& args, func.Arguments.emplace_back(lfarg); } + 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); } +bool cmCMakeLanguageCommandDEFER(Defer const& defer, + std::vector 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 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 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])); +} + bool cmCMakeLanguageCommandEVAL(std::vector const& args, cmExecutionStatus& status) { @@ -118,11 +239,105 @@ bool cmCMakeLanguageCommand(std::vector const& args, } return true; }; + auto finishArgs = [&]() { + std::vector tmpArgs(args.begin() + rawArg, args.end()); + status.GetMakefile().ExpandArguments(tmpArgs, expArgs); + rawArg = args.size(); + }; if (!moreArgs()) { return FatalError(status, "called with incorrect number of arguments"); } + cm::optional maybeDefer; + if (expArgs[expArg] == "DEFER"_s) { + ++expArg; // Consume "DEFER". + + if (!moreArgs()) { + return FatalError(status, "DEFER requires at least one 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 { + return FatalError( + status, cmStrCat("DEFER unknown option:\n "_s, expArgs[expArg])); + } + } + + 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". @@ -138,7 +353,8 @@ bool cmCMakeLanguageCommand(std::vector const& args, } // Run the CALL. - return cmCMakeLanguageCommandCALL(args, callCommand, rawArg, status); + return cmCMakeLanguageCommandCALL(args, callCommand, rawArg, + std::move(maybeDefer), status); } if (expArgs[expArg] == "EVAL") { 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 #include +#include +#include #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/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 46030e0..1197db6 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -15,6 +15,7 @@ #include #include +#include #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -1211,6 +1212,7 @@ void cmGlobalGenerator::Configure() { this->FirstTimeProgress = 0.0f; this->ClearGeneratorMembers(); + this->NextDeferId = 0; cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot(); @@ -3256,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 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 LanguageToLinkerPreference; std::map LanguageToOriginalSharedLibFlags; + // Deferral id generation. + size_t NextDeferId = 0; + // Record hashes for rules and outputs. struct RuleHash { 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 5773e6a..5617536 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -11,6 +11,8 @@ #include #include +#include + #include "cmStateSnapshot.h" /** \class cmListFileCache @@ -72,6 +74,8 @@ public: std::string Name; std::string FilePath; long Line = 0; + static long const DeferPlaceholderLine = -1; + cm::optional DeferId; cmListFileContext() = default; cmListFileContext(std::string name, std::string filePath, long line) @@ -81,13 +85,15 @@ public: { } - static cmListFileContext FromCommandContext(cmCommandContext const& lfcc, - std::string const& fileName) + static cmListFileContext FromCommandContext( + cmCommandContext const& lfcc, std::string const& fileName, + cm::optional 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/cmMakefile.cxx b/Source/cmMakefile.cxx index 896839b..ac3a193 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -16,6 +16,7 @@ #include #include #include +#include // IWYU pragma: keep #include #include #include @@ -274,7 +275,9 @@ cmListFileBacktrace cmMakefile::GetBacktrace() const return this->Backtrace; } -void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const +void cmMakefile::PrintCommandTrace( + cmListFileFunction const& lff, + cm::optional const& deferId) const { // Check if current file in the list of requested to trace... std::vector const& trace_only_this_files = @@ -322,6 +325,9 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const builder["indentation"] = ""; val["file"] = full_path; val["line"] = static_cast(lff.Line); + if (deferId) { + val["defer"] = *deferId; + } val["cmd"] = lff.Name.Original; val["args"] = Json::Value(Json::arrayValue); for (std::string const& arg : args) { @@ -335,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 << " "; @@ -361,11 +370,12 @@ class cmMakefileCall { public: cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff, - cmExecutionStatus& status) + cm::optional 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); @@ -402,7 +412,8 @@ void cmMakefile::OnExecuteCommand(std::function callback) } bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, - cmExecutionStatus& status) + cmExecutionStatus& status, + cm::optional deferId) { bool result = true; @@ -417,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(stack_manager); // Check for maximum recursion depth. @@ -445,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); @@ -663,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( @@ -705,7 +763,8 @@ bool cmMakefile::ReadListFileAsString(const std::string& content, } void cmMakefile::RunListFile(cmListFile const& listFile, - std::string const& filenametoread) + std::string const& filenametoread, + DeferCommands* defer) { // add this list file to the list of dependencies this->ListFiles.push_back(filenametoread); @@ -736,6 +795,33 @@ void cmMakefile::RunListFile(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", @@ -1678,7 +1764,9 @@ void cmMakefile::Configure() } } - this->RunListFile(listFile, currentStart); + this->Defer = cm::make_unique(); + this->RunListFile(listFile, currentStart, this->Defer.get()); + this->Defer.reset(); if (cmSystemTools::GetFatalErrorOccured()) { scope.Quiet(); } @@ -1753,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; @@ -2960,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 cmMakefile::DeferGetCallIds() const +{ + cm::optional 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 cmMakefile::DeferGetCall(std::string const& id) const +{ + cm::optional 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, @@ -2997,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); } @@ -3561,6 +3723,12 @@ void cmMakefile::AddTargetObject(std::string const& tgtName, void cmMakefile::EnableLanguage(std::vector 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 d851dd6..c7940fb 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -15,6 +15,7 @@ #include #include +#include #include #include "cmsys/RegularExpression.hxx" @@ -695,7 +696,8 @@ public: /** * Print a command's invocation */ - void PrintCommandTrace(const cmListFileFunction& lff) const; + void PrintCommandTrace(cmListFileFunction const& lff, + cm::optional const& deferId = {}) const; /** * Set a callback that is invoked whenever ExecuteCommand is called. @@ -706,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 deferId = {}); //! Enable support for named language, if nil then all languages are /// enabled. @@ -965,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 DeferGetCallIds() const; + cm::optional DeferGetCall(std::string const& id) const; + protected: // add link libraries and directories to the target void AddGlobalLinkInformation(cmTarget& target); @@ -1026,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 Commands; + }; + std::unique_ptr Defer; + bool DeferRunning = false; + void DoGenerate(cmLocalGenerator& lg); void RunListFile(cmListFile const& listFile, - const std::string& filenametoread); + const std::string& filenametoread, + DeferCommands* defer = nullptr); bool ParseDefineFlag(std::string const& definition, bool remove); @@ -1080,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/cmake.cxx b/Source/cmake.cxx index 014a707..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 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/cmake_language/RunCMakeTest.cmake b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake index 29a4d23..6480b2e 100644 --- a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake @@ -32,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/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/cmake_language/defer_call_add_subdirectory-result.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt @@ -0,0 +1 @@ +1 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 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 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 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 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) -- cgit v0.12