Skip to content

Commit aca254a

Browse files
committed
[clang][DependencyScanning] Track modules that resolve from sysroot.
That patch tracks whether all the file & module dependencies of a module resolve to a sysroot location. This information will later be queried by build systems for determining where to store the accompanying pcms.
1 parent 21ff15f commit aca254a

File tree

4 files changed

+139
-2
lines changed

4 files changed

+139
-2
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ struct ModuleDeps {
114114
/// Whether this is a "system" module.
115115
bool IsSystem;
116116

117+
/// Whether this is a module where it's dependencies resolve within the
118+
/// sysroot.
119+
bool IsInSysroot;
120+
117121
/// The path to the modulemap file which defines this module.
118122
///
119123
/// This can be used to explicitly build this module. This file will
@@ -219,6 +223,9 @@ class ModuleDepCollectorPP final : public PPCallbacks {
219223
llvm::DenseSet<const Module *> &AddedModules);
220224
void addAffectingClangModule(const Module *M, ModuleDeps &MD,
221225
llvm::DenseSet<const Module *> &AddedModules);
226+
227+
/// Add discovered module dependency for the given module.
228+
void addClangModule(const Module *M, const ModuleID ID, ModuleDeps &MD);
222229
};
223230

224231
/// Collects modular and non-modular dependencies of the main file by attaching

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,15 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
698698

699699
MD.ID.ModuleName = M->getFullModuleName();
700700
MD.IsSystem = M->IsSystem;
701+
702+
// Start off with the assumption that this module is in the sysroot when there
703+
// is a sysroot provided. As more dependencies are discovered, check if those
704+
// come from the provided sysroot.
705+
const StringRef CurrSysroot = MDC.ScanInstance.getHeaderSearchOpts().Sysroot;
706+
MD.IsInSysroot =
707+
!CurrSysroot.empty() &&
708+
(llvm::sys::path::root_directory(CurrSysroot) != CurrSysroot);
709+
701710
// For modules which use export_as link name, the linked product that of the
702711
// corresponding export_as-named module.
703712
if (!M->UseExportAsModuleLinkName)
@@ -739,6 +748,11 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
739748
MDC.ScanInstance.getASTReader()->visitInputFileInfos(
740749
*MF, /*IncludeSystem=*/true,
741750
[&](const serialization::InputFileInfo &IFI, bool IsSystem) {
751+
auto FullFilePath = ASTReader::ResolveImportedPath(
752+
PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory);
753+
if (MD.IsInSysroot)
754+
MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot);
755+
PathBuf.resize_for_overwrite(256);
742756
if (!(IFI.TopLevel && IFI.ModuleMap))
743757
return;
744758
if (IFI.UnresolvedImportedFilenameAsRequested.ends_with(
@@ -835,6 +849,13 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps(
835849
});
836850
}
837851

852+
void ModuleDepCollectorPP::addClangModule(const Module *M, const ModuleID ID,
853+
ModuleDeps &MD) {
854+
MD.ClangModuleDeps.push_back(ID);
855+
if (MD.IsInSysroot)
856+
MD.IsInSysroot = MDC.ModularDeps[M]->IsInSysroot;
857+
}
858+
838859
void ModuleDepCollectorPP::addModuleDep(
839860
const Module *M, ModuleDeps &MD,
840861
llvm::DenseSet<const Module *> &AddedModules) {
@@ -843,7 +864,7 @@ void ModuleDepCollectorPP::addModuleDep(
843864
!MDC.isPrebuiltModule(Import)) {
844865
if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
845866
if (AddedModules.insert(Import->getTopLevelModule()).second)
846-
MD.ClangModuleDeps.push_back(*ImportID);
867+
addClangModule(Import->getTopLevelModule(), *ImportID, MD);
847868
}
848869
}
849870
}
@@ -867,7 +888,7 @@ void ModuleDepCollectorPP::addAffectingClangModule(
867888
!MDC.isPrebuiltModule(Affecting)) {
868889
if (auto ImportID = handleTopLevelModule(Affecting))
869890
if (AddedModules.insert(Affecting).second)
870-
MD.ClangModuleDeps.push_back(*ImportID);
891+
addClangModule(Affecting, *ImportID, MD);
871892
}
872893
}
873894
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// This test verifies modules that are entirely comprised from sysroot inputs are captured in
2+
// dependency information.
3+
4+
// The first compilation verifies that transitive dependencies on non-sysroot input are captured.
5+
// The second compilation verifies that external paths are resolved when a vfsoverlay is applied when considering sysroot-ness.
6+
7+
// RUN: rm -rf %t
8+
// RUN: split-file %s %t
9+
// RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > %t/compile-commands.json
10+
// RUN: sed -e "s|DIR|%/t|g" %t/overlay.json.template > %t/overlay.json
11+
// RUN: clang-scan-deps -compilation-database %t/compile-commands.json \
12+
// RUN: -j 1 -format experimental-full > %t/deps.db
13+
// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
14+
15+
// CHECK: "modules": [
16+
// CHECK-NEXT: {
17+
// CHECK: "is-in-sysroot": true,
18+
// CHECK: "name": "A"
19+
20+
// Verify that there are no more occurances of sysroot.
21+
// CHECK-NOT: "is-in-sysroot"
22+
23+
// CHECK: "name": "A"
24+
// CHECK: "USE_VFS"
25+
// CHECK: "name": "B"
26+
// CHECK: "name": "C"
27+
// CHECK: "name": "D"
28+
// CHECK: "name": "NotInSDK"
29+
30+
//--- compile-commands.json.in
31+
[
32+
{
33+
"directory": "DIR",
34+
"command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk -I DIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
35+
"file": "DIR/client.m"
36+
},
37+
{
38+
"directory": "DIR",
39+
"command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk -ivfsoverlay DIR/overlay.json -DUSE_VFS -I DIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
40+
"file": "DIR/client.m"
41+
}
42+
]
43+
44+
//--- overlay.json.template
45+
{
46+
"version": 0,
47+
"case-sensitive": "false",
48+
"roots": [
49+
{
50+
"external-contents": "DIR/local/A/A_vfs.h",
51+
"name": "DIR/MacOSX.sdk/usr/include/A/A_vfs.h",
52+
"type": "file"
53+
}
54+
]
55+
}
56+
57+
//--- MacOSX.sdk/usr/include/A/module.modulemap
58+
module A {
59+
umbrella "."
60+
}
61+
62+
//--- MacOSX.sdk/usr/include/A/A.h
63+
#ifdef USE_VFS
64+
#include <A/A_vfs.h>
65+
#endif
66+
typedef int A_t;
67+
68+
//--- local/A/A_vfs.h
69+
typedef int typeFromVFS;
70+
71+
//--- MacOSX.sdk/usr/include/B/module.modulemap
72+
module B [system] {
73+
umbrella "."
74+
}
75+
76+
//--- MacOSX.sdk/usr/include/B/B.h
77+
#include <C/C.h>
78+
typedef int B_t;
79+
80+
//--- MacOSX.sdk/usr/include/C/module.modulemap
81+
module C [system] {
82+
umbrella "."
83+
}
84+
85+
//--- MacOSX.sdk/usr/include/C/C.h
86+
#include <D/D.h>
87+
88+
//--- MacOSX.sdk/usr/include/D/module.modulemap
89+
module D [system] {
90+
umbrella "."
91+
}
92+
93+
// Simulate a header that will be resolved in a local directory, from a sysroot header.
94+
//--- MacOSX.sdk/usr/include/D/D.h
95+
#include <HeaderNotFoundInSDK.h>
96+
97+
//--- BuildDir/module.modulemap
98+
module NotInSDK [system] {
99+
umbrella "."
100+
}
101+
102+
//--- BuildDir/HeaderNotFoundInSDK.h
103+
typedef int local_t;
104+
105+
//--- client.m
106+
#include <A/A.h>
107+
#include <B/B.h>

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,8 @@ class FullDeps {
471471
for (auto &&ModID : ModuleIDs) {
472472
auto &MD = Modules[ModID];
473473
JOS.object([&] {
474+
if (MD.IsInSysroot)
475+
JOS.attribute("is-in-sysroot", MD.IsInSysroot);
474476
JOS.attributeArray("clang-module-deps",
475477
toJSONSorted(JOS, MD.ClangModuleDeps));
476478
JOS.attribute("clang-modulemap-file",

0 commit comments

Comments
 (0)