| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmGlobVerificationManager.h" |
| |
| #include <sstream> |
| |
| #include "cmsys/FStream.hxx" |
| |
| #include "cmGeneratedFileStream.h" |
| #include "cmListFileCache.h" |
| #include "cmStringAlgorithms.h" |
| #include "cmSystemTools.h" |
| #include "cmVersion.h" |
| |
| bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path) |
| { |
| if (this->Cache.empty()) { |
| return true; |
| } |
| |
| std::string scriptFile = cmStrCat(path, "/CMakeFiles"); |
| std::string stampFile = scriptFile; |
| cmSystemTools::MakeDirectory(scriptFile); |
| scriptFile += "/VerifyGlobs.cmake"; |
| stampFile += "/cmake.verify_globs"; |
| cmGeneratedFileStream verifyScriptFile(scriptFile); |
| verifyScriptFile.SetCopyIfDifferent(true); |
| if (!verifyScriptFile) { |
| cmSystemTools::Error("Unable to open verification script file for save. " + |
| scriptFile); |
| cmSystemTools::ReportLastSystemError(""); |
| return false; |
| } |
| |
| verifyScriptFile << std::boolalpha; |
| verifyScriptFile << "# CMAKE generated file: DO NOT EDIT!\n" |
| << "# Generated by CMake Version " |
| << cmVersion::GetMajorVersion() << "." |
| << cmVersion::GetMinorVersion() << "\n"; |
| |
| verifyScriptFile << "cmake_policy(SET CMP0009 NEW)\n"; |
| |
| for (auto const& i : this->Cache) { |
| CacheEntryKey k = std::get<0>(i); |
| CacheEntryValue v = std::get<1>(i); |
| |
| if (!v.Initialized) { |
| continue; |
| } |
| |
| verifyScriptFile << "\n"; |
| |
| for (auto const& bt : v.Backtraces) { |
| verifyScriptFile << "# " << std::get<0>(bt); |
| std::get<1>(bt).PrintTitle(verifyScriptFile); |
| verifyScriptFile << "\n"; |
| } |
| |
| k.PrintGlobCommand(verifyScriptFile, "NEW_GLOB"); |
| verifyScriptFile << "\n"; |
| |
| verifyScriptFile << "set(OLD_GLOB\n"; |
| for (const std::string& file : v.Files) { |
| verifyScriptFile << " \"" << file << "\"\n"; |
| } |
| verifyScriptFile << " )\n"; |
| |
| verifyScriptFile << "if(NOT \"${NEW_GLOB}\" STREQUAL \"${OLD_GLOB}\")\n" |
| << " message(\"-- GLOB mismatch!\")\n" |
| << " file(TOUCH_NOCREATE \"" << stampFile << "\")\n" |
| << "endif()\n"; |
| } |
| verifyScriptFile.Close(); |
| |
| cmsys::ofstream verifyStampFile(stampFile.c_str()); |
| if (!verifyStampFile) { |
| cmSystemTools::Error("Unable to open verification stamp file for write. " + |
| stampFile); |
| return false; |
| } |
| verifyStampFile << "# This file is generated by CMake for checking of the " |
| "VerifyGlobs.cmake file\n"; |
| this->VerifyScript = scriptFile; |
| this->VerifyStamp = stampFile; |
| return true; |
| } |
| |
| bool cmGlobVerificationManager::DoWriteVerifyTarget() const |
| { |
| return !this->VerifyScript.empty() && !this->VerifyStamp.empty(); |
| } |
| |
| bool cmGlobVerificationManager::CacheEntryKey::operator<( |
| const CacheEntryKey& r) const |
| { |
| if (this->Recurse < r.Recurse) { |
| return true; |
| } |
| if (this->Recurse > r.Recurse) { |
| return false; |
| } |
| if (this->ListDirectories < r.ListDirectories) { |
| return true; |
| } |
| if (this->ListDirectories > r.ListDirectories) { |
| return false; |
| } |
| if (this->FollowSymlinks < r.FollowSymlinks) { |
| return true; |
| } |
| if (this->FollowSymlinks > r.FollowSymlinks) { |
| return false; |
| } |
| if (this->Relative < r.Relative) { |
| return true; |
| } |
| if (this->Relative > r.Relative) { |
| return false; |
| } |
| if (this->Expression < r.Expression) { |
| return true; |
| } |
| if (this->Expression > r.Expression) { |
| return false; |
| } |
| return false; |
| } |
| |
| void cmGlobVerificationManager::CacheEntryKey::PrintGlobCommand( |
| std::ostream& out, const std::string& cmdVar) |
| { |
| out << "file(GLOB" << (this->Recurse ? "_RECURSE " : " "); |
| out << cmdVar << " "; |
| if (this->Recurse && this->FollowSymlinks) { |
| out << "FOLLOW_SYMLINKS "; |
| } |
| out << "LIST_DIRECTORIES " << this->ListDirectories << " "; |
| if (!this->Relative.empty()) { |
| out << "RELATIVE \"" << this->Relative << "\" "; |
| } |
| out << "\"" << this->Expression << "\")"; |
| } |
| |
| void cmGlobVerificationManager::AddCacheEntry( |
| const bool recurse, const bool listDirectories, const bool followSymlinks, |
| const std::string& relative, const std::string& expression, |
| const std::vector<std::string>& files, const std::string& variable, |
| const cmListFileBacktrace& backtrace) |
| { |
| CacheEntryKey key = CacheEntryKey(recurse, listDirectories, followSymlinks, |
| relative, expression); |
| CacheEntryValue& value = this->Cache[key]; |
| if (!value.Initialized) { |
| value.Files = files; |
| value.Initialized = true; |
| value.Backtraces.emplace_back(variable, backtrace); |
| } else if (value.Initialized && value.Files != files) { |
| std::ostringstream message; |
| message << std::boolalpha; |
| message << "The glob expression\n"; |
| key.PrintGlobCommand(message, variable); |
| backtrace.PrintTitle(message); |
| message << "\nwas already present in the glob cache but the directory\n" |
| "contents have changed during the configuration run.\n"; |
| message << "Matching glob expressions:"; |
| for (auto const& bt : value.Backtraces) { |
| message << "\n " << std::get<0>(bt); |
| std::get<1>(bt).PrintTitle(message); |
| } |
| cmSystemTools::Error(message.str()); |
| } else { |
| value.Backtraces.emplace_back(variable, backtrace); |
| } |
| } |
| |
| void cmGlobVerificationManager::Reset() |
| { |
| this->Cache.clear(); |
| this->VerifyScript.clear(); |
| this->VerifyStamp.clear(); |
| } |