1 //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
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/DependencyScanningTool.h"
10 #include "clang/Frontend/Utils.h"
13 using namespace clang
;
14 using namespace tooling
;
15 using namespace dependencies
;
17 DependencyScanningTool::DependencyScanningTool(
18 DependencyScanningService
&Service
,
19 llvm::IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> FS
)
20 : Worker(Service
, std::move(FS
)) {}
23 /// Prints out all of the gathered dependencies into a string.
24 class MakeDependencyPrinterConsumer
: public DependencyConsumer
{
26 void handleBuildCommand(Command
) override
{}
29 handleDependencyOutputOpts(const DependencyOutputOptions
&Opts
) override
{
30 this->Opts
= std::make_unique
<DependencyOutputOptions
>(Opts
);
33 void handleFileDependency(StringRef File
) override
{
34 Dependencies
.push_back(std::string(File
));
37 // These are ignored for the make format as it can't support the full
38 // set of deps, and handleFileDependency handles enough for implicitly
39 // built modules to work.
40 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD
) override
{}
41 void handleModuleDependency(ModuleDeps MD
) override
{}
42 void handleDirectModuleDependency(ModuleID ID
) override
{}
43 void handleContextHash(std::string Hash
) override
{}
45 void printDependencies(std::string
&S
) {
46 assert(Opts
&& "Handled dependency output options.");
48 class DependencyPrinter
: public DependencyFileGenerator
{
50 DependencyPrinter(DependencyOutputOptions
&Opts
,
51 ArrayRef
<std::string
> Dependencies
)
52 : DependencyFileGenerator(Opts
) {
53 for (const auto &Dep
: Dependencies
)
57 void printDependencies(std::string
&S
) {
58 llvm::raw_string_ostream
OS(S
);
59 outputDependencyFile(OS
);
63 DependencyPrinter
Generator(*Opts
, Dependencies
);
64 Generator
.printDependencies(S
);
68 std::unique_ptr
<DependencyOutputOptions
> Opts
;
69 std::vector
<std::string
> Dependencies
;
71 } // anonymous namespace
73 llvm::Expected
<std::string
> DependencyScanningTool::getDependencyFile(
74 const std::vector
<std::string
> &CommandLine
, StringRef CWD
) {
75 MakeDependencyPrinterConsumer Consumer
;
76 CallbackActionController
Controller(nullptr);
78 Worker
.computeDependencies(CWD
, CommandLine
, Consumer
, Controller
);
80 return std::move(Result
);
82 Consumer
.printDependencies(Output
);
86 llvm::Expected
<P1689Rule
> DependencyScanningTool::getP1689ModuleDependencyFile(
87 const CompileCommand
&Command
, StringRef CWD
, std::string
&MakeformatOutput
,
88 std::string
&MakeformatOutputPath
) {
89 class P1689ModuleDependencyPrinterConsumer
90 : public MakeDependencyPrinterConsumer
{
92 P1689ModuleDependencyPrinterConsumer(P1689Rule
&Rule
,
93 const CompileCommand
&Command
)
94 : Filename(Command
.Filename
), Rule(Rule
) {
95 Rule
.PrimaryOutput
= Command
.Output
;
98 void handleProvidedAndRequiredStdCXXModules(
99 std::optional
<P1689ModuleInfo
> Provided
,
100 std::vector
<P1689ModuleInfo
> Requires
) override
{
101 Rule
.Provides
= Provided
;
103 Rule
.Provides
->SourcePath
= Filename
.str();
104 Rule
.Requires
= Requires
;
107 StringRef
getMakeFormatDependencyOutputPath() {
108 if (Opts
->OutputFormat
!= DependencyOutputFormat::Make
)
110 return Opts
->OutputFile
;
118 class P1689ActionController
: public DependencyActionController
{
120 // The lookupModuleOutput is for clang modules. P1689 format don't need it.
121 std::string
lookupModuleOutput(const ModuleID
&,
122 ModuleOutputKind Kind
) override
{
128 P1689ModuleDependencyPrinterConsumer
Consumer(Rule
, Command
);
129 P1689ActionController Controller
;
130 auto Result
= Worker
.computeDependencies(CWD
, Command
.CommandLine
, Consumer
,
133 return std::move(Result
);
135 MakeformatOutputPath
= Consumer
.getMakeFormatDependencyOutputPath();
136 if (!MakeformatOutputPath
.empty())
137 Consumer
.printDependencies(MakeformatOutput
);
141 llvm::Expected
<TranslationUnitDeps
>
142 DependencyScanningTool::getTranslationUnitDependencies(
143 const std::vector
<std::string
> &CommandLine
, StringRef CWD
,
144 const llvm::DenseSet
<ModuleID
> &AlreadySeen
,
145 LookupModuleOutputCallback LookupModuleOutput
) {
146 FullDependencyConsumer
Consumer(AlreadySeen
);
147 CallbackActionController
Controller(LookupModuleOutput
);
149 Worker
.computeDependencies(CWD
, CommandLine
, Consumer
, Controller
);
151 return std::move(Result
);
152 return Consumer
.takeTranslationUnitDeps();
155 llvm::Expected
<ModuleDepsGraph
> DependencyScanningTool::getModuleDependencies(
156 StringRef ModuleName
, const std::vector
<std::string
> &CommandLine
,
157 StringRef CWD
, const llvm::DenseSet
<ModuleID
> &AlreadySeen
,
158 LookupModuleOutputCallback LookupModuleOutput
) {
159 FullDependencyConsumer
Consumer(AlreadySeen
);
160 CallbackActionController
Controller(LookupModuleOutput
);
161 llvm::Error Result
= Worker
.computeDependencies(CWD
, CommandLine
, Consumer
,
162 Controller
, ModuleName
);
164 return std::move(Result
);
165 return Consumer
.takeModuleGraphDeps();
168 TranslationUnitDeps
FullDependencyConsumer::takeTranslationUnitDeps() {
169 TranslationUnitDeps TU
;
171 TU
.ID
.ContextHash
= std::move(ContextHash
);
172 TU
.FileDeps
= std::move(Dependencies
);
173 TU
.PrebuiltModuleDeps
= std::move(PrebuiltModuleDeps
);
174 TU
.Commands
= std::move(Commands
);
176 for (auto &&M
: ClangModuleDeps
) {
178 // TODO: Avoid handleModuleDependency even being called for modules
179 // we've already seen.
180 if (AlreadySeen
.count(M
.first
))
182 TU
.ModuleGraph
.push_back(std::move(MD
));
184 TU
.ClangModuleDeps
= std::move(DirectModuleDeps
);
189 ModuleDepsGraph
FullDependencyConsumer::takeModuleGraphDeps() {
190 ModuleDepsGraph ModuleGraph
;
192 for (auto &&M
: ClangModuleDeps
) {
194 // TODO: Avoid handleModuleDependency even being called for modules
195 // we've already seen.
196 if (AlreadySeen
.count(M
.first
))
198 ModuleGraph
.push_back(std::move(MD
));
204 CallbackActionController::~CallbackActionController() {}