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 "cmGlobVerificationManager.h"
7 #include "cmsys/FStream.hxx"
9 #include "cmGeneratedFileStream.h"
10 #include "cmListFileCache.h"
11 #include "cmMessageType.h"
12 #include "cmMessenger.h"
13 #include "cmStringAlgorithms.h"
14 #include "cmSystemTools.h"
15 #include "cmVersion.h"
17 bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path,
18 cmMessenger* messenger)
20 if (this->Cache.empty()) {
24 std::string scriptFile = cmStrCat(path, "/CMakeFiles");
25 std::string stampFile = scriptFile;
26 cmSystemTools::MakeDirectory(scriptFile);
27 scriptFile += "/VerifyGlobs.cmake";
28 stampFile += "/cmake.verify_globs";
29 cmGeneratedFileStream verifyScriptFile(scriptFile);
30 verifyScriptFile.SetCopyIfDifferent(true);
31 if (!verifyScriptFile) {
32 cmSystemTools::Error("Unable to open verification script file for save. " +
34 cmSystemTools::ReportLastSystemError("");
38 verifyScriptFile << std::boolalpha;
39 verifyScriptFile << "# CMAKE generated file: DO NOT EDIT!\n"
40 << "# Generated by CMake Version "
41 << cmVersion::GetMajorVersion() << "."
42 << cmVersion::GetMinorVersion() << "\n";
44 verifyScriptFile << "cmake_policy(SET CMP0009 NEW)\n";
46 for (auto const& i : this->Cache) {
47 CacheEntryKey k = std::get<0>(i);
48 CacheEntryValue v = std::get<1>(i);
54 verifyScriptFile << "\n";
56 for (auto const& bt : v.Backtraces) {
57 verifyScriptFile << "# " << std::get<0>(bt);
58 messenger->PrintBacktraceTitle(verifyScriptFile, std::get<1>(bt));
59 verifyScriptFile << "\n";
62 k.PrintGlobCommand(verifyScriptFile, "NEW_GLOB");
63 verifyScriptFile << "\n";
65 verifyScriptFile << "set(OLD_GLOB\n";
66 for (const std::string& file : v.Files) {
67 verifyScriptFile << " \"" << file << "\"\n";
69 verifyScriptFile << " )\n";
71 verifyScriptFile << "if(NOT \"${NEW_GLOB}\" STREQUAL \"${OLD_GLOB}\")\n"
72 << " message(\"-- GLOB mismatch!\")\n"
73 << " file(TOUCH_NOCREATE \"" << stampFile << "\")\n"
76 verifyScriptFile.Close();
78 cmsys::ofstream verifyStampFile(stampFile.c_str());
79 if (!verifyStampFile) {
80 cmSystemTools::Error("Unable to open verification stamp file for write. " +
84 verifyStampFile << "# This file is generated by CMake for checking of the "
85 "VerifyGlobs.cmake file\n";
86 this->VerifyScript = scriptFile;
87 this->VerifyStamp = stampFile;
91 bool cmGlobVerificationManager::DoWriteVerifyTarget() const
93 return !this->VerifyScript.empty() && !this->VerifyStamp.empty();
96 bool cmGlobVerificationManager::CacheEntryKey::operator<(
97 const CacheEntryKey& r) const
99 if (this->Recurse < r.Recurse) {
102 if (this->Recurse > r.Recurse) {
105 if (this->ListDirectories < r.ListDirectories) {
108 if (this->ListDirectories > r.ListDirectories) {
111 if (this->FollowSymlinks < r.FollowSymlinks) {
114 if (this->FollowSymlinks > r.FollowSymlinks) {
117 if (this->Relative < r.Relative) {
120 if (this->Relative > r.Relative) {
123 if (this->Expression < r.Expression) {
126 if (this->Expression > r.Expression) {
132 void cmGlobVerificationManager::CacheEntryKey::PrintGlobCommand(
133 std::ostream& out, const std::string& cmdVar)
135 out << "file(GLOB" << (this->Recurse ? "_RECURSE " : " ");
136 out << cmdVar << " ";
137 if (this->Recurse && this->FollowSymlinks) {
138 out << "FOLLOW_SYMLINKS ";
140 out << "LIST_DIRECTORIES " << this->ListDirectories << " ";
141 if (!this->Relative.empty()) {
142 out << "RELATIVE \"" << this->Relative << "\" ";
144 out << "\"" << this->Expression << "\")";
147 void cmGlobVerificationManager::AddCacheEntry(
148 const bool recurse, const bool listDirectories, const bool followSymlinks,
149 const std::string& relative, const std::string& expression,
150 const std::vector<std::string>& files, const std::string& variable,
151 const cmListFileBacktrace& backtrace, cmMessenger* messenger)
153 CacheEntryKey key = CacheEntryKey(recurse, listDirectories, followSymlinks,
154 relative, expression);
155 CacheEntryValue& value = this->Cache[key];
156 if (!value.Initialized) {
158 value.Initialized = true;
159 value.Backtraces.emplace_back(variable, backtrace);
160 } else if (value.Initialized && value.Files != files) {
161 std::ostringstream message;
162 message << std::boolalpha;
163 message << "The glob expression\n ";
164 key.PrintGlobCommand(message, variable);
165 message << "\nwas already present in the glob cache but the directory "
166 "contents have changed during the configuration run.\n";
167 message << "Matching glob expressions:";
168 for (auto const& bt : value.Backtraces) {
169 message << "\n " << std::get<0>(bt);
170 messenger->PrintBacktraceTitle(message, std::get<1>(bt));
172 messenger->IssueMessage(MessageType::FATAL_ERROR, message.str(),
175 value.Backtraces.emplace_back(variable, backtrace);
179 void cmGlobVerificationManager::Reset()
182 this->VerifyScript.clear();
183 this->VerifyStamp.clear();