cmCacheManager.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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 <algorithm>
  5. #include <cmsys/FStream.hxx>
  6. #include <cmsys/Glob.hxx>
  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", CM_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,
  199. CacheIterator const& i)
  200. {
  201. for (const char** p = this->PersistentProperties; *p; ++p) {
  202. if (const char* value = i.GetProperty(*p)) {
  203. std::string helpstring = *p;
  204. helpstring += " property for variable: ";
  205. helpstring += i.GetName();
  206. cmCacheManager::OutputHelpString(os, helpstring);
  207. std::string key = i.GetName();
  208. key += "-";
  209. key += *p;
  210. this->OutputKey(os, key);
  211. os << ":INTERNAL=";
  212. this->OutputValue(os, value);
  213. os << "\n";
  214. }
  215. }
  216. }
  217. bool cmCacheManager::SaveCache(const std::string& path)
  218. {
  219. std::string cacheFile = path;
  220. cacheFile += "/CMakeCache.txt";
  221. cmGeneratedFileStream fout(cacheFile.c_str());
  222. fout.SetCopyIfDifferent(true);
  223. if (!fout) {
  224. cmSystemTools::Error("Unable to open cache file for save. ",
  225. cacheFile.c_str());
  226. cmSystemTools::ReportLastSystemError("");
  227. return false;
  228. }
  229. // before writing the cache, update the version numbers
  230. // to the
  231. char temp[1024];
  232. sprintf(temp, "%d", cmVersion::GetMinorVersion());
  233. this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", temp,
  234. "Minor version of cmake used to create the "
  235. "current loaded cache",
  236. cmStateEnums::INTERNAL);
  237. sprintf(temp, "%d", cmVersion::GetMajorVersion());
  238. this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", temp,
  239. "Major version of cmake used to create the "
  240. "current loaded cache",
  241. cmStateEnums::INTERNAL);
  242. sprintf(temp, "%d", cmVersion::GetPatchVersion());
  243. this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION", temp,
  244. "Patch version of cmake used to create the "
  245. "current loaded cache",
  246. cmStateEnums::INTERNAL);
  247. // Let us store the current working directory so that if somebody
  248. // Copies it, he will not be surprised
  249. std::string currentcwd = path;
  250. if (currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' && currentcwd[1] == ':') {
  251. // Cast added to avoid compiler warning. Cast is ok because
  252. // value is guaranteed to fit in char by the above if...
  253. currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
  254. }
  255. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  256. this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
  257. "This is the directory where this CMakeCache.txt"
  258. " was created",
  259. cmStateEnums::INTERNAL);
  260. /* clang-format off */
  261. fout << "# This is the CMakeCache file.\n"
  262. << "# For build in directory: " << currentcwd << "\n"
  263. << "# It was generated by CMake: "
  264. << cmSystemTools::GetCMakeCommand() << std::endl;
  265. /* clang-format on */
  266. /* clang-format off */
  267. fout << "# You can edit this file to change values found and used by cmake."
  268. << std::endl
  269. << "# If you do not want to change any of the values, simply exit the "
  270. "editor." << std::endl
  271. << "# If you do want to change a value, simply edit, save, and exit "
  272. "the editor." << std::endl
  273. << "# The syntax for the file is as follows:\n"
  274. << "# KEY:TYPE=VALUE\n"
  275. << "# KEY is the name of a variable in the cache.\n"
  276. << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT "
  277. "TYPE!." << std::endl
  278. << "# VALUE is the current value for the KEY.\n\n";
  279. /* clang-format on */
  280. fout << "########################\n";
  281. fout << "# EXTERNAL cache entries\n";
  282. fout << "########################\n";
  283. fout << "\n";
  284. for (std::map<std::string, CacheEntry>::const_iterator i =
  285. this->Cache.begin();
  286. i != this->Cache.end(); ++i) {
  287. const CacheEntry& ce = (*i).second;
  288. cmStateEnums::CacheEntryType t = ce.Type;
  289. if (!ce.Initialized) {
  290. /*
  291. // This should be added in, but is not for now.
  292. cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
  293. "\" is uninitialized");
  294. */
  295. } else if (t != cmStateEnums::INTERNAL) {
  296. // Format is key:type=value
  297. if (const char* help = ce.GetProperty("HELPSTRING")) {
  298. cmCacheManager::OutputHelpString(fout, help);
  299. } else {
  300. cmCacheManager::OutputHelpString(fout, "Missing description");
  301. }
  302. this->OutputKey(fout, i->first);
  303. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  304. this->OutputValue(fout, ce.Value);
  305. fout << "\n\n";
  306. }
  307. }
  308. fout << "\n";
  309. fout << "########################\n";
  310. fout << "# INTERNAL cache entries\n";
  311. fout << "########################\n";
  312. fout << "\n";
  313. for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
  314. i.Next()) {
  315. if (!i.Initialized()) {
  316. continue;
  317. }
  318. cmStateEnums::CacheEntryType t = i.GetType();
  319. this->WritePropertyEntries(fout, i);
  320. if (t == cmStateEnums::INTERNAL) {
  321. // Format is key:type=value
  322. if (const char* help = i.GetProperty("HELPSTRING")) {
  323. this->OutputHelpString(fout, help);
  324. }
  325. this->OutputKey(fout, i.GetName());
  326. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  327. this->OutputValue(fout, i.GetValue());
  328. fout << "\n";
  329. }
  330. }
  331. fout << "\n";
  332. fout.Close();
  333. std::string checkCacheFile = path;
  334. checkCacheFile += cmake::GetCMakeFilesDirectory();
  335. cmSystemTools::MakeDirectory(checkCacheFile.c_str());
  336. checkCacheFile += "/cmake.check_cache";
  337. cmsys::ofstream checkCache(checkCacheFile.c_str());
  338. if (!checkCache) {
  339. cmSystemTools::Error("Unable to open check cache file for write. ",
  340. checkCacheFile.c_str());
  341. return false;
  342. }
  343. checkCache << "# This file is generated by cmake for dependency checking "
  344. "of the CMakeCache.txt file\n";
  345. return true;
  346. }
  347. bool cmCacheManager::DeleteCache(const std::string& path)
  348. {
  349. std::string cacheFile = path;
  350. cmSystemTools::ConvertToUnixSlashes(cacheFile);
  351. std::string cmakeFiles = cacheFile;
  352. cacheFile += "/CMakeCache.txt";
  353. if (cmSystemTools::FileExists(cacheFile.c_str())) {
  354. cmSystemTools::RemoveFile(cacheFile);
  355. // now remove the files in the CMakeFiles directory
  356. // this cleans up language cache files
  357. cmakeFiles += cmake::GetCMakeFilesDirectory();
  358. if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
  359. cmSystemTools::RemoveADirectory(cmakeFiles);
  360. }
  361. }
  362. return true;
  363. }
  364. void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
  365. {
  366. // support : in key name by double quoting
  367. const char* q =
  368. (key.find(':') != key.npos || key.find("//") == 0) ? "\"" : "";
  369. fout << q << key << q;
  370. }
  371. void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
  372. {
  373. // if value has trailing space or tab, enclose it in single quotes
  374. if (!value.empty() &&
  375. (value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) {
  376. fout << '\'' << value << '\'';
  377. } else {
  378. fout << value;
  379. }
  380. }
  381. void cmCacheManager::OutputHelpString(std::ostream& fout,
  382. const std::string& helpString)
  383. {
  384. std::string::size_type end = helpString.size();
  385. if (end == 0) {
  386. return;
  387. }
  388. std::string oneLine;
  389. std::string::size_type pos = 0;
  390. for (std::string::size_type i = 0; i <= end; i++) {
  391. if ((i == end) || (helpString[i] == '\n') ||
  392. ((i - pos >= 60) && (helpString[i] == ' '))) {
  393. fout << "//";
  394. if (helpString[pos] == '\n') {
  395. pos++;
  396. fout << "\\n";
  397. }
  398. oneLine = helpString.substr(pos, i - pos);
  399. fout << oneLine << "\n";
  400. pos = i;
  401. }
  402. }
  403. }
  404. void cmCacheManager::RemoveCacheEntry(const std::string& key)
  405. {
  406. CacheEntryMap::iterator i = this->Cache.find(key);
  407. if (i != this->Cache.end()) {
  408. this->Cache.erase(i);
  409. }
  410. }
  411. cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
  412. const std::string& key)
  413. {
  414. CacheEntryMap::iterator i = this->Cache.find(key);
  415. if (i != this->Cache.end()) {
  416. return &i->second;
  417. }
  418. return CM_NULLPTR;
  419. }
  420. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char* key)
  421. {
  422. return CacheIterator(*this, key);
  423. }
  424. const char* cmCacheManager::GetInitializedCacheValue(
  425. const std::string& key) const
  426. {
  427. CacheEntryMap::const_iterator i = this->Cache.find(key);
  428. if (i != this->Cache.end() && i->second.Initialized) {
  429. return i->second.Value.c_str();
  430. }
  431. return CM_NULLPTR;
  432. }
  433. void cmCacheManager::PrintCache(std::ostream& out) const
  434. {
  435. out << "=================================================" << std::endl;
  436. out << "CMakeCache Contents:" << std::endl;
  437. for (std::map<std::string, CacheEntry>::const_iterator i =
  438. this->Cache.begin();
  439. i != this->Cache.end(); ++i) {
  440. if ((*i).second.Type != cmStateEnums::INTERNAL) {
  441. out << (*i).first << " = " << (*i).second.Value << std::endl;
  442. }
  443. }
  444. out << "\n\n";
  445. out << "To change values in the CMakeCache, " << std::endl
  446. << "edit CMakeCache.txt in your output directory.\n";
  447. out << "=================================================" << std::endl;
  448. }
  449. void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
  450. const char* helpString,
  451. cmStateEnums::CacheEntryType type)
  452. {
  453. CacheEntry& e = this->Cache[key];
  454. if (value) {
  455. e.Value = value;
  456. e.Initialized = true;
  457. } else {
  458. e.Value = "";
  459. }
  460. e.Type = type;
  461. // make sure we only use unix style paths
  462. if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
  463. if (e.Value.find(';') != e.Value.npos) {
  464. std::vector<std::string> paths;
  465. cmSystemTools::ExpandListArgument(e.Value, paths);
  466. const char* sep = "";
  467. e.Value = "";
  468. for (std::vector<std::string>::iterator i = paths.begin();
  469. i != paths.end(); ++i) {
  470. cmSystemTools::ConvertToUnixSlashes(*i);
  471. e.Value += sep;
  472. e.Value += *i;
  473. sep = ";";
  474. }
  475. } else {
  476. cmSystemTools::ConvertToUnixSlashes(e.Value);
  477. }
  478. }
  479. e.SetProperty("HELPSTRING", helpString
  480. ? helpString
  481. : "(This variable does not exist and should not be used)");
  482. }
  483. bool cmCacheManager::CacheIterator::IsAtEnd() const
  484. {
  485. return this->Position == this->Container.Cache.end();
  486. }
  487. void cmCacheManager::CacheIterator::Begin()
  488. {
  489. this->Position = this->Container.Cache.begin();
  490. }
  491. bool cmCacheManager::CacheIterator::Find(const std::string& key)
  492. {
  493. this->Position = this->Container.Cache.find(key);
  494. return !this->IsAtEnd();
  495. }
  496. void cmCacheManager::CacheIterator::Next()
  497. {
  498. if (!this->IsAtEnd()) {
  499. ++this->Position;
  500. }
  501. }
  502. std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
  503. {
  504. return this->GetEntry().GetPropertyList();
  505. }
  506. void cmCacheManager::CacheIterator::SetValue(const char* value)
  507. {
  508. if (this->IsAtEnd()) {
  509. return;
  510. }
  511. CacheEntry* entry = &this->GetEntry();
  512. if (value) {
  513. entry->Value = value;
  514. entry->Initialized = true;
  515. } else {
  516. entry->Value = "";
  517. }
  518. }
  519. bool cmCacheManager::CacheIterator::GetValueAsBool() const
  520. {
  521. return cmSystemTools::IsOn(this->GetEntry().Value.c_str());
  522. }
  523. std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
  524. {
  525. return this->Properties.GetPropertyList();
  526. }
  527. const char* cmCacheManager::CacheEntry::GetProperty(
  528. const std::string& prop) const
  529. {
  530. if (prop == "TYPE") {
  531. return cmState::CacheEntryTypeToString(this->Type);
  532. }
  533. if (prop == "VALUE") {
  534. return this->Value.c_str();
  535. }
  536. return this->Properties.GetPropertyValue(prop);
  537. }
  538. void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
  539. const char* value)
  540. {
  541. if (prop == "TYPE") {
  542. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  543. } else if (prop == "VALUE") {
  544. this->Value = value ? value : "";
  545. } else {
  546. this->Properties.SetProperty(prop, value);
  547. }
  548. }
  549. void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
  550. const char* value,
  551. bool asString)
  552. {
  553. if (prop == "TYPE") {
  554. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  555. } else if (prop == "VALUE") {
  556. if (value) {
  557. if (!this->Value.empty() && *value && !asString) {
  558. this->Value += ";";
  559. }
  560. this->Value += value;
  561. }
  562. } else {
  563. this->Properties.AppendProperty(prop, value, asString);
  564. }
  565. }
  566. const char* cmCacheManager::CacheIterator::GetProperty(
  567. const std::string& prop) const
  568. {
  569. if (!this->IsAtEnd()) {
  570. return this->GetEntry().GetProperty(prop);
  571. }
  572. return CM_NULLPTR;
  573. }
  574. void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
  575. const char* v)
  576. {
  577. if (!this->IsAtEnd()) {
  578. this->GetEntry().SetProperty(p, v);
  579. }
  580. }
  581. void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
  582. const char* v,
  583. bool asString)
  584. {
  585. if (!this->IsAtEnd()) {
  586. this->GetEntry().AppendProperty(p, v, asString);
  587. }
  588. }
  589. bool cmCacheManager::CacheIterator::GetPropertyAsBool(
  590. const std::string& prop) const
  591. {
  592. if (const char* value = this->GetProperty(prop)) {
  593. return cmSystemTools::IsOn(value);
  594. }
  595. return false;
  596. }
  597. void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
  598. {
  599. this->SetProperty(p, v ? "ON" : "OFF");
  600. }
  601. bool cmCacheManager::CacheIterator::PropertyExists(
  602. const std::string& prop) const
  603. {
  604. return this->GetProperty(prop) != CM_NULLPTR;
  605. }