This patch introduces new option `-eager-load-pcm` to `clang-scan-deps`, which controls whether the resulting command-lines will load PCM files eagerly (at the start of compilation) or lazily (when handling import directive). This patch also switches the default from eager to lazy.
To reduce the potential for churn in LIT tests in the future, this patch also removes redundant checks of command-line arguments and introduces new test `modules-dep-args.c` as a substitute.
Reviewed By: benlangmuir
Differential Revision: https://reviews.llvm.org/D132066
public:
DependencyScanningService(ScanningMode Mode, ScanningOutputFormat Format,
bool ReuseFileManager = true,
- bool OptimizeArgs = false);
+ bool OptimizeArgs = false,
+ bool EagerLoadModules = false);
ScanningMode getMode() const { return Mode; }
bool canOptimizeArgs() const { return OptimizeArgs; }
+ bool shouldEagerLoadModules() const { return EagerLoadModules; }
+
DependencyScanningFilesystemSharedCache &getSharedCache() {
return SharedCache;
}
const bool ReuseFileManager;
/// Whether to optimize the modules' command-line arguments.
const bool OptimizeArgs;
+ /// Whether to set up command-lines to load PCM files eagerly.
+ const bool EagerLoadModules;
/// The global file system cache.
DependencyScanningFilesystemSharedCache SharedCache;
};
class FullDependencyConsumer : public DependencyConsumer {
public:
FullDependencyConsumer(const llvm::StringSet<> &AlreadySeen,
- LookupModuleOutputCallback LookupModuleOutput)
- : AlreadySeen(AlreadySeen), LookupModuleOutput(LookupModuleOutput) {}
+ LookupModuleOutputCallback LookupModuleOutput,
+ bool EagerLoadModules)
+ : AlreadySeen(AlreadySeen), LookupModuleOutput(LookupModuleOutput),
+ EagerLoadModules(EagerLoadModules) {}
void handleDependencyOutputOpts(const DependencyOutputOptions &) override {}
std::vector<std::string> OutputPaths;
const llvm::StringSet<> &AlreadySeen;
LookupModuleOutputCallback LookupModuleOutput;
+ bool EagerLoadModules;
};
} // end namespace dependencies
DependencyConsumer &Consumer,
llvm::Optional<StringRef> ModuleName = None);
+ bool shouldEagerLoadModules() const { return EagerLoadModules; }
+
private:
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
ScanningOutputFormat Format;
/// Whether to optimize the modules' command-line arguments.
bool OptimizeArgs;
+ /// Whether to set up command-lines to load PCM files eagerly.
+ bool EagerLoadModules;
};
} // end namespace dependencies
public:
ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
- CompilerInvocation &&OriginalCI, bool OptimizeArgs);
+ CompilerInvocation &&OriginalCI, bool OptimizeArgs,
+ bool EagerLoadModules);
void attachToPreprocessor(Preprocessor &PP) override;
void attachToASTReader(ASTReader &R) override;
CompilerInvocation OriginalInvocation;
/// Whether to optimize the modules' command-line arguments.
bool OptimizeArgs;
+ /// Whether to set up command-lines to load PCM files eagerly.
+ bool EagerLoadModules;
/// Checks whether the module is known as being prebuilt.
bool isPrebuiltModule(const Module *M);
DependencyScanningService::DependencyScanningService(
ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager,
- bool OptimizeArgs)
+ bool OptimizeArgs, bool EagerLoadModules)
: Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager),
- OptimizeArgs(OptimizeArgs) {
+ OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules) {
// Initialize targets for object file support.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
const llvm::StringSet<> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
llvm::Optional<StringRef> ModuleName) {
- FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput);
+ FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
+ Worker.shouldEagerLoadModules());
llvm::Error Result =
Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
if (Result)
auto &MD = M.second;
if (MD.ImportedByMainFile) {
FD.ClangModuleDeps.push_back(MD.ID);
- FD.CommandLine.push_back(
- "-fmodule-file=" +
- LookupModuleOutput(MD.ID, ModuleOutputKind::ModuleFile));
+ auto PCMPath = LookupModuleOutput(MD.ID, ModuleOutputKind::ModuleFile);
+ if (EagerLoadModules) {
+ FD.CommandLine.push_back("-fmodule-file=" + PCMPath);
+ } else {
+ FD.CommandLine.push_back("-fmodule-map-file=" + MD.ClangModuleMapFile);
+ FD.CommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName + "=" +
+ PCMPath);
+ }
}
}
DependencyScanningAction(
StringRef WorkingDirectory, DependencyConsumer &Consumer,
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
- ScanningOutputFormat Format, bool OptimizeArgs, bool DisableFree,
- llvm::Optional<StringRef> ModuleName = None)
+ ScanningOutputFormat Format, bool OptimizeArgs, bool EagerLoadModules,
+ bool DisableFree, llvm::Optional<StringRef> ModuleName = None)
: WorkingDirectory(WorkingDirectory), Consumer(Consumer),
DepFS(std::move(DepFS)), Format(Format), OptimizeArgs(OptimizeArgs),
- DisableFree(DisableFree), ModuleName(ModuleName) {}
+ EagerLoadModules(EagerLoadModules), DisableFree(DisableFree),
+ ModuleName(ModuleName) {}
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
FileManager *FileMgr,
case ScanningOutputFormat::Full:
ScanInstance.addDependencyCollector(std::make_shared<ModuleDepCollector>(
std::move(Opts), ScanInstance, Consumer,
- std::move(OriginalInvocation), OptimizeArgs));
+ std::move(OriginalInvocation), OptimizeArgs, EagerLoadModules));
break;
}
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
ScanningOutputFormat Format;
bool OptimizeArgs;
+ bool EagerLoadModules;
bool DisableFree;
llvm::Optional<StringRef> ModuleName;
};
DependencyScanningWorker::DependencyScanningWorker(
DependencyScanningService &Service,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
- : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) {
+ : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()),
+ EagerLoadModules(Service.shouldEagerLoadModules()) {
PCHContainerOps = std::make_shared<PCHContainerOperations>();
PCHContainerOps->registerReader(
std::make_unique<ObjectFilePCHContainerReader>());
bool DisableFree = true;
DependencyScanningAction Action(
WorkingDirectory, Consumer, DepFS, Format,
- OptimizeArgs, DisableFree, ModuleName);
+ OptimizeArgs, EagerLoadModules, DisableFree,
+ ModuleName);
// Create an invocation that uses the underlying file
// system to ensure that any file system requests that
// are made by the driver do not go through the
void ModuleDepCollector::addOutputPaths(ModuleDeps &Deps) {
CompilerInvocation &CI = Deps.BuildInvocation;
- for (ModuleID MID : Deps.ClangModuleDeps)
- CI.getFrontendOpts().ModuleFiles.push_back(
- Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile));
+
+ // These are technically *inputs* to the compilation, but we populate them
+ // here in order to make \c getModuleContextHash() independent of
+ // \c lookupModuleOutput().
+ for (ModuleID MID : Deps.ClangModuleDeps) {
+ auto PCMPath =
+ Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
+ if (EagerLoadModules)
+ CI.getFrontendOpts().ModuleFiles.push_back(PCMPath);
+ else
+ CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
+ {MID.ModuleName, PCMPath});
+ }
CI.getFrontendOpts().OutputFile =
Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
+ if (!EagerLoadModules) {
+ ModuleMap &ModMap =
+ ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ for (ModuleID MID : Deps.ClangModuleDeps) {
+ const Module *M = ModMap.findModule(MID.ModuleName);
+ assert(M && "Modular dependency not found");
+ auto MDeps = ModularDeps.find(M);
+ assert(MDeps != ModularDeps.end() && "Inconsistent dependency info");
+ CI.getFrontendOpts().ModuleMapFiles.push_back(
+ MDeps->second->ClangModuleMapFile);
+ }
+ }
+
// Remove any macro definitions that are explicitly ignored.
if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
llvm::erase_if(
return serializeCompilerInvocation(BuildInvocation);
}
-static std::string getModuleContextHash(const ModuleDeps &MD) {
+static std::string getModuleContextHash(const ModuleDeps &MD,
+ bool EagerLoadModules) {
llvm::HashBuilder<llvm::TruncatedBLAKE3<16>,
llvm::support::endianness::native>
HashBuilder;
HashBuilder.add(ID.ContextHash);
}
+ HashBuilder.add(EagerLoadModules);
+
llvm::BLAKE3Result<16> Hash = HashBuilder.final();
std::array<uint64_t, 2> Words;
static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
// Add direct prebuilt module dependencies now, so that we can use them when
// creating a CompilerInvocation and computing context hash for this
// ModuleDeps instance.
+ // TODO: Squash these.
llvm::DenseSet<const Module *> SeenModules;
addAllSubmodulePrebuiltDeps(M, MD, SeenModules);
+ llvm::DenseSet<const Module *> AddedModules;
+ addAllSubmoduleDeps(M, MD, AddedModules);
MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutOutputs(
MD, [&](CompilerInvocation &BuildInvocation) {
*MDC.ScanInstance.getASTReader(), *MF);
});
- llvm::DenseSet<const Module *> AddedModules;
- addAllSubmoduleDeps(M, MD, AddedModules);
-
// Compute the context hash from the inputs. Requires dependencies.
- MD.ID.ContextHash = getModuleContextHash(MD);
+ MD.ID.ContextHash = getModuleContextHash(MD, MDC.EagerLoadModules);
// Finish the compiler invocation. Requires dependencies and the context hash.
MDC.addOutputPaths(MD);
return MD.ID;
ModuleDepCollector::ModuleDepCollector(
std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
- CompilerInvocation &&OriginalCI, bool OptimizeArgs)
+ CompilerInvocation &&OriginalCI, bool OptimizeArgs, bool EagerLoadModules)
: ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)),
- OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs) {}
+ OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs),
+ EagerLoadModules(EagerLoadModules) {}
void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
--- /dev/null
+// This test exercises the different ways explicit modular dependencies are
+// provided on the command-line.
+
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- cdb.json.template
+[{
+ "file": "DIR/tu.c",
+ "directory": "DIR",
+ "command": "clang DIR/tu.c -fmodules -fmodules-cache-path=DIR/cache -o DIR/tu.o"
+}]
+
+//--- module.modulemap
+module Transitive { header "transitive.h" }
+module Direct { header "direct.h" }
+//--- transitive.h
+//--- direct.h
+#include "transitive.h"
+//--- tu.c
+#include "direct.h"
+
+// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
+
+// Check that the PCM path defaults to the modules cache from implicit build.
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/result_cache.json
+// RUN: cat %t/result_cache.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefixes=CHECK,CHECK_CACHE
+
+// Check that the PCM path can be customized.
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-files-dir %t/build > %t/result_build.json
+// RUN: cat %t/result_build.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefixes=CHECK,CHECK_BUILD
+
+// Check that the PCM file is loaded lazily by default.
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/result_lazy.json
+// RUN: cat %t/result_lazy.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefixes=CHECK,CHECK_LAZY
+
+// Check that the PCM file can be loaded eagerly.
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -eager-load-pcm > %t/result_eager.json
+// RUN: cat %t/result_eager.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefixes=CHECK,CHECK_EAGER
+
+// CHECK: {
+// CHECK-NEXT: "modules": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "clang-module-deps": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "context-hash": "{{.*}}",
+// CHECK-NEXT: "module-name": "Transitive"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT: "command-line": [
+// CHECK_CACHE: "-fmodule-file={{.*}}/cache/{{.*}}/Transitive-{{.*}}.pcm"
+// CHECK_BUILD: "-fmodule-file={{.*}}/build/{{.*}}/Transitive-{{.*}}.pcm"
+// CHECK_LAZY: "-fmodule-map-file=[[PREFIX]]/module.modulemap"
+// CHECK_LAZY: "-fmodule-file=Transitive=[[PREFIX]]/{{.*}}/Transitive-{{.*}}.pcm"
+// CHECK_EAGER-NOT: "-fmodule-map-file={{.*}}"
+// CHECK_EAGER: "-fmodule-file=[[PREFIX]]/{{.*}}/Transitive-{{.*}}.pcm"
+// CHECK: ],
+// CHECK-NEXT: "context-hash": "{{.*}}",
+// CHECK-NEXT: "file-deps": [
+// CHECK-NEXT: "[[PREFIX]]/direct.h",
+// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
+// CHECK-NEXT: ],
+// CHECK-NEXT: "name": "Direct"
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "clang-module-deps": [],
+// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT: "command-line": [
+// CHECK: ],
+// CHECK-NEXT: "context-hash": "{{.*}}",
+// CHECK-NEXT: "file-deps": [
+// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT: "[[PREFIX]]/transitive.h"
+// CHECK-NEXT: ],
+// CHECK-NEXT: "name": "Transitive"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "translation-units": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "clang-context-hash": "{{.*}}",
+// CHECK-NEXT: "clang-module-deps": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "context-hash": "{{.*}}",
+// CHECK-NEXT: "module-name": "Direct"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "command-line": [
+// CHECK_CACHE: "-fmodule-file={{.*}}/cache/{{.*}}/Direct-{{.*}}.pcm"
+// CHECK_BUILD: "-fmodule-file={{.*}}/build/{{.*}}/Direct-{{.*}}.pcm"
+// CHECK_LAZY: "-fmodule-map-file=[[PREFIX]]/module.modulemap"
+// CHECK_LAZY: "-fmodule-file=Direct=[[PREFIX]]/{{.*}}/Direct-{{.*}}.pcm"
+// CHECK_EAGER-NOT: "-fmodule-map-file={{.*}}"
+// CHECK_EAGER: "-fmodule-file=[[PREFIX]]/{{.*}}/Direct-{{.*}}.pcm"
+// CHECK: ],
+// CHECK-NEXT: "file-deps": [
+// CHECK-NEXT: "[[PREFIX]]/tu.c"
+// CHECK-NEXT: ],
+// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
\ No newline at end of file
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
-// CHECK: "-fno-implicit-modules"
-// CHECK-NEXT: "-fno-implicit-module-maps"
-// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H2]]/header2-{{[A-Z0-9]+}}.pcm"
-// CHECK-NEXT: ],
+// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules-fmodule-name-no-module-built.m"
// CHECK-NEXT: "[[PREFIX]]/Inputs/header3.h"
//
// RUN: clang-scan-deps -compilation-database %t.cdb -j 4 -format experimental-full \
// RUN: -mode preprocess-dependency-directives > %t.result
-// RUN: cat %t.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir --check-prefixes=CHECK,CHECK-ABS %s
-//
-// RUN: clang-scan-deps -compilation-database %t.cdb -j 4 -format experimental-full \
-// RUN: -module-files-dir %t.dir/custom \
-// RUN: -mode preprocess-dependency-directives > %t.result
-// RUN: cat %t.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir --check-prefixes=CHECK,CHECK-CUSTOM %s
+// RUN: cat %t.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir %s
//
// RUN: clang-scan-deps -compilation-database %t_clangcl.cdb -j 4 -format experimental-full \
// RUN: -mode preprocess-dependency-directives > %t_clangcl.result
-// RUN: cat %t_clangcl.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir --check-prefixes=CHECK,CHECK-ABS %s
+// RUN: cat %t_clangcl.result | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t.dir %s
#include "header.h"
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-emit-module"
-// CHECK-ABS: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H2_DINCLUDE]]/header2-{{[A-Z0-9]+}}.pcm"
-// CHECK-CUSTOM: "-fmodule-file=[[PREFIX]]/custom/[[HASH_H2_DINCLUDE]]/header2-{{[A-Z0-9]+}}.pcm"
+// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H2_DINCLUDE]]/header2-{{[A-Z0-9]+}}.pcm"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: "-fmodule-name=header1"
// CHECK: "-fno-implicit-modules"
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
-// CHECK-NEXT: "-fno-implicit-module-maps"
-// CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-NEXT: ],
+// CHECK: "-fno-implicit-module-maps"
+// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
+// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
-// CHECK-NEXT: "-fno-implicit-module-maps"
-// CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-NEXT: ],
+// CHECK: "-fno-implicit-module-maps"
+// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
+// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
-// CHECK-NEXT: "-fno-implicit-module-maps"
-// CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-NEXT: ],
+// CHECK: "-fno-implicit-module-maps"
+// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
+// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
-// CHECK-NEXT: "-fno-implicit-module-maps"
-// CHECK-ABS-NEXT: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1_DINCLUDE]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-CUSTOM-NEXT: "-fmodule-file=[[PREFIX]]/custom/[[HASH_H1_DINCLUDE]]/header1-{{[A-Z0-9]+}}.pcm"
-// CHECK-NEXT: ],
+// CHECK: "-fno-implicit-module-maps"
+// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1_DINCLUDE]]/header1-{{[A-Z0-9]+}}.pcm"
+// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input2.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "clang-module-deps": [],
// CHECK-NEXT: "clang-modulemap-file": "[[SOURCEDIR]]/Inputs/frameworks/module.modulemap",
// CHECK-NEXT: "command-line": [
-// CHECK-NEXT: "-cc1",
-// CHECK: "-emit-module",
-// CHECK-NOT: "-fimplicit-module-maps",
-// CHECK: "-fmodule-name=Inferred",
-// CHECK: "-fno-implicit-modules",
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[HASH_INFERRED:[A-Z0-9]+]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
-// CHECK: "-fno-implicit-modules",
-// CHECK-NEXT: "-fno-implicit-module-maps",
-// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache/[[HASH_INFERRED]]/Inferred-{{[A-Z0-9]+}}.pcm"
-// CHECK-NEXT: ],
+// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-PCH-NEXT: "clang-module-deps": [],
// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH-NEXT: "-cc1"
-// CHECK-PCH: "-emit-module"
-// CHECK-PCH: "-fmodules"
-// CHECK-PCH: "-fmodule-name=ModCommon"
-// CHECK-PCH: "-fno-implicit-modules"
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON:.*]]",
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: }
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH: "-fno-implicit-modules"
-// CHECK-PCH-NEXT: "-fno-implicit-module-maps"
-// CHECK-PCH-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON]]/ModCommon-{{.*}}.pcm"
-// CHECK-PCH-NEXT: ],
+// CHECK-PCH: ],
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: ],
// CHECK-TU-NEXT: "clang-module-deps": [],
// CHECK-TU-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-TU-NEXT: "command-line": [
-// CHECK-TU-NEXT: "-cc1"
-// CHECK-TU: "-emit-module"
-// CHECK-TU: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON:.*]]/ModCommon-{{.*}}.pcm"
-// CHECK-TU: "-fmodules"
-// CHECK-TU: "-fmodule-name=ModTU"
-// CHECK-TU: "-fno-implicit-modules"
// CHECK-TU: ],
// CHECK-TU-NEXT: "context-hash": "[[HASH_MOD_TU:.*]]",
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU-NEXT: }
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "command-line": [
-// CHECK-TU: "-fno-implicit-modules",
-// CHECK-TU-NEXT: "-fno-implicit-module-maps",
-// CHECK-TU-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU:.*]]/ModTU-{{.*}}.pcm"
-// CHECK-TU-NEXT: ],
+// CHECK-TU: ],
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU-NEXT: "[[PREFIX]]/tu.c",
// CHECK-TU-NEXT: "[[PREFIX]]/pch.h.gch"
// section in XCOFF yet.
// UNSUPPORTED: aix
-// Check that we discover dependency on a precompiled module (and generate the
-// appropriate `-fmodule-file=` argument) when it's imported by a **submodule**
-// instead of a top-level module.
+// Check that we discover dependency on a precompiled module when it's imported
+// by a **submodule** instead of a top-level module.
// RUN: rm -rf %t && mkdir %t
// RUN: cp %S/Inputs/modules-pch-common-via-submodule/* %t
// CHECK-PCH-NEXT: "clang-module-deps": [],
// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH-NEXT: "-cc1"
-// CHECK-PCH: "-emit-module"
-// CHECK-PCH: "-fmodules"
-// CHECK-PCH: "-fmodule-name=ModCommon"
-// CHECK-PCH: "-fno-implicit-modules"
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON:.*]]",
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: }
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH: "-fno-implicit-modules"
-// CHECK-PCH-NEXT: "-fno-implicit-module-maps"
-// CHECK-PCH-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON]]/ModCommon-{{.*}}.pcm"
-// CHECK-PCH-NEXT: ],
+// CHECK-PCH: ],
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: ],
// CHECK-TU-NEXT: "clang-module-deps": [],
// CHECK-TU-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-TU-NEXT: "command-line": [
-// CHECK-TU-NEXT: "-cc1"
-// CHECK-TU: "-emit-module"
-// CHECK-TU: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON:.*]]/ModCommon-{{.*}}.pcm"
-// CHECK-TU: "-fmodules"
-// CHECK-TU: "-fmodule-name=ModTU"
-// CHECK-TU: "-fno-implicit-modules"
// CHECK-TU: ],
// CHECK-TU-NEXT: "context-hash": "[[HASH_MOD_TU:.*]]",
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU-NEXT: }
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "command-line": [
-// CHECK-TU: "-fno-implicit-modules",
-// CHECK-TU-NEXT: "-fno-implicit-module-maps",
-// CHECK-TU-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU:.*]]/ModTU-{{.*}}.pcm"
-// CHECK-TU-NEXT: ],
+// CHECK-TU: ],
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU-NEXT: "[[PREFIX]]/tu.c",
// CHECK-TU-NEXT: "[[PREFIX]]/pch.h.gch"
// CHECK-PCH-NEXT: "clang-module-deps": [],
// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH-NEXT: "-cc1"
-// CHECK-PCH: "-emit-module"
-// CHECK-PCH: "-fmodules"
-// CHECK-PCH-NOT: "-fimplicit-module-maps"
-// CHECK-PCH: "-fmodule-name=ModCommon1"
-// CHECK-PCH: "-fno-implicit-modules"
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_1:.*]]",
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: "clang-module-deps": [],
// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH-NEXT: "-cc1"
-// CHECK-PCH: "-emit-module"
-// CHECK-PCH: "-fmodules"
-// CHECK-PCH-NOT: "-fimplicit-module-maps"
-// CHECK-PCH: "-fmodule-name=ModCommon2"
-// CHECK-PCH: "-fno-implicit-modules"
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_2:.*]]",
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH-NEXT: "-cc1"
-// CHECK-PCH: "-emit-module"
-// CHECK-PCH: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON_2]]/ModCommon2-{{.*}}.pcm"
-// CHECK-PCH: "-fmodules"
-// CHECK-PCH-NOT: "-fimplicit-module-maps"
-// CHECK-PCH: "-fmodule-name=ModPCH"
-// CHECK-PCH: "-fno-implicit-modules"
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_PCH:.*]]",
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: }
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "command-line": [
-// CHECK-PCH: "-fno-implicit-modules",
-// CHECK-PCH-NEXT: "-fno-implicit-module-maps",
-// CHECK-PCH-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_COMMON_1]]/ModCommon1-{{.*}}.pcm",
-// CHECK-PCH-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_PCH]]/ModPCH-{{.*}}.pcm"
-// CHECK-PCH-NEXT: ],
+// CHECK-PCH: ],
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: ],
// CHECK-TU-NEXT: "clang-module-deps": [],
// CHECK-TU-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-TU-NEXT: "command-line": [
-// CHECK-TU-NEXT: "-cc1",
-// CHECK-TU: "-emit-module",
-// CHECK-TU-NOT: "-fimplicit-module-maps",
-// CHECK-TU: "-fmodule-name=ModTU",
-// CHECK-TU: "-fno-implicit-modules",
// CHECK-TU: ],
// CHECK-TU-NEXT: "context-hash": "[[HASH_MOD_TU:.*]]",
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU-NEXT: }
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "command-line": [
-// CHECK-TU: "-fno-implicit-modules",
-// CHECK-TU-NEXT: "-fno-implicit-module-maps",
-// CHECK-TU-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU]]/ModTU-{{.*}}.pcm"
-// CHECK-TU-NEXT: ],
+// CHECK-TU: ],
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU-NEXT: "[[PREFIX]]/tu.c",
// CHECK-TU-NEXT: "[[PREFIX]]/pch.h.gch"
// CHECK-TU-WITH-COMMON-NEXT: "clang-module-deps": [],
// CHECK-TU-WITH-COMMON-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// CHECK-TU-WITH-COMMON-NEXT: "command-line": [
-// CHECK-TU-WITH-COMMON-NEXT: "-cc1",
-// CHECK-TU-WITH-COMMON: "-emit-module",
-// CHECK-TU-WITH-COMMON: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon1-{{.*}}.pcm",
-// CHECK-TU-WITH-COMMON-NOT: "-fimplicit-module-maps",
-// CHECK-TU-WITH-COMMON: "-fmodule-name=ModTUWithCommon",
-// CHECK-TU-WITH-COMMON: "-fno-implicit-modules",
// CHECK-TU-WITH-COMMON: ],
// CHECK-TU-WITH-COMMON-NEXT: "context-hash": "[[HASH_MOD_TU_WITH_COMMON:.*]]",
// CHECK-TU-WITH-COMMON-NEXT: "file-deps": [
// CHECK-TU-WITH-COMMON-NEXT: }
// CHECK-TU-WITH-COMMON-NEXT: ],
// CHECK-TU-WITH-COMMON-NEXT: "command-line": [
-// CHECK-TU-WITH-COMMON: "-fno-implicit-modules",
-// CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-module-maps",
-// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm",
-// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU_WITH_COMMON]]/ModTUWithCommon-{{.*}}.pcm"
-// CHECK-TU-WITH-COMMON-NEXT: ],
+// CHECK-TU-WITH-COMMON: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm"
+// CHECK-TU-WITH-COMMON: ],
// CHECK-TU-WITH-COMMON-NEXT: "file-deps": [
// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/tu_with_common.c",
// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/pch.h.gch"
llvm::cl::desc("Whether to optimize command-line arguments of modules."),
llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
+static llvm::cl::opt<bool> EagerLoadModules(
+ "eager-load-pcm",
+ llvm::cl::desc("Load PCM files eagerly (instead of lazily on import)."),
+ llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
+
llvm::cl::opt<unsigned>
NumThreads("j", llvm::cl::Optional,
llvm::cl::desc("Number of worker threads to use (default: use "
SharedStream DependencyOS(llvm::outs());
DependencyScanningService Service(ScanMode, Format, ReuseFileManager,
- OptimizeArgs);
+ OptimizeArgs, EagerLoadModules);
llvm::ThreadPool Pool(llvm::hardware_concurrency(NumThreads));
std::vector<std::unique_ptr<DependencyScanningTool>> WorkerTools;
for (unsigned I = 0; I < Pool.getThreadCount(); ++I)