diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index b310e89fd0..8adc64abd3 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -584,6 +584,7 @@ Properties on Source Files /prop_sf/UNITY_GROUP /prop_sf/VS_COPY_TO_OUT_DIR /prop_sf/VS_CSHARP_tagname + /prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD /prop_sf/VS_DEPLOYMENT_CONTENT /prop_sf/VS_DEPLOYMENT_LOCATION /prop_sf/VS_INCLUDE_IN_VSIX diff --git a/Help/policy/CMP0147.rst b/Help/policy/CMP0147.rst index fd5dc5f998..1790678b47 100644 --- a/Help/policy/CMP0147.rst +++ b/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. This policy provides compatibility for projects that have not been updated 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 ``NEW`` behavior for this policy is to add ``BuildInParallel`` for diff --git a/Help/prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD.rst b/Help/prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD.rst new file mode 100644 index 0000000000..f8bb93dc2d --- /dev/null +++ b/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`. diff --git a/Help/release/dev/vs-custom-command-disable-parallel-build.rst b/Help/release/dev/vs-custom-command-disable-parallel-build.rst new file mode 100644 index 0000000000..1867a4a0f3 --- /dev/null +++ b/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. diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 694976e58a..813a83da2b 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1870,7 +1870,9 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( BuildInParallel buildInParallel = BuildInParallel::No; if (command.GetCMP0147Status() == cmPolicies::NEW && !command.GetUsesTerminal() && - !(command.HasMainDependency() && source->GetIsGenerated())) { + !(command.HasMainDependency() && source->GetIsGenerated()) && + !source->GetPropertyAsBool( + "VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD")) { buildInParallel = BuildInParallel::Yes; } this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(), diff --git a/Tests/RunCMake/VS10Project/CustomCommandParallelDisable-check.cmake b/Tests/RunCMake/VS10Project/CustomCommandParallelDisable-check.cmake new file mode 100644 index 0000000000..e0608f6ef9 --- /dev/null +++ b/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 "true") + set(SettingDisabledRegex "false") + + 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) diff --git a/Tests/RunCMake/VS10Project/CustomCommandParallelDisable.cmake b/Tests/RunCMake/VS10Project/CustomCommandParallelDisable.cmake new file mode 100644 index 0000000000..b9ea3ab314 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index bbd8c8b1a1..49c345cace 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -10,6 +10,7 @@ endif() run_cmake(CustomCommandGenex) if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 1[1-5] ") run_cmake(CustomCommandParallel) + run_cmake(CustomCommandParallelDisable) endif() run_cmake_with_options(VsCharacterSet -DSET_CHARSET=MultiByte) run_cmake_with_options(VsCharacterSet -DSET_CHARSET=Unicode)