cmCacheManager.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  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 (auto const& i : this->Cache) {
  284. CacheEntry const& ce = i.second;
  285. cmStateEnums::CacheEntryType t = ce.Type;
  286. if (!ce.Initialized) {
  287. /*
  288. // This should be added in, but is not for now.
  289. cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
  290. "\" is uninitialized");
  291. */
  292. } else if (t != cmStateEnums::INTERNAL) {
  293. // Format is key:type=value
  294. if (const char* help = ce.GetProperty("HELPSTRING")) {
  295. cmCacheManager::OutputHelpString(fout, help);
  296. } else {
  297. cmCacheManager::OutputHelpString(fout, "Missing description");
  298. }
  299. this->OutputKey(fout, i.first);
  300. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  301. this->OutputValue(fout, ce.Value);
  302. fout << "\n\n";
  303. }
  304. }
  305. fout << "\n";
  306. fout << "########################\n";
  307. fout << "# INTERNAL cache entries\n";
  308. fout << "########################\n";
  309. fout << "\n";
  310. for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
  311. i.Next()) {
  312. if (!i.Initialized()) {
  313. continue;
  314. }
  315. cmStateEnums::CacheEntryType t = i.GetType();
  316. this->WritePropertyEntries(fout, i);
  317. if (t == cmStateEnums::INTERNAL) {
  318. // Format is key:type=value
  319. if (const char* help = i.GetProperty("HELPSTRING")) {
  320. this->OutputHelpString(fout, help);
  321. }
  322. this->OutputKey(fout, i.GetName());
  323. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  324. this->OutputValue(fout, i.GetValue());
  325. fout << "\n";
  326. }
  327. }
  328. fout << "\n";
  329. fout.Close();
  330. std::string checkCacheFile = path;
  331. checkCacheFile += cmake::GetCMakeFilesDirectory();
  332. cmSystemTools::MakeDirectory(checkCacheFile.c_str());
  333. checkCacheFile += "/cmake.check_cache";
  334. cmsys::ofstream checkCache(checkCacheFile.c_str());
  335. if (!checkCache) {
  336. cmSystemTools::Error("Unable to open check cache file for write. ",
  337. checkCacheFile.c_str());
  338. return false;
  339. }
  340. checkCache << "# This file is generated by cmake for dependency checking "
  341. "of the CMakeCache.txt file\n";
  342. return true;
  343. }
  344. bool cmCacheManager::DeleteCache(const std::string& path)
  345. {
  346. std::string cacheFile = path;
  347. cmSystemTools::ConvertToUnixSlashes(cacheFile);
  348. std::string cmakeFiles = cacheFile;
  349. cacheFile += "/CMakeCache.txt";
  350. if (cmSystemTools::FileExists(cacheFile.c_str())) {
  351. cmSystemTools::RemoveFile(cacheFile);
  352. // now remove the files in the CMakeFiles directory
  353. // this cleans up language cache files
  354. cmakeFiles += cmake::GetCMakeFilesDirectory();
  355. if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
  356. cmSystemTools::RemoveADirectory(cmakeFiles);
  357. }
  358. }
  359. return true;
  360. }
  361. void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
  362. {
  363. // support : in key name by double quoting
  364. const char* q =
  365. (key.find(':') != std::string::npos || key.find("//") == 0) ? "\"" : "";
  366. fout << q << key << q;
  367. }
  368. void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
  369. {
  370. // if value has trailing space or tab, enclose it in single quotes
  371. if (!value.empty() &&
  372. (value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) {
  373. fout << '\'' << value << '\'';
  374. } else {
  375. fout << value;
  376. }
  377. }
  378. void cmCacheManager::OutputHelpString(std::ostream& fout,
  379. const std::string& helpString)
  380. {
  381. std::string::size_type end = helpString.size();
  382. if (end == 0) {
  383. return;
  384. }
  385. std::string oneLine;
  386. std::string::size_type pos = 0;
  387. for (std::string::size_type i = 0; i <= end; i++) {
  388. if ((i == end) || (helpString[i] == '\n') ||
  389. ((i - pos >= 60) && (helpString[i] == ' '))) {
  390. fout << "//";
  391. if (helpString[pos] == '\n') {
  392. pos++;
  393. fout << "\\n";
  394. }
  395. oneLine = helpString.substr(pos, i - pos);
  396. fout << oneLine << "\n";
  397. pos = i;
  398. }
  399. }
  400. }
  401. void cmCacheManager::RemoveCacheEntry(const std::string& key)
  402. {
  403. CacheEntryMap::iterator i = this->Cache.find(key);
  404. if (i != this->Cache.end()) {
  405. this->Cache.erase(i);
  406. }
  407. }
  408. cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
  409. const std::string& key)
  410. {
  411. CacheEntryMap::iterator i = this->Cache.find(key);
  412. if (i != this->Cache.end()) {
  413. return &i->second;
  414. }
  415. return nullptr;
  416. }
  417. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char* key)
  418. {
  419. return CacheIterator(*this, key);
  420. }
  421. const char* cmCacheManager::GetInitializedCacheValue(
  422. const std::string& key) const
  423. {
  424. CacheEntryMap::const_iterator i = this->Cache.find(key);
  425. if (i != this->Cache.end() && i->second.Initialized) {
  426. return i->second.Value.c_str();
  427. }
  428. return nullptr;
  429. }
  430. void cmCacheManager::PrintCache(std::ostream& out) const
  431. {
  432. out << "=================================================" << std::endl;
  433. out << "CMakeCache Contents:" << std::endl;
  434. for (auto const& i : this->Cache) {
  435. if (i.second.Type != cmStateEnums::INTERNAL) {
  436. out << i.first << " = " << i.second.Value << std::endl;
  437. }
  438. }
  439. out << "\n\n";
  440. out << "To change values in the CMakeCache, " << std::endl
  441. << "edit CMakeCache.txt in your output directory.\n";
  442. out << "=================================================" << std::endl;
  443. }
  444. void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
  445. const char* helpString,
  446. cmStateEnums::CacheEntryType type)
  447. {
  448. CacheEntry& e = this->Cache[key];
  449. if (value) {
  450. e.Value = value;
  451. e.Initialized = true;
  452. } else {
  453. e.Value.clear();
  454. }
  455. e.Type = type;
  456. // make sure we only use unix style paths
  457. if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
  458. if (e.Value.find(';') != std::string::npos) {
  459. std::vector<std::string> paths;
  460. cmSystemTools::ExpandListArgument(e.Value, paths);
  461. const char* sep = "";
  462. e.Value = "";
  463. for (std::string& i : paths) {
  464. cmSystemTools::ConvertToUnixSlashes(i);
  465. e.Value += sep;
  466. e.Value += i;
  467. sep = ";";
  468. }
  469. } else {
  470. cmSystemTools::ConvertToUnixSlashes(e.Value);
  471. }
  472. }
  473. e.SetProperty("HELPSTRING", helpString
  474. ? helpString
  475. : "(This variable does not exist and should not be used)");
  476. }
  477. bool cmCacheManager::CacheIterator::IsAtEnd() const
  478. {
  479. return this->Position == this->Container.Cache.end();
  480. }
  481. void cmCacheManager::CacheIterator::Begin()
  482. {
  483. this->Position = this->Container.Cache.begin();
  484. }
  485. bool cmCacheManager::CacheIterator::Find(const std::string& key)
  486. {
  487. this->Position = this->Container.Cache.find(key);
  488. return !this->IsAtEnd();
  489. }
  490. void cmCacheManager::CacheIterator::Next()
  491. {
  492. if (!this->IsAtEnd()) {
  493. ++this->Position;
  494. }
  495. }
  496. std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
  497. {
  498. return this->GetEntry().GetPropertyList();
  499. }
  500. void cmCacheManager::CacheIterator::SetValue(const char* value)
  501. {
  502. if (this->IsAtEnd()) {
  503. return;
  504. }
  505. CacheEntry* entry = &this->GetEntry();
  506. if (value) {
  507. entry->Value = value;
  508. entry->Initialized = true;
  509. } else {
  510. entry->Value.clear();
  511. }
  512. }
  513. bool cmCacheManager::CacheIterator::GetValueAsBool() const
  514. {
  515. return cmSystemTools::IsOn(this->GetEntry().Value.c_str());
  516. }
  517. std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
  518. {
  519. return this->Properties.GetPropertyList();
  520. }
  521. const char* cmCacheManager::CacheEntry::GetProperty(
  522. const std::string& prop) const
  523. {
  524. if (prop == "TYPE") {
  525. return cmState::CacheEntryTypeToString(this->Type);
  526. }
  527. if (prop == "VALUE") {
  528. return this->Value.c_str();
  529. }
  530. return this->Properties.GetPropertyValue(prop);
  531. }
  532. void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
  533. const char* value)
  534. {
  535. if (prop == "TYPE") {
  536. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  537. } else if (prop == "VALUE") {
  538. this->Value = value ? value : "";
  539. } else {
  540. this->Properties.SetProperty(prop, value);
  541. }
  542. }
  543. void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
  544. const char* value,
  545. bool asString)
  546. {
  547. if (prop == "TYPE") {
  548. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  549. } else if (prop == "VALUE") {
  550. if (value) {
  551. if (!this->Value.empty() && *value && !asString) {
  552. this->Value += ";";
  553. }
  554. this->Value += value;
  555. }
  556. } else {
  557. this->Properties.AppendProperty(prop, value, asString);
  558. }
  559. }
  560. const char* cmCacheManager::CacheIterator::GetProperty(
  561. const std::string& prop) const
  562. {
  563. if (!this->IsAtEnd()) {
  564. return this->GetEntry().GetProperty(prop);
  565. }
  566. return nullptr;
  567. }
  568. void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
  569. const char* v)
  570. {
  571. if (!this->IsAtEnd()) {
  572. this->GetEntry().SetProperty(p, v);
  573. }
  574. }
  575. void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
  576. const char* v,
  577. bool asString)
  578. {
  579. if (!this->IsAtEnd()) {
  580. this->GetEntry().AppendProperty(p, v, asString);
  581. }
  582. }
  583. bool cmCacheManager::CacheIterator::GetPropertyAsBool(
  584. const std::string& prop) const
  585. {
  586. if (const char* value = this->GetProperty(prop)) {
  587. return cmSystemTools::IsOn(value);
  588. }
  589. return false;
  590. }
  591. void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
  592. {
  593. this->SetProperty(p, v ? "ON" : "OFF");
  594. }
  595. bool cmCacheManager::CacheIterator::PropertyExists(
  596. const std::string& prop) const
  597. {
  598. return this->GetProperty(prop) != nullptr;
  599. }