diff options
Diffstat (limited to 'Source/cmFileAPICodemodel.cxx')
-rw-r--r-- | Source/cmFileAPICodemodel.cxx | 468 |
1 files changed, 386 insertions, 82 deletions
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 9061109..6b8757c 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -20,11 +20,16 @@ #include <cm3p/json/value.h> #include "cmCryptoHash.h" +#include "cmExportSet.h" #include "cmFileAPI.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmInstallDirectoryGenerator.h" +#include "cmInstallExportGenerator.h" +#include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmInstallScriptGenerator.h" #include "cmInstallSubdirectoryGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" @@ -42,81 +47,13 @@ #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetDepend.h" +#include "cmTargetExport.h" #include "cmake.h" namespace { -class Codemodel -{ - cmFileAPI& FileAPI; - unsigned long Version; - - Json::Value DumpPaths(); - Json::Value DumpConfigurations(); - Json::Value DumpConfiguration(std::string const& config); - -public: - Codemodel(cmFileAPI& fileAPI, unsigned long version); - Json::Value Dump(); -}; - -class CodemodelConfig -{ - cmFileAPI& FileAPI; - unsigned long 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 const Json::ArrayIndex 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; - - 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 DumpProjects(); - Json::Value DumpProject(Project& p); - - Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s); - -public: - CodemodelConfig(cmFileAPI& fileAPI, unsigned long version, - std::string const& config); - Json::Value Dump(); -}; +using TargetIndexMapType = + std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>; std::string RelativeIfUnder(std::string const& top, std::string const& in) { @@ -131,16 +68,6 @@ std::string RelativeIfUnder(std::string const& top, std::string const& in) return out; } -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; -} - class JBTIndex { public: @@ -290,6 +217,91 @@ Json::Value BacktraceData::Dump() return backtraceGraph; } +class Codemodel +{ + cmFileAPI& FileAPI; + unsigned long Version; + + Json::Value DumpPaths(); + Json::Value DumpConfigurations(); + Json::Value DumpConfiguration(std::string const& config); + +public: + Codemodel(cmFileAPI& fileAPI, unsigned long version); + Json::Value Dump(); +}; + +class CodemodelConfig +{ + cmFileAPI& FileAPI; + unsigned long 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 const Json::ArrayIndex 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 long 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 @@ -367,6 +379,31 @@ struct hash<CompileData> } // 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; @@ -663,6 +700,8 @@ Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt, target["projectIndex"] = pi; this->Projects[pi].TargetIndexes.append(ti); + this->TargetIndexMap[gt] = ti; + return target; } @@ -677,7 +716,7 @@ Json::Value CodemodelConfig::DumpDirectories() Json::Value CodemodelConfig::DumpDirectory(Directory& d) { - Json::Value directory = Json::objectValue; + Json::Value directory = this->DumpDirectoryObject(d); std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource(); directory["source"] = RelativeIfUnder(this->TopSource, sourceDir); @@ -717,6 +756,31 @@ Json::Value CodemodelConfig::DumpDirectory(Directory& d) 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; @@ -760,6 +824,246 @@ Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s) 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 (const auto& 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) +{ + Json::Value installer = Json::objectValue; + + // Exclude subdirectory installers. They are implementation details. + if (dynamic_cast<cmInstallSubdirectoryGenerator*>(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)); + } + } + + // Add fields common to all install generators. + installer["component"] = gen->GetComponent(); + if (gen->GetExcludeFromAll()) { + installer["isExcludeFromAll"] = 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) |