Commit 599c93e2 authored by Shane Parris's avatar Shane Parris
Browse files

Add cmGlobVerificationManager class, integrate with cmake and cmState

parent 08b49c27
......@@ -246,6 +246,8 @@ set(SRCS
cmGlobalGeneratorFactory.h
cmGlobalUnixMakefileGenerator3.cxx
cmGlobalUnixMakefileGenerator3.h
cmGlobVerificationManager.cxx
cmGlobVerificationManager.h
cmGraphAdjacencyList.h
cmGraphVizWriter.cxx
cmGraphVizWriter.h
......
/* 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);
}
}
/* 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
*/
......
......@@ -332,6 +332,7 @@ CMAKE_CXX_SOURCES="\
cmGlobalCommonGenerator \
cmGlobalGenerator \
cmGlobalUnixMakefileGenerator3 \
cmGlobVerificationManager \
cmHexFileConverter \
cmIfCommand \
cmIncludeCommand \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment