1//===- DependencyScanningTool.h - 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#ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H
10#define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H
11
12#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
13#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
14#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
15#include "clang/Tooling/JSONCompilationDatabase.h"
16#include "llvm/ADT/DenseSet.h"
17#include "llvm/ADT/MapVector.h"
18#include <optional>
19#include <string>
20#include <vector>
21
22namespace clang {
23namespace tooling {
24namespace dependencies {
25
26/// A callback to lookup module outputs for "-fmodule-file=", "-o" etc.
27using LookupModuleOutputCallback =
28 llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>;
29
30/// Graph of modular dependencies.
31using ModuleDepsGraph = std::vector<ModuleDeps>;
32
33/// The full dependencies and module graph for a specific input.
34struct TranslationUnitDeps {
35 /// The graph of direct and transitive modular dependencies.
36 ModuleDepsGraph ModuleGraph;
37
38 /// The identifier of the C++20 module this translation unit exports.
39 ///
40 /// If the translation unit is not a module then \c ID.ModuleName is empty.
41 ModuleID ID;
42
43 /// A collection of absolute paths to files that this translation unit
44 /// directly depends on, not including transitive dependencies.
45 std::vector<std::string> FileDeps;
46
47 /// A collection of prebuilt modules this translation unit directly depends
48 /// on, not including transitive dependencies.
49 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
50
51 /// A list of modules this translation unit directly depends on, not including
52 /// transitive dependencies.
53 ///
54 /// This may include modules with a different context hash when it can be
55 /// determined that the differences are benign for this compilation.
56 std::vector<ModuleID> ClangModuleDeps;
57
58 /// The sequence of commands required to build the translation unit. Commands
59 /// should be executed in order.
60 ///
61 /// FIXME: If we add support for multi-arch builds in clang-scan-deps, we
62 /// should make the dependencies between commands explicit to enable parallel
63 /// builds of each architecture.
64 std::vector<Command> Commands;
65
66 /// Deprecated driver command-line. This will be removed in a future version.
67 std::vector<std::string> DriverCommandLine;
68};
69
70struct P1689Rule {
71 std::string PrimaryOutput;
72 std::optional<P1689ModuleInfo> Provides;
73 std::vector<P1689ModuleInfo> Requires;
74};
75
76/// The high-level implementation of the dependency discovery tool that runs on
77/// an individual worker thread.
78class DependencyScanningTool {
79public:
80 /// Construct a dependency scanning tool.
81 DependencyScanningTool(DependencyScanningService &Service,
82 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
83 llvm::vfs::createPhysicalFileSystem());
84
85 /// Print out the dependency information into a string using the dependency
86 /// file format that is specified in the options (-MD is the default) and
87 /// return it.
88 ///
89 /// \returns A \c StringError with the diagnostic output if clang errors
90 /// occurred, dependency file contents otherwise.
91 llvm::Expected<std::string>
92 getDependencyFile(const std::vector<std::string> &CommandLine, StringRef CWD);
93
94 /// Collect the module dependency in P1689 format for C++20 named modules.
95 ///
96 /// \param MakeformatOutput The output parameter for dependency information
97 /// in make format if the command line requires to generate make-format
98 /// dependency information by `-MD -MF <dep_file>`.
99 ///
100 /// \param MakeformatOutputPath The output parameter for the path to
101 /// \param MakeformatOutput.
102 ///
103 /// \returns A \c StringError with the diagnostic output if clang errors
104 /// occurred, P1689 dependency format rules otherwise.
105 llvm::Expected<P1689Rule>
106 getP1689ModuleDependencyFile(const clang::tooling::CompileCommand &Command,
107 StringRef CWD, std::string &MakeformatOutput,
108 std::string &MakeformatOutputPath);
109 llvm::Expected<P1689Rule>
110 getP1689ModuleDependencyFile(const clang::tooling::CompileCommand &Command,
111 StringRef CWD) {
112 std::string MakeformatOutput;
113 std::string MakeformatOutputPath;
114
115 return getP1689ModuleDependencyFile(Command, CWD, MakeformatOutput,
116 MakeformatOutputPath);
117 }
118
119 /// Given a Clang driver command-line for a translation unit, gather the
120 /// modular dependencies and return the information needed for explicit build.
121 ///
122 /// \param AlreadySeen This stores modules which have previously been
123 /// reported. Use the same instance for all calls to this
124 /// function for a single \c DependencyScanningTool in a
125 /// single build. Use a different one for different tools,
126 /// and clear it between builds.
127 /// \param LookupModuleOutput This function is called to fill in
128 /// "-fmodule-file=", "-o" and other output
129 /// arguments for dependencies.
130 ///
131 /// \returns a \c StringError with the diagnostic output if clang errors
132 /// occurred, \c TranslationUnitDeps otherwise.
133 llvm::Expected<TranslationUnitDeps>
134 getTranslationUnitDependencies(const std::vector<std::string> &CommandLine,
135 StringRef CWD,
136 const llvm::DenseSet<ModuleID> &AlreadySeen,
137 LookupModuleOutputCallback LookupModuleOutput);
138
139 /// Given a compilation context specified via the Clang driver command-line,
140 /// gather modular dependencies of module with the given name, and return the
141 /// information needed for explicit build.
142 llvm::Expected<ModuleDepsGraph> getModuleDependencies(
143 StringRef ModuleName, const std::vector<std::string> &CommandLine,
144 StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
145 LookupModuleOutputCallback LookupModuleOutput);
146
147private:
148 DependencyScanningWorker Worker;
149};
150
151class FullDependencyConsumer : public DependencyConsumer {
152public:
153 FullDependencyConsumer(const llvm::DenseSet<ModuleID> &AlreadySeen)
154 : AlreadySeen(AlreadySeen) {}
155
156 void handleBuildCommand(Command Cmd) override {
157 Commands.push_back(x: std::move(Cmd));
158 }
159
160 void handleDependencyOutputOpts(const DependencyOutputOptions &) override {}
161
162 void handleFileDependency(StringRef File) override {
163 Dependencies.push_back(x: std::string(File));
164 }
165
166 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
167 PrebuiltModuleDeps.emplace_back(args: std::move(PMD));
168 }
169
170 void handleModuleDependency(ModuleDeps MD) override {
171 ClangModuleDeps[MD.ID] = std::move(MD);
172 }
173
174 void handleDirectModuleDependency(ModuleID ID) override {
175 DirectModuleDeps.push_back(x: ID);
176 }
177
178 void handleContextHash(std::string Hash) override {
179 ContextHash = std::move(Hash);
180 }
181
182 TranslationUnitDeps takeTranslationUnitDeps();
183 ModuleDepsGraph takeModuleGraphDeps();
184
185private:
186 std::vector<std::string> Dependencies;
187 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
188 llvm::MapVector<ModuleID, ModuleDeps> ClangModuleDeps;
189 std::vector<ModuleID> DirectModuleDeps;
190 std::vector<Command> Commands;
191 std::string ContextHash;
192 std::vector<std::string> OutputPaths;
193 const llvm::DenseSet<ModuleID> &AlreadySeen;
194};
195
196/// A simple dependency action controller that uses a callback. If no callback
197/// is provided, it is assumed that looking up module outputs is unreachable.
198class CallbackActionController : public DependencyActionController {
199public:
200 virtual ~CallbackActionController();
201
202 CallbackActionController(LookupModuleOutputCallback LMO)
203 : LookupModuleOutput(std::move(LMO)) {
204 if (!LookupModuleOutput) {
205 LookupModuleOutput = [](const ModuleID &,
206 ModuleOutputKind) -> std::string {
207 llvm::report_fatal_error(reason: "unexpected call to lookupModuleOutput");
208 };
209 }
210 }
211
212 std::string lookupModuleOutput(const ModuleID &ID,
213 ModuleOutputKind Kind) override {
214 return LookupModuleOutput(ID, Kind);
215 }
216
217private:
218 LookupModuleOutputCallback LookupModuleOutput;
219};
220
221} // end namespace dependencies
222} // end namespace tooling
223} // end namespace clang
224
225#endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H
226

source code of clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h