dexonsmith created this revision.
dexonsmith added reviewers: sammccall, erik.pilkington, marcrasi.
Herald added a subscriber: ributzka.
dexonsmith requested review of this revision.
Herald added a project: clang.

[This is supporting an RFC I'll post in a bit; marked WIP for now]

Adopt the new llvm::vfs::OutputManager in CompilerInstance.

Depends on https://reviews.llvm.org/D95501.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95502

Files:
  clang/include/clang/Frontend/CompilerInstance.h
  clang/lib/Frontend/CompilerInstance.cpp

Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -459,6 +459,10 @@
     collectVFSEntries(*this, ModuleDepCollector);
   }
 
+  // Modules need an output manager.
+  if (!hasOutputManager())
+    createOutputManager();
+
   for (auto &Listener : DependencyCollectors)
     Listener->attachToPreprocessor(*PP);
 
@@ -647,27 +651,19 @@
 // Output Files
 
 void CompilerInstance::clearOutputFiles(bool EraseFiles) {
-  for (OutputFile &OF : OutputFiles) {
-    if (EraseFiles) {
-      if (!OF.TempFilename.empty()) {
-        llvm::sys::fs::remove(OF.TempFilename);
-        continue;
-      }
-      if (!OF.Filename.empty())
-        llvm::sys::fs::remove(OF.Filename);
-      continue;
-    }
-
-    if (OF.TempFilename.empty())
-      continue;
-
-    std::error_code EC = llvm::sys::fs::rename(OF.TempFilename, OF.Filename);
-    if (!EC)
-      continue;
-    getDiagnostics().Report(diag::err_unable_to_rename_temp)
-        << OF.TempFilename << OF.Filename << EC.message();
-
-    llvm::sys::fs::remove(OF.TempFilename);
+  if (!EraseFiles) {
+    for (auto &O : OutputFiles)
+      llvm::handleAllErrors(
+          O->close(),
+          [&](const llvm::vfs::OnDiskOutputRenameTempError &E) {
+            getDiagnostics().Report(diag::err_unable_to_rename_temp)
+                << E.getTempPath() << E.getOutputPath()
+                << E.getErrorCode().message();
+          },
+          [&](const llvm::vfs::OutputError &E) {
+            getDiagnostics().Report(diag::err_fe_unable_to_open_output)
+                << E.getOutputPath() << E.getErrorCode().message();
+          });
   }
   OutputFiles.clear();
   if (DeleteBuiltModules) {
@@ -704,6 +700,28 @@
   return std::make_unique<llvm::raw_null_ostream>();
 }
 
+void CompilerInstance::setOutputManager(
+    std::shared_ptr<llvm::vfs::OutputManager> NewOutputs) {
+  assert(!TheOutputManager && "Already has an output manager");
+  TheOutputManager = std::move(NewOutputs);
+}
+
+void CompilerInstance::createOutputManager() {
+  assert(!TheOutputManager && "Already has an output manager");
+  TheOutputManager = std::make_unique<llvm::vfs::OutputManager>();
+}
+
+llvm::vfs::OutputManager &CompilerInstance::getOutputManager() {
+  assert(TheOutputManager);
+  return *TheOutputManager;
+}
+
+llvm::vfs::OutputManager &CompilerInstance::getOrCreateOutputManager() {
+  if (!hasOutputManager())
+    createOutputManager();
+  return getOutputManager();
+}
+
 std::unique_ptr<raw_pwrite_stream>
 CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
                                    bool RemoveFileOnSignal, bool UseTemporary,
@@ -735,86 +753,21 @@
     OutputPath = *AbsPath;
   }
 
-  std::unique_ptr<llvm::raw_fd_ostream> OS;
-  Optional<StringRef> OSFile;
+  using namespace llvm::vfs;
+  Expected<std::unique_ptr<Output>> O = getOrCreateOutputManager().createOutput(
+      OutputPath,
+      PartialOutputConfig()
+          .set(ClientIntentOutputConfig::NeedsSeeking, Binary)
+          .set(OnDiskOutputConfig::OpenFlagText, !Binary)
+          .set(OnDiskOutputConfig::RemoveFileOnSignal, RemoveFileOnSignal)
+          .set(OnDiskOutputConfig::UseTemporary, UseTemporary)
+          .set(OnDiskOutputConfig::UseTemporaryCreateMissingDirectories,
+               CreateMissingDirectories));
+  if (!O)
+    return O.takeError();
 
-  if (UseTemporary) {
-    if (OutputPath == "-")
-      UseTemporary = false;
-    else {
-      llvm::sys::fs::file_status Status;
-      llvm::sys::fs::status(OutputPath, Status);
-      if (llvm::sys::fs::exists(Status)) {
-        // Fail early if we can't write to the final destination.
-        if (!llvm::sys::fs::can_write(OutputPath))
-          return llvm::errorCodeToError(
-              make_error_code(llvm::errc::operation_not_permitted));
-
-        // Don't use a temporary if the output is a special file. This handles
-        // things like '-o /dev/null'
-        if (!llvm::sys::fs::is_regular_file(Status))
-          UseTemporary = false;
-      }
-    }
-  }
-
-  std::string TempFile;
-  if (UseTemporary) {
-    // Create a temporary file.
-    // Insert -%%%%%%%% before the extension (if any), and because some tools
-    // (noticeable, clang's own GlobalModuleIndex.cpp) glob for build
-    // artifacts, also append .tmp.
-    StringRef OutputExtension = llvm::sys::path::extension(OutputPath);
-    SmallString<128> TempPath =
-        StringRef(OutputPath).drop_back(OutputExtension.size());
-    TempPath += "-%%%%%%%%";
-    TempPath += OutputExtension;
-    TempPath += ".tmp";
-    int fd;
-    std::error_code EC =
-        llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath);
-
-    if (CreateMissingDirectories &&
-        EC == llvm::errc::no_such_file_or_directory) {
-      StringRef Parent = llvm::sys::path::parent_path(OutputPath);
-      EC = llvm::sys::fs::create_directories(Parent);
-      if (!EC) {
-        EC = llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath);
-      }
-    }
-
-    if (!EC) {
-      OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
-      OSFile = TempFile = std::string(TempPath.str());
-    }
-    // If we failed to create the temporary, fallback to writing to the file
-    // directly. This handles the corner case where we cannot write to the
-    // directory, but can write to the file.
-  }
-
-  if (!OS) {
-    OSFile = OutputPath;
-    std::error_code EC;
-    OS.reset(new llvm::raw_fd_ostream(
-        *OSFile, EC,
-        (Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text)));
-    if (EC)
-      return llvm::errorCodeToError(EC);
-  }
-
-  // Make sure the out stream file gets removed if we crash.
-  if (RemoveFileOnSignal)
-    llvm::sys::RemoveFileOnSignal(*OSFile);
-
-  // Add the output file -- but don't try to remove "-", since this means we are
-  // using stdin.
-  OutputFiles.emplace_back(((OutputPath != "-") ? OutputPath : "").str(),
-                           std::move(TempFile));
-
-  if (!Binary || OS->supportsSeeking())
-    return std::move(OS);
-
-  return std::make_unique<llvm::buffer_unique_ostream>(std::move(OS));
+  OutputFiles.push_back(std::move(*O));
+  return OutputFiles.back()->takeOS();
 }
 
 // Initialization Utilities
@@ -1117,6 +1070,11 @@
   SourceMgr.pushModuleBuildStack(ModuleName,
     FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
 
+  // Share an output manager.
+  assert(ImportingInstance.hasOutputManager() &&
+         "Expected an output manager to already be set up");
+  Instance.setOutputManager(ImportingInstance.getSharedOutputManager());
+
   // If we're collecting module dependencies, we need to share a collector
   // between all of the module CompilerInstances. Other than that, we don't
   // want to produce any dependency output from the module build.
Index: clang/include/clang/Frontend/CompilerInstance.h
===================================================================
--- clang/include/clang/Frontend/CompilerInstance.h
+++ clang/include/clang/Frontend/CompilerInstance.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/BuryPointer.h"
+#include "llvm/Support/OutputManager.h"
 #include <cassert>
 #include <list>
 #include <memory>
@@ -86,6 +87,9 @@
   /// The file manager.
   IntrusiveRefCntPtr<FileManager> FileMgr;
 
+  /// The output context.
+  std::shared_ptr<llvm::vfs::OutputManager> TheOutputManager;
+
   /// The source manager.
   IntrusiveRefCntPtr<SourceManager> SourceMgr;
 
@@ -158,22 +162,8 @@
   /// The stream for verbose output.
   raw_ostream *VerboseOutputStream = &llvm::errs();
 
-  /// Holds information about the output file.
-  ///
-  /// If TempFilename is not empty we must rename it to Filename at the end.
-  /// TempFilename may be empty and Filename non-empty if creating the temporary
-  /// failed.
-  struct OutputFile {
-    std::string Filename;
-    std::string TempFilename;
-
-    OutputFile(std::string filename, std::string tempFilename)
-        : Filename(std::move(filename)), TempFilename(std::move(tempFilename)) {
-    }
-  };
-
   /// The list of active output files.
-  std::list<OutputFile> OutputFiles;
+  std::list<std::unique_ptr<llvm::vfs::Output>> OutputFiles;
 
   /// Force an output buffer.
   std::unique_ptr<llvm::raw_pwrite_stream> OutputStream;
@@ -408,6 +398,20 @@
   /// Replace the current file manager and virtual file system.
   void setFileManager(FileManager *Value);
 
+  /// Set the output manager.
+  void setOutputManager(std::shared_ptr<llvm::vfs::OutputManager> NewOutputs);
+
+  /// Create an output manager.
+  void createOutputManager();
+
+  bool hasOutputManager() const { return bool(TheOutputManager); }
+
+  std::shared_ptr<llvm::vfs::OutputManager> getSharedOutputManager() {
+    return TheOutputManager;
+  }
+  llvm::vfs::OutputManager &getOutputManager();
+  llvm::vfs::OutputManager &getOrCreateOutputManager();
+
   /// }
   /// @name Source Manager
   /// {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D95502: WI... Duncan P. N. Exon Smith via Phabricator via cfe-commits

Reply via email to