1 //===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 10 #include "clang/Basic/DiagnosticDriver.h" 11 #include "clang/Basic/DiagnosticFrontend.h" 12 #include "clang/Basic/DiagnosticSerialization.h" 13 #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" 14 #include "clang/Driver/Compilation.h" 15 #include "clang/Driver/Driver.h" 16 #include "clang/Driver/Job.h" 17 #include "clang/Driver/Tool.h" 18 #include "clang/Frontend/CompilerInstance.h" 19 #include "clang/Frontend/CompilerInvocation.h" 20 #include "clang/Frontend/FrontendActions.h" 21 #include "clang/Frontend/TextDiagnosticPrinter.h" 22 #include "clang/Frontend/Utils.h" 23 #include "clang/Lex/PreprocessorOptions.h" 24 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" 25 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 26 #include "clang/Tooling/Tooling.h" 27 #include "llvm/ADT/ScopeExit.h" 28 #include "llvm/Support/Allocator.h" 29 #include "llvm/Support/Error.h" 30 #include "llvm/TargetParser/Host.h" 31 #include <optional> 32 33 using namespace clang; 34 using namespace tooling; 35 using namespace dependencies; 36 37 namespace { 38 39 /// Forwards the gatherered dependencies to the consumer. 40 class DependencyConsumerForwarder : public DependencyFileGenerator { 41 public: 42 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts, 43 StringRef WorkingDirectory, DependencyConsumer &C) 44 : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory), 45 Opts(std::move(Opts)), C(C) {} 46 47 void finishedMainFile(DiagnosticsEngine &Diags) override { 48 C.handleDependencyOutputOpts(*Opts); 49 llvm::SmallString<256> CanonPath; 50 for (const auto &File : getDependencies()) { 51 CanonPath = File; 52 llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true); 53 llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath); 54 C.handleFileDependency(CanonPath); 55 } 56 } 57 58 private: 59 StringRef WorkingDirectory; 60 std::unique_ptr<DependencyOutputOptions> Opts; 61 DependencyConsumer &C; 62 }; 63 64 static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts, 65 const HeaderSearchOptions &ExistingHSOpts, 66 DiagnosticsEngine *Diags, 67 const LangOptions &LangOpts) { 68 if (LangOpts.Modules) { 69 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) { 70 if (Diags) { 71 Diags->Report(diag::warn_pch_vfsoverlay_mismatch); 72 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) { 73 if (VFSOverlays.empty()) { 74 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type; 75 } else { 76 std::string Files = llvm::join(VFSOverlays, "\n"); 77 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files; 78 } 79 }; 80 VFSNote(0, HSOpts.VFSOverlayFiles); 81 VFSNote(1, ExistingHSOpts.VFSOverlayFiles); 82 } 83 } 84 } 85 return false; 86 } 87 88 using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles); 89 90 /// A listener that collects the imported modules and optionally the input 91 /// files. 92 class PrebuiltModuleListener : public ASTReaderListener { 93 public: 94 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles, 95 llvm::SmallVector<std::string> &NewModuleFiles, 96 PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, 97 const HeaderSearchOptions &HSOpts, 98 const LangOptions &LangOpts, DiagnosticsEngine &Diags) 99 : PrebuiltModuleFiles(PrebuiltModuleFiles), 100 NewModuleFiles(NewModuleFiles), 101 PrebuiltModuleVFSMap(PrebuiltModuleVFSMap), ExistingHSOpts(HSOpts), 102 ExistingLangOpts(LangOpts), Diags(Diags) {} 103 104 bool needsImportVisitation() const override { return true; } 105 106 void visitImport(StringRef ModuleName, StringRef Filename) override { 107 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second) 108 NewModuleFiles.push_back(Filename.str()); 109 } 110 111 void visitModuleFile(StringRef Filename, 112 serialization::ModuleKind Kind) override { 113 CurrentFile = Filename; 114 } 115 116 bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts, 117 bool Complain) override { 118 std::vector<std::string> VFSOverlayFiles = HSOpts.VFSOverlayFiles; 119 PrebuiltModuleVFSMap.insert( 120 {CurrentFile, llvm::StringSet<>(VFSOverlayFiles)}); 121 return checkHeaderSearchPaths( 122 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts); 123 } 124 125 private: 126 PrebuiltModuleFilesT &PrebuiltModuleFiles; 127 llvm::SmallVector<std::string> &NewModuleFiles; 128 PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap; 129 const HeaderSearchOptions &ExistingHSOpts; 130 const LangOptions &ExistingLangOpts; 131 DiagnosticsEngine &Diags; 132 std::string CurrentFile; 133 }; 134 135 /// Visit the given prebuilt module and collect all of the modules it 136 /// transitively imports and contributing input files. 137 static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename, 138 CompilerInstance &CI, 139 PrebuiltModuleFilesT &ModuleFiles, 140 PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, 141 DiagnosticsEngine &Diags) { 142 // List of module files to be processed. 143 llvm::SmallVector<std::string> Worklist; 144 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModuleVFSMap, 145 CI.getHeaderSearchOpts(), CI.getLangOpts(), 146 Diags); 147 148 Listener.visitModuleFile(PrebuiltModuleFilename, 149 serialization::MK_ExplicitModule); 150 if (ASTReader::readASTFileControlBlock( 151 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(), 152 CI.getPCHContainerReader(), 153 /*FindModuleFileExtensions=*/false, Listener, 154 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate)) 155 return true; 156 157 while (!Worklist.empty()) { 158 Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule); 159 if (ASTReader::readASTFileControlBlock( 160 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(), 161 CI.getPCHContainerReader(), 162 /*FindModuleFileExtensions=*/false, Listener, 163 /*ValidateDiagnosticOptions=*/false)) 164 return true; 165 } 166 return false; 167 } 168 169 /// Transform arbitrary file name into an object-like file name. 170 static std::string makeObjFileName(StringRef FileName) { 171 SmallString<128> ObjFileName(FileName); 172 llvm::sys::path::replace_extension(ObjFileName, "o"); 173 return std::string(ObjFileName); 174 } 175 176 /// Deduce the dependency target based on the output file and input files. 177 static std::string 178 deduceDepTarget(const std::string &OutputFile, 179 const SmallVectorImpl<FrontendInputFile> &InputFiles) { 180 if (OutputFile != "-") 181 return OutputFile; 182 183 if (InputFiles.empty() || !InputFiles.front().isFile()) 184 return "clang-scan-deps\\ dependency"; 185 186 return makeObjFileName(InputFiles.front().getFile()); 187 } 188 189 /// Sanitize diagnostic options for dependency scan. 190 static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) { 191 // Don't print 'X warnings and Y errors generated'. 192 DiagOpts.ShowCarets = false; 193 // Don't write out diagnostic file. 194 DiagOpts.DiagnosticSerializationFile.clear(); 195 // Don't emit warnings except for scanning specific warnings. 196 // TODO: It would be useful to add a more principled way to ignore all 197 // warnings that come from source code. The issue is that we need to 198 // ignore warnings that could be surpressed by 199 // `#pragma clang diagnostic`, while still allowing some scanning 200 // warnings for things we're not ready to turn into errors yet. 201 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example. 202 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) { 203 return llvm::StringSwitch<bool>(Warning) 204 .Cases("pch-vfs-diff", "error=pch-vfs-diff", false) 205 .StartsWith("no-error=", false) 206 .Default(true); 207 }); 208 } 209 210 // Clang implements -D and -U by splatting text into a predefines buffer. This 211 // allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and 212 // define the same macro, or adding C++ style comments before the macro name. 213 // 214 // This function checks that the first non-space characters in the macro 215 // obviously form an identifier that can be uniqued on without lexing. Failing 216 // to do this could lead to changing the final definition of a macro. 217 // 218 // We could set up a preprocessor and actually lex the name, but that's very 219 // heavyweight for a situation that will almost never happen in practice. 220 static std::optional<StringRef> getSimpleMacroName(StringRef Macro) { 221 StringRef Name = Macro.split("=").first.ltrim(" \t"); 222 std::size_t I = 0; 223 224 auto FinishName = [&]() -> std::optional<StringRef> { 225 StringRef SimpleName = Name.slice(0, I); 226 if (SimpleName.empty()) 227 return std::nullopt; 228 return SimpleName; 229 }; 230 231 for (; I != Name.size(); ++I) { 232 switch (Name[I]) { 233 case '(': // Start of macro parameter list 234 case ' ': // End of macro name 235 case '\t': 236 return FinishName(); 237 case '_': 238 continue; 239 default: 240 if (llvm::isAlnum(Name[I])) 241 continue; 242 return std::nullopt; 243 } 244 } 245 return FinishName(); 246 } 247 248 static void canonicalizeDefines(PreprocessorOptions &PPOpts) { 249 using MacroOpt = std::pair<StringRef, std::size_t>; 250 std::vector<MacroOpt> SimpleNames; 251 SimpleNames.reserve(PPOpts.Macros.size()); 252 std::size_t Index = 0; 253 for (const auto &M : PPOpts.Macros) { 254 auto SName = getSimpleMacroName(M.first); 255 // Skip optimizing if we can't guarantee we can preserve relative order. 256 if (!SName) 257 return; 258 SimpleNames.emplace_back(*SName, Index); 259 ++Index; 260 } 261 262 llvm::stable_sort(SimpleNames, llvm::less_first()); 263 // Keep the last instance of each macro name by going in reverse 264 auto NewEnd = std::unique( 265 SimpleNames.rbegin(), SimpleNames.rend(), 266 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; }); 267 SimpleNames.erase(SimpleNames.begin(), NewEnd.base()); 268 269 // Apply permutation. 270 decltype(PPOpts.Macros) NewMacros; 271 NewMacros.reserve(SimpleNames.size()); 272 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) { 273 std::size_t OriginalIndex = SimpleNames[I].second; 274 // We still emit undefines here as they may be undefining a predefined macro 275 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex])); 276 } 277 std::swap(PPOpts.Macros, NewMacros); 278 } 279 280 /// A clang tool that runs the preprocessor in a mode that's optimized for 281 /// dependency scanning for the given compiler invocation. 282 class DependencyScanningAction : public tooling::ToolAction { 283 public: 284 DependencyScanningAction( 285 StringRef WorkingDirectory, DependencyConsumer &Consumer, 286 DependencyActionController &Controller, 287 llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, 288 ScanningOutputFormat Format, ScanningOptimizations OptimizeArgs, 289 bool EagerLoadModules, bool DisableFree, 290 std::optional<StringRef> ModuleName = std::nullopt) 291 : WorkingDirectory(WorkingDirectory), Consumer(Consumer), 292 Controller(Controller), DepFS(std::move(DepFS)), Format(Format), 293 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), 294 DisableFree(DisableFree), ModuleName(ModuleName) {} 295 296 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, 297 FileManager *DriverFileMgr, 298 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 299 DiagnosticConsumer *DiagConsumer) override { 300 // Make a deep copy of the original Clang invocation. 301 CompilerInvocation OriginalInvocation(*Invocation); 302 // Restore the value of DisableFree, which may be modified by Tooling. 303 OriginalInvocation.getFrontendOpts().DisableFree = DisableFree; 304 if (any(OptimizeArgs & ScanningOptimizations::Macros)) 305 canonicalizeDefines(OriginalInvocation.getPreprocessorOpts()); 306 307 if (Scanned) { 308 // Scanning runs once for the first -cc1 invocation in a chain of driver 309 // jobs. For any dependent jobs, reuse the scanning result and just 310 // update the LastCC1Arguments to correspond to the new invocation. 311 // FIXME: to support multi-arch builds, each arch requires a separate scan 312 setLastCC1Arguments(std::move(OriginalInvocation)); 313 return true; 314 } 315 316 Scanned = true; 317 318 // Create a compiler instance to handle the actual work. 319 ScanInstanceStorage.emplace(std::move(PCHContainerOps)); 320 CompilerInstance &ScanInstance = *ScanInstanceStorage; 321 ScanInstance.setInvocation(std::move(Invocation)); 322 323 // Create the compiler's actual diagnostics engine. 324 sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); 325 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); 326 if (!ScanInstance.hasDiagnostics()) 327 return false; 328 329 // Some DiagnosticConsumers require that finish() is called. 330 auto DiagConsumerFinisher = 331 llvm::make_scope_exit([DiagConsumer]() { DiagConsumer->finish(); }); 332 333 ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = 334 true; 335 336 ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false; 337 ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false; 338 ScanInstance.getFrontendOpts().ModulesShareFileManager = false; 339 ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw"; 340 ScanInstance.getHeaderSearchOpts().ModulesIncludeVFSUsage = 341 any(OptimizeArgs & ScanningOptimizations::VFS); 342 343 // Support for virtual file system overlays. 344 auto FS = createVFSFromCompilerInvocation( 345 ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), 346 DriverFileMgr->getVirtualFileSystemPtr()); 347 348 // Create a new FileManager to match the invocation's FileSystemOptions. 349 auto *FileMgr = ScanInstance.createFileManager(FS); 350 ScanInstance.createSourceManager(*FileMgr); 351 352 // Store the list of prebuilt module files into header search options. This 353 // will prevent the implicit build to create duplicate modules and will 354 // force reuse of the existing prebuilt module files instead. 355 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap; 356 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 357 if (visitPrebuiltModule( 358 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, 359 ScanInstance, 360 ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles, 361 PrebuiltModuleVFSMap, ScanInstance.getDiagnostics())) 362 return false; 363 364 // Use the dependency scanning optimized file system if requested to do so. 365 if (DepFS) 366 ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile = 367 [LocalDepFS = DepFS](FileEntryRef File) 368 -> std::optional<ArrayRef<dependency_directives_scan::Directive>> { 369 if (llvm::ErrorOr<EntryRef> Entry = 370 LocalDepFS->getOrCreateFileSystemEntry(File.getName())) 371 if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry)) 372 return Entry->getDirectiveTokens(); 373 return std::nullopt; 374 }; 375 376 // Create the dependency collector that will collect the produced 377 // dependencies. 378 // 379 // This also moves the existing dependency output options from the 380 // invocation to the collector. The options in the invocation are reset, 381 // which ensures that the compiler won't create new dependency collectors, 382 // and thus won't write out the extra '.d' files to disk. 383 auto Opts = std::make_unique<DependencyOutputOptions>(); 384 std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts()); 385 // We need at least one -MT equivalent for the generator of make dependency 386 // files to work. 387 if (Opts->Targets.empty()) 388 Opts->Targets = { 389 deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile, 390 ScanInstance.getFrontendOpts().Inputs)}; 391 Opts->IncludeSystemHeaders = true; 392 393 switch (Format) { 394 case ScanningOutputFormat::Make: 395 ScanInstance.addDependencyCollector( 396 std::make_shared<DependencyConsumerForwarder>( 397 std::move(Opts), WorkingDirectory, Consumer)); 398 break; 399 case ScanningOutputFormat::P1689: 400 case ScanningOutputFormat::Full: 401 MDC = std::make_shared<ModuleDepCollector>( 402 std::move(Opts), ScanInstance, Consumer, Controller, 403 OriginalInvocation, std::move(PrebuiltModuleVFSMap), OptimizeArgs, 404 EagerLoadModules, Format == ScanningOutputFormat::P1689); 405 ScanInstance.addDependencyCollector(MDC); 406 break; 407 } 408 409 // Consider different header search and diagnostic options to create 410 // different modules. This avoids the unsound aliasing of module PCMs. 411 // 412 // TODO: Implement diagnostic bucketing to reduce the impact of strict 413 // context hashing. 414 ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true; 415 ScanInstance.getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true; 416 ScanInstance.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true; 417 ScanInstance.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = 418 true; 419 420 // Avoid some checks and module map parsing when loading PCM files. 421 ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false; 422 423 std::unique_ptr<FrontendAction> Action; 424 425 if (ModuleName) 426 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName); 427 else 428 Action = std::make_unique<ReadPCHAndPreprocessAction>(); 429 430 if (ScanInstance.getDiagnostics().hasErrorOccurred()) 431 return false; 432 433 // Each action is responsible for calling finish. 434 DiagConsumerFinisher.release(); 435 const bool Result = ScanInstance.ExecuteAction(*Action); 436 437 if (Result) 438 setLastCC1Arguments(std::move(OriginalInvocation)); 439 440 // Propagate the statistics to the parent FileManager. 441 DriverFileMgr->AddStats(ScanInstance.getFileManager()); 442 443 return Result; 444 } 445 446 bool hasScanned() const { return Scanned; } 447 448 /// Take the cc1 arguments corresponding to the most recent invocation used 449 /// with this action. Any modifications implied by the discovered dependencies 450 /// will have already been applied. 451 std::vector<std::string> takeLastCC1Arguments() { 452 std::vector<std::string> Result; 453 std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty. 454 return Result; 455 } 456 457 private: 458 void setLastCC1Arguments(CompilerInvocation &&CI) { 459 if (MDC) 460 MDC->applyDiscoveredDependencies(CI); 461 LastCC1Arguments = CI.getCC1CommandLine(); 462 } 463 464 private: 465 StringRef WorkingDirectory; 466 DependencyConsumer &Consumer; 467 DependencyActionController &Controller; 468 llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; 469 ScanningOutputFormat Format; 470 ScanningOptimizations OptimizeArgs; 471 bool EagerLoadModules; 472 bool DisableFree; 473 std::optional<StringRef> ModuleName; 474 std::optional<CompilerInstance> ScanInstanceStorage; 475 std::shared_ptr<ModuleDepCollector> MDC; 476 std::vector<std::string> LastCC1Arguments; 477 bool Scanned = false; 478 }; 479 480 } // end anonymous namespace 481 482 DependencyScanningWorker::DependencyScanningWorker( 483 DependencyScanningService &Service, 484 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 485 : Format(Service.getFormat()), OptimizeArgs(Service.getOptimizeArgs()), 486 EagerLoadModules(Service.shouldEagerLoadModules()) { 487 PCHContainerOps = std::make_shared<PCHContainerOperations>(); 488 // We need to read object files from PCH built outside the scanner. 489 PCHContainerOps->registerReader( 490 std::make_unique<ObjectFilePCHContainerReader>()); 491 // The scanner itself writes only raw ast files. 492 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>()); 493 494 switch (Service.getMode()) { 495 case ScanningMode::DependencyDirectivesScan: 496 DepFS = 497 new DependencyScanningWorkerFilesystem(Service.getSharedCache(), FS); 498 BaseFS = DepFS; 499 break; 500 case ScanningMode::CanonicalPreprocessing: 501 DepFS = nullptr; 502 BaseFS = FS; 503 break; 504 } 505 } 506 507 llvm::Error DependencyScanningWorker::computeDependencies( 508 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, 509 DependencyConsumer &Consumer, DependencyActionController &Controller, 510 std::optional<StringRef> ModuleName) { 511 std::vector<const char *> CLI; 512 for (const std::string &Arg : CommandLine) 513 CLI.push_back(Arg.c_str()); 514 auto DiagOpts = CreateAndPopulateDiagOpts(CLI); 515 sanitizeDiagOpts(*DiagOpts); 516 517 // Capture the emitted diagnostics and report them to the client 518 // in the case of a failure. 519 std::string DiagnosticOutput; 520 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); 521 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release()); 522 523 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller, 524 DiagPrinter, ModuleName)) 525 return llvm::Error::success(); 526 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(), 527 llvm::inconvertibleErrorCode()); 528 } 529 530 static bool forEachDriverJob( 531 ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags, FileManager &FM, 532 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) { 533 SmallVector<const char *, 256> Argv; 534 Argv.reserve(ArgStrs.size()); 535 for (const std::string &Arg : ArgStrs) 536 Argv.push_back(Arg.c_str()); 537 538 llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem(); 539 540 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>( 541 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags, 542 "clang LLVM compiler", FS); 543 Driver->setTitle("clang_based_tool"); 544 545 llvm::BumpPtrAllocator Alloc; 546 bool CLMode = driver::IsClangCL( 547 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1))); 548 549 if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) { 550 Diags.Report(diag::err_drv_expand_response_file) 551 << llvm::toString(std::move(E)); 552 return false; 553 } 554 555 const std::unique_ptr<driver::Compilation> Compilation( 556 Driver->BuildCompilation(llvm::ArrayRef(Argv))); 557 if (!Compilation) 558 return false; 559 560 if (Compilation->containsError()) 561 return false; 562 563 for (const driver::Command &Job : Compilation->getJobs()) { 564 if (!Callback(Job)) 565 return false; 566 } 567 return true; 568 } 569 570 static bool createAndRunToolInvocation( 571 std::vector<std::string> CommandLine, DependencyScanningAction &Action, 572 FileManager &FM, 573 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps, 574 DiagnosticsEngine &Diags, DependencyConsumer &Consumer) { 575 576 // Save executable path before providing CommandLine to ToolInvocation 577 std::string Executable = CommandLine[0]; 578 ToolInvocation Invocation(std::move(CommandLine), &Action, &FM, 579 PCHContainerOps); 580 Invocation.setDiagnosticConsumer(Diags.getClient()); 581 Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions()); 582 if (!Invocation.run()) 583 return false; 584 585 std::vector<std::string> Args = Action.takeLastCC1Arguments(); 586 Consumer.handleBuildCommand({std::move(Executable), std::move(Args)}); 587 return true; 588 } 589 590 bool DependencyScanningWorker::computeDependencies( 591 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine, 592 DependencyConsumer &Consumer, DependencyActionController &Controller, 593 DiagnosticConsumer &DC, std::optional<StringRef> ModuleName) { 594 // Reset what might have been modified in the previous worker invocation. 595 BaseFS->setCurrentWorkingDirectory(WorkingDirectory); 596 597 std::optional<std::vector<std::string>> ModifiedCommandLine; 598 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS; 599 600 // If we're scanning based on a module name alone, we don't expect the client 601 // to provide us with an input file. However, the driver really wants to have 602 // one. Let's just make it up to make the driver happy. 603 if (ModuleName) { 604 auto OverlayFS = 605 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS); 606 auto InMemoryFS = 607 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); 608 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); 609 OverlayFS->pushOverlay(InMemoryFS); 610 ModifiedFS = OverlayFS; 611 612 SmallString<128> FakeInputPath; 613 // TODO: We should retry the creation if the path already exists. 614 llvm::sys::fs::createUniquePath(*ModuleName + "-%%%%%%%%.input", 615 FakeInputPath, 616 /*MakeAbsolute=*/false); 617 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer("")); 618 619 ModifiedCommandLine = CommandLine; 620 ModifiedCommandLine->emplace_back(FakeInputPath); 621 } 622 623 const std::vector<std::string> &FinalCommandLine = 624 ModifiedCommandLine ? *ModifiedCommandLine : CommandLine; 625 auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS; 626 627 auto FileMgr = 628 llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS); 629 630 std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr); 631 llvm::transform(FinalCommandLine, FinalCCommandLine.begin(), 632 [](const std::string &Str) { return Str.c_str(); }); 633 634 auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine); 635 sanitizeDiagOpts(*DiagOpts); 636 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 637 CompilerInstance::createDiagnostics(DiagOpts.release(), &DC, 638 /*ShouldOwnClient=*/false); 639 640 // Although `Diagnostics` are used only for command-line parsing, the 641 // custom `DiagConsumer` might expect a `SourceManager` to be present. 642 SourceManager SrcMgr(*Diags, *FileMgr); 643 Diags->setSourceManager(&SrcMgr); 644 // DisableFree is modified by Tooling for running 645 // in-process; preserve the original value, which is 646 // always true for a driver invocation. 647 bool DisableFree = true; 648 DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS, 649 Format, OptimizeArgs, EagerLoadModules, 650 DisableFree, ModuleName); 651 652 bool Success = false; 653 if (FinalCommandLine[1] == "-cc1") { 654 Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr, 655 PCHContainerOps, *Diags, Consumer); 656 } else { 657 Success = forEachDriverJob( 658 FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) { 659 if (StringRef(Cmd.getCreator().getName()) != "clang") { 660 // Non-clang command. Just pass through to the dependency 661 // consumer. 662 Consumer.handleBuildCommand( 663 {Cmd.getExecutable(), 664 {Cmd.getArguments().begin(), Cmd.getArguments().end()}}); 665 return true; 666 } 667 668 // Insert -cc1 comand line options into Argv 669 std::vector<std::string> Argv; 670 Argv.push_back(Cmd.getExecutable()); 671 Argv.insert(Argv.end(), Cmd.getArguments().begin(), 672 Cmd.getArguments().end()); 673 674 // Create an invocation that uses the underlying file 675 // system to ensure that any file system requests that 676 // are made by the driver do not go through the 677 // dependency scanning filesystem. 678 return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr, 679 PCHContainerOps, *Diags, Consumer); 680 }); 681 } 682 683 if (Success && !Action.hasScanned()) 684 Diags->Report(diag::err_fe_expected_compiler_job) 685 << llvm::join(FinalCommandLine, " "); 686 return Success && Action.hasScanned(); 687 } 688 689 DependencyActionController::~DependencyActionController() {} 690