presets: Improve error diagnostics

Include the preset type when emitting generic error messages,
which avoids confusion over which preset is presenting problems
(e.g., if you you have a preset called "default" in each of the
configure, build, test, package and workflow preset types).

Include additional information about the specific error encountered
when processing a preset.

Fixes: #27774
This commit is contained in:
Richard
2026-05-01 13:18:42 -04:00
committed by Tyler Yankee
parent c6e81bf30e
commit 654a195d8b
41 changed files with 186 additions and 40 deletions
+14 -6
View File
@@ -80,9 +80,16 @@ void INVALID_PRESET(Json::Value const* value, cmJSONState* state)
state->AddErrorAtValue("Invalid preset", value);
}
void INVALID_PRESET_NAMED(std::string const& presetName, cmJSONState* state)
void INVALID_PRESET_NAMED(std::string const& presetName,
std::string const& kind, cmJSONState* state,
std::string const& detail)
{
state->AddError(cmStrCat("Invalid preset: \"", presetName, '"'));
std::string err_msg =
cmStrCat("Invalid ", kind, " preset: \"", presetName, '"');
if (!detail.empty()) {
err_msg = cmStrCat(err_msg, ": ", detail);
}
state->AddError(err_msg);
}
void INVALID_VARIABLE(Json::Value const* value, cmJSONState* state)
@@ -97,17 +104,18 @@ void DUPLICATE_PRESETS(std::string const& presetName, cmJSONState* state)
}
void CYCLIC_PRESET_INHERITANCE(std::string const& presetName,
cmJSONState* state)
std::string const& kind, cmJSONState* state)
{
state->AddError(
cmStrCat("Cyclic preset inheritance for preset \"", presetName, '"'));
state->AddError(cmStrCat("Cyclic preset inheritance for ", kind,
" preset \"", presetName, '"'));
}
void INHERITED_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName,
std::string const& kind,
cmJSONState* state)
{
state->AddError(cmStrCat("Inherited preset \"", presetName,
state->AddError(cmStrCat("Inherited ", kind, " preset \"", presetName,
"\" is unreachable from preset's file"));
}
+5 -2
View File
@@ -35,16 +35,19 @@ void INVALID_PRESETS(Json::Value const* value, cmJSONState* state);
void INVALID_PRESET(Json::Value const* value, cmJSONState* state);
void INVALID_PRESET_NAMED(std::string const& presetName, cmJSONState* state);
void INVALID_PRESET_NAMED(std::string const& presetName,
std::string const& kind, cmJSONState* state,
std::string const& detail);
void INVALID_VARIABLE(Json::Value const* value, cmJSONState* state);
void DUPLICATE_PRESETS(std::string const& presetName, cmJSONState* state);
void CYCLIC_PRESET_INHERITANCE(std::string const& presetName,
cmJSONState* state);
std::string const& kind, cmJSONState* state);
void INHERITED_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName,
std::string const& kind,
cmJSONState* state);
void CONFIGURE_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName,
+41 -17
View File
@@ -109,8 +109,8 @@ bool VisitPreset(
{
switch (cycleStatus[preset.Name]) {
case CycleStatus::InProgress:
cmCMakePresetsErrors::CYCLIC_PRESET_INHERITANCE(preset.Name,
&graph.parseState);
cmCMakePresetsErrors::CYCLIC_PRESET_INHERITANCE(
preset.Name, preset.kind(), &graph.parseState);
return false;
case CycleStatus::Verified:
return true;
@@ -121,28 +121,32 @@ bool VisitPreset(
cycleStatus[preset.Name] = CycleStatus::InProgress;
if (preset.Environment.count("") != 0) {
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name, &graph.parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph.parseState,
"Empty environment variable names are not allowed");
return false;
}
bool result = preset.VisitPresetBeforeInherit();
if (!result) {
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name, &graph.parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph.parseState, preset.ErrorDetail);
return false;
}
for (auto const& i : preset.Inherits) {
auto parent = presets.find(i);
if (parent == presets.end()) {
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
&graph.parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph.parseState,
cmStrCat("Could not find inherited preset \"", i, "\""));
return false;
}
auto& parentPreset = parent->second.Unexpanded;
if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) {
cmCMakePresetsErrors::INHERITED_PRESET_UNREACHABLE_FROM_FILE(
preset.Name, &graph.parseState);
preset.Name, preset.kind(), &graph.parseState);
return false;
}
@@ -152,8 +156,8 @@ bool VisitPreset(
result = preset.VisitPresetInherit(parentPreset);
if (!result) {
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
&graph.parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph.parseState, preset.ErrorDetail);
return false;
}
@@ -171,7 +175,8 @@ bool VisitPreset(
result = preset.VisitPresetAfterInherit(graph.GetVersion(preset),
&graph.parseState);
if (!result) {
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name, &graph.parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph.parseState, preset.ErrorDetail);
return false;
}
@@ -453,8 +458,9 @@ bool ExpandMacros(cmCMakePresetsGraph* graph, T const& preset,
switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
graph->GetVersion(preset))) {
case ExpandMacroResult::Error:
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
&graph->parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph->parseState,
"Invalid macro expansion");
return false;
case ExpandMacroResult::Ignore:
out.reset();
@@ -471,8 +477,8 @@ bool ExpandMacros(cmCMakePresetsGraph* graph, T const& preset,
cm::optional<bool> result;
if (!preset.ConditionEvaluator->Evaluate(
macroExpanders, graph->GetVersion(preset), result)) {
cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
&graph->parseState);
cmCMakePresetsErrors::INVALID_PRESET_NAMED(
preset.Name, preset.kind(), &graph->parseState, "Invalid condition");
return false;
}
if (!result) {
@@ -911,6 +917,8 @@ bool cmCMakePresetsGraph::ConfigurePreset::VisitPresetBeforeInherit()
{
auto& preset = *this;
if (preset.Environment.count("") != 0) {
this->ErrorDetail =
"Empty environment variable names are not allowed in configure presets";
return false;
}
@@ -945,6 +953,7 @@ bool cmCMakePresetsGraph::ConfigurePreset::VisitPresetAfterInherit(
}
if (preset.CacheVariables.count("") != 0) {
this->ErrorDetail = "Empty cache variable names are not allowed";
return false;
}
}
@@ -977,7 +986,12 @@ bool cmCMakePresetsGraph::BuildPreset::VisitPresetInherit(
bool cmCMakePresetsGraph::BuildPreset::VisitPresetAfterInherit(
int /* version */, cmJSONState* /*stat*/)
{
return this->Hidden || !this->ConfigurePreset.empty();
if (!this->Hidden && this->ConfigurePreset.empty()) {
this->ErrorDetail = "Build presets must either be hidden or have an "
"associated configure preset";
return false;
}
return true;
}
bool cmCMakePresetsGraph::TestPreset::VisitPresetInherit(
@@ -1087,7 +1101,12 @@ bool cmCMakePresetsGraph::TestPreset::VisitPresetInherit(
bool cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(
int /* version */, cmJSONState* /*state*/)
{
return this->Hidden || !this->ConfigurePreset.empty();
if (!this->Hidden && this->ConfigurePreset.empty()) {
this->ErrorDetail = "Test presets must either be hidden or have an "
"associated configure preset";
return false;
}
return true;
}
bool cmCMakePresetsGraph::PackagePreset::VisitPresetInherit(
@@ -1116,7 +1135,12 @@ bool cmCMakePresetsGraph::PackagePreset::VisitPresetInherit(
bool cmCMakePresetsGraph::PackagePreset::VisitPresetAfterInherit(
int /* version */, cmJSONState* /*state*/)
{
return this->Hidden || !this->ConfigurePreset.empty();
if (!this->Hidden && this->ConfigurePreset.empty()) {
this->ErrorDetail = "Package presets must either be hidden or have an "
"associated configure preset";
return false;
}
return true;
}
bool cmCMakePresetsGraph::WorkflowPreset::VisitPresetInherit(
+2
View File
@@ -84,6 +84,8 @@ public:
std::map<std::string, cm::optional<std::string>> Environment;
std::string ErrorDetail;
virtual bool VisitPresetInherit(Preset const& parent) = 0;
virtual bool VisitPresetBeforeInherit() { return true; }
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey:
Invalid build preset: "EmptyEnvKey": Empty environment variable names are not allowed$
@@ -0,0 +1,11 @@
{
"version": 2,
"buildPresets": [
{
"name": "EmptyEnvKey",
"environment": {
"": "value"
}
}
]
}
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/BuildInvalidInheritance:
Invalid build preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
@@ -0,0 +1,11 @@
{
"version": 2,
"buildPresets": [
{
"name": "InvalidInheritance",
"inherits": [
"NoExist"
]
}
]
}
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/CyclicInheritance0:
Cyclic preset inheritance for preset "CyclicInheritance0"$
Cyclic preset inheritance for configure preset "CyclicInheritance0"$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/CyclicInheritance1:
Cyclic preset inheritance for preset "CyclicInheritance0"$
Cyclic preset inheritance for configure preset "CyclicInheritance0"$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/CyclicInheritance2:
Cyclic preset inheritance for preset "CyclicInheritance0"$
Cyclic preset inheritance for configure preset "CyclicInheritance0"$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/EmptyCacheKey:
Invalid preset: "EmptyCacheKey"$
Invalid configure preset: "EmptyCacheKey": Empty cache variable names are not allowed$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/EmptyEnvKey:
Invalid preset: "EmptyEnvKey"$
Invalid configure preset: "EmptyEnvKey": Empty environment variable names are not allowed$
@@ -1,4 +1,4 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/EnvCycle:
Invalid preset: "EnvCycle"
Invalid configure preset: "EnvCycle": Invalid macro expansion
Invalid macro expansion in "EnvCycle"$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated:
Invalid preset: "ErrorNoWarningDeprecated"$
Invalid configure preset: "ErrorNoWarningDeprecated"$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/ErrorNoWarningDev:
Invalid preset: "ErrorNoWarningDev"$
Invalid configure preset: "ErrorNoWarningDev"$
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/InvalidInheritance:
Invalid preset: "InvalidInheritance"$
Invalid configure preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
@@ -1,4 +1,4 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/InvalidRegex:
Invalid preset: "InvalidRegex"
Invalid configure preset: "InvalidRegex": Invalid condition
Invalid macro expansion in "InvalidRegex"$
@@ -1,4 +1,4 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/NoPresetBinaryDir:
Preset "NoPresetBinaryDir" missing field "binaryDir"
Invalid preset: "NoPresetBinaryDir"$
Invalid configure preset: "NoPresetBinaryDir"$
@@ -1,4 +1,4 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/NoPresetGenerator:
Preset "NoPresetGenerator" missing field "generator"
Invalid preset: "NoPresetGenerator"$
Invalid configure preset: "NoPresetGenerator"$
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey:
Invalid package preset: "EmptyEnvKey": Empty environment variable names are not allowed$
@@ -0,0 +1,11 @@
{
"version": 6,
"packagePresets": [
{
"name": "EmptyEnvKey",
"environment": {
"": "value"
}
}
]
}
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/PackageInvalidInheritance:
Invalid package preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
@@ -0,0 +1,11 @@
{
"version": 6,
"packagePresets": [
{
"name": "InvalidInheritance",
"inherits": [
"NoExist"
]
}
]
}
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset:
Invalid package preset: "noConfigurePreset": Package presets must either be hidden or have an associated configure preset$
@@ -0,0 +1,8 @@
{
"version": 6,
"packagePresets": [
{
"name": "noConfigurePreset"
}
]
}
@@ -181,6 +181,10 @@ run_cmake_presets(CyclicInheritance0)
run_cmake_presets(CyclicInheritance1)
run_cmake_presets(CyclicInheritance2)
run_cmake_presets(InvalidInheritance)
run_cmake_presets(BuildInvalidInheritance)
run_cmake_presets(PackageInvalidInheritance)
run_cmake_presets(TestInvalidInheritance)
run_cmake_presets(PackageNoConfigurePreset)
run_cmake_presets(ErrorNoWarningDev)
run_cmake_presets(ErrorNoWarningDeprecated)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
@@ -190,6 +194,9 @@ run_cmake_presets(InvalidToolsetStrategy)
run_cmake_presets(UnknownToolsetStrategy)
run_cmake_presets(EmptyCacheKey)
run_cmake_presets(EmptyEnvKey)
run_cmake_presets(BuildEmptyEnvKey)
run_cmake_presets(PackageEmptyEnvKey)
run_cmake_presets(TestEmptyEnvKey)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
run_cmake_presets(UnclosedMacro)
run_cmake_presets(NoSuchMacro)
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/TestEmptyEnvKey:
Invalid test preset: "EmptyEnvKey": Empty environment variable names are not allowed$
@@ -0,0 +1,11 @@
{
"version": 2,
"testPresets": [
{
"name": "EmptyEnvKey",
"environment": {
"": "value"
}
}
]
}
@@ -0,0 +1 @@
1
@@ -0,0 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/TestInvalidInheritance:
Invalid test preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
@@ -0,0 +1,11 @@
{
"version": 2,
"testPresets": [
{
"name": "InvalidInheritance",
"inherits": [
"NoExist"
]
}
]
}
@@ -1,3 +1,3 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresets/UserInheritance:
Inherited preset "UserInheritance" is unreachable from preset's file$
Inherited configure preset "UserInheritance" is unreachable from preset's file$
@@ -1,3 +1,3 @@
CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset:
Invalid preset: "noConfigurePreset"$
Invalid build preset: "noConfigurePreset": Build presets must either be hidden or have an associated configure preset$
@@ -1,3 +1,3 @@
CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset:
Invalid preset: "noConfigurePreset"$
Invalid test preset: "noConfigurePreset": Test presets must either be hidden or have an associated configure preset$