mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-17 04:31:04 -06:00
Refactor: Generalize file graph in CMakePresets
Before this refactoring, presets had a simple flag that marked them as "user" or "not user", and checking the file graph of two files was as simple as checking this flag. This only allowed for two files in the graph. Generalize the code to allow for arbitrarily many files in the graph.
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include "cmCMakePresetsGraph.h"
|
#include "cmCMakePresetsGraph.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -106,8 +107,8 @@ ReadFileResult VisitPreset(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& parentPreset = parent->second.Unexpanded;
|
auto& parentPreset = parent->second.Unexpanded;
|
||||||
if (!preset.User && parentPreset.User) {
|
if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) {
|
||||||
return ReadFileResult::USER_PRESET_INHERITANCE;
|
return ReadFileResult::PRESET_UNREACHABLE_FROM_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = VisitPreset(parentPreset, presets, cycleStatus, graph);
|
auto result = VisitPreset(parentPreset, presets, cycleStatus, graph);
|
||||||
@@ -876,23 +877,28 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
|
|||||||
{
|
{
|
||||||
bool haveOneFile = false;
|
bool haveOneFile = false;
|
||||||
|
|
||||||
|
File* file;
|
||||||
std::string filename = GetUserFilename(this->SourceDir);
|
std::string filename = GetUserFilename(this->SourceDir);
|
||||||
|
std::vector<File*> inProgressFiles;
|
||||||
if (cmSystemTools::FileExists(filename)) {
|
if (cmSystemTools::FileExists(filename)) {
|
||||||
auto result = this->ReadJSONFile(filename, true);
|
auto result = this->ReadJSONFile(filename, RootType::User,
|
||||||
|
ReadReason::Root, inProgressFiles, file);
|
||||||
if (result != ReadFileResult::READ_OK) {
|
if (result != ReadFileResult::READ_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
haveOneFile = true;
|
haveOneFile = true;
|
||||||
}
|
} else {
|
||||||
|
filename = GetFilename(this->SourceDir);
|
||||||
filename = GetFilename(this->SourceDir);
|
if (cmSystemTools::FileExists(filename)) {
|
||||||
if (cmSystemTools::FileExists(filename)) {
|
auto result = this->ReadJSONFile(
|
||||||
auto result = this->ReadJSONFile(filename, false);
|
filename, RootType::Project, ReadReason::Root, inProgressFiles, file);
|
||||||
if (result != ReadFileResult::READ_OK) {
|
if (result != ReadFileResult::READ_OK) {
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
haveOneFile = true;
|
||||||
}
|
}
|
||||||
haveOneFile = true;
|
|
||||||
}
|
}
|
||||||
|
assert(inProgressFiles.empty());
|
||||||
|
|
||||||
if (!haveOneFile) {
|
if (!haveOneFile) {
|
||||||
return allowNoFiles ? ReadFileResult::READ_OK
|
return allowNoFiles ? ReadFileResult::READ_OK
|
||||||
@@ -983,8 +989,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
|
|||||||
return "Duplicate presets";
|
return "Duplicate presets";
|
||||||
case ReadFileResult::CYCLIC_PRESET_INHERITANCE:
|
case ReadFileResult::CYCLIC_PRESET_INHERITANCE:
|
||||||
return "Cyclic preset inheritance";
|
return "Cyclic preset inheritance";
|
||||||
case ReadFileResult::USER_PRESET_INHERITANCE:
|
case ReadFileResult::PRESET_UNREACHABLE_FROM_FILE:
|
||||||
return "Project preset inherits from user preset";
|
return "Inherited preset is unreachable from preset's file";
|
||||||
case ReadFileResult::INVALID_MACRO_EXPANSION:
|
case ReadFileResult::INVALID_MACRO_EXPANSION:
|
||||||
return "Invalid macro expansion";
|
return "Invalid macro expansion";
|
||||||
case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
|
case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
|
||||||
@@ -1002,6 +1008,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
|
|||||||
case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED:
|
case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED:
|
||||||
return "File version must be 3 or higher for toolchainFile preset "
|
return "File version must be 3 or higher for toolchainFile preset "
|
||||||
"support.";
|
"support.";
|
||||||
|
case ReadFileResult::CYCLIC_INCLUDE:
|
||||||
|
return "Cyclic include among preset files";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
@@ -1016,6 +1024,8 @@ void cmCMakePresetsGraph::ClearPresets()
|
|||||||
this->ConfigurePresetOrder.clear();
|
this->ConfigurePresetOrder.clear();
|
||||||
this->BuildPresetOrder.clear();
|
this->BuildPresetOrder.clear();
|
||||||
this->TestPresetOrder.clear();
|
this->TestPresetOrder.clear();
|
||||||
|
|
||||||
|
this->Files.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmCMakePresetsGraph::PrintPresets(
|
void cmCMakePresetsGraph::PrintPresets(
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ public:
|
|||||||
INVALID_VARIABLE,
|
INVALID_VARIABLE,
|
||||||
DUPLICATE_PRESETS,
|
DUPLICATE_PRESETS,
|
||||||
CYCLIC_PRESET_INHERITANCE,
|
CYCLIC_PRESET_INHERITANCE,
|
||||||
USER_PRESET_INHERITANCE,
|
PRESET_UNREACHABLE_FROM_FILE,
|
||||||
INVALID_MACRO_EXPANSION,
|
INVALID_MACRO_EXPANSION,
|
||||||
BUILD_TEST_PRESETS_UNSUPPORTED,
|
BUILD_TEST_PRESETS_UNSUPPORTED,
|
||||||
INVALID_CONFIGURE_PRESET,
|
INVALID_CONFIGURE_PRESET,
|
||||||
@@ -40,6 +41,7 @@ public:
|
|||||||
INVALID_CONDITION,
|
INVALID_CONDITION,
|
||||||
CONDITION_UNSUPPORTED,
|
CONDITION_UNSUPPORTED,
|
||||||
TOOLCHAIN_FILE_UNSUPPORTED,
|
TOOLCHAIN_FILE_UNSUPPORTED,
|
||||||
|
CYCLIC_INCLUDE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ArchToolsetStrategy
|
enum class ArchToolsetStrategy
|
||||||
@@ -57,6 +59,15 @@ public:
|
|||||||
|
|
||||||
class Condition;
|
class Condition;
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string Filename;
|
||||||
|
int Version;
|
||||||
|
|
||||||
|
std::unordered_set<File*> ReachableFiles;
|
||||||
|
};
|
||||||
|
|
||||||
class Preset
|
class Preset
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -77,7 +88,7 @@ public:
|
|||||||
std::string Name;
|
std::string Name;
|
||||||
std::vector<std::string> Inherits;
|
std::vector<std::string> Inherits;
|
||||||
bool Hidden;
|
bool Hidden;
|
||||||
bool User;
|
File* OriginFile;
|
||||||
std::string DisplayName;
|
std::string DisplayName;
|
||||||
std::string Description;
|
std::string Description;
|
||||||
|
|
||||||
@@ -321,12 +332,11 @@ public:
|
|||||||
std::vector<std::string> TestPresetOrder;
|
std::vector<std::string> TestPresetOrder;
|
||||||
|
|
||||||
std::string SourceDir;
|
std::string SourceDir;
|
||||||
int Version;
|
std::vector<std::unique_ptr<File>> Files;
|
||||||
int UserVersion;
|
|
||||||
|
|
||||||
int GetVersion(const Preset& preset) const
|
int GetVersion(const Preset& preset) const
|
||||||
{
|
{
|
||||||
return preset.User ? this->UserVersion : this->Version;
|
return preset.OriginFile->Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetFilename(const std::string& sourceDir);
|
static std::string GetFilename(const std::string& sourceDir);
|
||||||
@@ -372,7 +382,22 @@ public:
|
|||||||
void PrintAllPresets() const;
|
void PrintAllPresets() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class RootType
|
||||||
|
{
|
||||||
|
Project,
|
||||||
|
User,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ReadReason
|
||||||
|
{
|
||||||
|
Root,
|
||||||
|
Included,
|
||||||
|
};
|
||||||
|
|
||||||
ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
|
ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
|
||||||
ReadFileResult ReadJSONFile(const std::string& filename, bool user);
|
ReadFileResult ReadJSONFile(const std::string& filename, RootType rootType,
|
||||||
|
ReadReason readReason,
|
||||||
|
std::vector<File*>& inProgressFiles,
|
||||||
|
File*& file);
|
||||||
void ClearPresets();
|
void ClearPresets();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||||
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -18,6 +20,8 @@
|
|||||||
#include "cmCMakePresetsGraph.h"
|
#include "cmCMakePresetsGraph.h"
|
||||||
#include "cmCMakePresetsGraphInternal.h"
|
#include "cmCMakePresetsGraphInternal.h"
|
||||||
#include "cmJSONHelpers.h"
|
#include "cmJSONHelpers.h"
|
||||||
|
#include "cmStringAlgorithms.h"
|
||||||
|
#include "cmSystemTools.h"
|
||||||
#include "cmVersion.h"
|
#include "cmVersion.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -406,8 +410,21 @@ cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
||||||
const std::string& filename, bool user)
|
const std::string& filename, RootType rootType, ReadReason readReason,
|
||||||
|
std::vector<File*>& inProgressFiles, File*& file)
|
||||||
{
|
{
|
||||||
|
for (auto const& f : this->Files) {
|
||||||
|
if (cmSystemTools::SameFile(filename, f->Filename)) {
|
||||||
|
file = f.get();
|
||||||
|
auto fileIt =
|
||||||
|
std::find(inProgressFiles.begin(), inProgressFiles.end(), file);
|
||||||
|
if (fileIt != inProgressFiles.end()) {
|
||||||
|
return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE;
|
||||||
|
}
|
||||||
|
return cmCMakePresetsGraph::ReadFileResult::READ_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmsys::ifstream fin(filename.c_str());
|
cmsys::ifstream fin(filename.c_str());
|
||||||
if (!fin) {
|
if (!fin) {
|
||||||
return ReadFileResult::FILE_NOT_FOUND;
|
return ReadFileResult::FILE_NOT_FOUND;
|
||||||
@@ -430,11 +447,6 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
|||||||
if (v < MIN_VERSION || v > MAX_VERSION) {
|
if (v < MIN_VERSION || v > MAX_VERSION) {
|
||||||
return ReadFileResult::UNRECOGNIZED_VERSION;
|
return ReadFileResult::UNRECOGNIZED_VERSION;
|
||||||
}
|
}
|
||||||
if (user) {
|
|
||||||
this->UserVersion = v;
|
|
||||||
} else {
|
|
||||||
this->Version = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support for build and test presets added in version 2.
|
// Support for build and test presets added in version 2.
|
||||||
if (v < 2 &&
|
if (v < 2 &&
|
||||||
@@ -460,8 +472,16 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
|||||||
return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
|
return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto filePtr = cm::make_unique<File>();
|
||||||
|
file = filePtr.get();
|
||||||
|
this->Files.emplace_back(std::move(filePtr));
|
||||||
|
inProgressFiles.emplace_back(file);
|
||||||
|
file->Filename = filename;
|
||||||
|
file->Version = v;
|
||||||
|
file->ReachableFiles.insert(file);
|
||||||
|
|
||||||
for (auto& preset : presets.ConfigurePresets) {
|
for (auto& preset : presets.ConfigurePresets) {
|
||||||
preset.User = user;
|
preset.OriginFile = file;
|
||||||
if (preset.Name.empty()) {
|
if (preset.Name.empty()) {
|
||||||
return ReadFileResult::INVALID_PRESET;
|
return ReadFileResult::INVALID_PRESET;
|
||||||
}
|
}
|
||||||
@@ -494,7 +514,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& preset : presets.BuildPresets) {
|
for (auto& preset : presets.BuildPresets) {
|
||||||
preset.User = user;
|
preset.OriginFile = file;
|
||||||
if (preset.Name.empty()) {
|
if (preset.Name.empty()) {
|
||||||
return ReadFileResult::INVALID_PRESET;
|
return ReadFileResult::INVALID_PRESET;
|
||||||
}
|
}
|
||||||
@@ -515,7 +535,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& preset : presets.TestPresets) {
|
for (auto& preset : presets.TestPresets) {
|
||||||
preset.User = user;
|
preset.OriginFile = file;
|
||||||
if (preset.Name.empty()) {
|
if (preset.Name.empty()) {
|
||||||
return ReadFileResult::INVALID_PRESET;
|
return ReadFileResult::INVALID_PRESET;
|
||||||
}
|
}
|
||||||
@@ -535,5 +555,33 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
|
|||||||
this->TestPresetOrder.push_back(preset.Name);
|
this->TestPresetOrder.push_back(preset.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto const includeFile = [this, &inProgressFiles, file](
|
||||||
|
const std::string& include, RootType rootType2,
|
||||||
|
ReadReason readReason2) -> ReadFileResult {
|
||||||
|
ReadFileResult r;
|
||||||
|
File* includedFile;
|
||||||
|
if ((r = this->ReadJSONFile(include, rootType2, readReason2,
|
||||||
|
inProgressFiles, includedFile)) !=
|
||||||
|
ReadFileResult::READ_OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
|
||||||
|
includedFile->ReachableFiles.end());
|
||||||
|
return ReadFileResult::READ_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (rootType == RootType::User && readReason == ReadReason::Root) {
|
||||||
|
auto cmakePresetsFilename = GetFilename(this->SourceDir);
|
||||||
|
if (cmSystemTools::FileExists(cmakePresetsFilename)) {
|
||||||
|
if ((result = includeFile(cmakePresetsFilename, RootType::Project,
|
||||||
|
ReadReason::Root)) !=
|
||||||
|
ReadFileResult::READ_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inProgressFiles.pop_back();
|
||||||
return ReadFileResult::READ_OK;
|
return ReadFileResult::READ_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
^CMake Error: Could not read presets from [^
|
^CMake Error: Could not read presets from [^
|
||||||
]*/Tests/RunCMake/CMakePresets/UserInheritance: Project preset inherits from user preset$
|
]*/Tests/RunCMake/CMakePresets/UserInheritance: Inherited preset is unreachable from preset's file$
|
||||||
|
|||||||
Reference in New Issue
Block a user