cmCacheManager.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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 "cmCacheManager.h"
  4. #include "cmsys/FStream.hxx"
  5. #include "cmsys/Glob.hxx"
  6. #include <algorithm>
  7. #include <sstream>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "cmGeneratedFileStream.h"
  11. #include "cmState.h"
  12. #include "cmSystemTools.h"
  13. #include "cmVersion.h"
  14. #include "cmake.h"
  15. cmCacheManager::cmCacheManager()
  16. {
  17. this->CacheMajorVersion = 0;
  18. this->CacheMinorVersion = 0;
  19. }
  20. void cmCacheManager::CleanCMakeFiles(const std::string& path)
  21. {
  22. std::string glob = path;
  23. glob += cmake::GetCMakeFilesDirectory();
  24. glob += "/*.cmake";
  25. cmsys::Glob globIt;
  26. globIt.FindFiles(glob);
  27. std::vector<std::string> files = globIt.GetFiles();
  28. std::for_each(files.begin(), files.end(), cmSystemTools::RemoveFile);
  29. }
  30. bool cmCacheManager::LoadCache(const std::string& path, bool internal,
  31. std::set<std::string>& excludes,
  32. std::set<std::string>& includes)
  33. {
  34. std::string cacheFile = path;
  35. cacheFile += "/CMakeCache.txt";
  36. // clear the old cache, if we are reading in internal values
  37. if (internal) {
  38. this->Cache.clear();
  39. }
  40. if (!cmSystemTools::FileExists(cacheFile.c_str())) {
  41. this->CleanCMakeFiles(path);
  42. return false;
  43. }
  44. cmsys::ifstream fin(cacheFile.c_str());
  45. if (!fin) {
  46. return false;
  47. }
  48. const char* realbuffer;
  49. std::string buffer;
  50. std::string entryKey;
  51. unsigned int lineno = 0;
  52. while (fin) {
  53. // Format is key:type=value
  54. std::string helpString;
  55. CacheEntry e;
  56. cmSystemTools::GetLineFromStream(fin, buffer);
  57. lineno++;
  58. realbuffer = buffer.c_str();
  59. while (*realbuffer != '0' &&
  60. (*realbuffer == ' ' || *realbuffer == '\t' || *realbuffer == '\r' ||
  61. *realbuffer == '\n')) {
  62. if (*realbuffer == '\n') {
  63. lineno++;
  64. }
  65. realbuffer++;
  66. }
  67. // skip blank lines and comment lines
  68. if (realbuffer[0] == '#' || realbuffer[0] == 0) {
  69. continue;
  70. }
  71. while (realbuffer[0] == '/' && realbuffer[1] == '/') {
  72. if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) {
  73. helpString += "\n";
  74. helpString += &realbuffer[4];
  75. } else {
  76. helpString += &realbuffer[2];
  77. }
  78. cmSystemTools::GetLineFromStream(fin, buffer);
  79. lineno++;
  80. realbuffer = buffer.c_str();
  81. if (!fin) {
  82. continue;
  83. }
  84. }
  85. e.SetProperty("HELPSTRING", helpString.c_str());
  86. if (cmState::ParseCacheEntry(realbuffer, entryKey, e.Value, e.Type)) {
  87. if (excludes.find(entryKey) == excludes.end()) {
  88. // Load internal values if internal is set.
  89. // If the entry is not internal to the cache being loaded
  90. // or if it is in the list of internal entries to be
  91. // imported, load it.
  92. if (internal || (e.Type != cmStateEnums::INTERNAL) ||
  93. (includes.find(entryKey) != includes.end())) {
  94. // If we are loading the cache from another project,
  95. // make all loaded entries internal so that it is
  96. // not visible in the gui
  97. if (!internal) {
  98. e.Type = cmStateEnums::INTERNAL;
  99. helpString = "DO NOT EDIT, ";
  100. helpString += entryKey;
  101. helpString += " loaded from external file. "
  102. "To change this value edit this file: ";
  103. helpString += path;
  104. helpString += "/CMakeCache.txt";
  105. e.SetProperty("HELPSTRING", helpString.c_str());
  106. }
  107. if (!this->ReadPropertyEntry(entryKey, e)) {
  108. e.Initialized = true;
  109. this->Cache[entryKey] = e;
  110. }
  111. }
  112. }
  113. } else {
  114. std::ostringstream error;
  115. error << "Parse error in cache file " << cacheFile;
  116. error << " on line " << lineno << ". Offending entry: " << realbuffer;
  117. cmSystemTools::Error(error.str().c_str());
  118. }
  119. }
  120. this->CacheMajorVersion = 0;
  121. this->CacheMinorVersion = 0;
  122. if (const char* cmajor =
  123. this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) {
  124. unsigned int v = 0;
  125. if (sscanf(cmajor, "%u", &v) == 1) {
  126. this->CacheMajorVersion = v;
  127. }
  128. if (const char* cminor =
  129. this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) {
  130. if (sscanf(cminor, "%u", &v) == 1) {
  131. this->CacheMinorVersion = v;
  132. }
  133. }
  134. } else {
  135. // CMake version not found in the list file.
  136. // Set as version 0.0
  137. this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", "0",
  138. "Minor version of cmake used to create the "
  139. "current loaded cache",
  140. cmStateEnums::INTERNAL);
  141. this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", "0",
  142. "Major version of cmake used to create the "
  143. "current loaded cache",
  144. cmStateEnums::INTERNAL);
  145. }
  146. // check to make sure the cache directory has not
  147. // been moved
  148. const char* oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
  149. if (internal && oldDir) {
  150. std::string currentcwd = path;
  151. std::string oldcwd = oldDir;
  152. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  153. currentcwd += "/CMakeCache.txt";
  154. oldcwd += "/CMakeCache.txt";
  155. if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
  156. std::string message =
  157. std::string("The current CMakeCache.txt directory ") + currentcwd +
  158. std::string(" is different than the directory ") +
  159. std::string(this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) +
  160. std::string(" where CMakeCache.txt was created. This may result "
  161. "in binaries being created in the wrong place. If you "
  162. "are not sure, reedit the CMakeCache.txt");
  163. cmSystemTools::Error(message.c_str());
  164. }
  165. }
  166. return true;
  167. }
  168. const char* cmCacheManager::PersistentProperties[] = { "ADVANCED", "MODIFIED",
  169. "STRINGS", nullptr };
  170. bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey,
  171. CacheEntry& e)
  172. {
  173. // All property entries are internal.
  174. if (e.Type != cmStateEnums::INTERNAL) {
  175. return false;
  176. }
  177. const char* end = entryKey.c_str() + entryKey.size();
  178. for (const char** p = this->PersistentProperties; *p; ++p) {
  179. std::string::size_type plen = strlen(*p) + 1;
  180. if (entryKey.size() > plen && *(end - plen) == '-' &&
  181. strcmp(end - plen + 1, *p) == 0) {
  182. std::string key = entryKey.substr(0, entryKey.size() - plen);
  183. cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str());
  184. if (it.IsAtEnd()) {
  185. // Create an entry and store the property.
  186. CacheEntry& ne = this->Cache[key];
  187. ne.Type = cmStateEnums::UNINITIALIZED;
  188. ne.SetProperty(*p, e.Value.c_str());
  189. } else {
  190. // Store this property on its entry.
  191. it.SetProperty(*p, e.Value.c_str());
  192. }
  193. return true;
  194. }
  195. }
  196. return false;
  197. }
  198. void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i)
  199. {
  200. for (const char** p = this->PersistentProperties; *p; ++p) {
  201. if (const char* value = i.GetProperty(*p)) {
  202. std::string helpstring = *p;
  203. helpstring += " property for variable: ";
  204. helpstring += i.GetName();
  205. cmCacheManager::OutputHelpString(os, helpstring);
  206. std::string key = i.GetName();
  207. key += "-";
  208. key += *p;
  209. this->OutputKey(os, key);
  210. os << ":INTERNAL=";
  211. this->OutputValue(os, value);
  212. os << "\n";
  213. }
  214. }
  215. }
  216. bool cmCacheManager::SaveCache(const std::string& path)
  217. {
  218. std::string cacheFile = path;
  219. cacheFile += "/CMakeCache.txt";
  220. cmGeneratedFileStream fout(cacheFile.c_str());
  221. fout.SetCopyIfDifferent(true);
  222. if (!fout) {
  223. cmSystemTools::Error("Unable to open cache file for save. ",
  224. cacheFile.c_str());
  225. cmSystemTools::ReportLastSystemError("");
  226. return false;
  227. }
  228. // before writing the cache, update the version numbers
  229. // to the
  230. char temp[1024];
  231. sprintf(temp, "%d", cmVersion::GetMinorVersion());
  232. this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", temp,
  233. "Minor version of cmake used to create the "
  234. "current loaded cache",
  235. cmStateEnums::INTERNAL);
  236. sprintf(temp, "%d", cmVersion::GetMajorVersion());
  237. this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", temp,
  238. "Major version of cmake used to create the "
  239. "current loaded cache",
  240. cmStateEnums::INTERNAL);
  241. sprintf(temp, "%d", cmVersion::GetPatchVersion());
  242. this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION", temp,
  243. "Patch version of cmake used to create the "
  244. "current loaded cache",
  245. cmStateEnums::INTERNAL);
  246. // Let us store the current working directory so that if somebody
  247. // Copies it, he will not be surprised
  248. std::string currentcwd = path;
  249. if (currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' && currentcwd[1] == ':') {
  250. // Cast added to avoid compiler warning. Cast is ok because
  251. // value is guaranteed to fit in char by the above if...
  252. currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
  253. }
  254. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  255. this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
  256. "This is the directory where this CMakeCache.txt"
  257. " was created",
  258. cmStateEnums::INTERNAL);
  259. /* clang-format off */
  260. fout << "# This is the CMakeCache file.\n"
  261. << "# For build in directory: " << currentcwd << "\n"
  262. << "# It was generated by CMake: "
  263. << cmSystemTools::GetCMakeCommand() << std::endl;
  264. /* clang-format on */
  265. /* clang-format off */
  266. fout << "# You can edit this file to change values found and used by cmake."
  267. << std::endl
  268. << "# If you do not want to change any of the values, simply exit the "
  269. "editor." << std::endl
  270. << "# If you do want to change a value, simply edit, save, and exit "
  271. "the editor." << std::endl
  272. << "# The syntax for the file is as follows:\n"
  273. << "# KEY:TYPE=VALUE\n"
  274. << "# KEY is the name of a variable in the cache.\n"
  275. << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT "
  276. "TYPE!." << std::endl
  277. << "# VALUE is the current value for the KEY.\n\n";
  278. /* clang-format on */
  279. fout << "########################\n";
  280. fout << "# EXTERNAL cache entries\n";
  281. fout << "########################\n";
  282. fout << "\n";
  283. for (std::map<std::string, CacheEntry>::const_iterator i =
  284. this->Cache.begin();
  285. i != this->Cache.end(); ++i) {
  286. const CacheEntry& ce = (*i).second;
  287. cmStateEnums::CacheEntryType t = ce.Type;
  288. if (!ce.Initialized) {
  289. /*
  290. // This should be added in, but is not for now.
  291. cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
  292. "\" is uninitialized");
  293. */
  294. } else if (t != cmStateEnums::INTERNAL) {
  295. // Format is key:type=value
  296. if (const char* help = ce.GetProperty("HELPSTRING")) {
  297. cmCacheManager::OutputHelpString(fout, help);
  298. } else {
  299. cmCacheManager::OutputHelpString(fout, "Missing description");
  300. }
  301. this->OutputKey(fout, i->first);
  302. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  303. this->OutputValue(fout, ce.Value);
  304. fout << "\n\n";
  305. }
  306. }
  307. fout << "\n";
  308. fout << "########################\n";
  309. fout << "# INTERNAL cache entries\n";
  310. fout << "########################\n";
  311. fout << "\n";
  312. for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
  313. i.Next()) {
  314. if (!i.Initialized()) {
  315. continue;
  316. }
  317. cmStateEnums::CacheEntryType t = i.GetType();
  318. this->WritePropertyEntries(fout, i);
  319. if (t == cmStateEnums::INTERNAL) {
  320. // Format is key:type=value
  321. if (const char* help = i.GetProperty("HELPSTRING")) {
  322. this->OutputHelpString(fout, help);
  323. }
  324. this->OutputKey(fout, i.GetName());
  325. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  326. this->OutputValue(fout, i.GetValue());
  327. fout << "\n";
  328. }
  329. }
  330. fout << "\n";
  331. fout.Close();
  332. std::string checkCacheFile = path;
  333. checkCacheFile += cmake::GetCMakeFilesDirectory();
  334. cmSystemTools::MakeDirectory(checkCacheFile.c_str());
  335. checkCacheFile += "/cmake.check_cache";
  336. cmsys::ofstream checkCache(checkCacheFile.c_str());
  337. if (!checkCache) {
  338. cmSystemTools::Error("Unable to open check cache file for write. ",
  339. checkCacheFile.c_str());
  340. return false;
  341. }
  342. checkCache << "# This file is generated by cmake for dependency checking "
  343. "of the CMakeCache.txt file\n";
  344. return true;
  345. }
  346. bool cmCacheManager::DeleteCache(const std::string& path)
  347. {
  348. std::string cacheFile = path;
  349. cmSystemTools::ConvertToUnixSlashes(cacheFile);
  350. std::string cmakeFiles = cacheFile;
  351. cacheFile += "/CMakeCache.txt";
  352. if (cmSystemTools::FileExists(cacheFile.c_str())) {
  353. cmSystemTools::RemoveFile(cacheFile);
  354. // now remove the files in the CMakeFiles directory
  355. // this cleans up language cache files
  356. cmakeFiles += cmake::GetCMakeFilesDirectory();
  357. if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
  358. cmSystemTools::RemoveADirectory(cmakeFiles);
  359. }
  360. }
  361. return true;
  362. }
  363. void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
  364. {
  365. // support : in key name by double quoting
  366. const char* q =
  367. (key.find(':') != std::string::npos || key.find("//") == 0) ? "\"" : "";
  368. fout << q << key << q;
  369. }
  370. void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
  371. {
  372. // if value has trailing space or tab, enclose it in single quotes
  373. if (!value.empty() &&
  374. (value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) {
  375. fout << '\'' << value << '\'';
  376. } else {
  377. fout << value;
  378. }
  379. }
  380. void cmCacheManager::OutputHelpString(std::ostream& fout,
  381. const std::string& helpString)
  382. {
  383. std::string::size_type end = helpString.size();
  384. if (end == 0) {
  385. return;
  386. }
  387. std::string oneLine;
  388. std::string::size_type pos = 0;
  389. for (std::string::size_type i = 0; i <= end; i++) {
  390. if ((i == end) || (helpString[i] == '\n') ||
  391. ((i - pos >= 60) && (helpString[i] == ' '))) {
  392. fout << "//";
  393. if (helpString[pos] == '\n') {
  394. pos++;
  395. fout << "\\n";
  396. }
  397. oneLine = helpString.substr(pos, i - pos);
  398. fout << oneLine << "\n";
  399. pos = i;
  400. }
  401. }
  402. }
  403. void cmCacheManager::RemoveCacheEntry(const std::string& key)
  404. {
  405. CacheEntryMap::iterator i = this->Cache.find(key);
  406. if (i != this->Cache.end()) {
  407. this->Cache.erase(i);
  408. }
  409. }
  410. cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
  411. const std::string& key)
  412. {
  413. CacheEntryMap::iterator i = this->Cache.find(key);
  414. if (i != this->Cache.end()) {
  415. return &i->second;
  416. }
  417. return nullptr;
  418. }
  419. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char* key)
  420. {
  421. return CacheIterator(*this, key);
  422. }
  423. const char* cmCacheManager::GetInitializedCacheValue(
  424. const std::string& key) const
  425. {
  426. CacheEntryMap::const_iterator i = this->Cache.find(key);
  427. if (i != this->Cache.end() && i->second.Initialized) {
  428. return i->second.Value.c_str();
  429. }
  430. return nullptr;
  431. }
  432. void cmCacheManager::PrintCache(std::ostream& out) const
  433. {
  434. out << "=================================================" << std::endl;
  435. out << "CMakeCache Contents:" << std::endl;
  436. for (std::map<std::string, CacheEntry>::const_iterator i =
  437. this->Cache.begin();
  438. i != this->Cache.end(); ++i) {
  439. if ((*i).second.Type != cmStateEnums::INTERNAL) {
  440. out << (*i).first << " = " << (*i).second.Value << std::endl;
  441. }
  442. }
  443. out << "\n\n";
  444. out << "To change values in the CMakeCache, " << std::endl
  445. << "edit CMakeCache.txt in your output directory.\n";
  446. out << "=================================================" << std::endl;
  447. }
  448. void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
  449. const char* helpString,
  450. cmStateEnums::CacheEntryType type)
  451. {
  452. CacheEntry& e = this->Cache[key];
  453. if (value) {
  454. e.Value = value;
  455. e.Initialized = true;
  456. } else {
  457. e.Value = "";
  458. }
  459. e.Type = type;
  460. // make sure we only use unix style paths
  461. if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
  462. if (e.Value.find(';') != std::string::npos) {
  463. std::vector<std::string> paths;
  464. cmSystemTools::ExpandListArgument(e.Value, paths);
  465. const char* sep = "";
  466. e.Value = "";
  467. for (std::vector<std::string>::iterator i = paths.begin();
  468. i != paths.end(); ++i) {
  469. cmSystemTools::ConvertToUnixSlashes(*i);
  470. e.Value += sep;
  471. e.Value += *i;
  472. sep = ";";
  473. }
  474. } else {
  475. cmSystemTools::ConvertToUnixSlashes(e.Value);
  476. }
  477. }
  478. e.SetProperty("HELPSTRING", helpString
  479. ? helpString
  480. : "(This variable does not exist and should not be used)");
  481. }
  482. bool cmCacheManager::CacheIterator::IsAtEnd() const
  483. {
  484. return this->Position == this->Container.Cache.end();
  485. }
  486. void cmCacheManager::CacheIterator::Begin()
  487. {
  488. this->Position = this->Container.Cache.begin();
  489. }
  490. bool cmCacheManager::CacheIterator::Find(const std::string& key)
  491. {
  492. this->Position = this->Container.Cache.find(key);
  493. return !this->IsAtEnd();
  494. }
  495. void cmCacheManager::CacheIterator::Next()
  496. {
  497. if (!this->IsAtEnd()) {
  498. ++this->Position;
  499. }
  500. }
  501. std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
  502. {
  503. return this->GetEntry().GetPropertyList();
  504. }
  505. void cmCacheManager::CacheIterator::SetValue(const char* value)
  506. {
  507. if (this->IsAtEnd()) {
  508. return;
  509. }
  510. CacheEntry* entry = &this->GetEntry();
  511. if (value) {
  512. entry->Value = value;
  513. entry->Initialized = true;
  514. } else {
  515. entry->Value = "";
  516. }
  517. }
  518. bool cmCacheManager::CacheIterator::GetValueAsBool() const
  519. {
  520. return cmSystemTools::IsOn(this->GetEntry().Value.c_str());
  521. }
  522. std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
  523. {
  524. return this->Properties.GetPropertyList();
  525. }
  526. const char* cmCacheManager::CacheEntry::GetProperty(
  527. const std::string& prop) const
  528. {
  529. if (prop == "TYPE") {
  530. return cmState::CacheEntryTypeToString(this->Type);
  531. }
  532. if (prop == "VALUE") {
  533. return this->Value.c_str();
  534. }
  535. return this->Properties.GetPropertyValue(prop);
  536. }
  537. void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
  538. const char* value)
  539. {
  540. if (prop == "TYPE") {
  541. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  542. } else if (prop == "VALUE") {
  543. this->Value = value ? value : "";
  544. } else {
  545. this->Properties.SetProperty(prop, value);
  546. }
  547. }
  548. void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
  549. const char* value,
  550. bool asString)
  551. {
  552. if (prop == "TYPE") {
  553. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  554. } else if (prop == "VALUE") {
  555. if (value) {
  556. if (!this->Value.empty() && *value && !asString) {
  557. this->Value += ";";
  558. }
  559. this->Value += value;
  560. }
  561. } else {
  562. this->Properties.AppendProperty(prop, value, asString);
  563. }
  564. }
  565. const char* cmCacheManager::CacheIterator::GetProperty(
  566. const std::string& prop) const
  567. {
  568. if (!this->IsAtEnd()) {
  569. return this->GetEntry().GetProperty(prop);
  570. }
  571. return nullptr;
  572. }
  573. void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
  574. const char* v)
  575. {
  576. if (!this->IsAtEnd()) {
  577. this->GetEntry().SetProperty(p, v);
  578. }
  579. }
  580. void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
  581. const char* v,
  582. bool asString)
  583. {
  584. if (!this->IsAtEnd()) {
  585. this->GetEntry().AppendProperty(p, v, asString);
  586. }
  587. }
  588. bool cmCacheManager::CacheIterator::GetPropertyAsBool(
  589. const std::string& prop) const
  590. {
  591. if (const char* value = this->GetProperty(prop)) {
  592. return cmSystemTools::IsOn(value);
  593. }
  594. return false;
  595. }
  596. void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
  597. {
  598. this->SetProperty(p, v ? "ON" : "OFF");
  599. }
  600. bool cmCacheManager::CacheIterator::PropertyExists(
  601. const std::string& prop) const
  602. {
  603. return this->GetProperty(prop) != nullptr;
  604. }