Files
cmake/Source/cmCMakePresetsGraph.h
T
Tyler Yankee 95edd93948 presets: Support loading from arbitrary file
Allow CMake, CTest, and CPack to read presets from a path given by
command-line argument instead of always requiring `CMakePresets.json`
or `CMakeUserPresets.json` in the source tree. This makes the presets
feature more extensible to cases in which the user doesn't have access
to the presets defined in the source tree (e.g., if the source tree is
not writable).

For now, there is no equivalent implementation of such an option in the
`cmake-gui`, nor for the recent presets functionality implemented in
`ctest_configure` and `ctest_build`.

Fixes: #27329
2026-04-30 08:04:26 -04:00

557 lines
16 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
#include <cm/optional>
#include "cmDiagnostics.h"
#include "cmJSONState.h"
#include "cmStateTypes.h" // IWYU pragma: keep
#include "CTest/cmCTestTypes.h" // IWYU pragma: keep
enum class PackageResolveMode;
class cmCMakePresetsGraph
{
public:
std::string errors;
cmJSONState parseState;
enum class ArchToolsetStrategy
{
Set,
External,
};
enum class TraceEnableMode
{
Disable,
Default,
Expand,
};
struct CacheVariable
{
std::string Type;
std::string Value;
};
class Condition;
struct File
{
std::unordered_set<File*> ReachableFiles;
std::string Filename;
int Version;
};
class Preset
{
public:
Preset() = default;
Preset(Preset&& /*other*/) = default;
Preset(Preset const& /*other*/) = default;
Preset& operator=(Preset const& /*other*/) = default;
virtual ~Preset() = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
Preset& operator=(Preset&& /*other*/) = default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
Preset& operator=(Preset&& /*other*/) = delete;
#endif
std::string Name;
std::vector<std::string> Inherits;
bool Hidden = false;
File* OriginFile;
std::string DisplayName;
std::string Description;
std::shared_ptr<Condition> ConditionEvaluator;
bool ConditionResult = true;
std::map<std::string, cm::optional<std::string>> Environment;
virtual bool VisitPresetInherit(Preset const& parent) = 0;
virtual bool VisitPresetBeforeInherit() { return true; }
virtual bool VisitPresetAfterInherit(int /* version */,
cmJSONState* /*state*/)
{
return true;
}
};
class ConfigurePreset : public Preset
{
public:
ConfigurePreset() = default;
ConfigurePreset(ConfigurePreset&& /*other*/) = default;
ConfigurePreset(ConfigurePreset const& /*other*/) = default;
ConfigurePreset& operator=(ConfigurePreset const& /*other*/) = default;
~ConfigurePreset() override = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = delete;
#endif
std::string Generator;
std::string Architecture;
cm::optional<ArchToolsetStrategy> ArchitectureStrategy;
std::string Toolset;
cm::optional<ArchToolsetStrategy> ToolsetStrategy;
std::string ToolchainFile;
std::string GraphVizFile;
std::string BinaryDir;
std::string InstallDir;
std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
std::map<cmDiagnosticCategory, bool> Warnings;
std::map<cmDiagnosticCategory, bool> Errors;
cm::optional<bool> WarnSystemVars;
cm::optional<bool> WarnDev; // Deprecated synonym for Warnings.CMD_AUTHOR
cm::optional<bool> ErrorDev; // Deprecated synonym for Errors.CMD_AUTHOR
cm::optional<bool> DebugOutput;
cm::optional<bool> DebugTryCompile;
cm::optional<bool> DebugFind;
cm::optional<TraceEnableMode> TraceMode;
cm::optional<cmTraceEnums::TraceOutputFormat> TraceFormat;
std::vector<std::string> TraceSource;
std::string TraceRedirect;
bool VisitPresetInherit(Preset const& parent) override;
bool VisitPresetBeforeInherit() override;
bool VisitPresetAfterInherit(int version, cmJSONState* state) override;
static char const* kind() { return "configure"; }
};
class BuildPreset : public Preset
{
public:
BuildPreset() = default;
BuildPreset(BuildPreset&& /*other*/) = default;
BuildPreset(BuildPreset const& /*other*/) = default;
BuildPreset& operator=(BuildPreset const& /*other*/) = default;
~BuildPreset() override = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
BuildPreset& operator=(BuildPreset&& /*other*/) = default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
BuildPreset& operator=(BuildPreset&& /*other*/) = delete;
#endif
std::string ConfigurePreset;
cm::optional<bool> InheritConfigureEnvironment;
cm::optional<unsigned int> Jobs;
std::vector<std::string> Targets;
std::string Configuration;
cm::optional<bool> CleanFirst;
cm::optional<bool> Verbose;
std::vector<std::string> NativeToolOptions;
cm::optional<PackageResolveMode> ResolvePackageReferences;
bool VisitPresetInherit(Preset const& parent) override;
bool VisitPresetAfterInherit(int /* version */,
cmJSONState* /*state*/) override;
static char const* kind() { return "build"; }
};
class TestPreset : public Preset
{
public:
TestPreset() = default;
TestPreset(TestPreset&& /*other*/) = default;
TestPreset(TestPreset const& /*other*/) = default;
TestPreset& operator=(TestPreset const& /*other*/) = default;
~TestPreset() override = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
TestPreset& operator=(TestPreset&& /*other*/) = default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
TestPreset& operator=(TestPreset&& /*other*/) = delete;
#endif
struct OutputOptions
{
enum class VerbosityEnum
{
Default,
Verbose,
Extra
};
cm::optional<bool> ShortProgress;
cm::optional<VerbosityEnum> Verbosity;
cm::optional<bool> Debug;
cm::optional<bool> OutputOnFailure;
cm::optional<bool> Quiet;
std::string OutputLogFile;
std::string OutputJUnitFile;
cm::optional<bool> LabelSummary;
cm::optional<bool> SubprojectSummary;
cm::optional<int> MaxPassedTestOutputSize;
cm::optional<int> MaxFailedTestOutputSize;
cm::optional<cmCTestTypes::TruncationMode> TestOutputTruncation;
cm::optional<int> MaxTestNameWidth;
};
struct IncludeOptions
{
struct IndexOptions
{
cm::optional<int> Start;
cm::optional<int> End;
cm::optional<int> Stride;
std::vector<int> SpecificTests;
std::string IndexFile;
};
std::string Name;
std::string Label;
cm::optional<IndexOptions> Index;
cm::optional<bool> UseUnion;
};
struct ExcludeOptions
{
struct FixturesOptions
{
std::string Any;
std::string Setup;
std::string Cleanup;
};
std::string Name;
std::string Label;
cm::optional<FixturesOptions> Fixtures;
};
struct FilterOptions
{
cm::optional<IncludeOptions> Include;
cm::optional<ExcludeOptions> Exclude;
};
struct ExecutionOptions
{
enum class ShowOnlyEnum
{
Human,
JsonV1
};
struct RepeatOptions
{
enum class ModeEnum
{
UntilFail,
UntilPass,
AfterTimeout
};
ModeEnum Mode;
int Count;
};
enum class NoTestsActionEnum
{
Default,
Error,
Ignore
};
cm::optional<bool> StopOnFailure;
cm::optional<bool> EnableFailover;
cm::optional<cm::optional<unsigned int>> Jobs;
std::string ResourceSpecFile;
cm::optional<int> TestLoad;
cm::optional<ShowOnlyEnum> ShowOnly;
cm::optional<RepeatOptions> Repeat;
cm::optional<bool> InteractiveDebugging;
cm::optional<bool> ScheduleRandom;
cm::optional<int> Timeout;
cm::optional<NoTestsActionEnum> NoTestsAction;
std::vector<std::string> TestPassthroughArguments;
};
std::string ConfigurePreset;
cm::optional<bool> InheritConfigureEnvironment;
std::string Configuration;
std::vector<std::string> OverwriteConfigurationFile;
cm::optional<OutputOptions> Output;
cm::optional<FilterOptions> Filter;
cm::optional<ExecutionOptions> Execution;
bool VisitPresetInherit(Preset const& parent) override;
bool VisitPresetAfterInherit(int /* version */,
cmJSONState* /*state*/) override;
static char const* kind() { return "test"; }
};
class PackagePreset : public Preset
{
public:
PackagePreset() = default;
PackagePreset(PackagePreset&& /*other*/) = default;
PackagePreset(PackagePreset const& /*other*/) = default;
PackagePreset& operator=(PackagePreset const& /*other*/) = default;
~PackagePreset() override = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
PackagePreset& operator=(PackagePreset&& /*other*/) = default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
PackagePreset& operator=(PackagePreset&& /*other*/) = delete;
#endif
std::string ConfigurePreset;
cm::optional<bool> InheritConfigureEnvironment;
std::vector<std::string> Generators;
std::vector<std::string> Configurations;
std::map<std::string, std::string> Variables;
std::string ConfigFile;
cm::optional<bool> DebugOutput;
cm::optional<bool> VerboseOutput;
std::string PackageName;
std::string PackageVersion;
std::string PackageDirectory;
std::string VendorName;
bool VisitPresetInherit(Preset const& parent) override;
bool VisitPresetAfterInherit(int /* version */,
cmJSONState* /*state*/) override;
static char const* kind() { return "package"; }
};
class WorkflowPreset : public Preset
{
public:
WorkflowPreset() = default;
WorkflowPreset(WorkflowPreset&& /*other*/) = default;
WorkflowPreset(WorkflowPreset const& /*other*/) = default;
WorkflowPreset& operator=(WorkflowPreset const& /*other*/) = default;
~WorkflowPreset() override = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
WorkflowPreset& operator=(WorkflowPreset&& /*other*/) = default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
WorkflowPreset& operator=(WorkflowPreset&& /*other*/) = delete;
#endif
struct WorkflowStep
{
enum class Type
{
Configure,
Build,
Test,
Package,
};
Type PresetType;
std::string PresetName;
};
std::vector<WorkflowStep> Steps;
bool VisitPresetInherit(Preset const& parent) override;
bool VisitPresetAfterInherit(int /* version */,
cmJSONState* /* state */) override;
static char const* kind() { return "workflow"; }
};
template <typename T>
struct PresetPair
{
T Unexpanded;
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;
std::map<std::string, PresetPair<PackagePreset>> PackagePresets;
std::map<std::string, PresetPair<WorkflowPreset>> WorkflowPresets;
std::vector<std::string> ConfigurePresetOrder;
std::vector<std::string> BuildPresetOrder;
std::vector<std::string> TestPresetOrder;
std::vector<std::string> PackagePresetOrder;
std::vector<std::string> WorkflowPresetOrder;
std::string SourceDir;
std::vector<std::unique_ptr<File>> Files;
int GetVersion(Preset const& preset) const
{
return preset.OriginFile->Version;
}
enum class ReadOption
{
RequireFiles,
AllowNoFiles,
};
bool ReadProjectPresets(
std::string const& sourceDir, std::string const& presetsFile,
ReadOption readFilesOption = ReadOption::RequireFiles);
std::string GetGeneratorForPreset(std::string const& presetName) const;
void PrintConfigurePresetList() const;
void PrintConfigurePresetList(
std::function<bool(ConfigurePreset const&)> const& filter) const;
void PrintBuildPresetList() const;
void PrintTestPresetList() const;
void PrintPackagePresetList() const;
void PrintPackagePresetList(
std::function<bool(PackagePreset const&)> const& filter) const;
void PrintWorkflowPresetList() const;
void PrintAllPresets() const;
private:
enum class RootType
{
Any,
Project,
User,
};
enum class ReadReason
{
Root,
Included,
};
bool ReadProjectPresetsInternal(std::string const& presetsFile,
ReadOption readFilesOption);
bool ReadJSONFile(std::string const& filename, RootType rootType,
ReadReason readReason, std::vector<File*>& inProgressFiles,
File*& file, std::string& errMsg);
void ClearPresets();
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&);