Browse Source

VS: add source property VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD

This boolean setting allows parallel building to be disabled for
individual source files built via `add_custom_command`. Using this
option is equivalent to setting policy `CMP0147` to the `OLD` behavior.

Closes: #26413
Darragh Coy 11 months ago
parent
commit
4ee8705b12

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -584,6 +584,7 @@ Properties on Source Files
    /prop_sf/UNITY_GROUP
    /prop_sf/UNITY_GROUP
    /prop_sf/VS_COPY_TO_OUT_DIR
    /prop_sf/VS_COPY_TO_OUT_DIR
    /prop_sf/VS_CSHARP_tagname
    /prop_sf/VS_CSHARP_tagname
+   /prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD
    /prop_sf/VS_DEPLOYMENT_CONTENT
    /prop_sf/VS_DEPLOYMENT_CONTENT
    /prop_sf/VS_DEPLOYMENT_LOCATION
    /prop_sf/VS_DEPLOYMENT_LOCATION
    /prop_sf/VS_INCLUDE_IN_VSIX
    /prop_sf/VS_INCLUDE_IN_VSIX

+ 2 - 1
Help/policy/CMP0147.rst

@@ -10,7 +10,8 @@ parallel.  CMake 3.27 and above prefer to enable this behavior by adding
 a ``BuildInParallel`` setting to custom commands in ``.vcxproj`` files.
 a ``BuildInParallel`` setting to custom commands in ``.vcxproj`` files.
 This policy provides compatibility for projects that have not been updated
 This policy provides compatibility for projects that have not been updated
 to expect this, e.g., because their custom commands were accidentally
 to expect this, e.g., because their custom commands were accidentally
-relying on serial execution by MSBuild.
+relying on serial execution by MSBuild. To control this behavior in a more
+precise way, refer to :prop_sf:`VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD`.
 
 
 The ``OLD`` behavior for this policy is to not add ``BuildInParallel``.
 The ``OLD`` behavior for this policy is to not add ``BuildInParallel``.
 The ``NEW`` behavior for this policy is to add ``BuildInParallel`` for
 The ``NEW`` behavior for this policy is to add ``BuildInParallel`` for

+ 9 - 0
Help/prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD.rst

@@ -0,0 +1,9 @@
+VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD
+----------------------------------------
+
+.. versionadded:: 3.32
+
+A boolean property that disables parallel building for the source file in
+Visual Studio if it is built via :command:`add_custom_command` and is the
+``MAIN_DEPENDENCY`` input for the custom command.
+See policy :policy:`CMP0147`.

+ 6 - 0
Help/release/dev/vs-custom-command-disable-parallel-build.rst

@@ -0,0 +1,6 @@
+vs-custom-command-disable-parallel-build
+----------------------------------------
+
+* The :prop_sf:`VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD` source file property
+  was added to tell :ref:`Visual Studio Generators` not to run a custom command
+  in parallel.

+ 3 - 1
Source/cmVisualStudio10TargetGenerator.cxx

@@ -1870,7 +1870,9 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
       BuildInParallel buildInParallel = BuildInParallel::No;
       BuildInParallel buildInParallel = BuildInParallel::No;
       if (command.GetCMP0147Status() == cmPolicies::NEW &&
       if (command.GetCMP0147Status() == cmPolicies::NEW &&
           !command.GetUsesTerminal() &&
           !command.GetUsesTerminal() &&
-          !(command.HasMainDependency() && source->GetIsGenerated())) {
+          !(command.HasMainDependency() && source->GetIsGenerated()) &&
+          !source->GetPropertyAsBool(
+            "VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD")) {
         buildInParallel = BuildInParallel::Yes;
         buildInParallel = BuildInParallel::Yes;
       }
       }
       this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(),
       this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(),

+ 42 - 0
Tests/RunCMake/VS10Project/CustomCommandParallelDisable-check.cmake

@@ -0,0 +1,42 @@
+# Check whether the 'BuildInParallel' setting is set as expected for a specified project file.
+# Note: if the setting is not present in the project file then it is assumed to be implicitly 'false'.
+function(check_build_in_parallel_setting projectFile expectedEnabled)
+  set(SettingEnabledRegex "<BuildInParallel.*>true</BuildInParallel>")
+  set(SettingDisabledRegex "<BuildInParallel.*>false</BuildInParallel>")
+
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file '${projectFile}' does not exist." PARENT_SCOPE)
+    return()
+  endif()
+
+  set(settingEnabled FALSE)
+  set(settingExplicitlyDisabled FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+
+  foreach(line IN LISTS lines)
+    if(line MATCHES "${SettingEnabledRegex}")
+      set(settingEnabled TRUE)
+    elseif(line MATCHES "${SettingDisabledRegex}")
+      set(settingExplicitlyDisabled TRUE)
+    endif()
+  endforeach()
+
+  if(expectedEnabled)
+    if(NOT settingEnabled)
+      set(RunCMake_TEST_FAILED "Expected 'BuildInParallel' to be enabled for projectFile '${projectFile}' but it was not!" PARENT_SCOPE)
+    endif()
+    if(settingExplicitlyDisabled)
+      set(RunCMake_TEST_FAILED "Expected 'BuildInParallel' to be enabled for projectFile '${projectFile}' but instead found it explicitly disabled!" PARENT_SCOPE)
+    endif()
+  else()
+    if(settingEnabled)
+      set(RunCMake_TEST_FAILED "Expected 'BuildInParallel' to be disabled for projectFile '${projectFile}' but it was not!")
+    endif()
+  endif()
+endfunction()
+
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/foo1.vcxproj" TRUE)
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/bar1.vcxproj" FALSE)
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/foo2.vcxproj" FALSE)
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/bar2.vcxproj" FALSE)

+ 21 - 0
Tests/RunCMake/VS10Project/CustomCommandParallelDisable.cmake

@@ -0,0 +1,21 @@
+block()
+  cmake_policy(SET CMP0147 NEW) # Build custom commands in parallel by default
+
+  add_custom_command(OUTPUT "foo.out.txt" COMMAND echo Foo > foo.out.txt MAIN_DEPENDENCY "foo.txt")
+  add_custom_command(OUTPUT "bar.out.txt" COMMAND echo Bar > bar.out.txt MAIN_DEPENDENCY "bar.txt")
+  set_property(SOURCE "bar.txt" PROPERTY VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD TRUE)
+
+  add_custom_target(foo1 SOURCES foo.txt)
+  add_custom_target(bar1 SOURCES bar.txt)
+endblock()
+
+block()
+  cmake_policy(SET CMP0147 OLD) # Don't build custom commands in parallel by default
+
+  add_custom_command(OUTPUT "foo.out.cpp" COMMAND echo Foo > foo.out.txt MAIN_DEPENDENCY "foo.cpp")
+  add_custom_command(OUTPUT "bar.out.cpp" COMMAND echo Bar > bar.out.txt MAIN_DEPENDENCY "bar.cpp")
+  set_property(SOURCE "bar.cpp" PROPERTY VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD TRUE)
+
+  add_custom_target(foo2 SOURCES foo.cpp)
+  add_custom_target(bar2 SOURCES bar.cpp)
+endblock()

+ 1 - 0
Tests/RunCMake/VS10Project/RunCMakeTest.cmake

@@ -10,6 +10,7 @@ endif()
 run_cmake(CustomCommandGenex)
 run_cmake(CustomCommandGenex)
 if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 1[1-5] ")
 if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 1[1-5] ")
   run_cmake(CustomCommandParallel)
   run_cmake(CustomCommandParallel)
+  run_cmake(CustomCommandParallelDisable)
 endif()
 endif()
 run_cmake_with_options(VsCharacterSet -DSET_CHARSET=MultiByte)
 run_cmake_with_options(VsCharacterSet -DSET_CHARSET=MultiByte)
 run_cmake_with_options(VsCharacterSet -DSET_CHARSET=Unicode)
 run_cmake_with_options(VsCharacterSet -DSET_CHARSET=Unicode)