<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><b class="">TL;DR</b>: Let's virtualize compiler outputs in Clang. These patches would get us started:</div><div class="">- <a href="https://reviews.llvm.org/D95501" class="">https://reviews.llvm.org/D95501</a> Add llvm::vfs::OutputManager</div><div class="">- <a href="https://reviews.llvm.org/D95502" class="">https://reviews.llvm.org/D95502</a> Initial adoption of llvm::vfs::OutputManager in Clang.</div><div class=""><br class=""></div><div class=""><b class="">Questions for the reader</b></div><div class="">- Should we virtualize compiler outputs in Clang? (Hint: <i class="">yes</i>.)</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>- Does this support belong in LLVM? (I think it does, so that non-Clang tools can easily reuse it.)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">       </span>- Is `llvm::vfs::` a reasonable namespace? (If not, suggestions? I think `llvm::` itself is too broad.)</div><div class="">- Do you have a use case that this won't address well?</div><div class=""><span class="Apple-tab-span" style="white-space:pre">   </span>- Should that be fixed in the initial patch, or could this be evolved in-tree to address that?</div><div class="">- Any other major concerns / suggestions?</div><div class="">- If you think the above patches should be split up for initial review / commit, how?</div><div class=""><br class=""></div><div class="">(Other feedback welcome too!)</div><div class=""><br class=""></div><div class=""><b class="">Longer version</b></div><div class="">There are a number of use cases for capturing compiler outputs, which I'm hoping this proposal is a step toward addressing.</div><div class=""><br class=""></div><div class="">- Tooling wants to capture outputs directly, without going through the filesystem.</div><div class=""><span class="Apple-tab-span" style="white-space:pre">  </span>- Sometimes, tertiary outputs can be ignored, or still need to be written to disk.</div><div class="">- clang-scan-deps is using a form of stripped down "implicit" modules to determine which modules need to be built explicitly. It doesn't really want to be using the on-disk module cache—in-memory would be better.</div><div class="">- clang's ModuleManager manually maintains an in-memory modules cache for implicit modules. This involves copying the PCM outputs into memory. It'd be better for these modules to be file-backed, instead of copies of the stream.</div><div class=""><br class=""></div><div class="">The patch has a bunch of details written / tested (<a href="https://reviews.llvm.org/D95501" class="">https://reviews.llvm.org/D95501</a>). Here are the high-level structures in the design:</div><div class=""><br class=""></div><div class="">- OutputManager—a shared manager for creating outputs without knowing about the storage.</div><div class="">- OutputConfig—configuration set on the OutputManager that can be (partially) overridden for specific outputs.</div><div class="">- Output—opaque object with a raw_pwrite_stream, output path, and `erase`/`close` functionality. Internally, it has a linked list of output destinations.</div><div class="">- OutputBackend—abstract interface installed in an OutputManager to create the "guts" of an output. While an OutputManager only has one installed, these can be layered / forked / mirrored.</div><div class="">- OutputDestination—abstract interface paired with an OutputBackend, whose lifetime is managed by an Output.</div><div class="">- ContentBuffer—actual content to allow efficient use of data by multiple backends. For example, the installed backend is a mirror between an on-disk and in-memory backend, the in-memory backend will either get the content moved directly into an llvm::MemoryBuffer, or a just-written mmap'ed file.</div><div class=""><br class=""></div><div class="">The patch includes a few backends:</div><div class=""><br class=""></div>- NullOutputBackend, for ignoring all backends.<br class="">- OnDiskOutputBackend, for writing to disk (the default), initially based on the logic in `clang::CompilerInstance`.<br class="">- InMemoryOutputBackend, for writing to an `InMemoryFileSystem`.<br class="">- MirroringOutputBackend, for writing to multiple backends. OutputDestination's API is designed around supporting this.<br class="">- FilteringOutputBackend, for filtering which outputs get written to the underlying backend.<br class=""><br class=""><b class="">Why doesn't this inherit from llvm::vfs::FileSystem?</b><br class="">Separating the input and output abstractions seems a bit cleaner. It's easy enough to join them, when useful: e.g., write to an `InMemoryFileSystem` (via an `InMemoryOutputBackend`) and install this same FS in the `FileManager` (maybe indirectly via an `OverlayFileSystem`).<div class=""><br class=""></div><div class=""><b class="">Other work in the area</b></div><div class="">See also: <a href="https://reviews.llvm.org/D78058" class="">https://reviews.llvm.org/D78058</a> (thanks to Marc Rasi for posting that patch, and to Sam McCall for some feedback on an earlier version of this proposal).<br class=""><br class="">Thanks for reading!<div class="">Duncan</div></div></body></html>