From ead71873b2025a28df1208bbd3f2f8e1918a120c Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 9 Sep 2016 10:01:46 +0200 Subject: [PATCH 1/4] server-mode: Report information relevant for a codemodel Add "codemodel" command to report information relevant to feed a code model. --- Help/manual/cmake-server.7.rst | 184 ++++++++++++++++ Source/cmServerDictionary.h | 22 ++ Source/cmServerProtocol.cxx | 386 +++++++++++++++++++++++++++++++++ Source/cmServerProtocol.h | 1 + 4 files changed, 593 insertions(+) diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index b8a425c82..79b67b012 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -374,3 +374,187 @@ CMake will reply (after reporting progress information):: [== CMake Server ==[ {"cookie":"","inReplyTo":"compute","type":"reply"} ]== CMake Server ==] + + +Type "codemodel" +^^^^^^^^^^^^^^^^ + +The "codemodel" request can be used after a project was "compute"d successfully. + +It will list the complete project structure as it is known to cmake. + +The reply will contain a key "projects", which will contain a list of +project objects, one for each (sub-)project defined in the cmake build system. + +Each project object can have the following keys: + +"name" + contains the (sub-)projects name. +"sourceDirectory" + contains the current source directory +"buildDirectory" + contains the current build directory. +"configurations" + contains a list of configuration objects. + +Configuration objects are used to destinquish between different +configurations the build directory might have enabled. While most generators +only support one configuration, others support several. + +Each configuration object can have the following keys: + +"name" + contains the name of the configuration. The name may be empty. +"targets" + contains a list of target objects, one for each build target. + +Target objects define individual build targets for a certain configuration. + +Each target object can have the following keys: + +"name" + contains the name of the target. +"type" + defines the type of build of the target. Possible values are + "STATIC_LIBRARY", "MODULE_LIBRARY", "SHARED_LIBRARY", "OBJECT_LIBRARY", + "EXECUTABLE", "UTILITY" and "INTERFACE_LIBRARY". +"fullName" + contains the full name of the build result (incl. extensions, etc.). +"sourceDirectory" + contains the current source directory. +"buildDirectory" + contains the current build directory. +"artifacts" + with a list of build artifacts. The list is sorted with the most + important artifacts first (e.g. a .DLL file is listed before a + .PDB file on windows). +"linkerLanguage" + contains the language of the linker used to produce the artifact. +"linkLibraries" + with a list of libraries to link to. This value is encoded in the + system's native shell format. +"linkFlags" + with a list of flags to pass to the linker. This value is encoded in + the system's native shell format. +"linkLanguageFlags" + with the flags for a compiler using the linkerLanguage. This value is + encoded in the system's native shell format. +"frameworkPath" + with the framework path (on Apple computers). This value is encoded + in the system's native shell format. +"linkPath" + with the link path. This value is encoded in the system's native shell + format. +"sysroot" + with the sysroot path. +"fileGroups" + contains the source files making up the target. + +FileGroups are used to group sources using similar settings together. + +Each fileGroup object may contain the following keys: + +"language" + contains the programming language used by all files in the group. +"compileFlags" + with a string containing all the flags passed to the compiler + when building any of the files in this group. This value is encoded in + the system's native shell format. +"includePath" + with a list of include paths. Each include path is an object + containing a "path" with the actual include path and "isSystem" with a bool + value informing whether this is a normal include or a system include. This + value is encoded in the system's native shell format. +"defines" + with a list of defines in the form "SOMEVALUE" or "SOMEVALUE=42". This + value is encoded in the system's native shell format. +"sources" + with a list of source files. + +All file paths in the fileGroup are either absolute or relative to the +sourceDirectory of the target. + +Example:: + + [== CMake Server ==[ + {"type":"project"} + ]== CMake Server ==] + +CMake will reply:: + + [== CMake Server ==[ + { + "cookie":"", + "type":"reply", + "inReplyTo":"project", + + "projects": + [ + { + "name":"CMAKE_FORM", + "sourceDirectory":"/home/code/src/cmake/Source/CursesDialog/form" + "buildDirectory":"/tmp/cmake-build-test/Source/CursesDialog/form", + "configurations": + [ + { + "name":"", + "targets": + [ + { + "artifactDirectory":"/tmp/cmake/Source/CursesDialog/form", + "fileGroups": + [ + { + "compileFlags":" -std=gnu11", + "defines": + [ + "SOMETHING=1", + "LIBARCHIVE_STATIC" + ], + "includePath": + [ + { "path":"/tmp/cmake-build-test/Utilities" }, + { "isSystem": true, "path":"/usr/include/something" }, + ... + ] + "language":"C", + "sources": + [ + "fld_arg.c", + ... + "fty_regex.c" + ] + } + ], + "fullName":"libcmForm.a", + "linkerLanguage":"C", + "name":"cmForm", + "type":"STATIC_LIBRARY" + } + ] + } + ], + }, + ... + ] + } + ]== CMake Server ==] + +The output can be tailored to the specific needs via parameter passed when +requesting "project" information. + +You can have a "depth" key, which accepts "project", "configuration" and +"target" as string values. These cause the output to be trimmed at the +appropriate depth of the output tree. + +You can also set "configurations" to an array of strings with configuration +names to list. This will cause any configuration that is not listed to be +trimmed from the output. + +Generated files can be included in the listing by setting "includeGeneratedFiles" +to "true". This setting defaults to "false", so generated files are not +listed by default. + +Finally you can limit the target types that are going to be listed. This is +done by providing a list of target types as an array of strings to the +"targetTypes" key. diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index e4295711f..9e838648a 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -6,6 +6,7 @@ // Vocabulary: +static const std::string kCODE_MODEL_TYPE = "codemodel"; static const std::string kCOMPUTE_TYPE = "compute"; static const std::string kCONFIGURE_TYPE = "configure"; static const std::string kERROR_TYPE = "error"; @@ -17,29 +18,50 @@ static const std::string kREPLY_TYPE = "reply"; static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings"; static const std::string kSIGNAL_TYPE = "signal"; +static const std::string kARTIFACTS_KEY = "artifacts"; static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments"; static const std::string kCAPABILITIES_KEY = "capabilities"; static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars"; +static const std::string kCOMPILE_FLAGS_KEY = "compileFlags"; +static const std::string kCONFIGURATIONS_KEY = "configurations"; static const std::string kCOOKIE_KEY = "cookie"; static const std::string kDEBUG_OUTPUT_KEY = "debugOutput"; +static const std::string kDEFINES_KEY = "defines"; static const std::string kERROR_MESSAGE_KEY = "errorMessage"; static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; +static const std::string kFILE_GROUPS_KEY = "fileGroups"; +static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath"; +static const std::string kFULL_NAME_KEY = "fullName"; static const std::string kGENERATOR_KEY = "generator"; +static const std::string kINCLUDE_PATH_KEY = "includePath"; static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; +static const std::string kIS_GENERATED_KEY = "isGenerated"; +static const std::string kIS_SYSTEM_KEY = "isSystem"; +static const std::string kLANGUAGE_KEY = "language"; +static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; +static const std::string kLINK_FLAGS_KEY = "linkFlags"; +static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags"; +static const std::string kLINK_LIBRARIES_KEY = "linkLibraries"; +static const std::string kLINK_PATH_KEY = "linkPath"; static const std::string kMAJOR_KEY = "major"; static const std::string kMESSAGE_KEY = "message"; static const std::string kMINOR_KEY = "minor"; static const std::string kNAME_KEY = "name"; +static const std::string kPATH_KEY = "path"; static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent"; static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum"; static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage"; static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum"; +static const std::string kPROJECTS_KEY = "projects"; static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion"; static const std::string kREPLY_TO_KEY = "inReplyTo"; static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; +static const std::string kSOURCES_KEY = "sources"; static const std::string kSUPPORTED_PROTOCOL_VERSIONS = "supportedProtocolVersions"; +static const std::string kSYSROOT_KEY = "sysroot"; +static const std::string kTARGETS_KEY = "targets"; static const std::string kTITLE_KEY = "title"; static const std::string kTRACE_EXPAND_KEY = "traceExpand"; static const std::string kTRACE_KEY = "trace"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index c505568c0..c2eeee071 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 +#include +#include + +// Get rid of some windows macros: +#undef max + +namespace { + +static std::vector getConfigurations(const cmake* cm) +{ + std::vector 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 +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& defines); + + bool IsGenerated = false; + std::string Language; + std::string Flags; + std::vector Defines; + std::vector > 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& defines) +{ + std::vector result; + for (auto i : defines) { + result.push_back(i); + } + std::sort(result.begin(), result.end()); + Defines = result; +} + +namespace std { + +template <> +struct hash +{ + std::size_t operator()(const LanguageData& in) const + { + using std::hash; + size_t result = + hash()(in.Language) ^ hash()(in.Flags); + for (auto i : in.IncludePathList) { + result = result ^ (hash()(i.first) ^ + (i.second ? std::numeric_limits::max() : 0)); + } + for (auto i : in.Defines) { + result = result ^ hash()(i); + } + result = + result ^ (in.IsGenerated ? std::numeric_limits::max() : 0); + return result; + } +}; + +} // namespace std + +static Json::Value DumpSourceFileGroup(const LanguageData& data, + const std::vector& 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& languageDataMap) +{ + // Collect sourcefile groups: + + std::vector files; + target->GetSourceFiles(files, config); + + std::unordered_map > 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 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& 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 languages; + target->GetLanguages(languages, config); + std::map languageDataMap; + for (auto lang : languages) { + LanguageData& ld = languageDataMap[lang]; + ld.Language = lang; + lg->GetTargetCompileFlags(target, config, lang, ld.Flags); + std::set defines; + lg->GetTargetDefines(target, config, lang, defines); + ld.SetDefines(defines); + std::vector 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& generators, const std::string& config) +{ + Json::Value result = Json::arrayValue; + + std::vector 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) { diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 63ef0be26..193e0a35d 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -108,6 +108,7 @@ private: std::string* errorMessage) override; // Handle requests: + cmServerResponse ProcessCodeModel(const cmServerRequest& request); cmServerResponse ProcessCompute(const cmServerRequest& request); cmServerResponse ProcessConfigure(const cmServerRequest& request); cmServerResponse ProcessGlobalSettings(const cmServerRequest& request); From 84553a6e709ea810f3e7fc5ece5daa1c53be5cda Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 9 Sep 2016 10:01:46 +0200 Subject: [PATCH 2/4] server-mode: Add command to retrieve build system files Add a command to retrieve files that are input to cmake itself. --- Help/manual/cmake-server.7.rst | 41 ++++++++++++++ Source/cmServerDictionary.h | 5 ++ Source/cmServerProtocol.cxx | 99 +++++++++++++++++++++++++++++++++- Source/cmServerProtocol.h | 1 + 4 files changed, 144 insertions(+), 2 deletions(-) diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index 79b67b012..76ee3fb91 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -558,3 +558,44 @@ listed by default. Finally you can limit the target types that are going to be listed. This is done by providing a list of target types as an array of strings to the "targetTypes" key. + + +Type "cmakeInputs" +^^^^^^^^^^^^^^^^^^ + +The "cmakeInputs" requests will report files used by CMake as part +of the build system itself. + +This request is only available after a project was successfully +"configure"d. + +Example:: + + [== CMake Server ==[ + {"type":"cmakeInputs"} + ]== CMake Server ==] + +CMake will reply with the following information:: + + [== CMake Server ==[ + {"buildFiles": + [ + {"isCMake":true,"isTemporary":false,"sources":["/usr/lib/cmake/...", ... ]}, + {"isCMake":false,"isTemporary":false,"sources":["CMakeLists.txt", ...]}, + {"isCMake":false,"isTemporary":true,"sources":["/tmp/build/CMakeFiles/...", ...]} + ], + "cmakeRootDirectory":"/usr/lib/cmake", + "sourceDirectory":"/home/code/src/cmake", + "cookie":"", + "inReplyTo":"cmakeInputs", + "type":"reply" + } + ]== CMake Server ==] + +All file names are either relative to the top level source directory or +absolute. + +The list of files which "isCMake" set to true are part of the cmake installation. + +The list of files witch "isTemporary" set to true are part of the build directory +and will not survive the build directory getting cleaned out. diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index 9e838648a..bccce550b 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -6,6 +6,7 @@ // Vocabulary: +static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs"; static const std::string kCODE_MODEL_TYPE = "codemodel"; static const std::string kCOMPUTE_TYPE = "compute"; static const std::string kCONFIGURE_TYPE = "configure"; @@ -20,9 +21,11 @@ static const std::string kSIGNAL_TYPE = "signal"; static const std::string kARTIFACTS_KEY = "artifacts"; static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; +static const std::string kBUILD_FILES_KEY = "buildFiles"; static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments"; static const std::string kCAPABILITIES_KEY = "capabilities"; static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars"; +static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory"; static const std::string kCOMPILE_FLAGS_KEY = "compileFlags"; static const std::string kCONFIGURATIONS_KEY = "configurations"; static const std::string kCOOKIE_KEY = "cookie"; @@ -35,9 +38,11 @@ static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath"; static const std::string kFULL_NAME_KEY = "fullName"; static const std::string kGENERATOR_KEY = "generator"; static const std::string kINCLUDE_PATH_KEY = "includePath"; +static const std::string kIS_CMAKE_KEY = "isCMake"; static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; static const std::string kIS_GENERATED_KEY = "isGenerated"; static const std::string kIS_SYSTEM_KEY = "isSystem"; +static const std::string kIS_TEMPORARY_KEY = "isTemporary"; static const std::string kLANGUAGE_KEY = "language"; static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; static const std::string kLINK_FLAGS_KEY = "linkFlags"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index c2eeee071..00a813579 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -5,6 +5,7 @@ #include "cmExternalMakefileProjectGenerator.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmServer.h" @@ -61,6 +62,48 @@ static Json::Value fromStringList(const T& in) return result; } +static void getCMakeInputs(const cmGlobalGenerator* gg, + const std::string& sourceDir, + const std::string& buildDir, + std::vector* internalFiles, + std::vector* explicitFiles, + std::vector* tmpFiles) +{ + const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/'; + const std::vector makefiles = gg->GetMakefiles(); + for (auto it = makefiles.begin(); it != makefiles.end(); ++it) { + const std::vector listFiles = (*it)->GetListFiles(); + + for (auto jt = listFiles.begin(); jt != listFiles.end(); ++jt) { + + const std::string startOfFile = jt->substr(0, cmakeRootDir.size()); + const bool isInternal = (startOfFile == cmakeRootDir); + const bool isTemporary = !isInternal && (jt->find(buildDir + '/') == 0); + + std::string toAdd = *jt; + if (!sourceDir.empty()) { + const std::string& relative = + cmSystemTools::RelativePath(sourceDir.c_str(), jt->c_str()); + if (toAdd.size() > relative.size()) + toAdd = relative; + } + + if (isInternal) { + if (internalFiles) + internalFiles->push_back(toAdd); + } else { + if (isTemporary) { + if (tmpFiles) + tmpFiles->push_back(toAdd); + } else { + if (explicitFiles) + explicitFiles->push_back(toAdd); + } + } + } + } +} + } // namespace cmServerRequest::cmServerRequest(cmServer* server, const std::string& t, @@ -317,6 +360,9 @@ const cmServerResponse cmServerProtocol1_0::Process( { assert(this->m_State >= STATE_ACTIVE); + if (request.Type == kCMAKE_INPUTS_TYPE) { + return this->ProcessCMakeInputs(request); + } if (request.Type == kCODE_MODEL_TYPE) { return this->ProcessCodeModel(request); } @@ -341,6 +387,54 @@ bool cmServerProtocol1_0::IsExperimental() const return true; } +cmServerResponse cmServerProtocol1_0::ProcessCMakeInputs( + const cmServerRequest& request) +{ + if (this->m_State < STATE_CONFIGURED) { + return request.ReportError("This instance was not yet configured."); + } + + const cmake* cm = this->CMakeInstance(); + const cmGlobalGenerator* gg = cm->GetGlobalGenerator(); + const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot(); + const std::string buildDir = cm->GetHomeOutputDirectory(); + const std::string sourceDir = cm->GetHomeDirectory(); + + Json::Value result = Json::objectValue; + result[kSOURCE_DIRECTORY_KEY] = sourceDir; + result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir; + + std::vector internalFiles; + std::vector explicitFiles; + std::vector tmpFiles; + getCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles, + &tmpFiles); + + Json::Value array = Json::arrayValue; + + Json::Value tmp = Json::objectValue; + tmp[kIS_CMAKE_KEY] = true; + tmp[kIS_TEMPORARY_KEY] = false; + tmp[kSOURCES_KEY] = fromStringList(internalFiles); + array.append(tmp); + + tmp = Json::objectValue; + tmp[kIS_CMAKE_KEY] = false; + tmp[kIS_TEMPORARY_KEY] = false; + tmp[kSOURCES_KEY] = fromStringList(explicitFiles); + array.append(tmp); + + tmp = Json::objectValue; + tmp[kIS_CMAKE_KEY] = false; + tmp[kIS_TEMPORARY_KEY] = true; + tmp[kSOURCES_KEY] = fromStringList(tmpFiles); + array.append(tmp); + + result[kBUILD_FILES_KEY] = array; + + return request.Reply(result); +} + class LanguageData { public: @@ -732,6 +826,8 @@ cmServerResponse cmServerProtocol1_0::ProcessConfigure( std::string sourceDir = cm->GetHomeDirectory(); const std::string buildDir = cm->GetHomeOutputDirectory(); + cmGlobalGenerator* gg = cm->GetGlobalGenerator(); + if (buildDir.empty()) { return request.ReportError( "No build directory set via setGlobalSettings."); @@ -752,8 +848,7 @@ cmServerResponse cmServerProtocol1_0::ProcessConfigure( const char* cachedGenerator = cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR"); if (cachedGenerator) { - cmGlobalGenerator* gen = cm->GetGlobalGenerator(); - if (gen && gen->GetName() != cachedGenerator) { + if (gg && gg->GetName() != cachedGenerator) { return request.ReportError("Configured generator does not match with " "CMAKE_GENERATOR found in cache."); } diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 193e0a35d..2a6b1937c 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -108,6 +108,7 @@ private: std::string* errorMessage) override; // Handle requests: + cmServerResponse ProcessCMakeInputs(const cmServerRequest& request); cmServerResponse ProcessCodeModel(const cmServerRequest& request); cmServerResponse ProcessCompute(const cmServerRequest& request); cmServerResponse ProcessConfigure(const cmServerRequest& request); From 7b1e60f26e284e223be8638744ba3a3b0efdee63 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 9 Sep 2016 10:01:46 +0200 Subject: [PATCH 3/4] server-mode: Report CMakeCache entries With this it would be possible to implement something like cmake-gui using server-mode. --- Help/manual/cmake-server.7.rst | 36 +++++++++++++++++++ Source/cmServerDictionary.h | 6 ++++ Source/cmServerProtocol.cxx | 64 ++++++++++++++++++++++++++++++++++ Source/cmServerProtocol.h | 1 + 4 files changed, 107 insertions(+) diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index 76ee3fb91..f66212522 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -599,3 +599,39 @@ The list of files which "isCMake" set to true are part of the cmake installation The list of files witch "isTemporary" set to true are part of the build directory and will not survive the build directory getting cleaned out. + + +Type "cache" +^^^^^^^^^^^^ + +The "cache" request can be used once a project is configured and will +list the cached configuration values. + +Example:: + + [== CMake Server ==[ + {"type":"cache"} + ]== CMake Server ==] + +CMake will respond with the following output:: + + [== CMake Server ==[ + { + "cookie":"","inReplyTo":"cache","type":"reply", + "cache": + [ + { + "key":"SOMEVALUE", + "properties": + { + "ADVANCED":"1", + "HELPSTRING":"This is not helpful" + } + "type":"STRING", + "value":"TEST"} + ] + } + ]== CMake Server ==] + +The output can be limited to a list of keys by passing an array of key names +to the "keys" optional field of the "cache" request. diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index bccce550b..c811b83af 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -6,6 +6,7 @@ // Vocabulary: +static const std::string kCACHE_TYPE = "cache"; static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs"; static const std::string kCODE_MODEL_TYPE = "codemodel"; static const std::string kCOMPUTE_TYPE = "compute"; @@ -23,6 +24,7 @@ static const std::string kARTIFACTS_KEY = "artifacts"; static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; static const std::string kBUILD_FILES_KEY = "buildFiles"; static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments"; +static const std::string kCACHE_KEY = "cache"; static const std::string kCAPABILITIES_KEY = "capabilities"; static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars"; static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory"; @@ -43,6 +45,8 @@ static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; static const std::string kIS_GENERATED_KEY = "isGenerated"; static const std::string kIS_SYSTEM_KEY = "isSystem"; static const std::string kIS_TEMPORARY_KEY = "isTemporary"; +static const std::string kKEY_KEY = "key"; +static const std::string kKEYS_KEY = "keys"; static const std::string kLANGUAGE_KEY = "language"; static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; static const std::string kLINK_FLAGS_KEY = "linkFlags"; @@ -59,6 +63,7 @@ static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum"; static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage"; static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum"; static const std::string kPROJECTS_KEY = "projects"; +static const std::string kPROPERTIES_KEY = "properties"; static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion"; static const std::string kREPLY_TO_KEY = "inReplyTo"; static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; @@ -71,6 +76,7 @@ static const std::string kTITLE_KEY = "title"; static const std::string kTRACE_EXPAND_KEY = "traceExpand"; static const std::string kTRACE_KEY = "trace"; static const std::string kTYPE_KEY = "type"; +static const std::string kVALUE_KEY = "value"; static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized"; static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli"; static const std::string kWARN_UNUSED_KEY = "warnUnused"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 00a813579..f083e49fe 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmServerProtocol.h" +#include "cmCacheManager.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -62,6 +63,15 @@ static Json::Value fromStringList(const T& in) return result; } +static std::vector toStringList(const Json::Value& in) +{ + std::vector result; + for (const auto& it : in) { + result.push_back(it.asString()); + } + return result; +} + static void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir, const std::string& buildDir, @@ -360,6 +370,9 @@ const cmServerResponse cmServerProtocol1_0::Process( { assert(this->m_State >= STATE_ACTIVE); + if (request.Type == kCACHE_TYPE) { + return this->ProcessCache(request); + } if (request.Type == kCMAKE_INPUTS_TYPE) { return this->ProcessCMakeInputs(request); } @@ -387,6 +400,57 @@ bool cmServerProtocol1_0::IsExperimental() const return true; } +cmServerResponse cmServerProtocol1_0::ProcessCache( + const cmServerRequest& request) +{ + if (this->m_State < STATE_CONFIGURED) { + return request.ReportError("This project was not configured yet."); + } + + cmState* state = this->CMakeInstance()->GetState(); + + Json::Value result = Json::objectValue; + + std::vector allKeys = state->GetCacheEntryKeys(); + + Json::Value list = Json::arrayValue; + std::vector keys = toStringList(request.Data[kKEYS_KEY]); + if (keys.empty()) { + keys = allKeys; + } else { + for (auto i : keys) { + if (std::find_if(allKeys.begin(), allKeys.end(), + [i](const std::string& j) { return i == j; }) == + allKeys.end()) { + return request.ReportError("Key \"" + i + "\" not found in cache."); + } + } + } + std::sort(keys.begin(), keys.end()); + for (auto key : keys) { + Json::Value entry = Json::objectValue; + entry[kKEY_KEY] = key; + entry[kTYPE_KEY] = + cmState::CacheEntryTypeToString(state->GetCacheEntryType(key)); + entry[kVALUE_KEY] = state->GetCacheEntryValue(key); + + Json::Value props = Json::objectValue; + bool haveProperties = false; + for (auto prop : state->GetCacheEntryPropertyList(key)) { + haveProperties = true; + props[prop] = state->GetCacheEntryProperty(key, prop); + } + if (haveProperties) { + entry[kPROPERTIES_KEY] = props; + } + + list.append(entry); + } + + result[kCACHE_KEY] = list; + return request.Reply(result); +} + cmServerResponse cmServerProtocol1_0::ProcessCMakeInputs( const cmServerRequest& request) { diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 2a6b1937c..d672a60b6 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -108,6 +108,7 @@ private: std::string* errorMessage) override; // Handle requests: + cmServerResponse ProcessCache(const cmServerRequest& request); cmServerResponse ProcessCMakeInputs(const cmServerRequest& request); cmServerResponse ProcessCodeModel(const cmServerRequest& request); cmServerResponse ProcessCompute(const cmServerRequest& request); From 71a505870c1f5a4fc89a8ad4e4dc3bb008a35118 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 27 Sep 2016 21:29:20 +0200 Subject: [PATCH 4/4] server-mode: Add project data for unit tests Do some basic unit tests for "codemodel", "cmakeInputs" and "cache" commands of the cmake server. This just calls the commands right now and makes sure the server thinks it can reply to the request. The data itself is currently not validated. --- Tests/Server/CMakeLists.txt | 2 + Tests/Server/buildsystem1/CMakeLists.txt | 22 +++++++++++ Tests/Server/buildsystem1/foo.cpp | 5 +++ Tests/Server/buildsystem1/main.cpp | 5 +++ .../Server/buildsystem1/subdir/CMakeLists.txt | 5 +++ Tests/Server/buildsystem1/subdir/empty.cpp | 5 +++ Tests/Server/cmakelib.py | 20 +++++++--- Tests/Server/server-test.py | 37 +++++++++++-------- Tests/Server/tc_buildsystem1.json | 27 ++++++++++++++ 9 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 Tests/Server/buildsystem1/CMakeLists.txt create mode 100644 Tests/Server/buildsystem1/foo.cpp create mode 100644 Tests/Server/buildsystem1/main.cpp create mode 100644 Tests/Server/buildsystem1/subdir/CMakeLists.txt create mode 100644 Tests/Server/buildsystem1/subdir/empty.cpp create mode 100644 Tests/Server/tc_buildsystem1.json diff --git a/Tests/Server/CMakeLists.txt b/Tests/Server/CMakeLists.txt index 03f50429d..8913406fc 100644 --- a/Tests/Server/CMakeLists.txt +++ b/Tests/Server/CMakeLists.txt @@ -10,6 +10,7 @@ macro(do_test bsname file) "${CMAKE_SOURCE_DIR}/${file}" "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + "${CMAKE_GENERATOR}" RESULT_VARIABLE test_result ) @@ -20,5 +21,6 @@ endmacro() do_test("test_handshake" "tc_handshake.json") do_test("test_globalSettings" "tc_globalSettings.json") +do_test("test_buildsystem1" "tc_buildsystem1.json") add_executable(Server empty.cpp) diff --git a/Tests/Server/buildsystem1/CMakeLists.txt b/Tests/Server/buildsystem1/CMakeLists.txt new file mode 100644 index 000000000..d690472d1 --- /dev/null +++ b/Tests/Server/buildsystem1/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.4) + +project(buildsystem2) + +set(var1 123) + +set(var2 345) + +add_executable(main main.cpp) + +add_executable(m_other main.cpp) + +add_library(foo foo.cpp) + +function(f1) +endfunction() + +set(var3 345) + +add_library(someImportedLib UNKNOWN IMPORTED) + +add_subdirectory(subdir) diff --git a/Tests/Server/buildsystem1/foo.cpp b/Tests/Server/buildsystem1/foo.cpp new file mode 100644 index 000000000..7f39d7175 --- /dev/null +++ b/Tests/Server/buildsystem1/foo.cpp @@ -0,0 +1,5 @@ + +int foo() +{ + return 0; +} diff --git a/Tests/Server/buildsystem1/main.cpp b/Tests/Server/buildsystem1/main.cpp new file mode 100644 index 000000000..766b7751b --- /dev/null +++ b/Tests/Server/buildsystem1/main.cpp @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} diff --git a/Tests/Server/buildsystem1/subdir/CMakeLists.txt b/Tests/Server/buildsystem1/subdir/CMakeLists.txt new file mode 100644 index 000000000..915731286 --- /dev/null +++ b/Tests/Server/buildsystem1/subdir/CMakeLists.txt @@ -0,0 +1,5 @@ +set(bar4 something) + +set(bar5 more) + +add_executable(ooo empty.cpp) diff --git a/Tests/Server/buildsystem1/subdir/empty.cpp b/Tests/Server/buildsystem1/subdir/empty.cpp new file mode 100644 index 000000000..7f39d7175 --- /dev/null +++ b/Tests/Server/buildsystem1/subdir/empty.cpp @@ -0,0 +1,5 @@ + +int foo() +{ + return 0; +} diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py index 8beaeefa2..94384ebab 100644 --- a/Tests/Server/cmakelib.py +++ b/Tests/Server/cmakelib.py @@ -102,10 +102,20 @@ def waitForMessage(cmakeCommand, expected): sys.exit(-1) return packet -def waitForReply(cmakeCommand, originalType, cookie): - packet = waitForRawMessage(cmakeCommand) - if packet['cookie'] != cookie or packet['type'] != 'reply' or packet['inReplyTo'] != originalType: +def waitForReply(cmakeCommand, originalType, cookie, skipProgress): + gotResult = False + while True: + packet = waitForRawMessage(cmakeCommand) + t = packet['type'] + if packet['cookie'] != cookie or packet['inReplyTo'] != originalType: + sys.exit(1) + if t == 'message' or t == 'progress': + if skipProgress: + continue + if t == 'reply': + break sys.exit(1) + return packet def waitForError(cmakeCommand, originalType, cookie, message): @@ -126,10 +136,10 @@ def handshake(cmakeCommand, major, minor, source, build, generator, extraGenerat writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version, 'cookie': 'TEST_HANDSHAKE', 'sourceDirectory': source, 'buildDirectory': build, 'generator': generator, 'extraGenerator': extraGenerator }) - waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE') + waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE', False) def validateGlobalSettings(cmakeCommand, cmakeCommandPath, data): - packet = waitForReply(cmakeCommand, 'globalSettings', '') + packet = waitForReply(cmakeCommand, 'globalSettings', '', False) capabilities = packet['capabilities'] diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py index d2bf92ebb..72f82ba4c 100644 --- a/Tests/Server/server-test.py +++ b/Tests/Server/server-test.py @@ -1,24 +1,25 @@ -import sys, cmakelib, json +import sys, cmakelib, json, os, shutil debug = True cmakeCommand = sys.argv[1] testFile = sys.argv[2] sourceDir = sys.argv[3] -buildDir = sys.argv[4] +buildDir = sys.argv[4] + "/" + os.path.splitext(os.path.basename(testFile))[0] +cmakeGenerator = sys.argv[5] -print("SourceDir: ", sourceDir, " -- BuildDir: ", buildDir) +print("Test:", testFile, + "\n-- SourceDir:", sourceDir, + "\n-- BuildDir:", buildDir, + "\n-- Generator:", cmakeGenerator) + +if os.path.exists(buildDir): + shutil.rmtree(buildDir) proc = cmakelib.initProc(cmakeCommand) with open(testFile) as f: - testText = f.read() - testText = testText.replace('%BUILDDIR%', buildDir) - testText = testText.replace('%SOURCEDIR%', sourceDir) - testData = json.loads(testText) - -buildDir = sys.argv[3] -sourceDir = sys.argv[4] + testData = json.loads(f.read()) for obj in testData: if 'sendRaw' in obj: @@ -38,9 +39,11 @@ for obj in testData: if debug: print("Waiting for reply:", json.dumps(data)) originalType = "" cookie = "" + skipProgress = False; if 'cookie' in data: cookie = data['cookie'] if 'type' in data: originalType = data['type'] - cmakelib.waitForReply(proc, originalType, cookie) + if 'skipProgress' in data: skipProgress = data['skipProgress'] + cmakelib.waitForReply(proc, originalType, cookie, skipProgress) elif 'error' in obj: data = obj['error'] if debug: print("Waiting for error:", json.dumps(data)) @@ -68,8 +71,8 @@ for obj in testData: if debug: print("Doing handshake:", json.dumps(data)) major = -1 minor = -1 - generator = 'Ninja' - extraGenerator = 'CodeBlocks' + generator = cmakeGenerator + extraGenerator = '' sourceDirectory = sourceDir buildDirectory = buildDir if 'major' in data: major = data['major'] @@ -78,14 +81,18 @@ for obj in testData: if 'sourceDirectory' in data: sourceDirectory = data['sourceDirectory'] if 'generator' in data: generator = data['generator'] if 'extraGenerator' in data: extraGenerator = data['extraGenerator'] + if not os.path.isabs(buildDirectory): + buildDirectory = buildDir + "/" + buildDirectory + if not os.path.isabs(sourceDirectory): + sourceDirectory = sourceDir + "/" + sourceDirectory cmakelib.handshake(proc, major, minor, sourceDirectory, buildDirectory, generator, extraGenerator) elif 'validateGlobalSettings' in obj: data = obj['validateGlobalSettings'] if not 'buildDirectory' in data: data['buildDirectory'] = buildDir if not 'sourceDirectory' in data: data['sourceDirectory'] = sourceDir - if not 'generator' in data: data['generator'] = 'Ninja' - if not 'extraGenerator' in data: data['extraGenerator'] = 'CodeBlocks' + if not 'generator' in data: data['generator'] = cmakeGenerator + if not 'extraGenerator' in data: data['extraGenerator'] = '' cmakelib.validateGlobalSettings(proc, cmakeCommand, data) elif 'message' in obj: print("MESSAGE:", obj["message"]) diff --git a/Tests/Server/tc_buildsystem1.json b/Tests/Server/tc_buildsystem1.json new file mode 100644 index 000000000..08831b7c4 --- /dev/null +++ b/Tests/Server/tc_buildsystem1.json @@ -0,0 +1,27 @@ +[ +{ "message": "Testing globalSettings" }, + +{ "handshake": {"major": 1, "sourceDirectory":"buildsystem1","buildDirectory":"buildsystem1"} }, + +{ "message": "Configure:" }, +{ "send": { "type": "configure", "cookie":"CONFIG" } }, +{ "reply": { "type": "configure", "cookie":"CONFIG", "skipProgress":true } }, + +{ "message": "Compute:" }, +{ "send": { "type": "compute", "cookie":"COMPUTE" } }, +{ "reply": { "type": "compute", "cookie":"COMPUTE", "skipProgress":true } }, + +{ "message": "Codemodel:" }, +{ "send": { "type": "codemodel", "cookie":"CODEMODEL" } }, +{ "reply": { "type": "codemodel", "cookie":"CODEMODEL" } }, + +{ "message": "CMake Inputs:"}, +{ "send": { "type": "cmakeInputs", "cookie":"INPUTS" } }, +{ "reply": { "type": "cmakeInputs", "cookie":"INPUTS" } }, + +{ "message": "Cache:"}, +{ "send": { "type": "cache", "cookie":"CACHE" } }, +{ "reply": { "type": "cache", "cookie":"CACHE" } }, + +{ "message": "Everything ok." } +]