xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1480093f4SDimitry Andric //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
9a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
10a7dea167SDimitry Andric #include "clang/Frontend/Utils.h"
11*bdd1243dSDimitry Andric #include <optional>
12a7dea167SDimitry Andric 
13753f127fSDimitry Andric using namespace clang;
14753f127fSDimitry Andric using namespace tooling;
15753f127fSDimitry Andric using namespace dependencies;
16a7dea167SDimitry Andric 
17*bdd1243dSDimitry Andric static std::vector<std::string>
18*bdd1243dSDimitry Andric makeTUCommandLineWithoutPaths(ArrayRef<std::string> OriginalCommandLine) {
1981ad6265SDimitry Andric   std::vector<std::string> Args = OriginalCommandLine;
20fe6060f1SDimitry Andric 
2181ad6265SDimitry Andric   Args.push_back("-fno-implicit-modules");
2281ad6265SDimitry Andric   Args.push_back("-fno-implicit-module-maps");
23fe6060f1SDimitry Andric 
2481ad6265SDimitry Andric   // These arguments are unused in explicit compiles.
2581ad6265SDimitry Andric   llvm::erase_if(Args, [](StringRef Arg) {
2681ad6265SDimitry Andric     if (Arg.consume_front("-fmodules-")) {
2781ad6265SDimitry Andric       return Arg.startswith("cache-path=") ||
2881ad6265SDimitry Andric              Arg.startswith("prune-interval=") ||
2981ad6265SDimitry Andric              Arg.startswith("prune-after=") ||
3081ad6265SDimitry Andric              Arg == "validate-once-per-build-session";
3181ad6265SDimitry Andric     }
3281ad6265SDimitry Andric     return Arg.startswith("-fbuild-session-file=");
3381ad6265SDimitry Andric   });
3481ad6265SDimitry Andric 
35fe6060f1SDimitry Andric   return Args;
36fe6060f1SDimitry Andric }
37fe6060f1SDimitry Andric 
38480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool(
39fcaf7f86SDimitry Andric     DependencyScanningService &Service,
40fcaf7f86SDimitry Andric     llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
41fcaf7f86SDimitry Andric     : Worker(Service, std::move(FS)) {}
42a7dea167SDimitry Andric 
43480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
44349cc55cSDimitry Andric     const std::vector<std::string> &CommandLine, StringRef CWD,
45*bdd1243dSDimitry Andric     std::optional<StringRef> ModuleName) {
46a7dea167SDimitry Andric   /// Prints out all of the gathered dependencies into a string.
47480093f4SDimitry Andric   class MakeDependencyPrinterConsumer : public DependencyConsumer {
48a7dea167SDimitry Andric   public:
49*bdd1243dSDimitry Andric     void handleBuildCommand(Command) override {}
50*bdd1243dSDimitry Andric 
51fe6060f1SDimitry Andric     void
52fe6060f1SDimitry Andric     handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
53a7dea167SDimitry Andric       this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
54fe6060f1SDimitry Andric     }
55fe6060f1SDimitry Andric 
56fe6060f1SDimitry Andric     void handleFileDependency(StringRef File) override {
575ffd83dbSDimitry Andric       Dependencies.push_back(std::string(File));
58a7dea167SDimitry Andric     }
59a7dea167SDimitry Andric 
60fe6060f1SDimitry Andric     void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
61fe6060f1SDimitry Andric       // Same as `handleModuleDependency`.
62fe6060f1SDimitry Andric     }
63fe6060f1SDimitry Andric 
64480093f4SDimitry Andric     void handleModuleDependency(ModuleDeps MD) override {
65480093f4SDimitry Andric       // These are ignored for the make format as it can't support the full
66480093f4SDimitry Andric       // set of deps, and handleFileDependency handles enough for implicitly
67480093f4SDimitry Andric       // built modules to work.
68480093f4SDimitry Andric     }
69480093f4SDimitry Andric 
70480093f4SDimitry Andric     void handleContextHash(std::string Hash) override {}
71480093f4SDimitry Andric 
72*bdd1243dSDimitry Andric     std::string lookupModuleOutput(const ModuleID &ID,
73*bdd1243dSDimitry Andric                                    ModuleOutputKind Kind) override {
74*bdd1243dSDimitry Andric       llvm::report_fatal_error("unexpected call to lookupModuleOutput");
75*bdd1243dSDimitry Andric     }
76*bdd1243dSDimitry Andric 
77a7dea167SDimitry Andric     void printDependencies(std::string &S) {
78fe6060f1SDimitry Andric       assert(Opts && "Handled dependency output options.");
79a7dea167SDimitry Andric 
80a7dea167SDimitry Andric       class DependencyPrinter : public DependencyFileGenerator {
81a7dea167SDimitry Andric       public:
82a7dea167SDimitry Andric         DependencyPrinter(DependencyOutputOptions &Opts,
83a7dea167SDimitry Andric                           ArrayRef<std::string> Dependencies)
84a7dea167SDimitry Andric             : DependencyFileGenerator(Opts) {
85a7dea167SDimitry Andric           for (const auto &Dep : Dependencies)
86a7dea167SDimitry Andric             addDependency(Dep);
87a7dea167SDimitry Andric         }
88a7dea167SDimitry Andric 
89a7dea167SDimitry Andric         void printDependencies(std::string &S) {
90a7dea167SDimitry Andric           llvm::raw_string_ostream OS(S);
91a7dea167SDimitry Andric           outputDependencyFile(OS);
92a7dea167SDimitry Andric         }
93a7dea167SDimitry Andric       };
94a7dea167SDimitry Andric 
95a7dea167SDimitry Andric       DependencyPrinter Generator(*Opts, Dependencies);
96a7dea167SDimitry Andric       Generator.printDependencies(S);
97a7dea167SDimitry Andric     }
98a7dea167SDimitry Andric 
99a7dea167SDimitry Andric   private:
100a7dea167SDimitry Andric     std::unique_ptr<DependencyOutputOptions> Opts;
101a7dea167SDimitry Andric     std::vector<std::string> Dependencies;
102a7dea167SDimitry Andric   };
103a7dea167SDimitry Andric 
1045ffd83dbSDimitry Andric   MakeDependencyPrinterConsumer Consumer;
105349cc55cSDimitry Andric   auto Result =
106349cc55cSDimitry Andric       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
1075ffd83dbSDimitry Andric   if (Result)
1085ffd83dbSDimitry Andric     return std::move(Result);
1095ffd83dbSDimitry Andric   std::string Output;
1105ffd83dbSDimitry Andric   Consumer.printDependencies(Output);
1115ffd83dbSDimitry Andric   return Output;
1125ffd83dbSDimitry Andric }
1135ffd83dbSDimitry Andric 
1145ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult>
1155ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies(
116349cc55cSDimitry Andric     const std::vector<std::string> &CommandLine, StringRef CWD,
117349cc55cSDimitry Andric     const llvm::StringSet<> &AlreadySeen,
118*bdd1243dSDimitry Andric     LookupModuleOutputCallback LookupModuleOutput,
119*bdd1243dSDimitry Andric     std::optional<StringRef> ModuleName) {
120*bdd1243dSDimitry Andric   FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
121*bdd1243dSDimitry Andric                                   Worker.shouldEagerLoadModules());
122*bdd1243dSDimitry Andric   llvm::Error Result =
123*bdd1243dSDimitry Andric       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
124*bdd1243dSDimitry Andric   if (Result)
125*bdd1243dSDimitry Andric     return std::move(Result);
126*bdd1243dSDimitry Andric   return Consumer.takeFullDependencies();
127480093f4SDimitry Andric }
128480093f4SDimitry Andric 
129*bdd1243dSDimitry Andric llvm::Expected<FullDependenciesResult>
130*bdd1243dSDimitry Andric DependencyScanningTool::getFullDependenciesLegacyDriverCommand(
131*bdd1243dSDimitry Andric     const std::vector<std::string> &CommandLine, StringRef CWD,
132*bdd1243dSDimitry Andric     const llvm::StringSet<> &AlreadySeen,
133*bdd1243dSDimitry Andric     LookupModuleOutputCallback LookupModuleOutput,
134*bdd1243dSDimitry Andric     std::optional<StringRef> ModuleName) {
135*bdd1243dSDimitry Andric   FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
136*bdd1243dSDimitry Andric                                   Worker.shouldEagerLoadModules());
137*bdd1243dSDimitry Andric   llvm::Error Result =
138*bdd1243dSDimitry Andric       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
139*bdd1243dSDimitry Andric   if (Result)
140*bdd1243dSDimitry Andric     return std::move(Result);
141*bdd1243dSDimitry Andric   return Consumer.getFullDependenciesLegacyDriverCommand(CommandLine);
142fe6060f1SDimitry Andric }
143fe6060f1SDimitry Andric 
144*bdd1243dSDimitry Andric FullDependenciesResult FullDependencyConsumer::takeFullDependencies() {
145*bdd1243dSDimitry Andric   FullDependenciesResult FDR;
146*bdd1243dSDimitry Andric   FullDependencies &FD = FDR.FullDeps;
14781ad6265SDimitry Andric 
148fe6060f1SDimitry Andric   FD.ID.ContextHash = std::move(ContextHash);
149*bdd1243dSDimitry Andric   FD.FileDeps = std::move(Dependencies);
150*bdd1243dSDimitry Andric   FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
151*bdd1243dSDimitry Andric   FD.Commands = std::move(Commands);
152480093f4SDimitry Andric 
1535ffd83dbSDimitry Andric   for (auto &&M : ClangModuleDeps) {
1545ffd83dbSDimitry Andric     auto &MD = M.second;
155480093f4SDimitry Andric     if (MD.ImportedByMainFile)
156fe6060f1SDimitry Andric       FD.ClangModuleDeps.push_back(MD.ID);
157*bdd1243dSDimitry Andric     // TODO: Avoid handleModuleDependency even being called for modules
158*bdd1243dSDimitry Andric     //   we've already seen.
159*bdd1243dSDimitry Andric     if (AlreadySeen.count(M.first))
160*bdd1243dSDimitry Andric       continue;
161*bdd1243dSDimitry Andric     FDR.DiscoveredModules.push_back(std::move(MD));
162*bdd1243dSDimitry Andric   }
163*bdd1243dSDimitry Andric 
164*bdd1243dSDimitry Andric   return FDR;
165*bdd1243dSDimitry Andric }
166*bdd1243dSDimitry Andric 
167*bdd1243dSDimitry Andric FullDependenciesResult
168*bdd1243dSDimitry Andric FullDependencyConsumer::getFullDependenciesLegacyDriverCommand(
169*bdd1243dSDimitry Andric     const std::vector<std::string> &OriginalCommandLine) const {
170*bdd1243dSDimitry Andric   FullDependencies FD;
171*bdd1243dSDimitry Andric 
172*bdd1243dSDimitry Andric   FD.DriverCommandLine = makeTUCommandLineWithoutPaths(
173*bdd1243dSDimitry Andric       ArrayRef<std::string>(OriginalCommandLine).slice(1));
174*bdd1243dSDimitry Andric 
175*bdd1243dSDimitry Andric   FD.ID.ContextHash = std::move(ContextHash);
176*bdd1243dSDimitry Andric 
177*bdd1243dSDimitry Andric   FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
178*bdd1243dSDimitry Andric 
179*bdd1243dSDimitry Andric   for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
180*bdd1243dSDimitry Andric     FD.DriverCommandLine.push_back("-fmodule-file=" + PMD.PCMFile);
181*bdd1243dSDimitry Andric 
182*bdd1243dSDimitry Andric   for (auto &&M : ClangModuleDeps) {
183*bdd1243dSDimitry Andric     auto &MD = M.second;
184*bdd1243dSDimitry Andric     if (MD.ImportedByMainFile) {
185*bdd1243dSDimitry Andric       FD.ClangModuleDeps.push_back(MD.ID);
186*bdd1243dSDimitry Andric       auto PCMPath = LookupModuleOutput(MD.ID, ModuleOutputKind::ModuleFile);
187*bdd1243dSDimitry Andric       if (EagerLoadModules) {
188*bdd1243dSDimitry Andric         FD.DriverCommandLine.push_back("-fmodule-file=" + PCMPath);
189*bdd1243dSDimitry Andric       } else {
190*bdd1243dSDimitry Andric         FD.DriverCommandLine.push_back("-fmodule-map-file=" +
191*bdd1243dSDimitry Andric                                        MD.ClangModuleMapFile);
192*bdd1243dSDimitry Andric         FD.DriverCommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName +
193*bdd1243dSDimitry Andric                                        "=" + PCMPath);
194*bdd1243dSDimitry Andric       }
195*bdd1243dSDimitry Andric     }
196480093f4SDimitry Andric   }
197480093f4SDimitry Andric 
198fe6060f1SDimitry Andric   FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
199fe6060f1SDimitry Andric 
2005ffd83dbSDimitry Andric   FullDependenciesResult FDR;
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric   for (auto &&M : ClangModuleDeps) {
2035ffd83dbSDimitry Andric     // TODO: Avoid handleModuleDependency even being called for modules
2045ffd83dbSDimitry Andric     //   we've already seen.
2055ffd83dbSDimitry Andric     if (AlreadySeen.count(M.first))
2065ffd83dbSDimitry Andric       continue;
2075ffd83dbSDimitry Andric     FDR.DiscoveredModules.push_back(std::move(M.second));
208480093f4SDimitry Andric   }
209480093f4SDimitry Andric 
2105ffd83dbSDimitry Andric   FDR.FullDeps = std::move(FD);
2115ffd83dbSDimitry Andric   return FDR;
212480093f4SDimitry Andric }
213