Presets: Extract ResolvePreset utility for preset resolution

Replace duplicated inline preset lookup/validation logic in cmake.cxx,
cmCTest.cxx, and cpack.cxx with a shared ResolvePreset<T> template
method on cmCMakePresetsGraph.

Use the PresetType::kind() static method introduced in commit
0f3347bb27 (cmCMakePresetsGraph: generalize printing presets of
different types) to derive error message strings, replacing the
runtime presetType string parameter with a template parameter.

Error messages for configure presets now consistently include
"configure" in the preset type (e.g., "No such configure preset")
matching the pattern used by build, test, and package presets.
This commit is contained in:
Mickaël Germain
2026-04-21 10:10:02 -07:00
parent 56921fa912
commit e99fbf4100
14 changed files with 271 additions and 165 deletions

View File

@@ -136,6 +136,7 @@ add_library(
cmCMakePresetsGraphReadJSONPackagePresets.cxx
cmCMakePresetsGraphReadJSONTestPresets.cxx
cmCMakePresetsGraphReadJSONWorkflowPresets.cxx
cmCMakePresetsGraphResolve.cxx
cmCMakeString.hxx
cmCMakeString.cxx
cmCommandLineArgument.h

View File

@@ -276,41 +276,20 @@ int main(int argc, char const* const* argv)
return 0;
}
auto presetPair = presetsGraph.PackagePresets.find(preset);
if (presetPair == presetsGraph.PackagePresets.end()) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"No such package preset in " << workingDirectory << ": \""
<< preset << "\"\n");
auto resolveResult =
presetsGraph.ResolvePreset(preset, presetsGraph.PackagePresets);
auto resolveError = cmCMakePresetsGraph::FormatPresetError<
cmCMakePresetsGraph::PackagePreset>(resolveResult.StatusCode,
resolveResult.ErrorPresetName,
workingDirectory);
if (resolveError) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR, *resolveError << "\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
auto const* expandedPreset = resolveResult.Preset;
if (presetPair->second.Unexpanded.Hidden) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Cannot use hidden package preset in "
<< workingDirectory << ": \"" << preset << "\"\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
auto const& expandedPreset = presetPair->second.Expanded;
if (!expandedPreset) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Could not evaluate package preset \""
<< preset << "\": Invalid macro expansion\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
if (!expandedPreset->ConditionResult) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Cannot use disabled package preset in "
<< workingDirectory << ": \"" << preset << "\"\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
if (!presetGeneratorsPresent(presetPair->second.Unexpanded)) {
if (!presetGeneratorsPresent(*expandedPreset)) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use preset");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;

View File

@@ -4,10 +4,8 @@
#include <chrono>
#include <cstdlib>
#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <cm/memory>
@@ -36,48 +34,6 @@ using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
namespace {
cm::optional<ConfigurePreset> LoadPreset(cmExecutionStatus& status,
std::string sourceDirectory,
std::string presetName)
{
// Load a configure preset after verifying its existence and validity.
cmCMakePresetsGraph presetsGraph;
if (!presetsGraph.ReadProjectPresets(sourceDirectory)) {
status.SetError(
cmStrCat("Could not read presets from \"", sourceDirectory,
"\": ", presetsGraph.parseState.GetErrorMessage()));
return cm::nullopt;
}
auto preset = presetsGraph.ConfigurePresets.find(presetName);
if (preset == presetsGraph.ConfigurePresets.end()) {
status.SetError(cmStrCat("No such preset in ", sourceDirectory, ": \"",
presetName, '"'));
return cm::nullopt;
}
if (preset->second.Unexpanded.Hidden) {
status.SetError(cmStrCat("Cannot use hidden preset in ", sourceDirectory,
": \"", presetName, '"'));
return cm::nullopt;
}
auto const& expandedPreset = preset->second.Expanded;
if (!expandedPreset) {
status.SetError(cmStrCat("Could not evaluate preset \"", presetName,
"\": Invalid macro expansion."));
return cm::nullopt;
}
if (!expandedPreset->ConditionResult) {
status.SetError(
cmStrCat("Cannot use disabled preset \"", presetName, "\"."));
return cm::nullopt;
}
return expandedPreset;
}
bool ConstructConfigureCommand(cmExecutionStatus& status, cmMakefile& mf,
std::string const sourceDirectory,
std::string const buildDirectory,
@@ -107,11 +63,27 @@ bool ConstructConfigureCommand(cmExecutionStatus& status, cmMakefile& mf,
bool presetProvidesGenerator = false;
if (!presetName.empty()) {
auto expandedPreset = LoadPreset(status, sourceDirectory, presetName);
if (!expandedPreset) {
cmCMakePresetsGraph presetsGraph;
if (!presetsGraph.ReadProjectPresets(sourceDirectory)) {
status.SetError(
cmStrCat("Could not read presets from \"", sourceDirectory,
"\": ", presetsGraph.parseState.GetErrorMessage()));
return false;
}
auto resolveResult =
presetsGraph.ResolvePreset(presetName, presetsGraph.ConfigurePresets);
auto resolveError =
cmCMakePresetsGraph::FormatPresetError<ConfigurePreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
sourceDirectory);
if (resolveError) {
status.SetError(*resolveError);
return false;
}
auto const* expandedPreset = resolveResult.Preset;
configureCommand += " \"--preset\"";
configureCommand += " \"";
configureCommand += presetName;

View File

@@ -401,6 +401,38 @@ public:
cm::optional<T> Expanded;
};
enum class PresetResolveStatus
{
Success,
NotFound,
Hidden,
InvalidMacroExpansion,
Disabled,
};
// Result type for preset resolution
template <class T>
struct PresetResolveResult
{
using Status = PresetResolveStatus;
Status StatusCode = Status::Success;
std::string ErrorPresetName;
T const* Preset = nullptr;
};
template <class T>
PresetResolveResult<T> ResolvePreset(
std::string const& presetName,
std::map<std::string, PresetPair<T>> const& presets) const;
// Returns an error message for a preset resolve status,
// or cm::nullopt on Success.
template <class T>
static cm::optional<std::string> FormatPresetError(
PresetResolveStatus status, std::string const& errorPresetName,
std::string const& directory);
std::map<std::string, PresetPair<ConfigurePreset>> ConfigurePresets;
std::map<std::string, PresetPair<BuildPreset>> BuildPresets;
std::map<std::string, PresetPair<TestPreset>> TestPresets;
@@ -459,3 +491,57 @@ private:
static std::string GetFilename(std::string const& sourceDir);
static std::string GetUserFilename(std::string const& sourceDir);
};
extern template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::ConfigurePreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<std::string,
cmCMakePresetsGraph::PresetPair<
cmCMakePresetsGraph::ConfigurePreset>> const&) const;
extern template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::BuildPreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<
std::string,
cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::BuildPreset>> const&)
const;
extern template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::TestPreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<
std::string,
cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::TestPreset>> const&)
const;
extern template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::PackagePreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<std::string,
cmCMakePresetsGraph::PresetPair<
cmCMakePresetsGraph::PackagePreset>> const&) const;
extern template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::ConfigurePreset>(
cmCMakePresetsGraph::PresetResolveStatus, std::string const&,
std::string const&);
extern template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::BuildPreset>(
cmCMakePresetsGraph::PresetResolveStatus, std::string const&,
std::string const&);
extern template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::TestPreset>(
cmCMakePresetsGraph::PresetResolveStatus, std::string const&,
std::string const&);
extern template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::PackagePreset>(
cmCMakePresetsGraph::PresetResolveStatus, std::string const&,
std::string const&);

View File

@@ -0,0 +1,116 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#include <cassert>
#include <map>
#include <string>
#include <cm/optional>
#include "cmCMakePresetsGraph.h"
#include "cmStringAlgorithms.h"
template <class T>
cmCMakePresetsGraph::PresetResolveResult<T> cmCMakePresetsGraph::ResolvePreset(
std::string const& presetName,
std::map<std::string, PresetPair<T>> const& presets) const
{
using Result = PresetResolveResult<T>;
Result result;
auto presetPair = presets.find(presetName);
if (presetPair == presets.end()) {
result.StatusCode = Result::Status::NotFound;
result.ErrorPresetName = presetName;
return result;
}
if (presetPair->second.Unexpanded.Hidden) {
result.StatusCode = Result::Status::Hidden;
result.ErrorPresetName = presetName;
return result;
}
if (!presetPair->second.Expanded) {
result.StatusCode = Result::Status::InvalidMacroExpansion;
result.ErrorPresetName = presetName;
return result;
}
if (!presetPair->second.Expanded->ConditionResult) {
result.StatusCode = Result::Status::Disabled;
result.ErrorPresetName = presetName;
return result;
}
result.Preset = &*presetPair->second.Expanded;
return result;
}
// Explicit template instantiations
template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::ConfigurePreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<std::string,
PresetPair<cmCMakePresetsGraph::ConfigurePreset>> const&) const;
template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::BuildPreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<std::string, PresetPair<cmCMakePresetsGraph::BuildPreset>> const&)
const;
template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::TestPreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<std::string, PresetPair<cmCMakePresetsGraph::TestPreset>> const&)
const;
template cmCMakePresetsGraph::PresetResolveResult<
cmCMakePresetsGraph::PackagePreset>
cmCMakePresetsGraph::ResolvePreset(
std::string const&,
std::map<std::string, PresetPair<cmCMakePresetsGraph::PackagePreset>> const&)
const;
template <class T>
cm::optional<std::string> cmCMakePresetsGraph::FormatPresetError(
PresetResolveStatus status, std::string const& errorPresetName,
std::string const& directory)
{
using Status = PresetResolveStatus;
switch (status) {
case Status::NotFound:
return cmStrCat("No such ", T::kind(), " preset in ", directory, ": \"",
errorPresetName, '"');
case Status::Hidden:
return cmStrCat("Cannot use hidden ", T::kind(), " preset in ",
directory, ": \"", errorPresetName, '"');
case Status::InvalidMacroExpansion:
return cmStrCat("Could not evaluate ", T::kind(), " preset \"",
errorPresetName, "\": Invalid macro expansion");
case Status::Disabled:
return cmStrCat("Cannot use disabled ", T::kind(), " preset in ",
directory, ": \"", errorPresetName, '"');
case Status::Success:
return cm::nullopt;
}
assert(false && "Unreachable.");
return cm::nullopt;
}
// Explicit template instantiations for FormatPresetError
template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::ConfigurePreset>(
PresetResolveStatus, std::string const&, std::string const&);
template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::BuildPreset>(
PresetResolveStatus, std::string const&, std::string const&);
template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::TestPreset>(
PresetResolveStatus, std::string const&, std::string const&);
template cm::optional<std::string>
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::PackagePreset>(
PresetResolveStatus, std::string const&, std::string const&);

View File

@@ -1520,35 +1520,18 @@ bool cmCTest::SetArgsFromPreset(std::string const& presetName,
return true;
}
auto presetPair = settingsFile.TestPresets.find(presetName);
if (presetPair == settingsFile.TestPresets.end()) {
cmSystemTools::Error(cmStrCat("No such test preset in ", workingDirectory,
": \"", presetName, '"'));
settingsFile.PrintTestPresetList();
return false;
}
if (presetPair->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden test preset in ",
workingDirectory, ": \"", presetName, '"'));
settingsFile.PrintTestPresetList();
return false;
}
auto const& expandedPreset = presetPair->second.Expanded;
if (!expandedPreset) {
cmSystemTools::Error(cmStrCat("Could not evaluate test preset \"",
presetName, "\": Invalid macro expansion"));
settingsFile.PrintTestPresetList();
return false;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled test preset in ",
workingDirectory, ": \"", presetName, '"'));
auto resolveResult =
settingsFile.ResolvePreset(presetName, settingsFile.TestPresets);
auto resolveError =
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::TestPreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
workingDirectory);
if (resolveError) {
cmSystemTools::Error(*resolveError);
settingsFile.PrintTestPresetList();
return false;
}
auto const* expandedPreset = resolveResult.Preset;
auto configurePresetPair =
settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);

View File

@@ -2035,33 +2035,22 @@ bool cmake::SetArgsFromPreset(std::string const& presetName,
return false;
}
auto preset = presetsGraph.ConfigurePresets.find(presetName);
if (preset == presetsGraph.ConfigurePresets.end()) {
cmSystemTools::Error(cmStrCat("No such preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
this->PrintPresetList(presetsGraph);
return false;
}
if (preset->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
this->PrintPresetList(presetsGraph);
return false;
}
auto const& expandedPreset = preset->second.Expanded;
if (!expandedPreset) {
cmSystemTools::Error(cmStrCat("Could not evaluate preset \"",
preset->second.Unexpanded.Name,
"\": Invalid macro expansion"));
return false;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Could not use disabled preset \"",
preset->second.Unexpanded.Name, '"'));
auto resolveResult =
presetsGraph.ResolvePreset(presetName, presetsGraph.ConfigurePresets);
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
using S = cmCMakePresetsGraph::PresetResolveStatus;
auto resolveError = cmCMakePresetsGraph::FormatPresetError<ConfigurePreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
this->GetHomeDirectory());
if (resolveError) {
cmSystemTools::Error(*resolveError);
if (resolveResult.StatusCode == S::NotFound ||
resolveResult.StatusCode == S::Hidden) {
this->PrintPresetList(presetsGraph);
}
return false;
}
auto const* expandedPreset = resolveResult.Preset;
if (!this->State->IsCacheLoaded() && !haveBinaryDirArg &&
!expandedPreset->BinaryDir.empty()) {
@@ -3926,39 +3915,18 @@ int cmake::Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
return 0;
}
auto presetPair = settingsFile.BuildPresets.find(presetName);
if (presetPair == settingsFile.BuildPresets.end()) {
cmSystemTools::Error(cmStrCat("No such build preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
settingsFile.PrintBuildPresetList();
return 1;
}
if (presetPair->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden build preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
settingsFile.PrintBuildPresetList();
return 1;
}
auto const& expandedPreset = presetPair->second.Expanded;
if (!expandedPreset) {
cmSystemTools::Error(cmStrCat("Could not evaluate build preset \"",
presetName,
"\": Invalid macro expansion"));
settingsFile.PrintBuildPresetList();
return 1;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled build preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
auto resolveResult =
settingsFile.ResolvePreset(presetName, settingsFile.BuildPresets);
auto resolveError =
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::BuildPreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
this->GetHomeDirectory());
if (resolveError) {
cmSystemTools::Error(*resolveError);
settingsFile.PrintBuildPresetList();
return 1;
}
auto const* expandedPreset = resolveResult.Preset;
auto configurePresetPair =
settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);

View File

@@ -1,2 +1,2 @@
^CMake Error: Cannot use hidden preset in [^
^CMake Error: Cannot use hidden configure preset in [^
]*/Tests/RunCMake/CMakePresets/ListPresetsHidden: "ListPresetsHidden"$

View File

@@ -1,2 +1,2 @@
^CMake Error: No such preset in [^
^CMake Error: No such configure preset in [^
]*/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset: "ListPresetsNoSuchPreset"$

View File

@@ -1,2 +1,2 @@
^CMake Error: No such preset in [^
^CMake Error: No such configure preset in [^
]*/Tests/RunCMake/CMakePresets/NoPresets: "NoPresets"$

View File

@@ -1,2 +1,2 @@
^CMake Error: No such preset in [^
^CMake Error: No such configure preset in [^
]*/Tests/RunCMake/CMakePresets/NoSuchPreset: "NoSuchPreset"$

View File

@@ -1 +1,2 @@
^CMake Error: Could not use disabled preset "SimpleFalse"$
^CMake Error: Cannot use disabled configure preset in [^
]*/Tests/RunCMake/CMakePresets/SimpleFalse: "SimpleFalse"$

View File

@@ -1,2 +1,2 @@
^CMake Error: Cannot use hidden preset in [^
^CMake Error: Cannot use hidden configure preset in [^
]*/Tests/RunCMake/CMakePresets/UseHiddenPreset: "UseHiddenPreset"$

View File

@@ -1 +1 @@
^CMake Error: Could not evaluate preset "VendorMacro": Invalid macro expansion$
^CMake Error: Could not evaluate configure preset "VendorMacro": Invalid macro expansion$