Skip to content

Commit edc39ba

Browse files
Frontend: Adopt llvm::vfs::OutputBackend in CompilerInstance
Adopt new virtual output backend in CompilerInstance.
1 parent 3e5a6f0 commit edc39ba

File tree

2 files changed

+77
-133
lines changed

2 files changed

+77
-133
lines changed

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/StringRef.h"
2525
#include "llvm/Support/BuryPointer.h"
2626
#include "llvm/Support/FileSystem.h"
27+
#include "llvm/Support/VirtualOutputBackend.h"
2728
#include <cassert>
2829
#include <list>
2930
#include <memory>
@@ -92,6 +93,9 @@ class CompilerInstance : public ModuleLoader {
9293
/// The file manager.
9394
IntrusiveRefCntPtr<FileManager> FileMgr;
9495

96+
/// The output context.
97+
IntrusiveRefCntPtr<llvm::vfs::OutputBackend> TheOutputBackend;
98+
9599
/// The source manager.
96100
IntrusiveRefCntPtr<SourceManager> SourceMgr;
97101

@@ -164,22 +168,8 @@ class CompilerInstance : public ModuleLoader {
164168
/// The stream for verbose output.
165169
raw_ostream *VerboseOutputStream = &llvm::errs();
166170

167-
/// Holds information about the output file.
168-
///
169-
/// If TempFilename is not empty we must rename it to Filename at the end.
170-
/// TempFilename may be empty and Filename non-empty if creating the temporary
171-
/// failed.
172-
struct OutputFile {
173-
std::string Filename;
174-
std::optional<llvm::sys::fs::TempFile> File;
175-
176-
OutputFile(std::string filename,
177-
std::optional<llvm::sys::fs::TempFile> file)
178-
: Filename(std::move(filename)), File(std::move(file)) {}
179-
};
180-
181171
/// The list of active output files.
182-
std::list<OutputFile> OutputFiles;
172+
std::list<llvm::vfs::OutputFile> OutputFiles;
183173

184174
/// Force an output buffer.
185175
std::unique_ptr<llvm::raw_pwrite_stream> OutputStream;
@@ -430,6 +420,22 @@ class CompilerInstance : public ModuleLoader {
430420

431421
/// Replace the current file manager and virtual file system.
432422
void setFileManager(FileManager *Value);
423+
/// @name Output Backend.
424+
/// {
425+
426+
/// Set the output backend.
427+
void
428+
setOutputBackend(IntrusiveRefCntPtr<llvm::vfs::OutputBackend> NewOutputs);
429+
430+
/// Create an output manager.
431+
void createOutputBackend();
432+
433+
bool hasOutputBackend() const { return bool(TheOutputBackend); }
434+
435+
llvm::vfs::OutputBackend &getOutputBackend();
436+
llvm::vfs::OutputBackend &getOrCreateOutputBackend();
437+
438+
/// }
433439

434440
/// @}
435441
/// @name Source Manager

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 56 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
#include "llvm/Support/Signals.h"
5555
#include "llvm/Support/TimeProfiler.h"
5656
#include "llvm/Support/Timer.h"
57+
#include "llvm/Support/VirtualOutputBackends.h"
58+
#include "llvm/Support/VirtualOutputError.h"
5759
#include "llvm/Support/raw_ostream.h"
5860
#include "llvm/TargetParser/Host.h"
5961
#include <optional>
@@ -516,6 +518,10 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
516518
collectVFSEntries(*this, ModuleDepCollector);
517519
}
518520

521+
// Modules need an output manager.
522+
if (!hasOutputBackend())
523+
createOutputBackend();
524+
519525
for (auto &Listener : DependencyCollectors)
520526
Listener->attachToPreprocessor(*PP);
521527

@@ -759,32 +765,19 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind,
759765
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
760766
// The ASTConsumer can own streams that write to the output files.
761767
assert(!hasASTConsumer() && "ASTConsumer should be reset");
762-
// Ignore errors that occur when trying to discard the temp file.
763-
for (OutputFile &OF : OutputFiles) {
764-
if (EraseFiles) {
765-
if (OF.File)
766-
consumeError(OF.File->discard());
767-
if (!OF.Filename.empty())
768-
llvm::sys::fs::remove(OF.Filename);
769-
continue;
770-
}
771-
772-
if (!OF.File)
773-
continue;
774-
775-
if (OF.File->TmpName.empty()) {
776-
consumeError(OF.File->discard());
777-
continue;
778-
}
779-
780-
llvm::Error E = OF.File->keep(OF.Filename);
781-
if (!E)
782-
continue;
783-
784-
getDiagnostics().Report(diag::err_unable_to_rename_temp)
785-
<< OF.File->TmpName << OF.Filename << std::move(E);
786-
787-
llvm::sys::fs::remove(OF.File->TmpName);
768+
if (!EraseFiles) {
769+
for (auto &O : OutputFiles)
770+
llvm::handleAllErrors(
771+
O.keep(),
772+
[&](const llvm::vfs::TempFileOutputError &E) {
773+
getDiagnostics().Report(diag::err_unable_to_rename_temp)
774+
<< E.getTempPath() << E.getOutputPath()
775+
<< E.convertToErrorCode().message();
776+
},
777+
[&](const llvm::vfs::OutputError &E) {
778+
getDiagnostics().Report(diag::err_fe_unable_to_open_output)
779+
<< E.getOutputPath() << E.convertToErrorCode().message();
780+
});
788781
}
789782
OutputFiles.clear();
790783
if (DeleteBuiltModules) {
@@ -818,6 +811,29 @@ std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() {
818811
return std::make_unique<llvm::raw_null_ostream>();
819812
}
820813

814+
void CompilerInstance::setOutputBackend(
815+
IntrusiveRefCntPtr<llvm::vfs::OutputBackend> NewOutputs) {
816+
assert(!TheOutputBackend && "Already has an output manager");
817+
TheOutputBackend = std::move(NewOutputs);
818+
}
819+
820+
void CompilerInstance::createOutputBackend() {
821+
assert(!TheOutputBackend && "Already has an output manager");
822+
TheOutputBackend =
823+
llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>();
824+
}
825+
826+
llvm::vfs::OutputBackend &CompilerInstance::getOutputBackend() {
827+
assert(TheOutputBackend);
828+
return *TheOutputBackend;
829+
}
830+
831+
llvm::vfs::OutputBackend &CompilerInstance::getOrCreateOutputBackend() {
832+
if (!hasOutputBackend())
833+
createOutputBackend();
834+
return getOutputBackend();
835+
}
836+
821837
std::unique_ptr<raw_pwrite_stream>
822838
CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
823839
bool RemoveFileOnSignal, bool UseTemporary,
@@ -852,98 +868,20 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary,
852868
OutputPath = *AbsPath;
853869
}
854870

855-
std::unique_ptr<llvm::raw_fd_ostream> OS;
856-
std::optional<StringRef> OSFile;
857-
858-
if (UseTemporary) {
859-
if (OutputPath == "-")
860-
UseTemporary = false;
861-
else {
862-
llvm::sys::fs::file_status Status;
863-
llvm::sys::fs::status(OutputPath, Status);
864-
if (llvm::sys::fs::exists(Status)) {
865-
// Fail early if we can't write to the final destination.
866-
if (!llvm::sys::fs::can_write(OutputPath))
867-
return llvm::errorCodeToError(
868-
make_error_code(llvm::errc::operation_not_permitted));
869-
870-
// Don't use a temporary if the output is a special file. This handles
871-
// things like '-o /dev/null'
872-
if (!llvm::sys::fs::is_regular_file(Status))
873-
UseTemporary = false;
874-
}
875-
}
876-
}
877-
878-
std::optional<llvm::sys::fs::TempFile> Temp;
879-
if (UseTemporary) {
880-
// Create a temporary file.
881-
// Insert -%%%%%%%% before the extension (if any), and because some tools
882-
// (noticeable, clang's own GlobalModuleIndex.cpp) glob for build
883-
// artifacts, also append .tmp.
884-
StringRef OutputExtension = llvm::sys::path::extension(OutputPath);
885-
SmallString<128> TempPath =
886-
StringRef(OutputPath).drop_back(OutputExtension.size());
887-
TempPath += "-%%%%%%%%";
888-
TempPath += OutputExtension;
889-
TempPath += ".tmp";
890-
llvm::sys::fs::OpenFlags BinaryFlags =
891-
Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text;
892-
Expected<llvm::sys::fs::TempFile> ExpectedFile =
893-
llvm::sys::fs::TempFile::create(
894-
TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write,
895-
BinaryFlags);
896-
897-
llvm::Error E = handleErrors(
898-
ExpectedFile.takeError(), [&](const llvm::ECError &E) -> llvm::Error {
899-
std::error_code EC = E.convertToErrorCode();
900-
if (CreateMissingDirectories &&
901-
EC == llvm::errc::no_such_file_or_directory) {
902-
StringRef Parent = llvm::sys::path::parent_path(OutputPath);
903-
EC = llvm::sys::fs::create_directories(Parent);
904-
if (!EC) {
905-
ExpectedFile = llvm::sys::fs::TempFile::create(
906-
TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write,
907-
BinaryFlags);
908-
if (!ExpectedFile)
909-
return llvm::errorCodeToError(
910-
llvm::errc::no_such_file_or_directory);
911-
}
912-
}
913-
return llvm::errorCodeToError(EC);
914-
});
915-
916-
if (E) {
917-
consumeError(std::move(E));
918-
} else {
919-
Temp = std::move(ExpectedFile.get());
920-
OS.reset(new llvm::raw_fd_ostream(Temp->FD, /*shouldClose=*/false));
921-
OSFile = Temp->TmpName;
922-
}
923-
// If we failed to create the temporary, fallback to writing to the file
924-
// directly. This handles the corner case where we cannot write to the
925-
// directory, but can write to the file.
926-
}
927-
928-
if (!OS) {
929-
OSFile = OutputPath;
930-
std::error_code EC;
931-
OS.reset(new llvm::raw_fd_ostream(
932-
*OSFile, EC,
933-
(Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_TextWithCRLF)));
934-
if (EC)
935-
return llvm::errorCodeToError(EC);
936-
}
937-
938-
// Add the output file -- but don't try to remove "-", since this means we are
939-
// using stdin.
940-
OutputFiles.emplace_back(((OutputPath != "-") ? OutputPath : "").str(),
941-
std::move(Temp));
942-
943-
if (!Binary || OS->supportsSeeking())
944-
return std::move(OS);
945-
946-
return std::make_unique<llvm::buffer_unique_ostream>(std::move(OS));
871+
using namespace llvm::vfs;
872+
Expected<OutputFile> O = getOrCreateOutputBackend().createFile(
873+
OutputPath,
874+
OutputConfig()
875+
.setTextWithCRLF(!Binary)
876+
.setDiscardOnSignal(RemoveFileOnSignal)
877+
.setAtomicWrite(UseTemporary)
878+
.setImplyCreateDirectories(UseTemporary && CreateMissingDirectories));
879+
if (!O)
880+
return O.takeError();
881+
882+
O->discardOnDestroy([](llvm::Error E) { consumeError(std::move(E)); });
883+
OutputFiles.push_back(std::move(*O));
884+
return OutputFiles.back().createProxy();
947885
}
948886

949887
// Initialization Utilities

0 commit comments

Comments
 (0)