1 //===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===//
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
7 //===----------------------------------------------------------------------===//
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/Driver/Compilation.h"
14 #include "clang/Driver/Driver.h"
15 #include "clang/Driver/Job.h"
16 #include "clang/Driver/Tool.h"
17 #include "clang/Frontend/CompilerInstance.h"
18 #include "clang/Frontend/CompilerInvocation.h"
19 #include "clang/Frontend/FrontendActions.h"
20 #include "clang/Frontend/TextDiagnosticPrinter.h"
21 #include "clang/Frontend/Utils.h"
22 #include "clang/Lex/PreprocessorOptions.h"
23 #include "clang/Serialization/ObjectFilePCHContainerReader.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"
33 using namespace clang
;
34 using namespace tooling
;
35 using namespace dependencies
;
39 /// Forwards the gatherered dependencies to the consumer.
40 class DependencyConsumerForwarder
: public DependencyFileGenerator
{
42 DependencyConsumerForwarder(std::unique_ptr
<DependencyOutputOptions
> Opts
,
43 StringRef WorkingDirectory
, DependencyConsumer
&C
)
44 : DependencyFileGenerator(*Opts
), WorkingDirectory(WorkingDirectory
),
45 Opts(std::move(Opts
)), C(C
) {}
47 void finishedMainFile(DiagnosticsEngine
&Diags
) override
{
48 C
.handleDependencyOutputOpts(*Opts
);
49 llvm::SmallString
<256> CanonPath
;
50 for (const auto &File
: getDependencies()) {
52 llvm::sys::path::remove_dots(CanonPath
, /*remove_dot_dot=*/true);
53 llvm::sys::fs::make_absolute(WorkingDirectory
, CanonPath
);
54 C
.handleFileDependency(CanonPath
);
59 StringRef WorkingDirectory
;
60 std::unique_ptr
<DependencyOutputOptions
> Opts
;
61 DependencyConsumer
&C
;
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
) {
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
;
76 std::string Files
= llvm::join(VFSOverlays
, "\n");
77 Diags
->Report(diag::note_pch_vfsoverlay_files
) << Type
<< Files
;
80 VFSNote(0, HSOpts
.VFSOverlayFiles
);
81 VFSNote(1, ExistingHSOpts
.VFSOverlayFiles
);
88 using PrebuiltModuleFilesT
= decltype(HeaderSearchOptions::PrebuiltModuleFiles
);
90 /// A listener that collects the imported modules and optionally the input
92 class PrebuiltModuleListener
: public ASTReaderListener
{
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
) {}
104 bool needsImportVisitation() const override
{ return true; }
106 void visitImport(StringRef ModuleName
, StringRef Filename
) override
{
107 if (PrebuiltModuleFiles
.insert({ModuleName
.str(), Filename
.str()}).second
)
108 NewModuleFiles
.push_back(Filename
.str());
111 void visitModuleFile(StringRef Filename
,
112 serialization::ModuleKind Kind
) override
{
113 CurrentFile
= Filename
;
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
);
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
;
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(),
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
))
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))
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
);
176 /// Deduce the dependency target based on the output file and input files.
178 deduceDepTarget(const std::string
&OutputFile
,
179 const SmallVectorImpl
<FrontendInputFile
> &InputFiles
) {
180 if (OutputFile
!= "-")
183 if (InputFiles
.empty() || !InputFiles
.front().isFile())
184 return "clang-scan-deps\\ dependency";
186 return makeObjFileName(InputFiles
.front().getFile());
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)
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.
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.
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");
224 auto FinishName
= [&]() -> std::optional
<StringRef
> {
225 StringRef SimpleName
= Name
.slice(0, I
);
226 if (SimpleName
.empty())
231 for (; I
!= Name
.size(); ++I
) {
233 case '(': // Start of macro parameter list
234 case ' ': // End of macro name
240 if (llvm::isAlnum(Name
[I
]))
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.
258 SimpleNames
.emplace_back(*SName
, Index
);
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());
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
]));
277 std::swap(PPOpts
.Macros
, NewMacros
);
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
{
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
) {}
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());
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
));
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
));
323 // Create the compiler's actual diagnostics engine.
324 sanitizeDiagOpts(ScanInstance
.getDiagnosticOpts());
325 ScanInstance
.createDiagnostics(DriverFileMgr
->getVirtualFileSystem(),
326 DiagConsumer
, /*ShouldOwnClient=*/false);
327 if (!ScanInstance
.hasDiagnostics())
330 // Some DiagnosticConsumers require that finish() is called.
331 auto DiagConsumerFinisher
=
332 llvm::make_scope_exit([DiagConsumer
]() { DiagConsumer
->finish(); });
334 ScanInstance
.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath
=
337 ScanInstance
.getFrontendOpts().GenerateGlobalModuleIndex
= false;
338 ScanInstance
.getFrontendOpts().UseGlobalModuleIndex
= false;
339 // This will prevent us compiling individual modules asynchronously since
340 // FileManager is not thread-safe, but it does improve performance for now.
341 ScanInstance
.getFrontendOpts().ModulesShareFileManager
= true;
342 ScanInstance
.getHeaderSearchOpts().ModuleFormat
= "raw";
343 ScanInstance
.getHeaderSearchOpts().ModulesIncludeVFSUsage
=
344 any(OptimizeArgs
& ScanningOptimizations::VFS
);
346 // Support for virtual file system overlays.
347 auto FS
= createVFSFromCompilerInvocation(
348 ScanInstance
.getInvocation(), ScanInstance
.getDiagnostics(),
349 DriverFileMgr
->getVirtualFileSystemPtr());
351 // Use the dependency scanning optimized file system if requested to do so.
353 StringRef ModulesCachePath
=
354 ScanInstance
.getHeaderSearchOpts().ModuleCachePath
;
356 DepFS
->resetBypassedPathPrefix();
357 if (!ModulesCachePath
.empty())
358 DepFS
->setBypassedPathPrefix(ModulesCachePath
);
360 ScanInstance
.getPreprocessorOpts().DependencyDirectivesForFile
=
361 [LocalDepFS
= DepFS
](FileEntryRef File
)
362 -> std::optional
<ArrayRef
<dependency_directives_scan::Directive
>> {
363 if (llvm::ErrorOr
<EntryRef
> Entry
=
364 LocalDepFS
->getOrCreateFileSystemEntry(File
.getName()))
365 if (LocalDepFS
->ensureDirectiveTokensArePopulated(*Entry
))
366 return Entry
->getDirectiveTokens();
371 // Create a new FileManager to match the invocation's FileSystemOptions.
372 auto *FileMgr
= ScanInstance
.createFileManager(FS
);
373 ScanInstance
.createSourceManager(*FileMgr
);
375 // Store the list of prebuilt module files into header search options. This
376 // will prevent the implicit build to create duplicate modules and will
377 // force reuse of the existing prebuilt module files instead.
378 PrebuiltModuleVFSMapT PrebuiltModuleVFSMap
;
379 if (!ScanInstance
.getPreprocessorOpts().ImplicitPCHInclude
.empty())
380 if (visitPrebuiltModule(
381 ScanInstance
.getPreprocessorOpts().ImplicitPCHInclude
,
383 ScanInstance
.getHeaderSearchOpts().PrebuiltModuleFiles
,
384 PrebuiltModuleVFSMap
, ScanInstance
.getDiagnostics()))
387 // Create the dependency collector that will collect the produced
390 // This also moves the existing dependency output options from the
391 // invocation to the collector. The options in the invocation are reset,
392 // which ensures that the compiler won't create new dependency collectors,
393 // and thus won't write out the extra '.d' files to disk.
394 auto Opts
= std::make_unique
<DependencyOutputOptions
>();
395 std::swap(*Opts
, ScanInstance
.getInvocation().getDependencyOutputOpts());
396 // We need at least one -MT equivalent for the generator of make dependency
398 if (Opts
->Targets
.empty())
400 deduceDepTarget(ScanInstance
.getFrontendOpts().OutputFile
,
401 ScanInstance
.getFrontendOpts().Inputs
)};
402 Opts
->IncludeSystemHeaders
= true;
405 case ScanningOutputFormat::Make
:
406 ScanInstance
.addDependencyCollector(
407 std::make_shared
<DependencyConsumerForwarder
>(
408 std::move(Opts
), WorkingDirectory
, Consumer
));
410 case ScanningOutputFormat::P1689
:
411 case ScanningOutputFormat::Full
:
412 MDC
= std::make_shared
<ModuleDepCollector
>(
413 std::move(Opts
), ScanInstance
, Consumer
, Controller
,
414 OriginalInvocation
, std::move(PrebuiltModuleVFSMap
), OptimizeArgs
,
415 EagerLoadModules
, Format
== ScanningOutputFormat::P1689
);
416 ScanInstance
.addDependencyCollector(MDC
);
420 // Consider different header search and diagnostic options to create
421 // different modules. This avoids the unsound aliasing of module PCMs.
423 // TODO: Implement diagnostic bucketing to reduce the impact of strict
425 ScanInstance
.getHeaderSearchOpts().ModulesStrictContextHash
= true;
426 ScanInstance
.getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor
= true;
427 ScanInstance
.getHeaderSearchOpts().ModulesSkipDiagnosticOptions
= true;
428 ScanInstance
.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths
= true;
429 ScanInstance
.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings
=
432 // Avoid some checks and module map parsing when loading PCM files.
433 ScanInstance
.getPreprocessorOpts().ModulesCheckRelocated
= false;
435 std::unique_ptr
<FrontendAction
> Action
;
437 if (Format
== ScanningOutputFormat::P1689
)
438 Action
= std::make_unique
<PreprocessOnlyAction
>();
440 Action
= std::make_unique
<GetDependenciesByModuleNameAction
>(*ModuleName
);
442 Action
= std::make_unique
<ReadPCHAndPreprocessAction
>();
444 if (ScanInstance
.getDiagnostics().hasErrorOccurred())
447 // Each action is responsible for calling finish.
448 DiagConsumerFinisher
.release();
449 const bool Result
= ScanInstance
.ExecuteAction(*Action
);
452 setLastCC1Arguments(std::move(OriginalInvocation
));
454 // Propagate the statistics to the parent FileManager.
455 DriverFileMgr
->AddStats(ScanInstance
.getFileManager());
460 bool hasScanned() const { return Scanned
; }
462 /// Take the cc1 arguments corresponding to the most recent invocation used
463 /// with this action. Any modifications implied by the discovered dependencies
464 /// will have already been applied.
465 std::vector
<std::string
> takeLastCC1Arguments() {
466 std::vector
<std::string
> Result
;
467 std::swap(Result
, LastCC1Arguments
); // Reset LastCC1Arguments to empty.
472 void setLastCC1Arguments(CompilerInvocation
&&CI
) {
474 MDC
->applyDiscoveredDependencies(CI
);
475 LastCC1Arguments
= CI
.getCC1CommandLine();
479 StringRef WorkingDirectory
;
480 DependencyConsumer
&Consumer
;
481 DependencyActionController
&Controller
;
482 llvm::IntrusiveRefCntPtr
<DependencyScanningWorkerFilesystem
> DepFS
;
483 ScanningOutputFormat Format
;
484 ScanningOptimizations OptimizeArgs
;
485 bool EagerLoadModules
;
487 std::optional
<StringRef
> ModuleName
;
488 std::optional
<CompilerInstance
> ScanInstanceStorage
;
489 std::shared_ptr
<ModuleDepCollector
> MDC
;
490 std::vector
<std::string
> LastCC1Arguments
;
491 bool Scanned
= false;
494 } // end anonymous namespace
496 DependencyScanningWorker::DependencyScanningWorker(
497 DependencyScanningService
&Service
,
498 llvm::IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> FS
)
499 : Format(Service
.getFormat()), OptimizeArgs(Service
.getOptimizeArgs()),
500 EagerLoadModules(Service
.shouldEagerLoadModules()) {
501 PCHContainerOps
= std::make_shared
<PCHContainerOperations
>();
502 // We need to read object files from PCH built outside the scanner.
503 PCHContainerOps
->registerReader(
504 std::make_unique
<ObjectFilePCHContainerReader
>());
505 // The scanner itself writes only raw ast files.
506 PCHContainerOps
->registerWriter(std::make_unique
<RawPCHContainerWriter
>());
508 if (Service
.shouldTraceVFS())
509 FS
= llvm::makeIntrusiveRefCnt
<llvm::vfs::TracingFileSystem
>(std::move(FS
));
511 switch (Service
.getMode()) {
512 case ScanningMode::DependencyDirectivesScan
:
514 new DependencyScanningWorkerFilesystem(Service
.getSharedCache(), FS
);
517 case ScanningMode::CanonicalPreprocessing
:
524 llvm::Error
DependencyScanningWorker::computeDependencies(
525 StringRef WorkingDirectory
, const std::vector
<std::string
> &CommandLine
,
526 DependencyConsumer
&Consumer
, DependencyActionController
&Controller
,
527 std::optional
<StringRef
> ModuleName
) {
528 std::vector
<const char *> CLI
;
529 for (const std::string
&Arg
: CommandLine
)
530 CLI
.push_back(Arg
.c_str());
531 auto DiagOpts
= CreateAndPopulateDiagOpts(CLI
);
532 sanitizeDiagOpts(*DiagOpts
);
534 // Capture the emitted diagnostics and report them to the client
535 // in the case of a failure.
536 std::string DiagnosticOutput
;
537 llvm::raw_string_ostream
DiagnosticsOS(DiagnosticOutput
);
538 TextDiagnosticPrinter
DiagPrinter(DiagnosticsOS
, DiagOpts
.release());
540 if (computeDependencies(WorkingDirectory
, CommandLine
, Consumer
, Controller
,
541 DiagPrinter
, ModuleName
))
542 return llvm::Error::success();
543 return llvm::make_error
<llvm::StringError
>(DiagnosticsOS
.str(),
544 llvm::inconvertibleErrorCode());
547 static bool forEachDriverJob(
548 ArrayRef
<std::string
> ArgStrs
, DiagnosticsEngine
&Diags
, FileManager
&FM
,
549 llvm::function_ref
<bool(const driver::Command
&Cmd
)> Callback
) {
550 SmallVector
<const char *, 256> Argv
;
551 Argv
.reserve(ArgStrs
.size());
552 for (const std::string
&Arg
: ArgStrs
)
553 Argv
.push_back(Arg
.c_str());
555 llvm::vfs::FileSystem
*FS
= &FM
.getVirtualFileSystem();
557 std::unique_ptr
<driver::Driver
> Driver
= std::make_unique
<driver::Driver
>(
558 Argv
[0], llvm::sys::getDefaultTargetTriple(), Diags
,
559 "clang LLVM compiler", FS
);
560 Driver
->setTitle("clang_based_tool");
562 llvm::BumpPtrAllocator Alloc
;
563 bool CLMode
= driver::IsClangCL(
564 driver::getDriverMode(Argv
[0], ArrayRef(Argv
).slice(1)));
566 if (llvm::Error E
= driver::expandResponseFiles(Argv
, CLMode
, Alloc
, FS
)) {
567 Diags
.Report(diag::err_drv_expand_response_file
)
568 << llvm::toString(std::move(E
));
572 const std::unique_ptr
<driver::Compilation
> Compilation(
573 Driver
->BuildCompilation(llvm::ArrayRef(Argv
)));
577 if (Compilation
->containsError())
580 for (const driver::Command
&Job
: Compilation
->getJobs()) {
587 static bool createAndRunToolInvocation(
588 std::vector
<std::string
> CommandLine
, DependencyScanningAction
&Action
,
590 std::shared_ptr
<clang::PCHContainerOperations
> &PCHContainerOps
,
591 DiagnosticsEngine
&Diags
, DependencyConsumer
&Consumer
) {
593 // Save executable path before providing CommandLine to ToolInvocation
594 std::string Executable
= CommandLine
[0];
595 ToolInvocation
Invocation(std::move(CommandLine
), &Action
, &FM
,
597 Invocation
.setDiagnosticConsumer(Diags
.getClient());
598 Invocation
.setDiagnosticOptions(&Diags
.getDiagnosticOptions());
599 if (!Invocation
.run())
602 std::vector
<std::string
> Args
= Action
.takeLastCC1Arguments();
603 Consumer
.handleBuildCommand({std::move(Executable
), std::move(Args
)});
607 bool DependencyScanningWorker::computeDependencies(
608 StringRef WorkingDirectory
, const std::vector
<std::string
> &CommandLine
,
609 DependencyConsumer
&Consumer
, DependencyActionController
&Controller
,
610 DiagnosticConsumer
&DC
, std::optional
<StringRef
> ModuleName
) {
611 // Reset what might have been modified in the previous worker invocation.
612 BaseFS
->setCurrentWorkingDirectory(WorkingDirectory
);
614 std::optional
<std::vector
<std::string
>> ModifiedCommandLine
;
615 llvm::IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> ModifiedFS
;
617 // If we're scanning based on a module name alone, we don't expect the client
618 // to provide us with an input file. However, the driver really wants to have
619 // one. Let's just make it up to make the driver happy.
622 llvm::makeIntrusiveRefCnt
<llvm::vfs::OverlayFileSystem
>(BaseFS
);
624 llvm::makeIntrusiveRefCnt
<llvm::vfs::InMemoryFileSystem
>();
625 InMemoryFS
->setCurrentWorkingDirectory(WorkingDirectory
);
626 OverlayFS
->pushOverlay(InMemoryFS
);
627 ModifiedFS
= OverlayFS
;
629 SmallString
<128> FakeInputPath
;
630 // TODO: We should retry the creation if the path already exists.
631 llvm::sys::fs::createUniquePath(*ModuleName
+ "-%%%%%%%%.input",
633 /*MakeAbsolute=*/false);
634 InMemoryFS
->addFile(FakeInputPath
, 0, llvm::MemoryBuffer::getMemBuffer(""));
636 ModifiedCommandLine
= CommandLine
;
637 ModifiedCommandLine
->emplace_back(FakeInputPath
);
640 const std::vector
<std::string
> &FinalCommandLine
=
641 ModifiedCommandLine
? *ModifiedCommandLine
: CommandLine
;
642 auto &FinalFS
= ModifiedFS
? ModifiedFS
: BaseFS
;
645 llvm::makeIntrusiveRefCnt
<FileManager
>(FileSystemOptions
{}, FinalFS
);
647 std::vector
<const char *> FinalCCommandLine(FinalCommandLine
.size(), nullptr);
648 llvm::transform(FinalCommandLine
, FinalCCommandLine
.begin(),
649 [](const std::string
&Str
) { return Str
.c_str(); });
651 auto DiagOpts
= CreateAndPopulateDiagOpts(FinalCCommandLine
);
652 sanitizeDiagOpts(*DiagOpts
);
653 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags
=
654 CompilerInstance::createDiagnostics(*FinalFS
, DiagOpts
.release(), &DC
,
655 /*ShouldOwnClient=*/false);
657 // Although `Diagnostics` are used only for command-line parsing, the
658 // custom `DiagConsumer` might expect a `SourceManager` to be present.
659 SourceManager
SrcMgr(*Diags
, *FileMgr
);
660 Diags
->setSourceManager(&SrcMgr
);
661 // DisableFree is modified by Tooling for running
662 // in-process; preserve the original value, which is
663 // always true for a driver invocation.
664 bool DisableFree
= true;
665 DependencyScanningAction
Action(WorkingDirectory
, Consumer
, Controller
, DepFS
,
666 Format
, OptimizeArgs
, EagerLoadModules
,
667 DisableFree
, ModuleName
);
669 bool Success
= false;
670 if (FinalCommandLine
[1] == "-cc1") {
671 Success
= createAndRunToolInvocation(FinalCommandLine
, Action
, *FileMgr
,
672 PCHContainerOps
, *Diags
, Consumer
);
674 Success
= forEachDriverJob(
675 FinalCommandLine
, *Diags
, *FileMgr
, [&](const driver::Command
&Cmd
) {
676 if (StringRef(Cmd
.getCreator().getName()) != "clang") {
677 // Non-clang command. Just pass through to the dependency
679 Consumer
.handleBuildCommand(
680 {Cmd
.getExecutable(),
681 {Cmd
.getArguments().begin(), Cmd
.getArguments().end()}});
685 // Insert -cc1 comand line options into Argv
686 std::vector
<std::string
> Argv
;
687 Argv
.push_back(Cmd
.getExecutable());
688 Argv
.insert(Argv
.end(), Cmd
.getArguments().begin(),
689 Cmd
.getArguments().end());
691 // Create an invocation that uses the underlying file
692 // system to ensure that any file system requests that
693 // are made by the driver do not go through the
694 // dependency scanning filesystem.
695 return createAndRunToolInvocation(std::move(Argv
), Action
, *FileMgr
,
696 PCHContainerOps
, *Diags
, Consumer
);
700 if (Success
&& !Action
.hasScanned())
701 Diags
->Report(diag::err_fe_expected_compiler_job
)
702 << llvm::join(FinalCommandLine
, " ");
703 return Success
&& Action
.hasScanned();
706 DependencyActionController::~DependencyActionController() {}