[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
This commit is contained in:
Jan Svoboda 2021-03-30 13:31:03 +02:00
parent cf2fc41bd1
commit 0a92e09c07
4 changed files with 69 additions and 28 deletions

View File

@ -225,9 +225,11 @@ public:
bool hasInvocation() const { return Invocation != nullptr; }
CompilerInvocation &getInvocation() {
CompilerInvocation &getInvocation() { return *getInvocationPtr(); }
std::shared_ptr<CompilerInvocation> getInvocationPtr() {
assert(Invocation && "Compiler instance has no invocation!");
return *Invocation;
return Invocation;
}
/// setInvocation - Replace the current invocation.

View File

@ -12,6 +12,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/PPCallbacks.h"
@ -47,6 +48,9 @@ struct ModuleDeps {
/// The identifier of the module.
ModuleID ID;
/// Whether this is a "system" module.
bool IsSystem;
/// The path to the modulemap file which defines this module.
///
/// This can be used to explicitly build this module. This file will
@ -71,6 +75,10 @@ struct ModuleDeps {
// the primary TU.
bool ImportedByMainFile = false;
/// The compiler invocation associated with the translation unit that imports
/// this module.
std::shared_ptr<CompilerInvocation> Invocation;
/// Gets the full command line suitable for passing to clang.
///
/// \param LookupPCMPath This function is called to fill in `-fmodule-file=`

View File

@ -12,32 +12,61 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
#include "llvm/Support/StringSaver.h"
using namespace clang;
using namespace tooling;
using namespace dependencies;
static CompilerInvocation
makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps) {
// Make a deep copy of the invocation.
CompilerInvocation CI(*Deps.Invocation);
// Remove options incompatible with explicit module build.
CI.getFrontendOpts().Inputs.clear();
CI.getFrontendOpts().OutputFile.clear();
CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
CI.getLangOpts()->ModuleName = Deps.ID.ModuleName;
CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
CI.getLangOpts()->ImplicitModules = false;
CI.getHeaderSearchOpts().ImplicitModuleMaps = false;
return CI;
}
static std::vector<std::string>
serializeCompilerInvocation(CompilerInvocation &CI) {
// Set up string allocator.
llvm::BumpPtrAllocator Alloc;
llvm::StringSaver Strings(Alloc);
auto SA = [&Strings](const Twine &Arg) { return Strings.save(Arg).data(); };
SmallVector<const char *, 32> Args;
// Synthesize full command line from the CompilerInvocation.
CI.generateCC1CommandLine(Args, SA);
// Convert arguments to the return type.
std::vector<std::string> Ret;
Ret.reserve(Args.size());
for (const char *Arg : Args)
Ret.emplace_back(Arg);
return Ret;
}
std::vector<std::string> ModuleDeps::getFullCommandLine(
std::function<StringRef(ModuleID)> LookupPCMPath,
std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const {
// TODO: Build full command line. That also means capturing the original
// command line into NonPathCommandLine.
CompilerInvocation CI(makeInvocationForModuleBuildWithoutPaths(*this));
std::vector<std::string> Ret{
"-fno-implicit-modules",
"-fno-implicit-module-maps",
};
std::vector<std::string> PCMPaths;
std::vector<std::string> ModMapPaths;
dependencies::detail::collectPCMAndModuleMapPaths(
ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths);
for (const std::string &PCMPath : PCMPaths)
Ret.push_back("-fmodule-file=" + PCMPath);
for (const std::string &ModMapPath : ModMapPaths)
Ret.push_back("-fmodule-map-file=" + ModMapPath);
ClangModuleDeps, LookupPCMPath, LookupModuleDeps,
CI.getFrontendOpts().ModuleFiles, CI.getFrontendOpts().ModuleMapFiles);
return Ret;
return serializeCompilerInvocation(CI);
}
void dependencies::detail::collectPCMAndModuleMapPaths(
@ -149,10 +178,12 @@ void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
.getModuleMap()
.getContainingModuleMapFile(M);
MD.Invocation = Instance.getInvocationPtr();
MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : "");
MD.ID.ModuleName = M->getFullModuleName();
MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
MD.ID.ContextHash = MDC.ContextHash;
MD.IsSystem = M->IsSystem;
serialization::ModuleFile *MF =
MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
MDC.Instance.getASTReader()->visitInputFiles(

View File

@ -37,11 +37,11 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap",
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-fno-implicit-modules",
// CHECK-NEXT: "-fno-implicit-module-maps",
// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm",
// CHECK-NEXT: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap"
// CHECK-NEXT: ],
// CHECK: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap",
// CHECK: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm",
// CHECK-NOT: "-fimplicit-module-maps",
// CHECK: "-fno-implicit-modules",
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h",
@ -53,9 +53,9 @@
// CHECK-NEXT: "clang-module-deps": [],
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap",
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-fno-implicit-modules",
// CHECK-NEXT: "-fno-implicit-module-maps"
// CHECK-NEXT: ],
// CHECK-NOT: "-fimplicit-module-maps",
// CHECK: "-fno-implicit-modules",
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2:[A-Z0-9]+]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h",
@ -67,9 +67,9 @@
// CHECK-NEXT: "clang-module-deps": [],
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap",
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-fno-implicit-modules",
// CHECK-NEXT: "-fno-implicit-module-maps"
// CHECK-NEXT: ],
// CHECK-NOT: "-fimplicit-module-maps",
// CHECK: "-fno-implicit-modules",
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/Inputs/header2.h",