Explorar o código

VS: only add custom command line if it is not empty

Michael Stürmer %!s(int64=8) %!d(string=hai) anos
pai
achega
9ed2428078

+ 10 - 0
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.

+ 7 - 3
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.
     //

+ 7 - 5
Source/cmVisualStudio10TargetGenerator.cxx

@@ -3536,11 +3536,13 @@ void cmVisualStudio10TargetGenerator::WriteEvent(
   for (std::vector<cmCustomCommand>::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) {

+ 63 - 0
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 "^ *<ItemDefinitionGroup Condition=.*Configuration.*Platform.*>$")
+    set(inGroup TRUE)
+    string(REGEX MATCH "=='(.*)\\|(.*)'" out ${line})
+    set(config ${CMAKE_MATCH_1})
+  elseif(line MATCHES "^ *</ItemDefinitionGroup>$")
+    set(inGroup FALSE)
+  elseif(inGroup)
+    if(line MATCHES "^ *<Command>.*$")
+      set(inCommand TRUE)
+      string(REGEX MATCH "<Command>(.*)" cmd ${line})
+      set(currentCommand ${CMAKE_MATCH_1})
+    elseif(line MATCHES "^(.*)</Command>$")
+      string(REGEX MATCH "(.*)</Command>" 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()

+ 22 - 0
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 $<$<CONFIG:Debug>:cmd_1_dbg> $<$<CONFIG:Debug>:cmd_1_dbg_arg>)
+
+# add command for debug only
+add_custom_command(TARGET exe
+  COMMAND $<$<CONFIG:Debug>:cmd_2_dbg> $<$<CONFIG:Debug>:cmd_2_dbg_arg>)
+
+# add separate commands for configurations
+add_custom_command(TARGET exe
+  COMMAND $<$<CONFIG:Debug>:cmd_3_dbg> $<$<CONFIG:Debug>:cmd_3_dbg_arg>
+  COMMAND $<$<CONFIG:Release>:cmd_3_rel> $<$<CONFIG:Release>:cmd_3_rel_arg>)

+ 4 - 0
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()