diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index cdd87d1c4..c5d496829 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -328,3 +328,30 @@ CMake will reply to this with:: [== CMake Server ==[ {"inReplyTo":"setGlobalSettings","type":"reply"} ]== CMake Server ==] + + +Type "configure" +^^^^^^^^^^^^^^^^ + +This request will configure a project for build. + +To configure a build directory already containing cmake files, it is enough to +set "buildDirectory" via "setGlobalSettings". To create a fresh build directory +you also need to set "currentGenerator" and "sourceDirectory" via "setGlobalSettings" +in addition to "buildDirectory". + +You may a list of strings to "configure" via the "cacheArguments" key. These +strings will be interpreted similar to command line arguments related to +cache handling that are passed to the cmake command line client. + +Example:: + + [== CMake Server ==[ + {"type":"configure", "cacheArguments":["-Dsomething=else"]} + ]== CMake Server ==] + +CMake will reply like this (after reporting progress for some time):: + + [== CMake Server ==[ + {"cookie":"","inReplyTo":"configure","type":"reply"} + ]== CMake Server ==] diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index 657fbd638..b78a1f40b 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -16,6 +16,7 @@ // Vocabulary: +static const std::string kCONFIGURE_TYPE = "configure"; static const std::string kERROR_TYPE = "error"; static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings"; static const std::string kHANDSHAKE_TYPE = "handshake"; @@ -26,6 +27,7 @@ static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings"; static const std::string kSIGNAL_TYPE = "signal"; 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 kCOOKIE_KEY = "cookie"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 55ae24e9d..06f517718 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -280,6 +280,9 @@ const cmServerResponse cmServerProtocol1_0::Process( { assert(this->m_State >= STATE_ACTIVE); + if (request.Type == kCONFIGURE_TYPE) { + return this->ProcessConfigure(request); + } if (request.Type == kGLOBAL_SETTINGS_TYPE) { return this->ProcessGlobalSettings(request); } @@ -295,6 +298,92 @@ bool cmServerProtocol1_0::IsExperimental() const return true; } +cmServerResponse cmServerProtocol1_0::ProcessConfigure( + const cmServerRequest& request) +{ + if (this->m_State == STATE_INACTIVE) { + return request.ReportError("This instance is inactive."); + } + + // Make sure the types of cacheArguments matches (if given): + std::vector cacheArgs; + bool cacheArgumentsError = false; + const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY]; + if (!passedArgs.isNull()) { + if (passedArgs.isString()) { + cacheArgs.push_back(passedArgs.asString()); + } else if (passedArgs.isArray()) { + for (auto i = passedArgs.begin(); i != passedArgs.end(); ++i) { + if (!i->isString()) { + cacheArgumentsError = true; + break; + } + cacheArgs.push_back(i->asString()); + } + } else { + cacheArgumentsError = true; + } + } + if (cacheArgumentsError) { + request.ReportError( + "cacheArguments must be unset, a string or an array of strings."); + } + + cmake* cm = this->CMakeInstance(); + std::string sourceDir = cm->GetHomeDirectory(); + const std::string buildDir = cm->GetHomeOutputDirectory(); + + if (buildDir.empty()) { + return request.ReportError( + "No build directory set via setGlobalSettings."); + } + + if (cm->LoadCache(buildDir)) { + // build directory has been set up before + const char* cachedSourceDir = + cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY"); + if (!cachedSourceDir) { + return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache."); + } + if (sourceDir.empty()) { + sourceDir = std::string(cachedSourceDir); + cm->SetHomeDirectory(sourceDir); + } + + const char* cachedGenerator = + cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR"); + if (cachedGenerator) { + cmGlobalGenerator* gen = cm->GetGlobalGenerator(); + if (gen && gen->GetName() != cachedGenerator) { + return request.ReportError("Configured generator does not match with " + "CMAKE_GENERATOR found in cache."); + } + } + } else { + // build directory has not been set up before + if (sourceDir.empty()) { + return request.ReportError("No sourceDirectory set via " + "setGlobalSettings and no cache found in " + "buildDirectory."); + } + } + + if (cm->AddCMakePaths() != 1) { + return request.ReportError("Failed to set CMake paths."); + } + + if (!cm->SetCacheArgs(cacheArgs)) { + return request.ReportError("cacheArguments could not be set."); + } + + int ret = cm->Configure(); + if (ret < 0) { + return request.ReportError("Configuration failed."); + } + m_State = STATE_CONFIGURED; + return request.Reply(Json::Value()); +} + cmServerResponse cmServerProtocol1_0::ProcessGlobalSettings( const cmServerRequest& request) { diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 21515b28e..c0148a450 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -118,13 +118,15 @@ private: std::string* errorMessage) override; // Handle requests: + cmServerResponse ProcessConfigure(const cmServerRequest& request); cmServerResponse ProcessGlobalSettings(const cmServerRequest& request); cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request); enum State { STATE_INACTIVE, - STATE_ACTIVE + STATE_ACTIVE, + STATE_CONFIGURED }; State m_State = STATE_INACTIVE; };