summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>2023-02-10 10:26:35 +0800
committerTobias Hieta <tobias@hieta.se>2023-02-13 11:27:45 +0100
commit308a6cc3619ffff88fb0b8fc7c239a6e20b43f5f (patch)
treee5ab4b69afb29e6540f020924ce50f07d8e965cc
parent96faba7ee45b401e7c3e49649e81b662916c5b1a (diff)
downloadllvm-308a6cc3619ffff88fb0b8fc7c239a6e20b43f5f.tar.gz
[C++20] [Modules] [ClangScanDeps] Add ClangScanDeps support for C++20 Named Modules in P1689 format (2/4)
Close https://github.com/llvm/llvm-project/issues/51792 Close https://github.com/llvm/llvm-project/issues/56770 This patch adds ClangScanDeps support for C++20 Named Modules in P1689 format. We can find the P1689 format at: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html. After we land the patch, we're able to compile C++20 Named Modules with CMake! And although P1689 is written by kitware people, other build systems should be able to use the format to compile C++20 Named Modules too. TODO: Support header units in P1689 Format. TODO2: Support C++20 Modules in the full dependency format of ClangScanDeps. We also want to support C++20 Modules and clang modules together according to https://discourse.llvm.org/t/how-should-we-support-dependency-scanner-for-c-20-modules/66027. But P1689 format cares about C++20 Modules only for now. So let's focus on C++ Modules and P1689 format. And look at the full dependency format later. I'll add the ReleaseNotes and Documentations after the patch get landed. Reviewed By: jansvoboda11 Differential Revision: https://reviews.llvm.org/D137527
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h6
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h15
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h6
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h29
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp43
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp4
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp33
-rw-r--r--clang/test/ClangScanDeps/P1689.cppm157
-rw-r--r--clang/tools/clang-scan-deps/ClangScanDeps.cpp111
9 files changed, 388 insertions, 16 deletions
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
index a8cb15847b78..109cf049a652 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
@@ -35,9 +35,13 @@ enum class ScanningOutputFormat {
/// intermodule dependency information.
Make,
- /// This outputs the full module dependency graph suitable for use for
+ /// This outputs the full clang module dependency graph suitable for use for
/// explicitly building modules.
Full,
+
+ /// This outputs the dependency graph for standard c++ modules in P1689R5
+ /// format.
+ P1689,
};
/// The dependency scanning service contains shared configuration and state that
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index 6af878dbda95..d0c0c99fd25e 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -67,6 +67,12 @@ struct FullDependenciesResult {
std::vector<ModuleDeps> DiscoveredModules;
};
+struct P1689Rule {
+ std::string PrimaryOutput;
+ std::optional<P1689ModuleInfo> Provides;
+ std::vector<P1689ModuleInfo> Requires;
+};
+
/// The high-level implementation of the dependency discovery tool that runs on
/// an individual worker thread.
class DependencyScanningTool {
@@ -87,9 +93,12 @@ public:
getDependencyFile(const std::vector<std::string> &CommandLine, StringRef CWD,
std::optional<StringRef> ModuleName = std::nullopt);
- /// Collect the full module dependency graph for the input, ignoring any
- /// modules which have already been seen. If \p ModuleName isn't empty, this
- /// function returns the full dependency information of module \p ModuleName.
+ llvm::Expected<P1689Rule>
+ getP1689ModuleDependencyFile(const CompileCommand &Command,
+ StringRef CWD);
+
+ /// Given a Clang driver command-line for a translation unit, gather the
+ /// modular dependencies and return the information needed for explicit build.
///
/// \param AlreadySeen This stores modules which have previously been
/// reported. Use the same instance for all calls to this
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 458c4d936c83..6edf2cbe6b53 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -41,7 +41,11 @@ class DependencyConsumer {
public:
virtual ~DependencyConsumer() {}
- virtual void handleBuildCommand(Command Cmd) = 0;
+ virtual void handleProvidedAndRequiredStdCXXModules(
+ std::optional<P1689ModuleInfo> Provided,
+ std::vector<P1689ModuleInfo> Requires) {}
+
+ virtual void handleBuildCommand(Command Cmd) {}
virtual void
handleDependencyOutputOpts(const DependencyOutputOptions &Opts) = 0;
diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 6e4cec25961d..bce3e066372f 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -62,6 +62,27 @@ struct ModuleID {
}
};
+/// P1689ModuleInfo - Represents the needed information of standard C++20
+/// modules for P1689 format.
+struct P1689ModuleInfo {
+ /// The name of the module. This may include `:` for partitions.
+ std::string ModuleName;
+
+ /// Optional. The source path to the module.
+ std::string SourcePath;
+
+ /// If this module is a standard c++ interface unit.
+ bool IsStdCXXModuleInterface = true;
+
+ enum class ModuleType {
+ NamedCXXModule
+ // To be supported
+ // AngleHeaderUnit,
+ // QuoteHeaderUnit
+ };
+ ModuleType Type = ModuleType::NamedCXXModule;
+};
+
/// An output from a module compilation, such as the path of the module file.
enum class ModuleOutputKind {
/// The module file (.pcm). Required.
@@ -181,7 +202,7 @@ public:
ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
CompilerInvocation OriginalCI, bool OptimizeArgs,
- bool EagerLoadModules);
+ bool EagerLoadModules, bool IsStdModuleP1689Format);
void attachToPreprocessor(Preprocessor &PP) override;
void attachToASTReader(ASTReader &R) override;
@@ -219,6 +240,12 @@ private:
bool OptimizeArgs;
/// Whether to set up command-lines to load PCM files eagerly.
bool EagerLoadModules;
+ /// If we're generating dependency output in P1689 format
+ /// for standard C++ modules.
+ bool IsStdModuleP1689Format;
+
+ std::optional<P1689ModuleInfo> ProvidedStdCXXModule;
+ std::vector<P1689ModuleInfo> RequiredStdCXXModules;
/// Checks whether the module is known as being prebuilt.
bool isPrebuiltModule(const Module *M);
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 3fcef00a5780..eb01584073cb 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -111,6 +111,49 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
return Output;
}
+llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile(
+ const CompileCommand &Command, StringRef CWD) {
+ class P1689ModuleDependencyPrinterConsumer : public DependencyConsumer {
+ public:
+ P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,
+ const CompileCommand &Command)
+ : Filename(Command.Filename), Rule(Rule) {
+ Rule.PrimaryOutput = Command.Output;
+ }
+
+ void
+ handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {}
+ void handleFileDependency(StringRef File) override {}
+ void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {}
+ void handleModuleDependency(ModuleDeps MD) override {}
+ void handleContextHash(std::string Hash) override {}
+ std::string lookupModuleOutput(const ModuleID &ID,
+ ModuleOutputKind Kind) override {
+ llvm::report_fatal_error("unexpected call to lookupModuleOutput");
+ }
+
+ void handleProvidedAndRequiredStdCXXModules(
+ std::optional<P1689ModuleInfo> Provided,
+ std::vector<P1689ModuleInfo> Requires) override {
+ Rule.Provides = Provided;
+ if (Rule.Provides)
+ Rule.Provides->SourcePath = Filename.str();
+ Rule.Requires = Requires;
+ }
+
+ private:
+ StringRef Filename;
+ P1689Rule &Rule;
+ };
+
+ P1689Rule Rule;
+ P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);
+ auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer);
+ if (Result)
+ return std::move(Result);
+ return Rule;
+}
+
llvm::Expected<FullDependenciesResult>
DependencyScanningTool::getFullDependencies(
const std::vector<std::string> &CommandLine, StringRef CWD,
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index b54b8de9157e..8eb0328d6322 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -247,10 +247,12 @@ public:
std::make_shared<DependencyConsumerForwarder>(
std::move(Opts), WorkingDirectory, Consumer));
break;
+ case ScanningOutputFormat::P1689:
case ScanningOutputFormat::Full:
MDC = std::make_shared<ModuleDepCollector>(
std::move(Opts), ScanInstance, Consumer, OriginalInvocation,
- OptimizeArgs, EagerLoadModules);
+ OptimizeArgs, EagerLoadModules,
+ Format == ScanningOutputFormat::P1689);
ScanInstance.addDependencyCollector(MDC);
break;
}
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index cb1c66b8d63f..d1cbf79a843e 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -339,6 +339,14 @@ void ModuleDepCollectorPP::InclusionDirective(
void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc,
ModuleIdPath Path,
const Module *Imported) {
+ if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) {
+ P1689ModuleInfo RequiredModule;
+ RequiredModule.ModuleName = Path[0].first->getName().str();
+ RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
+ MDC.RequiredStdCXXModules.push_back(RequiredModule);
+ return;
+ }
+
handleImport(Imported);
}
@@ -361,6 +369,21 @@ void ModuleDepCollectorPP::EndOfMainFile() {
.getFileEntryForID(MainFileID)
->getName());
+ auto &PP = MDC.ScanInstance.getPreprocessor();
+ if (PP.isInNamedModule()) {
+ P1689ModuleInfo ProvidedModule;
+ ProvidedModule.ModuleName = PP.getNamedModuleName();
+ ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule;
+ ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit();
+ // Don't put implementation (non partition) unit as Provide.
+ // Put the module as required instead. Since the implementation
+ // unit will import the primary module implicitly.
+ if (PP.isInImplementationUnit())
+ MDC.RequiredStdCXXModules.push_back(ProvidedModule);
+ else
+ MDC.ProvidedStdCXXModule = ProvidedModule;
+ }
+
if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
@@ -374,6 +397,10 @@ void ModuleDepCollectorPP::EndOfMainFile() {
MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
+ if (MDC.IsStdModuleP1689Format)
+ MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
+ MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
+
for (auto &&I : MDC.ModularDeps)
MDC.Consumer.handleModuleDependency(*I.second);
@@ -548,10 +575,12 @@ void ModuleDepCollectorPP::addAffectingClangModule(
ModuleDepCollector::ModuleDepCollector(
std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
- CompilerInvocation OriginalCI, bool OptimizeArgs, bool EagerLoadModules)
+ CompilerInvocation OriginalCI, bool OptimizeArgs, bool EagerLoadModules,
+ bool IsStdModuleP1689Format)
: ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)),
OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs),
- EagerLoadModules(EagerLoadModules) {}
+ EagerLoadModules(EagerLoadModules),
+ IsStdModuleP1689Format(IsStdModuleP1689Format) {}
void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
diff --git a/clang/test/ClangScanDeps/P1689.cppm b/clang/test/ClangScanDeps/P1689.cppm
new file mode 100644
index 000000000000..c539f8ffb713
--- /dev/null
+++ b/clang/test/ClangScanDeps/P1689.cppm
@@ -0,0 +1,157 @@
+// RUN: rm -fr %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: sed "s|DIR|%/t|g" %t/P1689.json.in > %t/P1689.json
+// RUN: clang-scan-deps -compilation-database %t/P1689.json -format=p1689 | FileCheck %t/Checks.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps --mode=preprocess-dependency-directives -compilation-database %t/P1689.json -format=p1689 | FileCheck %t/Checks.cpp -DPREFIX=%/t
+
+//--- P1689.json.in
+[
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/M.cppm -c -o DIR/M.o",
+ "file": "DIR/M.cppm",
+ "output": "DIR/M.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/Impl.cpp -c -o DIR/Impl.o",
+ "file": "DIR/Impl.cpp",
+ "output": "DIR/Impl.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/impl_part.cppm -c -o DIR/impl_part.o",
+ "file": "DIR/impl_part.cppm",
+ "output": "DIR/impl_part.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/interface_part.cppm -c -o DIR/interface_part.o",
+ "file": "DIR/interface_part.cppm",
+ "output": "DIR/interface_part.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/User.cpp -c -o DIR/User.o",
+ "file": "DIR/User.cpp",
+ "output": "DIR/User.o"
+}
+]
+
+
+//--- M.cppm
+export module M;
+export import :interface_part;
+import :impl_part;
+export void Hello();
+
+//--- Impl.cpp
+module;
+#include "header.mock"
+module M;
+void Hello() {
+ std::cout << "Hello ";
+}
+
+//--- impl_part.cppm
+module;
+#include "header.mock"
+module M:impl_part;
+import :interface_part;
+
+std::string W = "World.";
+void World() {
+ std::cout << W << std::endl;
+}
+
+//--- interface_part.cppm
+export module M:interface_part;
+export void World();
+
+//--- User.cpp
+import M;
+import third_party_module;
+int main() {
+ Hello();
+ World();
+ return 0;
+}
+
+//--- Checks.cpp
+// CHECK: {
+// CHECK-NEXT: "revision": 0,
+// CHECK-NEXT: "rules": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "primary-output": "[[PREFIX]]/Impl.o",
+// CHECK-NEXT: "requires": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "logical-name": "M",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/M.cppm"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "primary-output": "[[PREFIX]]/M.o",
+// CHECK-NEXT: "provides": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "is-interface": true,
+// CHECK-NEXT: "logical-name": "M",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/M.cppm"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "requires": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "logical-name": "M:interface_part",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/interface_part.cppm"
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "logical-name": "M:impl_part",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/impl_part.cppm"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "primary-output": "[[PREFIX]]/User.o",
+// CHECK-NEXT: "requires": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "logical-name": "M",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/M.cppm"
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "logical-name": "third_party_module"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "primary-output": "[[PREFIX]]/impl_part.o",
+// CHECK-NEXT: "provides": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "is-interface": false,
+// CHECK-NEXT: "logical-name": "M:impl_part",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/impl_part.cppm"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "requires": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "logical-name": "M:interface_part",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/interface_part.cppm"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "primary-output": "[[PREFIX]]/interface_part.o",
+// CHECK-NEXT: "provides": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "is-interface": true,
+// CHECK-NEXT: "logical-name": "M:interface_part",
+// CHECK-NEXT: "source-path": "[[PREFIX]]/interface_part.cppm"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "version": 1
+// CHECK-NEXT: }
+
+//--- header.mock
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 0db7124c1230..fed2f701926b 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -131,12 +131,15 @@ static llvm::cl::opt<ScanningMode> ScanMode(
static llvm::cl::opt<ScanningOutputFormat> Format(
"format", llvm::cl::desc("The output format for the dependencies"),
- llvm::cl::values(clEnumValN(ScanningOutputFormat::Make, "make",
- "Makefile compatible dep file"),
- clEnumValN(ScanningOutputFormat::Full, "experimental-full",
- "Full dependency graph suitable"
- " for explicitly building modules. This format "
- "is experimental and will change.")),
+ llvm::cl::values(
+ clEnumValN(ScanningOutputFormat::Make, "make",
+ "Makefile compatible dep file"),
+ clEnumValN(ScanningOutputFormat::P1689, "p1689",
+ "Generate standard c++ modules dependency P1689 format"),
+ clEnumValN(ScanningOutputFormat::Full, "experimental-full",
+ "Full dependency graph suitable"
+ " for explicitly building modules. This format "
+ "is experimental and will change.")),
llvm::cl::init(ScanningOutputFormat::Make),
llvm::cl::cat(DependencyScannerCategory));
@@ -402,6 +405,92 @@ static bool handleFullDependencyToolResult(
return false;
}
+class P1689Deps {
+public:
+ void printDependencies(raw_ostream &OS) {
+ addSourcePathsToRequires();
+ // Sort the modules by name to get a deterministic order.
+ llvm::sort(Rules, [](const P1689Rule &A, const P1689Rule &B) {
+ return A.PrimaryOutput < B.PrimaryOutput;
+ });
+
+ using namespace llvm::json;
+ Array OutputRules;
+ for (const P1689Rule &R : Rules) {
+ Object O{{"primary-output", R.PrimaryOutput}};
+
+ if (R.Provides) {
+ Array Provides;
+ Object Provided{{"logical-name", R.Provides->ModuleName},
+ {"source-path", R.Provides->SourcePath},
+ {"is-interface", R.Provides->IsStdCXXModuleInterface}};
+ Provides.push_back(std::move(Provided));
+ O.insert({"provides", std::move(Provides)});
+ }
+
+ Array Requires;
+ for (const P1689ModuleInfo &Info : R.Requires) {
+ Object RequiredInfo{{"logical-name", Info.ModuleName}};
+ if (!Info.SourcePath.empty())
+ RequiredInfo.insert({"source-path", Info.SourcePath});
+ Requires.push_back(std::move(RequiredInfo));
+ }
+
+ if (!Requires.empty())
+ O.insert({"requires", std::move(Requires)});
+
+ OutputRules.push_back(std::move(O));
+ }
+
+ Object Output{
+ {"version", 1}, {"revision", 0}, {"rules", std::move(OutputRules)}};
+
+ OS << llvm::formatv("{0:2}\n", Value(std::move(Output)));
+ }
+
+ void addRules(P1689Rule &Rule) {
+ std::unique_lock<std::mutex> LockGuard(Lock);
+ Rules.push_back(Rule);
+ }
+
+private:
+ void addSourcePathsToRequires() {
+ llvm::DenseMap<StringRef, StringRef> ModuleSourceMapper;
+ for (const P1689Rule &R : Rules)
+ if (R.Provides && !R.Provides->SourcePath.empty())
+ ModuleSourceMapper[R.Provides->ModuleName] = R.Provides->SourcePath;
+
+ for (P1689Rule &R : Rules) {
+ for (P1689ModuleInfo &Info : R.Requires) {
+ auto Iter = ModuleSourceMapper.find(Info.ModuleName);
+ if (Iter != ModuleSourceMapper.end())
+ Info.SourcePath = Iter->second;
+ }
+ }
+ }
+
+ std::mutex Lock;
+ std::vector<P1689Rule> Rules;
+};
+
+static bool
+handleP1689DependencyToolResult(const std::string &Input,
+ llvm::Expected<P1689Rule> &MaybeRule,
+ P1689Deps &PD, SharedStream &Errs) {
+ if (!MaybeRule) {
+ llvm::handleAllErrors(
+ MaybeRule.takeError(), [&Input, &Errs](llvm::StringError &Err) {
+ Errs.applyLocked([&](raw_ostream &OS) {
+ OS << "Error while scanning dependencies for " << Input << ":\n";
+ OS << Err.getMessage();
+ });
+ });
+ return true;
+ }
+ PD.addRules(*MaybeRule);
+ return false;
+}
+
/// Construct a path for the explicitly built PCM.
static std::string constructPCMPath(ModuleID MID, StringRef OutputDir) {
SmallString<256> ExplicitPCMPath(OutputDir);
@@ -537,6 +626,7 @@ int main(int argc, const char **argv) {
std::atomic<bool> HadErrors(false);
FullDeps FD;
+ P1689Deps PD;
std::mutex Lock;
size_t Index = 0;
@@ -545,7 +635,7 @@ int main(int argc, const char **argv) {
<< " files using " << Pool.getThreadCount() << " workers\n";
}
for (unsigned I = 0; I < Pool.getThreadCount(); ++I) {
- Pool.async([I, &Lock, &Index, &Inputs, &HadErrors, &FD, &WorkerTools,
+ Pool.async([I, &Lock, &Index, &Inputs, &HadErrors, &FD, &PD, &WorkerTools,
&DependencyOS, &Errs]() {
llvm::StringSet<> AlreadySeenModules;
while (true) {
@@ -581,6 +671,11 @@ int main(int argc, const char **argv) {
if (handleMakeDependencyToolResult(Filename, MaybeFile, DependencyOS,
Errs))
HadErrors = true;
+ } else if (Format == ScanningOutputFormat::P1689) {
+ auto MaybeRule =
+ WorkerTools[I]->getP1689ModuleDependencyFile(*Input, CWD);
+ if (handleP1689DependencyToolResult(Filename, MaybeRule, PD, Errs))
+ HadErrors = true;
} else if (DeprecatedDriverCommand) {
auto MaybeFullDeps =
WorkerTools[I]->getFullDependenciesLegacyDriverCommand(
@@ -604,6 +699,8 @@ int main(int argc, const char **argv) {
if (Format == ScanningOutputFormat::Full)
FD.printFullOutput(llvm::outs());
+ else if (Format == ScanningOutputFormat::P1689)
+ PD.printDependencies(llvm::outs());
return HadErrors;
}