[LTO][COFF] Use bitcode file names in lto native object file names.

Currently the lto native object files have names like main.exe.lto.1.obj. In
PDB, those names are used as names for each compiland. Microsoft’s tool
SizeBench uses those names to present to users the size of each object files.
So, names like main.exe.lto.1.obj is not user friendly.

This patch makes the lto native object file names more readable by using
the bitcode file names as part of the file names. For example, if the input
bitcode file has path like "path/to/foo.obj", its corresponding lto native
object file path would be "path/to/main.exe.lto.foo.obj". Since the lto native
object file name only bothers PDB, this patch only changes the lld-linker's
behavior.

Reviewed By: tejohnson, MaskRay, #lld-macho

Differential Revision: https://reviews.llvm.org/D137217
This commit is contained in:
Zequan Wu 2022-11-01 17:06:01 -07:00
parent 629f17c516
commit 531ed6d5aa
19 changed files with 141 additions and 104 deletions

View File

@ -1110,7 +1110,7 @@ static void runThinLTOBackend(
if (!lto::initImportList(*M, *CombinedIndex, ImportList))
return;
auto AddStream = [&](size_t Task) {
auto AddStream = [&](size_t Task, const Twine &ModuleName) {
return std::make_unique<CachedFileStream>(std::move(OS),
CGOpts.ObjectFilenameForDebug);
};

View File

@ -843,7 +843,9 @@ Error linkBitcodeFiles(SmallVectorImpl<OffloadFile> &InputFiles,
// Run the LTO job to compile the bitcode.
size_t MaxTasks = LTOBackend->getMaxTasks();
SmallVector<StringRef> Files(MaxTasks);
auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
auto AddStream =
[&](size_t Task,
const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
int FD = -1;
auto &TempFile = Files[Task];
StringRef Extension = (Triple.isNVPTX()) ? "s" : "o";

View File

@ -171,16 +171,18 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
// specified, configure LTO to use it as the cache directory.
FileCache cache;
if (!config->ltoCache.empty())
cache =
check(localCache("ThinLTO", "Thin", config->ltoCache,
[&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
cache = check(localCache("ThinLTO", "Thin", config->ltoCache,
[&](size_t task, const Twine &moduleName,
std::unique_ptr<MemoryBuffer> mb) {
files[task].first = moduleName.str();
files[task].second = std::move(mb);
}));
checkError(ltoObj->run(
[&](size_t task) {
[&](size_t task, const Twine &moduleName) {
buf[task].first = moduleName.str();
return std::make_unique<CachedFileStream>(
std::make_unique<raw_svector_ostream>(buf[task]));
std::make_unique<raw_svector_ostream>(buf[task].second));
},
cache));
@ -197,7 +199,7 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
// distributed environment.
if (config->thinLTOIndexOnly) {
if (!config->ltoObjPath.empty())
saveBuffer(buf[0], config->ltoObjPath);
saveBuffer(buf[0].second, config->ltoObjPath);
if (indexFile)
indexFile->close();
return {};
@ -208,28 +210,40 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
std::vector<InputFile *> ret;
for (unsigned i = 0; i != maxTasks; ++i) {
// Assign unique names to LTO objects. This ensures they have unique names
// in the PDB if one is produced. The names should look like:
// - foo.exe.lto.obj
// - foo.exe.lto.1.obj
// - ...
StringRef ltoObjName =
saver().save(Twine(config->outputFile) + ".lto" +
(i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
StringRef bitcodeFilePath;
// Get the native object contents either from the cache or from memory. Do
// not use the cached MemoryBuffer directly, or the PDB will not be
// deterministic.
StringRef objBuf;
if (files[i])
objBuf = files[i]->getBuffer();
else
objBuf = buf[i];
if (files[i].second) {
objBuf = files[i].second->getBuffer();
bitcodeFilePath = files[i].first;
} else {
objBuf = buf[i].second;
bitcodeFilePath = buf[i].first;
}
if (objBuf.empty())
continue;
// If the input bitcode file is path/to/a.obj, then the corresponding lto
// object file name will soemthing like: path/to/main.exe.lto.a.obj.
StringRef ltoObjName;
if (bitcodeFilePath == "ld-temp.o") {
ltoObjName =
saver().save(Twine(config->outputFile) + ".lto" +
(i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
} else {
StringRef directory = sys::path::parent_path(bitcodeFilePath);
StringRef baseName = sys::path::filename(bitcodeFilePath);
StringRef outputFileBaseName = sys::path::filename(config->outputFile);
SmallString<64> path;
sys::path::append(path, directory,
outputFileBaseName + ".lto." + baseName);
sys::path::remove_dots(path, true);
ltoObjName = saver().save(path.str());
}
if (config->saveTemps)
saveBuffer(buf[i], ltoObjName);
saveBuffer(buf[i].second, ltoObjName);
ret.push_back(make<ObjFile>(ctx, MemoryBufferRef(objBuf, ltoObjName)));
}

View File

@ -47,8 +47,8 @@ public:
private:
std::unique_ptr<llvm::lto::LTO> ltoObj;
std::vector<SmallString<0>> buf;
std::vector<std::unique_ptr<MemoryBuffer>> files;
std::vector<std::pair<std::string, SmallString<0>>> buf;
std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> files;
std::unique_ptr<llvm::raw_fd_ostream> indexFile;
llvm::DenseSet<StringRef> thinIndices;
};

View File

@ -327,15 +327,15 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
// specified, configure LTO to use it as the cache directory.
FileCache cache;
if (!config->thinLTOCacheDir.empty())
cache =
check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
[&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
[&](size_t task, const Twine &moduleName,
std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
if (!ctx.bitcodeFiles.empty())
checkError(ltoObj->run(
[&](size_t task) {
[&](size_t task, const Twine &moduleName) {
return std::make_unique<CachedFileStream>(
std::make_unique<raw_svector_ostream>(buf[task]));
},

View File

@ -129,14 +129,14 @@ std::vector<ObjFile *> BitcodeCompiler::compile() {
// specified, configure LTO to use it as the cache directory.
FileCache cache;
if (!config->thinLTOCacheDir.empty())
cache =
check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
[&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
[&](size_t task, const Twine &moduleName,
std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
checkError(ltoObj->run(
[&](size_t task) {
[&](size_t task, const Twine &moduleName) {
return std::make_unique<CachedFileStream>(
std::make_unique<raw_svector_ostream>(buf[task]));
},

View File

@ -2,26 +2,31 @@
; Test to ensure that thinlto-index-only with lto-obj-path creates
; the native object file.
; RUN: opt -module-summary %s -o %t1.obj
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.obj
; RUN: rm -f %t4.obj
; RUN: lld-link -thinlto-index-only -lto-obj-path:%t4.obj -out:t3.exe \
; RUN: -entry:main %t1.obj %t2.obj
; RUN: llvm-readobj -h %t4.obj | FileCheck %s
; RUN: llvm-nm %t4.obj 2>&1 | FileCheck %s -check-prefix=SYMBOLS
; RUN: llvm-nm %t4.obj 2>&1 | count 1
; RUN: rm -rf %t.dir/objpath && mkdir -p %t.dir/objpath
; RUN: opt -module-summary %s -o %t.dir/objpath/t1.obj
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t.dir/objpath/t2.obj
; RUN: rm -f %t.dir/objpath/t4.obj
; RUN: lld-link -thinlto-index-only -lto-obj-path:%t.dir/objpath/t4.obj \
; RUN: -out:%t.dir/objpath/t3.exe -entry:main %t.dir/objpath/t1.obj \
; RUN: %t.dir/objpath/t2.obj
; RUN: llvm-readobj -h %t.dir/objpath/t4.obj | FileCheck %s
; RUN: llvm-nm %t.dir/objpath/t4.obj 2>&1 | FileCheck %s -check-prefix=SYMBOLS
; RUN: llvm-nm %t.dir/objpath/t4.obj 2>&1 | count 1
;; Ensure lld emits empty combined module if specific obj-path.
; RUN: rm -fr %t.dir/objpath && mkdir -p %t.dir/objpath
; RUN: lld-link /out:%t.dir/objpath/a.exe -lto-obj-path:%t4.obj \
; RUN: -entry:main %t1.obj %t2.obj -lldsavetemps
; RUN: ls %t.dir/objpath/a.exe.lto.* | count 3
; RUN: lld-link /out:%t.dir/objpath/a.exe -lto-obj-path:%t.dir/objpath/t4.obj \
; RUN: -entry:main %t.dir/objpath/t1.obj %t.dir/objpath/t2.obj -lldsavetemps
; RUN: ls %t.dir/objpath/a.exe.lto.obj
; RUN: ls %t.dir/objpath/a.exe.lto.t1.obj
; RUN: ls %t.dir/objpath/a.exe.lto.t2.obj
;; Ensure lld does not emit empty combined module in default.
; RUN: rm -fr %t.dir/objpath && mkdir -p %t.dir/objpath
; RUN: rm %t.dir/objpath/a.exe.lto.*
; RUN: lld-link /out:%t.dir/objpath/a.exe \
; RUN: -entry:main %t1.obj %t2.obj -lldsavetemps
; RUN: ls %t.dir/objpath/a.exe.lto.* | count 2
; RUN: -entry:main %t.dir/objpath/t1.obj %t.dir/objpath/t2.obj -lldsavetemps
; RUN: ls %t.dir/objpath/a.exe.lto.t1.obj
; RUN: ls %t.dir/objpath/a.exe.lto.t2.obj
; RUN: not ls %t.dir/objpath/a.exe.lto.obj
; CHECK: Format: COFF-x86-64
; SYMBOLS: @feat.00

View File

@ -29,8 +29,8 @@ declare void @foo()
; CHECK: Modules
; CHECK: ============================================================
; CHECK: Mod 0000 | `{{.*}}main.exe.lto.1.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.1.obj`:
; CHECK: Mod 0001 | `{{.*}}main.exe.lto.2.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.2.obj`:
; CHECK: Mod 0000 | `{{.*}}main.exe.lto.main.bc`:
; CHECK: Obj: `{{.*}}main.exe.lto.main.bc`:
; CHECK: Mod 0001 | `{{.*}}main.exe.lto.foo.bc`:
; CHECK: Obj: `{{.*}}main.exe.lto.foo.bc`:
; CHECK: Mod 0002 | `* Linker *`:

View File

@ -4,15 +4,15 @@
; RUN: opt -thinlto-bc -o %T/thinlto/main.obj %s
; RUN: opt -thinlto-bc -o %T/thinlto/foo.obj %S/Inputs/lto-dep.ll
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj
; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: llvm-nm %T/thinlto/main.exe.lto.foo.obj | FileCheck %s
; Test various possible options for /opt:lldltojobs
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=1
; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: llvm-nm %T/thinlto/main.exe.lto.foo.obj | FileCheck %s
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=all
; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: llvm-nm %T/thinlto/main.exe.lto.foo.obj | FileCheck %s
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=100
; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: llvm-nm %T/thinlto/main.exe.lto.foo.obj | FileCheck %s
; RUN: not lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=foo 2>&1 | FileCheck %s --check-prefix=BAD-JOBS
; BAD-JOBS: error: /opt:lldltojobs: invalid job count: foo

View File

@ -128,14 +128,14 @@ std::vector<StringRef> BitcodeCompiler::compile() {
// specified, configure LTO to use it as the cache directory.
FileCache cache;
if (!config->thinLTOCacheDir.empty())
cache =
check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
[&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
[&](size_t task, const Twine &moduleName,
std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
checkError(ltoObj->run(
[&](size_t task) {
[&](size_t task, const Twine &moduleName) {
return std::make_unique<CachedFileStream>(
std::make_unique<raw_svector_ostream>(buf[task]));
},

View File

@ -54,7 +54,8 @@ DataFileCache::DataFileCache(llvm::StringRef path, llvm::CachePruningPolicy poli
// m_take_ownership member variable to indicate if we need to take
// ownership.
auto add_buffer = [this](unsigned task, std::unique_ptr<llvm::MemoryBuffer> m) {
auto add_buffer = [this](unsigned task, const llvm::Twine &moduleName,
std::unique_ptr<llvm::MemoryBuffer> m) {
if (m_take_ownership)
m_mem_buff_up = std::move(m);
};
@ -80,7 +81,7 @@ DataFileCache::GetCachedData(llvm::StringRef key) {
// turn take ownership of the member buffer that is passed to the callback and
// put it into a member variable.
llvm::Expected<llvm::AddStreamFn> add_stream_or_err =
m_cache_callback(task, key);
m_cache_callback(task, key, "");
m_take_ownership = false;
// At this point we either already called the "add_buffer" lambda with
// the data or we haven't. We can tell if we got the cached data by checking
@ -112,7 +113,7 @@ bool DataFileCache::SetCachedData(llvm::StringRef key,
// add_buffer lambda function from the constructor which will ignore the
// data.
llvm::Expected<llvm::AddStreamFn> add_stream_or_err =
m_cache_callback(task, key);
m_cache_callback(task, key, "");
// If we reach this code then we either already called the callback with
// the data or we haven't. We can tell if we had the cached data by checking
// the CacheAddStream function pointer value below.
@ -127,7 +128,7 @@ bool DataFileCache::SetCachedData(llvm::StringRef key,
// want to write the data.
if (add_stream) {
llvm::Expected<std::unique_ptr<llvm::CachedFileStream>> file_or_err =
add_stream(task);
add_stream(task, "");
if (file_or_err) {
llvm::CachedFileStream *cfs = file_or_err->get();
cfs->OS->write((const char *)data.data(), data.size());

View File

@ -38,28 +38,30 @@ public:
/// This type defines the callback to add a file that is generated on the fly.
///
/// Stream callbacks must be thread safe.
using AddStreamFn =
std::function<Expected<std::unique_ptr<CachedFileStream>>(unsigned Task)>;
using AddStreamFn = std::function<Expected<std::unique_ptr<CachedFileStream>>(
unsigned Task, const Twine &ModuleName)>;
/// This is the type of a file cache. To request an item from the cache, pass a
/// unique string as the Key. For hits, the cached file will be added to the
/// link and this function will return AddStreamFn(). For misses, the cache will
/// return a stream callback which must be called at most once to produce
/// content for the stream. The file stream produced by the stream callback will
/// add the file to the link after the stream is written to.
/// add the file to the link after the stream is written to. ModuleName is the
/// unique module identifier for the bitcode module the cache is being checked
/// for.
///
/// Clients generally look like this:
///
/// if (AddStreamFn AddStream = Cache(Task, Key))
/// if (AddStreamFn AddStream = Cache(Task, Key, ModuleName))
/// ProduceContent(AddStream);
using FileCache =
std::function<Expected<AddStreamFn>(unsigned Task, StringRef Key)>;
using FileCache = std::function<Expected<AddStreamFn>(
unsigned Task, StringRef Key, const Twine &ModuleName)>;
/// This type defines the callback to add a pre-existing file (e.g. in a cache).
///
/// Buffer callbacks must be thread safe.
using AddBufferFn =
std::function<void(unsigned Task, std::unique_ptr<MemoryBuffer> MB)>;
using AddBufferFn = std::function<void(unsigned Task, const Twine &ModuleName,
std::unique_ptr<MemoryBuffer> MB)>;
/// Create a local file system cache which uses the given cache name, temporary
/// file prefix, cache directory and file callback. This function does not
@ -68,9 +70,10 @@ using AddBufferFn =
/// messages for errors during caching. The temporary file prefix is used in the
/// temporary file naming scheme used when writing files atomically.
Expected<FileCache> localCache(
Twine CacheNameRef, Twine TempFilePrefixRef, Twine CacheDirectoryPathRef,
AddBufferFn AddBuffer = [](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
});
const Twine &CacheNameRef, const Twine &TempFilePrefixRef,
const Twine &CacheDirectoryPathRef,
AddBufferFn AddBuffer = [](size_t Task, const Twine &ModuleName,
std::unique_ptr<MemoryBuffer> MB) {});
} // namespace llvm
#endif

View File

@ -224,7 +224,7 @@ Expected<std::string> getCachedOrDownloadArtifact(
FileCache Cache = *CacheOrErr;
// We choose an arbitrary Task parameter as we do not make use of it.
unsigned Task = 0;
Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, UniqueKey);
Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, UniqueKey, "");
if (!CacheAddStreamOrErr)
return CacheAddStreamOrErr.takeError();
AddStreamFn &CacheAddStream = *CacheAddStreamOrErr;
@ -251,8 +251,8 @@ Expected<std::string> getCachedOrDownloadArtifact(
// Perform the HTTP request and if successful, write the response body to
// the cache.
StreamedHTTPResponseHandler Handler([&]() { return CacheAddStream(Task); },
Client);
StreamedHTTPResponseHandler Handler(
[&]() { return CacheAddStream(Task, ""); }, Client);
HTTPRequest Request(ArtifactUrl);
Request.Headers = getHeaders();
Error Err = Client.perform(Request, Handler);

View File

@ -1313,7 +1313,7 @@ public:
computeLTOCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList,
ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs,
CfiFunctionDecls);
Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, Key);
Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, Key, ModuleID);
if (Error Err = CacheAddStreamOrErr.takeError())
return Err;
AddStreamFn &CacheAddStream = *CacheAddStreamOrErr;

View File

@ -391,7 +391,8 @@ static void codegen(const Config &Conf, TargetMachine *TM,
EC.message());
}
Expected<std::unique_ptr<CachedFileStream>> StreamOrErr = AddStream(Task);
Expected<std::unique_ptr<CachedFileStream>> StreamOrErr =
AddStream(Task, Mod.getModuleIdentifier());
if (Error Err = StreamOrErr.takeError())
report_fatal_error(std::move(Err));
std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;

View File

@ -301,7 +301,9 @@ bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) {
// make unique temp output file to put generated code
SmallString<128> Filename;
auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
auto AddStream =
[&](size_t Task,
const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
StringRef Extension(Config.CGFileType == CGFT_AssemblyFile ? "s" : "o");
int FD;

View File

@ -26,9 +26,9 @@
using namespace llvm;
Expected<FileCache> llvm::localCache(Twine CacheNameRef,
Twine TempFilePrefixRef,
Twine CacheDirectoryPathRef,
Expected<FileCache> llvm::localCache(const Twine &CacheNameRef,
const Twine &TempFilePrefixRef,
const Twine &CacheDirectoryPathRef,
AddBufferFn AddBuffer) {
// Create local copies which are safely captured-by-copy in lambdas
@ -37,7 +37,8 @@ Expected<FileCache> llvm::localCache(Twine CacheNameRef,
TempFilePrefixRef.toVector(TempFilePrefix);
CacheDirectoryPathRef.toVector(CacheDirectoryPath);
return [=](unsigned Task, StringRef Key) -> Expected<AddStreamFn> {
return [=](unsigned Task, StringRef Key,
const Twine &ModuleName) -> Expected<AddStreamFn> {
// This choice of file name allows the cache to be pruned (see pruneCache()
// in include/llvm/Support/CachePruning.h).
SmallString<64> EntryPath;
@ -54,7 +55,7 @@ Expected<FileCache> llvm::localCache(Twine CacheNameRef,
/*RequiresNullTerminator=*/false);
sys::fs::closeFile(*FDOrErr);
if (MBOrErr) {
AddBuffer(Task, std::move(*MBOrErr));
AddBuffer(Task, ModuleName, std::move(*MBOrErr));
return AddStreamFn();
}
EC = MBOrErr.getError();
@ -77,14 +78,15 @@ Expected<FileCache> llvm::localCache(Twine CacheNameRef,
struct CacheStream : CachedFileStream {
AddBufferFn AddBuffer;
sys::fs::TempFile TempFile;
std::string ModuleName;
unsigned Task;
CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddBufferFn AddBuffer,
sys::fs::TempFile TempFile, std::string EntryPath,
unsigned Task)
std::string ModuleName, unsigned Task)
: CachedFileStream(std::move(OS), std::move(EntryPath)),
AddBuffer(std::move(AddBuffer)), TempFile(std::move(TempFile)),
Task(Task) {}
ModuleName(ModuleName), Task(Task) {}
~CacheStream() {
// TODO: Manually commit rather than using non-trivial destructor,
@ -133,11 +135,12 @@ Expected<FileCache> llvm::localCache(Twine CacheNameRef,
TempFile.TmpName + " to " + ObjectPathName + ": " +
toString(std::move(E)) + "\n");
AddBuffer(Task, std::move(*MBOrErr));
AddBuffer(Task, ModuleName, std::move(*MBOrErr));
}
};
return [=](size_t Task) -> Expected<std::unique_ptr<CachedFileStream>> {
return [=](size_t Task, const Twine &ModuleName)
-> Expected<std::unique_ptr<CachedFileStream>> {
// Create the cache directory if not already done. Doing this lazily
// ensures the filesystem isn't mutated until the cache is.
if (std::error_code EC = sys::fs::create_directories(
@ -158,7 +161,8 @@ Expected<FileCache> llvm::localCache(Twine CacheNameRef,
// This CacheStream will move the temporary file into the cache when done.
return std::make_unique<CacheStream>(
std::make_unique<raw_fd_ostream>(Temp->FD, /* ShouldClose */ false),
AddBuffer, std::move(*Temp), std::string(EntryPath.str()), Task);
AddBuffer, std::move(*Temp), std::string(EntryPath.str()),
ModuleName.str(), Task);
};
};
}

View File

@ -317,11 +317,11 @@ namespace {
if (!CurrentActivity.empty())
OS << ' ' << CurrentActivity;
OS << ": ";
DiagnosticPrinterRawOStream DP(OS);
DI.print(DP);
OS << '\n';
if (DI.getSeverity() == DS_Error)
exit(1);
return true;
@ -1099,7 +1099,9 @@ int main(int argc, char **argv) {
error("writing merged module failed.");
}
auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
auto AddStream =
[&](size_t Task,
const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
std::string PartFilename = OutputFilename;
if (Parallelism != 1)
PartFilename += "." + utostr(Task);

View File

@ -411,7 +411,9 @@ static int run(int argc, char **argv) {
if (HasErrors)
return 1;
auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
auto AddStream =
[&](size_t Task,
const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
std::string Path = OutputFilename + "." + utostr(Task);
std::error_code EC;
@ -420,8 +422,9 @@ static int run(int argc, char **argv) {
return std::make_unique<CachedFileStream>(std::move(S), Path);
};
auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
*AddStream(Task)->OS << MB->getBuffer();
auto AddBuffer = [&](size_t Task, const Twine &ModuleName,
std::unique_ptr<MemoryBuffer> MB) {
*AddStream(Task, ModuleName)->OS << MB->getBuffer();
};
FileCache Cache;