1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 02:08:27 +08:00

fileapi: Add codemodelVersion fields to target and directory objects

This will allow JSON schemas for these two types of files to describe the
version-specific content without requiring any outside information.

Fixes: #27031
This commit is contained in:
Craig Scott
2025-07-04 14:39:46 +10:00
parent 892fa0bb88
commit 4315076f2e
8 changed files with 120 additions and 39 deletions

View File

@@ -704,6 +704,19 @@ A codemodel "directory" object is referenced by a `"codemodel" version 2`_
object's ``directories`` array. Each "directory" object is a JSON object
with members:
``codemodelVersion``
This specifies the codemodel version this file is part of. It will match
the ``version`` field of the codemodel object kind that references this file.
It is a JSON object with the following members:
``major``
The codemodel major version.
``minor``
The codemodel minor version.
This field was added in codemodel version 2.9.
``paths``
A JSON object containing members:
@@ -980,6 +993,19 @@ A codemodel "target" object is referenced by a `"codemodel" version 2`_
object's ``targets`` array. Each "target" object is a JSON object
with members:
``codemodelVersion``
This specifies the codemodel version this file is part of. It will match
the ``version`` field of the codemodel object kind that references this file.
It is a JSON object with the following members:
``major``
The codemodel major version.
``minor``
The codemodel minor version.
This field was added in codemodel version 2.9.
``name``
A string specifying the logical name of the target.

View File

@@ -0,0 +1,8 @@
codemodel-version-directory-target-objects
------------------------------------------
* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
been updated to 2.9.
* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" and
"directory" objects gained a new ``codemodelVersion`` field.

View File

@@ -789,8 +789,10 @@ std::string cmFileAPI::NoSupportedVersion(
// The "codemodel" object kind.
// Update Help/manual/cmake-file-api.7.rst when updating this constant.
static unsigned int const CodeModelV2Minor = 8;
// Update the following files as well when updating this constant:
// Help/manual/cmake-file-api.7.rst
// Tests/RunCMake/FileAPI/codemodel-v2-check.py (check_objects())
static unsigned int const CodeModelV2Minor = 9;
void cmFileAPI::BuildClientRequestCodeModel(
ClientRequest& r, std::vector<RequestVersion> const& versions)
@@ -809,7 +811,9 @@ void cmFileAPI::BuildClientRequestCodeModel(
Json::Value cmFileAPI::BuildCodeModel(Object const& object)
{
Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version);
assert(object.Version == 2);
Json::Value codemodel =
cmFileAPICodemodelDump(*this, object.Version, CodeModelV2Minor);
codemodel["kind"] = this->ObjectKindName(object.Kind);
Json::Value& version = codemodel["version"];

View File

@@ -64,6 +64,9 @@ public:
bool AddProjectQuery(ObjectKind kind, unsigned majorVersion,
unsigned minorVersion);
/** Build a JSON object with major and minor fields. */
static Json::Value BuildVersion(unsigned int major, unsigned int minor);
private:
cmake* CMakeInstance;
@@ -196,8 +199,6 @@ private:
static char const* ObjectKindName(ObjectKind kind);
static std::string ObjectName(Object const& o);
static Json::Value BuildVersion(unsigned int major, unsigned int minor);
Json::Value BuildObject(Object const& object);
ClientRequests BuildClientRequests(Json::Value const& requests);

View File

@@ -223,21 +223,24 @@ Json::Value BacktraceData::Dump()
class Codemodel
{
cmFileAPI& FileAPI;
unsigned int Version;
unsigned int VersionMajor;
unsigned int VersionMinor;
Json::Value DumpPaths();
Json::Value DumpConfigurations();
Json::Value DumpConfiguration(std::string const& config);
public:
Codemodel(cmFileAPI& fileAPI, unsigned int version);
Codemodel(cmFileAPI& fileAPI, unsigned int versionMajor,
unsigned int versionMinor);
Json::Value Dump();
};
class CodemodelConfig
{
cmFileAPI& FileAPI;
unsigned int Version;
unsigned int VersionMajor;
unsigned int VersionMinor;
std::string const& Config;
std::string TopSource;
std::string TopBuild;
@@ -290,8 +293,8 @@ class CodemodelConfig
Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
public:
CodemodelConfig(cmFileAPI& fileAPI, unsigned int version,
std::string const& config);
CodemodelConfig(cmFileAPI& fileAPI, unsigned int versionMajor,
unsigned int versionMinor, std::string const& config);
Json::Value Dump();
};
@@ -392,6 +395,8 @@ namespace {
class DirectoryObject
{
cmLocalGenerator const* LG = nullptr;
unsigned int VersionMajor;
unsigned int VersionMinor;
std::string const& Config;
TargetIndexMapType& TargetIndexMap;
std::string TopSource;
@@ -409,7 +414,8 @@ class DirectoryObject
std::string const& toPath);
public:
DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
DirectoryObject(cmLocalGenerator const* lg, unsigned int versionMajor,
unsigned int versionMinor, std::string const& config,
TargetIndexMapType& targetIndexMap);
Json::Value Dump();
};
@@ -417,6 +423,8 @@ public:
class Target
{
cmGeneratorTarget* GT;
unsigned int VersionMajor;
unsigned int VersionMinor;
std::string const& Config;
std::string TopSource;
std::string TopBuild;
@@ -511,13 +519,16 @@ class Target
Json::Value DumpDebugger();
public:
Target(cmGeneratorTarget* gt, std::string const& config);
Target(cmGeneratorTarget* gt, unsigned int versionMajor,
unsigned int versionMinor, std::string const& config);
Json::Value Dump();
};
Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned int version)
Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned int versionMajor,
unsigned int versionMinor)
: FileAPI(fileAPI)
, Version(version)
, VersionMajor(versionMajor)
, VersionMinor(versionMinor)
{
}
@@ -557,19 +568,21 @@ Json::Value Codemodel::DumpConfigurations()
Json::Value Codemodel::DumpConfiguration(std::string const& config)
{
CodemodelConfig configuration(this->FileAPI, this->Version, config);
CodemodelConfig configuration(this->FileAPI, this->VersionMajor,
this->VersionMinor, config);
return configuration.Dump();
}
CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned int version,
CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned int versionMajor,
unsigned int versionMinor,
std::string const& config)
: FileAPI(fileAPI)
, Version(version)
, VersionMajor(versionMajor)
, VersionMinor(versionMinor)
, Config(config)
, TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
, TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
{
static_cast<void>(this->Version);
}
Json::Value CodemodelConfig::Dump()
@@ -701,7 +714,7 @@ Json::Value CodemodelConfig::DumpTargets()
Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
Json::ArrayIndex ti)
{
Target t(gt, this->Config);
Target t(gt, this->VersionMajor, this->VersionMinor, this->Config);
std::string prefix = "target-" + gt->GetName();
if (!this->Config.empty()) {
prefix += "-" + this->Config;
@@ -797,7 +810,8 @@ Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
prefix += "-" + this->Config;
}
DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
DirectoryObject dir(d.LocalGenerator, this->VersionMajor, this->VersionMinor,
this->Config, this->TargetIndexMap);
return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
}
@@ -844,9 +858,13 @@ Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
}
DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
unsigned int versionMajor,
unsigned int versionMinor,
std::string const& config,
TargetIndexMapType& targetIndexMap)
: LG(lg)
, VersionMajor(versionMajor)
, VersionMinor(versionMinor)
, Config(config)
, TargetIndexMap(targetIndexMap)
, TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
@@ -859,6 +877,8 @@ DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
Json::Value DirectoryObject::Dump()
{
Json::Value directoryObject = Json::objectValue;
directoryObject["codemodelVersion"] =
cmFileAPI::BuildVersion(this->VersionMajor, this->VersionMinor);
directoryObject["paths"] = this->DumpPaths();
directoryObject["installers"] = this->DumpInstallers();
directoryObject["backtraceGraph"] = this->Backtraces.Dump();
@@ -1186,8 +1206,11 @@ Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
return installPath;
}
Target::Target(cmGeneratorTarget* gt, std::string const& config)
Target::Target(cmGeneratorTarget* gt, unsigned int versionMajor,
unsigned int versionMinor, std::string const& config)
: GT(gt)
, VersionMajor(versionMajor)
, VersionMinor(versionMinor)
, Config(config)
, TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
, TopBuild(
@@ -1203,6 +1226,8 @@ Json::Value Target::Dump()
cmStateEnums::TargetType const type = this->GT->GetType();
target["codemodelVersion"] =
cmFileAPI::BuildVersion(this->VersionMajor, this->VersionMinor);
target["name"] = this->GT->GetName();
target["type"] = cmState::GetTargetTypeName(type);
target["id"] = TargetId(this->GT, this->TopBuild);
@@ -2154,8 +2179,10 @@ Json::Value Target::DumpDebugger()
return debuggerInformation;
}
Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned int version)
Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
unsigned int versionMajor,
unsigned int versionMinor)
{
Codemodel codemodel(fileAPI, version);
Codemodel codemodel(fileAPI, versionMajor, versionMinor);
return codemodel.Dump();
}

View File

@@ -9,4 +9,5 @@
class cmFileAPI;
extern Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
unsigned int version);
unsigned int majorVersion,
unsigned int minorVersion);

View File

@@ -1 +1 @@
^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":8}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":9}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$

View File

@@ -12,7 +12,9 @@ def read_codemodel_json_data(filename):
def check_objects(o, g):
assert is_list(o)
assert len(o) == 1
check_index_object(o[0], "codemodel", 2, 8, check_object_codemodel(g))
major = 2
minor = 9
check_index_object(o[0], "codemodel", major, minor, check_object_codemodel(g, major, minor))
def check_backtrace(t, b, backtrace):
btg = t["backtraceGraph"]
@@ -52,7 +54,7 @@ def check_backtraces(t, actual, expected):
check_backtrace(t, actual[i], expected[i])
i += 1
def check_directory(c):
def check_directory(c, major, minor):
def _check(actual, expected):
assert is_dict(actual)
expected_keys = ["build", "jsonFile", "source", "projectIndex"]
@@ -100,7 +102,12 @@ def check_directory(c):
d = json.load(f)
assert is_dict(d)
assert sorted(d.keys()) == ["backtraceGraph", "installers", "paths"]
assert sorted(d.keys()) == ["backtraceGraph", "codemodelVersion", "installers", "paths"]
# We get the values for major and minor directly rather than from the "expected" data.
# This avoids having to update every data file any time the major or minor version changes.
assert is_int(d["codemodelVersion"]["major"], major)
assert is_int(d["codemodelVersion"]["minor"], minor)
assert is_string(d["paths"]["source"], actual["source"])
assert is_string(d["paths"]["build"], actual["build"])
@@ -266,7 +273,7 @@ def check_backtrace_graph(btg):
assert sorted(n.keys()) == sorted(expected_keys)
def check_target(c):
def check_target(c, major, minor):
def _check(actual, expected):
assert is_dict(actual)
assert sorted(actual.keys()) == ["directoryIndex", "id", "jsonFile", "name", "projectIndex"]
@@ -281,7 +288,7 @@ def check_target(c):
with open(filepath) as f:
obj = json.load(f)
expected_keys = ["name", "id", "type", "backtraceGraph", "paths", "sources"]
expected_keys = ["codemodelVersion", "name", "id", "type", "backtraceGraph", "paths", "sources"]
assert is_dict(obj)
assert is_string(obj["name"], expected["name"])
assert matches(obj["id"], expected["id"])
@@ -293,6 +300,13 @@ def check_target(c):
assert matches(obj["paths"]["build"], expected["build"])
assert matches(obj["paths"]["source"], expected["source"])
# We get the values for major and minor directly rather than from the "expected" data.
# This avoids having to update every data file any time the major or minor version changes.
assert is_dict(obj["codemodelVersion"])
assert sorted(obj["codemodelVersion"].keys()) == ["major", "minor"]
assert is_int(obj["codemodelVersion"]["major"], major)
assert is_int(obj["codemodelVersion"]["minor"], minor)
def check_file_set(actual, expected):
assert is_dict(actual)
expected_keys = ["name", "type", "visibility", "baseDirectories"]
@@ -794,9 +808,9 @@ def gen_check_directories(c, g):
return expected
def check_directories(c, g):
def check_directories(c, g, major, minor):
check_list_match(lambda a, e: matches(a["source"], e["source"]), c["directories"], gen_check_directories(c, g),
check=check_directory(c),
check=check_directory(c, major, minor),
check_exception=lambda a, e: "Directory source: %s" % a["source"],
missing_exception=lambda e: "Directory source: %s" % e["source"],
extra_exception=lambda a: "Directory source: %s" % a["source"])
@@ -1001,10 +1015,10 @@ def gen_check_targets(c, g, inSource):
return expected
def check_targets(c, g, inSource):
def check_targets(c, g, major, minor, inSource):
check_list_match(lambda a, e: matches(a["id"], e["id"]),
c["targets"], gen_check_targets(c, g, inSource),
check=check_target(c),
check=check_target(c, major, minor),
check_exception=lambda a, e: "Target ID: %s" % a["id"],
missing_exception=lambda e: "Target ID: %s" % e["id"],
extra_exception=lambda a: "Target ID: %s" % a["id"])
@@ -1045,14 +1059,14 @@ def check_projects(c, g):
missing_exception=lambda e: "Project name: %s" % e["name"],
extra_exception=lambda a: "Project name: %s" % a["name"])
def check_object_codemodel_configuration(c, g, inSource):
def check_object_codemodel_configuration(c, g, major, minor, inSource):
assert sorted(c.keys()) == ["directories", "name", "projects", "targets"]
assert is_string(c["name"])
check_directories(c, g)
check_targets(c, g, inSource)
check_directories(c, g, major, minor)
check_targets(c, g, major, minor, inSource)
check_projects(c, g)
def check_object_codemodel(g):
def check_object_codemodel(g, major, minor):
def _check(o):
assert sorted(o.keys()) == ["configurations", "kind", "paths", "version"]
# The "kind" and "version" members are handled by check_index_object.
@@ -1070,7 +1084,7 @@ def check_object_codemodel(g):
assert o["configurations"][0]["name"] in ("", "Debug", "Release", "RelWithDebInfo", "MinSizeRel")
for c in o["configurations"]:
check_object_codemodel_configuration(c, g, inSource)
check_object_codemodel_configuration(c, g, major, minor, inSource)
return _check
cxx_compiler_id = sys.argv[2]