r223539 - [modules] Instead of storing absolute paths in a .pcm file, store the path to

Richard Smith richard-llvm at metafoo.co.uk
Fri Dec 5 14:42:14 PST 2014


Author: rsmith
Date: Fri Dec  5 16:42:13 2014
New Revision: 223539

URL: http://llvm.org/viewvc/llvm-project?rev=223539&view=rev
Log:
[modules] Instead of storing absolute paths in a .pcm file, store the path to
the root of the module and use paths relative to that directory wherever
possible. This is a step towards allowing explicit modules to be relocated
without being rebuilt, which is important for some kinds of distributed builds,
for good paths in diagnostics, and for appropriate .d output.

This is a recommit of r223443, reverted in r223465; when joining together
imported file paths, we now use the system's separator rather than always
using '/'. This avoids path mismatches between the original module build and
the module user on Windows (at least, in some cases). A more comprehensive
fix will follow.

Modified:
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/include/clang/Serialization/ASTWriter.h
    cfe/trunk/include/clang/Serialization/Module.h
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTReaderInternals.h
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Fri Dec  5 16:42:13 2014
@@ -291,7 +291,10 @@ namespace clang {
       MODULE_MAP_FILE = 14,
 
       /// \brief Record code for the signature that identifiers this AST file.
-      SIGNATURE = 15
+      SIGNATURE = 15,
+
+      /// \brief Record code for the module build directory.
+      MODULE_DIRECTORY = 16,
     };
 
     /// \brief Record types that occur within the input-files block

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Fri Dec  5 16:42:13 2014
@@ -1113,12 +1113,11 @@ private:
   serialization::InputFile getInputFile(ModuleFile &F, unsigned ID,
                                         bool Complain = true);
 
-  /// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
-  /// into account all the necessary relocations.
-  const FileEntry *getFileEntry(StringRef filename);
-
-  void MaybeAddSystemRootToFilename(ModuleFile &M, std::string &Filename);
+public:
+  void ResolveImportedPath(ModuleFile &M, std::string &Filename);
+  static void ResolveImportedPath(std::string &Filename, StringRef Prefix);
 
+private:
   struct ImportedModule {
     ModuleFile *Mod;
     ModuleFile *ImportedBy;
@@ -1141,7 +1140,7 @@ private:
                                  const ModuleFile *ImportedBy,
                                  unsigned ClientLoadCapabilities);
   ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
-  bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
+  bool ParseLineTable(ModuleFile &F, const RecordData &Record);
   bool ReadSourceManagerBlock(ModuleFile &F);
   llvm::BitstreamCursor &SLocCursorForID(int ID);
   SourceLocation getImportLocation(ModuleFile *F);
@@ -2045,6 +2044,9 @@ public:
   // \brief Read a string
   static std::string ReadString(const RecordData &Record, unsigned &Idx);
 
+  // \brief Read a path
+  std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx);
+
   /// \brief Read a version tuple.
   static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
 

Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTWriter.h Fri Dec  5 16:42:13 2014
@@ -111,7 +111,10 @@ private:
 
   /// \brief The module we're currently writing, if any.
   Module *WritingModule;
-                    
+
+  /// \brief The base directory for any relative paths we emit.
+  std::string BaseDirectory;
+
   /// \brief Indicates when the AST writing is actively performing
   /// serialization, rather than just queueing updates.
   bool WritingAST;
@@ -457,13 +460,11 @@ private:
                          StringRef isysroot, const std::string &OutputFile);
   void WriteInputFiles(SourceManager &SourceMgr,
                        HeaderSearchOptions &HSOpts,
-                       StringRef isysroot,
                        bool Modules);
   void WriteSourceManagerBlock(SourceManager &SourceMgr,
-                               const Preprocessor &PP,
-                               StringRef isysroot);
+                               const Preprocessor &PP);
   void WritePreprocessor(const Preprocessor &PP, bool IsModule);
-  void WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot);
+  void WriteHeaderSearch(const HeaderSearch &HS);
   void WritePreprocessorDetail(PreprocessingRecord &PPRec);
   void WriteSubmodules(Module *WritingModule);
                                         
@@ -539,7 +540,8 @@ public:
   /// writing a precompiled header.
   ///
   /// \param isysroot if non-empty, write a relocatable file whose headers
-  /// are relative to the given system root.
+  /// are relative to the given system root. If we're writing a module, its
+  /// build directory will be used in preference to this if both are available.
   void WriteAST(Sema &SemaRef,
                 const std::string &OutputFile,
                 Module *WritingModule, StringRef isysroot,
@@ -686,6 +688,17 @@ public:
   /// \brief Add a string to the given record.
   void AddString(StringRef Str, RecordDataImpl &Record);
 
+  /// \brief Convert a path from this build process into one that is appropriate
+  /// for emission in the module file.
+  bool PreparePathForOutput(SmallVectorImpl<char> &Path);
+
+  /// \brief Add a path to the given record.
+  void AddPath(StringRef Path, RecordDataImpl &Record);
+
+  /// \brief Emit the current record with the given path as a blob.
+  void EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record,
+                          StringRef Path);
+
   /// \brief Add a version tuple to the given record
   void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
 

Modified: cfe/trunk/include/clang/Serialization/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/Module.h?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/Module.h (original)
+++ cfe/trunk/include/clang/Serialization/Module.h Fri Dec  5 16:42:13 2014
@@ -125,6 +125,9 @@ public:
   /// \brief The name of the module.
   std::string ModuleName;
 
+  /// \brief The base directory of the module.
+  std::string BaseDirectory;
+
   std::string getTimestampFilename() const {
     return FileName + ".timestamp";
   }

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Dec  5 16:42:13 2014
@@ -1029,7 +1029,7 @@ void ASTReader::Error(unsigned DiagID,
 /// \brief Read the line table in the source manager block.
 /// \returns true if there was an error.
 bool ASTReader::ParseLineTable(ModuleFile &F,
-                               SmallVectorImpl<uint64_t> &Record) {
+                               const RecordData &Record) {
   unsigned Idx = 0;
   LineTableInfo &LineTable = SourceMgr.getLineTable();
 
@@ -1037,10 +1037,7 @@ bool ASTReader::ParseLineTable(ModuleFil
   std::map<int, int> FileIDs;
   for (int I = 0, N = Record[Idx++]; I != N; ++I) {
     // Extract the file name
-    unsigned FilenameLen = Record[Idx++];
-    std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
-    Idx += FilenameLen;
-    MaybeAddSystemRootToFilename(F, Filename);
+    auto Filename = ReadPath(F, Record, Idx);
     FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
   }
 
@@ -1483,11 +1480,11 @@ ASTReader::getGlobalPreprocessedEntityID
 unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
   return llvm::hash_combine(ikey.Size, ikey.ModTime);
 }
-    
+
 HeaderFileInfoTrait::internal_key_type 
 HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
   internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
-                             FE->getName() };
+                             FE->getName(), /*Imported*/false };
   return ikey;
 }
     
@@ -1495,14 +1492,24 @@ bool HeaderFileInfoTrait::EqualKey(inter
   if (a.Size != b.Size || a.ModTime != b.ModTime)
     return false;
 
-  if (strcmp(a.Filename, b.Filename) == 0)
+  if (llvm::sys::path::is_absolute(a.Filename) &&
+      strcmp(a.Filename, b.Filename) == 0)
     return true;
   
   // Determine whether the actual files are equivalent.
   FileManager &FileMgr = Reader.getFileManager();
-  const FileEntry *FEA = FileMgr.getFile(a.Filename);
-  const FileEntry *FEB = FileMgr.getFile(b.Filename);
-  return (FEA && FEA == FEB);
+  auto GetFile = [&](const internal_key_type &Key) -> const FileEntry* {
+    if (!Key.Imported)
+      return FileMgr.getFile(Key.Filename);
+
+    std::string Resolved = Key.Filename;
+    Reader.ResolveImportedPath(M, Resolved);
+    return FileMgr.getFile(Resolved);
+  };
+
+  const FileEntry *FEA = GetFile(a);
+  const FileEntry *FEB = GetFile(b);
+  return FEA && FEA == FEB;
 }
     
 std::pair<unsigned, unsigned>
@@ -1520,6 +1527,7 @@ HeaderFileInfoTrait::ReadKey(const unsig
   ikey.Size = off_t(endian::readNext<uint64_t, little, unaligned>(d));
   ikey.ModTime = time_t(endian::readNext<uint64_t, little, unaligned>(d));
   ikey.Filename = (const char *)d;
+  ikey.Imported = true;
   return ikey;
 }
 
@@ -1559,11 +1567,13 @@ HeaderFileInfoTrait::ReadData(internal_k
       FileManager &FileMgr = Reader.getFileManager();
       ModuleMap &ModMap =
           Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
-      // FIXME: This is wrong. We should track the filename as written; this
-      // information should be propagated through the SUBMODULE_HEADER etc
-      // records rather than from here.
+      // FIXME: This information should be propagated through the
+      // SUBMODULE_HEADER etc records rather than from here.
       // FIXME: We don't ever mark excluded headers.
-      Module::Header H = { key.Filename, FileMgr.getFile(key.Filename) };
+      std::string Filename = key.Filename;
+      if (key.Imported)
+        Reader.ResolveImportedPath(M, Filename);
+      Module::Header H = { key.Filename, FileMgr.getFile(Filename) };
       ModMap.addHeader(Mod, H, HFI.getHeaderRole());
     }
   }
@@ -2084,14 +2094,14 @@ ASTReader::readInputFileInfo(ModuleFile
   off_t StoredSize;
   time_t StoredTime;
   bool Overridden;
-  
+
   assert(Record[0] == ID && "Bogus stored ID or offset");
   StoredSize = static_cast<off_t>(Record[1]);
   StoredTime = static_cast<time_t>(Record[2]);
   Overridden = static_cast<bool>(Record[3]);
   Filename = Blob;
-  MaybeAddSystemRootToFilename(F, Filename);
-  
+  ResolveImportedPath(F, Filename);
+
   InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
   return R;
 }
@@ -2229,46 +2239,22 @@ InputFile ASTReader::getInputFile(Module
   return IF;
 }
 
-const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
-  ModuleFile &M = ModuleMgr.getPrimaryModule();
-  std::string Filename = filenameStrRef;
-  MaybeAddSystemRootToFilename(M, Filename);
-  const FileEntry *File = FileMgr.getFile(Filename);
-  if (File == nullptr && !M.OriginalDir.empty() && !CurrentDir.empty() &&
-      M.OriginalDir != CurrentDir) {
-    std::string resolved = resolveFileRelativeToOriginalDir(Filename,
-                                                            M.OriginalDir,
-                                                            CurrentDir);
-    if (!resolved.empty())
-      File = FileMgr.getFile(resolved);
-  }
-
-  return File;
+/// \brief If we are loading a relocatable PCH or module file, and the filename
+/// is not an absolute path, add the system or module root to the beginning of
+/// the file name.
+void ASTReader::ResolveImportedPath(ModuleFile &M, std::string &Filename) {
+  // Resolve relative to the base directory, if we have one.
+  if (!M.BaseDirectory.empty())
+    return ResolveImportedPath(Filename, M.BaseDirectory);
 }
 
-/// \brief If we are loading a relocatable PCH file, and the filename is
-/// not an absolute path, add the system root to the beginning of the file
-/// name.
-void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
-                                             std::string &Filename) {
-  // If this is not a relocatable PCH file, there's nothing to do.
-  if (!M.RelocatablePCH)
-    return;
-
+void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) {
   if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
     return;
 
-  if (isysroot.empty()) {
-    // If no system root was given, default to '/'
-    Filename.insert(Filename.begin(), '/');
-    return;
-  }
-
-  unsigned Length = isysroot.size();
-  if (isysroot[Length - 1] != '/')
-    Filename.insert(Filename.begin(), '/');
-
-  Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end());
+  SmallString<128> Buffer;
+  llvm::sys::path::append(Buffer, Prefix, Filename);
+  Filename.assign(Buffer.begin(), Buffer.end());
 }
 
 ASTReader::ASTReadResult
@@ -2388,6 +2374,9 @@ ASTReader::ReadControlBlock(ModuleFile &
       }
 
       F.RelocatablePCH = Record[4];
+      // Relative paths in a relocatable PCH are relative to our sysroot.
+      if (F.RelocatablePCH)
+        F.BaseDirectory = isysroot.empty() ? "/" : isysroot;
 
       const std::string &CurBranch = getClangFullRepositoryVersion();
       StringRef ASTBranch = Blob;
@@ -2418,10 +2407,7 @@ ASTReader::ReadControlBlock(ModuleFile &
         off_t StoredSize = (off_t)Record[Idx++];
         time_t StoredModTime = (time_t)Record[Idx++];
         ASTFileSignature StoredSignature = Record[Idx++];
-        unsigned Length = Record[Idx++];
-        SmallString<128> ImportedFile(Record.begin() + Idx,
-                                      Record.begin() + Idx + Length);
-        Idx += Length;
+        auto ImportedFile = ReadPath(F, Record, Idx);
 
         // Load the AST file.
         switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
@@ -2505,7 +2491,7 @@ ASTReader::ReadControlBlock(ModuleFile &
       F.OriginalSourceFileID = FileID::get(Record[0]);
       F.ActualOriginalSourceFileName = Blob;
       F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
-      MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
+      ResolveImportedPath(F, F.OriginalSourceFileName);
       break;
 
     case ORIGINAL_FILE_ID:
@@ -2522,6 +2508,10 @@ ASTReader::ReadControlBlock(ModuleFile &
         Listener->ReadModuleName(F.ModuleName);
       break;
 
+    case MODULE_DIRECTORY:
+      F.BaseDirectory = Blob;
+      break;
+
     case MODULE_MAP_FILE:
       if (ASTReadResult Result =
               ReadModuleMapFileBlock(Record, F, ImportedBy, ClientLoadCapabilities))
@@ -3342,7 +3332,7 @@ ASTReader::ReadModuleMapFileBlock(Record
                                   const ModuleFile *ImportedBy,
                                   unsigned ClientLoadCapabilities) {
   unsigned Idx = 0;
-  F.ModuleMapPath = ReadString(Record, Idx);
+  F.ModuleMapPath = ReadPath(F, Record, Idx);
 
   if (F.Kind == MK_ExplicitModule) {
     // For an explicitly-loaded module, we don't care whether the original
@@ -3389,7 +3379,7 @@ ASTReader::ReadModuleMapFileBlock(Record
     llvm::SmallPtrSet<const FileEntry *, 1> AdditionalStoredMaps;
     for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) {
       // FIXME: we should use input files rather than storing names.
-      std::string Filename = ReadString(Record, Idx);
+      std::string Filename = ReadPath(F, Record, Idx);
       const FileEntry *F =
           FileMgr.getFile(Filename, false, false);
       if (F == nullptr) {
@@ -4256,6 +4246,7 @@ bool ASTReader::readASTFileControlBlock(
   
   // Scan for ORIGINAL_FILE inside the control block.
   RecordData Record;
+  std::string ModuleDir;
   while (1) {
     llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
     if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
@@ -4280,9 +4271,14 @@ bool ASTReader::readASTFileControlBlock(
     case MODULE_NAME:
       Listener.ReadModuleName(Blob);
       break;
+    case MODULE_DIRECTORY:
+      ModuleDir = Blob;
+      break;
     case MODULE_MAP_FILE: {
       unsigned Idx = 0;
-      Listener.ReadModuleMapFile(ReadString(Record, Idx));
+      auto Path = ReadString(Record, Idx);
+      ResolveImportedPath(Path, ModuleDir);
+      Listener.ReadModuleMapFile(Path);
       break;
     }
     case LANGUAGE_OPTIONS:
@@ -4344,7 +4340,10 @@ bool ASTReader::readASTFileControlBlock(
         switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
         case INPUT_FILE:
           bool Overridden = static_cast<bool>(Record[3]);
-          shouldContinue = Listener.visitInputFile(Blob, isSystemFile, Overridden);
+          std::string Filename = Blob;
+          ResolveImportedPath(Filename, ModuleDir);
+          shouldContinue =
+              Listener.visitInputFile(Filename, isSystemFile, Overridden);
           break;
         }
         if (!shouldContinue)
@@ -4361,11 +4360,9 @@ bool ASTReader::readASTFileControlBlock(
       while (Idx < N) {
         // Read information about the AST file.
         Idx += 5; // ImportLoc, Size, ModTime, Signature
-        unsigned Length = Record[Idx++];
-        SmallString<128> ImportedFile(Record.begin() + Idx,
-                                      Record.begin() + Idx + Length);
-        Idx += Length;
-        Listener.visitImport(ImportedFile);
+        std::string Filename = ReadString(Record, Idx);
+        ResolveImportedPath(Filename, ModuleDir);
+        Listener.visitImport(Filename);
       }
       break;
     }
@@ -8050,6 +8047,13 @@ std::string ASTReader::ReadString(const
   return Result;
 }
 
+std::string ASTReader::ReadPath(ModuleFile &F, const RecordData &Record,
+                                unsigned &Idx) {
+  std::string Filename = ReadString(Record, Idx);
+  ResolveImportedPath(F, Filename);
+  return Filename;
+}
+
 VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, 
                                          unsigned &Idx) {
   unsigned Major = Record[Idx++];

Modified: cfe/trunk/lib/Serialization/ASTReaderInternals.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderInternals.h?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderInternals.h (original)
+++ cfe/trunk/lib/Serialization/ASTReaderInternals.h Fri Dec  5 16:42:13 2014
@@ -194,8 +194,8 @@ typedef llvm::OnDiskChainedHashTable<AST
 ///
 /// The on-disk hash table contains a mapping from each header path to 
 /// information about that header (how many times it has been included, its
-/// controlling macro, etc.). Note that we actually hash based on the 
-/// filename, and support "deep" comparisons of file names based on current
+/// controlling macro, etc.). Note that we actually hash based on the size
+/// and mtime, and support "deep" comparisons of file names based on current
 /// inode numbers, so that the search can cope with non-normalized path names
 /// and symlinks.
 class HeaderFileInfoTrait {
@@ -211,6 +211,7 @@ public:
     off_t Size;
     time_t ModTime;
     const char *Filename;
+    bool Imported;
   };
   typedef const internal_key_type &internal_key_ref;
   

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=223539&r1=223538&r2=223539&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Dec  5 16:42:13 2014
@@ -1063,33 +1063,44 @@ void ASTWriter::WriteBlockInfoBlock() {
 ///
 /// \param Filename the file name to adjust.
 ///
-/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
-/// the returned filename will be adjusted by this system root.
+/// \param BaseDir When non-NULL, the PCH file is a relocatable AST file and
+/// the returned filename will be adjusted by this root directory.
 ///
 /// \returns either the original filename (if it needs no adjustment) or the
 /// adjusted filename (which points into the @p Filename parameter).
 static const char *
-adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
+adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) {
   assert(Filename && "No file name to adjust?");
 
-  if (isysroot.empty())
+  if (BaseDir.empty())
     return Filename;
 
   // Verify that the filename and the system root have the same prefix.
   unsigned Pos = 0;
-  for (; Filename[Pos] && Pos < isysroot.size(); ++Pos)
-    if (Filename[Pos] != isysroot[Pos])
+  for (; Filename[Pos] && Pos < BaseDir.size(); ++Pos)
+    if (Filename[Pos] != BaseDir[Pos])
       return Filename; // Prefixes don't match.
 
   // We hit the end of the filename before we hit the end of the system root.
   if (!Filename[Pos])
     return Filename;
 
-  // If the file name has a '/' at the current position, skip over the '/'.
-  // We distinguish sysroot-based includes from absolute includes by the
-  // absence of '/' at the beginning of sysroot-based includes.
-  if (Filename[Pos] == '/')
+  // If there's not a path separator at the end of the base directory nor
+  // immediately after it, then this isn't within the base directory.
+  if (!llvm::sys::path::is_separator(Filename[Pos])) {
+    if (!llvm::sys::path::is_separator(BaseDir.back()))
+      return Filename;
+  } else {
+    // If the file name has a '/' at the current position, skip over the '/'.
+    // We distinguish relative paths from absolute paths by the
+    // absence of '/' at the beginning of relative paths.
+    //
+    // FIXME: This is wrong. We distinguish them by asking if the path is
+    // absolute, which isn't the same thing. And there might be multiple '/'s
+    // in a row. Use a better mechanism to indicate whether we have emitted an
+    // absolute or relative path.
     ++Pos;
+  }
 
   return Filename + Pos;
 }
@@ -1126,6 +1137,8 @@ void ASTWriter::WriteControlBlock(Prepro
   Record.push_back(VERSION_MINOR);
   Record.push_back(CLANG_VERSION_MAJOR);
   Record.push_back(CLANG_VERSION_MINOR);
+  assert((!WritingModule || isysroot.empty()) &&
+         "writing module as a relocatable PCH?");
   Record.push_back(!isysroot.empty());
   Record.push_back(ASTHasCompilerErrors);
   Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
@@ -1136,8 +1149,8 @@ void ASTWriter::WriteControlBlock(Prepro
   Record.push_back(getSignature());
   Stream.EmitRecord(SIGNATURE, Record);
 
-  // Module name
   if (WritingModule) {
+    // Module name
     BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
     Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
@@ -1147,25 +1160,42 @@ void ASTWriter::WriteControlBlock(Prepro
     Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);
   }
 
+  if (WritingModule && WritingModule->Directory) {
+    // Module directory.
+    BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+    Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory
+    unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+    RecordData Record;
+    Record.push_back(MODULE_DIRECTORY);
+
+    SmallString<128> BaseDir(WritingModule->Directory->getName());
+    Context.getSourceManager().getFileManager().FixupRelativePath(BaseDir);
+    llvm::sys::fs::make_absolute(BaseDir);
+    Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir);
+
+    // Write out all other paths relative to the base directory if possible.
+    BaseDirectory.assign(BaseDir.begin(), BaseDir.end());
+  } else if (!isysroot.empty()) {
+    // Write out paths relative to the sysroot if possible.
+    BaseDirectory = isysroot;
+  }
+
   // Module map file
   if (WritingModule) {
     Record.clear();
-    auto addModMap = [&](const FileEntry *F) {
-      SmallString<128> ModuleMap(F->getName());
-      llvm::sys::fs::make_absolute(ModuleMap);
-      AddString(ModuleMap.str(), Record);
-    };
 
     auto &Map = PP.getHeaderSearchInfo().getModuleMap();
 
     // Primary module map file.
-    addModMap(Map.getModuleMapFileForUniquing(WritingModule));
+    AddPath(Map.getModuleMapFileForUniquing(WritingModule)->getName(), Record);
 
     // Additional module map files.
-    if (auto *AdditionalModMaps = Map.getAdditionalModuleMapFiles(WritingModule)) {
+    if (auto *AdditionalModMaps =
+            Map.getAdditionalModuleMapFiles(WritingModule)) {
       Record.push_back(AdditionalModMaps->size());
       for (const FileEntry *F : *AdditionalModMaps)
-        addModMap(F);
+        AddPath(F->getName(), Record);
     } else {
       Record.push_back(0);
     }
@@ -1189,9 +1219,7 @@ void ASTWriter::WriteControlBlock(Prepro
       Record.push_back((*M)->File->getSize());
       Record.push_back((*M)->File->getModificationTime());
       Record.push_back((*M)->Signature);
-      const std::string &FileName = (*M)->FileName;
-      Record.push_back(FileName.size());
-      Record.append(FileName.begin(), FileName.end());
+      AddPath((*M)->FileName, Record);
     }
     Stream.EmitRecord(IMPORTS, Record);
   }
@@ -1339,17 +1367,10 @@ void ASTWriter::WriteControlBlock(Prepro
     FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
     unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
 
-    SmallString<128> MainFilePath(MainFile->getName());
-
-    llvm::sys::fs::make_absolute(MainFilePath);
-
-    const char *MainFileNameStr = MainFilePath.c_str();
-    MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
-                                                      isysroot);
     Record.clear();
     Record.push_back(ORIGINAL_FILE);
     Record.push_back(SM.getMainFileID().getOpaqueValue());
-    Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
+    EmitRecordWithPath(FileAbbrevCode, Record, MainFile->getName());
   }
 
   Record.clear();
@@ -1375,7 +1396,6 @@ void ASTWriter::WriteControlBlock(Prepro
 
   WriteInputFiles(Context.SourceMgr,
                   PP.getHeaderSearchInfo().getHeaderSearchOpts(),
-                  isysroot,
                   PP.getLangOpts().Modules);
   Stream.ExitBlock();
 }
@@ -1391,7 +1411,6 @@ namespace  {
 
 void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
                                 HeaderSearchOptions &HSOpts,
-                                StringRef isysroot,
                                 bool Modules) {
   using namespace llvm;
   Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
@@ -1462,23 +1481,8 @@ void ASTWriter::WriteInputFiles(SourceMa
     // Whether this file was overridden.
     Record.push_back(Entry.BufferOverridden);
 
-    // Turn the file name into an absolute path, if it isn't already.
-    const char *Filename = Entry.File->getName();
-    SmallString<128> FilePath(Filename);
-    
-    // Ask the file manager to fixup the relative path for us. This will 
-    // honor the working directory.
-    SourceMgr.getFileManager().FixupRelativePath(FilePath);
-    
-    // FIXME: This call to make_absolute shouldn't be necessary, the
-    // call to FixupRelativePath should always return an absolute path.
-    llvm::sys::fs::make_absolute(FilePath);
-    Filename = FilePath.c_str();
-    
-    Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
-
-    Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
-  }  
+    EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+  }
 
   Stream.ExitBlock();
 
@@ -1588,6 +1592,9 @@ namespace {
       // The hash is based only on size/time of the file, so that the reader can
       // match even when symlinking or excess path elements ("foo/../", "../")
       // change the form of the name. However, complete path is still the key.
+      //
+      // FIXME: Using the mtime here will cause problems for explicit module
+      // imports.
       return llvm::hash_combine(key.FE->getSize(),
                                 key.FE->getModificationTime());
     }
@@ -1668,7 +1675,7 @@ namespace {
 /// \brief Write the header search block for the list of files that 
 ///
 /// \param HS The header search structure to save.
-void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
+void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
   SmallVector<const FileEntry *, 16> FilesByUID;
   HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
   
@@ -1692,17 +1699,16 @@ void ASTWriter::WriteHeaderSearch(const
         (HFI.isModuleHeader && !HFI.isCompilingModuleHeader))
       continue;
 
-    // Turn the file name into an absolute path, if it isn't already.
+    // Massage the file path into an appropriate form.
     const char *Filename = File->getName();
-    Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
-      
-    // If we performed any translation on the file name at all, we need to
-    // save this string, since the generator will refer to it later.
-    if (Filename != File->getName()) {
-      Filename = strdup(Filename);
+    SmallString<128> FilenameTmp(Filename);
+    if (PreparePathForOutput(FilenameTmp)) {
+      // If we performed any translation on the file name at all, we need to
+      // save this string, since the generator will refer to it later.
+      Filename = strdup(FilenameTmp.c_str());
       SavedStrings.push_back(Filename);
     }
-    
+
     HeaderFileInfoTrait::key_type key = { File, Filename };
     Generator.insert(key, HFI, GeneratorTrait);
     ++NumHeaderSearchEntries;
@@ -1752,8 +1758,7 @@ void ASTWriter::WriteHeaderSearch(const
 /// errors), we probably won't have to create file entries for any of
 /// the files in the AST.
 void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
-                                        const Preprocessor &PP,
-                                        StringRef isysroot) {
+                                        const Preprocessor &PP) {
   RecordData Record;
 
   // Enter the source manager block.
@@ -1902,17 +1907,10 @@ void ASTWriter::WriteSourceManagerBlock(
     LineTableInfo &LineTable = SourceMgr.getLineTable();
 
     Record.clear();
-    // Emit the file names
+    // Emit the file names.
     Record.push_back(LineTable.getNumFilenames());
-    for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
-      // Emit the file name
-      const char *Filename = LineTable.getFilename(I);
-      Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
-      unsigned FilenameLen = Filename? strlen(Filename) : 0;
-      Record.push_back(FilenameLen);
-      if (FilenameLen)
-        Record.insert(Record.end(), Filename, Filename + FilenameLen);
-    }
+    for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I)
+      AddPath(LineTable.getFilename(I), Record);
 
     // Emit the line entries
     for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
@@ -2543,7 +2541,7 @@ void ASTWriter::WriteSubmodules(Module *
       Record.clear();
       for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
         unsigned ImportedID = getSubmoduleID(Mod->Imports[I]);
-        assert(ImportedID && "Unknown submodule!");                                           
+        assert(ImportedID && "Unknown submodule!");
         Record.push_back(ImportedID);
       }
       Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
@@ -4077,6 +4075,47 @@ void ASTWriter::AddString(StringRef Str,
   Record.insert(Record.end(), Str.begin(), Str.end());
 }
 
+bool ASTWriter::PreparePathForOutput(SmallVectorImpl<char> &Path) {
+  bool Changed = false;
+
+  if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
+    // Ask the file manager to fixup the relative path for us. This will
+    // honor the working directory.
+    if (Context)
+      Context->getSourceManager().getFileManager().FixupRelativePath(Path);
+
+    // We want an absolute path even if we weren't given a spelling for the
+    // current working directory.
+    llvm::sys::fs::make_absolute(Path);
+
+    Changed = true;
+  }
+
+  // Remove a prefix to make the path relative, if relevant.
+  const char *PathBegin = Path.data();
+  const char *PathPtr =
+      adjustFilenameForRelocatableAST(PathBegin, BaseDirectory);
+  if (PathPtr != PathBegin) {
+    Path.erase(Path.begin(), Path.begin() + (PathPtr - PathBegin));
+    Changed = true;
+  }
+
+  return Changed;
+}
+
+void ASTWriter::AddPath(StringRef Path, RecordDataImpl &Record) {
+  SmallString<128> FilePath(Path);
+  PreparePathForOutput(FilePath);
+  AddString(FilePath, Record);
+}
+
+void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record,
+                                   StringRef Path) {
+  SmallString<128> FilePath(Path);
+  PreparePathForOutput(FilePath);
+  Stream.EmitRecordWithBlob(Abbrev, Record, FilePath);
+}
+
 void ASTWriter::AddVersionTuple(const VersionTuple &Version,
                                 RecordDataImpl &Record) {
   Record.push_back(Version.getMajor());
@@ -4161,6 +4200,7 @@ void ASTWriter::WriteAST(Sema &SemaRef,
   Context = nullptr;
   PP = nullptr;
   this->WritingModule = nullptr;
+  this->BaseDirectory.clear();
 
   WritingAST = false;
 }
@@ -4551,11 +4591,11 @@ void ASTWriter::WriteASTCore(Sema &SemaR
     Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
   WriteCXXBaseSpecifiersOffsets();
   WriteFileDeclIDsMap();
-  WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
+  WriteSourceManagerBlock(Context.getSourceManager(), PP);
 
   WriteComments();
   WritePreprocessor(PP, isModule);
-  WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
+  WriteHeaderSearch(PP.getHeaderSearchInfo());
   WriteSelectors(SemaRef);
   WriteReferencedSelectorsPool(SemaRef);
   WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);





More information about the cfe-commits mailing list