|
|
|
/* 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";
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|