diff options
64 files changed, 886 insertions, 695 deletions
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst index 23f0515..db71c87 100644 --- a/Help/cpack_gen/deb.rst +++ b/Help/cpack_gen/deb.rst @@ -179,16 +179,24 @@ List of CPack DEB generator specific variables: * Default : ``CPACK_PACKAGE_CONTACT`` .. variable:: CPACK_DEBIAN_PACKAGE_DESCRIPTION - CPACK_COMPONENT_<COMPONENT>_DESCRIPTION + CPACK_DEBIAN_<COMPONENT>_DESCRIPTION The Debian package description * Mandatory : YES * Default : - - :variable:`CPACK_DEBIAN_PACKAGE_DESCRIPTION` if set or - - :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` + - :variable:`CPACK_DEBIAN_<COMPONENT>_DESCRIPTION` (component + based installers only) if set, or :variable:`CPACK_DEBIAN_PACKAGE_DESCRIPTION` if set, or + - :variable:`CPACK_COMPONENT_<compName>_DESCRIPTION` (component + based installers only) if set, or :variable:`CPACK_PACKAGE_DESCRIPTION` if set, or + - content of the file specified in :variable:`CPACK_PACKAGE_DESCRIPTION_FILE` if set + If after that description is not set, :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` going to be + used if set. Otherwise, :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` will be added as the first + line of description as defined in `Debian Policy Manual`_. + +.. _Debian Policy Manual: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description .. variable:: CPACK_DEBIAN_PACKAGE_SECTION CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake index 7791822..ad8e078 100644 --- a/Modules/Internal/CPack/CPackDeb.cmake +++ b/Modules/Internal/CPack/CPackDeb.cmake @@ -56,6 +56,67 @@ function(extract_so_info shared_object libname version) endif() endfunction() +function(cpack_deb_check_description SUMMARY LINES RESULT_VARIABLE) + set(_result TRUE) + + # Get the summary line + if(NOT SUMMARY MATCHES "^[^\\s].*$") + set(_result FALSE) + set(${RESULT_VARIABLE} ${_result} PARENT_SCOPE) + return() + endif() + + foreach(_line IN LISTS LINES) + if(NOT _line MATCHES "^ +[^ ]+.*$") + set(_result FALSE) + break() + endif() + endforeach() + + set(${RESULT_VARIABLE} ${_result} PARENT_SCOPE) +endfunction() + +function(cpack_deb_format_package_description TEXT OUTPUT_VAR) + # Turn the possible multi-line string into a list + string(UUID uuid NAMESPACE 00000000-0000-0000-0000-000000000000 TYPE SHA1) + string(REPLACE ";" "${uuid}" _text "${TEXT}") + string(REPLACE "\n" ";" _lines "${_text}") + list(POP_FRONT _lines _summary) + + # Check if reformatting required + cpack_deb_check_description("${_summary}" "${_lines}" _result) + if(_result) + # Ok, no formatting required + set(${OUTPUT_VAR} "${TEXT}" PARENT_SCOPE) + return() + endif() + + # Format the summary line + string(STRIP "${_summary}" _summary) + + # Make sure the rest formatted properly + set(_result) + foreach(_line IN LISTS _lines) + string(STRIP "${_line}" _line_strip) + if(NOT _line_strip) + # Replace empty lines w/ a _single full stop character_ + set(_line " .") + else() + # Prepend the normal lines w/ a single space. + # If the line already starts w/ at least one space, + # it'll become _verbatim_ (assuming it supposed to be + # verbatim in the original text). + string(PREPEND _line " ") + endif() + list(APPEND _result "${_line}") + endforeach() + + list(PREPEND _result "${_summary}") + list(JOIN _result "\n" _result) + string(REPLACE "${uuid}" ";" _result "${_result}") + set(${OUTPUT_VAR} "${_result}" PARENT_SCOPE) +endfunction() + function(cpack_deb_prepare_package_vars) # CPACK_DEBIAN_PACKAGE_SHLIBDEPS # If specify OFF, only user depends are used @@ -102,7 +163,7 @@ function(cpack_deb_prepare_package_vars) RESULT_VARIABLE FILE_RESULT_ OUTPUT_VARIABLE INSTALL_FILE_) if(NOT FILE_RESULT_ EQUAL 0) - message (FATAL_ERROR "CPackDeb: execution of command: '${FILE_EXECUTABLE} ./${FILE_}' failed with exit code: ${FILE_RESULT_}") + message(FATAL_ERROR "CPackDeb: execution of command: '${FILE_EXECUTABLE} ./${FILE_}' failed with exit code: ${FILE_RESULT_}") endif() list(APPEND CPACK_DEB_INSTALL_FILES "${INSTALL_FILE_}") endforeach() @@ -210,7 +271,7 @@ function(cpack_deb_prepare_package_vars) if(_TMP_VERSION MATCHES "dpkg-shlibdeps version ([0-9]+\\.[0-9]+\\.[0-9]+)") set(SHLIBDEPS_EXECUTABLE_VERSION "${CMAKE_MATCH_1}") else() - set(SHLIBDEPS_EXECUTABLE_VERSION "") + unset(SHLIBDEPS_EXECUTABLE_VERSION) endif() if(CPACK_DEBIAN_PACKAGE_DEBUG) @@ -253,7 +314,7 @@ function(cpack_deb_prepare_package_vars) message( "CPackDeb Debug: dpkg-shlibdeps warnings \n${SHLIBDEPS_ERROR}") endif() if(NOT SHLIBDEPS_RESULT EQUAL 0) - message (FATAL_ERROR "CPackDeb: dpkg-shlibdeps: '${SHLIBDEPS_ERROR}';\n" + message(FATAL_ERROR "CPackDeb: dpkg-shlibdeps: '${SHLIBDEPS_ERROR}';\n" "executed command: '${SHLIBDEPS_EXECUTABLE} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}';\n" "found files: '${INSTALL_FILE_}';\n" "files info: '${CPACK_DEB_INSTALL_FILES}';\n" @@ -388,7 +449,7 @@ function(cpack_deb_prepare_package_vars) # if per-component variable, overrides the global CPACK_DEBIAN_PACKAGE_${variable_type_} # automatic dependency discovery will be performed afterwards. if(CPACK_DEB_PACKAGE_COMPONENT) - foreach(value_type_ DEPENDS RECOMMENDS SUGGESTS PREDEPENDS ENHANCES BREAKS CONFLICTS PROVIDES REPLACES SOURCE SECTION PRIORITY NAME) + foreach(value_type_ IN ITEMS DEPENDS RECOMMENDS SUGGESTS PREDEPENDS ENHANCES BREAKS CONFLICTS PROVIDES REPLACES SOURCE SECTION PRIORITY NAME) set(_component_var "CPACK_DEBIAN_${_local_component_name}_PACKAGE_${value_type_}") # if set, overrides the global variable @@ -402,21 +463,15 @@ function(cpack_deb_prepare_package_vars) endforeach() if(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS) - set(COMPONENT_DEPENDS "") - foreach (_PACK ${CPACK_COMPONENT_${_local_component_name}_DEPENDS}) + unset(COMPONENT_DEPENDS) + foreach(_PACK IN LISTS CPACK_COMPONENT_${_local_component_name}_DEPENDS) get_component_package_name(_PACK_NAME "${_PACK}") - if(COMPONENT_DEPENDS) - set(COMPONENT_DEPENDS "${_PACK_NAME} (= ${CPACK_DEBIAN_PACKAGE_VERSION}), ${COMPONENT_DEPENDS}") - else() - set(COMPONENT_DEPENDS "${_PACK_NAME} (= ${CPACK_DEBIAN_PACKAGE_VERSION})") - endif() + list(PREPEND COMPONENT_DEPENDS "${_PACK_NAME} (= ${CPACK_DEBIAN_PACKAGE_VERSION})") endforeach() + list(JOIN COMPONENT_DEPENDS ", " COMPONENT_DEPENDS) if(COMPONENT_DEPENDS) - if(CPACK_DEBIAN_PACKAGE_DEPENDS) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${COMPONENT_DEPENDS}, ${CPACK_DEBIAN_PACKAGE_DEPENDS}") - else() - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${COMPONENT_DEPENDS}") - endif() + list(PREPEND CPACK_DEBIAN_PACKAGE_DEPENDS ${COMPONENT_DEPENDS}) + list(JOIN CPACK_DEBIAN_PACKAGE_DEPENDS ", " CPACK_DEBIAN_PACKAGE_DEPENDS) endif() endif() endif() @@ -424,12 +479,9 @@ function(cpack_deb_prepare_package_vars) # at this point, the CPACK_DEBIAN_PACKAGE_DEPENDS is properly set # to the minimal dependency of the package # Append automatically discovered dependencies . - if(NOT "${CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS}" STREQUAL "") - if (CPACK_DEBIAN_PACKAGE_DEPENDS) - set (CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, ${CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS}") - else () - set (CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS}") - endif () + if(CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS) + list(APPEND CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS}) + list(JOIN CPACK_DEBIAN_PACKAGE_DEPENDS ", " CPACK_DEBIAN_PACKAGE_DEPENDS) endif() if(NOT CPACK_DEBIAN_PACKAGE_DEPENDS) @@ -445,26 +497,53 @@ function(cpack_deb_prepare_package_vars) endif() # Description: (mandatory) - if(NOT CPACK_DEB_PACKAGE_COMPONENT) - if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION) - if(NOT CPACK_PACKAGE_DESCRIPTION_SUMMARY) - message(FATAL_ERROR "CPackDeb: Debian package requires a summary for a package, set CPACK_PACKAGE_DESCRIPTION_SUMMARY or CPACK_DEBIAN_PACKAGE_DESCRIPTION") - endif() - set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}) - endif() + # Try package description first + if(CPACK_DEB_PACKAGE_COMPONENT) + cpack_deb_variable_fallback("CPACK_DEBIAN_PACKAGE_DESCRIPTION" + "CPACK_DEBIAN_${_local_component_name}_DESCRIPTION" + "CPACK_COMPONENT_${_local_component_name}_DESCRIPTION") else() - set(component_description_var CPACK_COMPONENT_${_local_component_name}_DESCRIPTION) - - # component description overrides package description - if(${component_description_var}) - set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${${component_description_var}}) - elseif(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION) - if(NOT CPACK_PACKAGE_DESCRIPTION_SUMMARY) - message(FATAL_ERROR "CPackDeb: Debian package requires a summary for a package, set CPACK_PACKAGE_DESCRIPTION_SUMMARY or CPACK_DEBIAN_PACKAGE_DESCRIPTION or ${component_description_var}") - endif() + cpack_deb_variable_fallback("CPACK_DEBIAN_PACKAGE_DESCRIPTION" + "CPACK_DEBIAN_PACKAGE_DESCRIPTION" + "CPACK_PACKAGE_DESCRIPTION") + endif() + + # Still no description? ... and description file has set ... + if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION AND CPACK_PACKAGE_DESCRIPTION_FILE) + # Read `CPACK_PACKAGE_DESCRIPTION_FILE` then... + file(READ ${CPACK_PACKAGE_DESCRIPTION_FILE} CPACK_DEBIAN_PACKAGE_DESCRIPTION) + endif() + + # Still no description? #2 + if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION) + # Try to get `CPACK_PACKAGE_DESCRIPTION_SUMMARY` as the last hope + if(CPACK_PACKAGE_DESCRIPTION_SUMMARY) set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}) + else() + # Giving up! Report an error... + set(_description_failure_message + "CPackDeb: Debian package requires a summary for a package, set CPACK_PACKAGE_DESCRIPTION_SUMMARY or CPACK_DEBIAN_PACKAGE_DESCRIPTION") + if(CPACK_DEB_PACKAGE_COMPONENT) + string(APPEND _description_failure_message + " or CPACK_DEBIAN_${_local_component_name}_DESCRIPTION") + endif() + message(FATAL_ERROR _description_failure_message) endif() + + # Ok, description has set. According to the `Debian Policy Manual`_ the frist + # line is a pacakge summary. Try to get it as well... + # See also: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description + elseif(CPACK_PACKAGE_DESCRIPTION_SUMMARY) + # Merge summary w/ the detailed description + string(PREPEND CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n") endif() + # assert(CPACK_DEBIAN_PACKAGE_DESCRIPTION) + + # Make sure description is properly formatted + cpack_deb_format_package_description( + "${CPACK_DEBIAN_PACKAGE_DESCRIPTION}" + CPACK_DEBIAN_PACKAGE_DESCRIPTION + ) # Homepage: (optional) if(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE AND CMAKE_PROJECT_HOMEPAGE_URL) @@ -519,7 +598,7 @@ function(cpack_deb_prepare_package_vars) # Are we packaging components ? if(CPACK_DEB_PACKAGE_COMPONENT) # override values with per component version if set - foreach(VAR_NAME_ "PACKAGE_CONTROL_EXTRA" "PACKAGE_CONTROL_STRICT_PERMISSION") + foreach(VAR_NAME_ IN ITEMS PACKAGE_CONTROL_EXTRA PACKAGE_CONTROL_STRICT_PERMISSION) if(CPACK_DEBIAN_${_local_component_name}_${VAR_NAME_}) set(CPACK_DEBIAN_${VAR_NAME_} "${CPACK_DEBIAN_${_local_component_name}_${VAR_NAME_}}") endif() @@ -527,12 +606,12 @@ function(cpack_deb_prepare_package_vars) get_component_package_name(CPACK_DEBIAN_PACKAGE_NAME ${_local_component_name}) endif() - set(CPACK_DEBIAN_PACKAGE_SHLIBS_LIST "") - - if (NOT CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY) + if(NOT CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY) set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=") endif() + unset(CPACK_DEBIAN_PACKAGE_SHLIBS_LIST) + if(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS) if(READELF_EXECUTABLE) foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES) @@ -544,9 +623,7 @@ function(cpack_deb_prepare_package_vars) message(AUTHOR_WARNING "Shared library '${_FILE}' is missing soname or soversion. Library will not be added to DEBIAN/shlibs control file.") endif() endforeach() - if (CPACK_DEBIAN_PACKAGE_SHLIBS_LIST) - string(REPLACE ";" "\n" CPACK_DEBIAN_PACKAGE_SHLIBS_LIST "${CPACK_DEBIAN_PACKAGE_SHLIBS_LIST}") - endif() + list(JOIN CPACK_DEBIAN_PACKAGE_SHLIBS_LIST "\n" CPACK_DEBIAN_PACKAGE_SHLIBS_LIST) else() message(FATAL_ERROR "Readelf utility is not available. CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS option is not available.") endif() @@ -554,7 +631,7 @@ function(cpack_deb_prepare_package_vars) # add ldconfig call in default postrm and postint set(CPACK_ADD_LDCONFIG_CALL 0) - foreach(_FILE ${CPACK_DEB_SHARED_OBJECT_FILES}) + foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES) get_filename_component(_DIR ${_FILE} DIRECTORY) # all files in CPACK_DEB_SHARED_OBJECT_FILES have dot at the beginning if(_DIR STREQUAL "./lib" OR _DIR STREQUAL "./usr/lib") @@ -565,12 +642,12 @@ function(cpack_deb_prepare_package_vars) if(CPACK_ADD_LDCONFIG_CALL) set(CPACK_DEBIAN_GENERATE_POSTINST 1) set(CPACK_DEBIAN_GENERATE_POSTRM 1) - foreach(f ${PACKAGE_CONTROL_EXTRA}) + foreach(f IN LISTS PACKAGE_CONTROL_EXTRA) get_filename_component(n "${f}" NAME) - if("${n}" STREQUAL "postinst") + if(n STREQUAL "postinst") set(CPACK_DEBIAN_GENERATE_POSTINST 0) endif() - if("${n}" STREQUAL "postrm") + if(n STREQUAL "postrm") set(CPACK_DEBIAN_GENERATE_POSTRM 0) endif() endforeach() @@ -671,7 +748,7 @@ function(cpack_deb_prepare_package_vars) if(BUILD_IDS) set(GEN_DBGSYMDIR "${DBGSYMDIR}" PARENT_SCOPE) set(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DBGSYM_OUTPUT_FILE_NAME}" PARENT_SCOPE) - string(REPLACE ";" " " BUILD_IDS "${BUILD_IDS}") + list(JOIN BUILD_IDS " " BUILD_IDS) set(GEN_BUILD_IDS "${BUILD_IDS}" PARENT_SCOPE) endif() endfunction() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 8ed7b2f..71a7dbd 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -168,6 +168,8 @@ set(SRCS cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h cmCacheManager.cxx cmCacheManager.h + cmCheckCustomOutputs.h + cmCheckCustomOutputs.cxx cmCLocaleEnvironmentScope.h cmCLocaleEnvironmentScope.cxx cmCommandArgumentParserHelper.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index f85707d..d24c2c0 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 15) -set(CMake_VERSION_PATCH 20190924) +set(CMake_VERSION_PATCH 20190925) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 02b00e3..ce690f9 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -9,6 +9,7 @@ #include "cmMessageType.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cm_static_string_view.hxx" #include "cmake.h" #include <cstring> @@ -16,17 +17,15 @@ class cmExecutionStatus; -cmCTestBuildCommand::cmCTestBuildCommand() +void cmCTestBuildCommand::BindArguments() { - this->GlobalGenerator = nullptr; - this->Arguments[ctb_NUMBER_ERRORS] = "NUMBER_ERRORS"; - this->Arguments[ctb_NUMBER_WARNINGS] = "NUMBER_WARNINGS"; - this->Arguments[ctb_TARGET] = "TARGET"; - this->Arguments[ctb_CONFIGURATION] = "CONFIGURATION"; - this->Arguments[ctb_FLAGS] = "FLAGS"; - this->Arguments[ctb_PROJECT_NAME] = "PROJECT_NAME"; - this->Arguments[ctb_LAST] = nullptr; - this->Last = ctb_LAST; + this->cmCTestHandlerCommand::BindArguments(); + this->Bind("NUMBER_ERRORS"_s, this->NumberErrors); + this->Bind("NUMBER_WARNINGS"_s, this->NumberWarnings); + this->Bind("TARGET"_s, this->Target); + this->Bind("CONFIGURATION"_s, this->Configuration); + this->Bind("FLAGS"_s, this->Flags); + this->Bind("PROJECT_NAME"_s, this->ProjectName); } cmCTestBuildCommand::~cmCTestBuildCommand() @@ -60,20 +59,17 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() // const char* ctestBuildConfiguration = this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION"); - const char* cmakeBuildConfiguration = - (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION]) - ? this->Values[ctb_CONFIGURATION] + const char* cmakeBuildConfiguration = !this->Configuration.empty() + ? this->Configuration.c_str() : ((ctestBuildConfiguration && *ctestBuildConfiguration) ? ctestBuildConfiguration : this->CTest->GetConfigType().c_str()); - const char* cmakeBuildAdditionalFlags = - (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS]) - ? this->Values[ctb_FLAGS] + const char* cmakeBuildAdditionalFlags = !this->Flags.empty() + ? this->Flags.c_str() : this->Makefile->GetDefinition("CTEST_BUILD_FLAGS"); - const char* cmakeBuildTarget = - (this->Values[ctb_TARGET] && *this->Values[ctb_TARGET]) - ? this->Values[ctb_TARGET] + const char* cmakeBuildTarget = !this->Target.empty() + ? this->Target.c_str() : this->Makefile->GetDefinition("CTEST_BUILD_TARGET"); if (cmakeGeneratorName && *cmakeGeneratorName) { @@ -153,16 +149,13 @@ bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus& status) { bool ret = cmCTestHandlerCommand::InitialPass(args, status); - if (this->Values[ctb_NUMBER_ERRORS] && *this->Values[ctb_NUMBER_ERRORS]) { + if (!this->NumberErrors.empty()) { this->Makefile->AddDefinition( - this->Values[ctb_NUMBER_ERRORS], - std::to_string(this->Handler->GetTotalErrors())); + this->NumberErrors, std::to_string(this->Handler->GetTotalErrors())); } - if (this->Values[ctb_NUMBER_WARNINGS] && - *this->Values[ctb_NUMBER_WARNINGS]) { + if (!this->NumberWarnings.empty()) { this->Makefile->AddDefinition( - this->Values[ctb_NUMBER_WARNINGS], - std::to_string(this->Handler->GetTotalWarnings())); + this->NumberWarnings, std::to_string(this->Handler->GetTotalWarnings())); } return ret; } diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h index 14f70bf..791e1f0 100644 --- a/Source/CTest/cmCTestBuildCommand.h +++ b/Source/CTest/cmCTestBuildCommand.h @@ -27,7 +27,6 @@ class cmGlobalGenerator; class cmCTestBuildCommand : public cmCTestHandlerCommand { public: - cmCTestBuildCommand(); ~cmCTestBuildCommand() override; /** @@ -49,23 +48,19 @@ public: bool InitialPass(std::vector<std::string> const& args, cmExecutionStatus& status) override; - cmGlobalGenerator* GlobalGenerator; + cmGlobalGenerator* GlobalGenerator = nullptr; protected: cmCTestBuildHandler* Handler; - enum - { - ctb_BUILD = ct_LAST, - ctb_NUMBER_ERRORS, - ctb_NUMBER_WARNINGS, - ctb_TARGET, - ctb_CONFIGURATION, - ctb_FLAGS, - ctb_PROJECT_NAME, - ctb_LAST - }; - + void BindArguments() override; cmCTestGenericHandler* InitializeHandler() override; + + std::string NumberErrors; + std::string NumberWarnings; + std::string Target; + std::string Configuration; + std::string Flags; + std::string ProjectName; }; #endif diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index 8a56f3d..948b9fb 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -8,25 +8,25 @@ #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cm_static_string_view.hxx" #include "cmake.h" #include <cstring> #include <sstream> #include <vector> -cmCTestConfigureCommand::cmCTestConfigureCommand() +void cmCTestConfigureCommand::BindArguments() { - this->Arguments[ctc_OPTIONS] = "OPTIONS"; - this->Arguments[ctc_LAST] = nullptr; - this->Last = ctc_LAST; + this->cmCTestHandlerCommand::BindArguments(); + this->Bind("OPTIONS"_s, this->Options); } cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() { std::vector<std::string> options; - if (this->Values[ctc_OPTIONS]) { - cmExpandList(this->Values[ctc_OPTIONS], options); + if (!this->Options.empty()) { + cmExpandList(this->Options, options); } if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) { diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h index 36ca7d5..0bc7848 100644 --- a/Source/CTest/cmCTestConfigureCommand.h +++ b/Source/CTest/cmCTestConfigureCommand.h @@ -23,8 +23,6 @@ class cmCTestGenericHandler; class cmCTestConfigureCommand : public cmCTestHandlerCommand { public: - cmCTestConfigureCommand(); - /** * This is a virtual constructor for the command. */ @@ -42,14 +40,10 @@ public: std::string GetName() const override { return "ctest_configure"; } protected: + void BindArguments() override; cmCTestGenericHandler* InitializeHandler() override; - enum - { - ctc_FIRST = ct_LAST, - ctc_OPTIONS, - ctc_LAST - }; + std::string Options; }; #endif diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx index 07aae76..b66bba7 100644 --- a/Source/CTest/cmCTestCoverageCommand.cxx +++ b/Source/CTest/cmCTestCoverageCommand.cxx @@ -2,14 +2,26 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestCoverageCommand.h" +#include <set> + +#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestCoverageHandler.h" +#include "cm_static_string_view.hxx" class cmCTestGenericHandler; -cmCTestCoverageCommand::cmCTestCoverageCommand() +void cmCTestCoverageCommand::BindArguments() +{ + this->cmCTestHandlerCommand::BindArguments(); + this->Bind("LABELS"_s, this->Labels); +} + +void cmCTestCoverageCommand::CheckArguments( + std::vector<std::string> const& keywords) { - this->LabelsMentioned = false; + this->LabelsMentioned = + !this->Labels.empty() || cmContains(keywords, "LABELS"); } cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() @@ -24,34 +36,10 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() // If a LABELS option was given, select only files with the labels. if (this->LabelsMentioned) { - handler->SetLabelFilter(this->Labels); + handler->SetLabelFilter( + std::set<std::string>(this->Labels.begin(), this->Labels.end())); } handler->SetQuiet(this->Quiet); return handler; } - -bool cmCTestCoverageCommand::CheckArgumentKeyword(std::string const& arg) -{ - // Look for arguments specific to this command. - if (arg == "LABELS") { - this->ArgumentDoing = ArgumentDoingLabels; - this->LabelsMentioned = true; - return true; - } - - // Look for other arguments. - return this->Superclass::CheckArgumentKeyword(arg); -} - -bool cmCTestCoverageCommand::CheckArgumentValue(std::string const& arg) -{ - // Handle states specific to this command. - if (this->ArgumentDoing == ArgumentDoingLabels) { - this->Labels.insert(arg); - return true; - } - - // Look for other arguments. - return this->Superclass::CheckArgumentValue(arg); -} diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index 75aefdf..fcffa75 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -8,9 +8,9 @@ #include "cmCTestHandlerCommand.h" #include "cmCommand.h" -#include <set> #include <string> #include <utility> +#include <vector> #include <cm/memory> @@ -24,8 +24,6 @@ class cmCTestGenericHandler; class cmCTestCoverageCommand : public cmCTestHandlerCommand { public: - cmCTestCoverageCommand(); - /** * This is a virtual constructor for the command. */ @@ -42,22 +40,13 @@ public: */ std::string GetName() const override { return "ctest_coverage"; } - using Superclass = cmCTestHandlerCommand; - protected: + void BindArguments() override; + void CheckArguments(std::vector<std::string> const& keywords) override; cmCTestGenericHandler* InitializeHandler() override; - bool CheckArgumentKeyword(std::string const& arg) override; - bool CheckArgumentValue(std::string const& arg) override; - - enum - { - ArgumentDoingLabels = Superclass::ArgumentDoingLast1, - ArgumentDoingLast2 - }; - bool LabelsMentioned; - std::set<std::string> Labels; + std::vector<std::string> Labels; }; #endif diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 9c5425d..3f9ce4e 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -7,31 +7,16 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" +#include "cm_static_string_view.hxx" +#include <algorithm> #include <cstdlib> #include <cstring> #include <sstream> -cmCTestHandlerCommand::cmCTestHandlerCommand() -{ - const size_t INIT_SIZE = 100; - size_t cc; - this->Arguments.reserve(INIT_SIZE); - for (cc = 0; cc < INIT_SIZE; ++cc) { - this->Arguments.push_back(nullptr); - } - this->Arguments[ct_RETURN_VALUE] = "RETURN_VALUE"; - this->Arguments[ct_CAPTURE_CMAKE_ERROR] = "CAPTURE_CMAKE_ERROR"; - this->Arguments[ct_SOURCE] = "SOURCE"; - this->Arguments[ct_BUILD] = "BUILD"; - this->Arguments[ct_SUBMIT_INDEX] = "SUBMIT_INDEX"; - this->Last = ct_LAST; - this->AppendXML = false; - this->Quiet = false; -} - namespace { // class to save and restore the error state for ctest_* commands // if a ctest_* command has a CAPTURE_CMAKE_ERROR then put the error @@ -90,30 +75,30 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, // save error state and restore it if needed SaveRestoreErrorState errorState; // Allocate space for argument values. - this->Values.clear(); - this->Values.resize(this->Last, nullptr); + this->BindArguments(); // Process input arguments. - this->ArgumentDoing = ArgumentDoingNone; - // look at all arguments and do not short circuit on the first - // bad one so that CAPTURE_CMAKE_ERROR can override setting the - // global error state - bool foundBadArgument = false; - for (std::string const& arg : args) { - // Check this argument. - if (!this->CheckArgumentKeyword(arg) && !this->CheckArgumentValue(arg)) { - std::ostringstream e; - e << "called with unknown argument \"" << arg << "\"."; - this->SetError(e.str()); - foundBadArgument = true; - } - // note bad argument - if (this->ArgumentDoing == ArgumentDoingError) { - foundBadArgument = true; - } + std::vector<std::string> unparsedArguments; + std::vector<std::string> keywordsMissingValue; + std::vector<std::string> parsedKeywords; + this->Parse(args, &unparsedArguments, &keywordsMissingValue, + &parsedKeywords); + this->CheckArguments(keywordsMissingValue); + + std::sort(parsedKeywords.begin(), parsedKeywords.end()); + auto it = std::adjacent_find(parsedKeywords.begin(), parsedKeywords.end()); + if (it != parsedKeywords.end()) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Called with more than one value for ", *it)); + } + + bool const foundBadArgument = !unparsedArguments.empty(); + if (foundBadArgument) { + this->SetError(cmStrCat("called with unknown argument \"", + unparsedArguments.front(), "\".")); } - bool captureCMakeError = (this->Values[ct_CAPTURE_CMAKE_ERROR] && - *this->Values[ct_CAPTURE_CMAKE_ERROR]); + bool const captureCMakeError = !this->CaptureCMakeError.empty(); // now that arguments are parsed check to see if there is a // CAPTURE_CMAKE_ERROR specified let the errorState object know. if (captureCMakeError) { @@ -123,8 +108,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, if (foundBadArgument) { // store the cmake error if (captureCMakeError) { - this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], - "-1"); + this->Makefile->AddDefinition(this->CaptureCMakeError, "-1"); 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"); @@ -146,10 +130,9 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, this->CTest->SetConfigType(ctestConfigType); } - if (this->Values[ct_BUILD]) { + if (!this->Build.empty()) { this->CTest->SetCTestConfiguration( - "BuildDirectory", - cmSystemTools::CollapseFullPath(this->Values[ct_BUILD]).c_str(), + "BuildDirectory", cmSystemTools::CollapseFullPath(this->Build).c_str(), this->Quiet); } else { std::string const& bdir = @@ -163,13 +146,11 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, "CTEST_BINARY_DIRECTORY not set" << std::endl;); } } - if (this->Values[ct_SOURCE]) { + if (!this->Source.empty()) { cmCTestLog(this->CTest, DEBUG, - "Set source directory to: " << this->Values[ct_SOURCE] - << std::endl); + "Set source directory to: " << this->Source << std::endl); this->CTest->SetCTestConfiguration( - "SourceDirectory", - cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(), + "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source).c_str(), this->Quiet); } else { this->CTest->SetCTestConfiguration( @@ -192,8 +173,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, "Cannot instantiate test handler " << this->GetName() << std::endl); if (captureCMakeError) { - this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], - "-1"); + this->Makefile->AddDefinition(this->CaptureCMakeError, "-1"); std::string const& err = status.GetError(); if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) { cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n"); @@ -203,11 +183,11 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, return false; } - handler->SetAppendXML(this->AppendXML); + handler->SetAppendXML(this->Append); handler->PopulateCustomVectors(this->Makefile); - if (this->Values[ct_SUBMIT_INDEX]) { - handler->SetSubmitIndex(atoi(this->Values[ct_SUBMIT_INDEX])); + if (!this->SubmitIndex.empty()) { + handler->SetSubmitIndex(atoi(this->SubmitIndex.c_str())); } cmWorkingDirectory workdir( this->CTest->GetCTestConfiguration("BuildDirectory")); @@ -216,8 +196,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, this->CTest->GetCTestConfiguration("BuildDirectory") + " : " + std::strerror(workdir.GetLastResult())); if (captureCMakeError) { - this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], - "-1"); + this->Makefile->AddDefinition(this->CaptureCMakeError, "-1"); cmCTestLog(this->CTest, ERROR_MESSAGE, this->GetName() << " " << status.GetError() << "\n"); // return success because failure is recorded in CAPTURE_CMAKE_ERROR @@ -227,9 +206,8 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, } int res = handler->ProcessHandler(); - if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) { - this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE], - std::to_string(res)); + if (!this->ReturnValue.empty()) { + this->Makefile->AddDefinition(this->ReturnValue, std::to_string(res)); } this->ProcessAdditionalValues(handler); // log the error message if there was an error @@ -245,8 +223,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, } } // store the captured cmake error state 0 or -1 - this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], - returnString); + this->Makefile->AddDefinition(this->CaptureCMakeError, returnString); } return true; } @@ -255,47 +232,17 @@ void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*) { } -bool cmCTestHandlerCommand::CheckArgumentKeyword(std::string const& arg) +void cmCTestHandlerCommand::BindArguments() { - // Look for non-value arguments common to all commands. - if (arg == "APPEND") { - this->ArgumentDoing = ArgumentDoingNone; - this->AppendXML = true; - return true; - } - if (arg == "QUIET") { - this->ArgumentDoing = ArgumentDoingNone; - this->Quiet = true; - return true; - } - - // Check for a keyword in our argument/value table. - for (unsigned int k = 0; k < this->Arguments.size(); ++k) { - if (this->Arguments[k] && arg == this->Arguments[k]) { - this->ArgumentDoing = ArgumentDoingKeyword; - this->ArgumentIndex = k; - return true; - } - } - return false; + this->Bind("APPEND"_s, this->Append); + this->Bind("QUIET"_s, this->Quiet); + this->Bind("RETURN_VALUE"_s, this->ReturnValue); + this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError); + this->Bind("SOURCE"_s, this->Source); + this->Bind("BUILD"_s, this->Build); + this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex); } -bool cmCTestHandlerCommand::CheckArgumentValue(std::string const& arg) +void cmCTestHandlerCommand::CheckArguments(std::vector<std::string> const&) { - if (this->ArgumentDoing == ArgumentDoingKeyword) { - this->ArgumentDoing = ArgumentDoingNone; - unsigned int k = this->ArgumentIndex; - if (this->Values[k]) { - std::ostringstream e; - e << "Called with more than one value for " << this->Arguments[k]; - this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - this->ArgumentDoing = ArgumentDoingError; - return true; - } - this->Values[k] = arg.c_str(); - cmCTestLog(this->CTest, DEBUG, - "Set " << this->Arguments[k] << " to " << arg << "\n"); - return true; - } - return false; } diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h index 79d61f3..5bbc569 100644 --- a/Source/CTest/cmCTestHandlerCommand.h +++ b/Source/CTest/cmCTestHandlerCommand.h @@ -5,9 +5,9 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmArgumentParser.h" #include "cmCTestCommand.h" -#include <stddef.h> #include <string> #include <vector> @@ -19,11 +19,11 @@ class cmExecutionStatus; * * cmCTestHandlerCommand defineds the command to test the project. */ -class cmCTestHandlerCommand : public cmCTestCommand +class cmCTestHandlerCommand + : public cmCTestCommand + , public cmArgumentParser<void> { public: - cmCTestHandlerCommand(); - /** * The name of the command as specified in CMakeList.txt. */ @@ -36,42 +36,22 @@ public: bool InitialPass(std::vector<std::string> const& args, cmExecutionStatus& status) override; - enum - { - ct_NONE, - ct_RETURN_VALUE, - ct_CAPTURE_CMAKE_ERROR, - ct_BUILD, - ct_SOURCE, - ct_SUBMIT_INDEX, - ct_LAST - }; - protected: virtual cmCTestGenericHandler* InitializeHandler() = 0; virtual void ProcessAdditionalValues(cmCTestGenericHandler* handler); // Command argument handling. - virtual bool CheckArgumentKeyword(std::string const& arg); - virtual bool CheckArgumentValue(std::string const& arg); - enum - { - ArgumentDoingNone, - ArgumentDoingError, - ArgumentDoingKeyword, - ArgumentDoingLast1 - }; - int ArgumentDoing; - unsigned int ArgumentIndex; - - bool AppendXML; - bool Quiet; - - std::string ReturnVariable; - std::vector<const char*> Arguments; - std::vector<const char*> Values; - size_t Last; + virtual void BindArguments(); + virtual void CheckArguments(std::vector<std::string> const& keywords); + + bool Append = false; + bool Quiet = false; + std::string CaptureCMakeError; + std::string ReturnValue; + std::string Build; + std::string Source; + std::string SubmitIndex; }; #define CTEST_COMMAND_APPEND_OPTION_DOCS \ diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx index 804efa5..abad5fc 100644 --- a/Source/CTest/cmCTestMemCheckCommand.cxx +++ b/Source/CTest/cmCTestMemCheckCommand.cxx @@ -2,18 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMemCheckCommand.h" -#include <string> -#include <vector> - #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" #include "cmMakefile.h" +#include "cm_static_string_view.hxx" -cmCTestMemCheckCommand::cmCTestMemCheckCommand() +void cmCTestMemCheckCommand::BindArguments() { - this->Arguments[ctm_DEFECT_COUNT] = "DEFECT_COUNT"; - this->Arguments[ctm_LAST] = nullptr; - this->Last = ctm_LAST; + this->cmCTestTestCommand::BindArguments(); + this->Bind("DEFECT_COUNT"_s, this->DefectCount); } cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler() @@ -43,9 +40,9 @@ cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler() void cmCTestMemCheckCommand::ProcessAdditionalValues( cmCTestGenericHandler* handler) { - if (this->Values[ctm_DEFECT_COUNT] && *this->Values[ctm_DEFECT_COUNT]) { + if (!this->DefectCount.empty()) { this->Makefile->AddDefinition( - this->Values[ctm_DEFECT_COUNT], + this->DefectCount, std::to_string( static_cast<cmCTestMemCheckHandler*>(handler)->GetDefectCount())); } diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h index 5dad4e7..8f4ffb8 100644 --- a/Source/CTest/cmCTestMemCheckCommand.h +++ b/Source/CTest/cmCTestMemCheckCommand.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <string> #include <utility> #include <cm/memory> @@ -22,8 +23,6 @@ class cmCTestGenericHandler; class cmCTestMemCheckCommand : public cmCTestTestCommand { public: - cmCTestMemCheckCommand(); - /** * This is a virtual constructor for the command. */ @@ -36,15 +35,13 @@ public: } protected: + void BindArguments() override; + cmCTestGenericHandler* InitializeActualHandler() override; void ProcessAdditionalValues(cmCTestGenericHandler* handler) override; - enum - { - ctm_DEFECT_COUNT = ctt_LAST, - ctm_LAST - }; + std::string DefectCount; }; #endif diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 2e2cf1a..706b45a 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -2,14 +2,18 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestSubmitCommand.h" +#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestSubmitHandler.h" #include "cmCommand.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cm_static_string_view.hxx" +#include <set> #include <sstream> #include <utility> @@ -17,18 +21,6 @@ class cmExecutionStatus; -cmCTestSubmitCommand::cmCTestSubmitCommand() -{ - this->PartsMentioned = false; - this->FilesMentioned = false; - this->InternalTest = false; - this->RetryCount = ""; - this->RetryDelay = ""; - this->CDashUpload = false; - this->Arguments[cts_BUILD_ID] = "BUILD_ID"; - this->Last = cts_LAST; -} - /** * This is a virtual constructor for the command. */ @@ -106,13 +98,18 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() // without any of the default parts. // handler->SelectParts(std::set<cmCTest::Part>()); - handler->SelectFiles(this->Files); + handler->SelectFiles( + std::set<std::string>(this->Files.begin(), this->Files.end())); } // If a PARTS option was given, select only the named parts for submission. // if (this->PartsMentioned) { - handler->SelectParts(this->Parts); + auto parts = + cmMakeRange(this->Parts).transform([this](std::string const& arg) { + return this->CTest->GetPartFromName(arg.c_str()); + }); + handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end())); } // Pass along any HTTPHEADER to the handler if this option was given. @@ -140,133 +137,61 @@ bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args, bool ret = this->cmCTestHandlerCommand::InitialPass(args, status); - if (this->Values[cts_BUILD_ID] && *this->Values[cts_BUILD_ID]) { - this->Makefile->AddDefinition(this->Values[cts_BUILD_ID], - this->CTest->GetBuildID()); + if (!this->BuildID.empty()) { + this->Makefile->AddDefinition(this->BuildID, this->CTest->GetBuildID()); } return ret; } -bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg) +void cmCTestSubmitCommand::BindArguments() { if (this->CDashUpload) { // Arguments specific to the CDASH_UPLOAD signature. - if (arg == "CDASH_UPLOAD") { - this->ArgumentDoing = ArgumentDoingCDashUpload; - return true; - } - - if (arg == "CDASH_UPLOAD_TYPE") { - this->ArgumentDoing = ArgumentDoingCDashUploadType; - return true; - } + this->Bind("CDASH_UPLOAD", this->CDashUploadFile); + this->Bind("CDASH_UPLOAD_TYPE", this->CDashUploadType); } else { // Arguments that cannot be used with CDASH_UPLOAD. - if (arg == "PARTS") { - this->ArgumentDoing = ArgumentDoingParts; - this->PartsMentioned = true; - return true; - } - - if (arg == "FILES") { - this->ArgumentDoing = ArgumentDoingFiles; - this->FilesMentioned = true; - return true; - } + this->Bind("PARTS"_s, this->Parts); + this->Bind("FILES"_s, this->Files); } // Arguments used by both modes. - if (arg == "HTTPHEADER") { - this->ArgumentDoing = ArgumentDoingHttpHeader; - return true; - } - - if (arg == "RETRY_COUNT") { - this->ArgumentDoing = ArgumentDoingRetryCount; - return true; - } - - if (arg == "RETRY_DELAY") { - this->ArgumentDoing = ArgumentDoingRetryDelay; - return true; - } - - if (arg == "SUBMIT_URL") { - this->ArgumentDoing = ArgumentDoingSubmitURL; - return true; - } - - if (arg == "INTERNAL_TEST_CHECKSUM") { - this->InternalTest = true; - return true; - } + this->Bind("BUILD_ID"_s, this->BuildID); + this->Bind("HTTPHEADER"_s, this->HttpHeaders); + this->Bind("RETRY_COUNT"_s, this->RetryCount); + this->Bind("RETRY_DELAY"_s, this->RetryDelay); + this->Bind("SUBMIT_URL"_s, this->SubmitURL); + this->Bind("INTERNAL_TEST_CHECKSUM", this->InternalTest); // Look for other arguments. - return this->Superclass::CheckArgumentKeyword(arg); + this->cmCTestHandlerCommand::BindArguments(); } -bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg) +void cmCTestSubmitCommand::CheckArguments( + std::vector<std::string> const& keywords) { - // Handle states specific to this command. - if (this->ArgumentDoing == ArgumentDoingParts) { + this->PartsMentioned = !this->Parts.empty() || cmContains(keywords, "PARTS"); + this->FilesMentioned = !this->Files.empty() || cmContains(keywords, "FILES"); + + cmEraseIf(this->Parts, [this](std::string const& arg) -> bool { cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str()); - if (p != cmCTest::PartCount) { - this->Parts.insert(p); - } else { + if (p == cmCTest::PartCount) { std::ostringstream e; e << "Part name \"" << arg << "\" is invalid."; this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - this->ArgumentDoing = ArgumentDoingError; + return true; } - return true; - } + return false; + }); - if (this->ArgumentDoing == ArgumentDoingFiles) { - if (cmSystemTools::FileExists(arg)) { - this->Files.insert(arg); - } else { + cmEraseIf(this->Files, [this](std::string const& arg) -> bool { + if (!cmSystemTools::FileExists(arg)) { std::ostringstream e; e << "File \"" << arg << "\" does not exist. Cannot submit " << "a non-existent file."; this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - this->ArgumentDoing = ArgumentDoingError; + return true; } - return true; - } - - if (this->ArgumentDoing == ArgumentDoingHttpHeader) { - this->HttpHeaders.push_back(arg); - return true; - } - - if (this->ArgumentDoing == ArgumentDoingRetryCount) { - this->RetryCount = arg; - return true; - } - - if (this->ArgumentDoing == ArgumentDoingRetryDelay) { - this->RetryDelay = arg; - return true; - } - - if (this->ArgumentDoing == ArgumentDoingCDashUpload) { - this->ArgumentDoing = ArgumentDoingNone; - this->CDashUploadFile = arg; - return true; - } - - if (this->ArgumentDoing == ArgumentDoingCDashUploadType) { - this->ArgumentDoing = ArgumentDoingNone; - this->CDashUploadType = arg; - return true; - } - - if (this->ArgumentDoing == ArgumentDoingSubmitURL) { - this->ArgumentDoing = ArgumentDoingNone; - this->SubmitURL = arg; - return true; - } - - // Look for other arguments. - return this->Superclass::CheckArgumentValue(arg); + return false; + }); } diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 8562207..249f844 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -5,11 +5,9 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmCTest.h" #include "cmCTestHandlerCommand.h" #include <memory> -#include <set> #include <string> #include <vector> @@ -26,7 +24,6 @@ class cmExecutionStatus; class cmCTestSubmitCommand : public cmCTestHandlerCommand { public: - cmCTestSubmitCommand(); std::unique_ptr<cmCommand> Clone() override; bool InitialPass(std::vector<std::string> const& args, @@ -37,45 +34,26 @@ public: */ std::string GetName() const override { return "ctest_submit"; } - using Superclass = cmCTestHandlerCommand; - protected: + void BindArguments() override; + void CheckArguments(std::vector<std::string> const& keywords) override; cmCTestGenericHandler* InitializeHandler() override; - bool CheckArgumentKeyword(std::string const& arg) override; - bool CheckArgumentValue(std::string const& arg) override; - - enum - { - ArgumentDoingParts = Superclass::ArgumentDoingLast1, - ArgumentDoingFiles, - ArgumentDoingRetryDelay, - ArgumentDoingRetryCount, - ArgumentDoingCDashUpload, - ArgumentDoingCDashUploadType, - ArgumentDoingHttpHeader, - ArgumentDoingSubmitURL, - ArgumentDoingLast2 - }; - - enum - { - cts_BUILD_ID = ct_LAST, - cts_LAST - }; + bool CDashUpload = false; + bool FilesMentioned = false; + bool InternalTest = false; + bool PartsMentioned = false; - bool PartsMentioned; - std::set<cmCTest::Part> Parts; - bool FilesMentioned; - bool InternalTest; - std::set<std::string> Files; - std::string RetryCount; - std::string RetryDelay; - bool CDashUpload; + std::string BuildID; std::string CDashUploadFile; std::string CDashUploadType; - std::vector<std::string> HttpHeaders; + std::string RetryCount; + std::string RetryDelay; std::string SubmitURL; + + std::vector<std::string> Files; + std::vector<std::string> HttpHeaders; + std::vector<std::string> Parts; }; #endif diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index 3a29ad3..c277db8 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -8,30 +8,29 @@ #include "cmDuration.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" +#include "cm_static_string_view.hxx" #include <chrono> #include <cstdlib> #include <sstream> -#include <vector> -cmCTestTestCommand::cmCTestTestCommand() +void cmCTestTestCommand::BindArguments() { - this->Arguments[ctt_START] = "START"; - this->Arguments[ctt_END] = "END"; - this->Arguments[ctt_STRIDE] = "STRIDE"; - this->Arguments[ctt_EXCLUDE] = "EXCLUDE"; - this->Arguments[ctt_INCLUDE] = "INCLUDE"; - this->Arguments[ctt_EXCLUDE_LABEL] = "EXCLUDE_LABEL"; - this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL"; - this->Arguments[ctt_EXCLUDE_FIXTURE] = "EXCLUDE_FIXTURE"; - this->Arguments[ctt_EXCLUDE_FIXTURE_SETUP] = "EXCLUDE_FIXTURE_SETUP"; - this->Arguments[ctt_EXCLUDE_FIXTURE_CLEANUP] = "EXCLUDE_FIXTURE_CLEANUP"; - this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL"; - this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM"; - this->Arguments[ctt_STOP_TIME] = "STOP_TIME"; - this->Arguments[ctt_TEST_LOAD] = "TEST_LOAD"; - this->Arguments[ctt_LAST] = nullptr; - this->Last = ctt_LAST; + this->cmCTestHandlerCommand::BindArguments(); + this->Bind("START"_s, this->Start); + this->Bind("END"_s, this->End); + this->Bind("STRIDE"_s, this->Stride); + this->Bind("EXCLUDE"_s, this->Exclude); + this->Bind("INCLUDE"_s, this->Include); + this->Bind("EXCLUDE_LABEL"_s, this->ExcludeLabel); + this->Bind("INCLUDE_LABEL"_s, this->IncludeLabel); + this->Bind("EXCLUDE_FIXTURE"_s, this->ExcludeFixture); + this->Bind("EXCLUDE_FIXTURE_SETUP"_s, this->ExcludeFixtureSetup); + this->Bind("EXCLUDE_FIXTURE_CLEANUP"_s, this->ExcludeFixtureCleanup); + this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel); + this->Bind("SCHEDULE_RANDOM"_s, this->ScheduleRandom); + this->Bind("STOP_TIME"_s, this->StopTime); + this->Bind("TEST_LOAD"_s, this->TestLoad); } cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() @@ -51,57 +50,44 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() } this->CTest->SetTimeOut(timeout); cmCTestGenericHandler* handler = this->InitializeActualHandler(); - if (this->Values[ctt_START] || this->Values[ctt_END] || - this->Values[ctt_STRIDE]) { - std::ostringstream testsToRunString; - if (this->Values[ctt_START]) { - testsToRunString << this->Values[ctt_START]; - } - testsToRunString << ","; - if (this->Values[ctt_END]) { - testsToRunString << this->Values[ctt_END]; - } - testsToRunString << ","; - if (this->Values[ctt_STRIDE]) { - testsToRunString << this->Values[ctt_STRIDE]; - } - handler->SetOption("TestsToRunInformation", - testsToRunString.str().c_str()); + if (!this->Start.empty() || !this->End.empty() || !this->Stride.empty()) { + handler->SetOption( + "TestsToRunInformation", + cmStrCat(this->Start, ',', this->End, ',', this->Stride).c_str()); } - if (this->Values[ctt_EXCLUDE]) { - handler->SetOption("ExcludeRegularExpression", this->Values[ctt_EXCLUDE]); + if (!this->Exclude.empty()) { + handler->SetOption("ExcludeRegularExpression", this->Exclude.c_str()); } - if (this->Values[ctt_INCLUDE]) { - handler->SetOption("IncludeRegularExpression", this->Values[ctt_INCLUDE]); + if (!this->Include.empty()) { + handler->SetOption("IncludeRegularExpression", this->Include.c_str()); } - if (this->Values[ctt_EXCLUDE_LABEL]) { + if (!this->ExcludeLabel.empty()) { handler->SetOption("ExcludeLabelRegularExpression", - this->Values[ctt_EXCLUDE_LABEL]); + this->ExcludeLabel.c_str()); } - if (this->Values[ctt_INCLUDE_LABEL]) { - handler->SetOption("LabelRegularExpression", - this->Values[ctt_INCLUDE_LABEL]); + if (!this->IncludeLabel.empty()) { + handler->SetOption("LabelRegularExpression", this->IncludeLabel.c_str()); } - if (this->Values[ctt_EXCLUDE_FIXTURE]) { + if (!this->ExcludeFixture.empty()) { handler->SetOption("ExcludeFixtureRegularExpression", - this->Values[ctt_EXCLUDE_FIXTURE]); + this->ExcludeFixture.c_str()); } - if (this->Values[ctt_EXCLUDE_FIXTURE_SETUP]) { + if (!this->ExcludeFixtureSetup.empty()) { handler->SetOption("ExcludeFixtureSetupRegularExpression", - this->Values[ctt_EXCLUDE_FIXTURE_SETUP]); + this->ExcludeFixtureSetup.c_str()); } - if (this->Values[ctt_EXCLUDE_FIXTURE_CLEANUP]) { + if (!this->ExcludeFixtureCleanup.empty()) { handler->SetOption("ExcludeFixtureCleanupRegularExpression", - this->Values[ctt_EXCLUDE_FIXTURE_CLEANUP]); + this->ExcludeFixtureCleanup.c_str()); } - if (this->Values[ctt_PARALLEL_LEVEL]) { - handler->SetOption("ParallelLevel", this->Values[ctt_PARALLEL_LEVEL]); + if (!this->ParallelLevel.empty()) { + handler->SetOption("ParallelLevel", this->ParallelLevel.c_str()); } - if (this->Values[ctt_SCHEDULE_RANDOM]) { - handler->SetOption("ScheduleRandom", this->Values[ctt_SCHEDULE_RANDOM]); + if (!this->ScheduleRandom.empty()) { + handler->SetOption("ScheduleRandom", this->ScheduleRandom.c_str()); } - if (this->Values[ctt_STOP_TIME]) { - this->CTest->SetStopTime(this->Values[ctt_STOP_TIME]); + if (!this->StopTime.empty()) { + this->CTest->SetStopTime(this->StopTime); } // Test load is determined by: TEST_LOAD argument, @@ -109,12 +95,12 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() // command line argument... in that order. unsigned long testLoad; const char* ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD"); - if (this->Values[ctt_TEST_LOAD] && *this->Values[ctt_TEST_LOAD]) { - if (!cmStrToULong(this->Values[ctt_TEST_LOAD], &testLoad)) { + if (!this->TestLoad.empty()) { + if (!cmStrToULong(this->TestLoad.c_str(), &testLoad)) { testLoad = 0; cmCTestLog(this->CTest, WARNING, - "Invalid value for 'TEST_LOAD' : " - << this->Values[ctt_TEST_LOAD] << std::endl); + "Invalid value for 'TEST_LOAD' : " << this->TestLoad + << std::endl); } } else if (ctestTestLoad && *ctestTestLoad) { if (!cmStrToULong(ctestTestLoad, &testLoad)) { diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index a9ba3ab..edd21b7 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -23,8 +23,6 @@ class cmCTestGenericHandler; class cmCTestTestCommand : public cmCTestHandlerCommand { public: - cmCTestTestCommand(); - /** * This is a virtual constructor for the command. */ @@ -42,29 +40,24 @@ public: std::string GetName() const override { return "ctest_test"; } protected: + void BindArguments() override; virtual cmCTestGenericHandler* InitializeActualHandler(); cmCTestGenericHandler* InitializeHandler() override; - enum - { - ctt_BUILD = ct_LAST, - ctt_RETURN_VALUE, - ctt_START, - ctt_END, - ctt_STRIDE, - ctt_EXCLUDE, - ctt_INCLUDE, - ctt_EXCLUDE_LABEL, - ctt_INCLUDE_LABEL, - ctt_EXCLUDE_FIXTURE, - ctt_EXCLUDE_FIXTURE_SETUP, - ctt_EXCLUDE_FIXTURE_CLEANUP, - ctt_PARALLEL_LEVEL, - ctt_SCHEDULE_RANDOM, - ctt_STOP_TIME, - ctt_TEST_LOAD, - ctt_LAST - }; + std::string Start; + std::string End; + std::string Stride; + std::string Exclude; + std::string Include; + std::string ExcludeLabel; + std::string IncludeLabel; + std::string ExcludeFixture; + std::string ExcludeFixtureSetup; + std::string ExcludeFixtureCleanup; + std::string ParallelLevel; + std::string ScheduleRandom; + std::string StopTime; + std::string TestLoad; }; #endif diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 65dc921..673eb9a 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -7,14 +7,11 @@ #include "cmMakefile.h" #include "cmSystemTools.h" -#include <vector> - cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() { - if (this->Values[ct_SOURCE]) { + if (!this->Source.empty()) { this->CTest->SetCTestConfiguration( - "SourceDirectory", - cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(), + "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source).c_str(), this->Quiet); } else { this->CTest->SetCTestConfiguration( diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h index 5b0e07e..a4798a5 100644 --- a/Source/CTest/cmCTestUpdateCommand.h +++ b/Source/CTest/cmCTestUpdateCommand.h @@ -23,8 +23,6 @@ class cmCTestGenericHandler; class cmCTestUpdateCommand : public cmCTestHandlerCommand { public: - cmCTestUpdateCommand() {} - /** * This is a virtual constructor for the command. */ diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index 59fbf37..9180821 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -2,61 +2,45 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestUploadCommand.h" +#include <set> #include <sstream> #include <vector> +#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestUploadHandler.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSystemTools.h" +#include "cm_static_string_view.hxx" -cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler() -{ - cmCTestUploadHandler* handler = this->CTest->GetUploadHandler(); - handler->Initialize(); - handler->SetFiles(this->Files); - handler->SetQuiet(this->Quiet); - return handler; -} - -bool cmCTestUploadCommand::CheckArgumentKeyword(std::string const& arg) +void cmCTestUploadCommand::BindArguments() { - if (arg == "FILES") { - this->ArgumentDoing = ArgumentDoingFiles; - return true; - } - if (arg == "QUIET") { - this->ArgumentDoing = ArgumentDoingNone; - this->Quiet = true; - return true; - } - if (arg == "CAPTURE_CMAKE_ERROR") { - this->ArgumentDoing = ArgumentDoingCaptureCMakeError; - return true; - } - return false; + this->Bind("FILES"_s, this->Files); + this->Bind("QUIET"_s, this->Quiet); + this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError); } -bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg) +void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&) { - if (this->ArgumentDoing == ArgumentDoingCaptureCMakeError) { - this->Values[ct_CAPTURE_CMAKE_ERROR] = arg.c_str(); - return true; - } - if (this->ArgumentDoing == ArgumentDoingFiles) { - if (cmSystemTools::FileExists(arg)) { - this->Files.insert(arg); + cmEraseIf(this->Files, [this](std::string const& arg) -> bool { + if (!cmSystemTools::FileExists(arg)) { + std::ostringstream e; + e << "File \"" << arg << "\" does not exist. Cannot submit " + << "a non-existent file."; + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return true; } - std::ostringstream e; - e << "File \"" << arg << "\" does not exist. Cannot submit " - << "a non-existent file."; - this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - this->ArgumentDoing = ArgumentDoingError; return false; - } + }); +} - // Look for other arguments. - return this->Superclass::CheckArgumentValue(arg); +cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler() +{ + cmCTestUploadHandler* handler = this->CTest->GetUploadHandler(); + handler->Initialize(); + handler->SetFiles( + std::set<std::string>(this->Files.begin(), this->Files.end())); + handler->SetQuiet(this->Quiet); + return handler; } diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h index 39314f2..f78f0ec 100644 --- a/Source/CTest/cmCTestUploadCommand.h +++ b/Source/CTest/cmCTestUploadCommand.h @@ -8,9 +8,9 @@ #include "cmCTestHandlerCommand.h" #include "cmCommand.h" -#include <set> #include <string> #include <utility> +#include <vector> #include <cm/memory> @@ -41,22 +41,12 @@ public: */ std::string GetName() const override { return "ctest_upload"; } - using Superclass = cmCTestHandlerCommand; - protected: + void BindArguments() override; + void CheckArguments(std::vector<std::string> const&) override; cmCTestGenericHandler* InitializeHandler() override; - bool CheckArgumentKeyword(std::string const& arg) override; - bool CheckArgumentValue(std::string const& arg) override; - - enum - { - ArgumentDoingFiles = Superclass::ArgumentDoingLast1, - ArgumentDoingCaptureCMakeError, - ArgumentDoingLast2 - }; - - std::set<std::string> Files; + std::vector<std::string> Files; }; #endif diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 35db6a4..94de851 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -5,6 +5,7 @@ #include <sstream> #include <unordered_set> +#include "cmCheckCustomOutputs.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" @@ -16,9 +17,6 @@ #include "cmSystemTools.h" #include "cmTarget.h" -static bool cmAddCustomCommandCommandCheckOutputs( - const std::vector<std::string>& outputs, cmExecutionStatus& status); - bool cmAddCustomCommandCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -307,9 +305,9 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, } // Make sure the output names and locations are safe. - if (!cmAddCustomCommandCommandCheckOutputs(output, status) || - !cmAddCustomCommandCommandCheckOutputs(outputs, status) || - !cmAddCustomCommandCommandCheckOutputs(byproducts, status)) { + if (!cmCheckCustomOutputs(output, "OUTPUT", status) || + !cmCheckCustomOutputs(outputs, "OUTPUTS", status) || + !cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) { return false; } @@ -322,8 +320,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, // No command for this output exists. status.SetError( - cmStrCat("given APPEND option with output\n\"", output[0], - "\"\nwhich is not already a custom command output.")); + cmStrCat("given APPEND option with output\n ", output[0], + "\nwhich is not already a custom command output.")); return false; } @@ -387,29 +385,3 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, return true; } - -bool cmAddCustomCommandCommandCheckOutputs( - const std::vector<std::string>& outputs, cmExecutionStatus& status) -{ - cmMakefile& mf = status.GetMakefile(); - for (std::string const& o : outputs) { - // Make sure the file will not be generated into the source - // directory during an out of source build. - if (!mf.CanIWriteThisFile(o)) { - std::string e = "attempted to have a file \"" + o + - "\" in a source directory as an output of custom command."; - status.SetError(e); - cmSystemTools::SetFatalErrorOccured(); - return false; - } - - // Make sure the output file name has no invalid characters. - std::string::size_type pos = o.find_first_of("#<>"); - if (pos != std::string::npos) { - status.SetError(cmStrCat("called with OUTPUT containing a \"", o[pos], - "\". This character is not allowed.")); - return false; - } - } - return true; -} diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index 9fd1234..b580c43 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -4,6 +4,7 @@ #include <utility> +#include "cmCheckCustomOutputs.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" @@ -205,6 +206,11 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args, return false; } + // Make sure the byproduct names and locations are safe. + if (!cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) { + return false; + } + // Add the utility target to the makefile. bool escapeOldStyle = !verbatim; cmTarget* target = mf.AddUtilityCommand( diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 751d117..4c87177 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -61,10 +61,14 @@ void Instance::Bind(MultiStringList& val) void Instance::Consume(cm::string_view arg, void* result, std::vector<std::string>* unparsedArguments, - std::vector<std::string>* keywordsMissingValue) + std::vector<std::string>* keywordsMissingValue, + std::vector<std::string>* parsedKeywords) { auto const it = this->Bindings.Find(arg); if (it != this->Bindings.end()) { + if (parsedKeywords != nullptr) { + parsedKeywords->emplace_back(arg); + } it->second(*this, result); if (this->ExpectValue && keywordsMissingValue != nullptr) { keywordsMissingValue->emplace_back(arg); diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index b6798bc..9be2488 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -45,7 +45,8 @@ public: void Consume(cm::string_view arg, void* result, std::vector<std::string>* unparsedArguments, - std::vector<std::string>* keywordsMissingValue); + std::vector<std::string>* keywordsMissingValue, + std::vector<std::string>* parsedKeywords); private: ActionMap const& Bindings; @@ -79,21 +80,25 @@ public: template <typename Range> void Parse(Result& result, Range const& args, std::vector<std::string>* unparsedArguments = nullptr, - std::vector<std::string>* keywordsMissingValue = nullptr) const + std::vector<std::string>* keywordsMissingValue = nullptr, + std::vector<std::string>* parsedKeywords = nullptr) const { ArgumentParser::Instance instance(this->Bindings); for (cm::string_view arg : args) { - instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue); + instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue, + parsedKeywords); } } template <typename Range> Result Parse(Range const& args, std::vector<std::string>* unparsedArguments = nullptr, - std::vector<std::string>* keywordsMissingValue = nullptr) const + std::vector<std::string>* keywordsMissingValue = nullptr, + std::vector<std::string>* parsedKeywords = nullptr) const { Result result; - this->Parse(result, args, unparsedArguments, keywordsMissingValue); + this->Parse(result, args, unparsedArguments, keywordsMissingValue, + parsedKeywords); return result; } @@ -116,11 +121,13 @@ public: template <typename Range> void Parse(Range const& args, std::vector<std::string>* unparsedArguments = nullptr, - std::vector<std::string>* keywordsMissingValue = nullptr) const + std::vector<std::string>* keywordsMissingValue = nullptr, + std::vector<std::string>* parsedKeywords = nullptr) const { ArgumentParser::Instance instance(this->Bindings); for (cm::string_view arg : args) { - instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue); + instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue, + parsedKeywords); } } diff --git a/Source/cmCheckCustomOutputs.cxx b/Source/cmCheckCustomOutputs.cxx new file mode 100644 index 0000000..7645c88 --- /dev/null +++ b/Source/cmCheckCustomOutputs.cxx @@ -0,0 +1,36 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCheckCustomOutputs.h" + +#include "cmExecutionStatus.h" +#include "cmMakefile.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +bool cmCheckCustomOutputs(const std::vector<std::string>& outputs, + cm::string_view keyword, cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + + for (std::string const& o : outputs) { + // Make sure the file will not be generated into the source + // directory during an out of source build. + if (!mf.CanIWriteThisFile(o)) { + status.SetError( + cmStrCat("attempted to have a file\n ", o, + "\nin a source directory as an output of custom command.")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + // Make sure the output file name has no invalid characters. + std::string::size_type pos = o.find_first_of("#<>"); + if (pos != std::string::npos) { + status.SetError(cmStrCat("called with ", keyword, " containing a \"", + o[pos], "\". This character is not allowed.")); + return false; + } + } + + return true; +} diff --git a/Source/cmCheckCustomOutputs.h b/Source/cmCheckCustomOutputs.h new file mode 100644 index 0000000..7c4b3fe --- /dev/null +++ b/Source/cmCheckCustomOutputs.h @@ -0,0 +1,18 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCheckCustomOutputs_h +#define cmCheckCustomOutputs_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cm/string_view> + +#include <string> +#include <vector> + +class cmExecutionStatus; + +bool cmCheckCustomOutputs(const std::vector<std::string>& outputs, + cm::string_view keyword, cmExecutionStatus& status); + +#endif diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 7faafba..0915189 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -45,6 +45,14 @@ static cmVS7FlagTable cmVS7ExtraFlagTable[] = { { "", "", "", "", 0 } }; +namespace { +std::string GetSLNFile(cmLocalGenerator* root) +{ + return cmStrCat(root->GetCurrentBinaryDirectory(), '/', + root->GetProjectName(), ".sln"); +} +} + cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator( cmake* cm, std::string const& platformInGeneratorName) : cmGlobalVisualStudioGenerator(cm, platformInGeneratorName) @@ -286,8 +294,10 @@ void cmGlobalVisualStudio7Generator::Generate() this->OutputSLNFile(); // If any solution or project files changed during the generation, // tell Visual Studio to reload them... - if (!cmSystemTools::GetErrorOccuredFlag()) { - this->CallVisualStudioMacro(MacroReload); + if (!cmSystemTools::GetErrorOccuredFlag() && + !this->LocalGenerators.empty()) { + this->CallVisualStudioMacro(MacroReload, + GetSLNFile(this->LocalGenerators[0])); } } @@ -298,8 +308,7 @@ void cmGlobalVisualStudio7Generator::OutputSLNFile( return; } this->CurrentProject = root->GetProjectName(); - std::string fname = cmStrCat(root->GetCurrentBinaryDirectory(), '/', - root->GetProjectName(), ".sln"); + std::string fname = GetSLNFile(root); cmGeneratedFileStream fout(fname.c_str()); fout.SetCopyIfDifferent(true); if (!fout) { diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 108a44f..7a564ed 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -288,11 +288,10 @@ void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros() } void cmGlobalVisualStudioGenerator::CallVisualStudioMacro( - MacroName m, const char* vsSolutionFile) + MacroName m, const std::string& vsSolutionFile) { // If any solution or project files changed during the generation, // tell Visual Studio to reload them... - cmMakefile* mf = this->LocalGenerators[0]->GetMakefile(); std::string dir = this->GetUserMacrosDirectory(); // Only really try to call the macro if: @@ -307,27 +306,18 @@ void cmGlobalVisualStudioGenerator::CallVisualStudioMacro( if (cmSystemTools::FileExists(macrosFile.c_str()) && IsVisualStudioMacrosFileRegistered( macrosFile, this->GetUserMacrosRegKeyBase(), nextSubkeyName)) { - std::string topLevelSlnName; - if (vsSolutionFile) { - topLevelSlnName = vsSolutionFile; - } else { - topLevelSlnName = - cmStrCat(mf->GetCurrentBinaryDirectory(), '/', - this->LocalGenerators[0]->GetProjectName(), ".sln"); - } - if (m == MacroReload) { std::vector<std::string> filenames; this->GetFilesReplacedDuringGenerate(filenames); if (!filenames.empty()) { std::string projects = cmJoin(filenames, ";"); cmCallVisualStudioMacro::CallMacro( - topLevelSlnName, CMAKE_VSMACROS_RELOAD_MACRONAME, projects, + vsSolutionFile, CMAKE_VSMACROS_RELOAD_MACRONAME, projects, this->GetCMakeInstance()->GetDebugOutput()); } } else if (m == MacroStop) { cmCallVisualStudioMacro::CallMacro( - topLevelSlnName, CMAKE_VSMACROS_STOP_MACRONAME, "", + vsSolutionFile, CMAKE_VSMACROS_STOP_MACRONAME, "", this->GetCMakeInstance()->GetDebugOutput()); } } diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index bd615ec..4f2007f 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -90,7 +90,7 @@ public: * Call the ReloadProjects macro if necessary based on * GetFilesReplacedDuringGenerate results. */ - void CallVisualStudioMacro(MacroName m, const char* vsSolutionFile = 0); + void CallVisualStudioMacro(MacroName m, const std::string& vsSolutionFile); // return true if target is fortran only bool TargetIsFortranOnly(const cmGeneratorTarget* gt); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 34aac49..d28905a 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1466,6 +1466,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } // output files for custom command std::stringstream outputs; + bool symbolic = false; { const char* sep = ""; for (std::string const& o : ccg.GetOutputs()) { @@ -1473,6 +1474,12 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( ConvertToWindowsSlash(out); outputs << sep << out; sep = ";"; + if (!symbolic) { + if (cmSourceFile* sf = this->Makefile->GetSource( + o, cmSourceFileLocationKind::Known)) { + symbolic = sf->GetPropertyAsBool("SYMBOLIC"); + } + } } } if (this->ProjectType == csproj) { @@ -1482,7 +1489,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( outputs.str(), comment); } else { this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(), - outputs.str(), comment); + outputs.str(), comment, symbolic); } } } @@ -1490,7 +1497,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( void cmVisualStudio10TargetGenerator::WriteCustomRuleCpp( Elem& e2, std::string const& config, std::string const& script, std::string const& additional_inputs, std::string const& outputs, - std::string const& comment) + std::string const& comment, bool symbolic) { const std::string cond = this->CalcCondition(config); e2.WritePlatformConfigTag("Message", cond, comment); @@ -1502,6 +1509,13 @@ void cmVisualStudio10TargetGenerator::WriteCustomRuleCpp( // VS >= 11 let us turn off linking of custom command outputs. e2.WritePlatformConfigTag("LinkObjects", cond, "false"); } + if (symbolic && + this->LocalGenerator->GetVersion() >= + cmGlobalVisualStudioGenerator::VS16) { + // VS >= 16.4 warn if outputs are not created, but one of our + // outputs is marked SYMBOLIC and not expected to be created. + e2.WritePlatformConfigTag("VerifyInputsAndOutputsExist", cond, "false"); + } } void cmVisualStudio10TargetGenerator::WriteCustomRuleCSharp( diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 4dd92eb..a18a33d 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -142,7 +142,7 @@ private: std::string const& script, std::string const& additional_inputs, std::string const& outputs, - std::string const& comment); + std::string const& comment, bool symbolic); void WriteCustomRuleCSharp(Elem& e0, std::string const& config, std::string const& commandName, std::string const& script, diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 96d903e..b96eedb 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1751,7 +1751,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) cmGlobalVisualStudioGenerator* gg = static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator); gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop, - this->VSSolutionFile.c_str()); + this->VSSolutionFile); } #endif return ret; diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in index 74d816c..67b108b 100644 --- a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in +++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in @@ -15,8 +15,9 @@ set(CPACK_COMPONENTS_IGNORE_GROUPS 1) #set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1) # overriding previous descriptions -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "main description") -set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION "applications_description") -set(CPACK_COMPONENT_HEADERS_DESCRIPTION "headers_description") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "main description") # This become a summary line (the first one) of all descriptions +set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION "applications_description") +set(CPACK_COMPONENT_HEADERS_DESCRIPTION "headers_description") # libraries does not have any description and should inherit from CPACK_PACKAGE_DESCRIPTION_SUMMARY +# plus content of the `CPACK_PACKAGE_DESCRIPTION_FILE`. unset(CPACK_COMPONENT_LIBRARIES_DESCRIPTION) diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in index cda79bc..d877325 100644 --- a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in +++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in @@ -15,12 +15,12 @@ set(CPACK_COMPONENTS_IGNORE_GROUPS 1) #set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1) # overriding previous descriptions -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "main description 2") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "main description 2") -# Components do not have any description +# Components do not have any description. +# So, content of `CPACK_PACKAGE_DESCRIPTION_FILE` gonna used +# after summary line. unset(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION) unset(CPACK_COMPONENT_HEADERS_DESCRIPTION) -unset(CPACK_COMPONENT_LIBRARIES_DESCRIPTION) - -set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "library description") +set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "library description") diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake index f74137c..86a74b2 100644 --- a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake +++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake @@ -48,26 +48,26 @@ if(DPKGDEB_EXECUTABLE) DPKGDEB_OUTPUT "${dpkg_output}" METAENTRY "Package:") - dpkgdeb_return_specific_metaentry(dpkg_description - DPKGDEB_OUTPUT "${dpkg_output}" - METAENTRY "Description:") + get_package_description("${dpkg_output}" dpkg_description) message(STATUS "package='${dpkg_package_name}', description='${dpkg_description}'") if(dpkg_package_name STREQUAL "mylib-applications") - if(NOT "${dpkg_description}" STREQUAL "applications_description") + set(expected_description "main description\n applications_description") + if(NOT dpkg_description STREQUAL expected_description) set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} - "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: ${dpkg_description} != applications_description") + "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`") endif() elseif(dpkg_package_name STREQUAL "mylib-headers") - if(NOT dpkg_description STREQUAL "headers_description") + set(expected_description "main description\n headers_description") + if(NOT dpkg_description STREQUAL expected_description) set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} - "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: ${dpkg_description} != headers_description") + "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`") endif() elseif(dpkg_package_name STREQUAL "mylib-libraries") - if(NOT dpkg_description STREQUAL "main description") + if(NOT dpkg_description MATCHES "main description\n.*") set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} - "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: ${dpkg_description} != 'main description'") + "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` =~ `main description.*`") endif() else() set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake index 241dda5..d53c73d 100644 --- a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake +++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake @@ -48,26 +48,20 @@ if(DPKGDEB_EXECUTABLE) DPKGDEB_OUTPUT "${dpkg_output}" METAENTRY "Package:") - dpkgdeb_return_specific_metaentry(dpkg_description - DPKGDEB_OUTPUT "${dpkg_output}" - METAENTRY "Description:") + get_package_description("${dpkg_output}" dpkg_description) message(STATUS "package='${dpkg_package_name}', description='${dpkg_description}'") - if(dpkg_package_name STREQUAL "mylib-applications") - if(NOT dpkg_description STREQUAL "main description 2") - set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} - "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: ${dpkg_description} != applications_description") - endif() - elseif(dpkg_package_name STREQUAL "mylib-headers") - if(NOT dpkg_description STREQUAL "main description 2") + if(dpkg_package_name STREQUAL "mylib-applications" OR dpkg_package_name STREQUAL "mylib-headers") + if(NOT dpkg_description MATCHES "main description 2\n.*") set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} - "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: ${dpkg_description} != headers_description") + "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` =~ `main description 2`") endif() elseif(dpkg_package_name STREQUAL "mylib-libraries") - if(NOT dpkg_description STREQUAL "library description") + set(expected_description "main description 2\n library description") + if(NOT dpkg_description STREQUAL expected_description) set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} - "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: ${dpkg_description} != 'main description'") + "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`") endif() else() set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all} diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake index 2093e7e..b172da2 100644 --- a/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake +++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake @@ -200,4 +200,29 @@ function(dpkgdeb_return_specific_metaentry output) endif() endfunction() +function(get_package_description DPKG_OUTPUT RESULT_VAR) + string(UUID uuid NAMESPACE 00000000-0000-0000-0000-000000000000 TYPE SHA1) + string(REPLACE ";" "${uuid}" DPKG_OUTPUT "${DPKG_OUTPUT}") + string(REPLACE "\n" ";" DPKG_OUTPUT "${DPKG_OUTPUT}") + + unset(_actual_description) + set(_parse_description FALSE) + foreach(_line IN LISTS DPKG_OUTPUT) + if(_line MATCHES " Description:.*") + set(_parse_description TRUE) + string(REPLACE " Description: " "" _line "${_line}") + list(APPEND _actual_description "${_line}") + elseif(_parse_description) + if(_line MATCHES " [A-Z][A-Za-z\-]+: .*") + set(_parse_description FALSE) + else() + list(APPEND _actual_description "${_line}") + endif() + endif() + endforeach() + list(JOIN _actual_description "\n" _actual_description) + + set(${RESULT_VAR} "${_actual_description}" PARENT_SCOPE) +endfunction() + cmake_policy(POP) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index c663484..026baa7 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -167,7 +167,7 @@ if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja") add_RunCMake_test(CompilerChange) endif() add_RunCMake_test(CompilerNotFound) -add_RunCMake_test(Configure) +add_RunCMake_test(Configure -DMSVC_IDE=${MSVC_IDE}) add_RunCMake_test(DisallowedCommands) add_RunCMake_test(ExternalData) add_RunCMake_test(FeatureSummary) @@ -510,6 +510,7 @@ set(cpack_tests DEB.TIMESTAMPS DEB.MD5SUMS DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY + DEB.DEB_DESCRIPTION RPM.CUSTOM_BINARY_SPEC_FILE RPM.CUSTOM_NAMES diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index 8e98961..b0b7a99 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -39,3 +39,10 @@ run_cpack_test_subtests(EXTERNAL "none;good;good_multi;bad_major;bad_minor;inval if(RunCMake_GENERATOR MATCHES "Visual Studio|Xcode") run_cpack_test(CPACK_INSTALL_CMAKE_CONFIGURATIONS "ZIP" false "MONOLITHIC") endif() +run_cpack_test_subtests( + DEB_DESCRIPTION + "CPACK_DEBIAN_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION_FILE" + "DEB.DEB_DESCRIPTION" + false + "MONOLITHIC;COMPONENT" +) diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake new file mode 100644 index 0000000..39f18a3 --- /dev/null +++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake @@ -0,0 +1,16 @@ +set(EXPECTED_FILES_COUNT_MONOLITHIC "1") +set(EXPECTED_FILES_COUNT_COMPONENT "2") +set(EXPECTED_FILES_COUNT "${EXPECTED_FILES_COUNT_${PACKAGING_TYPE}}") + +if(PACKAGING_TYPE STREQUAL "COMPONENT") + set(EXPECTED_FILE_1 "deb_description-0.1.1-*-satu.deb") + set(EXPECTED_FILE_2 "deb_description-0.1.1-*-dua.deb") + set(EXPECTED_FILE_CONTENT_1_LIST "/satu;/satu/CMakeLists.txt") + set(EXPECTED_FILE_CONTENT_2_LIST "/dua;/dua/CMakeLists.txt") + +elseif(PACKAGING_TYPE STREQUAL "MONOLITHIC") + set(EXPECTED_FILE_CONTENT_1_LIST "/dua;/dua/CMakeLists.txt;/satu;/satu/CMakeLists.txt") + +endif() + +# kate: indent-width 2; diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake new file mode 100644 index 0000000..e9ac13a --- /dev/null +++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake @@ -0,0 +1,65 @@ +function(checkPackageDescription FILE EXPECTED_DESCRIPTION) + getPackageInfo("${FILE}" "_file_info") + string(UUID uuid NAMESPACE 00000000-0000-0000-0000-000000000000 TYPE SHA1) + string(REPLACE ";" "${uuid}" _file_info "${_file_info}") + string(REPLACE ";" "${uuid}" EXPECTED_DESCRIPTION "${EXPECTED_DESCRIPTION}") + string(REPLACE "\n" ";" _file_info "${_file_info}") + + set(_actual_description) + set(_parse_description FALSE) + foreach(_line IN LISTS _file_info) + if(_line MATCHES " Description:.*") + set(_parse_description TRUE) + list(APPEND _actual_description "${_line}") + elseif(_parse_description) + if(_line MATCHES " [A-Z][A-Za-z\-]+: .*") + set(_parse_description FALSE) + else() + list(APPEND _actual_description "${_line}") + endif() + endif() + endforeach() + list(JOIN _actual_description "\n" _actual_description) + + if(NOT _actual_description STREQUAL EXPECTED_DESCRIPTION) + set(_error "---[BEGIN Expected description]---\n${EXPECTED_DESCRIPTION}---[END Expected description]---\n") + string(APPEND _error "---[BEGIN Actual description]---\n${_actual_description}---[END Actual description]---\n") + string(REPLACE "${uuid}" ";" _error "${_error}") + message(FATAL_ERROR "${_error}") + endif() +endfunction() + +# ALERT The output of `dpkg -I *.deb` indented by one space +set(_expected_description [[ Description: This is the summary line + This is the Debian package multiline description. + . + It must be formatted properly! Otherwise, the result `*.deb` + package become broken and cant be installed! + . + It may contains `;` characters (even like this `;;;;`). Example: + . + - one; + - two; + - three; + . + ... and they are properly handled by the automatic description formatter! + . + See also: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description]]) + +# ATTENTION The code in `cmCPackGenerator.cxx` to read `CPACK_PACKAGE_DESCRIPTION_FILE` +# has a BUG: it appends the `\n` character to every line of the +# input, even if there was no EOL (e.g. at the last line of the file). +# That is WHY for this sub-test the one more pre-formatted "empty" +# line required! +# NOTE For component based installers content of the file gonna read by +# `CPackDeb` module and the `file(READ...)` command so no the mentioned +# workaround required! +if(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_PACKAGE_DESCRIPTION_FILE" AND PACKAGING_TYPE STREQUAL "MONOLITHIC") + string(APPEND _expected_description "\n ." ) +endif() + +foreach(_file_no RANGE 1 ${EXPECTED_FILES_COUNT}) + checkPackageDescription("${FOUND_FILE_${_file_no}}" "${_expected_description}") +endforeach() + +# kate: indent-width 2; diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake new file mode 100644 index 0000000..ce3f651 --- /dev/null +++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake @@ -0,0 +1,45 @@ +install(FILES CMakeLists.txt DESTINATION satu COMPONENT satu) +install(FILES CMakeLists.txt DESTINATION dua COMPONENT dua) + +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "This is the summary line") +set(_description [[This is the Debian package multiline description. + +It must be formatted properly! Otherwise, the result `*.deb` +package become broken and cant be installed! + +It may contains `;` characters (even like this `;;;;`). Example: + + - one; + - two; + - three; + +... and they are properly handled by the automatic description formatter! + +See also: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description]]) + +if(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_DEBIAN_PACKAGE_DESCRIPTION") + if(PACKAGING_TYPE STREQUAL "COMPONENT") + set(CPACK_DEBIAN_SATU_DESCRIPTION "${_description}") + set(CPACK_DEBIAN_DUA_DESCRIPTION "${_description}") + else() + set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${_description}") + endif() + +elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_PACKAGE_DESCRIPTION") + # NOTE Documented fallback variable + if(PACKAGING_TYPE STREQUAL "COMPONENT") + set(CPACK_COMPONENT_SATU_DESCRIPTION "${_description}") + set(CPACK_COMPONENT_DUA_DESCRIPTION "${_description}") + else() + set(CPACK_PACKAGE_DESCRIPTION "${_description}") + endif() + +elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_PACKAGE_DESCRIPTION_FILE") + # NOTE Getting the description from the file + set(_file "${CMAKE_CURRENT_BINARY_DIR}/description.txt") + file(WRITE "${_file}" "${_description}") + set(CPACK_PACKAGE_DESCRIPTION_FILE "${_file}") + +endif() + +# kate: indent-width 2; diff --git a/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake index b4bdb61..c47b40e 100644 --- a/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake +++ b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake @@ -8,6 +8,9 @@ endfunction() if(GENERATOR_TYPE STREQUAL "DEB") set(name_ "Package") set(group_ "Section") + # NOTE For a Debian package the first line of the `Description` + # field is generated by CMake and gonna be ignored + set(ignore_rest_cond_ ".*\n") elseif(GENERATOR_TYPE STREQUAL "RPM") set(name_ "Name") set(group_ "Group") @@ -33,6 +36,6 @@ if(GENERATOR_TYPE STREQUAL "RPM") endif() # check package description -checkPackageInfo_("description" "${FOUND_FILE_1}" ".*Description${whitespaces_}:${whitespaces_}Description for pkg_1") -checkPackageInfo_("description" "${FOUND_FILE_2}" ".*Description${whitespaces_}:${whitespaces_}Description for pkg_2") -checkPackageInfo_("description" "${FOUND_FILE_3}" ".*Description${whitespaces_}:${whitespaces_}Description for pkg_3") +checkPackageInfo_("description" "${FOUND_FILE_1}" ".*Description${whitespaces_}:${ignore_rest_cond_}${whitespaces_}Description for pkg_1") +checkPackageInfo_("description" "${FOUND_FILE_2}" ".*Description${whitespaces_}:${ignore_rest_cond_}${whitespaces_}Description for pkg_2") +checkPackageInfo_("description" "${FOUND_FILE_3}" ".*Description${whitespaces_}:${ignore_rest_cond_}${whitespaces_}Description for pkg_3") diff --git a/Tests/RunCMake/Configure/RerunCMake-build3-result.txt b/Tests/RunCMake/Configure/RerunCMake-build3-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/Configure/RerunCMake-build3-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/Configure/RerunCMake-build3-stdout.txt b/Tests/RunCMake/Configure/RerunCMake-build3-stdout.txt new file mode 100644 index 0000000..dde2ea6 --- /dev/null +++ b/Tests/RunCMake/Configure/RerunCMake-build3-stdout.txt @@ -0,0 +1 @@ +Rerun error 3 diff --git a/Tests/RunCMake/Configure/RerunCMake-build4-result.txt b/Tests/RunCMake/Configure/RerunCMake-build4-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/Configure/RerunCMake-build4-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/Configure/RerunCMake-build4-stdout.txt b/Tests/RunCMake/Configure/RerunCMake-build4-stdout.txt new file mode 100644 index 0000000..b8727e1 --- /dev/null +++ b/Tests/RunCMake/Configure/RerunCMake-build4-stdout.txt @@ -0,0 +1 @@ +Rerun error 4 diff --git a/Tests/RunCMake/Configure/RerunCMake.cmake b/Tests/RunCMake/Configure/RerunCMake.cmake index 5a561bf..c0b0798 100644 --- a/Tests/RunCMake/Configure/RerunCMake.cmake +++ b/Tests/RunCMake/Configure/RerunCMake.cmake @@ -9,3 +9,9 @@ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${depend}) file(READ ${depend} content) file(WRITE ${output} "${content}") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS RerunCMake.txt) + +set(error ${CMAKE_CURRENT_BINARY_DIR}/CustomCMakeError.txt) +if(EXISTS ${error}) + file(READ ${error} content) + message(FATAL_ERROR "Rerun error ${content}") +endif() diff --git a/Tests/RunCMake/Configure/RunCMakeTest.cmake b/Tests/RunCMake/Configure/RunCMakeTest.cmake index 4a135be..76d843c 100644 --- a/Tests/RunCMake/Configure/RunCMakeTest.cmake +++ b/Tests/RunCMake/Configure/RunCMakeTest.cmake @@ -14,6 +14,7 @@ set(input "${RunCMake_TEST_BINARY_DIR}/CustomCMakeInput.txt") set(stamp "${RunCMake_TEST_BINARY_DIR}/CustomCMakeStamp.txt") set(depend "${RunCMake_TEST_BINARY_DIR}/CustomCMakeDepend.txt") set(output "${RunCMake_TEST_BINARY_DIR}/CustomCMakeOutput.txt") +set(error "${RunCMake_TEST_BINARY_DIR}/CustomCMakeError.txt") file(WRITE "${input}" "1") file(WRITE "${depend}" "1") run_cmake(RerunCMake) @@ -22,6 +23,22 @@ file(WRITE "${input}" "2") run_cmake_command(RerunCMake-build1 ${CMAKE_COMMAND} --build .) file(WRITE "${depend}" "2") run_cmake_command(RerunCMake-build2 ${CMAKE_COMMAND} --build .) +execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1) # handle 1s resolution +file(WRITE "${depend}" "3") +file(WRITE "${error}" "3") +set(RunCMake_TEST_OUTPUT_MERGE 1) +run_cmake_command(RerunCMake-build3 ${CMAKE_COMMAND} --build .) +if(MSVC_IDE) + # Make sure that for Visual Studio the error occurs from within the build + # system. + file(REMOVE "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/generate.stamp.list") + file(WRITE "${error}" "4") + # With Visual Studio the error must be on stdout, otherwise the error was not + # emitted by ZERO_CHECK. + set(RunCMake_TEST_OUTPUT_MERGE 0) + run_cmake_command(RerunCMake-build4 ${CMAKE_COMMAND} --build .) +endif() +unset(RunCMake_TEST_OUTPUT_MERGE) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt index cd542d8..b7ee23a 100644 --- a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt +++ b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt @@ -1,7 +1,7 @@ CMake Error at AppendNotOutput.cmake:1 \(add_custom_command\): add_custom_command given APPEND option with output - .*RunCMake/add_custom_command/AppendNotOutput-build/out.* + .*RunCMake/add_custom_command/AppendNotOutput-build/out which is not already a custom command output. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/add_custom_command/BadByproduct-result.txt b/Tests/RunCMake/add_custom_command/BadByproduct-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/add_custom_command/BadByproduct-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt b/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt new file mode 100644 index 0000000..086e397 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt @@ -0,0 +1,36 @@ +CMake Error at BadByproduct.cmake:2 \(add_custom_command\): + add_custom_command called with BYPRODUCTS containing a "#". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:3 \(add_custom_command\): + add_custom_command called with BYPRODUCTS containing a "<". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:4 \(add_custom_command\): + add_custom_command called with BYPRODUCTS containing a ">". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:5 \(add_custom_command\): + add_custom_command called with BYPRODUCTS containing a "<". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:6 \(add_custom_command\): + add_custom_command attempted to have a file + + .*RunCMake/add_custom_command/f + + in a source directory as an output of custom command. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/add_custom_command/BadByproduct.cmake b/Tests/RunCMake/add_custom_command/BadByproduct.cmake new file mode 100644 index 0000000..91bca52 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/BadByproduct.cmake @@ -0,0 +1,6 @@ +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +add_custom_command(OUTPUT a BYPRODUCTS "a#") +add_custom_command(OUTPUT b BYPRODUCTS "a<") +add_custom_command(OUTPUT c BYPRODUCTS "a>") +add_custom_command(OUTPUT d BYPRODUCTS "$<CONFIG>/#") +add_custom_command(OUTPUT e BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/f) diff --git a/Tests/RunCMake/add_custom_command/BadOutput-result.txt b/Tests/RunCMake/add_custom_command/BadOutput-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/add_custom_command/BadOutput-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt b/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt new file mode 100644 index 0000000..731e58d --- /dev/null +++ b/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt @@ -0,0 +1,36 @@ +CMake Error at BadOutput.cmake:2 \(add_custom_command\): + add_custom_command called with OUTPUT containing a "#". This character is + not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadOutput.cmake:3 \(add_custom_command\): + add_custom_command called with OUTPUT containing a "<". This character is + not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadOutput.cmake:4 \(add_custom_command\): + add_custom_command called with OUTPUT containing a ">". This character is + not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadOutput.cmake:5 \(add_custom_command\): + add_custom_command called with OUTPUT containing a "<". This character is + not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadOutput.cmake:6 \(add_custom_command\): + add_custom_command attempted to have a file + + .*RunCMake/add_custom_command/e + + in a source directory as an output of custom command. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/add_custom_command/BadOutput.cmake b/Tests/RunCMake/add_custom_command/BadOutput.cmake new file mode 100644 index 0000000..6875fe9 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/BadOutput.cmake @@ -0,0 +1,6 @@ +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +add_custom_command(OUTPUT "a#" COMMAND a) +add_custom_command(OUTPUT "a<" COMMAND b) +add_custom_command(OUTPUT "a>" COMMAND c) +add_custom_command(OUTPUT "$<CONFIG>/#" COMMAND d) +add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/e COMMAND f) diff --git a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake index 270df2f..96642fa 100644 --- a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake @@ -4,6 +4,8 @@ run_cmake(AppendLiteralQuotes) run_cmake(AppendNoOutput) run_cmake(AppendNotOutput) run_cmake(BadArgument) +run_cmake(BadByproduct) +run_cmake(BadOutput) run_cmake(GeneratedProperty) run_cmake(LiteralQuotes) run_cmake(NoArguments) diff --git a/Tests/RunCMake/add_custom_target/BadByproduct-result.txt b/Tests/RunCMake/add_custom_target/BadByproduct-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/add_custom_target/BadByproduct-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt b/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt new file mode 100644 index 0000000..0f58550 --- /dev/null +++ b/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt @@ -0,0 +1,36 @@ +CMake Error at BadByproduct.cmake:2 \(add_custom_target\): + add_custom_target called with BYPRODUCTS containing a "#". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:3 \(add_custom_target\): + add_custom_target called with BYPRODUCTS containing a "<". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:4 \(add_custom_target\): + add_custom_target called with BYPRODUCTS containing a ">". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:5 \(add_custom_target\): + add_custom_target called with BYPRODUCTS containing a "<". This character + is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) + + +CMake Error at BadByproduct.cmake:6 \(add_custom_target\): + add_custom_target attempted to have a file + + .*RunCMake/add_custom_target/j + + in a source directory as an output of custom command. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/add_custom_target/BadByproduct.cmake b/Tests/RunCMake/add_custom_target/BadByproduct.cmake new file mode 100644 index 0000000..963d641 --- /dev/null +++ b/Tests/RunCMake/add_custom_target/BadByproduct.cmake @@ -0,0 +1,6 @@ +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +add_custom_target(a BYPRODUCTS "a#" COMMAND b) +add_custom_target(c BYPRODUCTS "a<" COMMAND d) +add_custom_target(e BYPRODUCTS "a>" COMMAND f) +add_custom_target(g BYPRODUCTS "$<CONFIG>/#" COMMAND h) +add_custom_target(i BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/j COMMAND k) diff --git a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake index 49c7d3e..f5d5dd2 100644 --- a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake @@ -1,11 +1,12 @@ include(RunCMake) -run_cmake(CommandExpandsEmpty) -run_cmake(GeneratedProperty) -run_cmake(NoArguments) +run_cmake(BadByproduct) run_cmake(BadTargetName) run_cmake(ByproductsNoCommand) +run_cmake(CommandExpandsEmpty) +run_cmake(GeneratedProperty) run_cmake(LiteralQuotes) +run_cmake(NoArguments) run_cmake(UsesTerminalNoCommand) function(run_TargetOrder) @@ -278,6 +278,7 @@ CMAKE_CXX_SOURCES="\ cmCMakePolicyCommand \ cmCPackPropertiesGenerator \ cmCacheManager \ + cmCheckCustomOutputs \ cmCommand \ cmCommandArgumentParserHelper \ cmCommands \ |