summaryrefslogtreecommitdiffstats
path: root/Source/cmFileAPICodemodel.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmFileAPICodemodel.cxx')
-rw-r--r--Source/cmFileAPICodemodel.cxx267
1 files changed, 193 insertions, 74 deletions
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index fecbf63..eff32ea 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -21,6 +21,7 @@
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetDepend.h"
@@ -30,7 +31,11 @@
#include <algorithm>
#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <limits>
#include <map>
+#include <memory>
#include <set>
#include <string>
#include <unordered_map>
@@ -134,6 +139,40 @@ std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
}
+class JBTIndex
+{
+public:
+ JBTIndex() = default;
+ explicit operator bool() const { return 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;
+ }
+};
+
class BacktraceData
{
std::string TopSource;
@@ -168,7 +207,7 @@ class BacktraceData
public:
BacktraceData(std::string topSource);
- bool Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index);
+ JBTIndex Add(cmListFileBacktrace const& bt);
Json::Value Dump();
};
@@ -177,16 +216,17 @@ BacktraceData::BacktraceData(std::string topSource)
{
}
-bool BacktraceData::Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index)
+JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt)
{
+ JBTIndex index;
if (bt.Empty()) {
- return false;
+ return index;
}
cmListFileContext const* top = &bt.Top();
auto found = this->NodeMap.find(top);
if (found != this->NodeMap.end()) {
- index = found->second;
- return true;
+ index.Index = found->second;
+ return index;
}
Json::Value entry = Json::objectValue;
entry["file"] = this->AddFile(top->FilePath);
@@ -196,13 +236,12 @@ bool BacktraceData::Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index)
if (!top->Name.empty()) {
entry["command"] = this->AddCommand(top->Name);
}
- Json::ArrayIndex parent;
- if (this->Add(bt.Pop(), parent)) {
- entry["parent"] = parent;
+ if (JBTIndex parent = this->Add(bt.Pop())) {
+ entry["parent"] = parent.Index;
}
- index = this->NodeMap[top] = this->Nodes.size();
+ index.Index = this->NodeMap[top] = this->Nodes.size();
this->Nodes.append(std::move(entry)); // NOLINT(*)
- return true;
+ return index;
}
Json::Value BacktraceData::Dump()
@@ -221,32 +260,65 @@ struct CompileData
{
struct IncludeEntry
{
- BT<std::string> Path;
+ JBT<std::string> Path;
bool IsSystem = false;
- IncludeEntry(BT<std::string> path, bool isSystem)
+ 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;
+ }
};
- void SetDefines(std::set<BT<std::string>> const& defines);
-
std::string Language;
std::string Sysroot;
- std::vector<BT<std::string>> Flags;
- std::vector<BT<std::string>> Defines;
+ std::vector<JBT<std::string>> Flags;
+ std::vector<JBT<std::string>> Defines;
std::vector<IncludeEntry> Includes;
+
+ 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.Includes == r.Includes);
+ }
};
+}
+
+namespace std {
-void CompileData::SetDefines(std::set<BT<std::string>> const& defines)
+template <>
+struct hash<CompileData>
{
- this->Defines.reserve(defines.size());
- for (BT<std::string> const& d : defines) {
- this->Defines.push_back(d);
+ 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.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);
+ }
+ return result;
}
-}
+};
+} // namespace std
+
+namespace {
class Target
{
cmGeneratorTarget* GT;
@@ -271,24 +343,32 @@ class Target
struct CompileGroup
{
- std::map<Json::Value, Json::ArrayIndex>::iterator Entry;
+ std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry;
Json::Value SourceIndexes = Json::arrayValue;
};
- std::map<Json::Value, Json::ArrayIndex> CompileGroupMap;
+ std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
std::vector<CompileGroup> CompileGroups;
+ template <typename T>
+ JBT<T> ToJBT(BT<T> const& bt)
+ {
+ return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
+ }
+
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 cd);
+ Json::Value DumpCompileData(CompileData const& cd);
Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
- Json::Value DumpDefine(BT<std::string> const& def);
+ Json::Value DumpDefine(JBT<std::string> const& def);
Json::Value DumpSources();
Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
Json::ArrayIndex si);
@@ -305,8 +385,8 @@ class Target
Json::Value DumpLink();
Json::Value DumpArchive();
Json::Value DumpLinkCommandFragments();
- Json::Value DumpCommandFragments(std::vector<BT<std::string>> const& frags);
- Json::Value DumpCommandFragment(BT<std::string> const& frag,
+ 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);
@@ -727,16 +807,20 @@ void Target::ProcessLanguage(std::string const& lang)
// which may need to be factored out.
std::string flags;
lg->GetTargetCompileFlags(this->GT, this->Config, lang, flags);
- cd.Flags.emplace_back(std::move(flags), cmListFileBacktrace());
+ cd.Flags.emplace_back(std::move(flags), JBTIndex());
}
std::set<BT<std::string>> defines =
lg->GetTargetDefines(this->GT, this->Config, lang);
- cd.SetDefines(defines);
+ 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) {
cd.Includes.emplace_back(
- i, this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
+ this->ToJBT(i),
+ this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
}
}
@@ -759,30 +843,26 @@ CompileData Target::BuildCompileData(cmSourceFile* sf)
{
CompileData fd;
- fd.Language = sf->GetLanguage();
+ fd.Language = sf->GetOrDetermineLanguage();
if (fd.Language.empty()) {
return fd;
}
- CompileData const& cd = this->CompileDataMap.at(fd.Language);
-
- fd.Sysroot = cd.Sysroot;
cmLocalGenerator* lg = this->GT->GetLocalGenerator();
cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT,
fd.Language);
- fd.Flags = cd.Flags;
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) {
std::string flags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS);
- fd.Flags.emplace_back(std::move(flags), cmListFileBacktrace());
+ fd.Flags.emplace_back(std::move(flags), JBTIndex());
}
const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
if (const char* coptions = sf->GetProperty(COMPILE_OPTIONS)) {
std::string flags;
lg->AppendCompileOptions(
flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
- fd.Flags.emplace_back(std::move(flags), cmListFileBacktrace());
+ fd.Flags.emplace_back(std::move(flags), JBTIndex());
}
// Add include directories from source file properties.
@@ -801,8 +881,6 @@ CompileData Target::BuildCompileData(cmSourceFile* sf)
}
}
}
- fd.Includes.insert(fd.Includes.end(), cd.Includes.begin(),
- cd.Includes.end());
const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
std::set<std::string> fileDefines;
@@ -819,27 +897,62 @@ CompileData Target::BuildCompileData(cmSourceFile* sf)
genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS));
}
- std::set<BT<std::string>> defines;
- defines.insert(fileDefines.begin(), fileDefines.end());
- defines.insert(cd.Defines.begin(), cd.Defines.end());
-
- fd.SetDefines(defines);
+ fd.Defines.reserve(fileDefines.size());
+ for (std::string const& d : fileDefines) {
+ 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;
+
+ // 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 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)
{
- Json::Value compileDataJson =
- this->DumpCompileData(this->BuildCompileData(sf));
- std::map<Json::Value, Json::ArrayIndex>::iterator i =
- this->CompileGroupMap.find(compileDataJson);
+ 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(compileDataJson), cgIndex).first;
+ i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first;
CompileGroup g;
g.Entry = i;
this->CompileGroups.push_back(std::move(g));
@@ -850,9 +963,15 @@ Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf,
void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt)
{
- Json::ArrayIndex backtrace;
- if (this->Backtraces.Add(bt, backtrace)) {
- object["backtrace"] = backtrace;
+ 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;
}
}
@@ -920,7 +1039,7 @@ Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
return source;
}
-Json::Value Target::DumpCompileData(CompileData cd)
+Json::Value Target::DumpCompileData(CompileData const& cd)
{
Json::Value result = Json::objectValue;
@@ -942,7 +1061,7 @@ Json::Value Target::DumpCompileData(CompileData cd)
}
if (!cd.Defines.empty()) {
Json::Value defines = Json::arrayValue;
- for (BT<std::string> const& d : cd.Defines) {
+ for (JBT<std::string> const& d : cd.Defines) {
defines.append(this->DumpDefine(d));
}
result["defines"] = std::move(defines);
@@ -962,7 +1081,7 @@ Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc)
return include;
}
-Json::Value Target::DumpDefine(BT<std::string> const& def)
+Json::Value Target::DumpDefine(JBT<std::string> const& def)
{
Json::Value define = Json::objectValue;
define["define"] = def.Value;
@@ -998,7 +1117,8 @@ Json::Value Target::DumpCompileGroups()
Json::Value Target::DumpCompileGroup(CompileGroup& cg)
{
- Json::Value group = cg.Entry->first;
+ Json::Value group =
+ this->DumpCompileData(this->MergeCompileData(cg.Entry->first));
group["sourceIndexes"] = std::move(cg.SourceIndexes);
return group;
}
@@ -1078,17 +1198,16 @@ Json::Value Target::DumpArtifacts()
}
// 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) {
- if (this->GT->GetType() == cmStateEnums::SHARED_LIBRARY ||
- this->GT->IsExecutableWithExports()) {
- Json::Value artifact = Json::objectValue;
- artifact["path"] =
- RelativeIfUnder(this->TopBuild,
- this->GT->GetFullPath(
- this->Config, cmStateEnums::ImportLibraryArtifact));
- artifacts.append(std::move(artifact)); // NOLINT(*)
- }
cmGeneratorTarget::OutputInfo const* output =
this->GT->GetOutputInfo(this->Config);
if (output && !output->PdbDir.empty()) {
@@ -1158,11 +1277,11 @@ Json::Value Target::DumpLinkCommandFragments()
lg->GetTargetFlags(&linkLineComputer, this->Config, linkLibs,
linkLanguageFlags, linkFlags, frameworkPath, linkPath,
this->GT);
- linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags);
- linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
- frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath);
- linkPath = cmSystemTools::TrimWhitespace(linkPath);
- linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
+ linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
+ linkFlags = cmTrimWhitespace(linkFlags);
+ frameworkPath = cmTrimWhitespace(frameworkPath);
+ linkPath = cmTrimWhitespace(linkPath);
+ linkLibs = cmTrimWhitespace(linkLibs);
if (!linkLanguageFlags.empty()) {
linkFragments.append(
@@ -1193,16 +1312,16 @@ Json::Value Target::DumpLinkCommandFragments()
}
Json::Value Target::DumpCommandFragments(
- std::vector<BT<std::string>> const& frags)
+ std::vector<JBT<std::string>> const& frags)
{
Json::Value commandFragments = Json::arrayValue;
- for (BT<std::string> const& f : frags) {
+ for (JBT<std::string> const& f : frags) {
commandFragments.append(this->DumpCommandFragment(f));
}
return commandFragments;
}
-Json::Value Target::DumpCommandFragment(BT<std::string> const& frag,
+Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag,
std::string const& role)
{
Json::Value fragment = Json::objectValue;