summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmGlobVerificationManager.cxx172
-rw-r--r--Source/cmGlobVerificationManager.h89
-rw-r--r--Source/cmState.cxx36
-rw-r--r--Source/cmState.h14
-rw-r--r--Source/cmake.cxx28
-rw-r--r--Source/cmake.h10
7 files changed, 351 insertions, 0 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index e547356..e23b070 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -246,6 +246,8 @@ set(SRCS
cmGlobalGeneratorFactory.h
cmGlobalUnixMakefileGenerator3.cxx
cmGlobalUnixMakefileGenerator3.h
+ cmGlobVerificationManager.cxx
+ cmGlobVerificationManager.h
cmGraphAdjacencyList.h
cmGraphVizWriter.cxx
cmGraphVizWriter.h
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
new file mode 100644
index 0000000..e23b6ea
--- /dev/null
+++ b/Source/cmGlobVerificationManager.cxx
@@ -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);
+ }
+}
diff --git a/Source/cmGlobVerificationManager.h b/Source/cmGlobVerificationManager.h
new file mode 100644
index 0000000..4508602
--- /dev/null
+++ b/Source/cmGlobVerificationManager.h
@@ -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
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index bb891b5..a93fb11 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -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);
diff --git a/Source/cmState.h b/Source/cmState.h
index 6cbf82d..4c6fc69 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -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;
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 323bcf6..41a3a22 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -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('.');
diff --git a/Source/cmake.h b/Source/cmake.h
index 1ac549b..5e4930d 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -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
*/