For modules, use a hash of the compiler version, language options, and
target triple to separate modules built under different
conditions. The hash is used to create a subdirectory in the module
cache path where other invocations of the compiler (with the same
version, language options, etc.) can find the precompiled modules.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139662 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index adc9705..c1f715e 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -217,7 +217,8 @@
/// \brief Retrieve the directory that the given file name resides in.
/// Filename can point to either a real file or a virtual file.
static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
- StringRef Filename) {
+ StringRef Filename,
+ bool CacheFailure) {
if (Filename.empty())
return NULL;
@@ -229,7 +230,7 @@
if (DirName.empty())
DirName = ".";
- return FileMgr.getDirectory(DirName);
+ return FileMgr.getDirectory(DirName, CacheFailure);
}
/// Add all ancestors of the given path (pointing to either a file or
@@ -263,7 +264,8 @@
/// (real or virtual). This returns NULL if the directory doesn't
/// exist.
///
-const DirectoryEntry *FileManager::getDirectory(StringRef DirName) {
+const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
+ bool CacheFailure) {
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
SeenDirEntries.GetOrCreateValue(DirName);
@@ -287,6 +289,8 @@
struct stat StatBuf;
if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
// There's no real directory at the given path.
+ if (!CacheFailure)
+ SeenDirEntries.erase(DirName);
return 0;
}
@@ -309,7 +313,8 @@
/// getFile - Lookup, cache, and verify the specified file (real or
/// virtual). This returns NULL if the file doesn't exist.
///
-const FileEntry *FileManager::getFile(StringRef Filename, bool openFile) {
+const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
+ bool CacheFailure) {
++NumFileLookups;
// See if there is already an entry in the map.
@@ -335,10 +340,15 @@
// subdirectory. This will let us avoid having to waste time on known-to-fail
// searches when we go to find sys/bar.h, because all the search directories
// without a 'sys' subdir will get a cached failure result.
- const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
- if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
+ CacheFailure);
+ if (DirInfo == 0) { // Directory doesn't exist, file can't exist.
+ if (!CacheFailure)
+ SeenFileEntries.erase(Filename);
+
return 0;
-
+ }
+
// FIXME: Use the directory info to prune this, before doing the stat syscall.
// FIXME: This will reduce the # syscalls.
@@ -347,6 +357,9 @@
struct stat StatBuf;
if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
// There's no real file at the given path.
+ if (!CacheFailure)
+ SeenFileEntries.erase(Filename);
+
return 0;
}
@@ -380,10 +393,6 @@
return &UFE;
}
-void FileManager::forgetFile(StringRef Filename) {
- SeenFileEntries.erase(Filename);
-}
-
const FileEntry *
FileManager::getVirtualFile(StringRef Filename, off_t Size,
time_t ModificationTime) {
@@ -408,7 +417,8 @@
// Now that all ancestors of Filename are in the cache, the
// following call is guaranteed to find the DirectoryEntry from the
// cache.
- const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
+ const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
+ /*CacheFailure=*/true);
assert(DirInfo &&
"The directory of a virtual file should already be in the cache.");
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ece9cd8..720f7bb 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -221,6 +221,15 @@
InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
+ // Set up the module path, including the hash for the
+ // module-creation options.
+ llvm::SmallString<256> SpecificModuleCache(
+ getHeaderSearchOpts().ModuleCachePath);
+ if (!getHeaderSearchOpts().DisableModuleHash)
+ llvm::sys::path::append(SpecificModuleCache,
+ getInvocation().getModuleHash());
+ PP->getHeaderSearchInfo().setModuleCachePath(SpecificModuleCache);
+
// Handle generating dependencies, if requested.
const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
if (!DepOpts.OutputFile.empty())
@@ -644,13 +653,8 @@
/// instance.
static void compileModule(CompilerInstance &ImportingInstance,
StringRef ModuleName,
+ StringRef ModuleFileName,
StringRef UmbrellaHeader) {
- // Determine the file that we'll be writing to.
- llvm::SmallString<128> ModuleFile;
- ModuleFile +=
- ImportingInstance.getInvocation().getHeaderSearchOpts().ModuleCachePath;
- llvm::sys::path::append(ModuleFile, ModuleName + ".pcm");
-
// Construct a compiler invocation for creating this module.
llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation
(new CompilerInvocation(ImportingInstance.getInvocation()));
@@ -658,7 +662,7 @@
Invocation->getPreprocessorOpts().resetNonModularOptions();
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
- FrontendOpts.OutputFile = ModuleFile.str();
+ FrontendOpts.OutputFile = ModuleFileName.str();
FrontendOpts.DisableFree = false;
FrontendOpts.Inputs.clear();
FrontendOpts.Inputs.push_back(
@@ -686,10 +690,6 @@
// FIXME: Need to synchronize when multiple processes do this.
Instance.ExecuteAction(CreateModuleAction);
- // Tell the importing instance's file manager to forget about the module
- // file, since we've just created it.
- ImportingInstance.getFileManager().forgetFile(ModuleFile);
-
// Tell the diagnostic client that it's (re-)starting to process a source
// file.
ImportingInstance.getDiagnosticClient()
@@ -710,8 +710,10 @@
// Search for a module with the given name.
std::string UmbrellaHeader;
+ std::string ModuleFileName;
const FileEntry *ModuleFile
= PP->getHeaderSearchInfo().lookupModule(ModuleName.getName(),
+ &ModuleFileName,
&UmbrellaHeader);
bool BuildingModule = false;
@@ -720,7 +722,7 @@
// can be used to create the module file. Create a separate compilation
// module to do so.
BuildingModule = true;
- compileModule(*this, ModuleName.getName(), UmbrellaHeader);
+ compileModule(*this, ModuleName.getName(), ModuleFileName, UmbrellaHeader);
ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName());
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 6c999ca..6c47d7b 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1383,6 +1383,7 @@
Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path);
+ Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
// Add -I..., -F..., and -index-header-map options in order.
bool IsIndexHeaderMap = false;
@@ -1914,3 +1915,84 @@
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
}
+
+namespace {
+
+ class ModuleSignature {
+ llvm::SmallVector<uint64_t, 16> Data;
+ unsigned CurBit;
+ uint64_t CurValue;
+
+ public:
+ ModuleSignature() : CurBit(0), CurValue(0) { }
+
+ void add(uint64_t Value, unsigned Bits);
+ void add(StringRef Value);
+ void flush();
+
+ llvm::APInt getAsInteger() const;
+ };
+}
+
+void ModuleSignature::add(uint64_t Value, unsigned int NumBits) {
+ CurValue |= Value << CurBit;
+ if (CurBit + NumBits < 64) {
+ CurBit += NumBits;
+ return;
+ }
+
+ // Add the current word.
+ Data.push_back(CurValue);
+
+ if (CurBit)
+ CurValue = Value >> (64-CurBit);
+ else
+ CurValue = 0;
+ CurBit = (CurBit+NumBits) & 63;
+}
+
+void ModuleSignature::flush() {
+ if (CurBit == 0)
+ return;
+
+ Data.push_back(CurValue);
+ CurBit = 0;
+ CurValue = 0;
+}
+
+void ModuleSignature::add(StringRef Value) {
+ for (StringRef::iterator I = Value.begin(), IEnd = Value.end(); I != IEnd;++I)
+ add(*I, 8);
+}
+
+llvm::APInt ModuleSignature::getAsInteger() const {
+ return llvm::APInt(Data.size() * 64, Data);
+}
+
+std::string CompilerInvocation::getModuleHash() const {
+ ModuleSignature Signature;
+
+ // Start the signature with the compiler version.
+ Signature.add(getClangFullRepositoryVersion());
+
+ // Extend the signature with the language options
+#define LANGOPT(Name, Bits, Default, Description) \
+ Signature.add(LangOpts.Name, Bits);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Signature.add(static_cast<unsigned>(LangOpts.get##Name()), Bits);
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
+ // Extend the signature with the target triple
+ llvm::Triple T(TargetOpts.Triple);
+ Signature.add((unsigned)T.getArch(), 5);
+ Signature.add((unsigned)T.getVendor(), 4);
+ Signature.add((unsigned)T.getOS(), 5);
+ Signature.add((unsigned)T.getEnvironment(), 4);
+
+ // We've generated the signature. Treat it as one large APInt that we'll
+ // encode as hex and return.
+ Signature.flush();
+ return Signature.getAsInteger().toString(16, /*Signed=*/false);
+}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 05152a7..08af532 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -1161,7 +1161,5 @@
if (HSOpts.UseStandardIncludes)
Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts);
- HS.setModuleCachePath(HSOpts.ModuleCachePath);
-
Init.Realize(Lang);
}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 5cf65cb..bc18d0d 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -99,15 +99,24 @@
}
const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName,
+ std::string *ModuleFileName,
std::string *UmbrellaHeader) {
// If we don't have a module cache path, we can't do anything.
- if (ModuleCachePath.empty())
+ if (ModuleCachePath.empty()) {
+ if (ModuleFileName)
+ ModuleFileName->clear();
return 0;
-
+ }
+
// Try to find the module path.
llvm::SmallString<256> FileName(ModuleCachePath);
llvm::sys::path::append(FileName, ModuleName + ".pcm");
- if (const FileEntry *ModuleFile = getFileMgr().getFile(FileName))
+ if (ModuleFileName)
+ *ModuleFileName = FileName.str();
+
+ if (const FileEntry *ModuleFile
+ = getFileMgr().getFile(FileName, /*OpenFile=*/false,
+ /*CacheFailure=*/false))
return ModuleFile;
// We didn't find the module. If we're not supposed to look for an