cmServerProtocol.cxx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmServerProtocol.h"
  4. #include "cmAlgorithms.h"
  5. #include "cmExternalMakefileProjectGenerator.h"
  6. #include "cmFileMonitor.h"
  7. #include "cmGlobalGenerator.h"
  8. #include "cmServer.h"
  9. #include "cmServerDictionary.h"
  10. #include "cmState.h"
  11. #include "cmSystemTools.h"
  12. #include "cm_uv.h"
  13. #include "cmake.h"
  14. #include <algorithm>
  15. #include <cassert>
  16. #include <functional>
  17. #include <memory>
  18. #include <string>
  19. #include <vector>
  20. // Get rid of some windows macros:
  21. #undef max
  22. namespace {
  23. std::vector<std::string> toStringList(const Json::Value& in)
  24. {
  25. std::vector<std::string> result;
  26. for (auto const& it : in) {
  27. result.push_back(it.asString());
  28. }
  29. return result;
  30. }
  31. } // namespace
  32. #include "cmJsonObjects.cxx"
  33. cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
  34. const std::string& t, const std::string& c,
  35. const Json::Value& d)
  36. : Type(t)
  37. , Cookie(c)
  38. , Data(d)
  39. , Connection(connection)
  40. , m_Server(server)
  41. {
  42. }
  43. void cmServerRequest::ReportProgress(int min, int current, int max,
  44. const std::string& message) const
  45. {
  46. this->m_Server->WriteProgress(*this, min, current, max, message);
  47. }
  48. void cmServerRequest::ReportMessage(const std::string& message,
  49. const std::string& title) const
  50. {
  51. m_Server->WriteMessage(*this, message, title);
  52. }
  53. cmServerResponse cmServerRequest::Reply(const Json::Value& data) const
  54. {
  55. cmServerResponse response(*this);
  56. response.SetData(data);
  57. return response;
  58. }
  59. cmServerResponse cmServerRequest::ReportError(const std::string& message) const
  60. {
  61. cmServerResponse response(*this);
  62. response.SetError(message);
  63. return response;
  64. }
  65. cmServerResponse::cmServerResponse(const cmServerRequest& request)
  66. : Type(request.Type)
  67. , Cookie(request.Cookie)
  68. {
  69. }
  70. void cmServerResponse::SetData(const Json::Value& data)
  71. {
  72. assert(this->m_Payload == PAYLOAD_UNKNOWN);
  73. if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) {
  74. this->SetError("Response contains cookie or type field.");
  75. return;
  76. }
  77. this->m_Payload = PAYLOAD_DATA;
  78. this->m_Data = data;
  79. }
  80. void cmServerResponse::SetError(const std::string& message)
  81. {
  82. assert(this->m_Payload == PAYLOAD_UNKNOWN);
  83. this->m_Payload = PAYLOAD_ERROR;
  84. this->m_ErrorMessage = message;
  85. }
  86. bool cmServerResponse::IsComplete() const
  87. {
  88. return this->m_Payload != PAYLOAD_UNKNOWN;
  89. }
  90. bool cmServerResponse::IsError() const
  91. {
  92. assert(this->m_Payload != PAYLOAD_UNKNOWN);
  93. return this->m_Payload == PAYLOAD_ERROR;
  94. }
  95. std::string cmServerResponse::ErrorMessage() const
  96. {
  97. if (this->m_Payload == PAYLOAD_ERROR) {
  98. return this->m_ErrorMessage;
  99. }
  100. return std::string();
  101. }
  102. Json::Value cmServerResponse::Data() const
  103. {
  104. assert(this->m_Payload != PAYLOAD_UNKNOWN);
  105. return this->m_Data;
  106. }
  107. bool cmServerProtocol::Activate(cmServer* server,
  108. const cmServerRequest& request,
  109. std::string* errorMessage)
  110. {
  111. assert(server);
  112. this->m_Server = server;
  113. this->m_CMakeInstance = cm::make_unique<cmake>(cmake::RoleProject);
  114. const bool result = this->DoActivate(request, errorMessage);
  115. if (!result) {
  116. this->m_CMakeInstance = nullptr;
  117. }
  118. return result;
  119. }
  120. cmFileMonitor* cmServerProtocol::FileMonitor() const
  121. {
  122. return this->m_Server ? this->m_Server->FileMonitor() : nullptr;
  123. }
  124. void cmServerProtocol::SendSignal(const std::string& name,
  125. const Json::Value& data) const
  126. {
  127. if (this->m_Server) {
  128. this->m_Server->WriteSignal(name, data);
  129. }
  130. }
  131. cmake* cmServerProtocol::CMakeInstance() const
  132. {
  133. return this->m_CMakeInstance.get();
  134. }
  135. bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/,
  136. std::string* /*errorMessage*/)
  137. {
  138. return true;
  139. }
  140. std::pair<int, int> cmServerProtocol1::ProtocolVersion() const
  141. {
  142. // Revision history
  143. // 1, 1 - Report backtraces in codemodel response
  144. // 1, 2 - Add target install destinations to codemodel
  145. // 1, 3 - Add a flag to target filegroups indicating whether or not the
  146. // filegroup is for INTERFACE_SOURCES
  147. return std::make_pair(1, 3);
  148. }
  149. static void setErrorMessage(std::string* errorMessage, const std::string& text)
  150. {
  151. if (errorMessage) {
  152. *errorMessage = text;
  153. }
  154. }
  155. static bool getOrTestHomeDirectory(cmState* state, std::string& value,
  156. std::string* errorMessage)
  157. {
  158. const std::string cachedValue =
  159. std::string(state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"));
  160. if (value.empty()) {
  161. value = cachedValue;
  162. return true;
  163. }
  164. const std::string suffix = "/CMakeLists.txt";
  165. const std::string cachedValueCML = cachedValue + suffix;
  166. const std::string valueCML = value + suffix;
  167. if (!cmSystemTools::SameFile(valueCML, cachedValueCML)) {
  168. setErrorMessage(errorMessage,
  169. std::string("\"CMAKE_HOME_DIRECTORY\" is set but "
  170. "incompatible with configured "
  171. "source directory value."));
  172. return false;
  173. }
  174. return true;
  175. }
  176. static bool getOrTestValue(cmState* state, const std::string& key,
  177. std::string& value,
  178. const std::string& keyDescription,
  179. std::string* errorMessage)
  180. {
  181. const char* entry = state->GetCacheEntryValue(key);
  182. const std::string cachedValue =
  183. entry == nullptr ? std::string() : std::string(entry);
  184. if (value.empty()) {
  185. value = cachedValue;
  186. }
  187. if (!cachedValue.empty() && cachedValue != value) {
  188. setErrorMessage(errorMessage,
  189. std::string("\"") + key +
  190. "\" is set but incompatible with configured " +
  191. keyDescription + " value.");
  192. return false;
  193. }
  194. return true;
  195. }
  196. bool cmServerProtocol1::DoActivate(const cmServerRequest& request,
  197. std::string* errorMessage)
  198. {
  199. std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString();
  200. const std::string buildDirectory =
  201. request.Data[kBUILD_DIRECTORY_KEY].asString();
  202. std::string generator = request.Data[kGENERATOR_KEY].asString();
  203. std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString();
  204. std::string toolset = request.Data[kTOOLSET_KEY].asString();
  205. std::string platform = request.Data[kPLATFORM_KEY].asString();
  206. if (buildDirectory.empty()) {
  207. setErrorMessage(errorMessage,
  208. std::string("\"") + kBUILD_DIRECTORY_KEY +
  209. "\" is missing.");
  210. return false;
  211. }
  212. cmake* cm = CMakeInstance();
  213. if (cmSystemTools::PathExists(buildDirectory)) {
  214. if (!cmSystemTools::FileIsDirectory(buildDirectory)) {
  215. setErrorMessage(errorMessage,
  216. std::string("\"") + kBUILD_DIRECTORY_KEY +
  217. "\" exists but is not a directory.");
  218. return false;
  219. }
  220. const std::string cachePath = cm->FindCacheFile(buildDirectory);
  221. if (cm->LoadCache(cachePath)) {
  222. cmState* state = cm->GetState();
  223. // Check generator:
  224. if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator",
  225. errorMessage)) {
  226. return false;
  227. }
  228. // check extra generator:
  229. if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator,
  230. "extra generator", errorMessage)) {
  231. return false;
  232. }
  233. // check sourcedir:
  234. if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) {
  235. return false;
  236. }
  237. // check toolset:
  238. if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset",
  239. errorMessage)) {
  240. return false;
  241. }
  242. // check platform:
  243. if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform,
  244. "platform", errorMessage)) {
  245. return false;
  246. }
  247. }
  248. }
  249. if (sourceDirectory.empty()) {
  250. setErrorMessage(errorMessage,
  251. std::string("\"") + kSOURCE_DIRECTORY_KEY +
  252. "\" is unset but required.");
  253. return false;
  254. }
  255. if (!cmSystemTools::FileIsDirectory(sourceDirectory)) {
  256. setErrorMessage(errorMessage,
  257. std::string("\"") + kSOURCE_DIRECTORY_KEY +
  258. "\" is not a directory.");
  259. return false;
  260. }
  261. if (generator.empty()) {
  262. setErrorMessage(errorMessage,
  263. std::string("\"") + kGENERATOR_KEY +
  264. "\" is unset but required.");
  265. return false;
  266. }
  267. std::vector<cmake::GeneratorInfo> generators;
  268. cm->GetRegisteredGenerators(generators);
  269. auto baseIt = std::find_if(generators.begin(), generators.end(),
  270. [&generator](const cmake::GeneratorInfo& info) {
  271. return info.name == generator;
  272. });
  273. if (baseIt == generators.end()) {
  274. setErrorMessage(errorMessage,
  275. std::string("Generator \"") + generator +
  276. "\" not supported.");
  277. return false;
  278. }
  279. auto extraIt = std::find_if(
  280. generators.begin(), generators.end(),
  281. [&generator, &extraGenerator](const cmake::GeneratorInfo& info) {
  282. return info.baseName == generator && info.extraName == extraGenerator;
  283. });
  284. if (extraIt == generators.end()) {
  285. setErrorMessage(errorMessage,
  286. std::string("The combination of generator \"" + generator +
  287. "\" and extra generator \"" + extraGenerator +
  288. "\" is not supported."));
  289. return false;
  290. }
  291. if (!extraIt->supportsToolset && !toolset.empty()) {
  292. setErrorMessage(errorMessage,
  293. std::string("Toolset was provided but is not supported by "
  294. "the requested generator."));
  295. return false;
  296. }
  297. if (!extraIt->supportsPlatform && !platform.empty()) {
  298. setErrorMessage(errorMessage,
  299. std::string("Platform was provided but is not supported "
  300. "by the requested generator."));
  301. return false;
  302. }
  303. this->GeneratorInfo =
  304. GeneratorInformation(generator, extraGenerator, toolset, platform,
  305. sourceDirectory, buildDirectory);
  306. this->m_State = STATE_ACTIVE;
  307. return true;
  308. }
  309. void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path,
  310. int event, int status)
  311. {
  312. assert(status == 0);
  313. static_cast<void>(status);
  314. if (!m_isDirty) {
  315. m_isDirty = true;
  316. SendSignal(kDIRTY_SIGNAL, Json::objectValue);
  317. }
  318. Json::Value obj = Json::objectValue;
  319. obj[kPATH_KEY] = path;
  320. Json::Value properties = Json::arrayValue;
  321. if (event & UV_RENAME) {
  322. properties.append(kRENAME_PROPERTY_VALUE);
  323. }
  324. if (event & UV_CHANGE) {
  325. properties.append(kCHANGE_PROPERTY_VALUE);
  326. }
  327. obj[kPROPERTIES_KEY] = properties;
  328. SendSignal(kFILE_CHANGE_SIGNAL, obj);
  329. }
  330. const cmServerResponse cmServerProtocol1::Process(
  331. const cmServerRequest& request)
  332. {
  333. assert(this->m_State >= STATE_ACTIVE);
  334. if (request.Type == kCACHE_TYPE) {
  335. return this->ProcessCache(request);
  336. }
  337. if (request.Type == kCMAKE_INPUTS_TYPE) {
  338. return this->ProcessCMakeInputs(request);
  339. }
  340. if (request.Type == kCODE_MODEL_TYPE) {
  341. return this->ProcessCodeModel(request);
  342. }
  343. if (request.Type == kCOMPUTE_TYPE) {
  344. return this->ProcessCompute(request);
  345. }
  346. if (request.Type == kCONFIGURE_TYPE) {
  347. return this->ProcessConfigure(request);
  348. }
  349. if (request.Type == kFILESYSTEM_WATCHERS_TYPE) {
  350. return this->ProcessFileSystemWatchers(request);
  351. }
  352. if (request.Type == kGLOBAL_SETTINGS_TYPE) {
  353. return this->ProcessGlobalSettings(request);
  354. }
  355. if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) {
  356. return this->ProcessSetGlobalSettings(request);
  357. }
  358. if (request.Type == kCTEST_INFO_TYPE) {
  359. return this->ProcessCTests(request);
  360. }
  361. return request.ReportError("Unknown command!");
  362. }
  363. bool cmServerProtocol1::IsExperimental() const
  364. {
  365. return true;
  366. }
  367. cmServerResponse cmServerProtocol1::ProcessCache(
  368. const cmServerRequest& request)
  369. {
  370. cmState* state = this->CMakeInstance()->GetState();
  371. Json::Value result = Json::objectValue;
  372. std::vector<std::string> allKeys = state->GetCacheEntryKeys();
  373. Json::Value list = Json::arrayValue;
  374. std::vector<std::string> keys = toStringList(request.Data[kKEYS_KEY]);
  375. if (keys.empty()) {
  376. keys = allKeys;
  377. } else {
  378. for (auto const& i : keys) {
  379. if (std::find(allKeys.begin(), allKeys.end(), i) == allKeys.end()) {
  380. return request.ReportError("Key \"" + i + "\" not found in cache.");
  381. }
  382. }
  383. }
  384. std::sort(keys.begin(), keys.end());
  385. for (auto const& key : keys) {
  386. Json::Value entry = Json::objectValue;
  387. entry[kKEY_KEY] = key;
  388. entry[kTYPE_KEY] =
  389. cmState::CacheEntryTypeToString(state->GetCacheEntryType(key));
  390. entry[kVALUE_KEY] = state->GetCacheEntryValue(key);
  391. Json::Value props = Json::objectValue;
  392. bool haveProperties = false;
  393. for (auto const& prop : state->GetCacheEntryPropertyList(key)) {
  394. haveProperties = true;
  395. props[prop] = state->GetCacheEntryProperty(key, prop);
  396. }
  397. if (haveProperties) {
  398. entry[kPROPERTIES_KEY] = props;
  399. }
  400. list.append(entry);
  401. }
  402. result[kCACHE_KEY] = list;
  403. return request.Reply(result);
  404. }
  405. cmServerResponse cmServerProtocol1::ProcessCMakeInputs(
  406. const cmServerRequest& request)
  407. {
  408. if (this->m_State < STATE_CONFIGURED) {
  409. return request.ReportError("This instance was not yet configured.");
  410. }
  411. const cmake* cm = this->CMakeInstance();
  412. const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot();
  413. const std::string& sourceDir = cm->GetHomeDirectory();
  414. Json::Value result = Json::objectValue;
  415. result[kSOURCE_DIRECTORY_KEY] = sourceDir;
  416. result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir;
  417. result[kBUILD_FILES_KEY] = DumpCMakeInputs(cm);
  418. return request.Reply(result);
  419. }
  420. cmServerResponse cmServerProtocol1::ProcessCodeModel(
  421. const cmServerRequest& request)
  422. {
  423. if (this->m_State != STATE_COMPUTED) {
  424. return request.ReportError("No build system was generated yet.");
  425. }
  426. return request.Reply(DumpCodeModel(this->CMakeInstance()));
  427. }
  428. cmServerResponse cmServerProtocol1::ProcessCompute(
  429. const cmServerRequest& request)
  430. {
  431. if (this->m_State > STATE_CONFIGURED) {
  432. return request.ReportError("This build system was already generated.");
  433. }
  434. if (this->m_State < STATE_CONFIGURED) {
  435. return request.ReportError("This project was not configured yet.");
  436. }
  437. cmake* cm = this->CMakeInstance();
  438. int ret = cm->Generate();
  439. if (ret < 0) {
  440. return request.ReportError("Failed to compute build system.");
  441. }
  442. m_State = STATE_COMPUTED;
  443. return request.Reply(Json::Value());
  444. }
  445. cmServerResponse cmServerProtocol1::ProcessConfigure(
  446. const cmServerRequest& request)
  447. {
  448. if (this->m_State == STATE_INACTIVE) {
  449. return request.ReportError("This instance is inactive.");
  450. }
  451. FileMonitor()->StopMonitoring();
  452. std::string errorMessage;
  453. cmake* cm = this->CMakeInstance();
  454. this->GeneratorInfo.SetupGenerator(cm, &errorMessage);
  455. if (!errorMessage.empty()) {
  456. return request.ReportError(errorMessage);
  457. }
  458. // Make sure the types of cacheArguments matches (if given):
  459. std::vector<std::string> cacheArgs = { "unused" };
  460. bool cacheArgumentsError = false;
  461. const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY];
  462. if (!passedArgs.isNull()) {
  463. if (passedArgs.isString()) {
  464. cacheArgs.push_back(passedArgs.asString());
  465. } else if (passedArgs.isArray()) {
  466. for (auto const& arg : passedArgs) {
  467. if (!arg.isString()) {
  468. cacheArgumentsError = true;
  469. break;
  470. }
  471. cacheArgs.push_back(arg.asString());
  472. }
  473. } else {
  474. cacheArgumentsError = true;
  475. }
  476. }
  477. if (cacheArgumentsError) {
  478. request.ReportError(
  479. "cacheArguments must be unset, a string or an array of strings.");
  480. }
  481. std::string sourceDir = cm->GetHomeDirectory();
  482. const std::string buildDir = cm->GetHomeOutputDirectory();
  483. cmGlobalGenerator* gg = cm->GetGlobalGenerator();
  484. if (buildDir.empty()) {
  485. return request.ReportError("No build directory set via Handshake.");
  486. }
  487. if (cm->LoadCache(buildDir)) {
  488. // build directory has been set up before
  489. const std::string* cachedSourceDir =
  490. cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
  491. if (!cachedSourceDir) {
  492. return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache.");
  493. }
  494. if (sourceDir.empty()) {
  495. sourceDir = *cachedSourceDir;
  496. cm->SetHomeDirectory(sourceDir);
  497. }
  498. const std::string* cachedGenerator =
  499. cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
  500. if (cachedGenerator) {
  501. if (gg && gg->GetName() != *cachedGenerator) {
  502. return request.ReportError("Configured generator does not match with "
  503. "CMAKE_GENERATOR found in cache.");
  504. }
  505. }
  506. } else {
  507. // build directory has not been set up before
  508. if (sourceDir.empty()) {
  509. return request.ReportError("No sourceDirectory set via "
  510. "setGlobalSettings and no cache found in "
  511. "buildDirectory.");
  512. }
  513. }
  514. cmSystemTools::ResetErrorOccuredFlag(); // Reset error state
  515. if (cm->AddCMakePaths() != 1) {
  516. return request.ReportError("Failed to set CMake paths.");
  517. }
  518. if (!cm->SetCacheArgs(cacheArgs)) {
  519. return request.ReportError("cacheArguments could not be set.");
  520. }
  521. int ret = cm->Configure();
  522. if (ret < 0) {
  523. return request.ReportError("Configuration failed.");
  524. }
  525. std::vector<std::string> toWatchList;
  526. getCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList, nullptr);
  527. FileMonitor()->MonitorPaths(toWatchList,
  528. [this](const std::string& p, int e, int s) {
  529. this->HandleCMakeFileChanges(p, e, s);
  530. });
  531. m_State = STATE_CONFIGURED;
  532. m_isDirty = false;
  533. return request.Reply(Json::Value());
  534. }
  535. cmServerResponse cmServerProtocol1::ProcessGlobalSettings(
  536. const cmServerRequest& request)
  537. {
  538. cmake* cm = this->CMakeInstance();
  539. Json::Value obj = Json::objectValue;
  540. // Capabilities information:
  541. obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(true);
  542. obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
  543. obj[kTRACE_KEY] = cm->GetTrace();
  544. obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand();
  545. obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized();
  546. obj[kWARN_UNUSED_KEY] = cm->GetWarnUnused();
  547. obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli();
  548. obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars();
  549. obj[kSOURCE_DIRECTORY_KEY] = this->GeneratorInfo.SourceDirectory;
  550. obj[kBUILD_DIRECTORY_KEY] = this->GeneratorInfo.BuildDirectory;
  551. // Currently used generator:
  552. obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName;
  553. obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName;
  554. return request.Reply(obj);
  555. }
  556. static void setBool(const cmServerRequest& request, const std::string& key,
  557. std::function<void(bool)> const& setter)
  558. {
  559. if (request.Data[key].isNull()) {
  560. return;
  561. }
  562. setter(request.Data[key].asBool());
  563. }
  564. cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings(
  565. const cmServerRequest& request)
  566. {
  567. const std::vector<std::string> boolValues = {
  568. kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY,
  569. kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY,
  570. kCHECK_SYSTEM_VARS_KEY
  571. };
  572. for (std::string const& i : boolValues) {
  573. if (!request.Data[i].isNull() && !request.Data[i].isBool()) {
  574. return request.ReportError("\"" + i +
  575. "\" must be unset or a bool value.");
  576. }
  577. }
  578. cmake* cm = this->CMakeInstance();
  579. setBool(request, kDEBUG_OUTPUT_KEY,
  580. [cm](bool e) { cm->SetDebugOutputOn(e); });
  581. setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); });
  582. setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); });
  583. setBool(request, kWARN_UNINITIALIZED_KEY,
  584. [cm](bool e) { cm->SetWarnUninitialized(e); });
  585. setBool(request, kWARN_UNUSED_KEY, [cm](bool e) { cm->SetWarnUnused(e); });
  586. setBool(request, kWARN_UNUSED_CLI_KEY,
  587. [cm](bool e) { cm->SetWarnUnusedCli(e); });
  588. setBool(request, kCHECK_SYSTEM_VARS_KEY,
  589. [cm](bool e) { cm->SetCheckSystemVars(e); });
  590. return request.Reply(Json::Value());
  591. }
  592. cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers(
  593. const cmServerRequest& request)
  594. {
  595. const cmFileMonitor* const fm = FileMonitor();
  596. Json::Value result = Json::objectValue;
  597. Json::Value files = Json::arrayValue;
  598. for (auto const& f : fm->WatchedFiles()) {
  599. files.append(f);
  600. }
  601. Json::Value directories = Json::arrayValue;
  602. for (auto const& d : fm->WatchedDirectories()) {
  603. directories.append(d);
  604. }
  605. result[kWATCHED_FILES_KEY] = files;
  606. result[kWATCHED_DIRECTORIES_KEY] = directories;
  607. return request.Reply(result);
  608. }
  609. cmServerResponse cmServerProtocol1::ProcessCTests(
  610. const cmServerRequest& request)
  611. {
  612. if (this->m_State < STATE_COMPUTED) {
  613. return request.ReportError("This instance was not yet computed.");
  614. }
  615. return request.Reply(DumpCTestInfo(this->CMakeInstance()));
  616. }
  617. cmServerProtocol1::GeneratorInformation::GeneratorInformation(
  618. const std::string& generatorName, const std::string& extraGeneratorName,
  619. const std::string& toolset, const std::string& platform,
  620. const std::string& sourceDirectory, const std::string& buildDirectory)
  621. : GeneratorName(generatorName)
  622. , ExtraGeneratorName(extraGeneratorName)
  623. , Toolset(toolset)
  624. , Platform(platform)
  625. , SourceDirectory(sourceDirectory)
  626. , BuildDirectory(buildDirectory)
  627. {
  628. }
  629. void cmServerProtocol1::GeneratorInformation::SetupGenerator(
  630. cmake* cm, std::string* errorMessage)
  631. {
  632. const std::string fullGeneratorName =
  633. cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
  634. GeneratorName, ExtraGeneratorName);
  635. cm->SetHomeDirectory(SourceDirectory);
  636. cm->SetHomeOutputDirectory(BuildDirectory);
  637. cmGlobalGenerator* gg = cm->CreateGlobalGenerator(fullGeneratorName);
  638. if (!gg) {
  639. setErrorMessage(
  640. errorMessage,
  641. std::string("Could not set up the requested combination of \"") +
  642. kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\"");
  643. return;
  644. }
  645. cm->SetGlobalGenerator(gg);
  646. cm->SetGeneratorToolset(Toolset);
  647. cm->SetGeneratorPlatform(Platform);
  648. }