From 34c4108bbcb8774821ac857e0ad0a92294ee8b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Wed, 30 Aug 2017 15:30:32 +0200 Subject: add HasOnlyEmptyCommandLines() method to cmCustomCommandGenerator --- Source/cmCustomCommandGenerator.cxx | 12 ++++++++++++ Source/cmCustomCommandGenerator.h | 1 + 2 files changed, 13 insertions(+) diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index fdc0a97..c6a2800 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -97,6 +97,18 @@ const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const return nullptr; } +bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const +{ + for (size_t i = 0; i < this->CommandLines.size(); ++i) { + for (size_t j = 0; j < this->CommandLines[i].size(); ++j) { + if (!this->CommandLines[i][j].empty()) { + return false; + } + } + } + return true; +} + std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const { if (const char* emulator = this->GetCrossCompilingEmulator(c)) { diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index ea33b51..34fd653 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -40,6 +40,7 @@ public: std::vector const& GetOutputs() const; std::vector const& GetByproducts() const; std::vector const& GetDepends() const; + bool HasOnlyEmptyCommandLines() const; }; #endif -- cgit v0.12 From 9ed242807893becd4cd8245248fade93f7054c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Wed, 30 Aug 2017 17:40:02 +0200 Subject: VS: only add custom command line if it is not empty --- Help/command/add_custom_command.rst | 10 ++++ Source/cmLocalVisualStudioGenerator.cxx | 10 ++-- Source/cmVisualStudio10TargetGenerator.cxx | 12 +++-- .../RemoveEmptyCommands-check.cmake | 63 ++++++++++++++++++++++ .../add_custom_command/RemoveEmptyCommands.cmake | 22 ++++++++ .../RunCMake/add_custom_command/RunCMakeTest.cmake | 4 ++ 6 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 Tests/RunCMake/add_custom_command/RemoveEmptyCommands-check.cmake create mode 100644 Tests/RunCMake/add_custom_command/RemoveEmptyCommands.cmake diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index d038406..1b0aa14 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -225,3 +225,13 @@ of the following is specified: :command:`add_custom_target` command. ``POST_BUILD`` Run after all other rules within the target have been executed. + +.. note:: + Because generator expressions can be used in custom commands, + it is possible to define ``COMMAND`` lines or whole custom commands + which evaluate to empty strings for certain configurations. + For **Visual Studio 2010 (and newer)** generators these command + lines or custom commands will be omitted for the specific + configuration and no "empty-string-command" will be added. + + This allows to add individual build events for every configuration. diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 41025af..d772d95 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -191,13 +191,17 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( // Write each command on a single line. for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) { + // Add this command line. + std::string cmd = ccg.GetCommand(c); + + if (cmd.empty()) { + continue; + } + // Start a new line. script += newline; newline = newline_text; - // Add this command line. - std::string cmd = ccg.GetCommand(c); - // Use "call " before any invocations of .bat or .cmd files // invoked as custom commands. // diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 86099eb..2b3d40f 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3536,11 +3536,13 @@ void cmVisualStudio10TargetGenerator::WriteEvent( for (std::vector::const_iterator i = commands.begin(); i != commands.end(); ++i) { cmCustomCommandGenerator ccg(*i, configName, this->LocalGenerator); - comment += pre; - comment += lg->ConstructComment(ccg); - script += pre; - pre = "\n"; - script += cmVS10EscapeXML(lg->ConstructScript(ccg)); + if (!ccg.HasOnlyEmptyCommandLines()) { + comment += pre; + comment += lg->ConstructComment(ccg); + script += pre; + pre = "\n"; + script += cmVS10EscapeXML(lg->ConstructScript(ccg)); + } } comment = cmVS10EscapeComment(comment); if (this->ProjectType != csproj) { diff --git a/Tests/RunCMake/add_custom_command/RemoveEmptyCommands-check.cmake b/Tests/RunCMake/add_custom_command/RemoveEmptyCommands-check.cmake new file mode 100644 index 0000000..b297044 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/RemoveEmptyCommands-check.cmake @@ -0,0 +1,63 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/exe.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(inGroup FALSE) +set(inCommand FALSE) + +set(expected_Debug + "cmd_1 cmd_1_arg" + "cmd_1_dbg cmd_1_dbg_arg" + "cmd_2_dbg cmd_2_dbg_arg" + "cmd_3_dbg cmd_3_dbg_arg") + +set(expected_Release + "cmd_1 cmd_1_arg" + "cmd_3_rel cmd_3_rel_arg") + +# extract build events +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *$") + set(inGroup TRUE) + string(REGEX MATCH "=='(.*)\\|(.*)'" out ${line}) + set(config ${CMAKE_MATCH_1}) + elseif(line MATCHES "^ *$") + set(inGroup FALSE) + elseif(inGroup) + if(line MATCHES "^ *.*$") + set(inCommand TRUE) + string(REGEX MATCH "(.*)" cmd ${line}) + set(currentCommand ${CMAKE_MATCH_1}) + elseif(line MATCHES "^(.*)$") + string(REGEX MATCH "(.*)" cmd ${line}) + list(APPEND currentCommand ${CMAKE_MATCH_1}) + set(command_${config} ${currentCommand}) + set(inCommand FALSE) + elseif(inCommand) + list(APPEND currentCommand ${line}) + endif() + endif() +endforeach() + +foreach(config "Debug" "Release") + set(currentName command_${config}) + set(expectedName expected_${config}) + set(strippedCommand "") + if(DEFINED ${currentName}) + foreach(v ${${currentName}}) + if(${v} MATCHES "cmd_") + list(APPEND strippedCommand ${v}) + endif() + endforeach() + if(NOT "${strippedCommand}" STREQUAL + "${${expectedName}}") + message(" - ${strippedCommand}") + message(" + ${${expectedName}}") + set(RunCMake_TEST_FAILED "build event command does not match") + return() + endif() + endif() +endforeach() diff --git a/Tests/RunCMake/add_custom_command/RemoveEmptyCommands.cmake b/Tests/RunCMake/add_custom_command/RemoveEmptyCommands.cmake new file mode 100644 index 0000000..eb190cc --- /dev/null +++ b/Tests/RunCMake/add_custom_command/RemoveEmptyCommands.cmake @@ -0,0 +1,22 @@ +enable_language(CXX) + +# reduce number of configuration types +set(CMAKE_CONFIGURATION_TYPES "Debug" "Release") + +set(main_file "${CMAKE_BINARY_DIR}/main.cpp") +file(WRITE "${main_file}" "test") +add_executable(exe "${main_file}") + +# add one command for all and one for debug only +add_custom_command(TARGET exe + COMMAND "cmd_1" "cmd_1_arg" + COMMAND $<$:cmd_1_dbg> $<$:cmd_1_dbg_arg>) + +# add command for debug only +add_custom_command(TARGET exe + COMMAND $<$:cmd_2_dbg> $<$:cmd_2_dbg_arg>) + +# add separate commands for configurations +add_custom_command(TARGET exe + COMMAND $<$:cmd_3_dbg> $<$:cmd_3_dbg_arg> + COMMAND $<$:cmd_3_rel> $<$:cmd_3_rel_arg>) diff --git a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake index 397c63d..c12e5aa 100644 --- a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake @@ -10,3 +10,7 @@ run_cmake(SourceByproducts) run_cmake(SourceUsesTerminal) run_cmake(TargetImported) run_cmake(TargetNotInDir) + +if(${RunCMake_GENERATOR} MATCHES "Visual Studio ([^89]|[89][0-9])") + run_cmake(RemoveEmptyCommands) +endif() -- cgit v0.12