1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-05-09 14:57:08 +08:00
CMake/Source/cmGlobVerificationManager.cxx
Shane Parris 818ec34bdd file: GLOB_RECURSE VerifyGlobs.cmake should have CMP0009 set to new
In certain cases, rebuilds with CMake using the CONFIGURE_DEPENDS flag
with GLOB_RECURSE could result in a reconfigure loop due to CMP0009 not
being propogated to the generated VerifyGlobs.cmake script.

During the inital configuration phase, RecurseThroughSymlinksOn() is
called for recursive glob operations either by having the CMP0009 status
not set to NEW or by explicitly providing the FOLLOW_SYMLINKS flag. At
the end when the VerifyGlobs script is created, the FOLLOW_SYMLINKS flag
is written according to the final resolved form through a call to
GetRecurseThroughSymlinks(). Thus, setting CMP0009 to NEW in the
generated file is safe and allows correct behavior whether or not the
end user sets the policy status to NEW or OLD.
2020-02-11 08:45:35 -05:00

182 lines
5.4 KiB
C++

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