99#include " DependencyScannerImpl.h"
1010#include " clang/Basic/DiagnosticFrontend.h"
1111#include " clang/Basic/DiagnosticSerialization.h"
12+ #include " clang/Driver/Driver.h"
1213#include " clang/Frontend/FrontendActions.h"
1314#include " clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
15+ #include " llvm/TargetParser/Host.h"
1416
1517using namespace clang ;
1618using namespace tooling ;
@@ -334,6 +336,17 @@ class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
334336};
335337} // namespace
336338
339+ std::unique_ptr<DiagnosticOptions>
340+ clang::tooling::dependencies::createDiagOptions (
341+ const std::vector<std::string> &CommandLine) {
342+ std::vector<const char *> CLI;
343+ for (const std::string &Arg : CommandLine)
344+ CLI.push_back (Arg.c_str ());
345+ auto DiagOpts = CreateAndPopulateDiagOpts (CLI);
346+ sanitizeDiagOpts (*DiagOpts);
347+ return DiagOpts;
348+ }
349+
337350// / Sanitize diagnostic options for dependency scan.
338351void clang::tooling::dependencies::sanitizeDiagOpts (
339352 DiagnosticOptions &DiagOpts) {
@@ -356,43 +369,131 @@ void clang::tooling::dependencies::sanitizeDiagOpts(
356369 });
357370}
358371
359- bool DependencyScanningAction::runInvocation (
360- std::shared_ptr<CompilerInvocation> Invocation,
361- IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
362- std::shared_ptr<PCHContainerOperations> PCHContainerOps,
363- DiagnosticConsumer *DiagConsumer) {
364- // Making sure that we canonicalize the defines before we create the deep
365- // copy to avoid unnecessary variants in the scanner and in the resulting
366- // explicit command lines.
367- if (any (Service.getOptimizeArgs () & ScanningOptimizations::Macros))
368- canonicalizeDefines (Invocation->getPreprocessorOpts ());
372+ std::pair<std::unique_ptr<driver::Driver>, std::unique_ptr<driver::Compilation>>
373+ clang::tooling::dependencies::buildCompilation (
374+ ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
375+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
376+ SmallVector<const char *, 256 > Argv;
377+ Argv.reserve (ArgStrs.size ());
378+ for (const std::string &Arg : ArgStrs)
379+ Argv.push_back (Arg.c_str ());
380+
381+ std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
382+ Argv[0 ], llvm::sys::getDefaultTargetTriple (), Diags,
383+ " clang LLVM compiler" , FS);
384+ Driver->setTitle (" clang_based_tool" );
385+
386+ llvm::BumpPtrAllocator Alloc;
387+ bool CLMode = driver::IsClangCL (
388+ driver::getDriverMode (Argv[0 ], ArrayRef (Argv).slice (1 )));
389+
390+ if (llvm::Error E =
391+ driver::expandResponseFiles (Argv, CLMode, Alloc, FS.get ())) {
392+ Diags.Report (diag::err_drv_expand_response_file)
393+ << llvm::toString (std::move (E));
394+ return std::make_pair (nullptr , nullptr );
395+ }
369396
370- // Make a deep copy of the original Clang invocation.
371- CompilerInvocation OriginalInvocation (*Invocation);
397+ std::unique_ptr<driver::Compilation> Compilation (
398+ Driver->BuildCompilation (llvm::ArrayRef (Argv)));
399+ if (!Compilation)
400+ return std::make_pair (nullptr , nullptr );
372401
373- if (Scanned) {
374- // Scanning runs once for the first -cc1 invocation in a chain of driver
375- // jobs. For any dependent jobs, reuse the scanning result and just
376- // update the LastCC1Arguments to correspond to the new invocation.
377- // FIXME: to support multi-arch builds, each arch requires a separate scan
378- setLastCC1Arguments (std::move (OriginalInvocation));
379- return true ;
402+ if (Compilation->containsError ())
403+ return std::make_pair (nullptr , nullptr );
404+
405+ return std::make_pair (std::move (Driver), std::move (Compilation));
406+ }
407+
408+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
409+ clang::tooling::dependencies::initVFSForTUBufferScanning (
410+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
411+ std::optional<std::vector<std::string>> &ModifiedCommandLine,
412+ const std::vector<std::string> &CommandLine, StringRef WorkingDirectory,
413+ std::optional<llvm::MemoryBufferRef> TUBuffer) {
414+ // Reset what might have been modified in the previous worker invocation.
415+ BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
416+
417+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
418+ if (TUBuffer) {
419+ auto OverlayFS =
420+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
421+ auto InMemoryFS =
422+ llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
423+ InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
424+ auto InputPath = TUBuffer->getBufferIdentifier ();
425+ InMemoryFS->addFile (
426+ InputPath, 0 ,
427+ llvm::MemoryBuffer::getMemBufferCopy (TUBuffer->getBuffer ()));
428+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay =
429+ InMemoryFS;
430+
431+ OverlayFS->pushOverlay (InMemoryOverlay);
432+ ModifiedFS = OverlayFS;
433+ ModifiedCommandLine = CommandLine;
434+ ModifiedCommandLine->emplace_back (InputPath);
435+
436+ return ModifiedFS;
380437 }
381438
382- Scanned = true ;
439+ return BaseFS;
440+ }
383441
384- // Create a compiler instance to handle the actual work.
385- auto ModCache = makeInProcessModuleCache (Service.getModuleCacheEntries ());
386- ScanInstanceStorage.emplace (std::move (Invocation), std::move (PCHContainerOps),
387- ModCache.get ());
388- CompilerInstance &ScanInstance = *ScanInstanceStorage;
442+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
443+ clang::tooling::dependencies::initVFSForByNameScanning (
444+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
445+ std::vector<std::string> &CommandLine, StringRef WorkingDirectory,
446+ StringRef FakeFileNamePrefix) {
447+ // Reset what might have been modified in the previous worker invocation.
448+ BaseFS->setCurrentWorkingDirectory (WorkingDirectory);
449+
450+ // If we're scanning based on a module name alone, we don't expect the client
451+ // to provide us with an input file. However, the driver really wants to have
452+ // one. Let's just make it up to make the driver happy.
453+ auto OverlayFS =
454+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
455+ auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
456+ InMemoryFS->setCurrentWorkingDirectory (WorkingDirectory);
457+ SmallString<128 > FakeInputPath;
458+ // TODO: We should retry the creation if the path already exists.
459+ llvm::sys::fs::createUniquePath (FakeFileNamePrefix + " -%%%%%%%%.input" ,
460+ FakeInputPath,
461+ /* MakeAbsolute=*/ false );
462+ InMemoryFS->addFile (FakeInputPath, 0 , llvm::MemoryBuffer::getMemBuffer (" " ));
463+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
464+ OverlayFS->pushOverlay (InMemoryOverlay);
465+
466+ CommandLine.emplace_back (FakeInputPath);
467+
468+ return OverlayFS;
469+ }
470+
471+ std::unique_ptr<CompilerInvocation>
472+ clang::tooling::dependencies::createCompilerInvocation (
473+ const std::vector<std::string> &CommandLine, DiagnosticsEngine &Diags) {
474+ llvm::opt::ArgStringList Argv;
475+ for (const std::string &Str : ArrayRef (CommandLine).drop_front ())
476+ Argv.push_back (Str.c_str ());
477+
478+ auto Invocation = std::make_unique<CompilerInvocation>();
479+ if (!CompilerInvocation::CreateFromArgs (*Invocation, Argv, Diags)) {
480+ // FIXME: Should we just go on like cc1_main does?
481+ return nullptr ;
482+ }
483+ return Invocation;
484+ }
485+
486+ bool clang::tooling::dependencies::initializeScanCompilerInstance (
487+ CompilerInstance &ScanInstance,
488+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
489+ DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
490+ llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS) {
389491 ScanInstance.setBuildingModule (false );
390492
391493 ScanInstance.createVirtualFileSystem (FS, DiagConsumer);
392494
393495 // Create the compiler's actual diagnostics engine.
394496 sanitizeDiagOpts (ScanInstance.getDiagnosticOpts ());
395- assert (!DiagConsumerFinished && " attempt to reuse finished consumer" );
396497 ScanInstance.createDiagnostics (DiagConsumer, /* ShouldOwnClient=*/ false );
397498 if (!ScanInstance.hasDiagnostics ())
398499 return false ;
@@ -434,14 +535,39 @@ bool DependencyScanningAction::runInvocation(
434535
435536 ScanInstance.createSourceManager (*FileMgr);
436537
538+ // Consider different header search and diagnostic options to create
539+ // different modules. This avoids the unsound aliasing of module PCMs.
540+ //
541+ // TODO: Implement diagnostic bucketing to reduce the impact of strict
542+ // context hashing.
543+ ScanInstance.getHeaderSearchOpts ().ModulesStrictContextHash = true ;
544+ ScanInstance.getHeaderSearchOpts ().ModulesSerializeOnlyPreprocessor = true ;
545+ ScanInstance.getHeaderSearchOpts ().ModulesSkipDiagnosticOptions = true ;
546+ ScanInstance.getHeaderSearchOpts ().ModulesSkipHeaderSearchPaths = true ;
547+ ScanInstance.getHeaderSearchOpts ().ModulesSkipPragmaDiagnosticMappings = true ;
548+ ScanInstance.getHeaderSearchOpts ().ModulesForceValidateUserHeaders = false ;
549+
550+ // Avoid some checks and module map parsing when loading PCM files.
551+ ScanInstance.getPreprocessorOpts ().ModulesCheckRelocated = false ;
552+
553+ return true ;
554+ }
555+
556+ llvm::SmallVector<StringRef> clang::tooling::dependencies::computeStableDirs (
557+ CompilerInstance &ScanInstance) {
437558 // Create a collection of stable directories derived from the ScanInstance
438559 // for determining whether module dependencies would fully resolve from
439560 // those directories.
440561 llvm::SmallVector<StringRef> StableDirs;
441562 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts ().Sysroot ;
442563 if (!Sysroot.empty () && (llvm::sys::path::root_directory (Sysroot) != Sysroot))
443564 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts ().ResourceDir };
565+ return StableDirs;
566+ }
444567
568+ std::optional<PrebuiltModulesAttrsMap>
569+ clang::tooling::dependencies::computePrebuiltModulesASTMap (
570+ CompilerInstance &ScanInstance, llvm::SmallVector<StringRef> &StableDirs) {
445571 // Store a mapping of prebuilt module files and their properties like header
446572 // search options. This will prevent the implicit build to create duplicate
447573 // modules and will force reuse of the existing prebuilt module files
@@ -453,8 +579,18 @@ bool DependencyScanningAction::runInvocation(
453579 ScanInstance.getPreprocessorOpts ().ImplicitPCHInclude , ScanInstance,
454580 ScanInstance.getHeaderSearchOpts ().PrebuiltModuleFiles ,
455581 PrebuiltModulesASTMap, ScanInstance.getDiagnostics (), StableDirs))
456- return false ;
582+ return {} ;
457583
584+ return PrebuiltModulesASTMap;
585+ }
586+
587+ void clang::tooling::dependencies::initializeModuleDepCollector (
588+ CompilerInstance &ScanInstance, std::shared_ptr<ModuleDepCollector> &MDC,
589+ StringRef WorkingDirectory, DependencyConsumer &Consumer,
590+ DependencyScanningService &Service, CompilerInvocation &Inv,
591+ DependencyActionController &Controller,
592+ PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
593+ llvm::SmallVector<StringRef> &StableDirs) {
458594 // Create the dependency collector that will collect the produced
459595 // dependencies.
460596 //
@@ -463,6 +599,11 @@ bool DependencyScanningAction::runInvocation(
463599 // which ensures that the compiler won't create new dependency collectors,
464600 // and thus won't write out the extra '.d' files to disk.
465601 auto Opts = std::make_unique<DependencyOutputOptions>();
602+
603+ // We rely on the behaviour that that ScanInstance's Invocation instance's
604+ // dependency output opts are cleared here.
605+ // TODO: we will need to preserve and recover the original dependency output
606+ // opts if we want to reuse ScanInstance.
466607 std::swap (*Opts, ScanInstance.getInvocation ().getDependencyOutputOpts ());
467608 // We need at least one -MT equivalent for the generator of make dependency
468609 // files to work.
@@ -480,26 +621,58 @@ bool DependencyScanningAction::runInvocation(
480621 case ScanningOutputFormat::P1689:
481622 case ScanningOutputFormat::Full:
482623 MDC = std::make_shared<ModuleDepCollector>(
483- Service, std::move (Opts), ScanInstance, Consumer, Controller,
484- OriginalInvocation, std::move (PrebuiltModulesASTMap), StableDirs);
624+ Service, std::move (Opts), ScanInstance, Consumer, Controller, Inv,
625+ std::move (PrebuiltModulesASTMap), StableDirs);
485626 ScanInstance.addDependencyCollector (MDC);
486627 break ;
487628 }
629+ }
488630
489- // Consider different header search and diagnostic options to create
490- // different modules. This avoids the unsound aliasing of module PCMs.
491- //
492- // TODO: Implement diagnostic bucketing to reduce the impact of strict
493- // context hashing.
494- ScanInstance.getHeaderSearchOpts ().ModulesStrictContextHash = true ;
495- ScanInstance.getHeaderSearchOpts ().ModulesSerializeOnlyPreprocessor = true ;
496- ScanInstance.getHeaderSearchOpts ().ModulesSkipDiagnosticOptions = true ;
497- ScanInstance.getHeaderSearchOpts ().ModulesSkipHeaderSearchPaths = true ;
498- ScanInstance.getHeaderSearchOpts ().ModulesSkipPragmaDiagnosticMappings = true ;
499- ScanInstance.getHeaderSearchOpts ().ModulesForceValidateUserHeaders = false ;
631+ bool DependencyScanningAction::runInvocation (
632+ std::unique_ptr<CompilerInvocation> Invocation,
633+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
634+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
635+ DiagnosticConsumer *DiagConsumer) {
636+ // Making sure that we canonicalize the defines before we create the deep
637+ // copy to avoid unnecessary variants in the scanner and in the resulting
638+ // explicit command lines.
639+ if (any (Service.getOptimizeArgs () & ScanningOptimizations::Macros))
640+ canonicalizeDefines (Invocation->getPreprocessorOpts ());
500641
501- // Avoid some checks and module map parsing when loading PCM files.
502- ScanInstance.getPreprocessorOpts ().ModulesCheckRelocated = false ;
642+ // Make a deep copy of the original Clang invocation.
643+ CompilerInvocation OriginalInvocation (*Invocation);
644+
645+ if (Scanned) {
646+ // Scanning runs once for the first -cc1 invocation in a chain of driver
647+ // jobs. For any dependent jobs, reuse the scanning result and just
648+ // update the LastCC1Arguments to correspond to the new invocation.
649+ // FIXME: to support multi-arch builds, each arch requires a separate scan
650+ setLastCC1Arguments (std::move (OriginalInvocation));
651+ return true ;
652+ }
653+
654+ Scanned = true ;
655+
656+ // Create a compiler instance to handle the actual work.
657+ auto ModCache = makeInProcessModuleCache (Service.getModuleCacheEntries ());
658+ ScanInstanceStorage.emplace (std::move (Invocation), std::move (PCHContainerOps),
659+ ModCache.get ());
660+ CompilerInstance &ScanInstance = *ScanInstanceStorage;
661+
662+ assert (!DiagConsumerFinished && " attempt to reuse finished consumer" );
663+ if (!initializeScanCompilerInstance (ScanInstance, FS, DiagConsumer, Service,
664+ DepFS))
665+ return false ;
666+
667+ llvm::SmallVector<StringRef> StableDirs = computeStableDirs (ScanInstance);
668+ auto MaybePrebuiltModulesASTMap =
669+ computePrebuiltModulesASTMap (ScanInstance, StableDirs);
670+ if (!MaybePrebuiltModulesASTMap)
671+ return false ;
672+
673+ initializeModuleDepCollector (ScanInstance, MDC, WorkingDirectory, Consumer,
674+ Service, OriginalInvocation, Controller,
675+ *MaybePrebuiltModulesASTMap, StableDirs);
503676
504677 std::unique_ptr<FrontendAction> Action;
505678
0 commit comments