26#include "llvm/Support/Allocator.h"
27#include "llvm/Support/Error.h"
28#include "llvm/TargetParser/Host.h"
32using namespace tooling;
33using namespace dependencies;
40 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
43 Opts(
std::move(Opts)),
C(
C) {}
46 C.handleDependencyOutputOpts(*Opts);
50 llvm::sys::path::remove_dots(CanonPath,
true);
51 llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath);
52 C.handleFileDependency(CanonPath);
57 StringRef WorkingDirectory;
58 std::unique_ptr<DependencyOutputOptions> Opts;
68 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
70 : PrebuiltModuleFiles(PrebuiltModuleFiles),
71 NewModuleFiles(NewModuleFiles) {}
76 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
77 NewModuleFiles.push_back(
Filename.str());
81 PrebuiltModuleFilesT &PrebuiltModuleFiles;
87static void visitPrebuiltModule(StringRef PrebuiltModuleFilename,
89 PrebuiltModuleFilesT &ModuleFiles) {
92 PrebuiltModuleListener Listener(ModuleFiles, Worklist);
94 while (!Worklist.empty())
103static std::string makeObjFileName(StringRef FileName) {
105 llvm::sys::path::replace_extension(ObjFileName,
"o");
106 return std::string(ObjFileName.str());
111deduceDepTarget(
const std::string &OutputFile,
113 if (OutputFile !=
"-")
116 if (InputFiles.empty() || !InputFiles.front().isFile())
117 return "clang-scan-deps\\ dependency";
119 return makeObjFileName(InputFiles.front().getFile());
125 DiagOpts.ShowCarets =
false;
129 DiagOpts.IgnoreWarnings =
true;
136 DependencyScanningAction(
141 bool DisableFree, std::optional<StringRef> ModuleName = std::nullopt)
142 : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
143 Controller(Controller), DepFS(
std::move(DepFS)), Format(Format),
144 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
145 DisableFree(DisableFree), ModuleName(ModuleName) {}
147 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
149 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
154 OriginalInvocation.getFrontendOpts().DisableFree = DisableFree;
161 setLastCC1Arguments(std::move(OriginalInvocation));
168 ScanInstanceStorage.emplace(std::move(PCHContainerOps));
209 if (llvm::ErrorOr<EntryRef> Entry =
210 LocalDepFS->getOrCreateFileSystemEntry(
File.getName()))
211 return Entry->getDirectiveTokens();
223 auto Opts = std::make_unique<DependencyOutputOptions>();
227 if (Opts->Targets.empty())
231 Opts->IncludeSystemHeaders =
true;
234 case ScanningOutputFormat::Make:
236 std::make_shared<DependencyConsumerForwarder>(
237 std::move(Opts), WorkingDirectory, Consumer));
239 case ScanningOutputFormat::P1689:
240 case ScanningOutputFormat::Full:
241 MDC = std::make_shared<ModuleDepCollector>(
242 std::move(Opts), ScanInstance, Consumer, Controller,
243 OriginalInvocation, OptimizeArgs, EagerLoadModules,
244 Format == ScanningOutputFormat::P1689);
256 std::unique_ptr<FrontendAction> Action;
259 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
261 Action = std::make_unique<ReadPCHAndPreprocessAction>();
266 setLastCC1Arguments(std::move(OriginalInvocation));
271 bool hasScanned()
const {
return Scanned; }
276 std::vector<std::string> takeLastCC1Arguments() {
277 std::vector<std::string>
Result;
278 std::swap(Result, LastCC1Arguments);
285 MDC->applyDiscoveredDependencies(CI);
286 LastCC1Arguments = CI.getCC1CommandLine();
290 StringRef WorkingDirectory;
296 bool EagerLoadModules;
298 std::optional<StringRef> ModuleName;
299 std::optional<CompilerInstance> ScanInstanceStorage;
300 std::shared_ptr<ModuleDepCollector> MDC;
301 std::vector<std::string> LastCC1Arguments;
302 bool Scanned =
false;
310 : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()),
311 EagerLoadModules(Service.shouldEagerLoadModules()) {
312 PCHContainerOps = std::make_shared<PCHContainerOperations>();
314 PCHContainerOps->registerReader(
315 std::make_unique<ObjectFilePCHContainerReader>());
317 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
333 StringRef WorkingDirectory,
const std::vector<std::string> &CommandLine,
335 std::optional<StringRef> ModuleName) {
336 std::vector<const char *> CLI;
337 for (
const std::string &Arg : CommandLine)
338 CLI.push_back(Arg.c_str());
340 sanitizeDiagOpts(*DiagOpts);
344 std::string DiagnosticOutput;
345 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
349 DiagPrinter, ModuleName))
350 return llvm::Error::success();
351 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
352 llvm::inconvertibleErrorCode());
359 Argv.reserve(ArgStrs.size());
360 for (
const std::string &Arg : ArgStrs)
361 Argv.push_back(Arg.c_str());
365 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
366 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
367 "clang LLVM compiler", FS);
368 Driver->setTitle(
"clang_based_tool");
370 llvm::BumpPtrAllocator Alloc;
375 Diags.
Report(diag::err_drv_expand_response_file)
376 << llvm::toString(std::move(E));
380 const std::unique_ptr<driver::Compilation> Compilation(
393 StringRef WorkingDirectory,
const std::vector<std::string> &CommandLine,
397 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
399 std::optional<std::vector<std::string>> ModifiedCommandLine;
407 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
409 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
410 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
411 OverlayFS->pushOverlay(InMemoryFS);
412 ModifiedFS = OverlayFS;
416 llvm::sys::fs::createUniquePath(*ModuleName +
"-%%%%%%%%.input",
419 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(
""));
421 ModifiedCommandLine = CommandLine;
422 ModifiedCommandLine->emplace_back(FakeInputPath);
425 const std::vector<std::string> &FinalCommandLine =
426 ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
427 auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
431 auto FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(FSOpts, FinalFS);
433 std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(),
nullptr);
434 llvm::transform(FinalCommandLine, FinalCCommandLine.begin(),
435 [](
const std::string &Str) { return Str.c_str(); });
438 sanitizeDiagOpts(*DiagOpts);
446 Diags->setSourceManager(&SrcMgr);
450 bool DisableFree =
true;
451 DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS,
452 Format, OptimizeArgs, EagerLoadModules,
453 DisableFree, ModuleName);
456 if (StringRef(
Cmd.getCreator().getName()) !=
"clang") {
459 Consumer.handleBuildCommand(
460 {Cmd.getExecutable(),
461 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
465 std::vector<std::string> Argv;
466 Argv.push_back(
Cmd.getExecutable());
467 Argv.insert(Argv.end(),
Cmd.getArguments().begin(),
468 Cmd.getArguments().end());
478 if (!Invocation.
run())
481 std::vector<std::string> Args = Action.takeLastCC1Arguments();
486 if (Success && !Action.hasScanned())
487 Diags->
Report(diag::err_fe_expected_compiler_job)
488 << llvm::join(FinalCommandLine,
" ");
489 return Success && Action.hasScanned();
static bool forEachDriverJob(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, FileManager &FM, llvm::function_ref< bool(const driver::Command &Cmd)> Callback)
Abstract interface for callback invocations by the ASTReader.
virtual void visitImport(StringRef ModuleName, StringRef Filename)
If needsImportVisitation returns true, this is called for each AST file imported by this AST file.
virtual bool needsImportVisitation() const
Returns true if this ASTReaderListener wants to receive the imports of the AST file via visitImport,...
static bool readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, const InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions)
Read the control block for the named AST file.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void setFileManager(FileManager *Value)
Replace the current file manager and virtual file system.
void createSourceManager(FileManager &FileMgr)
Create the source manager and replace any existing one with it.
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
void setInvocation(std::shared_ptr< CompilerInvocation > Value)
setInvocation - Replace the current invocation.
FileManager & getFileManager() const
Return the current file manager to the caller.
InMemoryModuleCache & getModuleCache() const
void addDependencyCollector(std::shared_ptr< DependencyCollector > Listener)
FrontendOptions & getFrontendOpts()
bool hasDiagnostics() const
HeaderSearchOptions & getHeaderSearchOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
DiagnosticOptions & getDiagnosticOpts()
DependencyOutputOptions & getDependencyOutputOpts()
Helper class for holding the data necessary to invoke the compiler.
ArrayRef< std::string > getDependencies() const
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
void finishedMainFile(DiagnosticsEngine &Diags) override
Called when the end of the main file is reached.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Options for controlling the compiler diagnostics engine.
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Implements support for file system lookup, file system caching, and directory search management.
llvm::vfs::FileSystem & getVirtualFileSystem() const
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
void setVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Keeps track of options that affect how file operations are performed.
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
unsigned ModulesShareFileManager
Whether to share the FileManager when building modules.
std::string OutputFile
The output file, if any.
unsigned GenerateGlobalModuleIndex
Whether we can generate the global module index if needed.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
unsigned UseGlobalModuleIndex
Whether we can use the global module index if available.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool AllowPCHWithDifferentModulesCachePath
When true, a PCH with modules cache path different to the current compilation will not be rejected.
std::function< std::optional< ArrayRef< dependency_directives_scan::Directive > >(FileEntryRef)> DependencyDirectivesForFile
Function for getting the dependency preprocessor directives of a file.
This class handles loading and caching of source files into memory.
Command - An executable path/name and argument vector to execute.
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
llvm::Error expandResponseFiles(SmallVectorImpl< const char * > &Args, bool ClangCLMode, llvm::BumpPtrAllocator &Alloc, llvm::vfs::FileSystem *FS=nullptr)
Expand response files from a clang driver or cc1 invocation.
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ C
Languages that the frontend can parse and compile.
@ Result
The result type of a method or function.
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)