@@ -236,6 +236,27 @@ namespace {
236
236
// handled.
237
237
class CompileJobCache {
238
238
public:
239
+ // / Categorization for the output kinds that is used to decouple the
240
+ // / compilation cache key from the specific output paths.
241
+ enum class OutputKind {
242
+ MainOutput,
243
+ SerializedDiagnostics,
244
+ Dependencies,
245
+ };
246
+ static ArrayRef<OutputKind> getAllOutputKinds () {
247
+ static const OutputKind AllOutputKinds[] = {
248
+ OutputKind::MainOutput, OutputKind::SerializedDiagnostics,
249
+ OutputKind::Dependencies};
250
+ return llvm::makeArrayRef (AllOutputKinds);
251
+ }
252
+
253
+ static StringRef getOutputKindName (OutputKind Kind);
254
+
255
+ // / \returns \p None if \p Name doesn't match one of the output kind names.
256
+ static Optional<OutputKind> getOutputKindForName (StringRef Name);
257
+
258
+ StringRef getPathForOutputKind (OutputKind Kind);
259
+
239
260
// / Canonicalize \p Clang.
240
261
// /
241
262
// / Return status if should exit immediately, otherwise None.
@@ -267,19 +288,60 @@ class CompileJobCache {
267
288
SmallString<256 > ResultDiags;
268
289
Optional<llvm::cas::CASID> ResultCacheKey;
269
290
std::unique_ptr<llvm::raw_ostream> ResultDiagsOS;
291
+ SmallString<256 > SerialDiagsBuf;
270
292
IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> CASOutputs;
271
293
std::string OutputFile;
294
+ std::string SerialDiagsFile;
295
+ std::string DependenciesFile;
272
296
Optional<llvm::vfs::OutputFile> SerialDiagsOutput;
273
297
};
274
298
} // end anonymous namespace
275
299
300
+ static constexpr llvm::StringLiteral MainOutputKindName = " <output>" ;
301
+ static constexpr llvm::StringLiteral SerializedDiagnosticsKindName =
302
+ " <serial-diags>" ;
303
+ static constexpr llvm::StringLiteral DependenciesOutputKindName =
304
+ " <dependencies>" ;
305
+
306
+ StringRef CompileJobCache::getOutputKindName (OutputKind Kind) {
307
+ switch (Kind) {
308
+ case OutputKind::MainOutput:
309
+ return MainOutputKindName;
310
+ case OutputKind::SerializedDiagnostics:
311
+ return SerializedDiagnosticsKindName;
312
+ case OutputKind::Dependencies:
313
+ return DependenciesOutputKindName;
314
+ }
315
+ }
316
+
317
+ Optional<CompileJobCache::OutputKind>
318
+ CompileJobCache::getOutputKindForName (StringRef Name) {
319
+ return llvm::StringSwitch<Optional<OutputKind>>(Name)
320
+ .Case (MainOutputKindName, OutputKind::MainOutput)
321
+ .Case (SerializedDiagnosticsKindName, OutputKind::SerializedDiagnostics)
322
+ .Case (DependenciesOutputKindName, OutputKind::Dependencies)
323
+ .Default (None);
324
+ }
325
+
326
+ StringRef CompileJobCache::getPathForOutputKind (OutputKind Kind) {
327
+ switch (Kind) {
328
+ case OutputKind::MainOutput:
329
+ return OutputFile;
330
+ case OutputKind::SerializedDiagnostics:
331
+ return SerialDiagsFile;
332
+ case OutputKind::Dependencies:
333
+ return DependenciesFile;
334
+ }
335
+ }
336
+
276
337
Optional<int > CompileJobCache::initialize (CompilerInstance &Clang) {
277
338
CompilerInvocation &Invocation = Clang.getInvocation ();
278
339
DiagnosticsEngine &Diags = Clang.getDiagnostics ();
340
+ FrontendOptions &FrontendOpts = Invocation.getFrontendOpts ();
279
341
280
342
// Extract whether caching is on (and canonicalize setting).
281
- CacheCompileJob = Invocation. getFrontendOpts () .CacheCompileJob ;
282
- Invocation. getFrontendOpts () .CacheCompileJob = false ;
343
+ CacheCompileJob = FrontendOpts .CacheCompileJob ;
344
+ FrontendOpts .CacheCompileJob = false ;
283
345
284
346
// Nothing else to do if we're not caching.
285
347
if (!CacheCompileJob)
@@ -300,10 +362,11 @@ Optional<int> CompileJobCache::initialize(CompilerInstance &Clang) {
300
362
// TODO: Canonicalize DiagnosticOptions here to be "serialized" only. Pass in
301
363
// a hook to mirror diagnostics to stderr (when writing there), and handle
302
364
// other outputs during replay.
365
+ FrontendOpts.IncludeTimestamps = false ;
303
366
304
- // TODO: Canonicalize OutputFile to "-" here. During replay, move it and
305
- // derived outputs to the right place.
306
- OutputFile = Invocation.getFrontendOpts ().OutputFile ;
367
+ OutputFile = FrontendOpts. OutputFile ;
368
+ SerialDiagsFile = Invocation. getDiagnosticOpts (). DiagnosticSerializationFile ;
369
+ DependenciesFile = Invocation.getDependencyOutputOpts ().OutputFile ;
307
370
return None;
308
371
}
309
372
@@ -387,6 +450,11 @@ Optional<int> CompileJobCache::tryReplayCachedResult(CompilerInstance &Clang) {
387
450
388
451
// Set up the output backend so we can save / cache the result after.
389
452
CASOutputs = llvm::makeIntrusiveRefCnt<llvm::cas::CASOutputBackend>(*CAS);
453
+ for (OutputKind K : getAllOutputKinds ()) {
454
+ StringRef OutPath = getPathForOutputKind (K);
455
+ if (!OutPath.empty ())
456
+ CASOutputs->addKindMap (getOutputKindName (K), OutPath);
457
+ }
390
458
391
459
Clang.setOutputBackend (llvm::vfs::makeMirroringOutputBackend (
392
460
CASOutputs, std::move (OnDiskOutputs)));
@@ -442,6 +510,14 @@ Optional<int> CompileJobCache::tryReplayCachedResult(CompilerInstance &Clang) {
442
510
OutputFile, &DiagOpts, /* MergeChildRecords*/ false , std::move (*OS));
443
511
Diags.setClient (new ChainedDiagnosticConsumer (
444
512
Diags.takeClient (), std::move (SerializedConsumer)));
513
+ } else {
514
+ // We always generate the serialized diagnostics so the key is independent
515
+ // of the presence of '--serialize-diagnostics'.
516
+ auto OS = std::make_unique<llvm::raw_svector_ostream>(SerialDiagsBuf);
517
+ auto SerializedConsumer = clang::serialized_diags::create (
518
+ StringRef (), &DiagOpts, /* MergeChildRecords*/ false , std::move (OS));
519
+ Diags.setClient (new ChainedDiagnosticConsumer (
520
+ Diags.takeClient (), std::move (SerializedConsumer)));
445
521
}
446
522
447
523
return None;
@@ -476,6 +552,21 @@ void CompileJobCache::finishComputedResult(CompilerInstance &Clang,
476
552
return ;
477
553
478
554
// FIXME: Stop calling report_fatal_error().
555
+ if (!SerialDiagsOutput) {
556
+ // Not requested to get a serialized diagnostics file but we generated it
557
+ // and will store it regardless so that the key is independent of the
558
+ // presence of '--serialize-diagnostics'.
559
+ Expected<llvm::cas::ObjectProxy> SerialDiags =
560
+ CAS->createProxy (None, SerialDiagsBuf);
561
+ // FIXME: Stop calling report_fatal_error().
562
+ if (!SerialDiags)
563
+ llvm::report_fatal_error (SerialDiags.takeError ());
564
+ if (Error E = CASOutputs->addObject (
565
+ getOutputKindName (OutputKind::SerializedDiagnostics),
566
+ SerialDiags->getRef ()))
567
+ llvm::report_fatal_error (std::move (E));
568
+ }
569
+
479
570
Expected<llvm::cas::ObjectProxy> Outputs = CASOutputs->getCASProxy ();
480
571
if (!Outputs)
481
572
llvm::report_fatal_error (Outputs.takeError ());
@@ -557,20 +648,28 @@ Optional<int> CompileJobCache::replayCachedResult(CompilerInstance &Clang,
557
648
llvm::cas::CASID PathID = Outputs->getReferenceID (I);
558
649
llvm::cas::CASID BytesID = Outputs->getReferenceID (I + 1 );
559
650
560
- Optional<llvm::cas::ObjectProxy> Path ;
561
- if (Error E = CAS->getProxy (PathID).moveInto (Path ))
651
+ Optional<llvm::cas::ObjectProxy> PathProxy ;
652
+ if (Error E = CAS->getProxy (PathID).moveInto (PathProxy ))
562
653
llvm::report_fatal_error (std::move (E));
563
654
655
+ Optional<OutputKind> OutKind = getOutputKindForName (PathProxy->getData ());
656
+ StringRef Path =
657
+ OutKind ? getPathForOutputKind (*OutKind) : PathProxy->getData ();
658
+ if (Path.empty ()) {
659
+ // The output may be always generated but not needed with this invocation,
660
+ // like the serialized diagnostics file.
661
+ continue ;
662
+ }
663
+
564
664
Optional<StringRef> Contents;
565
665
SmallString<50 > ContentsStorage;
566
666
Optional<llvm::cas::ObjectProxy> Bytes;
567
667
if (Error E = CAS->getProxy (BytesID).moveInto (Bytes))
568
668
llvm::report_fatal_error (std::move (E));
569
669
Contents = Bytes->getData ();
570
670
std::unique_ptr<llvm::FileOutputBuffer> Output;
571
- if (Error E =
572
- llvm::FileOutputBuffer::create (Path->getData (), Contents->size ())
573
- .moveInto (Output))
671
+ if (Error E = llvm::FileOutputBuffer::create (Path, Contents->size ())
672
+ .moveInto (Output))
574
673
llvm::report_fatal_error (std::move (E));
575
674
llvm::copy (*Contents, Output->getBufferStart ());
576
675
if (llvm::Error E = Output->commit ())
0 commit comments