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
This commit is contained in:
Darragh Coy 2024-11-06 09:57:00 -08:00 committed by Brad King
parent 65c1147e6c
commit 4ee8705b12
8 changed files with 85 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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`.

View File

@ -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.

View File

@ -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(),

View File

@ -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)

View File

@ -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()

View File

@ -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)