diff options
60 files changed, 1013 insertions, 951 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 399e79c..5efa077 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -429,10 +429,7 @@ macro (CMAKE_BUILD_UTILITIES) set(_CMAKE_USE_OPENSSL_DEFAULT OFF) if(NOT DEFINED CMAKE_USE_OPENSSL AND NOT WIN32 AND NOT APPLE AND CMAKE_SYSTEM_NAME MATCHES "(Linux|FreeBSD)") - find_package(OpenSSL QUIET) - if(OPENSSL_FOUND) - set(_CMAKE_USE_OPENSSL_DEFAULT ON) - endif() + set(_CMAKE_USE_OPENSSL_DEFAULT ON) endif() option(CMAKE_USE_OPENSSL "Use OpenSSL." ${_CMAKE_USE_OPENSSL_DEFAULT}) mark_as_advanced(CMAKE_USE_OPENSSL) diff --git a/Help/command/message.rst b/Help/command/message.rst index 5dca6b4..3002842 100644 --- a/Help/command/message.rst +++ b/Help/command/message.rst @@ -60,6 +60,11 @@ messages one at a time on a status line and other messages in an interactive pop-up box. The ``--loglevel`` command-line option to each of these tools can be used to control which messages will be shown. +Messages of log levels ``NOTICE`` and below will also have each line preceded +by the content of the :variable:`CMAKE_MESSAGE_INDENT` variable (converted to +a single string by concatenating its list items). For ``STATUS`` to ``TRACE`` +messages, this indenting content will be inserted after the hyphens. + CMake Warning and Error message text displays using a simple markup language. Non-indented text is formatted in line-wrapped paragraphs delimited by newlines. Indented text is considered pre-formatted. diff --git a/Help/command/string.rst b/Help/command/string.rst index 2e89d7b..81a2061 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -22,8 +22,8 @@ Synopsis string(`PREPEND`_ <string-var> [<input>...]) string(`CONCAT`_ <out-var> [<input>...]) string(`JOIN`_ <glue> <out-var> [<input>...]) - string(`TOLOWER`_ <string1> <out-var>) - string(`TOUPPER`_ <string1> <out-var>) + string(`TOLOWER`_ <string> <out-var>) + string(`TOUPPER`_ <string> <out-var>) string(`LENGTH`_ <string> <out-var>) string(`SUBSTRING`_ <string> <begin> <length> <out-var>) string(`STRIP`_ <string> <out-var>) @@ -38,7 +38,7 @@ Synopsis `Generation`_ string(`ASCII`_ <number>... <out-var>) - string(`CONFIGURE`_ <string1> <out-var> [...]) + string(`CONFIGURE`_ <string> <out-var> [...]) string(`MAKE_C_IDENTIFIER`_ <string> <out-var>) string(`RANDOM`_ [<option>...] <out-var>) string(`TIMESTAMP`_ <out-var> [<format string>] [UTC]) @@ -51,23 +51,28 @@ Search and Replace .. code-block:: cmake - string(FIND <string> <substring> <output variable> [REVERSE]) + string(FIND <string> <substring> <output_variable> [REVERSE]) -Return the position where the given substring was found in -the supplied string. If the ``REVERSE`` flag was used, the command will +Return the position where the given ``<substring>`` was found in +the supplied ``<string>``. If the ``REVERSE`` flag was used, the command will search for the position of the last occurrence of the specified -substring. If the substring is not found, a position of -1 is returned. +``<substring>``. If the ``<substring>`` is not found, a position of -1 is +returned. + +The ``string(FIND)`` subcommand treats all strings as ASCII-only characters. +The index stored in ``<output_variable>`` will also be counted in bytes, +so strings containing multi-byte characters may lead to unexpected results. .. _REPLACE: .. code-block:: cmake string(REPLACE <match_string> - <replace_string> <output variable> + <replace_string> <output_variable> <input> [<input>...]) -Replace all occurrences of ``match_string`` in the input -with ``replace_string`` and store the result in the output. +Replace all occurrences of ``<match_string>`` in the ``<input>`` +with ``<replace_string>`` and store the result in the ``<output_variable>``. Regular Expressions ^^^^^^^^^^^^^^^^^^^ @@ -77,9 +82,10 @@ Regular Expressions .. code-block:: cmake string(REGEX MATCH <regular_expression> - <output variable> <input> [<input>...]) + <output_variable> <input> [<input>...]) -Match the regular expression once and store the match in the output variable. +Match the ``<regular_expression>`` once and store the match in the +``<output_variable>``. All ``<input>`` arguments are concatenated before matching. .. _`REGEX MATCHALL`: @@ -87,10 +93,10 @@ All ``<input>`` arguments are concatenated before matching. .. code-block:: cmake string(REGEX MATCHALL <regular_expression> - <output variable> <input> [<input>...]) + <output_variable> <input> [<input>...]) -Match the regular expression as many times as possible and store the matches -in the output variable as a list. +Match the ``<regular_expression>`` as many times as possible and store the +matches in the ``<output_variable>`` as a list. All ``<input>`` arguments are concatenated before matching. .. _`REGEX REPLACE`: @@ -98,16 +104,17 @@ All ``<input>`` arguments are concatenated before matching. .. code-block:: cmake string(REGEX REPLACE <regular_expression> - <replace_expression> <output variable> + <replacement_expression> <output_variable> <input> [<input>...]) -Match the regular expression as many times as possible and substitute the -replacement expression for the match in the output. +Match the ``<regular_expression>`` as many times as possible and substitute +the ``<replacement_expression>`` for the match in the output. All ``<input>`` arguments are concatenated before matching. -The replace expression may refer to paren-delimited subexpressions of the -match using ``\1``, ``\2``, ..., ``\9``. Note that two backslashes (``\\1``) -are required in CMake code to get a backslash through argument parsing. +The ``<replacement_expression>`` may refer to parenthesis-delimited +subexpressions of the match using ``\1``, ``\2``, ..., ``\9``. Note that +two backslashes (``\\1``) are required in CMake code to get a backslash +through argument parsing. .. _`Regex Specification`: @@ -180,103 +187,109 @@ Manipulation .. code-block:: cmake - string(APPEND <string variable> [<input>...]) + string(APPEND <string_variable> [<input>...]) -Append all the input arguments to the string. +Append all the ``<input>`` arguments to the string. .. _PREPEND: .. code-block:: cmake - string(PREPEND <string variable> [<input>...]) + string(PREPEND <string_variable> [<input>...]) -Prepend all the input arguments to the string. +Prepend all the ``<input>`` arguments to the string. .. _CONCAT: .. code-block:: cmake - string(CONCAT <output variable> [<input>...]) + string(CONCAT <output_variable> [<input>...]) -Concatenate all the input arguments together and store -the result in the named output variable. +Concatenate all the ``<input>`` arguments together and store +the result in the named ``<output_variable>``. .. _JOIN: .. code-block:: cmake - string(JOIN <glue> <output variable> [<input>...]) + string(JOIN <glue> <output_variable> [<input>...]) -Join all the input arguments together using the glue -string and store the result in the named output variable. +Join all the ``<input>`` arguments together using the ``<glue>`` +string and store the result in the named ``<output_variable>``. -To join list's elements, use preferably the ``JOIN`` operator -from :command:`list` command. This allows for the elements to have +To join a list's elements, prefer to use the ``JOIN`` operator +from the :command:`list` command. This allows for the elements to have special characters like ``;`` in them. .. _TOLOWER: .. code-block:: cmake - string(TOLOWER <string1> <output variable>) + string(TOLOWER <string> <output_variable>) -Convert string to lower characters. +Convert ``<string>`` to lower characters. .. _TOUPPER: .. code-block:: cmake - string(TOUPPER <string1> <output variable>) + string(TOUPPER <string> <output_variable>) -Convert string to upper characters. +Convert ``<string>`` to upper characters. .. _LENGTH: .. code-block:: cmake - string(LENGTH <string> <output variable>) + string(LENGTH <string> <output_variable>) -Store in an output variable a given string's length. +Store in an ``<output_variable>`` a given string's length in bytes. +Note that this means if ``<string>`` contains multi-byte characters, the +result stored in ``<output_variable>`` will *not* be the number of characters. .. _SUBSTRING: .. code-block:: cmake - string(SUBSTRING <string> <begin> <length> <output variable>) + string(SUBSTRING <string> <begin> <length> <output_variable>) + +Store in an ``<output_variable>`` a substring of a given ``<string>``. If +``<length>`` is ``-1`` the remainder of the string starting at ``<begin>`` +will be returned. If ``<string>`` is shorter than ``<length>`` then the +end of the string is used instead. -Store in an output variable a substring of a given string. If length is -``-1`` the remainder of the string starting at begin will be returned. -If string is shorter than length then end of string is used instead. +Both ``<begin>`` and ``<length>`` are counted in bytes, so care must +be exercised if ``<string>`` could contain multi-byte characters. .. note:: - CMake 3.1 and below reported an error if length pointed past - the end of string. + CMake 3.1 and below reported an error if ``<length>`` pointed past + the end of ``<string>``. .. _STRIP: .. code-block:: cmake - string(STRIP <string> <output variable>) + string(STRIP <string> <output_variable>) -Store in an output variable a substring of a given string with leading and -trailing spaces removed. +Store in an ``<output_variable>`` a substring of a given ``<string>`` with +leading and trailing spaces removed. .. _GENEX_STRIP: .. code-block:: cmake - string(GENEX_STRIP <input string> <output variable>) + string(GENEX_STRIP <string> <output_variable>) Strip any :manual:`generator expressions <cmake-generator-expressions(7)>` -from the ``input string`` and store the result in the ``output variable``. +from the input ``<string>`` and store the result in the ``<output_variable>``. .. _REPEAT: .. code-block:: cmake - string(REPEAT <input string> <count> <output variable>) + string(REPEAT <string> <count> <output_variable>) -Produce the output string as repetion of ``input string`` ``count`` times. +Produce the output string as the input ``<string>`` repeated ``<count>`` times. Comparison ^^^^^^^^^^ @@ -285,14 +298,14 @@ Comparison .. code-block:: cmake - string(COMPARE LESS <string1> <string2> <output variable>) - string(COMPARE GREATER <string1> <string2> <output variable>) - string(COMPARE EQUAL <string1> <string2> <output variable>) - string(COMPARE NOTEQUAL <string1> <string2> <output variable>) - string(COMPARE LESS_EQUAL <string1> <string2> <output variable>) - string(COMPARE GREATER_EQUAL <string1> <string2> <output variable>) + string(COMPARE LESS <string1> <string2> <output_variable>) + string(COMPARE GREATER <string1> <string2> <output_variable>) + string(COMPARE EQUAL <string1> <string2> <output_variable>) + string(COMPARE NOTEQUAL <string1> <string2> <output_variable>) + string(COMPARE LESS_EQUAL <string1> <string2> <output_variable>) + string(COMPARE GREATER_EQUAL <string1> <string2> <output_variable>) -Compare the strings and store true or false in the output variable. +Compare the strings and store true or false in the ``<output_variable>``. .. _`Supported Hash Algorithms`: @@ -303,9 +316,9 @@ Hashing .. code-block:: cmake - string(<HASH> <output variable> <input>) + string(<HASH> <output_variable> <input>) -Compute a cryptographic hash of the input string. +Compute a cryptographic hash of the ``<input>`` string. The supported ``<HASH>`` algorithm names are: ``MD5`` @@ -336,7 +349,7 @@ Generation .. code-block:: cmake - string(ASCII <number> [<number> ...] <output variable>) + string(ASCII <number> [<number> ...] <output_variable>) Convert all numbers into corresponding ASCII characters. @@ -344,31 +357,31 @@ Convert all numbers into corresponding ASCII characters. .. code-block:: cmake - string(CONFIGURE <string1> <output variable> + string(CONFIGURE <string> <output_variable> [@ONLY] [ESCAPE_QUOTES]) -Transform a string like :command:`configure_file` transforms a file. +Transform a ``<string>`` like :command:`configure_file` transforms a file. .. _MAKE_C_IDENTIFIER: .. code-block:: cmake - string(MAKE_C_IDENTIFIER <input string> <output variable>) + string(MAKE_C_IDENTIFIER <string> <output_variable>) -Convert each non-alphanumeric character in the ``<input string>`` to an -underscore and store the result in the ``<output variable>``. If the first -character of the string is a digit, an underscore will also be prepended to -the result. +Convert each non-alphanumeric character in the input ``<string>`` to an +underscore and store the result in the ``<output_variable>``. If the first +character of the ``<string>`` is a digit, an underscore will also be prepended +to the result. .. _RANDOM: .. code-block:: cmake string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>] - [RANDOM_SEED <seed>] <output variable>) + [RANDOM_SEED <seed>] <output_variable>) -Return a random string of given length consisting of -characters from the given alphabet. Default length is 5 characters +Return a random string of given ``<length>`` consisting of +characters from the given ``<alphabet>``. Default length is 5 characters and default alphabet is all numbers and upper and lower case letters. If an integer ``RANDOM_SEED`` is given, its value will be used to seed the random number generator. @@ -377,18 +390,18 @@ random number generator. .. code-block:: cmake - string(TIMESTAMP <output variable> [<format string>] [UTC]) + string(TIMESTAMP <output_variable> [<format_string>] [UTC]) Write a string representation of the current date -and/or time to the output variable. +and/or time to the ``<output_variable>``. -Should the command be unable to obtain a timestamp the output variable -will be set to the empty string "". +If the command is unable to obtain a timestamp, the ``<output_variable>`` +will be set to the empty string ``""``. The optional ``UTC`` flag requests the current date/time representation to be in Coordinated Universal Time (UTC) rather than local time. -The optional ``<format string>`` may contain the following format +The optional ``<format_string>`` may contain the following format specifiers: :: @@ -415,7 +428,7 @@ specifiers: Unknown format specifiers will be ignored and copied to the output as-is. -If no explicit ``<format string>`` is given it will default to: +If no explicit ``<format_string>`` is given, it will default to: :: @@ -432,7 +445,7 @@ If no explicit ``<format string>`` is given it will default to: .. code-block:: cmake - string(UUID <output variable> NAMESPACE <namespace> NAME <name> + string(UUID <output_variable> NAMESPACE <namespace> NAME <name> TYPE <MD5|SHA1> [UPPER]) Create a universally unique identifier (aka GUID) as per RFC4122 @@ -441,6 +454,6 @@ based on the hash of the combined values of ``<namespace>`` The hash algorithm can be either ``MD5`` (Version 3 UUID) or ``SHA1`` (Version 5 UUID). A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`` -where each `x` represents a lower case hexadecimal character. -Where required an uppercase representation can be requested +where each ``x`` represents a lower case hexadecimal character. +Where required, an uppercase representation can be requested with the optional ``UPPER`` flag. diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst index db8e7a0..41ed0c4 100644 --- a/Help/guide/tutorial/index.rst +++ b/Help/guide/tutorial/index.rst @@ -228,7 +228,8 @@ remove our uses of the ``EXTRA_INCLUDES`` variable from the top-level CMakeLists. Once this is done, run **cmake** or **cmake-gui** to configure the project -and then build it with your chosen build tool. +and then build it with your chosen build tool or by using ``cmake --build .`` +from the build directory. Installing and Testing (Step 4) =============================== @@ -258,14 +259,15 @@ And the to top-level ``CMakeLists.txt`` we add: That is all that is needed to create a basic local install of the tutorial. Run **cmake** or **cmake-gui** to configure the project and then build it -with your chosen build tool. Build the ``install`` target by typing -``make install`` from the command line or build the ``INSTALL`` target from -an IDE. This will install the appropriate header files, libraries, and -executables. +with your chosen build tool. Run the install step by typing +``cmake --install .`` or from the command line, or build the ``INSTALL`` +target from an IDE. This will install the appropriate header files, libraries, +and executables. Verify that the installed Tutorial runs. Note: The CMake variable ``CMAKE_INSTALL_PREFIX`` is used to determine the root of where the files will -be installed. +be installed. If using ``cmake --install`` a custom installation directory can +be given via ``--prefix`` argument. Testing Support --------------- diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index e0ce6f7..c3f6f8a 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -69,6 +69,7 @@ Variables that Provide Information /variable/CMAKE_MAKE_PROGRAM /variable/CMAKE_MATCH_COUNT /variable/CMAKE_MATCH_n + /variable/CMAKE_MESSAGE_INDENT /variable/CMAKE_MINIMUM_REQUIRED_VERSION /variable/CMAKE_MINOR_VERSION /variable/CMAKE_NETRC @@ -609,7 +610,6 @@ Variables for CPack /variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION /variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY /variable/CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS - /variable/CPACK_INSTALL_SCRIPT /variable/CPACK_PACKAGING_INSTALL_PREFIX /variable/CPACK_SET_DESTDIR /variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION diff --git a/Help/release/dev/cpack-install-scripts.rst b/Help/release/dev/cpack-install-scripts.rst new file mode 100644 index 0000000..7b80d33 --- /dev/null +++ b/Help/release/dev/cpack-install-scripts.rst @@ -0,0 +1,5 @@ +cpack-install-scripts +--------------------- + +* The ``CPACK_INSTALL_SCRIPT`` variable has been deprecated in favor of the + new, more accurately named :variable:`CPACK_INSTALL_SCRIPTS` variable. diff --git a/Help/release/dev/message-indent.rst b/Help/release/dev/message-indent.rst new file mode 100644 index 0000000..b170708 --- /dev/null +++ b/Help/release/dev/message-indent.rst @@ -0,0 +1,5 @@ +message-indent +-------------- + +* The :command:`message` command learned indentation control with the new + :variable:`CMAKE_MESSAGE_INDENT` variable. diff --git a/Help/variable/CMAKE_MESSAGE_INDENT.rst b/Help/variable/CMAKE_MESSAGE_INDENT.rst new file mode 100644 index 0000000..f7975ab --- /dev/null +++ b/Help/variable/CMAKE_MESSAGE_INDENT.rst @@ -0,0 +1,30 @@ +CMAKE_MESSAGE_INDENT +-------------------- + +The :command:`message` command joins the strings from this list and for +log levels of ``NOTICE`` and below, it prepends the resultant string to +each line of the message. + +Example: + +.. code-block:: cmake + + list(APPEND listVar one two three) + + message(VERBOSE [[Collected items in the "listVar":]]) + list(APPEND CMAKE_MESSAGE_INDENT " ") + + foreach(item IN LISTS listVar) + message(VERBOSE ${item}) + endforeach() + + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(VERBOSE "No more indent") + +Which results in the following output: + + -- Collected items in the "listVar": + -- one + -- two + -- tree + -- No more indent diff --git a/Help/variable/CPACK_INSTALL_SCRIPT.rst b/Help/variable/CPACK_INSTALL_SCRIPT.rst deleted file mode 100644 index 12a48a4..0000000 --- a/Help/variable/CPACK_INSTALL_SCRIPT.rst +++ /dev/null @@ -1,8 +0,0 @@ -CPACK_INSTALL_SCRIPT --------------------- - -Extra CMake script provided by the user. - -If set this CMake script will be executed by CPack during its local -[CPack-private] installation which is done right before packaging the -files. The script is not called by e.g.: ``make install``. diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index c9008db..8a6a712 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -325,7 +325,21 @@ The following variables are for advanced uses of CPack: .. variable:: CPACK_INSTALL_COMMANDS - Extra commands to install components. + Extra commands to install components. The environment variable + ``CMAKE_INSTALL_PREFIX`` is set to the temporary install directory + during execution. + +.. variable:: CPACK_INSTALL_SCRIPTS + + Extra CMake scripts executed by CPack during its local staging + installation, which is done right before packaging the files. + The scripts are not called by a standalone install (e.g.: ``make install``). + For every script, the following variables will be set: + :variable:`CMAKE_CURRENT_SOURCE_DIR`, :variable:`CMAKE_CURRENT_BINARY_DIR` + and :variable:`CMAKE_INSTALL_PREFIX` (which is set to the staging install + directory). The singular form ``CMAKE_INSTALL_SCRIPT`` is supported as + an alternative variable for historical reasons, but its value is ignored if + ``CMAKE_INSTALL_SCRIPTS`` is set and a warning will be issued. .. variable:: CPACK_INSTALLED_DIRECTORIES diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 0316532..8117916 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -662,8 +662,6 @@ set(SRCS cmTryCompileCommand.h cmTryRunCommand.cxx cmTryRunCommand.h - cmUnexpectedCommand.cxx - cmUnexpectedCommand.h cmUnsetCommand.cxx cmUnsetCommand.h cmUseMangledMesaCommand.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 1a0e0d3..5833058 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 15) -set(CMake_VERSION_PATCH 20190720) +set(CMake_VERSION_PATCH 20190723) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 4a91698..350ebed 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -235,7 +235,7 @@ int cmCPackGenerator::InstallProject() return 0; } - // If the CPackConfig file sets CPACK_INSTALL_SCRIPT then run them + // If the CPackConfig file sets CPACK_INSTALL_SCRIPT(S) then run them // as listed if (!this->InstallProjectViaInstallScript(setDestDir, tempInstallDirectory)) { @@ -448,7 +448,19 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( int cmCPackGenerator::InstallProjectViaInstallScript( bool setDestDir, const std::string& tempInstallDirectory) { - const char* cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPT"); + const char* cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPTS"); + { + const char* const cmakeScript = this->GetOption("CPACK_INSTALL_SCRIPT"); + if (cmakeScript && cmakeScripts) { + cmCPackLogger( + cmCPackLog::LOG_WARNING, + "Both CPACK_INSTALL_SCRIPTS and CPACK_INSTALL_SCRIPT are set, " + "the latter will be ignored." + << std::endl); + } else if (cmakeScript && !cmakeScripts) { + cmakeScripts = cmakeScript; + } + } if (cmakeScripts && *cmakeScripts) { cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Install scripts: " << cmakeScripts << std::endl); diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index adf9553..2b73d40 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -4,6 +4,7 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSystemTools.h" @@ -13,8 +14,6 @@ #include <sstream> #include <stdlib.h> -class cmExecutionStatus; - cmCTestHandlerCommand::cmCTestHandlerCommand() { const size_t INIT_SIZE = 100; @@ -86,7 +85,7 @@ private: } bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, - cmExecutionStatus& /*unused*/) + cmExecutionStatus& status) { // save error state and restore it if needed SaveRestoreErrorState errorState; @@ -126,7 +125,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, if (capureCMakeError) { this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], "-1"); - std::string const err = this->GetName() + " " + this->GetError(); + std::string const err = this->GetName() + " " + status.GetError(); if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) { cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n"); } @@ -195,8 +194,8 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, if (capureCMakeError) { this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], "-1"); - const char* err = this->GetError(); - if (err && !cmSystemTools::FindLastString(err, "unknown error.")) { + std::string const& err = status.GetError(); + if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) { cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n"); } return true; @@ -220,7 +219,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], "-1"); cmCTestLog(this->CTest, ERROR_MESSAGE, - this->GetName() << " " << this->GetError() << "\n"); + this->GetName() << " " << status.GetError() << "\n"); // return success because failure is recorded in CAPTURE_CMAKE_ERROR return true; } @@ -240,10 +239,10 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, const char* returnString = "0"; if (cmSystemTools::GetErrorOccuredFlag()) { returnString = "-1"; - const char* err = this->GetError(); + std::string const& err = status.GetError(); // print out the error if it is not "unknown error" which means // there was no message - if (err && !cmSystemTools::FindLastString(err, "unknown error.")) { + if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) { cmCTestLog(this->CTest, ERROR_MESSAGE, err); } } diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index c2748e1..cfbdad0 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -423,54 +423,11 @@ int cmCTestTestHandler::PostProcessHandler() return 1; } -// clearly it would be nice if this were broken up into a few smaller -// functions and commented... int cmCTestTestHandler::ProcessHandler() { - // Update internal data structure from generic one - this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation")); - this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion"))); - if (cmSystemTools::IsOn(this->GetOption("ScheduleRandom"))) { - this->CTest->SetScheduleType("Random"); - } - if (this->GetOption("ParallelLevel")) { - this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel"))); - } - - const char* val; - val = this->GetOption("LabelRegularExpression"); - if (val) { - this->UseIncludeLabelRegExpFlag = true; - this->IncludeLabelRegExp = val; - } - val = this->GetOption("ExcludeLabelRegularExpression"); - if (val) { - this->UseExcludeLabelRegExpFlag = true; - this->ExcludeLabelRegExp = val; - } - val = this->GetOption("IncludeRegularExpression"); - if (val) { - this->UseIncludeRegExp(); - this->SetIncludeRegExp(val); - } - val = this->GetOption("ExcludeRegularExpression"); - if (val) { - this->UseExcludeRegExp(); - this->SetExcludeRegExp(val); - } - val = this->GetOption("ExcludeFixtureRegularExpression"); - if (val) { - this->ExcludeFixtureRegExp = val; - } - val = this->GetOption("ExcludeFixtureSetupRegularExpression"); - if (val) { - this->ExcludeFixtureSetupRegExp = val; - } - val = this->GetOption("ExcludeFixtureCleanupRegularExpression"); - if (val) { - this->ExcludeFixtureCleanupRegExp = val; + if (!this->ProcessOptions()) { + return -1; } - this->SetRerunFailed(cmSystemTools::IsOn(this->GetOption("RerunFailed"))); this->TestResults.clear(); @@ -490,7 +447,6 @@ int cmCTestTestHandler::ProcessHandler() std::vector<std::string> passed; std::vector<std::string> failed; - int total; // start the real time clock auto clock_start = std::chrono::steady_clock::now(); @@ -499,9 +455,7 @@ int cmCTestTestHandler::ProcessHandler() auto clock_finish = std::chrono::steady_clock::now(); - total = int(passed.size()) + int(failed.size()); - - if (total == 0) { + if (passed.size() + failed.size() == 0) { if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) { cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!" << std::endl); @@ -519,9 +473,6 @@ int cmCTestTestHandler::ProcessHandler() } } - typedef std::set<cmCTestTestHandler::cmCTestTestResult, - cmCTestTestResultLess> - SetOfTests; SetOfTests resultsSet(this->TestResults.begin(), this->TestResults.end()); std::vector<cmCTestTestHandler::cmCTestTestResult> disabledTests; @@ -532,92 +483,182 @@ int cmCTestTestHandler::ProcessHandler() } } - float percent = float(passed.size()) * 100.0f / float(total); - if (!failed.empty() && percent > 99) { - percent = 99; - } + cmDuration durationInSecs = clock_finish - clock_start; + this->LogTestSummary(passed, failed, durationInSecs); - std::string passColorCode; - std::string failedColorCode; - if (failed.empty()) { - passColorCode = this->CTest->GetColorCode(cmCTest::Color::GREEN); - } else { - failedColorCode = this->CTest->GetColorCode(cmCTest::Color::RED); - } + this->LogDisabledTests(disabledTests); + + this->LogFailedTests(failed, resultsSet); + } + + if (!this->GenerateXML()) { + return 1; + } + + if (!this->PostProcessHandler()) { + this->LogFile = nullptr; + return -1; + } + + if (!failed.empty()) { + this->LogFile = nullptr; + return -1; + } + this->LogFile = nullptr; + return 0; +} + +bool cmCTestTestHandler::ProcessOptions() +{ + // Update internal data structure from generic one + this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation")); + this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion"))); + if (cmSystemTools::IsOn(this->GetOption("ScheduleRandom"))) { + this->CTest->SetScheduleType("Random"); + } + if (this->GetOption("ParallelLevel")) { + this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel"))); + } + + const char* val; + val = this->GetOption("LabelRegularExpression"); + if (val) { + this->UseIncludeLabelRegExpFlag = true; + this->IncludeLabelRegExp = val; + } + val = this->GetOption("ExcludeLabelRegularExpression"); + if (val) { + this->UseExcludeLabelRegExpFlag = true; + this->ExcludeLabelRegExp = val; + } + val = this->GetOption("IncludeRegularExpression"); + if (val) { + this->UseIncludeRegExp(); + this->SetIncludeRegExp(val); + } + val = this->GetOption("ExcludeRegularExpression"); + if (val) { + this->UseExcludeRegExp(); + this->SetExcludeRegExp(val); + } + val = this->GetOption("ExcludeFixtureRegularExpression"); + if (val) { + this->ExcludeFixtureRegExp = val; + } + val = this->GetOption("ExcludeFixtureSetupRegularExpression"); + if (val) { + this->ExcludeFixtureSetupRegExp = val; + } + val = this->GetOption("ExcludeFixtureCleanupRegularExpression"); + if (val) { + this->ExcludeFixtureCleanupRegExp = val; + } + this->SetRerunFailed(cmSystemTools::IsOn(this->GetOption("RerunFailed"))); + + return true; +} + +void cmCTestTestHandler::LogTestSummary(const std::vector<std::string>& passed, + const std::vector<std::string>& failed, + const cmDuration& durationInSecs) +{ + std::size_t total = passed.size() + failed.size(); + + float percent = float(passed.size()) * 100.0f / float(total); + if (!failed.empty() && percent > 99) { + percent = 99; + } + + std::string passColorCode; + std::string failedColorCode; + if (failed.empty()) { + passColorCode = this->CTest->GetColorCode(cmCTest::Color::GREEN); + } else { + failedColorCode = this->CTest->GetColorCode(cmCTest::Color::RED); + } + cmCTestLog(this->CTest, HANDLER_OUTPUT, + std::endl + << passColorCode << std::lround(percent) << "% tests passed" + << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) + << ", " << failedColorCode << failed.size() << " tests failed" + << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) + << " out of " << total << std::endl); + if ((!this->CTest->GetLabelsForSubprojects().empty() && + this->CTest->GetSubprojectSummary())) { + this->PrintLabelOrSubprojectSummary(true); + } + if (this->CTest->GetLabelSummary()) { + this->PrintLabelOrSubprojectSummary(false); + } + char realBuf[1024]; + sprintf(realBuf, "%6.2f sec", durationInSecs.count()); + cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, + "\nTotal Test time (real) = " << realBuf << "\n", + this->Quiet); +} + +void cmCTestTestHandler::LogDisabledTests( + const std::vector<cmCTestTestResult>& disabledTests) +{ + if (!disabledTests.empty()) { + cmGeneratedFileStream ofs; cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl - << passColorCode << std::lround(percent) << "% tests passed" - << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) - << ", " << failedColorCode << failed.size() << " tests failed" - << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) - << " out of " << total << std::endl); - if ((!this->CTest->GetLabelsForSubprojects().empty() && - this->CTest->GetSubprojectSummary())) { - this->PrintLabelOrSubprojectSummary(true); - } - if (this->CTest->GetLabelSummary()) { - this->PrintLabelOrSubprojectSummary(false); - } - char realBuf[1024]; - cmDuration durationInSecs = clock_finish - clock_start; - sprintf(realBuf, "%6.2f sec", durationInSecs.count()); - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - "\nTotal Test time (real) = " << realBuf << "\n", - this->Quiet); + << "The following tests did not run:" << std::endl); + this->StartLogFile("TestsDisabled", ofs); - if (!disabledTests.empty()) { - cmGeneratedFileStream ofs; - cmCTestLog(this->CTest, HANDLER_OUTPUT, - std::endl - << "The following tests did not run:" << std::endl); - this->StartLogFile("TestsDisabled", ofs); - - const char* disabled_reason; - cmCTestLog(this->CTest, HANDLER_OUTPUT, - this->CTest->GetColorCode(cmCTest::Color::BLUE)); - for (cmCTestTestResult const& dt : disabledTests) { - ofs << dt.TestCount << ":" << dt.Name << std::endl; - if (dt.CompletionStatus == "Disabled") { - disabled_reason = "Disabled"; - } else { - disabled_reason = "Skipped"; - } - cmCTestLog(this->CTest, HANDLER_OUTPUT, - "\t" << std::setw(3) << dt.TestCount << " - " << dt.Name - << " (" << disabled_reason << ")" << std::endl); + const char* disabled_reason; + cmCTestLog(this->CTest, HANDLER_OUTPUT, + this->CTest->GetColorCode(cmCTest::Color::BLUE)); + for (cmCTestTestResult const& dt : disabledTests) { + ofs << dt.TestCount << ":" << dt.Name << std::endl; + if (dt.CompletionStatus == "Disabled") { + disabled_reason = "Disabled"; + } else { + disabled_reason = "Skipped"; } cmCTestLog(this->CTest, HANDLER_OUTPUT, - this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)); + "\t" << std::setw(3) << dt.TestCount << " - " << dt.Name + << " (" << disabled_reason << ")" << std::endl); } + cmCTestLog(this->CTest, HANDLER_OUTPUT, + this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)); + } +} - if (!failed.empty()) { - cmGeneratedFileStream ofs; - cmCTestLog(this->CTest, HANDLER_OUTPUT, - std::endl - << "The following tests FAILED:" << std::endl); - this->StartLogFile("TestsFailed", ofs); - - for (cmCTestTestResult const& ft : resultsSet) { - if (ft.Status != cmCTestTestHandler::COMPLETED && - !cmHasLiteralPrefix(ft.CompletionStatus, "SKIP_") && - ft.CompletionStatus != "Disabled") { - ofs << ft.TestCount << ":" << ft.Name << std::endl; - auto testColor = cmCTest::Color::RED; - if (this->GetTestStatus(ft) == "Not Run") { - testColor = cmCTest::Color::YELLOW; - } - cmCTestLog( - this->CTest, HANDLER_OUTPUT, - "\t" << this->CTest->GetColorCode(testColor) << std::setw(3) - << ft.TestCount << " - " << ft.Name << " (" - << this->GetTestStatus(ft) << ")" - << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) - << std::endl); +void cmCTestTestHandler::LogFailedTests(const std::vector<std::string>& failed, + const SetOfTests& resultsSet) +{ + if (!failed.empty()) { + cmGeneratedFileStream ofs; + cmCTestLog(this->CTest, HANDLER_OUTPUT, + std::endl + << "The following tests FAILED:" << std::endl); + this->StartLogFile("TestsFailed", ofs); + + for (cmCTestTestResult const& ft : resultsSet) { + if (ft.Status != cmCTestTestHandler::COMPLETED && + !cmHasLiteralPrefix(ft.CompletionStatus, "SKIP_") && + ft.CompletionStatus != "Disabled") { + ofs << ft.TestCount << ":" << ft.Name << std::endl; + auto testColor = cmCTest::Color::RED; + if (this->GetTestStatus(ft) == "Not Run") { + testColor = cmCTest::Color::YELLOW; } + cmCTestLog( + this->CTest, HANDLER_OUTPUT, + "\t" << this->CTest->GetColorCode(testColor) << std::setw(3) + << ft.TestCount << " - " << ft.Name << " (" + << this->GetTestStatus(ft) << ")" + << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) + << std::endl); } } } +} +bool cmCTestTestHandler::GenerateXML() +{ if (this->CTest->GetProduceXML()) { cmGeneratedFileStream xmlfile; if (!this->StartResultingXML( @@ -628,23 +669,13 @@ int cmCTestTestHandler::ProcessHandler() << (this->MemCheck ? "memory check" : "testing") << " XML file" << std::endl); this->LogFile = nullptr; - return 1; + return false; } cmXMLWriter xml(xmlfile); this->GenerateDartOutput(xml); } - if (!this->PostProcessHandler()) { - this->LogFile = nullptr; - return -1; - } - - if (!failed.empty()) { - this->LogFile = nullptr; - return -1; - } - this->LogFile = nullptr; - return 0; + return true; } void cmCTestTestHandler::PrintLabelOrSubprojectSummary(bool doSubProject) diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 5bbc68e..9345185 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -191,12 +191,25 @@ public: typedef std::vector<cmCTestTestProperties> ListOfTests; protected: + typedef std::set<cmCTestTestHandler::cmCTestTestResult, + cmCTestTestResultLess> + SetOfTests; + // compute a final test list virtual int PreProcessHandler(); virtual int PostProcessHandler(); virtual void GenerateTestCommand(std::vector<std::string>& args, int test); int ExecuteCommands(std::vector<std::string>& vec); + bool ProcessOptions(); + void LogTestSummary(const std::vector<std::string>& passed, + const std::vector<std::string>& failed, + const cmDuration& durationInSecs); + void LogDisabledTests(const std::vector<cmCTestTestResult>& disabledTests); + void LogFailedTests(const std::vector<std::string>& failed, + const SetOfTests& resultsSet); + bool GenerateXML(); + void WriteTestResultHeader(cmXMLWriter& xml, cmCTestTestResult const& result); void WriteTestResultFooter(cmXMLWriter& xml, diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 255a8e6..8c2d987 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -421,7 +421,7 @@ int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs, // Assume all arguments are quoted. lff.Arguments.emplace_back(args[i], cmListFileArgument::Quoted, 0); } - cmExecutionStatus status; + cmExecutionStatus status(*mf); return mf->ExecuteCommand(lff, status); } diff --git a/Source/cmCommand.cxx b/Source/cmCommand.cxx index d349c91..0c2734e 100644 --- a/Source/cmCommand.cxx +++ b/Source/cmCommand.cxx @@ -2,11 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCommand.h" +#include <utility> + +#include "cmExecutionStatus.h" #include "cmMakefile.h" -class cmExecutionStatus; struct cmListFileArgument; +void cmCommand::SetExecutionStatus(cmExecutionStatus* status) +{ + this->Status = status; + this->Makefile = &status->GetMakefile(); +} + bool cmCommand::InvokeInitialPass(const std::vector<cmListFileArgument>& args, cmExecutionStatus& status) { @@ -19,15 +27,33 @@ bool cmCommand::InvokeInitialPass(const std::vector<cmListFileArgument>& args, return this->InitialPass(expandedArguments, status); } -const char* cmCommand::GetError() +void cmCommand::SetError(const std::string& e) { - if (this->Error.empty()) { - return "unknown error."; - } - return this->Error.c_str(); + this->Status->SetError(e); } -void cmCommand::SetError(const std::string& e) +cmLegacyCommandWrapper::cmLegacyCommandWrapper(std::unique_ptr<cmCommand> cmd) + : Command(std::move(cmd)) +{ +} + +cmLegacyCommandWrapper::cmLegacyCommandWrapper( + cmLegacyCommandWrapper const& other) + : Command(other.Command->Clone()) +{ +} + +cmLegacyCommandWrapper& cmLegacyCommandWrapper::operator=( + cmLegacyCommandWrapper const& other) +{ + this->Command = other.Command->Clone(); + return *this; +} + +bool cmLegacyCommandWrapper::operator()( + std::vector<cmListFileArgument> const& args, cmExecutionStatus& status) const { - this->Error = e; + auto cmd = this->Command->Clone(); + cmd->SetExecutionStatus(&status); + return cmd->InvokeInitialPass(args, status); } diff --git a/Source/cmCommand.h b/Source/cmCommand.h index b210f27..bcb178d 100644 --- a/Source/cmCommand.h +++ b/Source/cmCommand.h @@ -42,16 +42,18 @@ public: /** * Specify the makefile. */ - void SetMakefile(cmMakefile* m) { this->Makefile = m; } cmMakefile* GetMakefile() { return this->Makefile; } + void SetExecutionStatus(cmExecutionStatus* s); + cmExecutionStatus* GetExecutionStatus() { return this->Status; }; + /** * This is called by the cmMakefile when the command is first * encountered in the CMakeLists.txt file. It expands the command's * arguments and then invokes the InitialPass. */ - virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args, - cmExecutionStatus& status); + bool InvokeInitialPass(const std::vector<cmListFileArgument>& args, + cmExecutionStatus& status); /** * This is called when the command is first encountered in @@ -66,11 +68,6 @@ public: virtual std::unique_ptr<cmCommand> Clone() = 0; /** - * Return the last error string. - */ - const char* GetError(); - - /** * Set the error message */ void SetError(const std::string& e); @@ -79,7 +76,25 @@ protected: cmMakefile* Makefile = nullptr; private: - std::string Error; + cmExecutionStatus* Status = nullptr; +}; + +class cmLegacyCommandWrapper +{ +public: + explicit cmLegacyCommandWrapper(std::unique_ptr<cmCommand> cmd); + + cmLegacyCommandWrapper(cmLegacyCommandWrapper const& other); + cmLegacyCommandWrapper& operator=(cmLegacyCommandWrapper const& other); + + cmLegacyCommandWrapper(cmLegacyCommandWrapper&&) = default; + cmLegacyCommandWrapper& operator=(cmLegacyCommandWrapper&&) = default; + + bool operator()(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status) const; + +private: + std::unique_ptr<cmCommand> Command; }; #endif diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 96c7105..f351ff8 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -147,7 +147,7 @@ void GetScriptingCommands(cmState* state) cm::make_unique<cmGetFilenameComponentCommand>()); state->AddBuiltinCommand("get_property", cm::make_unique<cmGetPropertyCommand>()); - state->AddBuiltinCommand("if", cm::make_unique<cmIfCommand>()); + state->AddBuiltinCommand("if", cmIfCommand); state->AddBuiltinCommand("include", cm::make_unique<cmIncludeCommand>()); state->AddBuiltinCommand("include_guard", cm::make_unique<cmIncludeGuardCommand>()); @@ -162,7 +162,7 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("option", cm::make_unique<cmOptionCommand>()); state->AddBuiltinCommand("cmake_parse_arguments", cm::make_unique<cmParseArgumentsCommand>()); - state->AddBuiltinCommand("return", cm::make_unique<cmReturnCommand>()); + state->AddBuiltinCommand("return", cmReturnCommand); state->AddBuiltinCommand("separate_arguments", cm::make_unique<cmSeparateArgumentsCommand>()); state->AddBuiltinCommand("set", cm::make_unique<cmSetCommand>()); @@ -173,7 +173,7 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("site_name", cm::make_unique<cmSiteNameCommand>()); state->AddBuiltinCommand("string", cm::make_unique<cmStringCommand>()); state->AddBuiltinCommand("unset", cm::make_unique<cmUnsetCommand>()); - state->AddBuiltinCommand("while", cm::make_unique<cmWhileCommand>()); + state->AddBuiltinCommand("while", cmWhileCommand); state->AddUnexpectedCommand( "else", @@ -255,8 +255,7 @@ void GetProjectCommands(cmState* state) cm::make_unique<cmDefinePropertyCommand>()); state->AddBuiltinCommand("enable_language", cm::make_unique<cmEnableLanguageCommand>()); - state->AddBuiltinCommand("enable_testing", - cm::make_unique<cmEnableTestingCommand>()); + state->AddBuiltinCommand("enable_testing", cmEnableTestingCommand); state->AddBuiltinCommand("get_source_file_property", cm::make_unique<cmGetSourceFilePropertyCommand>()); state->AddBuiltinCommand("get_target_property", diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index e7e91c1..2907f4a 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -4,6 +4,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <functional> #include <sstream> #include <stdio.h> #include <stdlib.h> @@ -17,7 +18,6 @@ #include "cmSystemTools.h" #include "cmake.h" -class cmCommand; class cmTest; static std::string const keyAND = "AND"; @@ -452,7 +452,7 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, } // does a command exist if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) { - cmCommand* command = + cmState::Command command = this->Makefile.GetState()->GetCommand(argP1->c_str()); this->HandlePredicate(command != nullptr, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmDisallowedCommand.cxx b/Source/cmDisallowedCommand.cxx index 418d98c..aa1f90b 100644 --- a/Source/cmDisallowedCommand.cxx +++ b/Source/cmDisallowedCommand.cxx @@ -24,8 +24,6 @@ bool cmDisallowedCommand::InitialPass(std::vector<std::string> const& args, return true; } - this->Command->SetMakefile(this->GetMakefile()); - bool const ret = this->Command->InitialPass(args, status); - this->SetError(this->Command->GetError()); - return ret; + this->Command->SetExecutionStatus(this->GetExecutionStatus()); + return this->Command->InitialPass(args, status); } diff --git a/Source/cmEnableTestingCommand.cxx b/Source/cmEnableTestingCommand.cxx index 6a64450..89212c8 100644 --- a/Source/cmEnableTestingCommand.cxx +++ b/Source/cmEnableTestingCommand.cxx @@ -2,15 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmEnableTestingCommand.h" +#include "cmExecutionStatus.h" #include "cmMakefile.h" -class cmExecutionStatus; - -// we do this in the final pass so that we now the subdirs have all -// been defined -bool cmEnableTestingCommand::InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) +bool cmEnableTestingCommand(std::vector<std::string> const&, + cmExecutionStatus& status) { - this->Makefile->AddDefinition("CMAKE_TESTING_ENABLED", "1"); + status.GetMakefile().AddDefinition("CMAKE_TESTING_ENABLED", "1"); return true; } diff --git a/Source/cmEnableTestingCommand.h b/Source/cmEnableTestingCommand.h index fd50ebc..e4593f2 100644 --- a/Source/cmEnableTestingCommand.h +++ b/Source/cmEnableTestingCommand.h @@ -8,13 +8,9 @@ #include <string> #include <vector> -#include "cm_memory.hxx" - -#include "cmCommand.h" - class cmExecutionStatus; -/** \class cmEnableTestingCommand +/** * \brief Enable testing for this directory and below. * * Produce the output testfile. This produces a file in the build directory @@ -27,23 +23,7 @@ class cmExecutionStatus; * Note that CTest expects to find this file in the build directory root; * therefore, this command should be in the source directory root too. */ -class cmEnableTestingCommand : public cmCommand -{ -public: - /** - * This is a virtual constructor for the command. - */ - std::unique_ptr<cmCommand> Clone() override - { - return cm::make_unique<cmEnableTestingCommand>(); - } - - /** - * This is called when the command is first encountered in - * the CMakeLists.txt file. - */ - bool InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) override; -}; +bool cmEnableTestingCommand(std::vector<std::string> const&, + cmExecutionStatus&); #endif diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h index 56199dd..bcacc2f 100644 --- a/Source/cmExecutionStatus.h +++ b/Source/cmExecutionStatus.h @@ -3,6 +3,11 @@ #ifndef cmExecutionStatus_h #define cmExecutionStatus_h +#include <cmConfigure.h> // IWYU pragma: keep +#include <string> + +class cmMakefile; + /** \class cmExecutionStatus * \brief Superclass for all command status classes * @@ -11,14 +16,26 @@ class cmExecutionStatus { public: + cmExecutionStatus(cmMakefile& makefile) + : Makefile(makefile) + , Error("unknown error.") + { + } + void Clear() { + this->Error = "unknown error."; this->ReturnInvoked = false; this->BreakInvoked = false; this->ContinueInvoked = false; this->NestedError = false; } + cmMakefile& GetMakefile() { return this->Makefile; } + + void SetError(std::string const& e) { this->Error = e; } + std::string const& GetError() const { return this->Error; } + void SetReturnInvoked() { this->ReturnInvoked = true; } bool GetReturnInvoked() const { return this->ReturnInvoked; } @@ -32,6 +49,8 @@ public: bool GetNestedError() const { return this->NestedError; } private: + cmMakefile& Makefile; + std::string Error; bool ReturnInvoked = false; bool BreakInvoked = false; bool ContinueInvoked = false; diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx index 49e8cd5..4f1a158 100644 --- a/Source/cmFileCopier.cxx +++ b/Source/cmFileCopier.cxx @@ -174,11 +174,8 @@ bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode) cmSystemTools::ExpandListArgument(default_dir_install_permissions, items); for (const auto& arg : items) { if (!this->CheckPermissions(arg, **mode)) { - std::ostringstream e; - e << this->FileCommand->GetError() - << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS " - "variable."; - this->FileCommand->SetError(e.str()); + this->FileCommand->SetError( + " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS variable."); return false; } } diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index a30ebe1..e3918b5 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -55,7 +55,7 @@ bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, // set the variable to the loop value mf.AddDefinition(this->Args[0], arg.c_str()); // Invoke all the functions that were collected in the block. - cmExecutionStatus status; + cmExecutionStatus status(mf); for (cmListFileFunction const& func : this->Functions) { status.Clear(); mf.ExecuteCommand(func, status); diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 6d06531..8b664ad 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -5,8 +5,6 @@ #include <sstream> #include <utility> -#include "cm_memory.hxx" - #include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -15,35 +13,15 @@ #include "cmState.h" // define the class for function commands -class cmFunctionHelperCommand : public cmCommand +class cmFunctionHelperCommand { public: /** - * This is a virtual constructor for the command. - */ - std::unique_ptr<cmCommand> Clone() override - { - auto newC = cm::make_unique<cmFunctionHelperCommand>(); - // we must copy when we clone - newC->Args = this->Args; - newC->Functions = this->Functions; - newC->Policies = this->Policies; - newC->FilePath = this->FilePath; - return std::unique_ptr<cmCommand>(std::move(newC)); - } - - /** * This is called when the command is first encountered in * the CMakeLists.txt file. */ - bool InvokeInitialPass(const std::vector<cmListFileArgument>& args, - cmExecutionStatus&) override; - - bool InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) override - { - return false; - } + bool operator()(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& inStatus) const; std::vector<std::string> Args; std::vector<cmListFileFunction> Functions; @@ -51,12 +29,15 @@ public: std::string FilePath; }; -bool cmFunctionHelperCommand::InvokeInitialPass( - const std::vector<cmListFileArgument>& args, cmExecutionStatus& inStatus) +bool cmFunctionHelperCommand::operator()( + std::vector<cmListFileArgument> const& args, + cmExecutionStatus& inStatus) const { + cmMakefile& makefile = inStatus.GetMakefile(); + // Expand the argument list to the function. std::vector<std::string> expandedArgs; - this->Makefile->ExpandArguments(args, expandedArgs); + makefile.ExpandArguments(args, expandedArgs); // make sure the number of arguments passed is at least the number // required by the signature @@ -64,30 +45,30 @@ bool cmFunctionHelperCommand::InvokeInitialPass( std::string errorMsg = "Function invoked with incorrect arguments for function named: "; errorMsg += this->Args[0]; - this->SetError(errorMsg); + inStatus.SetError(errorMsg); return false; } - cmMakefile::FunctionPushPop functionScope(this->Makefile, this->FilePath, + cmMakefile::FunctionPushPop functionScope(&makefile, this->FilePath, this->Policies); // set the value of argc std::ostringstream strStream; strStream << expandedArgs.size(); - this->Makefile->AddDefinition("ARGC", strStream.str().c_str()); - this->Makefile->MarkVariableAsUsed("ARGC"); + makefile.AddDefinition("ARGC", strStream.str().c_str()); + makefile.MarkVariableAsUsed("ARGC"); // set the values for ARGV0 ARGV1 ... for (unsigned int t = 0; t < expandedArgs.size(); ++t) { std::ostringstream tmpStream; tmpStream << "ARGV" << t; - this->Makefile->AddDefinition(tmpStream.str(), expandedArgs[t].c_str()); - this->Makefile->MarkVariableAsUsed(tmpStream.str()); + makefile.AddDefinition(tmpStream.str(), expandedArgs[t].c_str()); + makefile.MarkVariableAsUsed(tmpStream.str()); } // define the formal arguments for (unsigned int j = 1; j < this->Args.size(); ++j) { - this->Makefile->AddDefinition(this->Args[j], expandedArgs[j - 1].c_str()); + makefile.AddDefinition(this->Args[j], expandedArgs[j - 1].c_str()); } // define ARGV and ARGN @@ -95,17 +76,16 @@ bool cmFunctionHelperCommand::InvokeInitialPass( std::vector<std::string>::const_iterator eit = expandedArgs.begin() + (this->Args.size() - 1); std::string argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";"); - this->Makefile->AddDefinition("ARGV", argvDef.c_str()); - this->Makefile->MarkVariableAsUsed("ARGV"); - this->Makefile->AddDefinition("ARGN", argnDef.c_str()); - this->Makefile->MarkVariableAsUsed("ARGN"); + makefile.AddDefinition("ARGV", argvDef.c_str()); + makefile.MarkVariableAsUsed("ARGV"); + makefile.AddDefinition("ARGN", argnDef.c_str()); + makefile.MarkVariableAsUsed("ARGN"); // Invoke all the functions that were collected in the block. // for each function for (cmListFileFunction const& func : this->Functions) { - cmExecutionStatus status; - if (!this->Makefile->ExecuteCommand(func, status) || - status.GetNestedError()) { + cmExecutionStatus status(makefile); + if (!makefile.ExecuteCommand(func, status) || status.GetNestedError()) { // The error message should have already included the call stack // so we do not need to report an error here. functionScope.Quiet(); @@ -132,11 +112,11 @@ bool cmFunctionFunctionBlocker::IsFunctionBlocked( // if this is the endfunction for this function then execute if (!this->Depth) { // create a new command and add it to cmake - auto f = cm::make_unique<cmFunctionHelperCommand>(); - f->Args = this->Args; - f->Functions = this->Functions; - f->FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f->Policies); + cmFunctionHelperCommand f; + f.Args = this->Args; + f.Functions = this->Functions; + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); // remove the function blocker now that the function is defined mf.RemoveFunctionBlocker(this, lff); diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 728f2a4..817f41e 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -68,9 +68,7 @@ void cmGeneratorExpressionDAGChecker::Initialize() return; } } - const_cast<cmGeneratorExpressionDAGChecker*>(top) - ->Seen[this->Target] - .insert(this->Property); + top->Seen[this->Target].insert(this->Property); } } diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index e1fba5e..6d7d6ef 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -88,7 +88,7 @@ private: const cmGeneratorExpressionDAGChecker* const Parent; cmGeneratorTarget const* Target; const std::string Property; - std::map<cmGeneratorTarget const*, std::set<std::string>> Seen; + mutable std::map<cmGeneratorTarget const*, std::set<std::string>> Seen; const GeneratorExpressionContent* const Content; const cmListFileBacktrace Backtrace; Result CheckResult; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index d3e8248..6e6c917 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -92,9 +92,6 @@ public: virtual bool GetHadContextSensitiveCondition() const { return false; } cmLinkImplItem const& LinkImplItem; - -private: - cmListFileBacktrace Backtrace; }; cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem; @@ -209,6 +206,63 @@ void CreatePropertyGeneratorExpressions( } } +namespace { +// Represent a target property entry after evaluating generator expressions +// and splitting up lists. +struct EvaluatedTargetPropertyEntry +{ + EvaluatedTargetPropertyEntry(cmLinkImplItem const& item, + cmListFileBacktrace bt) + : LinkImplItem(item) + , Backtrace(std::move(bt)) + { + } + + // Move-only. + EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default; + EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete; + EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) = + delete; + EvaluatedTargetPropertyEntry& operator=( + EvaluatedTargetPropertyEntry const&) = delete; + + cmLinkImplItem const& LinkImplItem; + cmListFileBacktrace Backtrace; + std::vector<std::string> Values; + bool ContextDependent = false; +}; + +EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry( + cmGeneratorTarget const* thisTarget, std::string const& config, + std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, + cmGeneratorTarget::TargetPropertyEntry* entry) +{ + EvaluatedTargetPropertyEntry ee(entry->LinkImplItem, entry->GetBacktrace()); + cmSystemTools::ExpandListArgument( + entry->Evaluate(thisTarget->GetLocalGenerator(), config, false, thisTarget, + dagChecker, lang), + ee.Values); + if (entry->GetHadContextSensitiveCondition()) { + ee.ContextDependent = true; + } + return ee; +} + +std::vector<EvaluatedTargetPropertyEntry> EvaluateTargetPropertyEntries( + cmGeneratorTarget const* thisTarget, std::string const& config, + std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, + std::vector<cmGeneratorTarget::TargetPropertyEntry*> const& in) +{ + std::vector<EvaluatedTargetPropertyEntry> out; + out.reserve(in.size()); + for (cmGeneratorTarget::TargetPropertyEntry* entry : in) { + out.emplace_back(EvaluateTargetPropertyEntry(thisTarget, config, lang, + dagChecker, entry)); + } + return out; +} +} + cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) : Target(t) , FortranModuleDirectoryCreated(false) @@ -654,12 +708,14 @@ std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends( return nullptr; } -static void handleSystemIncludesDep( - cmLocalGenerator* lg, cmGeneratorTarget const* depTgt, - const std::string& config, cmGeneratorTarget const* headTarget, - cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<std::string>& result, bool excludeImported, - std::string const& language) +namespace { +void handleSystemIncludesDep(cmLocalGenerator* lg, + cmGeneratorTarget const* depTgt, + const std::string& config, + cmGeneratorTarget const* headTarget, + cmGeneratorExpressionDAGChecker* dagChecker, + std::vector<std::string>& result, + bool excludeImported, std::string const& language) { if (const char* dirs = depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) { @@ -682,6 +738,7 @@ static void handleSystemIncludesDep( result); } } +} /* clang-format off */ #define IMPLEMENT_VISIT(KIND) \ @@ -1084,77 +1141,91 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const return this->Target->GetPropertyAsBool(prop); } -static void AddInterfaceEntries( - cmGeneratorTarget const* thisTarget, std::string const& config, - std::string const& prop, - std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries) +namespace { +void AddInterfaceEntries(cmGeneratorTarget const* headTarget, + std::string const& config, std::string const& prop, + std::string const& lang, + cmGeneratorExpressionDAGChecker* dagChecker, + std::vector<EvaluatedTargetPropertyEntry>& entries) { if (cmLinkImplementationLibraries const* impl = - thisTarget->GetLinkImplementationLibraries(config)) { + headTarget->GetLinkImplementationLibraries(config)) { for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target) { std::string uniqueName = - thisTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( + headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( lib.Target); std::string genex = "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," + prop + ">"; cmGeneratorExpression ge(lib.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); cge->SetEvaluateForBuildsystem(true); - entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib)); + + EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); + cmSystemTools::ExpandListArgument( + cge->Evaluate(headTarget->GetLocalGenerator(), config, false, + headTarget, dagChecker, lang), + ee.Values); + if (cge->GetHadContextSensitiveCondition()) { + ee.ContextDependent = true; + } + entries.emplace_back(std::move(ee)); } } } } -static void AddObjectEntries( - cmGeneratorTarget const* thisTarget, std::string const& config, - std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries) +void AddObjectEntries(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + std::vector<EvaluatedTargetPropertyEntry>& entries) { if (cmLinkImplementationLibraries const* impl = - thisTarget->GetLinkImplementationLibraries(config)) { + headTarget->GetLinkImplementationLibraries(config)) { for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target && lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { std::string uniqueName = - thisTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( + headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( lib.Target); std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">"; cmGeneratorExpression ge(lib.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); cge->SetEvaluateForBuildsystem(true); - entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib)); + + EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); + cmSystemTools::ExpandListArgument( + cge->Evaluate(headTarget->GetLocalGenerator(), config, false, + headTarget, dagChecker), + ee.Values); + if (cge->GetHadContextSensitiveCondition()) { + ee.ContextDependent = true; + } + entries.emplace_back(std::move(ee)); } } } } -static bool processSources( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& srcs, - std::unordered_set<std::string>& uniqueSrcs, - cmGeneratorExpressionDAGChecker* dagChecker, std::string const& config, - bool debugSources) +bool processSources(cmGeneratorTarget const* tgt, + std::vector<EvaluatedTargetPropertyEntry>& entries, + std::vector<BT<std::string>>& srcs, + std::unordered_set<std::string>& uniqueSrcs, + bool debugSources) { cmMakefile* mf = tgt->Target->GetMakefile(); bool contextDependent = false; - for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) { - cmLinkImplItem const& item = entry->LinkImplItem; - std::string const& targetName = item.AsStr(); - std::vector<std::string> entrySources; - cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(), - config, false, tgt, tgt, - dagChecker), - entrySources); - - if (entry->GetHadContextSensitiveCondition()) { + for (EvaluatedTargetPropertyEntry& entry : entries) { + if (entry.ContextDependent) { contextDependent = true; } - for (std::string& src : entrySources) { + cmLinkImplItem const& item = entry.LinkImplItem; + std::string const& targetName = item.AsStr(); + + for (std::string& src : entry.Values) { cmSourceFile* sf = mf->GetOrCreateSource(src); std::string e; std::string fullPath = sf->GetFullPath(&e); @@ -1183,9 +1254,9 @@ static bool processSources( src = fullPath; } std::string usedSources; - for (std::string const& src : entrySources) { + for (std::string const& src : entry.Values) { if (uniqueSrcs.insert(src).second) { - srcs.emplace_back(src, entry->GetBacktrace()); + srcs.emplace_back(src, entry.Backtrace); if (debugSources) { usedSources += " * " + src + "\n"; } @@ -1196,11 +1267,12 @@ static bool processSources( MessageType::LOG, std::string("Used sources for target ") + tgt->GetName() + ":\n" + usedSources, - entry->GetBacktrace()); + entry.Backtrace); } } return contextDependent; } +} std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( std::string const& config) const @@ -1248,28 +1320,28 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr); + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, std::string(), &dagChecker, + this->SourceEntries); + std::unordered_set<std::string> uniqueSrcs; bool contextDependentDirectSources = - processSources(this, this->SourceEntries, files, uniqueSrcs, &dagChecker, - config, debugSources); + processSources(this, entries, files, uniqueSrcs, debugSources); // Collect INTERFACE_SOURCES of all direct link-dependencies. - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceSourcesEntries; - AddInterfaceEntries(this, config, "INTERFACE_SOURCES", - linkInterfaceSourcesEntries); + std::vector<EvaluatedTargetPropertyEntry> linkInterfaceSourcesEntries; + AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), + &dagChecker, linkInterfaceSourcesEntries); std::vector<std::string>::size_type numFilesBefore = files.size(); - bool contextDependentInterfaceSources = - processSources(this, linkInterfaceSourcesEntries, files, uniqueSrcs, - &dagChecker, config, debugSources); + bool contextDependentInterfaceSources = processSources( + this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources); // Collect TARGET_OBJECTS of direct object link-dependencies. - std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkObjectsEntries; - AddObjectEntries(this, config, linkObjectsEntries); + std::vector<EvaluatedTargetPropertyEntry> linkObjectsEntries; + AddObjectEntries(this, config, &dagChecker, linkObjectsEntries); std::vector<std::string>::size_type numFilesBefore2 = files.size(); bool contextDependentObjects = - processSources(this, linkObjectsEntries, files, uniqueSrcs, &dagChecker, - config, debugSources); + processSources(this, linkObjectsEntries, files, uniqueSrcs, debugSources); if (!contextDependentDirectSources && !(contextDependentInterfaceSources && numFilesBefore < files.size()) && @@ -1277,8 +1349,6 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( this->LinkImplementationLanguageIsContextDependent = false; } - cmDeleteAll(linkInterfaceSourcesEntries); - cmDeleteAll(linkObjectsEntries); return files; } @@ -1855,16 +1925,17 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const return this->GetLibraryNames(config).SharedObject; } -static bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level) +namespace { +bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level) { return level == cmGeneratorTarget::FullLevel; } -static bool shouldAddContentLevel( - cmGeneratorTarget::BundleDirectoryLevel level) +bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level) { return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level); } +} std::string cmGeneratorTarget::GetAppBundleDirectory( const std::string& config, BundleDirectoryLevel level) const @@ -2767,27 +2838,22 @@ std::string cmGeneratorTarget::GetCreateRuleVariable( } return ""; } -static void processIncludeDirectories( + +namespace { +void processIncludeDirectories( cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, + std::vector<EvaluatedTargetPropertyEntry>& entries, std::vector<BT<std::string>>& includes, - std::unordered_set<std::string>& uniqueIncludes, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugIncludes, const std::string& language) + std::unordered_set<std::string>& uniqueIncludes, bool debugIncludes) { - for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) { - cmLinkImplItem const& item = entry->LinkImplItem; + for (EvaluatedTargetPropertyEntry& entry : entries) { + cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); bool const fromImported = item.Target && item.Target->IsImported(); bool const checkCMP0027 = item.FromGenex; - std::vector<std::string> entryIncludes; - cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(), - config, false, tgt, - dagChecker, language), - entryIncludes); std::string usedIncludes; - for (std::string& entryInclude : entryIncludes) { + for (std::string& entryInclude : entry.Values) { if (fromImported && !cmSystemTools::FileExists(entryInclude)) { std::ostringstream e; MessageType messageType = MessageType::FATAL_ERROR; @@ -2859,12 +2925,11 @@ static void processIncludeDirectories( if (!cmSystemTools::IsOff(entryInclude)) { cmSystemTools::ConvertToUnixSlashes(entryInclude); } - std::string inc = entryInclude; - if (uniqueIncludes.insert(inc).second) { - includes.emplace_back(inc, entry->GetBacktrace()); + if (uniqueIncludes.insert(entryInclude).second) { + includes.emplace_back(entryInclude, entry.Backtrace); if (debugIncludes) { - usedIncludes += " * " + inc + "\n"; + usedIncludes += " * " + entryInclude + "\n"; } } } @@ -2873,10 +2938,11 @@ static void processIncludeDirectories( MessageType::LOG, std::string("Used includes for target ") + tgt->GetName() + ":\n" + usedIncludes, - entry->GetBacktrace()); + entry.Backtrace); } } } +} std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( const std::string& config, const std::string& lang) const @@ -2902,14 +2968,12 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( this->DebugIncludesDone = true; } - processIncludeDirectories(this, this->IncludeDirectoriesEntries, includes, - uniqueIncludes, &dagChecker, config, debugIncludes, - lang); + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, lang, &dagChecker, + this->IncludeDirectoriesEntries); - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceIncludeDirectoriesEntries; - AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", - linkInterfaceIncludeDirectoriesEntries); + AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang, + &dagChecker, entries); if (this->Makefile->IsOn("APPLE")) { cmLinkImplementationLibraries const* impl = @@ -2925,16 +2989,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( libDir = frameworkCheck.match(1); - linkInterfaceIncludeDirectoriesEntries.push_back( - CreateTargetPropertyEntry(libDir)); + EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace()); + ee.Values.emplace_back(std::move(libDir)); + entries.emplace_back(std::move(ee)); } } - processIncludeDirectories(this, linkInterfaceIncludeDirectoriesEntries, - includes, uniqueIncludes, &dagChecker, config, - debugIncludes, lang); - - cmDeleteAll(linkInterfaceIncludeDirectoriesEntries); + processIncludeDirectories(this, entries, includes, uniqueIncludes, + debugIncludes); return includes; } @@ -2945,33 +3007,26 @@ enum class OptionsParse Shell }; -static void processOptionsInternal( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions, const char* logName, std::string const& language, - OptionsParse parse) -{ - for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) { - std::vector<std::string> entryOptions; - cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(), - config, false, tgt, - dagChecker, language), - entryOptions); +namespace { +void processOptions(cmGeneratorTarget const* tgt, + std::vector<EvaluatedTargetPropertyEntry> const& entries, + std::vector<BT<std::string>>& options, + std::unordered_set<std::string>& uniqueOptions, + bool debugOptions, const char* logName, OptionsParse parse) +{ + for (EvaluatedTargetPropertyEntry const& entry : entries) { std::string usedOptions; - for (std::string const& opt : entryOptions) { + for (std::string const& opt : entry.Values) { if (uniqueOptions.insert(opt).second) { if (parse == OptionsParse::Shell && cmHasLiteralPrefix(opt, "SHELL:")) { std::vector<std::string> tmp; cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp); for (std::string& o : tmp) { - options.emplace_back(std::move(o), entry->GetBacktrace()); + options.emplace_back(std::move(o), entry.Backtrace); } } else { - options.emplace_back(opt, entry->GetBacktrace()); + options.emplace_back(opt, entry.Backtrace); } if (debugOptions) { usedOptions += " * " + opt + "\n"; @@ -2983,22 +3038,10 @@ static void processOptionsInternal( MessageType::LOG, std::string("Used ") + logName + std::string(" for target ") + tgt->GetName() + ":\n" + usedOptions, - entry->GetBacktrace()); + entry.Backtrace); } } } - -static void processCompileOptions( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions, std::string const& language) -{ - processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, - config, debugOptions, "compile options", language, - OptionsParse::Shell); } void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, @@ -3036,37 +3079,19 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( this->DebugCompileOptionsDone = true; } - processCompileOptions(this, this->CompileOptionsEntries, result, - uniqueOptions, &dagChecker, config, debugOptions, - language); + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, language, &dagChecker, + this->CompileOptionsEntries); - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceCompileOptionsEntries; + AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language, + &dagChecker, entries); - AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", - linkInterfaceCompileOptionsEntries); + processOptions(this, entries, result, uniqueOptions, debugOptions, + "compile options", OptionsParse::Shell); - processCompileOptions(this, linkInterfaceCompileOptionsEntries, result, - uniqueOptions, &dagChecker, config, debugOptions, - language); - - cmDeleteAll(linkInterfaceCompileOptionsEntries); return result; } -static void processCompileFeatures( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions) -{ - processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, - config, debugOptions, "compile features", - std::string(), OptionsParse::None); -} - void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result, const std::string& config) const { @@ -3101,34 +3126,19 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( this->DebugCompileFeaturesDone = true; } - processCompileFeatures(this, this->CompileFeaturesEntries, result, - uniqueFeatures, &dagChecker, config, debugFeatures); + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, std::string(), &dagChecker, + this->CompileFeaturesEntries); - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceCompileFeaturesEntries; AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES", - linkInterfaceCompileFeaturesEntries); + std::string(), &dagChecker, entries); - processCompileFeatures(this, linkInterfaceCompileFeaturesEntries, result, - uniqueFeatures, &dagChecker, config, debugFeatures); + processOptions(this, entries, result, uniqueFeatures, debugFeatures, + "compile features", OptionsParse::None); - cmDeleteAll(linkInterfaceCompileFeaturesEntries); return result; } -static void processCompileDefinitions( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions, std::string const& language) -{ - processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, - config, debugOptions, "compile definitions", language, - OptionsParse::None); -} - void cmGeneratorTarget::GetCompileDefinitions( std::vector<std::string>& result, const std::string& config, const std::string& language) const @@ -3165,14 +3175,13 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( this->DebugCompileDefinitionsDone = true; } - processCompileDefinitions(this, this->CompileDefinitionsEntries, list, - uniqueOptions, &dagChecker, config, debugDefines, - language); + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, language, &dagChecker, + this->CompileDefinitionsEntries); + + AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language, + &dagChecker, entries); - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceCompileDefinitionsEntries; - AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", - linkInterfaceCompileDefinitionsEntries); if (!config.empty()) { std::string configPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); @@ -3187,8 +3196,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( CM_FALLTHROUGH; } case cmPolicies::OLD: { - linkInterfaceCompileDefinitionsEntries.push_back( + std::unique_ptr<TargetPropertyEntry> entry( CreateTargetPropertyEntry(configProp)); + entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, entry.get())); } break; case cmPolicies::NEW: case cmPolicies::REQUIRED_ALWAYS: @@ -3198,29 +3209,12 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( } } - processCompileDefinitions(this, linkInterfaceCompileDefinitionsEntries, list, - uniqueOptions, &dagChecker, config, debugDefines, - language); + processOptions(this, entries, list, uniqueOptions, debugDefines, + "compile definitions", OptionsParse::None); - cmDeleteAll(linkInterfaceCompileDefinitionsEntries); return list; } -namespace { -void processLinkOptions( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions, std::string const& language) -{ - processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, - config, debugOptions, "link options", language, - OptionsParse::Shell); -} -} - void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const @@ -3256,20 +3250,15 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( this->DebugLinkOptionsDone = true; } - processLinkOptions(this, this->LinkOptionsEntries, result, uniqueOptions, - &dagChecker, config, debugOptions, language); - - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceLinkOptionsEntries; + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, language, &dagChecker, + this->LinkOptionsEntries); - AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", - linkInterfaceLinkOptionsEntries); + AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, + &dagChecker, entries); - processLinkOptions(this, linkInterfaceLinkOptionsEntries, result, - uniqueOptions, &dagChecker, config, debugOptions, - language); - - cmDeleteAll(linkInterfaceLinkOptionsEntries); + processOptions(this, entries, result, uniqueOptions, debugOptions, + "link options", OptionsParse::Shell); // Last step: replace "LINKER:" prefixed elements by // actual linker wrapper @@ -3375,21 +3364,6 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( return result; } -namespace { -void processStaticLibraryLinkOptions( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - std::string const& language) -{ - processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, - config, false, "static library link options", - language, OptionsParse::Shell); -} -} - void cmGeneratorTarget::GetStaticLibraryLinkOptions( std::vector<std::string>& result, const std::string& config, const std::string& language) const @@ -3406,47 +3380,41 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( std::string const& config, std::string const& language) const { std::vector<BT<std::string>> result; - std::vector<cmGeneratorTarget::TargetPropertyEntry*> entries; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr); + std::vector<EvaluatedTargetPropertyEntry> entries; if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { std::vector<std::string> options; cmSystemTools::ExpandListArgument(linkOptions, options); for (const auto& option : options) { - entries.push_back(CreateTargetPropertyEntry(option)); + std::unique_ptr<TargetPropertyEntry> entry( + CreateTargetPropertyEntry(option)); + entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, entry.get())); } } - processStaticLibraryLinkOptions(this, entries, result, uniqueOptions, - &dagChecker, config, language); + processOptions(this, entries, result, uniqueOptions, false, + "static library link options", OptionsParse::Shell); - cmDeleteAll(entries); return result; } namespace { -void processLinkDirectories( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& directories, - std::unordered_set<std::string>& uniqueDirectories, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugDirectories, std::string const& language) -{ - for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) { - cmLinkImplItem const& item = entry->LinkImplItem; +void processLinkDirectories(cmGeneratorTarget const* tgt, + std::vector<EvaluatedTargetPropertyEntry>& entries, + std::vector<BT<std::string>>& directories, + std::unordered_set<std::string>& uniqueDirectories, + bool debugDirectories) +{ + for (EvaluatedTargetPropertyEntry& entry : entries) { + cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); - std::vector<std::string> entryDirectories; - cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(), - config, false, tgt, - dagChecker, language), - entryDirectories); - std::string usedDirectories; - for (std::string& entryDirectory : entryDirectories) { + for (std::string& entryDirectory : entry.Values) { if (!cmSystemTools::FileIsFullPath(entryDirectory)) { std::ostringstream e; bool noMessage = false; @@ -3499,7 +3467,7 @@ void processLinkDirectories( MessageType::LOG, std::string("Used link directories for target ") + tgt->GetName() + ":\n" + usedDirectories, - entry->GetBacktrace()); + entry.Backtrace); } } } @@ -3541,39 +3509,19 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( this->DebugLinkDirectoriesDone = true; } - processLinkDirectories(this, this->LinkDirectoriesEntries, result, - uniqueDirectories, &dagChecker, config, - debugDirectories, language); - - std::vector<cmGeneratorTarget::TargetPropertyEntry*> - linkInterfaceLinkDirectoriesEntries; + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, language, &dagChecker, + this->LinkDirectoriesEntries); - AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", - linkInterfaceLinkDirectoriesEntries); + AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, + &dagChecker, entries); - processLinkDirectories(this, linkInterfaceLinkDirectoriesEntries, result, - uniqueDirectories, &dagChecker, config, - debugDirectories, language); + processLinkDirectories(this, entries, result, uniqueDirectories, + debugDirectories); - cmDeleteAll(linkInterfaceLinkDirectoriesEntries); return result; } -namespace { -void processLinkDepends( - cmGeneratorTarget const* tgt, - const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<BT<std::string>>& options, - std::unordered_set<std::string>& uniqueOptions, - cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - std::string const& language) -{ - processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, - config, false, "link depends", language, - OptionsParse::None); -} -} - void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result, const std::string& config, const std::string& language) const @@ -3589,24 +3537,27 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( std::string const& config, std::string const& language) const { std::vector<BT<std::string>> result; - std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkDependsEntries; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr, nullptr); + std::vector<EvaluatedTargetPropertyEntry> entries; if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) { std::vector<std::string> depends; cmSystemTools::ExpandListArgument(linkDepends, depends); for (const auto& depend : depends) { - linkDependsEntries.push_back(CreateTargetPropertyEntry(depend)); + std::unique_ptr<TargetPropertyEntry> entry( + CreateTargetPropertyEntry(depend)); + entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, entry.get())); } } - AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", - linkDependsEntries); - processLinkDepends(this, linkDependsEntries, result, uniqueOptions, - &dagChecker, config, language); + AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, + &dagChecker, entries); + + processOptions(this, entries, result, uniqueOptions, false, "link depends", + OptionsParse::None); - cmDeleteAll(linkDependsEntries); return result; } @@ -4346,8 +4297,9 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, } } -static std::string intersect(const std::set<std::string>& s1, - const std::set<std::string>& s2) +namespace { +std::string intersect(const std::set<std::string>& s1, + const std::set<std::string>& s2) { std::set<std::string> intersect; std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), @@ -4358,9 +4310,9 @@ static std::string intersect(const std::set<std::string>& s1, return ""; } -static std::string intersect(const std::set<std::string>& s1, - const std::set<std::string>& s2, - const std::set<std::string>& s3) +std::string intersect(const std::set<std::string>& s1, + const std::set<std::string>& s2, + const std::set<std::string>& s3) { std::string result; result = intersect(s1, s2); @@ -4374,10 +4326,10 @@ static std::string intersect(const std::set<std::string>& s1, return intersect(s2, s3); } -static std::string intersect(const std::set<std::string>& s1, - const std::set<std::string>& s2, - const std::set<std::string>& s3, - const std::set<std::string>& s4) +std::string intersect(const std::set<std::string>& s1, + const std::set<std::string>& s2, + const std::set<std::string>& s3, + const std::set<std::string>& s4) { std::string result; result = intersect(s1, s2); @@ -4394,6 +4346,7 @@ static std::string intersect(const std::set<std::string>& s1, } return intersect(s2, s3, s4); } +} void cmGeneratorTarget::CheckPropertyCompatibility( cmComputeLinkInformation* info, const std::string& config) const diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 625dd45..385022c 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -13,6 +13,7 @@ #include "cmSystemTools.h" #include "cmake.h" +#include <string> #include <utility> static std::string cmIfCommandError( @@ -47,7 +48,7 @@ bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, } // execute the functions for the true parts of the if statement - cmExecutionStatus status; + cmExecutionStatus status(mf); int scopeDepth = 0; for (cmListFileFunction const& func : this->Functions) { // keep track of scope depth @@ -176,19 +177,19 @@ bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, } //========================================================================= -bool cmIfCommand::InvokeInitialPass( - const std::vector<cmListFileArgument>& args, cmExecutionStatus&) +bool cmIfCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& inStatus) { + cmMakefile& makefile = inStatus.GetMakefile(); std::string errorString; std::vector<cmExpandedCommandArgument> expandedArguments; - this->Makefile->ExpandArguments(args, expandedArguments); + makefile.ExpandArguments(args, expandedArguments); MessageType status; cmConditionEvaluator conditionEvaluator( - *(this->Makefile), this->Makefile->GetExecutionContext(), - this->Makefile->GetBacktrace()); + makefile, makefile.GetExecutionContext(), makefile.GetBacktrace()); bool isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, status); @@ -197,11 +198,11 @@ bool cmIfCommand::InvokeInitialPass( std::string err = "if " + cmIfCommandError(expandedArguments); err += errorString; if (status == MessageType::FATAL_ERROR) { - this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err); + makefile.IssueMessage(MessageType::FATAL_ERROR, err); cmSystemTools::SetFatalErrorOccured(); return true; } - this->Makefile->IssueMessage(status, err); + makefile.IssueMessage(status, err); } { @@ -213,7 +214,7 @@ bool cmIfCommand::InvokeInitialPass( fb->HasRun = true; } fb->Args = args; - this->Makefile->AddFunctionBlocker(std::move(fb)); + makefile.AddFunctionBlocker(std::move(fb)); } return true; diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index 4a67760..775e609 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -5,17 +5,12 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <string> #include <vector> -#include "cm_memory.hxx" - -#include "cmCommand.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" class cmExecutionStatus; -class cmExpandedCommandArgument; class cmMakefile; class cmIfFunctionBlocker : public cmFunctionBlocker @@ -34,37 +29,7 @@ public: }; /// Starts an if block -class cmIfCommand : public cmCommand -{ -public: - /** - * This is a virtual constructor for the command. - */ - std::unique_ptr<cmCommand> Clone() override - { - return cm::make_unique<cmIfCommand>(); - } - - /** - * This overrides the default InvokeInitialPass implementation. - * It records the arguments before expansion. - */ - bool InvokeInitialPass(const std::vector<cmListFileArgument>& args, - cmExecutionStatus&) override; - - /** - * This is called when the command is first encountered in - * the CMakeLists.txt file. - */ - bool InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) override - { - return false; - } - - // Filter the given variable definition based on policy CMP0054. - static const char* GetDefinitionIfUnquoted( - const cmMakefile* mf, cmExpandedCommandArgument const& argument); -}; +bool cmIfCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status); #endif diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index f5da2ee..78f4f83 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -247,7 +247,8 @@ bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, // function blocker if (initFunction) { this->Makefile->GetState()->AddScriptedCommand( - args[0], cm::make_unique<cmLoadedCommand>(initFunction)); + args[0], + cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction))); return true; } this->SetError("Attempt to load command failed. " diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4ffd6e0..d177278 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1134,11 +1134,13 @@ void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags, std::string const& linkLanguage, cmGeneratorTarget* target) { - this->AppendFlags( - flags, this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS")); - if (!config.empty()) { - std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + config; - this->AppendFlags(flags, this->Makefile->GetSafeDefinition(name)); + if (linkLanguage != "Swift") { + this->AppendFlags( + flags, this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS")); + if (!config.empty()) { + std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + config; + this->AppendFlags(flags, this->Makefile->GetSafeDefinition(name)); + } } this->AppendFlags(flags, target->GetProperty("STATIC_LIBRARY_FLAGS")); if (!config.empty()) { diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 6e65c6b..22748b4 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -17,35 +17,15 @@ #include "cmSystemTools.h" // define the class for macro commands -class cmMacroHelperCommand : public cmCommand +class cmMacroHelperCommand { public: /** - * This is a virtual constructor for the command. - */ - std::unique_ptr<cmCommand> Clone() override - { - auto newC = cm::make_unique<cmMacroHelperCommand>(); - // we must copy when we clone - newC->Args = this->Args; - newC->Functions = this->Functions; - newC->FilePath = this->FilePath; - newC->Policies = this->Policies; - return std::unique_ptr<cmCommand>(std::move(newC)); - } - - /** * This is called when the command is first encountered in * the CMakeLists.txt file. */ - bool InvokeInitialPass(const std::vector<cmListFileArgument>& args, - cmExecutionStatus&) override; - - bool InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) override - { - return false; - } + bool operator()(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& inStatus) const; std::vector<std::string> Args; std::vector<cmListFileFunction> Functions; @@ -53,12 +33,15 @@ public: std::string FilePath; }; -bool cmMacroHelperCommand::InvokeInitialPass( - const std::vector<cmListFileArgument>& args, cmExecutionStatus& inStatus) +bool cmMacroHelperCommand::operator()( + std::vector<cmListFileArgument> const& args, + cmExecutionStatus& inStatus) const { + cmMakefile& makefile = inStatus.GetMakefile(); + // Expand the argument list to the macro. std::vector<std::string> expandedArgs; - this->Makefile->ExpandArguments(args, expandedArgs); + makefile.ExpandArguments(args, expandedArgs); // make sure the number of arguments passed is at least the number // required by the signature @@ -66,11 +49,11 @@ bool cmMacroHelperCommand::InvokeInitialPass( std::string errorMsg = "Macro invoked with incorrect arguments for macro named: "; errorMsg += this->Args[0]; - this->SetError(errorMsg); + inStatus.SetError(errorMsg); return false; } - cmMakefile::MacroPushPop macroScope(this->Makefile, this->FilePath, + cmMakefile::MacroPushPop macroScope(&makefile, this->FilePath, this->Policies); // set the value of argc @@ -132,9 +115,8 @@ bool cmMacroHelperCommand::InvokeInitialPass( arg.Line = k.Line; newLFF.Arguments.push_back(std::move(arg)); } - cmExecutionStatus status; - if (!this->Makefile->ExecuteCommand(newLFF, status) || - status.GetNestedError()) { + cmExecutionStatus status(makefile); + if (!makefile.ExecuteCommand(newLFF, status) || status.GetNestedError()) { // The error message should have already included the call stack // so we do not need to report an error here. macroScope.Quiet(); @@ -166,11 +148,11 @@ bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, if (!this->Depth) { mf.AppendProperty("MACROS", this->Args[0].c_str()); // create a new command and add it to cmake - auto f = cm::make_unique<cmMacroHelperCommand>(); - f->Args = this->Args; - f->Functions = this->Functions; - f->FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f->Policies); + cmMacroHelperCommand f; + f.Args = this->Args; + f.Functions = this->Functions; + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); // remove the function blocker now that the macro is defined mf.RemoveFunctionBlocker(this, lff); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 1723c5a..3177adc 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -16,7 +16,6 @@ #include <utility> #include "cmAlgorithms.h" -#include "cmCommand.h" #include "cmCommandArgumentParserHelper.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" @@ -388,12 +387,8 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, } // Lookup the command prototype. - if (cmCommand* proto = + if (cmState::Command command = this->GetState()->GetCommandByExactName(lff.Name.Lower)) { - // Clone the prototype. - std::unique_ptr<cmCommand> pcmd(proto->Clone()); - pcmd->SetMakefile(this); - // Decide whether to invoke the command. if (!cmSystemTools::GetFatalErrorOccured()) { // if trace is enabled, print out invoke information @@ -401,13 +396,13 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, this->PrintCommandTrace(lff); } // Try invoking the command. - bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status); + bool invokeSucceeded = command(lff.Arguments, status); bool hadNestedError = status.GetNestedError(); if (!invokeSucceeded || hadNestedError) { if (!hadNestedError) { // The command invocation requested that we report an error. std::string const error = - std::string(lff.Name.Original) + " " + pcmd->GetError(); + std::string(lff.Name.Original) + " " + status.GetError(); this->IssueMessage(MessageType::FATAL_ERROR, error); } result = false; @@ -657,7 +652,7 @@ void cmMakefile::ReadListFile(cmListFile const& listFile, // Run the parsed commands. const size_t numberFunctions = listFile.Functions.size(); for (size_t i = 0; i < numberFunctions; ++i) { - cmExecutionStatus status; + cmExecutionStatus status(*this); this->ExecuteCommand(listFile.Functions[i], status); if (cmSystemTools::GetFatalErrorOccured()) { break; diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 5320ec5..58f3b2f 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -25,7 +25,6 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, auto i = args.cbegin(); auto type = MessageType::MESSAGE; - auto status = false; auto fatal = false; auto level = cmake::LogLevel::LOG_UNDEFINED; if (*i == "SEND_ERROR") { @@ -55,19 +54,15 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, } ++i; } else if (*i == "STATUS") { - status = true; level = cmake::LogLevel::LOG_STATUS; ++i; } else if (*i == "VERBOSE") { - status = true; level = cmake::LogLevel::LOG_VERBOSE; ++i; } else if (*i == "DEBUG") { - status = true; level = cmake::LogLevel::LOG_DEBUG; ++i; } else if (*i == "TRACE") { - status = true; level = cmake::LogLevel::LOG_TRACE; ++i; } else if (*i == "DEPRECATION") { @@ -105,17 +100,46 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, auto message = cmJoin(cmMakeRange(i, args.cend()), ""); - if (type != MessageType::MESSAGE) { - // we've overridden the message type, above, so display it directly - cmMessenger* m = this->Makefile->GetMessenger(); - m->DisplayMessage(type, message, this->Makefile->GetBacktrace()); - } else { - if (status) { - this->Makefile->DisplayStatus(message, -1); - } else { + if (cmake::LogLevel::LOG_NOTICE <= level) { + // Check if any indentation has requested: + // `CMAKE_MESSAGE_INDENT` is a list of "padding" pieces + // to be joined and prepended to the message lines. + auto indent = + cmJoin(cmSystemTools::ExpandedListArgument( + this->Makefile->GetSafeDefinition("CMAKE_MESSAGE_INDENT")), + ""); + // Make every line of the `message` indented + // NOTE Can't reuse `cmDocumentationFormatter::PrintPreformatted` + // here cuz it appends `\n` to the EOM ;-( + cmSystemTools::ReplaceString(message, "\n", "\n" + indent); + message = indent + message; + } + + switch (level) { + case cmake::LogLevel::LOG_ERROR: + case cmake::LogLevel::LOG_WARNING: + // we've overridden the message type, above, so display it directly + this->Makefile->GetMessenger()->DisplayMessage( + type, message, this->Makefile->GetBacktrace()); + break; + + case cmake::LogLevel::LOG_NOTICE: cmSystemTools::Message(message); - } + break; + + case cmake::LogLevel::LOG_STATUS: + case cmake::LogLevel::LOG_VERBOSE: + case cmake::LogLevel::LOG_DEBUG: + case cmake::LogLevel::LOG_TRACE: + this->Makefile->DisplayStatus(message, -1); + break; + + default: + assert("Unexpected log level! Review the `cmMessageCommand.cxx`." && + false); + break; } + if (fatal) { cmSystemTools::SetFatalErrorOccured(); } diff --git a/Source/cmReturnCommand.cxx b/Source/cmReturnCommand.cxx index ceea8b4..5905669 100644 --- a/Source/cmReturnCommand.cxx +++ b/Source/cmReturnCommand.cxx @@ -5,8 +5,8 @@ #include "cmExecutionStatus.h" // cmReturnCommand -bool cmReturnCommand::InitialPass(std::vector<std::string> const&, - cmExecutionStatus& status) +bool cmReturnCommand(std::vector<std::string> const&, + cmExecutionStatus& status) { status.SetReturnInvoked(); return true; diff --git a/Source/cmReturnCommand.h b/Source/cmReturnCommand.h index e9264d2..2404a36 100644 --- a/Source/cmReturnCommand.h +++ b/Source/cmReturnCommand.h @@ -8,34 +8,10 @@ #include <string> #include <vector> -#include "cm_memory.hxx" - -#include "cmCommand.h" - class cmExecutionStatus; -/** \class cmReturnCommand - * \brief Return from a directory or function - * - * cmReturnCommand returns from a directory or function - */ -class cmReturnCommand : public cmCommand -{ -public: - /** - * This is a virtual constructor for the command. - */ - std::unique_ptr<cmCommand> Clone() override - { - return cm::make_unique<cmReturnCommand>(); - } - - /** - * This is called when the command is first encountered in - * the CMakeLists.txt file. - */ - bool InitialPass(std::vector<std::string> const& args, - cmExecutionStatus& status) override; -}; +/// Return from a directory or function +bool cmReturnCommand(std::vector<std::string> const& args, + cmExecutionStatus& status); #endif diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 9748cf5..0b12a65 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -5,8 +5,8 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <assert.h> +#include <stdlib.h> #include <string.h> -#include <type_traits> #include <utility> #include "cm_memory.hxx" @@ -16,12 +16,13 @@ #include "cmCommand.h" #include "cmDefinitions.h" #include "cmDisallowedCommand.h" +#include "cmExecutionStatus.h" #include "cmGlobVerificationManager.h" #include "cmListFileCache.h" +#include "cmMakefile.h" #include "cmStatePrivate.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" -#include "cmUnexpectedCommand.h" #include "cmake.h" cmState::cmState() @@ -421,11 +422,31 @@ void cmState::SetIsGeneratorMultiConfig(bool b) void cmState::AddBuiltinCommand(std::string const& name, std::unique_ptr<cmCommand> command) { + this->AddBuiltinCommand(name, cmLegacyCommandWrapper(std::move(command))); +} + +void cmState::AddBuiltinCommand(std::string const& name, Command command) +{ assert(name == cmSystemTools::LowerCase(name)); assert(this->BuiltinCommands.find(name) == this->BuiltinCommands.end()); - this->BuiltinCommands.insert( - std::map<std::string, std::unique_ptr<cmCommand>>::value_type( - name, std::move(command))); + this->BuiltinCommands.emplace(name, std::move(command)); +} + +void cmState::AddBuiltinCommand(std::string const& name, + BuiltinCommand command) +{ + this->AddBuiltinCommand( + name, + [command](const std::vector<cmListFileArgument>& args, + cmExecutionStatus& status) -> bool { + std::vector<std::string> expandedArguments; + if (!status.GetMakefile().ExpandArguments(args, expandedArguments)) { + // There was an error expanding arguments. It was already + // reported, so we can skip this command without error. + return true; + } + return command(expandedArguments, status); + }); } void cmState::AddDisallowedCommand(std::string const& name, @@ -440,49 +461,46 @@ void cmState::AddDisallowedCommand(std::string const& name, void cmState::AddUnexpectedCommand(std::string const& name, const char* error) { - this->AddBuiltinCommand(name, - cm::make_unique<cmUnexpectedCommand>(name, error)); + this->AddBuiltinCommand( + name, + [name, error](std::vector<cmListFileArgument> const&, + cmExecutionStatus& status) -> bool { + const char* versionValue = + status.GetMakefile().GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); + if (name == "endif" && (!versionValue || atof(versionValue) <= 1.4)) { + return true; + } + status.SetError(error); + return false; + }); } -void cmState::AddScriptedCommand(std::string const& name, - std::unique_ptr<cmCommand> command) +void cmState::AddScriptedCommand(std::string const& name, Command command) { std::string sName = cmSystemTools::LowerCase(name); // if the command already exists, give a new name to the old command. - if (cmCommand* oldCmd = this->GetCommand(sName)) { - std::string const newName = "_" + sName; - auto pos = this->ScriptedCommands.find(newName); - if (pos != this->ScriptedCommands.end()) { - this->ScriptedCommands.erase(pos); - } - this->ScriptedCommands.insert(std::make_pair(newName, oldCmd->Clone())); + if (Command oldCmd = this->GetCommand(sName)) { + this->ScriptedCommands["_" + sName] = oldCmd; } - // if the command already exists, free the old one - auto pos = this->ScriptedCommands.find(sName); - if (pos != this->ScriptedCommands.end()) { - this->ScriptedCommands.erase(pos); - } - this->ScriptedCommands.insert( - std::map<std::string, std::unique_ptr<cmCommand>>::value_type( - sName, std::move(command))); + this->ScriptedCommands[sName] = std::move(command); } -cmCommand* cmState::GetCommand(std::string const& name) const +cmState::Command cmState::GetCommand(std::string const& name) const { return GetCommandByExactName(cmSystemTools::LowerCase(name)); } -cmCommand* cmState::GetCommandByExactName(std::string const& name) const +cmState::Command cmState::GetCommandByExactName(std::string const& name) const { auto pos = this->ScriptedCommands.find(name); if (pos != this->ScriptedCommands.end()) { - return pos->second.get(); + return pos->second; } pos = this->BuiltinCommands.find(name); if (pos != this->BuiltinCommands.end()) { - return pos->second.get(); + return pos->second; } return nullptr; } @@ -507,9 +525,7 @@ std::vector<std::string> cmState::GetCommandNames() const void cmState::RemoveBuiltinCommand(std::string const& name) { assert(name == cmSystemTools::LowerCase(name)); - auto i = this->BuiltinCommands.find(name); - assert(i != this->BuiltinCommands.end()); - this->BuiltinCommands.erase(i); + this->BuiltinCommands.erase(name); } void cmState::RemoveUserDefinedCommands() diff --git a/Source/cmState.h b/Source/cmState.h index 7e88030..8847f3b 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <functional> #include <map> #include <memory> #include <set> @@ -27,6 +28,7 @@ class cmGlobVerificationManager; class cmPropertyDefinition; class cmStateSnapshot; class cmMessenger; +class cmExecutionStatus; class cmState { @@ -141,19 +143,25 @@ public: bool GetIsGeneratorMultiConfig() const; void SetIsGeneratorMultiConfig(bool b); + using Command = std::function<bool(std::vector<cmListFileArgument> const&, + cmExecutionStatus&)>; + using BuiltinCommand = bool (*)(std::vector<std::string> const&, + cmExecutionStatus&); + // Returns a command from its name, case insensitive, or nullptr - cmCommand* GetCommand(std::string const& name) const; + Command GetCommand(std::string const& name) const; // Returns a command from its name, or nullptr - cmCommand* GetCommandByExactName(std::string const& name) const; + Command GetCommandByExactName(std::string const& name) const; void AddBuiltinCommand(std::string const& name, std::unique_ptr<cmCommand> command); + void AddBuiltinCommand(std::string const& name, Command command); + void AddBuiltinCommand(std::string const& name, BuiltinCommand command); void AddDisallowedCommand(std::string const& name, std::unique_ptr<cmCommand> command, cmPolicies::PolicyID policy, const char* message); void AddUnexpectedCommand(std::string const& name, const char* error); - void AddScriptedCommand(std::string const& name, - std::unique_ptr<cmCommand> command); + void AddScriptedCommand(std::string const& name, Command command); void RemoveBuiltinCommand(std::string const& name); void RemoveUserDefinedCommands(); std::vector<std::string> GetCommandNames() const; @@ -212,8 +220,8 @@ private: std::map<cmProperty::ScopeType, cmPropertyDefinitionMap> PropertyDefinitions; std::vector<std::string> EnabledLanguages; - std::map<std::string, std::unique_ptr<cmCommand>> BuiltinCommands; - std::map<std::string, std::unique_ptr<cmCommand>> ScriptedCommands; + std::map<std::string, Command> BuiltinCommands; + std::map<std::string, Command> ScriptedCommands; cmPropertyMap GlobalProperties; std::unique_ptr<cmCacheManager> CacheManager; std::unique_ptr<cmGlobVerificationManager> GlobVerificationManager; diff --git a/Source/cmUnexpectedCommand.cxx b/Source/cmUnexpectedCommand.cxx deleted file mode 100644 index a8de9e6..0000000 --- a/Source/cmUnexpectedCommand.cxx +++ /dev/null @@ -1,22 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmUnexpectedCommand.h" - -#include <stdlib.h> - -#include "cmMakefile.h" - -class cmExecutionStatus; - -bool cmUnexpectedCommand::InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) -{ - const char* versionValue = - this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); - if (this->Name == "endif" && (!versionValue || atof(versionValue) <= 1.4)) { - return true; - } - - this->SetError(this->Error); - return false; -} diff --git a/Source/cmUnexpectedCommand.h b/Source/cmUnexpectedCommand.h deleted file mode 100644 index 6e4cee5..0000000 --- a/Source/cmUnexpectedCommand.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmUnexpectedCommand_h -#define cmUnexpectedCommand_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include <string> -#include <utility> -#include <vector> - -#include "cm_memory.hxx" - -#include "cmCommand.h" - -class cmExecutionStatus; - -class cmUnexpectedCommand : public cmCommand -{ -public: - cmUnexpectedCommand(std::string name, const char* error) - : Name(std::move(name)) - , Error(error) - { - } - - std::unique_ptr<cmCommand> Clone() override - { - return cm::make_unique<cmUnexpectedCommand>(this->Name, this->Error); - } - - bool InitialPass(std::vector<std::string> const& args, - cmExecutionStatus& status) override; - -private: - std::string Name; - const char* Error; -}; - -#endif diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index afc0b76..83a774d 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -55,7 +55,7 @@ static void cmVariableWatchCommandVariableAccessed(const std::string& variable, newLFF.Arguments.emplace_back(stack, cmListFileArgument::Quoted, 9999); newLFF.Name = data->Command; newLFF.Line = 9999; - cmExecutionStatus status; + cmExecutionStatus status(*makefile); if (!makefile->ExecuteCommand(newLFF, status)) { std::ostringstream error; error << "Error in cmake code at\nUnknown:0:\n" diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index a902964..37d1c74 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -11,6 +11,7 @@ #include "cmMessageType.h" #include "cmSystemTools.h" +#include <string> #include <utility> cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf) @@ -82,7 +83,7 @@ bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, // Invoke all the functions that were collected in the block. for (cmListFileFunction const& fn : this->Functions) { - cmExecutionStatus status; + cmExecutionStatus status(mf); mf.ExecuteCommand(fn, status); if (status.GetReturnInvoked()) { inStatus.SetReturnInvoked(); @@ -129,19 +130,20 @@ bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } -bool cmWhileCommand::InvokeInitialPass( - const std::vector<cmListFileArgument>& args, cmExecutionStatus&) +bool cmWhileCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status) { if (args.empty()) { - this->SetError("called with incorrect number of arguments"); + status.SetError("called with incorrect number of arguments"); return false; } // create a function blocker { - auto fb = cm::make_unique<cmWhileFunctionBlocker>(this->Makefile); + cmMakefile& makefile = status.GetMakefile(); + auto fb = cm::make_unique<cmWhileFunctionBlocker>(&makefile); fb->Args = args; - this->Makefile->AddFunctionBlocker(std::move(fb)); + makefile.AddFunctionBlocker(std::move(fb)); } return true; } diff --git a/Source/cmWhileCommand.h b/Source/cmWhileCommand.h index 857d1c8..2257799 100644 --- a/Source/cmWhileCommand.h +++ b/Source/cmWhileCommand.h @@ -5,12 +5,8 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <string> #include <vector> -#include "cm_memory.hxx" - -#include "cmCommand.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" @@ -35,33 +31,7 @@ private: }; /// \brief Starts a while loop -class cmWhileCommand : public cmCommand -{ -public: - /** - * This is a virtual constructor for the command. - */ - std::unique_ptr<cmCommand> Clone() override - { - return cm::make_unique<cmWhileCommand>(); - } - - /** - * This overrides the default InvokeInitialPass implementation. - * It records the arguments before expansion. - */ - bool InvokeInitialPass(const std::vector<cmListFileArgument>& args, - cmExecutionStatus&) override; - - /** - * This is called when the command is first encountered in - * the CMakeLists.txt file. - */ - bool InitialPass(std::vector<std::string> const&, - cmExecutionStatus&) override - { - return false; - } -}; +bool cmWhileCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status); #endif diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index 37df57c..d93f280 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -33,6 +33,6 @@ run_cpack_test(TIMESTAMPS "DEB.TIMESTAMPS;TGZ" false "COMPONENT") unset(ENVIRONMENT) run_cpack_test(USER_FILELIST "RPM.USER_FILELIST" false "MONOLITHIC") run_cpack_test(MD5SUMS "DEB.MD5SUMS" false "MONOLITHIC;COMPONENT") -run_cpack_test(CPACK_INSTALL_SCRIPT "ZIP" false "MONOLITHIC") +run_cpack_test_subtests(CPACK_INSTALL_SCRIPTS "singular;plural;both" "ZIP" false "MONOLITHIC") run_cpack_test(DEB_PACKAGE_VERSION_BACK_COMPATIBILITY "DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY" false "MONOLITHIC;COMPONENT") run_cpack_test_subtests(EXTERNAL "none;good;good_multi;bad_major;bad_minor;invalid_good;invalid_bad;stage_and_package" "External" false "MONOLITHIC;COMPONENT") diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPT/test.cmake b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPT/test.cmake deleted file mode 100644 index e3fe0ca..0000000 --- a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPT/test.cmake +++ /dev/null @@ -1,11 +0,0 @@ -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/abc.txt" "test content") -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/user-script.cmake" - "file(INSTALL DESTINATION \"\${CMAKE_INSTALL_PREFIX}/foo\" - TYPE FILE FILES \"${CMAKE_CURRENT_BINARY_DIR}/abc.txt\")") -set(CPACK_INSTALL_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/user-script.cmake") - -function(run_after_include_cpack) - file(READ "${CPACK_OUTPUT_CONFIG_FILE}" conf_file_) - string(REGEX REPLACE "SET\\(CPACK_INSTALL_CMAKE_PROJECTS [^)]*\\)" "" conf_file_ "${conf_file_}") - file(WRITE "${CPACK_OUTPUT_CONFIG_FILE}" "${conf_file_}") -endfunction() diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPT/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/ExpectedFiles.cmake index 02a7821..02a7821 100644 --- a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPT/ExpectedFiles.cmake +++ b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/ExpectedFiles.cmake diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt new file mode 100644 index 0000000..666030e --- /dev/null +++ b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt @@ -0,0 +1 @@ +CPack Warning: Both CPACK_INSTALL_SCRIPTS and CPACK_INSTALL_SCRIPT are set, the latter will be ignored. diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake new file mode 100644 index 0000000..249d2e6 --- /dev/null +++ b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake @@ -0,0 +1,26 @@ +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/abc.txt" "test content") +set(user_script_ "${CMAKE_CURRENT_BINARY_DIR}/user-script.cmake") +file(WRITE "${user_script_}" + "file(INSTALL DESTINATION \"\${CMAKE_INSTALL_PREFIX}/foo\" + TYPE FILE FILES \"${CMAKE_CURRENT_BINARY_DIR}/abc.txt\")") + +if(RunCMake_SUBTEST_SUFFIX STREQUAL "both") + set(CPACK_INSTALL_SCRIPT "${user_script_}") + set(CPACK_INSTALL_SCRIPTS "${CPACK_INSTALL_SCRIPT}") + +elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "singular") + set(CPACK_INSTALL_SCRIPT "${user_script_}") + +elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "plural") + set(CPACK_INSTALL_SCRIPTS "${user_script_}") + +else() + message(FATAL_ERROR "Unexpected subtest name: ${RunCMake_SUBTEST_SUFFIX}") + +endif() + +function(run_after_include_cpack) + file(READ "${CPACK_OUTPUT_CONFIG_FILE}" conf_file_) + string(REGEX REPLACE "SET\\(CPACK_INSTALL_CMAKE_PROJECTS [^)]*\\)" "" conf_file_ "${conf_file_}") + file(WRITE "${CPACK_OUTPUT_CONFIG_FILE}" "${conf_file_}") +endfunction() diff --git a/Tests/RunCMake/message/RunCMakeTest.cmake b/Tests/RunCMake/message/RunCMakeTest.cmake index cecfc7f..3c7e51c 100644 --- a/Tests/RunCMake/message/RunCMakeTest.cmake +++ b/Tests/RunCMake/message/RunCMakeTest.cmake @@ -52,3 +52,12 @@ run_cmake_command( message-loglevel-trace ${CMAKE_COMMAND} --loglevel=trace -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake ) + +run_cmake_command( + message-indent + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-indent.cmake + ) +run_cmake_command( + message-indent-multiline + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-indent-multiline.cmake + ) diff --git a/Tests/RunCMake/message/message-indent-multiline-stderr.txt b/Tests/RunCMake/message/message-indent-multiline-stderr.txt new file mode 100644 index 0000000..5853a31 --- /dev/null +++ b/Tests/RunCMake/message/message-indent-multiline-stderr.txt @@ -0,0 +1,3 @@ + >This is + >the multiline + >message diff --git a/Tests/RunCMake/message/message-indent-multiline-stdout.txt b/Tests/RunCMake/message/message-indent-multiline-stdout.txt new file mode 100644 index 0000000..ae0c72e --- /dev/null +++ b/Tests/RunCMake/message/message-indent-multiline-stdout.txt @@ -0,0 +1,8 @@ +-- >This is + >the multiline + >message + > + > +-- >This is + >the multiline + >message diff --git a/Tests/RunCMake/message/message-indent-multiline.cmake b/Tests/RunCMake/message/message-indent-multiline.cmake new file mode 100644 index 0000000..0f789bf --- /dev/null +++ b/Tests/RunCMake/message/message-indent-multiline.cmake @@ -0,0 +1,13 @@ +# NOTE Use non-space indent string, to check indentation +# of line endings and "empty" lines. +# ALERT Do not put any space characters after the non-space! +list(APPEND CMAKE_MESSAGE_INDENT " >") +set(msg [[This is +the multiline +message]]) # No `\n` at the end! +# NOTE Two empty lines after the text +message(STATUS "${msg}\n\n") +message(STATUS "${msg}") +# This is just to make sure NOTICE messages are also get indented: +# https://gitlab.kitware.com/cmake/cmake/issues/19418#note_588011 +message(NOTICE "${msg}") diff --git a/Tests/RunCMake/message/message-indent-stdout.txt b/Tests/RunCMake/message/message-indent-stdout.txt new file mode 100644 index 0000000..b2c3c60 --- /dev/null +++ b/Tests/RunCMake/message/message-indent-stdout.txt @@ -0,0 +1,13 @@ +-- COUNTING: +-- COUNTING_ENGLISH: +-- one +-- two +-- three +-- four +-- five +-- COUNTING_BAHASA: +-- satu +-- dua +-- tiga +-- empat +-- lima diff --git a/Tests/RunCMake/message/message-indent.cmake b/Tests/RunCMake/message/message-indent.cmake new file mode 100644 index 0000000..c07ff45 --- /dev/null +++ b/Tests/RunCMake/message/message-indent.cmake @@ -0,0 +1,19 @@ +function(debug_list LIST_VAR) + message(STATUS "${LIST_VAR}:") + list(APPEND CMAKE_MESSAGE_INDENT " ") + foreach(_item IN LISTS ${LIST_VAR}) + list(LENGTH ${_item} _item_len) + if(_item_len GREATER 1) + debug_list(${_item}) + else() + message(STATUS "${_item}") + endif() + endforeach() +endfunction() + +list(APPEND COUNTING_ENGLISH one two three four five) +list(APPEND COUNTING_BAHASA satu dua tiga empat lima) + +list(APPEND COUNTING COUNTING_ENGLISH COUNTING_BAHASA) + +debug_list(COUNTING) diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 37522fc..bc8a7dc 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -449,7 +449,12 @@ if(CMAKE_USE_SECTRANSP) endif() if(CMAKE_USE_OPENSSL) - find_package(OpenSSL REQUIRED) + find_package(OpenSSL) + if(NOT OpenSSL_FOUND) + message(FATAL_ERROR + "Could not find OpenSSL. Install an OpenSSL development package or " + "configure CMake with -DCMAKE_USE_OPENSSL=OFF to build without OpenSSL.") + endif() set(SSL_ENABLED ON) set(USE_OPENSSL ON) set(HAVE_LIBCRYPTO ON) @@ -440,7 +440,6 @@ CMAKE_CXX_SOURCES="\ cmTimestamp \ cmTryCompileCommand \ cmTryRunCommand \ - cmUnexpectedCommand \ cmUnsetCommand \ cmUVHandlePtr \ cmUVProcessChain \ @@ -1125,6 +1124,25 @@ echo ' #error "SunPro <= 5.13 mode not supported due to bug in move semantics." #endif +#if __cplusplus > 201103L +#include <iterator> +int check_cxx14() +{ + int a[] = { 0, 1, 2 }; + auto ai = std::cbegin(a); + + int b[] = { 2, 1, 0 }; + auto bi = std::cend(b); + + return *ai + *(bi - 1); +} +#else +int check_cxx14() +{ + return 0; +} +#endif + class Class { public: @@ -1135,7 +1153,7 @@ private: int main() { auto const c = std::unique_ptr<Class>(new Class); - std::cout << c->Get() << std::endl; + std::cout << c->Get() << check_cxx14() << std::endl; return 0; } ' > "${TMPFILE}.cxx" |