Skip to content

Commit 0a92e09

Browse files
committed
[clang][deps] Generate the full command-line for modules
This patch uses the new `CompilerInvocation::generateCC1CommandLine` to generate the full canonical command line for modular dependencies, instead of only appending additional arguments. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D100534
1 parent cf2fc41 commit 0a92e09

File tree

4 files changed

+69
-28
lines changed

4 files changed

+69
-28
lines changed

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,11 @@ class CompilerInstance : public ModuleLoader {
225225

226226
bool hasInvocation() const { return Invocation != nullptr; }
227227

228-
CompilerInvocation &getInvocation() {
228+
CompilerInvocation &getInvocation() { return *getInvocationPtr(); }
229+
230+
std::shared_ptr<CompilerInvocation> getInvocationPtr() {
229231
assert(Invocation && "Compiler instance has no invocation!");
230-
return *Invocation;
232+
return Invocation;
231233
}
232234

233235
/// setInvocation - Replace the current invocation.

clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "clang/Basic/LLVM.h"
1414
#include "clang/Basic/SourceManager.h"
15+
#include "clang/Frontend/CompilerInvocation.h"
1516
#include "clang/Frontend/Utils.h"
1617
#include "clang/Lex/HeaderSearch.h"
1718
#include "clang/Lex/PPCallbacks.h"
@@ -47,6 +48,9 @@ struct ModuleDeps {
4748
/// The identifier of the module.
4849
ModuleID ID;
4950

51+
/// Whether this is a "system" module.
52+
bool IsSystem;
53+
5054
/// The path to the modulemap file which defines this module.
5155
///
5256
/// This can be used to explicitly build this module. This file will
@@ -71,6 +75,10 @@ struct ModuleDeps {
7175
// the primary TU.
7276
bool ImportedByMainFile = false;
7377

78+
/// The compiler invocation associated with the translation unit that imports
79+
/// this module.
80+
std::shared_ptr<CompilerInvocation> Invocation;
81+
7482
/// Gets the full command line suitable for passing to clang.
7583
///
7684
/// \param LookupPCMPath This function is called to fill in `-fmodule-file=`

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,61 @@
1212
#include "clang/Frontend/CompilerInstance.h"
1313
#include "clang/Lex/Preprocessor.h"
1414
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
15+
#include "llvm/Support/StringSaver.h"
1516

1617
using namespace clang;
1718
using namespace tooling;
1819
using namespace dependencies;
1920

21+
static CompilerInvocation
22+
makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps) {
23+
// Make a deep copy of the invocation.
24+
CompilerInvocation CI(*Deps.Invocation);
25+
26+
// Remove options incompatible with explicit module build.
27+
CI.getFrontendOpts().Inputs.clear();
28+
CI.getFrontendOpts().OutputFile.clear();
29+
30+
CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
31+
CI.getLangOpts()->ModuleName = Deps.ID.ModuleName;
32+
CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
33+
34+
CI.getLangOpts()->ImplicitModules = false;
35+
CI.getHeaderSearchOpts().ImplicitModuleMaps = false;
36+
37+
return CI;
38+
}
39+
40+
static std::vector<std::string>
41+
serializeCompilerInvocation(CompilerInvocation &CI) {
42+
// Set up string allocator.
43+
llvm::BumpPtrAllocator Alloc;
44+
llvm::StringSaver Strings(Alloc);
45+
auto SA = [&Strings](const Twine &Arg) { return Strings.save(Arg).data(); };
46+
SmallVector<const char *, 32> Args;
47+
48+
// Synthesize full command line from the CompilerInvocation.
49+
CI.generateCC1CommandLine(Args, SA);
50+
51+
// Convert arguments to the return type.
52+
std::vector<std::string> Ret;
53+
Ret.reserve(Args.size());
54+
for (const char *Arg : Args)
55+
Ret.emplace_back(Arg);
56+
57+
return Ret;
58+
}
59+
2060
std::vector<std::string> ModuleDeps::getFullCommandLine(
2161
std::function<StringRef(ModuleID)> LookupPCMPath,
2262
std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const {
23-
// TODO: Build full command line. That also means capturing the original
24-
// command line into NonPathCommandLine.
25-
26-
std::vector<std::string> Ret{
27-
"-fno-implicit-modules",
28-
"-fno-implicit-module-maps",
29-
};
63+
CompilerInvocation CI(makeInvocationForModuleBuildWithoutPaths(*this));
3064

31-
std::vector<std::string> PCMPaths;
32-
std::vector<std::string> ModMapPaths;
3365
dependencies::detail::collectPCMAndModuleMapPaths(
34-
ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths);
35-
for (const std::string &PCMPath : PCMPaths)
36-
Ret.push_back("-fmodule-file=" + PCMPath);
37-
for (const std::string &ModMapPath : ModMapPaths)
38-
Ret.push_back("-fmodule-map-file=" + ModMapPath);
66+
ClangModuleDeps, LookupPCMPath, LookupModuleDeps,
67+
CI.getFrontendOpts().ModuleFiles, CI.getFrontendOpts().ModuleMapFiles);
3968

40-
return Ret;
69+
return serializeCompilerInvocation(CI);
4170
}
4271

4372
void dependencies::detail::collectPCMAndModuleMapPaths(
@@ -149,10 +178,12 @@ void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
149178
.getModuleMap()
150179
.getContainingModuleMapFile(M);
151180

181+
MD.Invocation = Instance.getInvocationPtr();
152182
MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : "");
153183
MD.ID.ModuleName = M->getFullModuleName();
154184
MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
155185
MD.ID.ContextHash = MDC.ContextHash;
186+
MD.IsSystem = M->IsSystem;
156187
serialization::ModuleFile *MF =
157188
MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
158189
MDC.Instance.getASTReader()->visitInputFiles(

clang/test/ClangScanDeps/modules-full.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
// CHECK-NEXT: ],
3838
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap",
3939
// CHECK-NEXT: "command-line": [
40-
// CHECK-NEXT: "-fno-implicit-modules",
41-
// CHECK-NEXT: "-fno-implicit-module-maps",
42-
// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm",
43-
// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap"
44-
// CHECK-NEXT: ],
40+
// CHECK: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap",
41+
// CHECK: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm",
42+
// CHECK-NOT: "-fimplicit-module-maps",
43+
// CHECK: "-fno-implicit-modules",
44+
// CHECK: ],
4545
// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]",
4646
// CHECK-NEXT: "file-deps": [
4747
// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h",
@@ -53,9 +53,9 @@
5353
// CHECK-NEXT: "clang-module-deps": [],
5454
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap",
5555
// CHECK-NEXT: "command-line": [
56-
// CHECK-NEXT: "-fno-implicit-modules",
57-
// CHECK-NEXT: "-fno-implicit-module-maps"
58-
// CHECK-NEXT: ],
56+
// CHECK-NOT: "-fimplicit-module-maps",
57+
// CHECK: "-fno-implicit-modules",
58+
// CHECK: ],
5959
// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2:[A-Z0-9]+]]",
6060
// CHECK-NEXT: "file-deps": [
6161
// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h",
@@ -67,9 +67,9 @@
6767
// CHECK-NEXT: "clang-module-deps": [],
6868
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap",
6969
// CHECK-NEXT: "command-line": [
70-
// CHECK-NEXT: "-fno-implicit-modules",
71-
// CHECK-NEXT: "-fno-implicit-module-maps"
72-
// CHECK-NEXT: ],
70+
// CHECK-NOT: "-fimplicit-module-maps",
71+
// CHECK: "-fno-implicit-modules",
72+
// CHECK: ],
7373
// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]",
7474
// CHECK-NEXT: "file-deps": [
7575
// CHECK-NEXT: "[[PREFIX]]/Inputs/header2.h",

0 commit comments

Comments
 (0)