150
|
1 //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
|
|
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/DependencyScanningTool.h"
|
|
10 #include "clang/Frontend/Utils.h"
|
252
|
11 #include <optional>
|
150
|
12
|
236
|
13 using namespace clang;
|
|
14 using namespace tooling;
|
|
15 using namespace dependencies;
|
150
|
16
|
|
17 DependencyScanningTool::DependencyScanningTool(
|
236
|
18 DependencyScanningService &Service,
|
|
19 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
|
|
20 : Worker(Service, std::move(FS)) {}
|
150
|
21
|
252
|
22 namespace {
|
|
23 /// Prints out all of the gathered dependencies into a string.
|
|
24 class MakeDependencyPrinterConsumer : public DependencyConsumer {
|
|
25 public:
|
|
26 void handleBuildCommand(Command) override {}
|
236
|
27
|
252
|
28 void
|
|
29 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
|
|
30 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
|
|
31 }
|
223
|
32
|
252
|
33 void handleFileDependency(StringRef File) override {
|
|
34 Dependencies.push_back(std::string(File));
|
|
35 }
|
223
|
36
|
252
|
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 {}
|
150
|
44
|
252
|
45 void printDependencies(std::string &S) {
|
|
46 assert(Opts && "Handled dependency output options.");
|
150
|
47
|
252
|
48 class DependencyPrinter : public DependencyFileGenerator {
|
|
49 public:
|
|
50 DependencyPrinter(DependencyOutputOptions &Opts,
|
|
51 ArrayRef<std::string> Dependencies)
|
|
52 : DependencyFileGenerator(Opts) {
|
|
53 for (const auto &Dep : Dependencies)
|
|
54 addDependency(Dep);
|
|
55 }
|
150
|
56
|
252
|
57 void printDependencies(std::string &S) {
|
|
58 llvm::raw_string_ostream OS(S);
|
|
59 outputDependencyFile(OS);
|
|
60 }
|
|
61 };
|
150
|
62
|
252
|
63 DependencyPrinter Generator(*Opts, Dependencies);
|
|
64 Generator.printDependencies(S);
|
|
65 }
|
150
|
66
|
252
|
67 protected:
|
|
68 std::unique_ptr<DependencyOutputOptions> Opts;
|
|
69 std::vector<std::string> Dependencies;
|
|
70 };
|
|
71 } // anonymous namespace
|
150
|
72
|
252
|
73 llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
|
|
74 const std::vector<std::string> &CommandLine, StringRef CWD) {
|
150
|
75 MakeDependencyPrinterConsumer Consumer;
|
252
|
76 CallbackActionController Controller(nullptr);
|
236
|
77 auto Result =
|
252
|
78 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller);
|
150
|
79 if (Result)
|
|
80 return std::move(Result);
|
|
81 std::string Output;
|
|
82 Consumer.printDependencies(Output);
|
|
83 return Output;
|
|
84 }
|
|
85
|
252
|
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 {
|
|
91 public:
|
|
92 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,
|
|
93 const CompileCommand &Command)
|
|
94 : Filename(Command.Filename), Rule(Rule) {
|
|
95 Rule.PrimaryOutput = Command.Output;
|
|
96 }
|
|
97
|
|
98 void handleProvidedAndRequiredStdCXXModules(
|
|
99 std::optional<P1689ModuleInfo> Provided,
|
|
100 std::vector<P1689ModuleInfo> Requires) override {
|
|
101 Rule.Provides = Provided;
|
|
102 if (Rule.Provides)
|
|
103 Rule.Provides->SourcePath = Filename.str();
|
|
104 Rule.Requires = Requires;
|
|
105 }
|
|
106
|
|
107 StringRef getMakeFormatDependencyOutputPath() {
|
|
108 if (Opts->OutputFormat != DependencyOutputFormat::Make)
|
|
109 return {};
|
|
110 return Opts->OutputFile;
|
|
111 }
|
|
112
|
|
113 private:
|
|
114 StringRef Filename;
|
|
115 P1689Rule &Rule;
|
|
116 };
|
|
117
|
|
118 class P1689ActionController : public DependencyActionController {
|
|
119 public:
|
|
120 // The lookupModuleOutput is for clang modules. P1689 format don't need it.
|
|
121 std::string lookupModuleOutput(const ModuleID &,
|
|
122 ModuleOutputKind Kind) override {
|
|
123 return "";
|
|
124 }
|
|
125 };
|
|
126
|
|
127 P1689Rule Rule;
|
|
128 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);
|
|
129 P1689ActionController Controller;
|
|
130 auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer,
|
|
131 Controller);
|
236
|
132 if (Result)
|
|
133 return std::move(Result);
|
252
|
134
|
|
135 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
|
|
136 if (!MakeformatOutputPath.empty())
|
|
137 Consumer.printDependencies(MakeformatOutput);
|
|
138 return Rule;
|
236
|
139 }
|
150
|
140
|
252
|
141 llvm::Expected<TranslationUnitDeps>
|
|
142 DependencyScanningTool::getTranslationUnitDependencies(
|
236
|
143 const std::vector<std::string> &CommandLine, StringRef CWD,
|
252
|
144 const llvm::DenseSet<ModuleID> &AlreadySeen,
|
|
145 LookupModuleOutputCallback LookupModuleOutput) {
|
|
146 FullDependencyConsumer Consumer(AlreadySeen);
|
|
147 CallbackActionController Controller(LookupModuleOutput);
|
150
|
148 llvm::Error Result =
|
252
|
149 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller);
|
150
|
150 if (Result)
|
|
151 return std::move(Result);
|
252
|
152 return Consumer.takeTranslationUnitDeps();
|
236
|
153 }
|
|
154
|
252
|
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);
|
|
163 if (Result)
|
|
164 return std::move(Result);
|
|
165 return Consumer.takeModuleGraphDeps();
|
|
166 }
|
236
|
167
|
252
|
168 TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {
|
|
169 TranslationUnitDeps TU;
|
|
170
|
|
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);
|
236
|
175
|
|
176 for (auto &&M : ClangModuleDeps) {
|
|
177 auto &MD = M.second;
|
|
178 // TODO: Avoid handleModuleDependency even being called for modules
|
|
179 // we've already seen.
|
|
180 if (AlreadySeen.count(M.first))
|
|
181 continue;
|
252
|
182 TU.ModuleGraph.push_back(std::move(MD));
|
236
|
183 }
|
252
|
184 TU.ClangModuleDeps = std::move(DirectModuleDeps);
|
236
|
185
|
252
|
186 return TU;
|
150
|
187 }
|
|
188
|
252
|
189 ModuleDepsGraph FullDependencyConsumer::takeModuleGraphDeps() {
|
|
190 ModuleDepsGraph ModuleGraph;
|
236
|
191
|
|
192 for (auto &&M : ClangModuleDeps) {
|
|
193 auto &MD = M.second;
|
|
194 // TODO: Avoid handleModuleDependency even being called for modules
|
|
195 // we've already seen.
|
|
196 if (AlreadySeen.count(M.first))
|
|
197 continue;
|
252
|
198 ModuleGraph.push_back(std::move(MD));
|
236
|
199 }
|
|
200
|
252
|
201 return ModuleGraph;
|
236
|
202 }
|
252
|
203
|
|
204 CallbackActionController::~CallbackActionController() {}
|