|
57 | 57 | #include "llvm/Support/TimeProfiler.h"
|
58 | 58 | #include "llvm/Support/Timer.h"
|
59 | 59 | #include "llvm/Support/VirtualFileSystem.h"
|
| 60 | +#include "llvm/Support/VirtualOutputBackends.h" |
| 61 | +#include "llvm/Support/VirtualOutputError.h" |
60 | 62 | #include "llvm/Support/raw_ostream.h"
|
61 | 63 | #include "llvm/TargetParser/Host.h"
|
62 | 64 | #include <optional>
|
@@ -522,6 +524,10 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
|
522 | 524 | collectVFSEntries(*this, ModuleDepCollector);
|
523 | 525 | }
|
524 | 526 |
|
| 527 | + // Modules need an output manager. |
| 528 | + if (!hasOutputManager()) |
| 529 | + createOutputManager(); |
| 530 | + |
525 | 531 | for (auto &Listener : DependencyCollectors)
|
526 | 532 | Listener->attachToPreprocessor(*PP);
|
527 | 533 |
|
@@ -778,32 +784,23 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind,
|
778 | 784 | void CompilerInstance::clearOutputFiles(bool EraseFiles) {
|
779 | 785 | // The ASTConsumer can own streams that write to the output files.
|
780 | 786 | assert(!hasASTConsumer() && "ASTConsumer should be reset");
|
781 |
| - // Ignore errors that occur when trying to discard the temp file. |
782 |
| - for (OutputFile &OF : OutputFiles) { |
783 |
| - if (EraseFiles) { |
784 |
| - if (OF.File) |
785 |
| - consumeError(OF.File->discard()); |
786 |
| - if (!OF.Filename.empty()) |
787 |
| - llvm::sys::fs::remove(OF.Filename); |
788 |
| - continue; |
789 |
| - } |
790 |
| - |
791 |
| - if (!OF.File) |
792 |
| - continue; |
793 |
| - |
794 |
| - if (OF.File->TmpName.empty()) { |
795 |
| - consumeError(OF.File->discard()); |
796 |
| - continue; |
797 |
| - } |
798 |
| - |
799 |
| - llvm::Error E = OF.File->keep(OF.Filename); |
800 |
| - if (!E) |
801 |
| - continue; |
802 |
| - |
803 |
| - getDiagnostics().Report(diag::err_unable_to_rename_temp) |
804 |
| - << OF.File->TmpName << OF.Filename << std::move(E); |
805 |
| - |
806 |
| - llvm::sys::fs::remove(OF.File->TmpName); |
| 787 | + if (!EraseFiles) { |
| 788 | + for (auto &O : OutputFiles) |
| 789 | + llvm::handleAllErrors( |
| 790 | + O.keep(), |
| 791 | + [&](const llvm::vfs::TempFileOutputError &E) { |
| 792 | + getDiagnostics().Report(diag::err_unable_to_rename_temp) |
| 793 | + << E.getTempPath() << E.getOutputPath() |
| 794 | + << E.convertToErrorCode().message(); |
| 795 | + }, |
| 796 | + [&](const llvm::vfs::OutputError &E) { |
| 797 | + getDiagnostics().Report(diag::err_fe_unable_to_open_output) |
| 798 | + << E.getOutputPath() << E.convertToErrorCode().message(); |
| 799 | + }, |
| 800 | + [&](const llvm::ErrorInfoBase &EIB) { // Handle any remaining error |
| 801 | + getDiagnostics().Report(diag::err_fe_unable_to_open_output) |
| 802 | + << O.getPath() << EIB.message(); |
| 803 | + }); |
807 | 804 | }
|
808 | 805 | OutputFiles.clear();
|
809 | 806 | if (DeleteBuiltModules) {
|
@@ -837,6 +834,30 @@ std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() {
|
837 | 834 | return std::make_unique<llvm::raw_null_ostream>();
|
838 | 835 | }
|
839 | 836 |
|
| 837 | +// Output Manager |
| 838 | + |
| 839 | +void CompilerInstance::setOutputManager( |
| 840 | + IntrusiveRefCntPtr<llvm::vfs::OutputBackend> NewOutputs) { |
| 841 | + assert(!OutputMgr && "Already has an output manager"); |
| 842 | + OutputMgr = std::move(NewOutputs); |
| 843 | +} |
| 844 | + |
| 845 | +void CompilerInstance::createOutputManager() { |
| 846 | + assert(!OutputMgr && "Already has an output manager"); |
| 847 | + OutputMgr = llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>(); |
| 848 | +} |
| 849 | + |
| 850 | +llvm::vfs::OutputBackend &CompilerInstance::getOutputManager() { |
| 851 | + assert(OutputMgr); |
| 852 | + return *OutputMgr; |
| 853 | +} |
| 854 | + |
| 855 | +llvm::vfs::OutputBackend &CompilerInstance::getOrCreateOutputManager() { |
| 856 | + if (!hasOutputManager()) |
| 857 | + createOutputManager(); |
| 858 | + return getOutputManager(); |
| 859 | +} |
| 860 | + |
840 | 861 | std::unique_ptr<raw_pwrite_stream>
|
841 | 862 | CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
|
842 | 863 | bool RemoveFileOnSignal, bool UseTemporary,
|
@@ -871,98 +892,20 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary,
|
871 | 892 | OutputPath = *AbsPath;
|
872 | 893 | }
|
873 | 894 |
|
874 |
| - std::unique_ptr<llvm::raw_fd_ostream> OS; |
875 |
| - std::optional<StringRef> OSFile; |
876 |
| - |
877 |
| - if (UseTemporary) { |
878 |
| - if (OutputPath == "-") |
879 |
| - UseTemporary = false; |
880 |
| - else { |
881 |
| - llvm::sys::fs::file_status Status; |
882 |
| - llvm::sys::fs::status(OutputPath, Status); |
883 |
| - if (llvm::sys::fs::exists(Status)) { |
884 |
| - // Fail early if we can't write to the final destination. |
885 |
| - if (!llvm::sys::fs::can_write(OutputPath)) |
886 |
| - return llvm::errorCodeToError( |
887 |
| - make_error_code(llvm::errc::operation_not_permitted)); |
888 |
| - |
889 |
| - // Don't use a temporary if the output is a special file. This handles |
890 |
| - // things like '-o /dev/null' |
891 |
| - if (!llvm::sys::fs::is_regular_file(Status)) |
892 |
| - UseTemporary = false; |
893 |
| - } |
894 |
| - } |
895 |
| - } |
896 |
| - |
897 |
| - std::optional<llvm::sys::fs::TempFile> Temp; |
898 |
| - if (UseTemporary) { |
899 |
| - // Create a temporary file. |
900 |
| - // Insert -%%%%%%%% before the extension (if any), and because some tools |
901 |
| - // (noticeable, clang's own GlobalModuleIndex.cpp) glob for build |
902 |
| - // artifacts, also append .tmp. |
903 |
| - StringRef OutputExtension = llvm::sys::path::extension(OutputPath); |
904 |
| - SmallString<128> TempPath = |
905 |
| - StringRef(OutputPath).drop_back(OutputExtension.size()); |
906 |
| - TempPath += "-%%%%%%%%"; |
907 |
| - TempPath += OutputExtension; |
908 |
| - TempPath += ".tmp"; |
909 |
| - llvm::sys::fs::OpenFlags BinaryFlags = |
910 |
| - Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text; |
911 |
| - Expected<llvm::sys::fs::TempFile> ExpectedFile = |
912 |
| - llvm::sys::fs::TempFile::create( |
913 |
| - TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write, |
914 |
| - BinaryFlags); |
915 |
| - |
916 |
| - llvm::Error E = handleErrors( |
917 |
| - ExpectedFile.takeError(), [&](const llvm::ECError &E) -> llvm::Error { |
918 |
| - std::error_code EC = E.convertToErrorCode(); |
919 |
| - if (CreateMissingDirectories && |
920 |
| - EC == llvm::errc::no_such_file_or_directory) { |
921 |
| - StringRef Parent = llvm::sys::path::parent_path(OutputPath); |
922 |
| - EC = llvm::sys::fs::create_directories(Parent); |
923 |
| - if (!EC) { |
924 |
| - ExpectedFile = llvm::sys::fs::TempFile::create( |
925 |
| - TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write, |
926 |
| - BinaryFlags); |
927 |
| - if (!ExpectedFile) |
928 |
| - return llvm::errorCodeToError( |
929 |
| - llvm::errc::no_such_file_or_directory); |
930 |
| - } |
931 |
| - } |
932 |
| - return llvm::errorCodeToError(EC); |
933 |
| - }); |
934 |
| - |
935 |
| - if (E) { |
936 |
| - consumeError(std::move(E)); |
937 |
| - } else { |
938 |
| - Temp = std::move(ExpectedFile.get()); |
939 |
| - OS.reset(new llvm::raw_fd_ostream(Temp->FD, /*shouldClose=*/false)); |
940 |
| - OSFile = Temp->TmpName; |
941 |
| - } |
942 |
| - // If we failed to create the temporary, fallback to writing to the file |
943 |
| - // directly. This handles the corner case where we cannot write to the |
944 |
| - // directory, but can write to the file. |
945 |
| - } |
946 |
| - |
947 |
| - if (!OS) { |
948 |
| - OSFile = OutputPath; |
949 |
| - std::error_code EC; |
950 |
| - OS.reset(new llvm::raw_fd_ostream( |
951 |
| - *OSFile, EC, |
952 |
| - (Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_TextWithCRLF))); |
953 |
| - if (EC) |
954 |
| - return llvm::errorCodeToError(EC); |
955 |
| - } |
956 |
| - |
957 |
| - // Add the output file -- but don't try to remove "-", since this means we are |
958 |
| - // using stdin. |
959 |
| - OutputFiles.emplace_back(((OutputPath != "-") ? OutputPath : "").str(), |
960 |
| - std::move(Temp)); |
961 |
| - |
962 |
| - if (!Binary || OS->supportsSeeking()) |
963 |
| - return std::move(OS); |
964 |
| - |
965 |
| - return std::make_unique<llvm::buffer_unique_ostream>(std::move(OS)); |
| 895 | + using namespace llvm::vfs; |
| 896 | + Expected<OutputFile> O = getOrCreateOutputManager().createFile( |
| 897 | + OutputPath, |
| 898 | + OutputConfig() |
| 899 | + .setTextWithCRLF(!Binary) |
| 900 | + .setDiscardOnSignal(RemoveFileOnSignal) |
| 901 | + .setAtomicWrite(UseTemporary) |
| 902 | + .setImplyCreateDirectories(UseTemporary && CreateMissingDirectories)); |
| 903 | + if (!O) |
| 904 | + return O.takeError(); |
| 905 | + |
| 906 | + O->discardOnDestroy([](llvm::Error E) { consumeError(std::move(E)); }); |
| 907 | + OutputFiles.push_back(std::move(*O)); |
| 908 | + return OutputFiles.back().createProxy(); |
966 | 909 | }
|
967 | 910 |
|
968 | 911 | // Initialization Utilities
|
|
0 commit comments