|
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