summaryrefslogtreecommitdiffstats
path: root/Source/cmServerProtocol.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmServerProtocol.cxx')
-rw-r--r--Source/cmServerProtocol.cxx386
1 files changed, 386 insertions, 0 deletions
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index c505568..c2eeee0 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -3,9 +3,13 @@
#include "cmServerProtocol.h"
#include "cmExternalMakefileProjectGenerator.h"
+#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
+#include "cmSourceFile.h"
#include "cmSystemTools.h"
#include "cmake.h"
@@ -16,6 +20,49 @@
#include "cm_jsoncpp_value.h"
#endif
+#include <algorithm>
+#include <string>
+#include <vector>
+
+// Get rid of some windows macros:
+#undef max
+
+namespace {
+
+static std::vector<std::string> getConfigurations(const cmake* cm)
+{
+ std::vector<std::string> configurations;
+ auto makefiles = cm->GetGlobalGenerator()->GetMakefiles();
+ if (makefiles.empty()) {
+ return configurations;
+ }
+
+ makefiles[0]->GetConfigurations(configurations);
+ if (configurations.empty())
+ configurations.push_back("");
+ return configurations;
+}
+
+static bool hasString(const Json::Value& v, const std::string& s)
+{
+ return !v.isNull() &&
+ std::find_if(v.begin(), v.end(), [s](const Json::Value& i) {
+ return i.asString() == s;
+ }) != v.end();
+}
+
+template <class T>
+static Json::Value fromStringList(const T& in)
+{
+ Json::Value result = Json::arrayValue;
+ for (const std::string& i : in) {
+ result.append(i);
+ }
+ return result;
+}
+
+} // namespace
+
cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
const std::string& c, const Json::Value& d)
: Type(t)
@@ -270,6 +317,9 @@ const cmServerResponse cmServerProtocol1_0::Process(
{
assert(this->m_State >= STATE_ACTIVE);
+ if (request.Type == kCODE_MODEL_TYPE) {
+ return this->ProcessCodeModel(request);
+ }
if (request.Type == kCOMPUTE_TYPE) {
return this->ProcessCompute(request);
}
@@ -291,6 +341,342 @@ bool cmServerProtocol1_0::IsExperimental() const
return true;
}
+class LanguageData
+{
+public:
+ bool operator==(const LanguageData& other) const;
+
+ void SetDefines(const std::set<std::string>& defines);
+
+ bool IsGenerated = false;
+ std::string Language;
+ std::string Flags;
+ std::vector<std::string> Defines;
+ std::vector<std::pair<std::string, bool> > IncludePathList;
+};
+
+bool LanguageData::operator==(const LanguageData& other) const
+{
+ return Language == other.Language && Defines == other.Defines &&
+ Flags == other.Flags && IncludePathList == other.IncludePathList &&
+ IsGenerated == other.IsGenerated;
+}
+
+void LanguageData::SetDefines(const std::set<std::string>& defines)
+{
+ std::vector<std::string> result;
+ for (auto i : defines) {
+ result.push_back(i);
+ }
+ std::sort(result.begin(), result.end());
+ Defines = result;
+}
+
+namespace std {
+
+template <>
+struct hash<LanguageData>
+{
+ std::size_t operator()(const LanguageData& in) const
+ {
+ using std::hash;
+ size_t result =
+ hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags);
+ for (auto i : in.IncludePathList) {
+ result = result ^ (hash<std::string>()(i.first) ^
+ (i.second ? std::numeric_limits<size_t>::max() : 0));
+ }
+ for (auto i : in.Defines) {
+ result = result ^ hash<std::string>()(i);
+ }
+ result =
+ result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0);
+ return result;
+ }
+};
+
+} // namespace std
+
+static Json::Value DumpSourceFileGroup(const LanguageData& data,
+ const std::vector<std::string>& files,
+ const std::string& baseDir)
+{
+ Json::Value result = Json::objectValue;
+
+ if (!data.Language.empty()) {
+ result[kLANGUAGE_KEY] = data.Language;
+ if (!data.Flags.empty()) {
+ result[kCOMPILE_FLAGS_KEY] = data.Flags;
+ }
+ if (!data.IncludePathList.empty()) {
+ Json::Value includes = Json::arrayValue;
+ for (auto i : data.IncludePathList) {
+ Json::Value tmp = Json::objectValue;
+ tmp[kPATH_KEY] = i.first;
+ if (i.second) {
+ tmp[kIS_SYSTEM_KEY] = i.second;
+ }
+ includes.append(tmp);
+ }
+ result[kINCLUDE_PATH_KEY] = includes;
+ }
+ if (!data.Defines.empty()) {
+ result[kDEFINES_KEY] = fromStringList(data.Defines);
+ }
+ }
+
+ result[kIS_GENERATED_KEY] = data.IsGenerated;
+
+ Json::Value sourcesValue = Json::arrayValue;
+ for (auto i : files) {
+ const std::string relPath =
+ cmSystemTools::RelativePath(baseDir.c_str(), i.c_str());
+ sourcesValue.append(relPath.size() < i.size() ? relPath : i);
+ }
+
+ result[kSOURCES_KEY] = sourcesValue;
+ return result;
+}
+
+static Json::Value DumpSourceFilesList(
+ cmGeneratorTarget* target, const std::string& config,
+ const std::map<std::string, LanguageData>& languageDataMap)
+{
+ // Collect sourcefile groups:
+
+ std::vector<cmSourceFile*> files;
+ target->GetSourceFiles(files, config);
+
+ std::unordered_map<LanguageData, std::vector<std::string> > fileGroups;
+ for (cmSourceFile* file : files) {
+ LanguageData fileData;
+ fileData.Language = file->GetLanguage();
+ if (!fileData.Language.empty()) {
+ const LanguageData& ld = languageDataMap.at(fileData.Language);
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+
+ std::string compileFlags = ld.Flags;
+ lg->AppendFlags(compileFlags, file->GetProperty("COMPILE_FLAGS"));
+ fileData.Flags = compileFlags;
+
+ fileData.IncludePathList = ld.IncludePathList;
+
+ std::set<std::string> defines;
+ lg->AppendDefines(defines, file->GetProperty("COMPILE_DEFINITIONS"));
+ const std::string defPropName =
+ "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
+ lg->AppendDefines(defines, file->GetProperty(defPropName));
+ defines.insert(ld.Defines.begin(), ld.Defines.end());
+
+ fileData.SetDefines(defines);
+ }
+
+ fileData.IsGenerated = file->GetPropertyAsBool("GENERATED");
+ std::vector<std::string>& groupFileList = fileGroups[fileData];
+ groupFileList.push_back(file->GetFullPath());
+ }
+
+ const std::string baseDir = target->Makefile->GetCurrentSourceDirectory();
+ Json::Value result = Json::arrayValue;
+ for (auto it = fileGroups.begin(); it != fileGroups.end(); ++it) {
+ Json::Value group = DumpSourceFileGroup(it->first, it->second, baseDir);
+ if (!group.isNull())
+ result.append(group);
+ }
+
+ return result;
+}
+
+static Json::Value DumpTarget(cmGeneratorTarget* target,
+ const std::string& config)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ const cmState* state = lg->GetState();
+
+ const cmState::TargetType type = target->GetType();
+ const std::string typeName = state->GetTargetTypeName(type);
+
+ Json::Value ttl = Json::arrayValue;
+ ttl.append("EXECUTABLE");
+ ttl.append("STATIC_LIBRARY");
+ ttl.append("SHARED_LIBRARY");
+ ttl.append("MODULE_LIBRARY");
+ ttl.append("OBJECT_LIBRARY");
+ ttl.append("UTILITY");
+ ttl.append("INTERFACE_LIBRARY");
+
+ if (!hasString(ttl, typeName) || target->IsImported()) {
+ return Json::Value();
+ }
+
+ Json::Value result = Json::objectValue;
+ result[kNAME_KEY] = target->GetName();
+
+ result[kTYPE_KEY] = typeName;
+ result[kFULL_NAME_KEY] = target->GetFullName(config);
+ result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
+ result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
+
+ if (target->HaveWellDefinedOutputFiles()) {
+ Json::Value artifacts = Json::arrayValue;
+ artifacts.append(target->GetFullPath(config, false));
+ if (target->IsDLLPlatform()) {
+ artifacts.append(target->GetFullPath(config, true));
+ const cmGeneratorTarget::OutputInfo* output =
+ target->GetOutputInfo(config);
+ if (output && !output->PdbDir.empty()) {
+ artifacts.append(output->PdbDir + '/' + target->GetPDBName(config));
+ }
+ }
+ result[kARTIFACTS_KEY] = artifacts;
+
+ result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config);
+
+ std::string linkLibs;
+ std::string linkFlags;
+ std::string linkLanguageFlags;
+ std::string frameworkPath;
+ std::string linkPath;
+ lg->GetTargetFlags(config, linkLibs, linkLanguageFlags, linkFlags,
+ frameworkPath, linkPath, target, false);
+
+ linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
+ linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
+ linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags);
+ frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath);
+ linkPath = cmSystemTools::TrimWhitespace(linkPath);
+
+ if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) {
+ result[kLINK_LIBRARIES_KEY] = linkLibs;
+ }
+ if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) {
+ result[kLINK_FLAGS_KEY] = linkFlags;
+ }
+ if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) {
+ result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags;
+ }
+ if (!frameworkPath.empty()) {
+ result[kFRAMEWORK_PATH_KEY] = frameworkPath;
+ }
+ if (!linkPath.empty()) {
+ result[kLINK_PATH_KEY] = linkPath;
+ }
+ const std::string sysroot =
+ lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT");
+ if (!sysroot.empty()) {
+ result[kSYSROOT_KEY] = sysroot;
+ }
+ }
+
+ std::set<std::string> languages;
+ target->GetLanguages(languages, config);
+ std::map<std::string, LanguageData> languageDataMap;
+ for (auto lang : languages) {
+ LanguageData& ld = languageDataMap[lang];
+ ld.Language = lang;
+ lg->GetTargetCompileFlags(target, config, lang, ld.Flags);
+ std::set<std::string> defines;
+ lg->GetTargetDefines(target, config, lang, defines);
+ ld.SetDefines(defines);
+ std::vector<std::string> includePathList;
+ lg->GetIncludeDirectories(includePathList, target, lang, config, true);
+ for (auto i : includePathList) {
+ ld.IncludePathList.push_back(
+ std::make_pair(i, target->IsSystemIncludeDirectory(i, config)));
+ }
+ }
+
+ Json::Value sourceGroupsValue =
+ DumpSourceFilesList(target, config, languageDataMap);
+ if (!sourceGroupsValue.empty()) {
+ result[kFILE_GROUPS_KEY] = sourceGroupsValue;
+ }
+
+ return result;
+}
+
+static Json::Value DumpTargetsList(
+ const std::vector<cmLocalGenerator*>& generators, const std::string& config)
+{
+ Json::Value result = Json::arrayValue;
+
+ std::vector<cmGeneratorTarget*> targetList;
+ for (const auto& lgIt : generators) {
+ auto list = lgIt->GetGeneratorTargets();
+ targetList.insert(targetList.end(), list.begin(), list.end());
+ }
+ std::sort(targetList.begin(), targetList.end());
+
+ for (cmGeneratorTarget* target : targetList) {
+ Json::Value tmp = DumpTarget(target, config);
+ if (!tmp.isNull()) {
+ result.append(tmp);
+ }
+ }
+
+ return result;
+}
+
+static Json::Value DumpProjectList(const cmake* cm, const std::string config)
+{
+ Json::Value result = Json::arrayValue;
+
+ auto globalGen = cm->GetGlobalGenerator();
+
+ for (const auto& projectIt : globalGen->GetProjectMap()) {
+ Json::Value pObj = Json::objectValue;
+ pObj[kNAME_KEY] = projectIt.first;
+
+ assert(projectIt.second.size() >
+ 0); // All Projects must have at least one local generator
+ const cmLocalGenerator* lg = projectIt.second.at(0);
+
+ // Project structure information:
+ const cmMakefile* mf = lg->GetMakefile();
+ pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
+ pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
+ pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
+
+ result.append(pObj);
+ }
+
+ return result;
+}
+
+static Json::Value DumpConfiguration(const cmake* cm,
+ const std::string& config)
+{
+ Json::Value result = Json::objectValue;
+ result[kNAME_KEY] = config;
+
+ result[kPROJECTS_KEY] = DumpProjectList(cm, config);
+
+ return result;
+}
+
+static Json::Value DumpConfigurationsList(const cmake* cm)
+{
+ Json::Value result = Json::arrayValue;
+
+ for (const std::string& c : getConfigurations(cm)) {
+ result.append(DumpConfiguration(cm, c));
+ }
+
+ return result;
+}
+
+cmServerResponse cmServerProtocol1_0::ProcessCodeModel(
+ const cmServerRequest& request)
+{
+ if (this->m_State != STATE_COMPUTED) {
+ return request.ReportError("No build system was generated yet.");
+ }
+
+ Json::Value result = Json::objectValue;
+ result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(this->CMakeInstance());
+ return request.Reply(result);
+}
+
cmServerResponse cmServerProtocol1_0::ProcessCompute(
const cmServerRequest& request)
{