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

The file API code used unsigned long to hold the major version in most places, but not all. Some places used unsigned int, and an important one of those is the cmFileApi::BuildVersion() function. As a result, it has never been safe for a large value not representable by an unsigned int to be used in these variables. Convert all of the file API version number variables and function arguments to use unsigned int consistently. This avoids any size mismatch warnings when passing values around. They also don't need to be unsigned long, as we never expect version numbers to be anything even close to what an unsigned int cannot represent.
2162 lines
67 KiB
C++
2162 lines
67 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include "cmFileAPICodemodel.h"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <cm/string_view>
|
|
#include <cmext/algorithm>
|
|
#include <cmext/string_view>
|
|
|
|
#include <cm3p/json/value.h>
|
|
|
|
#include "cmCryptoHash.h"
|
|
#include "cmExportSet.h"
|
|
#include "cmFileAPI.h"
|
|
#include "cmFileSet.h"
|
|
#include "cmGeneratorExpression.h"
|
|
#include "cmGeneratorTarget.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmInstallCxxModuleBmiGenerator.h"
|
|
#include "cmInstallDirectoryGenerator.h"
|
|
#include "cmInstallExportGenerator.h"
|
|
#include "cmInstallFileSetGenerator.h"
|
|
#include "cmInstallFilesGenerator.h"
|
|
#include "cmInstallGenerator.h"
|
|
#include "cmInstallGetRuntimeDependenciesGenerator.h"
|
|
#include "cmInstallImportedRuntimeArtifactsGenerator.h"
|
|
#include "cmInstallRuntimeDependencySet.h"
|
|
#include "cmInstallRuntimeDependencySetGenerator.h"
|
|
#include "cmInstallScriptGenerator.h"
|
|
#include "cmInstallSubdirectoryGenerator.h"
|
|
#include "cmInstallTargetGenerator.h"
|
|
#include "cmLinkLineComputer.h" // IWYU pragma: keep
|
|
#include "cmList.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmLocalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmRange.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmSourceGroup.h"
|
|
#include "cmState.h"
|
|
#include "cmStateDirectory.h"
|
|
#include "cmStateSnapshot.h"
|
|
#include "cmStateTypes.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmTarget.h"
|
|
#include "cmTargetDepend.h"
|
|
#include "cmTargetExport.h"
|
|
#include "cmValue.h"
|
|
#include "cmake.h"
|
|
|
|
namespace {
|
|
|
|
using TargetIndexMapType =
|
|
std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
|
|
|
|
std::string RelativeIfUnder(std::string const& top, std::string const& in)
|
|
{
|
|
return cmSystemTools::RelativeIfUnder(top, in);
|
|
}
|
|
|
|
class JBTIndex
|
|
{
|
|
public:
|
|
JBTIndex() = default;
|
|
explicit operator bool() const { return this->Index != None; }
|
|
Json::ArrayIndex Index = None;
|
|
static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1);
|
|
};
|
|
|
|
template <typename T>
|
|
class JBT
|
|
{
|
|
public:
|
|
JBT(T v = T(), JBTIndex bt = JBTIndex())
|
|
: Value(std::move(v))
|
|
, Backtrace(bt)
|
|
{
|
|
}
|
|
T Value;
|
|
JBTIndex Backtrace;
|
|
friend bool operator==(JBT<T> const& l, JBT<T> const& r)
|
|
{
|
|
return l.Value == r.Value && l.Backtrace.Index == r.Backtrace.Index;
|
|
}
|
|
static bool ValueEq(JBT<T> const& l, JBT<T> const& r)
|
|
{
|
|
return l.Value == r.Value;
|
|
}
|
|
static bool ValueLess(JBT<T> const& l, JBT<T> const& r)
|
|
{
|
|
return l.Value < r.Value;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class JBTs
|
|
{
|
|
public:
|
|
JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>())
|
|
: Value(std::move(v))
|
|
, Backtraces(std::move(ids))
|
|
{
|
|
}
|
|
T Value;
|
|
std::vector<JBTIndex> Backtraces;
|
|
friend bool operator==(JBTs<T> const& l, JBTs<T> const& r)
|
|
{
|
|
if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) {
|
|
for (size_t i = 0; i < l.Backtraces.size(); i++) {
|
|
if (l.Backtraces[i].Index != r.Backtraces[i].Index) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r)
|
|
{
|
|
return l.Value == r.Value;
|
|
}
|
|
static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r)
|
|
{
|
|
return l.Value < r.Value;
|
|
}
|
|
};
|
|
|
|
class BacktraceData
|
|
{
|
|
std::string TopSource;
|
|
std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
|
|
std::unordered_map<std::string, Json::ArrayIndex> FileMap;
|
|
std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
|
|
Json::Value Commands = Json::arrayValue;
|
|
Json::Value Files = Json::arrayValue;
|
|
Json::Value Nodes = Json::arrayValue;
|
|
|
|
Json::ArrayIndex AddCommand(std::string const& command)
|
|
{
|
|
auto i = this->CommandMap.find(command);
|
|
if (i == this->CommandMap.end()) {
|
|
auto cmdIndex = static_cast<Json::ArrayIndex>(this->Commands.size());
|
|
i = this->CommandMap.emplace(command, cmdIndex).first;
|
|
this->Commands.append(command);
|
|
}
|
|
return i->second;
|
|
}
|
|
|
|
Json::ArrayIndex AddFile(std::string const& file)
|
|
{
|
|
auto i = this->FileMap.find(file);
|
|
if (i == this->FileMap.end()) {
|
|
auto fileIndex = static_cast<Json::ArrayIndex>(this->Files.size());
|
|
i = this->FileMap.emplace(file, fileIndex).first;
|
|
this->Files.append(RelativeIfUnder(this->TopSource, file));
|
|
}
|
|
return i->second;
|
|
}
|
|
|
|
public:
|
|
BacktraceData(std::string topSource);
|
|
JBTIndex Add(cmListFileBacktrace const& bt);
|
|
Json::Value Dump();
|
|
};
|
|
|
|
BacktraceData::BacktraceData(std::string topSource)
|
|
: TopSource(std::move(topSource))
|
|
{
|
|
}
|
|
|
|
JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt)
|
|
{
|
|
JBTIndex index;
|
|
if (bt.Empty()) {
|
|
return index;
|
|
}
|
|
cmListFileContext const* top = &bt.Top();
|
|
auto found = this->NodeMap.find(top);
|
|
if (found != this->NodeMap.end()) {
|
|
index.Index = found->second;
|
|
return index;
|
|
}
|
|
Json::Value entry = Json::objectValue;
|
|
entry["file"] = this->AddFile(top->FilePath);
|
|
if (top->Line) {
|
|
entry["line"] = static_cast<int>(top->Line);
|
|
}
|
|
if (!top->Name.empty()) {
|
|
entry["command"] = this->AddCommand(top->Name);
|
|
}
|
|
if (JBTIndex parent = this->Add(bt.Pop())) {
|
|
entry["parent"] = parent.Index;
|
|
}
|
|
index.Index = this->NodeMap[top] = this->Nodes.size();
|
|
this->Nodes.append(std::move(entry)); // NOLINT(*)
|
|
return index;
|
|
}
|
|
|
|
Json::Value BacktraceData::Dump()
|
|
{
|
|
Json::Value backtraceGraph;
|
|
this->CommandMap.clear();
|
|
this->FileMap.clear();
|
|
this->NodeMap.clear();
|
|
backtraceGraph["commands"] = std::move(this->Commands);
|
|
backtraceGraph["files"] = std::move(this->Files);
|
|
backtraceGraph["nodes"] = std::move(this->Nodes);
|
|
return backtraceGraph;
|
|
}
|
|
|
|
class Codemodel
|
|
{
|
|
cmFileAPI& FileAPI;
|
|
unsigned int Version;
|
|
|
|
Json::Value DumpPaths();
|
|
Json::Value DumpConfigurations();
|
|
Json::Value DumpConfiguration(std::string const& config);
|
|
|
|
public:
|
|
Codemodel(cmFileAPI& fileAPI, unsigned int version);
|
|
Json::Value Dump();
|
|
};
|
|
|
|
class CodemodelConfig
|
|
{
|
|
cmFileAPI& FileAPI;
|
|
unsigned int Version;
|
|
std::string const& Config;
|
|
std::string TopSource;
|
|
std::string TopBuild;
|
|
|
|
struct Directory
|
|
{
|
|
cmStateSnapshot Snapshot;
|
|
cmLocalGenerator const* LocalGenerator = nullptr;
|
|
Json::Value TargetIndexes = Json::arrayValue;
|
|
Json::ArrayIndex ProjectIndex;
|
|
bool HasInstallRule = false;
|
|
};
|
|
std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
|
|
DirectoryMap;
|
|
std::vector<Directory> Directories;
|
|
|
|
struct Project
|
|
{
|
|
cmStateSnapshot Snapshot;
|
|
static Json::ArrayIndex const NoParentIndex =
|
|
static_cast<Json::ArrayIndex>(-1);
|
|
Json::ArrayIndex ParentIndex = NoParentIndex;
|
|
Json::Value ChildIndexes = Json::arrayValue;
|
|
Json::Value DirectoryIndexes = Json::arrayValue;
|
|
Json::Value TargetIndexes = Json::arrayValue;
|
|
};
|
|
std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
|
|
ProjectMap;
|
|
std::vector<Project> Projects;
|
|
|
|
TargetIndexMapType TargetIndexMap;
|
|
|
|
void ProcessDirectories();
|
|
|
|
Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
|
|
Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
|
|
|
|
Json::ArrayIndex AddProject(cmStateSnapshot s);
|
|
|
|
Json::Value DumpTargets();
|
|
Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
|
|
|
|
Json::Value DumpDirectories();
|
|
Json::Value DumpDirectory(Directory& d);
|
|
Json::Value DumpDirectoryObject(Directory& d);
|
|
|
|
Json::Value DumpProjects();
|
|
Json::Value DumpProject(Project& p);
|
|
|
|
Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
|
|
|
|
public:
|
|
CodemodelConfig(cmFileAPI& fileAPI, unsigned int version,
|
|
std::string const& config);
|
|
Json::Value Dump();
|
|
};
|
|
|
|
std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
|
|
{
|
|
cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
|
|
std::string path = RelativeIfUnder(
|
|
topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
|
|
std::string hash = hasher.HashString(path);
|
|
hash.resize(20, '0');
|
|
return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
|
|
}
|
|
|
|
struct CompileData
|
|
{
|
|
struct IncludeEntry
|
|
{
|
|
JBT<std::string> Path;
|
|
bool IsSystem = false;
|
|
IncludeEntry(JBT<std::string> path, bool isSystem)
|
|
: Path(std::move(path))
|
|
, IsSystem(isSystem)
|
|
{
|
|
}
|
|
friend bool operator==(IncludeEntry const& l, IncludeEntry const& r)
|
|
{
|
|
return l.Path == r.Path && l.IsSystem == r.IsSystem;
|
|
}
|
|
};
|
|
|
|
std::string Language;
|
|
std::string Sysroot;
|
|
JBTs<std::string> LanguageStandard;
|
|
std::vector<JBT<std::string>> Flags;
|
|
std::vector<JBT<std::string>> Defines;
|
|
std::vector<JBT<std::string>> PrecompileHeaders;
|
|
std::vector<IncludeEntry> Includes;
|
|
std::vector<IncludeEntry> Frameworks;
|
|
|
|
friend bool operator==(CompileData const& l, CompileData const& r)
|
|
{
|
|
return (l.Language == r.Language && l.Sysroot == r.Sysroot &&
|
|
l.Flags == r.Flags && l.Defines == r.Defines &&
|
|
l.PrecompileHeaders == r.PrecompileHeaders &&
|
|
l.LanguageStandard == r.LanguageStandard &&
|
|
l.Includes == r.Includes && l.Frameworks == r.Frameworks);
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace std {
|
|
|
|
template <>
|
|
struct hash<CompileData>
|
|
{
|
|
std::size_t operator()(CompileData const& in) const
|
|
{
|
|
using std::hash;
|
|
size_t result =
|
|
hash<std::string>()(in.Language) ^ hash<std::string>()(in.Sysroot);
|
|
for (auto const& i : in.Includes) {
|
|
result = result ^
|
|
(hash<std::string>()(i.Path.Value) ^
|
|
hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
|
|
(i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
|
|
}
|
|
for (auto const& i : in.Frameworks) {
|
|
result = result ^
|
|
(hash<std::string>()(i.Path.Value) ^
|
|
hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
|
|
(i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
|
|
}
|
|
for (auto const& i : in.Flags) {
|
|
result = result ^ hash<std::string>()(i.Value) ^
|
|
hash<Json::ArrayIndex>()(i.Backtrace.Index);
|
|
}
|
|
for (auto const& i : in.Defines) {
|
|
result = result ^ hash<std::string>()(i.Value) ^
|
|
hash<Json::ArrayIndex>()(i.Backtrace.Index);
|
|
}
|
|
for (auto const& i : in.PrecompileHeaders) {
|
|
result = result ^ hash<std::string>()(i.Value) ^
|
|
hash<Json::ArrayIndex>()(i.Backtrace.Index);
|
|
}
|
|
if (!in.LanguageStandard.Value.empty()) {
|
|
result = result ^ hash<std::string>()(in.LanguageStandard.Value);
|
|
for (JBTIndex backtrace : in.LanguageStandard.Backtraces) {
|
|
result = result ^ hash<Json::ArrayIndex>()(backtrace.Index);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
namespace {
|
|
class DirectoryObject
|
|
{
|
|
cmLocalGenerator const* LG = nullptr;
|
|
std::string const& Config;
|
|
TargetIndexMapType& TargetIndexMap;
|
|
std::string TopSource;
|
|
std::string TopBuild;
|
|
BacktraceData Backtraces;
|
|
|
|
void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
|
|
|
|
Json::Value DumpPaths();
|
|
Json::Value DumpInstallers();
|
|
Json::Value DumpInstaller(cmInstallGenerator* gen);
|
|
Json::Value DumpInstallerExportTargets(cmExportSet* exp);
|
|
Json::Value DumpInstallerPath(std::string const& top,
|
|
std::string const& fromPathIn,
|
|
std::string const& toPath);
|
|
|
|
public:
|
|
DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
|
|
TargetIndexMapType& targetIndexMap);
|
|
Json::Value Dump();
|
|
};
|
|
|
|
class Target
|
|
{
|
|
cmGeneratorTarget* GT;
|
|
std::string const& Config;
|
|
std::string TopSource;
|
|
std::string TopBuild;
|
|
std::vector<cmSourceGroup> SourceGroupsLocal;
|
|
BacktraceData Backtraces;
|
|
|
|
std::map<std::string, CompileData> CompileDataMap;
|
|
|
|
std::unordered_map<cmSourceFile const*, Json::ArrayIndex> SourceMap;
|
|
Json::Value Sources = Json::arrayValue;
|
|
|
|
struct SourceGroup
|
|
{
|
|
std::string Name;
|
|
Json::Value SourceIndexes = Json::arrayValue;
|
|
};
|
|
std::unordered_map<cmSourceGroup const*, Json::ArrayIndex> SourceGroupsMap;
|
|
std::vector<SourceGroup> SourceGroups;
|
|
|
|
struct CompileGroup
|
|
{
|
|
std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry;
|
|
Json::Value SourceIndexes = Json::arrayValue;
|
|
};
|
|
std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
|
|
std::vector<CompileGroup> CompileGroups;
|
|
|
|
using FileSetDatabase = std::map<std::string, Json::ArrayIndex>;
|
|
|
|
template <typename T>
|
|
JBT<T> ToJBT(BT<T> const& bt)
|
|
{
|
|
return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
|
|
}
|
|
|
|
template <typename T>
|
|
JBTs<T> ToJBTs(BTs<T> const& bts)
|
|
{
|
|
std::vector<JBTIndex> ids;
|
|
ids.reserve(bts.Backtraces.size());
|
|
for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
|
|
ids.emplace_back(this->Backtraces.Add(backtrace));
|
|
}
|
|
return JBTs<T>(bts.Value, ids);
|
|
}
|
|
|
|
void ProcessLanguages();
|
|
void ProcessLanguage(std::string const& lang);
|
|
|
|
Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si);
|
|
CompileData BuildCompileData(cmSourceFile* sf);
|
|
CompileData MergeCompileData(CompileData const& fd);
|
|
Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf,
|
|
Json::ArrayIndex si);
|
|
void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
|
|
void AddBacktrace(Json::Value& object, JBTIndex bt);
|
|
Json::Value DumpPaths();
|
|
Json::Value DumpCompileData(CompileData const& cd);
|
|
Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
|
|
Json::Value DumpFramework(CompileData::IncludeEntry const& fw);
|
|
Json::Value DumpPrecompileHeader(JBT<std::string> const& header);
|
|
Json::Value DumpLanguageStandard(JBTs<std::string> const& standard);
|
|
Json::Value DumpDefine(JBT<std::string> const& def);
|
|
std::pair<Json::Value, FileSetDatabase> DumpFileSets();
|
|
Json::Value DumpFileSet(cmFileSet const* fs,
|
|
std::vector<std::string> const& directories);
|
|
Json::Value DumpSources(FileSetDatabase const& fsdb);
|
|
Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
|
|
Json::ArrayIndex si, FileSetDatabase const& fsdb);
|
|
Json::Value DumpSourceGroups();
|
|
Json::Value DumpSourceGroup(SourceGroup& sg);
|
|
Json::Value DumpCompileGroups();
|
|
Json::Value DumpCompileGroup(CompileGroup& cg);
|
|
Json::Value DumpSysroot(std::string const& path);
|
|
Json::Value DumpInstall();
|
|
Json::Value DumpInstallPrefix();
|
|
Json::Value DumpInstallDestinations();
|
|
Json::Value DumpInstallDestination(cmInstallTargetGenerator* itGen);
|
|
Json::Value DumpArtifacts();
|
|
Json::Value DumpLink();
|
|
Json::Value DumpArchive();
|
|
Json::Value DumpLinkCommandFragments();
|
|
Json::Value DumpCommandFragments(std::vector<JBT<std::string>> const& frags);
|
|
Json::Value DumpCommandFragment(JBT<std::string> const& frag,
|
|
std::string const& role = std::string());
|
|
Json::Value DumpDependencies();
|
|
Json::Value DumpDependency(cmTargetDepend const& td);
|
|
Json::Value DumpFolder();
|
|
Json::Value DumpLauncher(char const* name, char const* type);
|
|
Json::Value DumpLaunchers();
|
|
|
|
Json::Value DumpDebugger();
|
|
|
|
public:
|
|
Target(cmGeneratorTarget* gt, std::string const& config);
|
|
Json::Value Dump();
|
|
};
|
|
|
|
Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned int version)
|
|
: FileAPI(fileAPI)
|
|
, Version(version)
|
|
{
|
|
}
|
|
|
|
Json::Value Codemodel::Dump()
|
|
{
|
|
Json::Value codemodel = Json::objectValue;
|
|
|
|
codemodel["paths"] = this->DumpPaths();
|
|
codemodel["configurations"] = this->DumpConfigurations();
|
|
|
|
return codemodel;
|
|
}
|
|
|
|
Json::Value Codemodel::DumpPaths()
|
|
{
|
|
Json::Value paths = Json::objectValue;
|
|
paths["source"] = this->FileAPI.GetCMakeInstance()->GetHomeDirectory();
|
|
paths["build"] = this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory();
|
|
return paths;
|
|
}
|
|
|
|
Json::Value Codemodel::DumpConfigurations()
|
|
{
|
|
Json::Value configurations = Json::arrayValue;
|
|
cmGlobalGenerator* gg =
|
|
this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
|
|
auto const& makefiles = gg->GetMakefiles();
|
|
if (!makefiles.empty()) {
|
|
std::vector<std::string> const& configs =
|
|
makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
|
|
for (std::string const& config : configs) {
|
|
configurations.append(this->DumpConfiguration(config));
|
|
}
|
|
}
|
|
return configurations;
|
|
}
|
|
|
|
Json::Value Codemodel::DumpConfiguration(std::string const& config)
|
|
{
|
|
CodemodelConfig configuration(this->FileAPI, this->Version, config);
|
|
return configuration.Dump();
|
|
}
|
|
|
|
CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned int version,
|
|
std::string const& config)
|
|
: FileAPI(fileAPI)
|
|
, Version(version)
|
|
, Config(config)
|
|
, TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
|
|
, TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
|
|
{
|
|
static_cast<void>(this->Version);
|
|
}
|
|
|
|
Json::Value CodemodelConfig::Dump()
|
|
{
|
|
Json::Value configuration = Json::objectValue;
|
|
configuration["name"] = this->Config;
|
|
this->ProcessDirectories();
|
|
configuration["targets"] = this->DumpTargets();
|
|
configuration["directories"] = this->DumpDirectories();
|
|
configuration["projects"] = this->DumpProjects();
|
|
return configuration;
|
|
}
|
|
|
|
void CodemodelConfig::ProcessDirectories()
|
|
{
|
|
cmGlobalGenerator* gg =
|
|
this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
|
|
auto const& localGens = gg->GetLocalGenerators();
|
|
|
|
// Add directories in forward order to process parents before children.
|
|
this->Directories.reserve(localGens.size());
|
|
for (auto const& lg : localGens) {
|
|
auto directoryIndex =
|
|
static_cast<Json::ArrayIndex>(this->Directories.size());
|
|
this->Directories.emplace_back();
|
|
Directory& d = this->Directories[directoryIndex];
|
|
d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory();
|
|
d.LocalGenerator = lg.get();
|
|
this->DirectoryMap[d.Snapshot] = directoryIndex;
|
|
|
|
d.ProjectIndex = this->AddProject(d.Snapshot);
|
|
this->Projects[d.ProjectIndex].DirectoryIndexes.append(directoryIndex);
|
|
}
|
|
|
|
// Update directories in reverse order to process children before parents.
|
|
for (auto di = this->Directories.rbegin(); di != this->Directories.rend();
|
|
++di) {
|
|
Directory& d = *di;
|
|
|
|
// Accumulate the presence of install rules on the way up.
|
|
for (auto const& gen :
|
|
d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
|
|
if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) {
|
|
d.HasInstallRule = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!d.HasInstallRule) {
|
|
for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
|
|
cmStateSnapshot childDir = child.GetBuildsystemDirectory();
|
|
Json::ArrayIndex const childIndex = this->GetDirectoryIndex(childDir);
|
|
if (this->Directories[childIndex].HasInstallRule) {
|
|
d.HasInstallRule = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmLocalGenerator const* lg)
|
|
{
|
|
return this->GetDirectoryIndex(
|
|
lg->GetStateSnapshot().GetBuildsystemDirectory());
|
|
}
|
|
|
|
Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmStateSnapshot s)
|
|
{
|
|
auto i = this->DirectoryMap.find(s);
|
|
assert(i != this->DirectoryMap.end());
|
|
return i->second;
|
|
}
|
|
|
|
Json::ArrayIndex CodemodelConfig::AddProject(cmStateSnapshot s)
|
|
{
|
|
cmStateSnapshot ps = s.GetBuildsystemDirectoryParent();
|
|
if (ps.IsValid() && ps.GetProjectName() == s.GetProjectName()) {
|
|
// This directory is part of its parent directory project.
|
|
Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
|
|
return this->Directories[parentDirIndex].ProjectIndex;
|
|
}
|
|
|
|
// This directory starts a new project.
|
|
auto projectIndex = static_cast<Json::ArrayIndex>(this->Projects.size());
|
|
this->Projects.emplace_back();
|
|
Project& p = this->Projects[projectIndex];
|
|
p.Snapshot = s;
|
|
this->ProjectMap[s] = projectIndex;
|
|
if (ps.IsValid()) {
|
|
Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
|
|
p.ParentIndex = this->Directories[parentDirIndex].ProjectIndex;
|
|
this->Projects[p.ParentIndex].ChildIndexes.append(projectIndex);
|
|
}
|
|
return projectIndex;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpTargets()
|
|
{
|
|
Json::Value targets = Json::arrayValue;
|
|
|
|
std::vector<cmGeneratorTarget*> targetList;
|
|
cmGlobalGenerator* gg =
|
|
this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
|
|
for (auto const& lg : gg->GetLocalGenerators()) {
|
|
cm::append(targetList, lg->GetGeneratorTargets());
|
|
}
|
|
std::sort(targetList.begin(), targetList.end(),
|
|
[](cmGeneratorTarget* l, cmGeneratorTarget* r) {
|
|
return l->GetName() < r->GetName();
|
|
});
|
|
|
|
for (cmGeneratorTarget* gt : targetList) {
|
|
if (gt->GetType() == cmStateEnums::GLOBAL_TARGET ||
|
|
!gt->IsInBuildSystem()) {
|
|
continue;
|
|
}
|
|
|
|
// Ignore targets starting with `__cmake_` as they are internal.
|
|
if (cmHasLiteralPrefix(gt->GetName(), "__cmake_")) {
|
|
continue;
|
|
}
|
|
|
|
targets.append(this->DumpTarget(gt, targets.size()));
|
|
}
|
|
|
|
return targets;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
|
|
Json::ArrayIndex ti)
|
|
{
|
|
Target t(gt, this->Config);
|
|
std::string prefix = "target-" + gt->GetName();
|
|
if (!this->Config.empty()) {
|
|
prefix += "-" + this->Config;
|
|
}
|
|
Json::Value target = this->FileAPI.MaybeJsonFile(t.Dump(), prefix);
|
|
target["name"] = gt->GetName();
|
|
target["id"] = TargetId(gt, this->TopBuild);
|
|
|
|
// Cross-reference directory containing target.
|
|
Json::ArrayIndex di = this->GetDirectoryIndex(gt->GetLocalGenerator());
|
|
target["directoryIndex"] = di;
|
|
this->Directories[di].TargetIndexes.append(ti);
|
|
|
|
// Cross-reference project containing target.
|
|
Json::ArrayIndex pi = this->Directories[di].ProjectIndex;
|
|
target["projectIndex"] = pi;
|
|
this->Projects[pi].TargetIndexes.append(ti);
|
|
|
|
this->TargetIndexMap[gt] = ti;
|
|
|
|
return target;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpDirectories()
|
|
{
|
|
Json::Value directories = Json::arrayValue;
|
|
for (Directory& d : this->Directories) {
|
|
directories.append(this->DumpDirectory(d));
|
|
}
|
|
return directories;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpDirectory(Directory& d)
|
|
{
|
|
Json::Value directory = this->DumpDirectoryObject(d);
|
|
|
|
std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
|
|
directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
|
|
|
|
std::string buildDir = d.Snapshot.GetDirectory().GetCurrentBinary();
|
|
directory["build"] = RelativeIfUnder(this->TopBuild, buildDir);
|
|
|
|
cmStateSnapshot parentDir = d.Snapshot.GetBuildsystemDirectoryParent();
|
|
if (parentDir.IsValid()) {
|
|
directory["parentIndex"] = this->GetDirectoryIndex(parentDir);
|
|
}
|
|
|
|
Json::Value childIndexes = Json::arrayValue;
|
|
for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
|
|
childIndexes.append(
|
|
this->GetDirectoryIndex(child.GetBuildsystemDirectory()));
|
|
}
|
|
if (!childIndexes.empty()) {
|
|
directory["childIndexes"] = std::move(childIndexes);
|
|
}
|
|
|
|
directory["projectIndex"] = d.ProjectIndex;
|
|
|
|
if (!d.TargetIndexes.empty()) {
|
|
directory["targetIndexes"] = std::move(d.TargetIndexes);
|
|
}
|
|
|
|
Json::Value minimumCMakeVersion = this->DumpMinimumCMakeVersion(d.Snapshot);
|
|
if (!minimumCMakeVersion.isNull()) {
|
|
directory["minimumCMakeVersion"] = std::move(minimumCMakeVersion);
|
|
}
|
|
|
|
if (d.HasInstallRule) {
|
|
directory["hasInstallRule"] = true;
|
|
}
|
|
|
|
return directory;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
|
|
{
|
|
std::string prefix = "directory";
|
|
std::string sourceDirRel = RelativeIfUnder(
|
|
this->TopSource, d.Snapshot.GetDirectory().GetCurrentSource());
|
|
std::string buildDirRel = RelativeIfUnder(
|
|
this->TopBuild, d.Snapshot.GetDirectory().GetCurrentBinary());
|
|
if (!cmSystemTools::FileIsFullPath(buildDirRel)) {
|
|
prefix = cmStrCat(prefix, '-', buildDirRel);
|
|
} else if (!cmSystemTools::FileIsFullPath(sourceDirRel)) {
|
|
prefix = cmStrCat(prefix, '-', sourceDirRel);
|
|
}
|
|
for (char& c : prefix) {
|
|
if (c == '/' || c == '\\') {
|
|
c = '.';
|
|
}
|
|
}
|
|
if (!this->Config.empty()) {
|
|
prefix += "-" + this->Config;
|
|
}
|
|
|
|
DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
|
|
return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpProjects()
|
|
{
|
|
Json::Value projects = Json::arrayValue;
|
|
for (Project& p : this->Projects) {
|
|
projects.append(this->DumpProject(p));
|
|
}
|
|
return projects;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpProject(Project& p)
|
|
{
|
|
Json::Value project = Json::objectValue;
|
|
|
|
project["name"] = p.Snapshot.GetProjectName();
|
|
|
|
if (p.ParentIndex != Project::NoParentIndex) {
|
|
project["parentIndex"] = p.ParentIndex;
|
|
}
|
|
|
|
if (!p.ChildIndexes.empty()) {
|
|
project["childIndexes"] = std::move(p.ChildIndexes);
|
|
}
|
|
|
|
project["directoryIndexes"] = std::move(p.DirectoryIndexes);
|
|
|
|
if (!p.TargetIndexes.empty()) {
|
|
project["targetIndexes"] = std::move(p.TargetIndexes);
|
|
}
|
|
|
|
return project;
|
|
}
|
|
|
|
Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
|
|
{
|
|
Json::Value minimumCMakeVersion;
|
|
if (cmValue def = s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
|
|
minimumCMakeVersion = Json::objectValue;
|
|
minimumCMakeVersion["string"] = *def;
|
|
}
|
|
return minimumCMakeVersion;
|
|
}
|
|
|
|
DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
|
|
std::string const& config,
|
|
TargetIndexMapType& targetIndexMap)
|
|
: LG(lg)
|
|
, Config(config)
|
|
, TargetIndexMap(targetIndexMap)
|
|
, TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
|
|
, TopBuild(
|
|
lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
|
|
, Backtraces(this->TopSource)
|
|
{
|
|
}
|
|
|
|
Json::Value DirectoryObject::Dump()
|
|
{
|
|
Json::Value directoryObject = Json::objectValue;
|
|
directoryObject["paths"] = this->DumpPaths();
|
|
directoryObject["installers"] = this->DumpInstallers();
|
|
directoryObject["backtraceGraph"] = this->Backtraces.Dump();
|
|
return directoryObject;
|
|
}
|
|
|
|
void DirectoryObject::AddBacktrace(Json::Value& object,
|
|
cmListFileBacktrace const& bt)
|
|
{
|
|
if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
|
|
object["backtrace"] = backtrace.Index;
|
|
}
|
|
}
|
|
|
|
Json::Value DirectoryObject::DumpPaths()
|
|
{
|
|
Json::Value paths = Json::objectValue;
|
|
|
|
std::string const& sourceDir = this->LG->GetCurrentSourceDirectory();
|
|
paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
|
|
|
|
std::string const& buildDir = this->LG->GetCurrentBinaryDirectory();
|
|
paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
|
|
|
|
return paths;
|
|
}
|
|
|
|
Json::Value DirectoryObject::DumpInstallers()
|
|
{
|
|
Json::Value installers = Json::arrayValue;
|
|
for (auto const& gen : this->LG->GetMakefile()->GetInstallGenerators()) {
|
|
Json::Value installer = this->DumpInstaller(gen.get());
|
|
if (!installer.empty()) {
|
|
installers.append(std::move(installer)); // NOLINT(*)
|
|
}
|
|
}
|
|
return installers;
|
|
}
|
|
|
|
Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
|
|
{
|
|
assert(gen);
|
|
Json::Value installer = Json::objectValue;
|
|
|
|
// Exclude subdirectory installers and file(GET_RUNTIME_DEPENDENCIES)
|
|
// installers. They are implementation details.
|
|
if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen) ||
|
|
dynamic_cast<cmInstallGetRuntimeDependenciesGenerator*>(gen)) {
|
|
return installer;
|
|
}
|
|
|
|
// Exclude installers not used in this configuration.
|
|
if (!gen->InstallsForConfig(this->Config)) {
|
|
return installer;
|
|
}
|
|
|
|
// Add fields specific to each kind of install generator.
|
|
if (auto* installTarget = dynamic_cast<cmInstallTargetGenerator*>(gen)) {
|
|
cmInstallTargetGenerator::Files const& files =
|
|
installTarget->GetFiles(this->Config);
|
|
if (files.From.empty()) {
|
|
return installer;
|
|
}
|
|
|
|
installer["type"] = "target";
|
|
installer["destination"] = installTarget->GetDestination(this->Config);
|
|
installer["targetId"] =
|
|
TargetId(installTarget->GetTarget(), this->TopBuild);
|
|
installer["targetIndex"] =
|
|
this->TargetIndexMap[installTarget->GetTarget()];
|
|
|
|
std::string fromDir = files.FromDir;
|
|
if (!fromDir.empty()) {
|
|
fromDir.push_back('/');
|
|
}
|
|
|
|
std::string toDir = files.ToDir;
|
|
if (!toDir.empty()) {
|
|
toDir.push_back('/');
|
|
}
|
|
|
|
Json::Value paths = Json::arrayValue;
|
|
for (size_t i = 0; i < files.From.size(); ++i) {
|
|
std::string const& fromPath = cmStrCat(fromDir, files.From[i]);
|
|
std::string const& toPath = cmStrCat(toDir, files.To[i]);
|
|
paths.append(this->DumpInstallerPath(this->TopBuild, fromPath, toPath));
|
|
}
|
|
installer["paths"] = std::move(paths);
|
|
|
|
if (installTarget->GetOptional()) {
|
|
installer["isOptional"] = true;
|
|
}
|
|
|
|
if (installTarget->IsImportLibrary()) {
|
|
installer["targetIsImportLibrary"] = true;
|
|
}
|
|
|
|
switch (files.NamelinkMode) {
|
|
case cmInstallTargetGenerator::NamelinkModeNone:
|
|
break;
|
|
case cmInstallTargetGenerator::NamelinkModeOnly:
|
|
installer["targetInstallNamelink"] = "only";
|
|
break;
|
|
case cmInstallTargetGenerator::NamelinkModeSkip:
|
|
installer["targetInstallNamelink"] = "skip";
|
|
break;
|
|
}
|
|
|
|
// FIXME: Parse FilePermissions to provide structured information.
|
|
// FIXME: Thread EXPORT name through from install() call.
|
|
} else if (auto* installFiles =
|
|
dynamic_cast<cmInstallFilesGenerator*>(gen)) {
|
|
std::vector<std::string> const& files =
|
|
installFiles->GetFiles(this->Config);
|
|
if (files.empty()) {
|
|
return installer;
|
|
}
|
|
|
|
installer["type"] = "file";
|
|
installer["destination"] = installFiles->GetDestination(this->Config);
|
|
Json::Value paths = Json::arrayValue;
|
|
std::string const& rename = installFiles->GetRename(this->Config);
|
|
if (!rename.empty() && files.size() == 1) {
|
|
paths.append(this->DumpInstallerPath(this->TopSource, files[0], rename));
|
|
} else {
|
|
for (std::string const& file : installFiles->GetFiles(this->Config)) {
|
|
paths.append(RelativeIfUnder(this->TopSource, file));
|
|
}
|
|
}
|
|
installer["paths"] = std::move(paths);
|
|
if (installFiles->GetOptional()) {
|
|
installer["isOptional"] = true;
|
|
}
|
|
// FIXME: Parse FilePermissions to provide structured information.
|
|
} else if (auto* installDir =
|
|
dynamic_cast<cmInstallDirectoryGenerator*>(gen)) {
|
|
std::vector<std::string> const& dirs =
|
|
installDir->GetDirectories(this->Config);
|
|
if (dirs.empty()) {
|
|
return installer;
|
|
}
|
|
|
|
installer["type"] = "directory";
|
|
installer["destination"] = installDir->GetDestination(this->Config);
|
|
Json::Value paths = Json::arrayValue;
|
|
for (std::string const& dir : dirs) {
|
|
if (cmHasLiteralSuffix(dir, "/")) {
|
|
paths.append(this->DumpInstallerPath(
|
|
this->TopSource, dir.substr(0, dir.size() - 1), "."));
|
|
} else {
|
|
paths.append(this->DumpInstallerPath(
|
|
this->TopSource, dir, cmSystemTools::GetFilenameName(dir)));
|
|
}
|
|
}
|
|
installer["paths"] = std::move(paths);
|
|
if (installDir->GetOptional()) {
|
|
installer["isOptional"] = true;
|
|
}
|
|
// FIXME: Parse FilePermissions, DirPermissions, and LiteralArguments.
|
|
// to provide structured information.
|
|
} else if (auto* installExport =
|
|
dynamic_cast<cmInstallExportGenerator*>(gen)) {
|
|
installer["type"] = "export";
|
|
installer["destination"] = installExport->GetDestination();
|
|
cmExportSet* exportSet = installExport->GetExportSet();
|
|
installer["exportName"] = exportSet->GetName();
|
|
installer["exportTargets"] = this->DumpInstallerExportTargets(exportSet);
|
|
Json::Value paths = Json::arrayValue;
|
|
paths.append(
|
|
RelativeIfUnder(this->TopBuild, installExport->GetMainImportFile()));
|
|
installer["paths"] = std::move(paths);
|
|
} else if (auto* installScript =
|
|
dynamic_cast<cmInstallScriptGenerator*>(gen)) {
|
|
if (installScript->IsCode()) {
|
|
installer["type"] = "code";
|
|
} else {
|
|
installer["type"] = "script";
|
|
installer["scriptFile"] = RelativeIfUnder(
|
|
this->TopSource, installScript->GetScript(this->Config));
|
|
}
|
|
} else if (auto* installImportedRuntimeArtifacts =
|
|
dynamic_cast<cmInstallImportedRuntimeArtifactsGenerator*>(
|
|
gen)) {
|
|
installer["type"] = "importedRuntimeArtifacts";
|
|
installer["destination"] =
|
|
installImportedRuntimeArtifacts->GetDestination(this->Config);
|
|
if (installImportedRuntimeArtifacts->GetOptional()) {
|
|
installer["isOptional"] = true;
|
|
}
|
|
} else if (auto* installRuntimeDependencySet =
|
|
dynamic_cast<cmInstallRuntimeDependencySetGenerator*>(gen)) {
|
|
installer["type"] = "runtimeDependencySet";
|
|
installer["destination"] =
|
|
installRuntimeDependencySet->GetDestination(this->Config);
|
|
std::string name(
|
|
installRuntimeDependencySet->GetRuntimeDependencySet()->GetName());
|
|
if (!name.empty()) {
|
|
installer["runtimeDependencySetName"] = name;
|
|
}
|
|
switch (installRuntimeDependencySet->GetDependencyType()) {
|
|
case cmInstallRuntimeDependencySetGenerator::DependencyType::Framework:
|
|
installer["runtimeDependencySetType"] = "framework";
|
|
break;
|
|
case cmInstallRuntimeDependencySetGenerator::DependencyType::Library:
|
|
installer["runtimeDependencySetType"] = "library";
|
|
break;
|
|
}
|
|
} else if (auto* installFileSet =
|
|
dynamic_cast<cmInstallFileSetGenerator*>(gen)) {
|
|
auto const* fileSet = installFileSet->GetFileSet();
|
|
|
|
// No fileSet by that name exists for the associated target
|
|
if (!fileSet) {
|
|
return installer;
|
|
}
|
|
|
|
installer["type"] = "fileSet";
|
|
installer["destination"] = installFileSet->GetDestination(this->Config);
|
|
|
|
auto* target = installFileSet->GetTarget();
|
|
|
|
auto dirCges = fileSet->CompileDirectoryEntries();
|
|
auto dirs = fileSet->EvaluateDirectoryEntries(
|
|
dirCges, target->GetLocalGenerator(), this->Config, target);
|
|
|
|
auto entryCges = fileSet->CompileFileEntries();
|
|
std::map<std::string, std::vector<std::string>> entries;
|
|
for (auto const& entryCge : entryCges) {
|
|
fileSet->EvaluateFileEntry(dirs, entries, entryCge,
|
|
target->GetLocalGenerator(), this->Config,
|
|
target);
|
|
}
|
|
|
|
Json::Value files = Json::arrayValue;
|
|
for (auto const& it : entries) {
|
|
auto dir = it.first;
|
|
if (!dir.empty()) {
|
|
dir += '/';
|
|
}
|
|
for (auto const& file : it.second) {
|
|
files.append(this->DumpInstallerPath(
|
|
this->TopSource, file,
|
|
cmStrCat(dir, cmSystemTools::GetFilenameName(file))));
|
|
}
|
|
}
|
|
installer["paths"] = std::move(files);
|
|
installer["fileSetName"] = fileSet->GetName();
|
|
installer["fileSetType"] = fileSet->GetType();
|
|
installer["fileSetDirectories"] = Json::arrayValue;
|
|
for (auto const& dir : dirs) {
|
|
installer["fileSetDirectories"].append(
|
|
RelativeIfUnder(this->TopSource, dir));
|
|
}
|
|
installer["fileSetTarget"] = Json::objectValue;
|
|
installer["fileSetTarget"]["id"] = TargetId(target, this->TopBuild);
|
|
installer["fileSetTarget"]["index"] = this->TargetIndexMap[target];
|
|
|
|
if (installFileSet->GetOptional()) {
|
|
installer["isOptional"] = true;
|
|
}
|
|
} else if (auto* cxxModuleBmi =
|
|
dynamic_cast<cmInstallCxxModuleBmiGenerator*>(gen)) {
|
|
installer["type"] = "cxxModuleBmi";
|
|
installer["destination"] = cxxModuleBmi->GetDestination(this->Config);
|
|
|
|
auto const* target = cxxModuleBmi->GetTarget();
|
|
installer["cxxModuleBmiTarget"] = Json::objectValue;
|
|
installer["cxxModuleBmiTarget"]["id"] = TargetId(target, this->TopBuild);
|
|
installer["cxxModuleBmiTarget"]["index"] = this->TargetIndexMap[target];
|
|
|
|
// FIXME: Parse FilePermissions.
|
|
// FIXME: Parse MessageLevel.
|
|
if (cxxModuleBmi->GetOptional()) {
|
|
installer["isOptional"] = true;
|
|
}
|
|
}
|
|
|
|
// Add fields common to all install generators.
|
|
installer["component"] = gen->GetComponent();
|
|
if (gen->GetExcludeFromAll()) {
|
|
installer["isExcludeFromAll"] = true;
|
|
}
|
|
|
|
if (gen->GetAllComponentsFlag()) {
|
|
installer["isForAllComponents"] = true;
|
|
}
|
|
|
|
this->AddBacktrace(installer, gen->GetBacktrace());
|
|
|
|
return installer;
|
|
}
|
|
|
|
Json::Value DirectoryObject::DumpInstallerExportTargets(cmExportSet* exp)
|
|
{
|
|
Json::Value targets = Json::arrayValue;
|
|
for (auto const& targetExport : exp->GetTargetExports()) {
|
|
Json::Value target = Json::objectValue;
|
|
target["id"] = TargetId(targetExport->Target, this->TopBuild);
|
|
target["index"] = this->TargetIndexMap[targetExport->Target];
|
|
targets.append(std::move(target)); // NOLINT(*)
|
|
}
|
|
return targets;
|
|
}
|
|
|
|
Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
|
|
std::string const& fromPathIn,
|
|
std::string const& toPath)
|
|
{
|
|
Json::Value installPath;
|
|
|
|
std::string fromPath = RelativeIfUnder(top, fromPathIn);
|
|
|
|
// If toPath is the last component of fromPath, use just fromPath.
|
|
if (toPath.find_first_of('/') == std::string::npos &&
|
|
cmHasSuffix(fromPath, toPath) &&
|
|
(fromPath.size() == toPath.size() ||
|
|
fromPath[fromPath.size() - toPath.size() - 1] == '/')) {
|
|
installPath = fromPath;
|
|
} else {
|
|
installPath = Json::objectValue;
|
|
installPath["from"] = fromPath;
|
|
installPath["to"] = toPath;
|
|
}
|
|
|
|
return installPath;
|
|
}
|
|
|
|
Target::Target(cmGeneratorTarget* gt, std::string const& config)
|
|
: GT(gt)
|
|
, Config(config)
|
|
, TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
|
|
, TopBuild(
|
|
gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
|
|
, SourceGroupsLocal(this->GT->Makefile->GetSourceGroups())
|
|
, Backtraces(this->TopSource)
|
|
{
|
|
}
|
|
|
|
Json::Value Target::Dump()
|
|
{
|
|
Json::Value target = Json::objectValue;
|
|
|
|
cmStateEnums::TargetType const type = this->GT->GetType();
|
|
|
|
target["name"] = this->GT->GetName();
|
|
target["type"] = cmState::GetTargetTypeName(type);
|
|
target["id"] = TargetId(this->GT, this->TopBuild);
|
|
target["paths"] = this->DumpPaths();
|
|
if (this->GT->Target->GetIsGeneratorProvided()) {
|
|
target["isGeneratorProvided"] = true;
|
|
}
|
|
|
|
this->AddBacktrace(target, this->GT->GetBacktrace());
|
|
|
|
if (this->GT->Target->GetHaveInstallRule()) {
|
|
target["install"] = this->DumpInstall();
|
|
}
|
|
|
|
if (this->GT->HaveWellDefinedOutputFiles()) {
|
|
Json::Value artifacts = this->DumpArtifacts();
|
|
if (!artifacts.empty()) {
|
|
target["artifacts"] = std::move(artifacts);
|
|
}
|
|
}
|
|
|
|
if (type == cmStateEnums::EXECUTABLE ||
|
|
type == cmStateEnums::SHARED_LIBRARY ||
|
|
type == cmStateEnums::MODULE_LIBRARY) {
|
|
target["nameOnDisk"] = this->GT->GetFullName(this->Config);
|
|
target["link"] = this->DumpLink();
|
|
} else if (type == cmStateEnums::STATIC_LIBRARY) {
|
|
target["nameOnDisk"] = this->GT->GetFullName(this->Config);
|
|
target["archive"] = this->DumpArchive();
|
|
}
|
|
|
|
if (type == cmStateEnums::EXECUTABLE) {
|
|
Json::Value launchers = this->DumpLaunchers();
|
|
if (!launchers.empty()) {
|
|
target["launchers"] = std::move(launchers);
|
|
}
|
|
}
|
|
|
|
Json::Value dependencies = this->DumpDependencies();
|
|
if (!dependencies.empty()) {
|
|
target["dependencies"] = dependencies;
|
|
}
|
|
|
|
{
|
|
this->ProcessLanguages();
|
|
|
|
auto fileSetInfo = this->DumpFileSets();
|
|
|
|
if (!fileSetInfo.first.isNull()) {
|
|
target["fileSets"] = fileSetInfo.first;
|
|
}
|
|
|
|
target["sources"] = this->DumpSources(fileSetInfo.second);
|
|
|
|
Json::Value folder = this->DumpFolder();
|
|
if (!folder.isNull()) {
|
|
target["folder"] = std::move(folder);
|
|
}
|
|
|
|
Json::Value sourceGroups = this->DumpSourceGroups();
|
|
if (!sourceGroups.empty()) {
|
|
target["sourceGroups"] = std::move(sourceGroups);
|
|
}
|
|
|
|
Json::Value compileGroups = this->DumpCompileGroups();
|
|
if (!compileGroups.empty()) {
|
|
target["compileGroups"] = std::move(compileGroups);
|
|
}
|
|
}
|
|
|
|
target["backtraceGraph"] = this->Backtraces.Dump();
|
|
|
|
Json::Value debugger = this->DumpDebugger();
|
|
if (!debugger.isNull()) {
|
|
target["debugger"] = std::move(debugger);
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
void Target::ProcessLanguages()
|
|
{
|
|
std::set<std::string> languages;
|
|
this->GT->GetLanguages(languages, this->Config);
|
|
for (std::string const& lang : languages) {
|
|
this->ProcessLanguage(lang);
|
|
}
|
|
}
|
|
|
|
void Target::ProcessLanguage(std::string const& lang)
|
|
{
|
|
CompileData& cd = this->CompileDataMap[lang];
|
|
cd.Language = lang;
|
|
if (cmValue sysrootCompile =
|
|
this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
|
|
cd.Sysroot = *sysrootCompile;
|
|
} else if (cmValue sysroot =
|
|
this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
|
|
cd.Sysroot = *sysroot;
|
|
}
|
|
cmLocalGenerator* lg = this->GT->GetLocalGenerator();
|
|
{
|
|
// FIXME: Add flags from end section of ExpandRuleVariable,
|
|
// which may need to be factored out.
|
|
std::vector<BT<std::string>> flags =
|
|
lg->GetTargetCompileFlags(this->GT, this->Config, lang);
|
|
|
|
cd.Flags.reserve(flags.size());
|
|
for (const BT<std::string>& f : flags) {
|
|
cd.Flags.emplace_back(this->ToJBT(f));
|
|
}
|
|
}
|
|
std::set<BT<std::string>> defines =
|
|
lg->GetTargetDefines(this->GT, this->Config, lang);
|
|
cd.Defines.reserve(defines.size());
|
|
for (BT<std::string> const& d : defines) {
|
|
cd.Defines.emplace_back(this->ToJBT(d));
|
|
}
|
|
std::vector<BT<std::string>> includePathList =
|
|
lg->GetIncludeDirectories(this->GT, lang, this->Config);
|
|
for (BT<std::string> const& i : includePathList) {
|
|
if (this->GT->IsApple() && cmSystemTools::IsPathToFramework(i.Value)) {
|
|
cd.Frameworks.emplace_back(
|
|
this->ToJBT(i),
|
|
this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
|
|
} else {
|
|
cd.Includes.emplace_back(
|
|
this->ToJBT(i),
|
|
this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
|
|
}
|
|
}
|
|
std::vector<BT<std::string>> precompileHeaders =
|
|
this->GT->GetPrecompileHeaders(this->Config, lang);
|
|
for (BT<std::string> const& pch : precompileHeaders) {
|
|
cd.PrecompileHeaders.emplace_back(this->ToJBT(pch));
|
|
}
|
|
BTs<std::string> const* languageStandard =
|
|
this->GT->GetLanguageStandardProperty(lang, this->Config);
|
|
if (languageStandard) {
|
|
cd.LanguageStandard = this->ToJBTs(*languageStandard);
|
|
}
|
|
}
|
|
|
|
Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si)
|
|
{
|
|
auto i = this->SourceGroupsMap.find(sg);
|
|
if (i == this->SourceGroupsMap.end()) {
|
|
auto sgIndex = static_cast<Json::ArrayIndex>(this->SourceGroups.size());
|
|
i = this->SourceGroupsMap.emplace(sg, sgIndex).first;
|
|
SourceGroup g;
|
|
g.Name = sg->GetFullName();
|
|
this->SourceGroups.push_back(std::move(g));
|
|
}
|
|
this->SourceGroups[i->second].SourceIndexes.append(si);
|
|
return i->second;
|
|
}
|
|
|
|
CompileData Target::BuildCompileData(cmSourceFile* sf)
|
|
{
|
|
CompileData fd;
|
|
|
|
fd.Language = sf->GetOrDetermineLanguage();
|
|
if (fd.Language.empty()) {
|
|
return fd;
|
|
}
|
|
|
|
cmLocalGenerator* lg = this->GT->GetLocalGenerator();
|
|
cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT,
|
|
fd.Language);
|
|
|
|
std::string const COMPILE_FLAGS("COMPILE_FLAGS");
|
|
if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
|
|
std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
|
|
fd.Flags.emplace_back(std::move(flags), JBTIndex());
|
|
}
|
|
std::string const COMPILE_OPTIONS("COMPILE_OPTIONS");
|
|
for (BT<std::string> tmpOpt : sf->GetCompileOptions()) {
|
|
tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
|
|
// After generator evaluation we need to use the AppendCompileOptions
|
|
// method so we handle situations where backtrace entries have lists
|
|
// and properly escape flags.
|
|
std::string tmp;
|
|
lg->AppendCompileOptions(tmp, tmpOpt.Value);
|
|
BT<std::string> opt(tmp, tmpOpt.Backtrace);
|
|
fd.Flags.emplace_back(this->ToJBT(opt));
|
|
}
|
|
|
|
// Add precompile headers compile options.
|
|
std::vector<std::string> pchArchs =
|
|
this->GT->GetPchArchs(this->Config, fd.Language);
|
|
|
|
std::unordered_map<std::string, std::string> pchSources;
|
|
for (std::string const& arch : pchArchs) {
|
|
std::string const pchSource =
|
|
this->GT->GetPchSource(this->Config, fd.Language, arch);
|
|
if (!pchSource.empty()) {
|
|
pchSources.insert(std::make_pair(pchSource, arch));
|
|
}
|
|
}
|
|
|
|
if (!pchSources.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
|
|
std::string pchOptions;
|
|
auto pchIt = pchSources.find(sf->ResolveFullPath());
|
|
if (pchIt != pchSources.end()) {
|
|
pchOptions = this->GT->GetPchCreateCompileOptions(
|
|
this->Config, fd.Language, pchIt->second);
|
|
} else {
|
|
pchOptions =
|
|
this->GT->GetPchUseCompileOptions(this->Config, fd.Language);
|
|
}
|
|
|
|
BT<std::string> tmpOpt(pchOptions);
|
|
tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
|
|
|
|
// After generator evaluation we need to use the AppendCompileOptions
|
|
// method so we handle situations where backtrace entries have lists
|
|
// and properly escape flags.
|
|
std::string tmp;
|
|
lg->AppendCompileOptions(tmp, tmpOpt.Value);
|
|
BT<std::string> opt(tmp, tmpOpt.Backtrace);
|
|
fd.Flags.emplace_back(this->ToJBT(opt));
|
|
}
|
|
|
|
// Add include directories from source file properties.
|
|
{
|
|
std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
|
|
for (BT<std::string> tmpInclude : sf->GetIncludeDirectories()) {
|
|
tmpInclude.Value =
|
|
genexInterpreter.Evaluate(tmpInclude.Value, INCLUDE_DIRECTORIES);
|
|
|
|
// After generator evaluation we need to use the AppendIncludeDirectories
|
|
// method so we handle situations where backtrace entries have lists.
|
|
std::vector<std::string> tmp;
|
|
lg->AppendIncludeDirectories(tmp, tmpInclude.Value, *sf);
|
|
for (std::string& i : tmp) {
|
|
bool const isSystemInclude =
|
|
this->GT->IsSystemIncludeDirectory(i, this->Config, fd.Language);
|
|
BT<std::string> include(i, tmpInclude.Backtrace);
|
|
if (this->GT->IsApple() && cmSystemTools::IsPathToFramework(i)) {
|
|
fd.Frameworks.emplace_back(this->ToJBT(include), isSystemInclude);
|
|
} else {
|
|
fd.Includes.emplace_back(this->ToJBT(include), isSystemInclude);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string const COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
|
|
std::set<BT<std::string>> fileDefines;
|
|
for (BT<std::string> tmpDef : sf->GetCompileDefinitions()) {
|
|
tmpDef.Value =
|
|
genexInterpreter.Evaluate(tmpDef.Value, COMPILE_DEFINITIONS);
|
|
|
|
// After generator evaluation we need to use the AppendDefines method
|
|
// so we handle situations where backtrace entries have lists.
|
|
std::set<std::string> tmp;
|
|
lg->AppendDefines(tmp, tmpDef.Value);
|
|
for (std::string const& i : tmp) {
|
|
BT<std::string> def(i, tmpDef.Backtrace);
|
|
fileDefines.insert(def);
|
|
}
|
|
}
|
|
|
|
std::set<std::string> configFileDefines;
|
|
std::string const defPropName =
|
|
"COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config);
|
|
if (cmValue config_defs = sf->GetProperty(defPropName)) {
|
|
lg->AppendDefines(
|
|
configFileDefines,
|
|
genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
|
|
}
|
|
|
|
fd.Defines.reserve(fileDefines.size() + configFileDefines.size());
|
|
|
|
for (BT<std::string> const& def : fileDefines) {
|
|
fd.Defines.emplace_back(this->ToJBT(def));
|
|
}
|
|
|
|
for (std::string const& d : configFileDefines) {
|
|
fd.Defines.emplace_back(d, JBTIndex());
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
CompileData Target::MergeCompileData(CompileData const& fd)
|
|
{
|
|
CompileData cd;
|
|
cd.Language = fd.Language;
|
|
if (cd.Language.empty()) {
|
|
return cd;
|
|
}
|
|
CompileData const& td = this->CompileDataMap.at(cd.Language);
|
|
|
|
// All compile groups share the sysroot of the target.
|
|
cd.Sysroot = td.Sysroot;
|
|
|
|
// All compile groups share the precompile headers of the target.
|
|
cd.PrecompileHeaders = td.PrecompileHeaders;
|
|
|
|
// All compile groups share the language standard of the target.
|
|
cd.LanguageStandard = td.LanguageStandard;
|
|
|
|
// Use target-wide flags followed by source-specific flags.
|
|
cd.Flags.reserve(td.Flags.size() + fd.Flags.size());
|
|
cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end());
|
|
cd.Flags.insert(cd.Flags.end(), fd.Flags.begin(), fd.Flags.end());
|
|
|
|
// Use source-specific includes followed by target-wide includes.
|
|
cd.Includes.reserve(fd.Includes.size() + td.Includes.size());
|
|
cd.Includes.insert(cd.Includes.end(), fd.Includes.begin(),
|
|
fd.Includes.end());
|
|
cd.Includes.insert(cd.Includes.end(), td.Includes.begin(),
|
|
td.Includes.end());
|
|
|
|
// Use source-specific frameworks followed by target-wide frameworks.
|
|
cd.Frameworks.reserve(fd.Frameworks.size() + td.Frameworks.size());
|
|
cd.Frameworks.insert(cd.Frameworks.end(), fd.Frameworks.begin(),
|
|
fd.Frameworks.end());
|
|
cd.Frameworks.insert(cd.Frameworks.end(), td.Frameworks.begin(),
|
|
td.Frameworks.end());
|
|
|
|
// Use target-wide defines followed by source-specific defines.
|
|
cd.Defines.reserve(td.Defines.size() + fd.Defines.size());
|
|
cd.Defines.insert(cd.Defines.end(), td.Defines.begin(), td.Defines.end());
|
|
cd.Defines.insert(cd.Defines.end(), fd.Defines.begin(), fd.Defines.end());
|
|
|
|
// De-duplicate defines.
|
|
std::stable_sort(cd.Defines.begin(), cd.Defines.end(),
|
|
JBT<std::string>::ValueLess);
|
|
auto end = std::unique(cd.Defines.begin(), cd.Defines.end(),
|
|
JBT<std::string>::ValueEq);
|
|
cd.Defines.erase(end, cd.Defines.end());
|
|
|
|
return cd;
|
|
}
|
|
|
|
Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf,
|
|
Json::ArrayIndex si)
|
|
{
|
|
CompileData compileData = this->BuildCompileData(sf);
|
|
auto i = this->CompileGroupMap.find(compileData);
|
|
if (i == this->CompileGroupMap.end()) {
|
|
Json::ArrayIndex cgIndex =
|
|
static_cast<Json::ArrayIndex>(this->CompileGroups.size());
|
|
i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first;
|
|
CompileGroup g;
|
|
g.Entry = i;
|
|
this->CompileGroups.push_back(std::move(g));
|
|
}
|
|
this->CompileGroups[i->second].SourceIndexes.append(si);
|
|
return i->second;
|
|
}
|
|
|
|
void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt)
|
|
{
|
|
if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
|
|
object["backtrace"] = backtrace.Index;
|
|
}
|
|
}
|
|
|
|
void Target::AddBacktrace(Json::Value& object, JBTIndex bt)
|
|
{
|
|
if (bt) {
|
|
object["backtrace"] = bt.Index;
|
|
}
|
|
}
|
|
|
|
Json::Value Target::DumpPaths()
|
|
{
|
|
Json::Value paths = Json::objectValue;
|
|
cmLocalGenerator* lg = this->GT->GetLocalGenerator();
|
|
|
|
std::string const& sourceDir = lg->GetCurrentSourceDirectory();
|
|
paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
|
|
|
|
std::string const& buildDir = lg->GetCurrentBinaryDirectory();
|
|
paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
|
|
|
|
return paths;
|
|
}
|
|
|
|
std::pair<Json::Value, Target::FileSetDatabase> Target::DumpFileSets()
|
|
{
|
|
Json::Value fsJson = Json::nullValue;
|
|
FileSetDatabase fsdb;
|
|
|
|
// Build the fileset database.
|
|
auto const* tgt = this->GT->Target;
|
|
auto const& fs_names = tgt->GetAllFileSetNames();
|
|
|
|
if (!fs_names.empty()) {
|
|
fsJson = Json::arrayValue;
|
|
size_t fsIndex = 0;
|
|
for (auto const& fs_name : fs_names) {
|
|
auto const* fs = tgt->GetFileSet(fs_name);
|
|
if (!fs) {
|
|
this->GT->Makefile->IssueMessage(
|
|
MessageType::INTERNAL_ERROR,
|
|
cmStrCat("Target \"", tgt->GetName(),
|
|
"\" is tracked to have file set \"", fs_name,
|
|
"\", but it was not found."));
|
|
continue;
|
|
}
|
|
|
|
auto fileEntries = fs->CompileFileEntries();
|
|
auto directoryEntries = fs->CompileDirectoryEntries();
|
|
|
|
auto directories = fs->EvaluateDirectoryEntries(
|
|
directoryEntries, this->GT->LocalGenerator, this->Config, this->GT);
|
|
|
|
fsJson.append(this->DumpFileSet(fs, directories));
|
|
|
|
std::map<std::string, std::vector<std::string>> files_per_dirs;
|
|
for (auto const& entry : fileEntries) {
|
|
fs->EvaluateFileEntry(directories, files_per_dirs, entry,
|
|
this->GT->LocalGenerator, this->Config,
|
|
this->GT);
|
|
}
|
|
|
|
for (auto const& files_per_dir : files_per_dirs) {
|
|
auto const& dir = files_per_dir.first;
|
|
for (auto const& file : files_per_dir.second) {
|
|
std::string sf_path;
|
|
if (dir.empty()) {
|
|
sf_path = file;
|
|
} else {
|
|
sf_path = cmStrCat(dir, '/', file);
|
|
}
|
|
fsdb[sf_path] = static_cast<Json::ArrayIndex>(fsIndex);
|
|
}
|
|
}
|
|
|
|
++fsIndex;
|
|
}
|
|
}
|
|
|
|
return std::make_pair(fsJson, fsdb);
|
|
}
|
|
|
|
Json::Value Target::DumpFileSet(cmFileSet const* fs,
|
|
std::vector<std::string> const& directories)
|
|
{
|
|
Json::Value fileSet = Json::objectValue;
|
|
|
|
fileSet["name"] = fs->GetName();
|
|
fileSet["type"] = fs->GetType();
|
|
fileSet["visibility"] =
|
|
std::string(cmFileSetVisibilityToName(fs->GetVisibility()));
|
|
|
|
Json::Value baseDirs = Json::arrayValue;
|
|
for (auto const& directory : directories) {
|
|
baseDirs.append(RelativeIfUnder(this->TopSource, directory));
|
|
}
|
|
fileSet["baseDirectories"] = baseDirs;
|
|
|
|
return fileSet;
|
|
}
|
|
|
|
Json::Value Target::DumpSources(FileSetDatabase const& fsdb)
|
|
{
|
|
Json::Value sources = Json::arrayValue;
|
|
cmGeneratorTarget::KindedSources const& kinded =
|
|
this->GT->GetKindedSources(this->Config);
|
|
for (cmGeneratorTarget::SourceAndKind const& sk : kinded.Sources) {
|
|
sources.append(this->DumpSource(sk, sources.size(), fsdb));
|
|
}
|
|
return sources;
|
|
}
|
|
|
|
Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
|
|
Json::ArrayIndex si,
|
|
FileSetDatabase const& fsdb)
|
|
{
|
|
Json::Value source = Json::objectValue;
|
|
|
|
cmSourceFile* sf = sk.Source.Value;
|
|
std::string const path = sf->ResolveFullPath();
|
|
source["path"] = RelativeIfUnder(this->TopSource, path);
|
|
if (sk.Source.Value->GetIsGenerated()) {
|
|
source["isGenerated"] = true;
|
|
}
|
|
this->AddBacktrace(source, sk.Source.Backtrace);
|
|
|
|
auto fsit = fsdb.find(path);
|
|
if (fsit != fsdb.end()) {
|
|
source["fileSetIndex"] = fsit->second;
|
|
}
|
|
|
|
if (cmSourceGroup* sg =
|
|
this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) {
|
|
source["sourceGroupIndex"] = this->AddSourceGroup(sg, si);
|
|
}
|
|
|
|
switch (sk.Kind) {
|
|
case cmGeneratorTarget::SourceKindCxxModuleSource:
|
|
case cmGeneratorTarget::SourceKindObjectSource: {
|
|
source["compileGroupIndex"] =
|
|
this->AddSourceCompileGroup(sk.Source.Value, si);
|
|
} break;
|
|
case cmGeneratorTarget::SourceKindAppManifest:
|
|
case cmGeneratorTarget::SourceKindCertificate:
|
|
case cmGeneratorTarget::SourceKindCustomCommand:
|
|
case cmGeneratorTarget::SourceKindExternalObject:
|
|
case cmGeneratorTarget::SourceKindExtra:
|
|
case cmGeneratorTarget::SourceKindHeader:
|
|
case cmGeneratorTarget::SourceKindIDL:
|
|
case cmGeneratorTarget::SourceKindManifest:
|
|
case cmGeneratorTarget::SourceKindModuleDefinition:
|
|
case cmGeneratorTarget::SourceKindResx:
|
|
case cmGeneratorTarget::SourceKindXaml:
|
|
case cmGeneratorTarget::SourceKindUnityBatched:
|
|
break;
|
|
}
|
|
|
|
return source;
|
|
}
|
|
|
|
Json::Value Target::DumpCompileData(CompileData const& cd)
|
|
{
|
|
Json::Value result = Json::objectValue;
|
|
|
|
if (!cd.Language.empty()) {
|
|
result["language"] = cd.Language;
|
|
}
|
|
if (!cd.Sysroot.empty()) {
|
|
result["sysroot"] = this->DumpSysroot(cd.Sysroot);
|
|
}
|
|
if (!cd.Flags.empty()) {
|
|
result["compileCommandFragments"] = this->DumpCommandFragments(cd.Flags);
|
|
}
|
|
if (!cd.Includes.empty()) {
|
|
Json::Value includes = Json::arrayValue;
|
|
for (auto const& i : cd.Includes) {
|
|
includes.append(this->DumpInclude(i));
|
|
}
|
|
result["includes"] = includes;
|
|
}
|
|
if (!cd.Frameworks.empty()) {
|
|
Json::Value frameworks = Json::arrayValue;
|
|
for (auto const& i : cd.Frameworks) {
|
|
frameworks.append(this->DumpFramework(i));
|
|
}
|
|
result["frameworks"] = frameworks;
|
|
}
|
|
if (!cd.Defines.empty()) {
|
|
Json::Value defines = Json::arrayValue;
|
|
for (JBT<std::string> const& d : cd.Defines) {
|
|
defines.append(this->DumpDefine(d));
|
|
}
|
|
result["defines"] = std::move(defines);
|
|
}
|
|
if (!cd.PrecompileHeaders.empty()) {
|
|
Json::Value precompileHeaders = Json::arrayValue;
|
|
for (JBT<std::string> const& pch : cd.PrecompileHeaders) {
|
|
precompileHeaders.append(this->DumpPrecompileHeader(pch));
|
|
}
|
|
result["precompileHeaders"] = std::move(precompileHeaders);
|
|
}
|
|
if (!cd.LanguageStandard.Value.empty()) {
|
|
result["languageStandard"] =
|
|
this->DumpLanguageStandard(cd.LanguageStandard);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc)
|
|
{
|
|
Json::Value include = Json::objectValue;
|
|
include["path"] = inc.Path.Value;
|
|
if (inc.IsSystem) {
|
|
include["isSystem"] = true;
|
|
}
|
|
this->AddBacktrace(include, inc.Path.Backtrace);
|
|
return include;
|
|
}
|
|
|
|
Json::Value Target::DumpFramework(CompileData::IncludeEntry const& fw)
|
|
{
|
|
// for now, idem as include
|
|
return this->DumpInclude(fw);
|
|
}
|
|
|
|
Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header)
|
|
{
|
|
Json::Value precompileHeader = Json::objectValue;
|
|
precompileHeader["header"] = header.Value;
|
|
this->AddBacktrace(precompileHeader, header.Backtrace);
|
|
return precompileHeader;
|
|
}
|
|
|
|
Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard)
|
|
{
|
|
Json::Value languageStandard = Json::objectValue;
|
|
languageStandard["standard"] = standard.Value;
|
|
if (!standard.Backtraces.empty()) {
|
|
Json::Value backtraces = Json::arrayValue;
|
|
for (JBTIndex backtrace : standard.Backtraces) {
|
|
backtraces.append(backtrace.Index);
|
|
}
|
|
languageStandard["backtraces"] = backtraces;
|
|
}
|
|
return languageStandard;
|
|
}
|
|
|
|
Json::Value Target::DumpDefine(JBT<std::string> const& def)
|
|
{
|
|
Json::Value define = Json::objectValue;
|
|
define["define"] = def.Value;
|
|
this->AddBacktrace(define, def.Backtrace);
|
|
return define;
|
|
}
|
|
|
|
Json::Value Target::DumpSourceGroups()
|
|
{
|
|
Json::Value sourceGroups = Json::arrayValue;
|
|
for (auto& sg : this->SourceGroups) {
|
|
sourceGroups.append(this->DumpSourceGroup(sg));
|
|
}
|
|
return sourceGroups;
|
|
}
|
|
|
|
Json::Value Target::DumpSourceGroup(SourceGroup& sg)
|
|
{
|
|
Json::Value group = Json::objectValue;
|
|
group["name"] = sg.Name;
|
|
group["sourceIndexes"] = std::move(sg.SourceIndexes);
|
|
return group;
|
|
}
|
|
|
|
Json::Value Target::DumpCompileGroups()
|
|
{
|
|
Json::Value compileGroups = Json::arrayValue;
|
|
for (auto& cg : this->CompileGroups) {
|
|
compileGroups.append(this->DumpCompileGroup(cg));
|
|
}
|
|
return compileGroups;
|
|
}
|
|
|
|
Json::Value Target::DumpCompileGroup(CompileGroup& cg)
|
|
{
|
|
Json::Value group =
|
|
this->DumpCompileData(this->MergeCompileData(cg.Entry->first));
|
|
group["sourceIndexes"] = std::move(cg.SourceIndexes);
|
|
return group;
|
|
}
|
|
|
|
Json::Value Target::DumpSysroot(std::string const& path)
|
|
{
|
|
Json::Value sysroot = Json::objectValue;
|
|
sysroot["path"] = path;
|
|
return sysroot;
|
|
}
|
|
|
|
Json::Value Target::DumpInstall()
|
|
{
|
|
Json::Value install = Json::objectValue;
|
|
install["prefix"] = this->DumpInstallPrefix();
|
|
install["destinations"] = this->DumpInstallDestinations();
|
|
return install;
|
|
}
|
|
|
|
Json::Value Target::DumpInstallPrefix()
|
|
{
|
|
Json::Value prefix = Json::objectValue;
|
|
std::string p =
|
|
this->GT->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
|
|
cmSystemTools::ConvertToUnixSlashes(p);
|
|
prefix["path"] = p;
|
|
return prefix;
|
|
}
|
|
|
|
Json::Value Target::DumpInstallDestinations()
|
|
{
|
|
Json::Value destinations = Json::arrayValue;
|
|
auto installGens = this->GT->Target->GetInstallGenerators();
|
|
for (auto* itGen : installGens) {
|
|
destinations.append(this->DumpInstallDestination(itGen));
|
|
}
|
|
return destinations;
|
|
}
|
|
|
|
Json::Value Target::DumpInstallDestination(cmInstallTargetGenerator* itGen)
|
|
{
|
|
Json::Value destination = Json::objectValue;
|
|
destination["path"] = itGen->GetDestination(this->Config);
|
|
this->AddBacktrace(destination, itGen->GetBacktrace());
|
|
return destination;
|
|
}
|
|
|
|
Json::Value Target::DumpArtifacts()
|
|
{
|
|
Json::Value artifacts = Json::arrayValue;
|
|
|
|
// Object libraries have only object files as artifacts.
|
|
if (this->GT->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
|
if (!this->GT->Target->HasKnownObjectFileLocation(nullptr)) {
|
|
return artifacts;
|
|
}
|
|
std::vector<cmSourceFile const*> objectSources;
|
|
this->GT->GetObjectSources(objectSources, this->Config);
|
|
std::string const obj_dir = this->GT->GetObjectDirectory(this->Config);
|
|
for (cmSourceFile const* sf : objectSources) {
|
|
std::string const& obj = this->GT->GetObjectName(sf);
|
|
Json::Value artifact = Json::objectValue;
|
|
artifact["path"] = RelativeIfUnder(this->TopBuild, obj_dir + obj);
|
|
artifacts.append(std::move(artifact)); // NOLINT(*)
|
|
}
|
|
return artifacts;
|
|
}
|
|
|
|
// Other target types always have a "main" artifact.
|
|
{
|
|
Json::Value artifact = Json::objectValue;
|
|
artifact["path"] =
|
|
RelativeIfUnder(this->TopBuild,
|
|
this->GT->GetFullPath(
|
|
this->Config, cmStateEnums::RuntimeBinaryArtifact));
|
|
artifacts.append(std::move(artifact)); // NOLINT(*)
|
|
}
|
|
|
|
// Add Windows-specific artifacts produced by the linker.
|
|
if (this->GT->HasImportLibrary(this->Config)) {
|
|
Json::Value artifact = Json::objectValue;
|
|
artifact["path"] =
|
|
RelativeIfUnder(this->TopBuild,
|
|
this->GT->GetFullPath(
|
|
this->Config, cmStateEnums::ImportLibraryArtifact));
|
|
artifacts.append(std::move(artifact)); // NOLINT(*)
|
|
}
|
|
if (this->GT->IsDLLPlatform() &&
|
|
this->GT->GetType() != cmStateEnums::STATIC_LIBRARY) {
|
|
cmGeneratorTarget::OutputInfo const* output =
|
|
this->GT->GetOutputInfo(this->Config);
|
|
if (output && !output->PdbDir.empty()) {
|
|
Json::Value artifact = Json::objectValue;
|
|
artifact["path"] = RelativeIfUnder(this->TopBuild,
|
|
output->PdbDir + '/' +
|
|
this->GT->GetPDBName(this->Config));
|
|
artifacts.append(std::move(artifact)); // NOLINT(*)
|
|
}
|
|
}
|
|
return artifacts;
|
|
}
|
|
|
|
Json::Value Target::DumpLink()
|
|
{
|
|
Json::Value link = Json::objectValue;
|
|
std::string lang = this->GT->GetLinkerLanguage(this->Config);
|
|
link["language"] = lang;
|
|
{
|
|
Json::Value commandFragments = this->DumpLinkCommandFragments();
|
|
if (!commandFragments.empty()) {
|
|
link["commandFragments"] = std::move(commandFragments);
|
|
}
|
|
}
|
|
if (cmValue sysrootLink =
|
|
this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
|
|
link["sysroot"] = this->DumpSysroot(*sysrootLink);
|
|
} else if (cmValue sysroot =
|
|
this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
|
|
link["sysroot"] = this->DumpSysroot(*sysroot);
|
|
}
|
|
if (this->GT->IsIPOEnabled(lang, this->Config)) {
|
|
link["lto"] = true;
|
|
}
|
|
return link;
|
|
}
|
|
|
|
Json::Value Target::DumpArchive()
|
|
{
|
|
Json::Value archive = Json::objectValue;
|
|
{
|
|
// The "link" fragments not relevant to static libraries are empty.
|
|
Json::Value commandFragments = this->DumpLinkCommandFragments();
|
|
if (!commandFragments.empty()) {
|
|
archive["commandFragments"] = std::move(commandFragments);
|
|
}
|
|
}
|
|
std::string lang = this->GT->GetLinkerLanguage(this->Config);
|
|
if (this->GT->IsIPOEnabled(lang, this->Config)) {
|
|
archive["lto"] = true;
|
|
}
|
|
return archive;
|
|
}
|
|
|
|
Json::Value Target::DumpLinkCommandFragments()
|
|
{
|
|
Json::Value linkFragments = Json::arrayValue;
|
|
|
|
std::string linkLanguageFlags;
|
|
std::vector<BT<std::string>> linkFlags;
|
|
std::string frameworkPath;
|
|
std::vector<BT<std::string>> linkPath;
|
|
std::vector<BT<std::string>> linkLibs;
|
|
cmLocalGenerator* lg = this->GT->GetLocalGenerator();
|
|
cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
|
|
std::unique_ptr<cmLinkLineComputer> linkLineComputer =
|
|
gg->CreateLinkLineComputer(lg, lg->GetStateSnapshot().GetDirectory());
|
|
lg->GetTargetFlags(linkLineComputer.get(), this->Config, linkLibs,
|
|
linkLanguageFlags, linkFlags, frameworkPath, linkPath,
|
|
this->GT);
|
|
linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
|
|
frameworkPath = cmTrimWhitespace(frameworkPath);
|
|
|
|
if (!linkLanguageFlags.empty()) {
|
|
linkFragments.append(
|
|
this->DumpCommandFragment(std::move(linkLanguageFlags), "flags"));
|
|
}
|
|
|
|
if (!linkFlags.empty()) {
|
|
for (BT<std::string> frag : linkFlags) {
|
|
frag.Value = cmTrimWhitespace(frag.Value);
|
|
linkFragments.append(
|
|
this->DumpCommandFragment(this->ToJBT(frag), "flags"));
|
|
}
|
|
}
|
|
|
|
if (!frameworkPath.empty()) {
|
|
linkFragments.append(
|
|
this->DumpCommandFragment(std::move(frameworkPath), "frameworkPath"));
|
|
}
|
|
|
|
if (!linkPath.empty()) {
|
|
for (BT<std::string> frag : linkPath) {
|
|
frag.Value = cmTrimWhitespace(frag.Value);
|
|
linkFragments.append(
|
|
this->DumpCommandFragment(this->ToJBT(frag), "libraryPath"));
|
|
}
|
|
}
|
|
|
|
if (!linkLibs.empty()) {
|
|
for (BT<std::string> frag : linkLibs) {
|
|
frag.Value = cmTrimWhitespace(frag.Value);
|
|
linkFragments.append(
|
|
this->DumpCommandFragment(this->ToJBT(frag), "libraries"));
|
|
}
|
|
}
|
|
|
|
return linkFragments;
|
|
}
|
|
|
|
Json::Value Target::DumpCommandFragments(
|
|
std::vector<JBT<std::string>> const& frags)
|
|
{
|
|
Json::Value commandFragments = Json::arrayValue;
|
|
for (JBT<std::string> const& f : frags) {
|
|
commandFragments.append(this->DumpCommandFragment(f));
|
|
}
|
|
return commandFragments;
|
|
}
|
|
|
|
Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag,
|
|
std::string const& role)
|
|
{
|
|
Json::Value fragment = Json::objectValue;
|
|
fragment["fragment"] = frag.Value;
|
|
if (!role.empty()) {
|
|
fragment["role"] = role;
|
|
}
|
|
this->AddBacktrace(fragment, frag.Backtrace);
|
|
return fragment;
|
|
}
|
|
|
|
Json::Value Target::DumpDependencies()
|
|
{
|
|
Json::Value dependencies = Json::arrayValue;
|
|
cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
|
|
for (cmTargetDepend const& td : gg->GetTargetDirectDepends(this->GT)) {
|
|
dependencies.append(this->DumpDependency(td));
|
|
}
|
|
return dependencies;
|
|
}
|
|
|
|
Json::Value Target::DumpDependency(cmTargetDepend const& td)
|
|
{
|
|
Json::Value dependency = Json::objectValue;
|
|
dependency["id"] = TargetId(td, this->TopBuild);
|
|
this->AddBacktrace(dependency, td.GetBacktrace());
|
|
return dependency;
|
|
}
|
|
|
|
Json::Value Target::DumpFolder()
|
|
{
|
|
Json::Value folder;
|
|
if (cmValue f = this->GT->GetProperty("FOLDER")) {
|
|
folder = Json::objectValue;
|
|
folder["name"] = *f;
|
|
}
|
|
return folder;
|
|
}
|
|
|
|
Json::Value Target::DumpLauncher(char const* name, char const* type)
|
|
{
|
|
cmValue property = this->GT->GetProperty(name);
|
|
Json::Value launcher;
|
|
if (property) {
|
|
cmLocalGenerator* lg = this->GT->GetLocalGenerator();
|
|
cmGeneratorExpression ge(*lg->GetCMakeInstance());
|
|
cmList commandWithArgs{ ge.Parse(*property)->Evaluate(lg, this->Config) };
|
|
if (!commandWithArgs.empty() && !commandWithArgs[0].empty()) {
|
|
std::string command(commandWithArgs[0]);
|
|
cmSystemTools::ConvertToUnixSlashes(command);
|
|
launcher = Json::objectValue;
|
|
launcher["command"] = RelativeIfUnder(this->TopSource, command);
|
|
launcher["type"] = type;
|
|
Json::Value args;
|
|
for (std::string const& arg : cmMakeRange(commandWithArgs).advance(1)) {
|
|
args.append(arg);
|
|
}
|
|
if (!args.empty()) {
|
|
launcher["arguments"] = std::move(args);
|
|
}
|
|
}
|
|
}
|
|
return launcher;
|
|
}
|
|
|
|
Json::Value Target::DumpLaunchers()
|
|
{
|
|
Json::Value launchers;
|
|
{
|
|
Json::Value launcher = DumpLauncher("TEST_LAUNCHER", "test");
|
|
if (!launcher.empty()) {
|
|
launchers.append(std::move(launcher));
|
|
}
|
|
}
|
|
if (this->GT->Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
|
|
Json::Value emulator = DumpLauncher("CROSSCOMPILING_EMULATOR", "emulator");
|
|
if (!emulator.empty()) {
|
|
launchers.append(std::move(emulator));
|
|
}
|
|
}
|
|
return launchers;
|
|
}
|
|
}
|
|
|
|
Json::Value Target::DumpDebugger()
|
|
{
|
|
Json::Value debuggerInformation;
|
|
if (cmValue debuggerWorkingDirectory =
|
|
this->GT->GetGlobalGenerator()->GetDebuggerWorkingDirectory(
|
|
this->GT)) {
|
|
debuggerInformation = Json::objectValue;
|
|
debuggerInformation["workingDirectory"] = *debuggerWorkingDirectory;
|
|
}
|
|
|
|
return debuggerInformation;
|
|
}
|
|
|
|
Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned int version)
|
|
{
|
|
Codemodel codemodel(fileAPI, version);
|
|
return codemodel.Dump();
|
|
}
|