mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-16 14:08:35 +08:00
Add cmGlobVerificationManager class, integrate with cmake and cmState
This commit is contained in:
@@ -246,6 +246,8 @@ set(SRCS
|
||||
cmGlobalGeneratorFactory.h
|
||||
cmGlobalUnixMakefileGenerator3.cxx
|
||||
cmGlobalUnixMakefileGenerator3.h
|
||||
cmGlobVerificationManager.cxx
|
||||
cmGlobVerificationManager.h
|
||||
cmGraphAdjacencyList.h
|
||||
cmGraphVizWriter.cxx
|
||||
cmGraphVizWriter.h
|
||||
|
172
Source/cmGlobVerificationManager.cxx
Normal file
172
Source/cmGlobVerificationManager.cxx
Normal file
@@ -0,0 +1,172 @@
|
||||
/* 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 "cmsys/FStream.hxx"
|
||||
#include <sstream>
|
||||
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmVersion.h"
|
||||
#include "cmake.h"
|
||||
|
||||
bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path)
|
||||
{
|
||||
if (this->Cache.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string scriptFile = path;
|
||||
scriptFile += cmake::GetCMakeFilesDirectory();
|
||||
std::string stampFile = scriptFile;
|
||||
cmSystemTools::MakeDirectory(scriptFile);
|
||||
scriptFile += "/VerifyGlobs.cmake";
|
||||
stampFile += "/cmake.verify_globs";
|
||||
cmGeneratedFileStream verifyScriptFile(scriptFile.c_str());
|
||||
verifyScriptFile.SetCopyIfDifferent(true);
|
||||
if (!verifyScriptFile) {
|
||||
cmSystemTools::Error("Unable to open verification script file for save. ",
|
||||
scriptFile.c_str());
|
||||
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.c_str());
|
||||
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().c_str());
|
||||
} else {
|
||||
value.Backtraces.emplace_back(variable, backtrace);
|
||||
}
|
||||
}
|
89
Source/cmGlobVerificationManager.h
Normal file
89
Source/cmGlobVerificationManager.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#ifndef cmGlobVerificationManager_h
|
||||
#define cmGlobVerificationManager_h
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmListFileCache.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/** \class cmGlobVerificationManager
|
||||
* \brief Class for expressing build-time dependencies on glob expressions.
|
||||
*
|
||||
* Generates a CMake script which verifies glob outputs during prebuild.
|
||||
*
|
||||
*/
|
||||
class cmGlobVerificationManager
|
||||
{
|
||||
public:
|
||||
cmGlobVerificationManager() {}
|
||||
|
||||
protected:
|
||||
///! Save verification script for given makefile.
|
||||
///! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
|
||||
bool SaveVerificationScript(const std::string& path);
|
||||
|
||||
///! Add an entry into the glob cache
|
||||
void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
|
||||
const std::string& relative,
|
||||
const std::string& expression,
|
||||
const std::vector<std::string>& files,
|
||||
const std::string& variable,
|
||||
const cmListFileBacktrace& bt);
|
||||
|
||||
///! Check targets should be written in generated build system.
|
||||
bool DoWriteVerifyTarget() const;
|
||||
|
||||
///! Get the paths to the generated script and stamp files
|
||||
std::string const& GetVerifyScript() const { return this->VerifyScript; }
|
||||
std::string const& GetVerifyStamp() const { return this->VerifyStamp; }
|
||||
|
||||
private:
|
||||
struct CacheEntryKey
|
||||
{
|
||||
const bool Recurse;
|
||||
const bool ListDirectories;
|
||||
const bool FollowSymlinks;
|
||||
const std::string Relative;
|
||||
const std::string Expression;
|
||||
CacheEntryKey(const bool rec, const bool l, const bool s,
|
||||
const std::string& rel, const std::string& e)
|
||||
: Recurse(rec)
|
||||
, ListDirectories(l)
|
||||
, FollowSymlinks(s)
|
||||
, Relative(rel)
|
||||
, Expression(e)
|
||||
{
|
||||
}
|
||||
bool operator<(const CacheEntryKey& r) const;
|
||||
void PrintGlobCommand(std::ostream& out, const std::string& cmdVar);
|
||||
};
|
||||
|
||||
struct CacheEntryValue
|
||||
{
|
||||
bool Initialized;
|
||||
std::vector<std::string> Files;
|
||||
std::vector<std::pair<std::string, cmListFileBacktrace>> Backtraces;
|
||||
CacheEntryValue()
|
||||
: Initialized(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<CacheEntryKey, CacheEntryValue> CacheEntryMap;
|
||||
CacheEntryMap Cache;
|
||||
std::string VerifyScript;
|
||||
std::string VerifyStamp;
|
||||
|
||||
// Only cmState should be able to add cache values.
|
||||
// cmGlobVerificationManager should never be used directly.
|
||||
friend class cmState; // allow access to add cache values
|
||||
};
|
||||
|
||||
#endif
|
@@ -13,6 +13,7 @@
|
||||
#include "cmCommand.h"
|
||||
#include "cmDefinitions.h"
|
||||
#include "cmDisallowedCommand.h"
|
||||
#include "cmGlobVerificationManager.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmStatePrivate.h"
|
||||
#include "cmStateSnapshot.h"
|
||||
@@ -31,11 +32,13 @@ cmState::cmState()
|
||||
, MSYSShell(false)
|
||||
{
|
||||
this->CacheManager = new cmCacheManager;
|
||||
this->GlobVerificationManager = new cmGlobVerificationManager;
|
||||
}
|
||||
|
||||
cmState::~cmState()
|
||||
{
|
||||
delete this->CacheManager;
|
||||
delete this->GlobVerificationManager;
|
||||
cmDeleteAll(this->BuiltinCommands);
|
||||
cmDeleteAll(this->ScriptedCommands);
|
||||
}
|
||||
@@ -207,6 +210,39 @@ void cmState::AddCacheEntry(const std::string& key, const char* value,
|
||||
this->CacheManager->AddCacheEntry(key, value, helpString, type);
|
||||
}
|
||||
|
||||
bool cmState::DoWriteGlobVerifyTarget() const
|
||||
{
|
||||
return this->GlobVerificationManager->DoWriteVerifyTarget();
|
||||
}
|
||||
|
||||
std::string const& cmState::GetGlobVerifyScript() const
|
||||
{
|
||||
return this->GlobVerificationManager->GetVerifyScript();
|
||||
}
|
||||
|
||||
std::string const& cmState::GetGlobVerifyStamp() const
|
||||
{
|
||||
return this->GlobVerificationManager->GetVerifyStamp();
|
||||
}
|
||||
|
||||
bool cmState::SaveVerificationScript(const std::string& path)
|
||||
{
|
||||
return this->GlobVerificationManager->SaveVerificationScript(path);
|
||||
}
|
||||
|
||||
void cmState::AddGlobCacheEntry(bool recurse, bool listDirectories,
|
||||
bool followSymlinks,
|
||||
const std::string& relative,
|
||||
const std::string& expression,
|
||||
const std::vector<std::string>& files,
|
||||
const std::string& variable,
|
||||
cmListFileBacktrace const& backtrace)
|
||||
{
|
||||
this->GlobVerificationManager->AddCacheEntry(
|
||||
recurse, listDirectories, followSymlinks, relative, expression, files,
|
||||
variable, backtrace);
|
||||
}
|
||||
|
||||
void cmState::RemoveCacheEntry(std::string const& key)
|
||||
{
|
||||
this->CacheManager->RemoveCacheEntry(key);
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "cmDefinitions.h"
|
||||
#include "cmLinkedTree.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmProperty.h"
|
||||
#include "cmPropertyDefinitionMap.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
|
||||
class cmCacheManager;
|
||||
class cmCommand;
|
||||
class cmGlobVerificationManager;
|
||||
class cmPropertyDefinition;
|
||||
class cmStateSnapshot;
|
||||
class cmMessenger;
|
||||
@@ -165,12 +167,24 @@ private:
|
||||
const char* helpString,
|
||||
cmStateEnums::CacheEntryType type);
|
||||
|
||||
bool DoWriteGlobVerifyTarget() const;
|
||||
std::string const& GetGlobVerifyScript() const;
|
||||
std::string const& GetGlobVerifyStamp() const;
|
||||
bool SaveVerificationScript(const std::string& path);
|
||||
void AddGlobCacheEntry(bool recurse, bool listDirectories,
|
||||
bool followSymlinks, const std::string& relative,
|
||||
const std::string& expression,
|
||||
const std::vector<std::string>& files,
|
||||
const std::string& variable,
|
||||
cmListFileBacktrace const& bt);
|
||||
|
||||
std::map<cmProperty::ScopeType, cmPropertyDefinitionMap> PropertyDefinitions;
|
||||
std::vector<std::string> EnabledLanguages;
|
||||
std::map<std::string, cmCommand*> BuiltinCommands;
|
||||
std::map<std::string, cmCommand*> ScriptedCommands;
|
||||
cmPropertyMap GlobalProperties;
|
||||
cmCacheManager* CacheManager;
|
||||
cmGlobVerificationManager* GlobVerificationManager;
|
||||
|
||||
cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>
|
||||
BuildsystemDirectory;
|
||||
|
@@ -1434,6 +1434,7 @@ int cmake::ActualConfigure()
|
||||
|
||||
// only save the cache if there were no fatal errors
|
||||
if (this->GetWorkingMode() == NORMAL_MODE) {
|
||||
this->State->SaveVerificationScript(this->GetHomeOutputDirectory());
|
||||
this->SaveCache(this->GetHomeOutputDirectory());
|
||||
}
|
||||
if (cmSystemTools::GetErrorOccuredFlag()) {
|
||||
@@ -1649,6 +1650,33 @@ void cmake::AddCacheEntry(const std::string& key, const char* value,
|
||||
this->UnwatchUnusedCli(key);
|
||||
}
|
||||
|
||||
bool cmake::DoWriteGlobVerifyTarget() const
|
||||
{
|
||||
return this->State->DoWriteGlobVerifyTarget();
|
||||
}
|
||||
|
||||
std::string const& cmake::GetGlobVerifyScript() const
|
||||
{
|
||||
return this->State->GetGlobVerifyScript();
|
||||
}
|
||||
|
||||
std::string const& cmake::GetGlobVerifyStamp() const
|
||||
{
|
||||
return this->State->GetGlobVerifyStamp();
|
||||
}
|
||||
|
||||
void cmake::AddGlobCacheEntry(bool recurse, bool listDirectories,
|
||||
bool followSymlinks, const std::string& relative,
|
||||
const std::string& expression,
|
||||
const std::vector<std::string>& files,
|
||||
const std::string& variable,
|
||||
cmListFileBacktrace const& backtrace)
|
||||
{
|
||||
this->State->AddGlobCacheEntry(recurse, listDirectories, followSymlinks,
|
||||
relative, expression, files, variable,
|
||||
backtrace);
|
||||
}
|
||||
|
||||
std::string cmake::StripExtension(const std::string& file) const
|
||||
{
|
||||
auto dotpos = file.rfind('.');
|
||||
|
@@ -255,6 +255,16 @@ public:
|
||||
void AddCacheEntry(const std::string& key, const char* value,
|
||||
const char* helpString, int type);
|
||||
|
||||
bool DoWriteGlobVerifyTarget() const;
|
||||
std::string const& GetGlobVerifyScript() const;
|
||||
std::string const& GetGlobVerifyStamp() const;
|
||||
void AddGlobCacheEntry(bool recurse, bool listDirectories,
|
||||
bool followSymlinks, const std::string& relative,
|
||||
const std::string& expression,
|
||||
const std::vector<std::string>& files,
|
||||
const std::string& variable,
|
||||
cmListFileBacktrace const& bt);
|
||||
|
||||
/**
|
||||
* Get the system information and write it to the file specified
|
||||
*/
|
||||
|
Reference in New Issue
Block a user