presets: Factor out command line arguments

Create a separate hierarchy of classes to manage command-line arguments
for CMake presets to facilitate shared definitions across our programs.
This commit is contained in:
Tyler Yankee
2026-04-30 07:49:43 -04:00
parent e75b62fd73
commit 81c22a67b6
8 changed files with 186 additions and 123 deletions
+1
View File
@@ -125,6 +125,7 @@ add_library(
cmCLocaleEnvironmentScope.cxx
cmCMakePath.h
cmCMakePath.cxx
cmCMakePresetsArgs.h
cmCMakePresetsErrors.cxx
cmCMakePresetsErrors.h
cmCMakePresetsGraph.cxx
+8 -8
View File
@@ -19,6 +19,7 @@
#include "cmsys/Encoding.hxx"
#include "cmCMakePresetsArgs.h"
#include "cmCMakePresetsGraph.h"
#include "cmCPackGenerator.h"
#include "cmCPackGeneratorFactory.h"
@@ -130,8 +131,7 @@ int main(int argc, char const* const* argv)
std::string cpackProjectVendor;
std::string cpackConfigFile;
std::string preset;
bool listPresets = false;
cmCMakePresetsArgs presetsArgs;
std::map<std::string, std::string> definitions;
@@ -201,9 +201,9 @@ int main(int argc, char const* const* argv)
CommandArgument::setToValue(cpackProjectVendor) },
CommandArgument{ "--preset", "No preset specified for --preset",
CommandArgument::Values::One,
CommandArgument::setToValue(preset) },
CommandArgument::setToValue(presetsArgs.PresetName) },
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
CommandArgument::setToTrue(listPresets) },
CommandArgument::setToTrue(presetsArgs.ListPresets) },
CommandArgument{ "-D", CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
[&log, &definitions](std::string const& arg, cmake*,
@@ -249,7 +249,7 @@ int main(int argc, char const* const* argv)
generators.SetLogger(&log);
// Set up presets
if (!preset.empty() || listPresets) {
if (presetsArgs.HasPresetsArg()) {
auto const workingDirectory = cmSystemTools::GetLogicalWorkingDirectory();
auto const presetGeneratorsPresent =
@@ -271,13 +271,13 @@ int main(int argc, char const* const* argv)
return 1;
}
if (listPresets) {
if (presetsArgs.ListPresets) {
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 0;
}
auto resolveResult =
presetsGraph.ResolvePreset(preset, presetsGraph.PackagePresets);
auto resolveResult = presetsGraph.ResolvePreset(
presetsArgs.PresetName, presetsGraph.PackagePresets);
auto resolveError = cmCMakePresetsGraph::FormatPresetError<
cmCMakePresetsGraph::PackagePreset>(resolveResult.StatusCode,
resolveResult.ErrorPresetName,
+77
View File
@@ -0,0 +1,77 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#include <string>
class cmCMakePresetsArgsBase
{
public:
virtual ~cmCMakePresetsArgsBase() = default;
virtual bool HasPresetsArg() const { return !this->PresetName.empty(); };
virtual void Clear() { this->PresetName.clear(); }
std::string PresetName;
protected:
cmCMakePresetsArgsBase() = default;
};
class cmCMakePresetsArgs : public cmCMakePresetsArgsBase
{
public:
bool HasPresetsArg() const override
{
return this->cmCMakePresetsArgsBase::HasPresetsArg() || this->ListPresets;
}
void Clear() override
{
this->cmCMakePresetsArgsBase::Clear();
this->ListPresets = false;
}
bool ListPresets = false;
};
class cmCMakePresetsConfigureArgs : public cmCMakePresetsArgsBase
{
public:
enum class ListPresetsOption
{
None,
Configure,
Build,
Test,
Package,
Workflow,
All,
};
bool HasPresetsArg() const override
{
return this->cmCMakePresetsArgsBase::HasPresetsArg() ||
this->ListPresets != ListPresetsOption::None;
}
void Clear() override
{
this->cmCMakePresetsArgsBase::Clear();
this->ListPresets = ListPresetsOption::None;
}
ListPresetsOption ListPresets = ListPresetsOption::None;
};
class cmCMakePresetsWorkflowArgs : public cmCMakePresetsArgs
{
public:
void Clear() override
{
this->cmCMakePresetsArgs::Clear();
this->Fresh = false;
}
bool Fresh = false;
};
+12 -13
View File
@@ -42,6 +42,7 @@
#include "cm_parse_date.h"
#include "cmCMakePresetsArgs.h"
#include "cmCMakePresetsGraph.h"
#include "cmCTestBuildAndTest.h"
#include "cmCTestScriptHandler.h"
@@ -1501,8 +1502,7 @@ bool cmCTest::AddVariableDefinition(std::string const& arg)
return false;
}
bool cmCTest::SetArgsFromPreset(std::string const& presetName,
bool listPresets)
bool cmCTest::SetArgsFromPreset(cmCMakePresetsArgs const& args)
{
auto const workingDirectory = cmSystemTools::GetLogicalWorkingDirectory();
@@ -1515,13 +1515,13 @@ bool cmCTest::SetArgsFromPreset(std::string const& presetName,
return false;
}
if (listPresets) {
if (args.ListPresets) {
settingsFile.PrintTestPresetList();
return true;
}
auto resolveResult =
settingsFile.ResolvePreset(presetName, settingsFile.TestPresets);
settingsFile.ResolvePreset(args.PresetName, settingsFile.TestPresets);
auto resolveError =
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::TestPreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
@@ -1801,8 +1801,7 @@ int cmCTest::Run(std::vector<std::string> const& args)
bool processSteps = false;
bool SRArgumentSpecified = false;
std::vector<std::pair<std::string, bool>> runScripts;
bool listPresets = false;
std::string presetName;
cmCMakePresetsArgs presetsArgs;
// copy the command line
cm::append(this->Impl->InitialCommandLineArguments, args);
@@ -1990,14 +1989,14 @@ int cmCTest::Run(std::vector<std::string> const& args)
auto const presetArguments = std::vector<CommandArgument>{
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
[&listPresets](std::string const&) -> bool {
listPresets = true;
[&presetsArgs](std::string const&) -> bool {
presetsArgs.ListPresets = true;
return true;
} },
CommandArgument{ "--preset", "'--preset' requires an argument",
CommandArgument::Values::One,
[&presetName](std::string const& presetArg) -> bool {
presetName = presetArg;
[&presetsArgs](std::string const& presetArg) -> bool {
presetsArgs.PresetName = presetArg;
return true;
} }
};
@@ -2490,9 +2489,9 @@ int cmCTest::Run(std::vector<std::string> const& args)
}
}
if (listPresets || !presetName.empty()) {
bool success = this->SetArgsFromPreset(presetName, listPresets);
if (listPresets) {
if (presetsArgs.HasPresetsArg()) {
bool success = this->SetArgsFromPreset(presetsArgs);
if (presetsArgs.ListPresets) {
return static_cast<int>(!success);
}
if (!success) {
+2 -1
View File
@@ -20,6 +20,7 @@
#include "cmProcessOutput.h"
class cmake;
class cmCMakePresetsArgs;
class cmGeneratedFileStream;
class cmInstrumentation;
class cmMakefile;
@@ -452,7 +453,7 @@ private:
bool AddVariableDefinition(std::string const& arg);
/** set command line arguments read from a test preset */
bool SetArgsFromPreset(std::string const& presetName, bool listPresets);
bool SetArgsFromPreset(cmCMakePresetsArgs const& args);
/** returns true iff the console supports progress output */
static bool ProgressOutputSupportedByConsole();
+64 -50
View File
@@ -86,6 +86,7 @@
# include <cm3p/curl/curl.h>
# include <cm3p/json/writer.h>
# include "cmCMakePresetsArgs.h"
# include "cmConfigureLog.h"
# include "cmFileAPI.h"
# include "cmGraphVizWriter.h"
@@ -1014,9 +1015,9 @@ void cmake::SetArgs(std::vector<std::string> const& args)
#if !defined(CMAKE_BOOTSTRAP)
std::string profilingFormat;
std::string profilingOutput;
std::string presetName;
ListPresets listPresets = ListPresets::None;
cmCMakePresetsConfigureArgs presetsArgs;
using ListPresets = cmCMakePresetsConfigureArgs::ListPresetsOption;
#endif
auto EmptyStringArgLambda = [](std::string const&, cmake* state) -> bool {
@@ -1429,24 +1430,24 @@ void cmake::SetArgs(std::vector<std::string> const& args)
arguments.emplace_back("--preset", "No preset specified for --preset",
CommandArgument::Values::One,
[&](std::string const& value, cmake*) -> bool {
presetName = value;
presetsArgs.PresetName = value;
return true;
});
arguments.emplace_back(
"--list-presets", CommandArgument::Values::ZeroOrOne,
[&](std::string const& value, cmake*) -> bool {
if (value.empty() || value == "configure") {
listPresets = ListPresets::Configure;
presetsArgs.ListPresets = ListPresets::Configure;
} else if (value == "build") {
listPresets = ListPresets::Build;
presetsArgs.ListPresets = ListPresets::Build;
} else if (value == "test") {
listPresets = ListPresets::Test;
presetsArgs.ListPresets = ListPresets::Test;
} else if (value == "package") {
listPresets = ListPresets::Package;
presetsArgs.ListPresets = ListPresets::Package;
} else if (value == "workflow") {
listPresets = ListPresets::Workflow;
presetsArgs.ListPresets = ListPresets::Workflow;
} else if (value == "all") {
listPresets = ListPresets::All;
presetsArgs.ListPresets = ListPresets::All;
} else {
cmSystemTools::Error(
"Invalid value specified for --list-presets.\n"
@@ -1573,7 +1574,7 @@ void cmake::SetArgs(std::vector<std::string> const& args)
#ifdef CMAKE_BOOTSTRAP
false;
#else
!presetName.empty();
!presetsArgs.PresetName.empty();
#endif
if (this->State->GetRole() == cmState::Role::Project && !haveSourceDir &&
@@ -1593,8 +1594,8 @@ void cmake::SetArgs(std::vector<std::string> const& args)
}
#if !defined(CMAKE_BOOTSTRAP)
if (listPresets != ListPresets::None || !presetName.empty()) {
this->SetArgsFromPreset(presetName, listPresets, haveBArg);
if (presetsArgs.HasPresetsArg()) {
this->SetArgsFromPreset(presetsArgs, haveBArg);
}
#endif
}
@@ -2009,9 +2010,11 @@ bool cmake::CreateAndSetGlobalGenerator(std::string const& name)
}
#ifndef CMAKE_BOOTSTRAP
bool cmake::SetArgsFromPreset(std::string const& presetName,
ListPresets listPresets, bool haveBinaryDirArg)
bool cmake::SetArgsFromPreset(cmCMakePresetsConfigureArgs const& args,
bool haveBinaryDirArg)
{
using ListPresets = cmCMakePresetsConfigureArgs::ListPresetsOption;
cmCMakePresetsGraph presetsGraph;
auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory());
if (result != true) {
@@ -2022,19 +2025,28 @@ bool cmake::SetArgsFromPreset(std::string const& presetName,
return false;
}
if (listPresets != ListPresets::None) {
if (listPresets == ListPresets::Configure) {
this->PrintPresetList(presetsGraph);
} else if (listPresets == ListPresets::Build) {
presetsGraph.PrintBuildPresetList();
} else if (listPresets == ListPresets::Test) {
presetsGraph.PrintTestPresetList();
} else if (listPresets == ListPresets::Package) {
presetsGraph.PrintPackagePresetList();
} else if (listPresets == ListPresets::Workflow) {
presetsGraph.PrintWorkflowPresetList();
} else if (listPresets == ListPresets::All) {
presetsGraph.PrintAllPresets();
if (args.ListPresets != ListPresets::None) {
switch (args.ListPresets) {
case ListPresets::Configure:
this->PrintPresetList(presetsGraph);
break;
case ListPresets::Build:
presetsGraph.PrintBuildPresetList();
break;
case ListPresets::Test:
presetsGraph.PrintTestPresetList();
break;
case ListPresets::Package:
presetsGraph.PrintPackagePresetList();
break;
case ListPresets::Workflow:
presetsGraph.PrintWorkflowPresetList();
break;
case ListPresets::All:
presetsGraph.PrintAllPresets();
break;
default:
break;
}
this->State->SetRoleToHelpForListPresets();
@@ -2042,7 +2054,7 @@ bool cmake::SetArgsFromPreset(std::string const& presetName,
}
auto resolveResult =
presetsGraph.ResolvePreset(presetName, presetsGraph.ConfigurePresets);
presetsGraph.ResolvePreset(args.PresetName, presetsGraph.ConfigurePresets);
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
using S = cmCMakePresetsGraph::PresetResolveStatus;
auto resolveError = cmCMakePresetsGraph::FormatPresetError<ConfigurePreset>(
@@ -3897,13 +3909,14 @@ std::vector<std::string> cmake::GetDebugConfigs()
int cmake::Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
std::vector<std::string> nativeOptions,
cmBuildOptions& buildOptions, std::string const& presetName,
bool listPresets, std::vector<std::string> const& args)
cmBuildOptions& buildOptions,
cmCMakePresetsArgs const& presetsArgs,
std::vector<std::string> const& args)
{
buildArgs.timeout = cmDuration::zero();
#if !defined(CMAKE_BOOTSTRAP)
if (!presetName.empty() || listPresets) {
if (presetsArgs.HasPresetsArg()) {
// If the binary directory was specified, use it to find
// the source directory so we can locate the presets file.
if (!buildArgs.binaryDir.empty() &&
@@ -3924,13 +3937,13 @@ int cmake::Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
return 1;
}
if (listPresets) {
if (presetsArgs.ListPresets) {
settingsFile.PrintBuildPresetList();
return 0;
}
auto resolveResult =
settingsFile.ResolvePreset(presetName, settingsFile.BuildPresets);
auto resolveResult = settingsFile.ResolvePreset(presetsArgs.PresetName,
settingsFile.BuildPresets);
auto resolveError =
cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::BuildPreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
@@ -4261,8 +4274,7 @@ std::function<cmUVProcessChain::Status()> buildWorkflowStep(
}
#endif
int cmake::Workflow(std::string const& presetName,
WorkflowListPresets listPresets, WorkflowFresh fresh)
int cmake::Workflow(cmCMakePresetsWorkflowArgs const& args)
{
int exitStatus = 0;
#ifndef CMAKE_BOOTSTRAP
@@ -4278,24 +4290,24 @@ int cmake::Workflow(std::string const& presetName,
return 1;
}
if (listPresets == WorkflowListPresets::Yes) {
if (args.ListPresets) {
settingsFile.PrintWorkflowPresetList();
return 0;
}
auto presetPair = settingsFile.WorkflowPresets.find(presetName);
auto presetPair = settingsFile.WorkflowPresets.find(args.PresetName);
if (presetPair == settingsFile.WorkflowPresets.end()) {
cmSystemTools::Error(cmStrCat("No such workflow preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
this->GetHomeDirectory(), ": \"",
args.PresetName, '"'));
settingsFile.PrintWorkflowPresetList();
return 1;
}
if (presetPair->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden workflow preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
this->GetHomeDirectory(), ": \"",
args.PresetName, '"'));
settingsFile.PrintWorkflowPresetList();
return 1;
}
@@ -4303,15 +4315,16 @@ int cmake::Workflow(std::string const& presetName,
auto const& expandedPreset = presetPair->second.Expanded;
if (!expandedPreset) {
cmSystemTools::Error(cmStrCat("Could not evaluate workflow preset \"",
presetName, "\": Invalid macro expansion"));
args.PresetName,
"\": Invalid macro expansion"));
settingsFile.PrintWorkflowPresetList();
return 1;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled workflow preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
this->GetHomeDirectory(), ": \"",
args.PresetName, '"'));
settingsFile.PrintWorkflowPresetList();
return 1;
}
@@ -4347,13 +4360,14 @@ int cmake::Workflow(std::string const& presetName,
if (!configurePreset) {
return 1;
}
std::vector<std::string> args{ cmSystemTools::GetCMakeCommand(),
"--preset", step.PresetName };
if (fresh == WorkflowFresh::Yes) {
args.emplace_back("--fresh");
std::vector<std::string> configureCmdArgs{
cmSystemTools::GetCMakeCommand(), "--preset", step.PresetName
};
if (args.Fresh) {
configureCmdArgs.emplace_back("--fresh");
}
steps.emplace_back(stepNumber, "configure"_s, step.PresetName,
buildWorkflowStep(args));
buildWorkflowStep(configureCmdArgs));
} break;
case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Build: {
auto const* buildPreset = this->FindPresetForWorkflow(
+9 -27
View File
@@ -48,6 +48,9 @@ class cmDebuggerAdapter;
#endif
class cmExternalMakefileProjectGeneratorFactory;
class cmCMakePresetsArgs;
class cmCMakePresetsConfigureArgs;
class cmCMakePresetsWorkflowArgs;
class cmFileAPI;
class cmInstrumentation;
class cmFileTimeCache;
@@ -254,19 +257,8 @@ public:
bool CreateAndSetGlobalGenerator(std::string const& name);
#ifndef CMAKE_BOOTSTRAP
enum class ListPresets
{
None,
Configure,
Build,
Test,
Package,
Workflow,
All,
};
bool SetArgsFromPreset(std::string const& presetName,
ListPresets listPresets, bool haveBinaryDirArg);
bool SetArgsFromPreset(cmCMakePresetsConfigureArgs const& args,
bool haveBinaryDirArg);
void PrintPresetList(cmCMakePresetsGraph const& graph) const;
#endif
@@ -627,8 +619,9 @@ public:
//! run the --build option
int Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
std::vector<std::string> nativeOptions,
cmBuildOptions& buildOptions, std::string const& presetName,
bool listPresets, std::vector<std::string> const& args);
cmBuildOptions& buildOptions,
cmCMakePresetsArgs const& presetsArgs,
std::vector<std::string> const& args);
enum class DryRun
{
@@ -640,18 +633,7 @@ public:
bool Open(std::string const& dir, DryRun dryRun);
//! run the --workflow option
enum class WorkflowListPresets
{
No,
Yes,
};
enum class WorkflowFresh
{
No,
Yes,
};
int Workflow(std::string const& presetName, WorkflowListPresets listPresets,
WorkflowFresh fresh);
int Workflow(cmCMakePresetsWorkflowArgs const& args);
void UnwatchUnusedCli(std::string const& var);
void WatchUnusedCli(std::string const& var);
+13 -24
View File
@@ -44,6 +44,7 @@
#include "cmcmd.h"
#ifndef CMAKE_BOOTSTRAP
# include "cmCMakePresetsArgs.h"
# include "cmDocumentation.h"
#endif
@@ -474,8 +475,7 @@ int do_build(int ac, char const* const* av)
bool foundNonClean = false;
PackageResolveMode resolveMode = PackageResolveMode::Default;
buildArgs.verbose = cmSystemTools::HasEnv("VERBOSE");
std::string presetName;
bool listPresets = false;
cmCMakePresetsArgs presetsArgs;
auto jLambda = extract_job_number_lambda_builder(buildArgs.binaryDir,
buildArgs.jobs, "-j");
@@ -523,9 +523,9 @@ int do_build(int ac, char const* const* av)
std::vector<CommandArgument> arguments = {
CommandArgument{ "--preset", "No preset specified for --preset",
CommandArgument::Values::One,
CommandArgument::setToValue(presetName) },
CommandArgument::setToValue(presetsArgs.PresetName) },
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
CommandArgument::setToTrue(listPresets) },
CommandArgument::setToTrue(presetsArgs.ListPresets) },
CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne,
CommandArgument::RequiresSeparator::No, jLambda },
CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
@@ -622,7 +622,7 @@ int do_build(int ac, char const* const* av)
}
}
if (buildArgs.binaryDir.empty() && presetName.empty() && !listPresets) {
if (buildArgs.binaryDir.empty() && !presetsArgs.HasPresetsArg()) {
/* clang-format off */
std::cerr <<
"Usage: cmake --build <dir> "
@@ -672,7 +672,7 @@ int do_build(int ac, char const* const* av)
std::vector<std::string> cmd;
cm::append(cmd, av, av + ac);
return cm.Build(buildArgs, std::move(targets), std::move(nativeOptions),
buildOptions, presetName, listPresets, cmd);
buildOptions, presetsArgs, cmd);
#endif
}
@@ -980,11 +980,7 @@ int do_workflow(int ac, char const* const* av)
std::cerr << "This cmake does not support --workflow\n";
return -1;
#else
using WorkflowListPresets = cmake::WorkflowListPresets;
using WorkflowFresh = cmake::WorkflowFresh;
std::string presetName;
auto listPresets = WorkflowListPresets::No;
auto fresh = WorkflowFresh::No;
cmCMakePresetsWorkflowArgs presetsArgs;
using CommandArgument =
cmCommandLineArgument<bool(std::string const& value)>;
@@ -992,17 +988,11 @@ int do_workflow(int ac, char const* const* av)
std::vector<CommandArgument> arguments = {
CommandArgument{ "--preset", "No preset specified for --preset",
CommandArgument::Values::One,
CommandArgument::setToValue(presetName) },
CommandArgument::setToValue(presetsArgs.PresetName) },
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
[&listPresets](std::string const&) -> bool {
listPresets = WorkflowListPresets::Yes;
return true;
} },
CommandArgument::setToTrue(presetsArgs.ListPresets) },
CommandArgument{ "--fresh", CommandArgument::Values::Zero,
[&fresh](std::string const&) -> bool {
fresh = WorkflowFresh::Yes;
return true;
} },
CommandArgument::setToTrue(presetsArgs.Fresh) }
};
std::vector<std::string> inputArgs;
@@ -1029,15 +1019,14 @@ int do_workflow(int ac, char const* const* av)
}
if (!(matched && parsed)) {
if (!matched) {
presetName.clear();
listPresets = WorkflowListPresets::No;
presetsArgs.Clear();
std::cerr << "Unknown argument " << arg << std::endl;
}
break;
}
}
if (presetName.empty() && listPresets == WorkflowListPresets::No) {
if (!presetsArgs.HasPresetsArg()) {
/* clang-format off */
std::cerr <<
"Usage: cmake --workflow <options>\n"
@@ -1060,7 +1049,7 @@ int do_workflow(int ac, char const* const* av)
cmakemainProgressCallback(msg, prog, &cm);
});
return cm.Workflow(presetName, listPresets, fresh);
return cm.Workflow(presetsArgs);
#endif
}