From 23615b7ca4fdebf69068f34bf4a0aececa08359f Mon Sep 17 00:00:00 2001 From: Tyler Yankee Date: Mon, 15 Dec 2025 07:08:33 -0500 Subject: [PATCH] presets: Allow jobs to match `ctest -j` with no value Allow an empty string for the "jobs" field of test presets to mirror the `ctest --parallel` option without a number specified, which corresponds to setting the parallelism to the maximum of the number of processors or 2. Issue: #27070 --- Help/manual/cmake-presets.7.rst | 10 +++++-- Help/manual/presets/schema.json | 16 +++++++++-- Source/cmCMakePresetsErrors.cxx | 6 ++++ Source/cmCMakePresetsErrors.h | 2 ++ Source/cmCMakePresetsGraph.h | 2 +- Source/cmCMakePresetsGraphReadJSON.cxx | 7 +++++ ...cmCMakePresetsGraphReadJSONTestPresets.cxx | 28 ++++++++++++++++++- Source/cmCTest.cxx | 8 ++++-- .../Good-test-jobsProc-stdout.txt | 4 +++ Tests/RunCMake/CMakePresetsTest/Good.json.in | 9 +++++- .../InvalidJobs-test-x-stderr.txt | 2 +- .../JobsProcUnsupported-test-x-result.txt | 1 + .../JobsProcUnsupported-test-x-stderr.txt | 3 ++ .../JobsProcUnsupported.json.in | 19 +++++++++++++ .../ListPresets-test-x-stdout.txt | 1 + .../CMakePresetsTest/RunCMakeTest.cmake | 3 +- 16 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-result.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst index a4714b0681..7ad9e5eeaa 100644 --- a/Help/manual/cmake-presets.7.rst +++ b/Help/manual/cmake-presets.7.rst @@ -902,7 +902,9 @@ that may contain the following fields: :option:`--parallel ` on the command line. If the value is ``0``, it is equivalent to unbounded parallelism. - In preset files specifying version ``11`` or above, this field does not accept + In preset files specifying version ``11`` or above, this field can also be + a string, in which case it must be empty, and is equivalent to passing + ``--parallel`` with ```` omitted; additionally, it does not accept negative values. ``resourceSpecFile`` @@ -1465,8 +1467,10 @@ they were added and a summary of the new features and changes is given below. * Changes to `Test Presets `_ - * The `jobs `_ field no longer accepts negative - values. + * The `jobs `_ field now accepts an empty string + representing :option:`--parallel ` with ```` + omitted. In addition, when an integer is specified, it must not be + negative. Schema ====== diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json index 3da3dfd0cc..ec4b62bac5 100644 --- a/Help/manual/presets/schema.json +++ b/Help/manual/presets/schema.json @@ -1006,9 +1006,19 @@ } }, "testPresetsExecutionJobsV11": { - "type": "integer", - "description": "An optional integer. Equivalent to passing --parallel on the command line.", - "minimum": 0 + "oneOf": [ + { + "type": "integer", + "description": "An optional integer. Equivalent to passing --parallel on the command line.", + "minimum": 0 + }, + { + "type": "string", + "description": "An optional string. Equivalent to passing --parallel on the command line with the number of jobs omitted.", + "minLength": 0, + "maxLength": 0 + } + ] }, "testPresetsExecutionJobsV2": { "type": "integer", diff --git a/Source/cmCMakePresetsErrors.cxx b/Source/cmCMakePresetsErrors.cxx index c77a528815..f2cbe84271 100644 --- a/Source/cmCMakePresetsErrors.cxx +++ b/Source/cmCMakePresetsErrors.cxx @@ -183,6 +183,12 @@ void GRAPHVIZ_FILE_UNSUPPORTED(cmJSONState* state) "File version must be 10 or higher for graphviz preset support"); } +void JOBS_PROC_UNSUPPORTED(cmJSONState* state) +{ + state->AddError("File version must be 11 or higher for " + "processor-count-based jobs preset support"); +} + void CYCLIC_INCLUDE(std::string const& file, cmJSONState* state) { state->AddError(cmStrCat("Cyclic include among preset files: ", file)); diff --git a/Source/cmCMakePresetsErrors.h b/Source/cmCMakePresetsErrors.h index 8bb9de959c..372ceb8803 100644 --- a/Source/cmCMakePresetsErrors.h +++ b/Source/cmCMakePresetsErrors.h @@ -72,6 +72,8 @@ void TOOLCHAIN_FILE_UNSUPPORTED(cmJSONState* state); void GRAPHVIZ_FILE_UNSUPPORTED(cmJSONState* state); +void JOBS_PROC_UNSUPPORTED(cmJSONState* state); + void CYCLIC_INCLUDE(std::string const& file, cmJSONState* state); void TEST_OUTPUT_TRUNCATION_UNSUPPORTED(cmJSONState* state); diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h index 7485e35d08..4ce0ace626 100644 --- a/Source/cmCMakePresetsGraph.h +++ b/Source/cmCMakePresetsGraph.h @@ -289,7 +289,7 @@ public: cm::optional StopOnFailure; cm::optional EnableFailover; - cm::optional Jobs; + cm::optional> Jobs; std::string ResourceSpecFile; cm::optional TestLoad; cm::optional ShowOnly; diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index 21af48fbdb..d141b10086 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -693,6 +693,13 @@ bool cmCMakePresetsGraph::ReadJSONFile(std::string const& filename, return false; } + // Support for processor-count-based jobs added in version 11. + if (v < 11 && preset.Execution && preset.Execution->Jobs.has_value() && + !preset.Execution->Jobs->has_value()) { + cmCMakePresetsErrors::JOBS_PROC_UNSUPPORTED(&this->parseState); + return false; + } + this->TestPresetOrder.push_back(preset.Name); } diff --git a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx index 87ea03157d..d7164452ea 100644 --- a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx +++ b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx @@ -301,6 +301,32 @@ auto const TestPresetOptionalExecutionNoTestsActionHelper = JSONHelperBuilder::Optional( TestPresetExecutionNoTestsActionHelper); +bool TestPresetExecutionJobsHelper(cm::optional& out, + Json::Value const* value, + cmJSONState* state) +{ + if (value->isString()) { + if (!value->asString().empty()) { + cmCMakePresetsErrors::INVALID_PRESET(value, state); + return false; + } + out.reset(); + return true; + } + + if (value->isUInt()) { + out.emplace(value->asUInt()); + return true; + } + + cmCMakePresetsErrors::INVALID_PRESET(value, state); + return false; +} + +auto const TestPresetOptionalExecutionJobsHelper = + JSONHelperBuilder::Optional>( + TestPresetExecutionJobsHelper); + auto const TestPresetExecutionHelper = JSONHelperBuilder::Optional( JSONHelperBuilder::Object() @@ -309,7 +335,7 @@ auto const TestPresetExecutionHelper = .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover, cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs, - cmCMakePresetsGraphInternal::PresetOptionalUIntHelper, false) + TestPresetOptionalExecutionJobsHelper, false) .Bind("resourceSpecFile"_s, &TestPreset::ExecutionOptions::ResourceSpecFile, cmCMakePresetsGraphInternal::PresetStringHelper, false) diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 583f26e91d..6dc3726821 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1710,8 +1710,12 @@ bool cmCTest::SetArgsFromPreset(std::string const& presetName, expandedPreset->Execution->EnableFailover.value_or(false); if (expandedPreset->Execution->Jobs) { - unsigned int jobs = *expandedPreset->Execution->Jobs; - this->SetParallelLevel(static_cast(jobs)); + cm::optional jobs = *expandedPreset->Execution->Jobs; + if (jobs.has_value()) { + this->SetParallelLevel(static_cast(jobs.value())); + } else { + this->SetParallelLevel(cm::nullopt); + } this->Impl->ParallelLevelSetInCli = true; } diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt new file mode 100644 index 0000000000..c59dcd3afb --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt @@ -0,0 +1,4 @@ +Test project [^ +]*/Tests/RunCMake/CMakePresetsTest/Good/build/default +.* +100% tests passed, 0 tests failed out of 5 diff --git a/Tests/RunCMake/CMakePresetsTest/Good.json.in b/Tests/RunCMake/CMakePresetsTest/Good.json.in index a4b875a1d8..b436cc86b3 100644 --- a/Tests/RunCMake/CMakePresetsTest/Good.json.in +++ b/Tests/RunCMake/CMakePresetsTest/Good.json.in @@ -1,5 +1,5 @@ { - "version": 6, + "version": 11, "configurePresets": [ { "name": "default", @@ -160,6 +160,13 @@ } } }, + { + "name": "jobsProc", + "inherits": "minimal", + "execution": { + "jobs": "" + } + }, { "name": "showOnly", "inherits": "minimal", diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt index 57ecb8ec38..d47899c356 100644 --- a/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt +++ b/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt @@ -1,5 +1,5 @@ ^CMake Error: Could not read presets from [^ ]*/Tests/RunCMake/CMakePresetsTest/InvalidJobs: -CMakePresets\.json:15: "jobs" expected an unsigned integer, got: -10 +CMakePresets\.json:15: Invalid preset "jobs": -10 \^$ diff --git a/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-result.txt b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt new file mode 100644 index 0000000000..0c0ae4a2e9 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt @@ -0,0 +1,3 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported: +File version must be 11 or higher for processor-count-based jobs preset support$ diff --git a/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in new file mode 100644 index 0000000000..8f09b24fd3 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in @@ -0,0 +1,19 @@ +{ + "version": 10, + "configurePresets": [ + { + "name": "default", + "generator": "@RunCMake_GENERATOR@", + "binaryDir": "${sourceDir}/build" + } + ], + "testPresets": [ + { + "name": "default", + "configurePreset": "default", + "execution": { + "jobs": "" + } + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt index 46ffbcfb60..737a2a0127 100644 --- a/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt +++ b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt @@ -9,4 +9,5 @@ Available test presets: "exclude" "index" "indexFile" + "jobsProc" "showOnly" diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake index d97294a4f5..d7fcb48d7d 100644 --- a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake @@ -82,7 +82,7 @@ set(CMakePresetsTest_ASSETS "Good-indexFile.txt") set(GoodTestPresets "minimal;defaults;noEnvironment;withEnvironment" "config-debug;config-release" - "exclude;index;indexFile;showOnly;outputLog;outputJUnit") + "exclude;index;indexFile;jobsProc;showOnly;outputLog;outputJUnit") run_cmake_test_presets(Good "default" "" @@ -112,6 +112,7 @@ run_cmake_test_presets(ConditionFuture "" "" "x") run_cmake_test_presets(TestOutputTruncationUnsupported "" "" "x") run_cmake_test_presets(OutputJUnitUnsupported "" "" "x") run_cmake_test_presets(InvalidJobs "" "" "x") +run_cmake_test_presets(JobsProcUnsupported "" "" "x") set(CMakePresets_SCHEMA_EXPECTED_RESULT 0) run_cmake_test_presets(ConfigurePresetUnreachable "" "" "x") set(CMakePresetsTest_NO_CONFIGURE 0)