[clang] de17c66 - [C++20] [Modules] [ClangScanDeps] Add ClangScanDeps support for C++20 Named Modules in P1689 format (2/4)
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 9 18:31:15 PST 2023
Author: Chuanqi Xu
Date: 2023-02-10T10:26:43+08:00
New Revision: de17c665e3f995c7f5a0e453461ce3a1b8aec196
URL: https://github.com/llvm/llvm-project/commit/de17c665e3f995c7f5a0e453461ce3a1b8aec196
DIFF: https://github.com/llvm/llvm-project/commit/de17c665e3f995c7f5a0e453461ce3a1b8aec196.diff
LOG: [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
Added:
clang/test/ClangScanDeps/P1689.cppm
Modified:
clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
clang/tools/clang-scan-deps/ClangScanDeps.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
index a8cb15847b781..109cf049a6523 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 52a08d294dcfc..505137c539e6f 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -68,6 +68,12 @@ struct TranslationUnitDeps {
std::vector<std::string> DriverCommandLine;
};
+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 {
@@ -86,6 +92,10 @@ class DependencyScanningTool {
llvm::Expected<std::string>
getDependencyFile(const std::vector<std::string> &CommandLine, StringRef CWD);
+ 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.
///
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 5fb8d52f9ff01..5ada65c0a8308 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 3e1b71e6b8a48..238fc84ddd11c 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 @@ class ModuleDepCollector final : public DependencyCollector {
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 @@ class ModuleDepCollector final : public DependencyCollector {
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 a7ab4dd3af6da..ded5684190221 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -88,6 +88,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<TranslationUnitDeps>
DependencyScanningTool::getTranslationUnitDependencies(
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 f14de94025798..8b15ad1fb461b 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -247,10 +247,12 @@ class DependencyScanningAction : public tooling::ToolAction {
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 94ece9eb4c685..e882067dca398 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -341,6 +341,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);
}
@@ -363,6 +371,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);
@@ -376,6 +399,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);
@@ -550,10 +577,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 0000000000000..c539f8ffb7134
--- /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 53879a4064f0e..49d9648f3c6ac 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -132,12 +132,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));
@@ -462,6 +465,88 @@ static bool handleModuleResult(
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) { 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::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);
@@ -597,6 +682,7 @@ int main(int argc, const char **argv) {
std::atomic<bool> HadErrors(false);
FullDeps FD;
+ P1689Deps PD;
std::mutex Lock;
size_t Index = 0;
@@ -605,7 +691,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) {
@@ -641,6 +727,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 (MaybeModuleName) {
auto MaybeModuleDepsGraph = WorkerTools[I]->getModuleDependencies(
*MaybeModuleName, Input->CommandLine, CWD, AlreadySeenModules,
@@ -666,6 +757,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;
}
More information about the cfe-commits
mailing list