Skip to content

Commit 01f9dd6

Browse files
authored
Merge pull request #10124 from qiongsiwu/cherry_pick_fix_145249881
[clang modules] Setting `DebugCompilationDir` when it is safe to ignore current working directory (llvm#128446)
2 parents c9ced05 + 3599451 commit 01f9dd6

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ class ModuleDepCollector final : public DependencyCollector {
329329

330330
/// Compute the context hash for \p Deps, and create the mapping
331331
/// \c ModuleDepsByID[Deps.ID] = &Deps.
332-
void associateWithContextHash(const CowCompilerInvocation &CI,
332+
void associateWithContextHash(const CowCompilerInvocation &CI, bool IgnoreCWD,
333333
ModuleDeps &Deps);
334334
};
335335

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,34 @@ static void optimizeDiagnosticOpts(DiagnosticOptions &Opts,
134134
Opts.Remarks.clear();
135135
}
136136

137+
static void optimizeCWD(CowCompilerInvocation &BuildInvocation, StringRef CWD) {
138+
BuildInvocation.getMutFileSystemOpts().WorkingDir.clear();
139+
if (BuildInvocation.getCodeGenOpts().DwarfVersion) {
140+
// It is necessary to explicitly set the DebugCompilationDir
141+
// to a common directory (e.g. root) if IgnoreCWD is true.
142+
// When IgnoreCWD is true, the module's content should not
143+
// depend on the current working directory. However, if dwarf
144+
// information is needed (when CGOpts.DwarfVersion is
145+
// non-zero), then CGOpts.DebugCompilationDir must be
146+
// populated, because otherwise the current working directory
147+
// will be automatically embedded in the dwarf information in
148+
// the pcm, contradicting the assumption that it is safe to
149+
// ignore the CWD. Thus in such cases,
150+
// CGOpts.DebugCompilationDir is explicitly set to a common
151+
// directory.
152+
// FIXME: It is still excessive to create a copy of
153+
// CodeGenOpts for each module. Since we do not modify the
154+
// CodeGenOpts otherwise per module, the following code
155+
// ends up generating identical CodeGenOpts for each module
156+
// with DebugCompilationDir pointing to the root directory.
157+
// We can optimize this away by creating a _single_ copy of
158+
// CodeGenOpts whose DebugCompilationDir points to the root
159+
// directory and reuse it across modules.
160+
BuildInvocation.getMutCodeGenOpts().DebugCompilationDir =
161+
llvm::sys::path::root_path(CWD);
162+
}
163+
}
164+
137165
static std::vector<std::string> splitString(std::string S, char Separator) {
138166
SmallVector<StringRef> Segments;
139167
StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
@@ -534,14 +562,12 @@ static std::string getModuleContextHash(const ModuleDeps &MD,
534562
HashBuilder.add(getClangFullRepositoryVersion());
535563
HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
536564
llvm::ErrorOr<std::string> CWD = VFS.getCurrentWorkingDirectory();
537-
auto &FSOpts = const_cast<FileSystemOptions &>(CI.getFileSystemOpts());
538565
if (CWD && !IgnoreCWD)
539566
HashBuilder.add(*CWD);
540-
else
541-
FSOpts.WorkingDir.clear();
542567

543568
// Save and restore options that should not affect the hash, e.g. the exact
544569
// contents of input files, or prefix mappings.
570+
auto &FSOpts = const_cast<FileSystemOptions &>(CI.getFileSystemOpts());
545571
auto &FEOpts = const_cast<FrontendOptions &>(CI.getFrontendOpts());
546572
auto &CASOpts = const_cast<CASOptions &>(CI.getCASOpts());
547573
llvm::SaveAndRestore RestoreCASFSRootID(FSOpts.CASFileSystemRootID, {});
@@ -594,9 +620,7 @@ static void checkCompileCacheKeyMatch(cas::ObjectStore &CAS,
594620
#endif
595621

596622
void ModuleDepCollector::associateWithContextHash(
597-
const CowCompilerInvocation &CI, ModuleDeps &Deps) {
598-
bool IgnoreCWD = any(OptimizeArgs & ScanningOptimizations::IgnoreCWD) &&
599-
isSafeToIgnoreCWD(CI);
623+
const CowCompilerInvocation &CI, bool IgnoreCWD, ModuleDeps &Deps) {
600624
Deps.ID.ContextHash =
601625
getModuleContextHash(Deps, CI, EagerLoadModules, IgnoreCWD,
602626
ScanInstance.getVirtualFileSystem());
@@ -810,6 +834,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
810834
}
811835
}
812836

837+
bool IgnoreCWD = false;
813838
CowCompilerInvocation CI =
814839
MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
815840
MD, [&](CowCompilerInvocation &BuildInvocation) {
@@ -819,10 +844,22 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
819844
*MDC.ScanInstance.getASTReader(), *MF,
820845
MDC.PrebuiltModuleVFSMap,
821846
MDC.OptimizeArgs);
847+
822848
if (any(MDC.OptimizeArgs & ScanningOptimizations::SystemWarnings))
823849
optimizeDiagnosticOpts(
824850
BuildInvocation.getMutDiagnosticOpts(),
825851
BuildInvocation.getFrontendOpts().IsSystemModule);
852+
853+
IgnoreCWD =
854+
any(MDC.OptimizeArgs & ScanningOptimizations::IgnoreCWD) &&
855+
isSafeToIgnoreCWD(BuildInvocation);
856+
if (IgnoreCWD) {
857+
llvm::ErrorOr<std::string> CWD =
858+
MDC.ScanInstance.getVirtualFileSystem()
859+
.getCurrentWorkingDirectory();
860+
if (CWD)
861+
optimizeCWD(BuildInvocation, *CWD);
862+
}
826863
});
827864

828865
auto &Diags = MDC.ScanInstance.getDiagnostics();
@@ -837,7 +874,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
837874
MD.ModuleCacheKey = Key->toString();
838875
}
839876

840-
MDC.associateWithContextHash(CI, MD);
877+
MDC.associateWithContextHash(CI, IgnoreCWD, MD);
841878

842879
// Finish the compiler invocation. Requires dependencies and the context hash.
843880
MDC.addOutputPaths(CI, MD);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// REQUIRES: shell
2+
3+
// RUN: rm -rf %t
4+
// RUN: split-file %s %t
5+
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json
6+
// RUN: clang-scan-deps -compilation-database %t/cdb.json -format \
7+
// RUN: experimental-full > %t/result.json
8+
// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck %s
9+
10+
//--- cdb.json.in
11+
[{
12+
"directory": "DIR",
13+
"command": "clang -c -g -gmodules DIR/tu.c -fmodules -fmodules-cache-path=DIR/cache -IDIR/include/ -fdebug-compilation-dir=DIR -o DIR/tu.o",
14+
"file": "DIR/tu.c"
15+
}]
16+
17+
//--- include/module.modulemap
18+
module mod {
19+
header "mod.h"
20+
}
21+
22+
//--- include/mod.h
23+
24+
//--- tu.c
25+
#include "mod.h"
26+
27+
// Check the -fdebug-compilation-dir used for the module is the root
28+
// directory when current working directory optimization is in effect.
29+
// CHECK: "modules": [
30+
// CHECK: "command-line": [
31+
// CHECK: "-fdebug-compilation-dir={{\/|.*:(\\)?}}",
32+
// CHECK: "translation-units": [

0 commit comments

Comments
 (0)