https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/130634
>From aca254a154489fda68292f6d06a866ae7011a7f6 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida <cyndy_ish...@apple.com> Date: Mon, 10 Mar 2025 09:06:32 -0700 Subject: [PATCH 1/4] [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. --- .../DependencyScanning/ModuleDepCollector.h | 7 ++ .../DependencyScanning/ModuleDepCollector.cpp | 25 +++- clang/test/ClangScanDeps/modules-in-sysroot.c | 107 ++++++++++++++++++ clang/tools/clang-scan-deps/ClangScanDeps.cpp | 2 + 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 clang/test/ClangScanDeps/modules-in-sysroot.c diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h index 20fb4de6a2a73..6187f0168e6d9 100644 --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -114,6 +114,10 @@ struct ModuleDeps { /// Whether this is a "system" module. bool IsSystem; + /// Whether this is a module where it's dependencies resolve within the + /// sysroot. + bool IsInSysroot; + /// The path to the modulemap file which defines this module. /// /// This can be used to explicitly build this module. This file will @@ -219,6 +223,9 @@ class ModuleDepCollectorPP final : public PPCallbacks { llvm::DenseSet<const Module *> &AddedModules); void addAffectingClangModule(const Module *M, ModuleDeps &MD, llvm::DenseSet<const Module *> &AddedModules); + + /// Add discovered module dependency for the given module. + void addClangModule(const Module *M, const ModuleID ID, ModuleDeps &MD); }; /// Collects modular and non-modular dependencies of the main file by attaching diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 36b75c1016cd8..86eda34472cf0 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -698,6 +698,15 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MD.ID.ModuleName = M->getFullModuleName(); MD.IsSystem = M->IsSystem; + + // Start off with the assumption that this module is in the sysroot when there + // is a sysroot provided. As more dependencies are discovered, check if those + // come from the provided sysroot. + const StringRef CurrSysroot = MDC.ScanInstance.getHeaderSearchOpts().Sysroot; + MD.IsInSysroot = + !CurrSysroot.empty() && + (llvm::sys::path::root_directory(CurrSysroot) != CurrSysroot); + // For modules which use export_as link name, the linked product that of the // corresponding export_as-named module. if (!M->UseExportAsModuleLinkName) @@ -739,6 +748,11 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MDC.ScanInstance.getASTReader()->visitInputFileInfos( *MF, /*IncludeSystem=*/true, [&](const serialization::InputFileInfo &IFI, bool IsSystem) { + auto FullFilePath = ASTReader::ResolveImportedPath( + PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory); + if (MD.IsInSysroot) + MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot); + PathBuf.resize_for_overwrite(256); if (!(IFI.TopLevel && IFI.ModuleMap)) return; if (IFI.UnresolvedImportedFilenameAsRequested.ends_with( @@ -835,6 +849,13 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps( }); } +void ModuleDepCollectorPP::addClangModule(const Module *M, const ModuleID ID, + ModuleDeps &MD) { + MD.ClangModuleDeps.push_back(ID); + if (MD.IsInSysroot) + MD.IsInSysroot = MDC.ModularDeps[M]->IsInSysroot; +} + void ModuleDepCollectorPP::addModuleDep( const Module *M, ModuleDeps &MD, llvm::DenseSet<const Module *> &AddedModules) { @@ -843,7 +864,7 @@ void ModuleDepCollectorPP::addModuleDep( !MDC.isPrebuiltModule(Import)) { if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule())) if (AddedModules.insert(Import->getTopLevelModule()).second) - MD.ClangModuleDeps.push_back(*ImportID); + addClangModule(Import->getTopLevelModule(), *ImportID, MD); } } } @@ -867,7 +888,7 @@ void ModuleDepCollectorPP::addAffectingClangModule( !MDC.isPrebuiltModule(Affecting)) { if (auto ImportID = handleTopLevelModule(Affecting)) if (AddedModules.insert(Affecting).second) - MD.ClangModuleDeps.push_back(*ImportID); + addClangModule(Affecting, *ImportID, MD); } } } diff --git a/clang/test/ClangScanDeps/modules-in-sysroot.c b/clang/test/ClangScanDeps/modules-in-sysroot.c new file mode 100644 index 0000000000000..d96aa69c0e8f4 --- /dev/null +++ b/clang/test/ClangScanDeps/modules-in-sysroot.c @@ -0,0 +1,107 @@ +// This test verifies modules that are entirely comprised from sysroot inputs are captured in +// dependency information. + +// The first compilation verifies that transitive dependencies on non-sysroot input are captured. +// The second compilation verifies that external paths are resolved when a vfsoverlay is applied when considering sysroot-ness. + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > %t/compile-commands.json +// RUN: sed -e "s|DIR|%/t|g" %t/overlay.json.template > %t/overlay.json +// RUN: clang-scan-deps -compilation-database %t/compile-commands.json \ +// RUN: -j 1 -format experimental-full > %t/deps.db +// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t + +// CHECK: "modules": [ +// CHECK-NEXT: { +// CHECK: "is-in-sysroot": true, +// CHECK: "name": "A" + +// Verify that there are no more occurances of sysroot. +// CHECK-NOT: "is-in-sysroot" + +// CHECK: "name": "A" +// CHECK: "USE_VFS" +// CHECK: "name": "B" +// CHECK: "name": "C" +// CHECK: "name": "D" +// CHECK: "name": "NotInSDK" + +//--- compile-commands.json.in +[ +{ + "directory": "DIR", + "command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk -I DIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", + "file": "DIR/client.m" +}, +{ + "directory": "DIR", + "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", + "file": "DIR/client.m" +} +] + +//--- overlay.json.template +{ + "version": 0, + "case-sensitive": "false", + "roots": [ + { + "external-contents": "DIR/local/A/A_vfs.h", + "name": "DIR/MacOSX.sdk/usr/include/A/A_vfs.h", + "type": "file" + } + ] +} + +//--- MacOSX.sdk/usr/include/A/module.modulemap +module A { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/A/A.h +#ifdef USE_VFS +#include <A/A_vfs.h> +#endif +typedef int A_t; + +//--- local/A/A_vfs.h +typedef int typeFromVFS; + +//--- MacOSX.sdk/usr/include/B/module.modulemap +module B [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/B/B.h +#include <C/C.h> +typedef int B_t; + +//--- MacOSX.sdk/usr/include/C/module.modulemap +module C [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/C/C.h +#include <D/D.h> + +//--- MacOSX.sdk/usr/include/D/module.modulemap +module D [system] { + umbrella "." +} + +// Simulate a header that will be resolved in a local directory, from a sysroot header. +//--- MacOSX.sdk/usr/include/D/D.h +#include <HeaderNotFoundInSDK.h> + +//--- BuildDir/module.modulemap +module NotInSDK [system] { + umbrella "." +} + +//--- BuildDir/HeaderNotFoundInSDK.h +typedef int local_t; + +//--- client.m +#include <A/A.h> +#include <B/B.h> diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 3bdeb461e4bfa..f5946b30fb84d 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -471,6 +471,8 @@ class FullDeps { for (auto &&ModID : ModuleIDs) { auto &MD = Modules[ModID]; JOS.object([&] { + if (MD.IsInSysroot) + JOS.attribute("is-in-sysroot", MD.IsInSysroot); JOS.attributeArray("clang-module-deps", toJSONSorted(JOS, MD.ClangModuleDeps)); JOS.attribute("clang-modulemap-file", >From fd4abaa6c8097694fe1fad2510beb6b11653f01f Mon Sep 17 00:00:00 2001 From: Cyndy Ishida <cyndy_ish...@apple.com> Date: Mon, 10 Mar 2025 13:39:42 -0700 Subject: [PATCH 2/4] Add explicit search paths into SDK as they aren't passed with non-darwin targets --- clang/test/ClangScanDeps/modules-in-sysroot.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/test/ClangScanDeps/modules-in-sysroot.c b/clang/test/ClangScanDeps/modules-in-sysroot.c index d96aa69c0e8f4..2ecf9c293b23d 100644 --- a/clang/test/ClangScanDeps/modules-in-sysroot.c +++ b/clang/test/ClangScanDeps/modules-in-sysroot.c @@ -4,6 +4,7 @@ // The first compilation verifies that transitive dependencies on non-sysroot input are captured. // The second compilation verifies that external paths are resolved when a vfsoverlay is applied when considering sysroot-ness. +// REQUIRES: shell // RUN: rm -rf %t // RUN: split-file %s %t // RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > %t/compile-commands.json @@ -31,13 +32,13 @@ [ { "directory": "DIR", - "command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk -I DIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", - "file": "DIR/client.m" + "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk -IDIR/MacOSX.sdk/usr/include -IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", + "file": "DIR/client.c" }, { "directory": "DIR", - "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", - "file": "DIR/client.m" + "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk -IDIR/MacOSX.sdk/usr/include -ivfsoverlay DIR/overlay.json -DUSE_VFS -IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", + "file": "DIR/client.c" } ] @@ -102,6 +103,6 @@ module NotInSDK [system] { //--- BuildDir/HeaderNotFoundInSDK.h typedef int local_t; -//--- client.m +//--- client.c #include <A/A.h> #include <B/B.h> >From 032d7f84a0bf3647dba8633993ed1cbf1653b0bc Mon Sep 17 00:00:00 2001 From: Cyndy Ishida <cyndy_ish...@apple.com> Date: Thu, 13 Mar 2025 23:27:12 -0700 Subject: [PATCH 3/4] Address review comments except for prebuilt module dependencies --- .../Tooling/DependencyScanning/ModuleDepCollector.h | 8 ++++++-- .../Tooling/DependencyScanning/ModuleDepCollector.cpp | 9 +++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h index 6187f0168e6d9..b0eed8a85a9c6 100644 --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -114,8 +114,12 @@ struct ModuleDeps { /// Whether this is a "system" module. bool IsSystem; - /// Whether this is a module where it's dependencies resolve within the - /// sysroot. + /// Whether this module is fully composed of file & module inputs from the + /// sysroot. External paths, as opposed to virtual file paths, are always used + /// for computing this value. + /// + /// This attribute is useful for identifying modules that are unlikely to + /// change under an active development and build cycle. bool IsInSysroot; /// The path to the modulemap file which defines this module. diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 86eda34472cf0..2f9939d4ac3c8 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -748,11 +748,12 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MDC.ScanInstance.getASTReader()->visitInputFileInfos( *MF, /*IncludeSystem=*/true, [&](const serialization::InputFileInfo &IFI, bool IsSystem) { - auto FullFilePath = ASTReader::ResolveImportedPath( - PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory); - if (MD.IsInSysroot) + if (MD.IsInSysroot) { + auto FullFilePath = ASTReader::ResolveImportedPath( + PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory); MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot); - PathBuf.resize_for_overwrite(256); + PathBuf.resize_for_overwrite(256); + } if (!(IFI.TopLevel && IFI.ModuleMap)) return; if (IFI.UnresolvedImportedFilenameAsRequested.ends_with( >From 175e9ce016dbcef19de98bfdc5d82118fca72592 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida <cyndy_ish...@apple.com> Date: Fri, 14 Mar 2025 18:00:16 -0700 Subject: [PATCH 4/4] Update IsInSysroot -> IsShareable * We need to track more than just sysroot, so start with sysroot and resource directory as a starting point, but allow the ability to capture more as they are discovered in the future. * Check a subset of the compiler invocation of module compilations for determining if a module can be shared. * When a module has a prebuilt module dependency, consider is not shareable for now. --- .../DependencyScanning/ModuleDepCollector.h | 20 +-- .../DependencyScanning/ModuleDepCollector.cpp | 86 ++++++++++--- ...-in-sysroot.c => modules-in-shared-dirs.c} | 37 +++--- .../prebuilt-modules-in-shared-dirs.c | 114 ++++++++++++++++++ clang/tools/clang-scan-deps/ClangScanDeps.cpp | 4 +- 5 files changed, 219 insertions(+), 42 deletions(-) rename clang/test/ClangScanDeps/{modules-in-sysroot.c => modules-in-shared-dirs.c} (63%) create mode 100644 clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h index b0eed8a85a9c6..cab4c6771666e 100644 --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -114,13 +114,13 @@ struct ModuleDeps { /// Whether this is a "system" module. bool IsSystem; - /// Whether this module is fully composed of file & module inputs from the - /// sysroot. External paths, as opposed to virtual file paths, are always used - /// for computing this value. + /// Whether this module is fully composed of file & module inputs from + /// locations likely to stay the same across the active development and build + /// cycle. For example, when all those input paths only resolve in Sysroot. /// - /// This attribute is useful for identifying modules that are unlikely to - /// change under an active development and build cycle. - bool IsInSysroot; + /// External paths, as opposed to virtual file paths, are always used + /// for computing this value. + bool IsShareable; /// The path to the modulemap file which defines this module. /// @@ -229,7 +229,7 @@ class ModuleDepCollectorPP final : public PPCallbacks { llvm::DenseSet<const Module *> &AddedModules); /// Add discovered module dependency for the given module. - void addClangModule(const Module *M, const ModuleID ID, ModuleDeps &MD); + void addOneModuleDep(const Module *M, const ModuleID ID, ModuleDeps &MD); }; /// Collects modular and non-modular dependencies of the main file by attaching @@ -331,6 +331,12 @@ void resetBenignCodeGenOptions(frontend::ActionKind ProgramAction, const LangOptions &LangOpts, CodeGenOptions &CGOpts); +/// Determine if \c Input can be resolved within a shared location. +/// +/// \param Directories Paths known to be in a shared location. e.g. Sysroot. +/// \param Input Path to evaluate. +bool isPathInSharedDir(ArrayRef<StringRef> Directories, const StringRef Input); + } // end namespace dependencies } // end namespace tooling } // end namespace clang diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 2f9939d4ac3c8..05ca7718cb99e 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -157,6 +157,32 @@ static void optimizeCWD(CowCompilerInvocation &BuildInvocation, StringRef CWD) { } } +/// Check a subset of invocation options to determine whether the current +/// context can safely be considered as shareable. +static bool areOptionsInSharedDir(CowCompilerInvocation &BuildInvocation, + const ArrayRef<StringRef> SharedDirs) { + const auto &HSOpts = BuildInvocation.getHeaderSearchOpts(); + if (!isPathInSharedDir(SharedDirs, HSOpts.Sysroot)) + return false; + + if (!isPathInSharedDir(SharedDirs, HSOpts.ResourceDir)) + return false; + + for (const auto &Entry : HSOpts.UserEntries) { + if (!Entry.IgnoreSysRoot) + continue; + if (!isPathInSharedDir(SharedDirs, Entry.Path)) + return false; + } + + for (const auto &SysPrefix : HSOpts.SystemHeaderPrefixes) { + if (!isPathInSharedDir(SharedDirs, SysPrefix.Prefix)) + return false; + } + + return true; +} + static std::vector<std::string> splitString(std::string S, char Separator) { SmallVector<StringRef> Segments; StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false); @@ -212,6 +238,25 @@ void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction, } } +bool dependencies::isPathInSharedDir(ArrayRef<StringRef> Directories, + const StringRef Input) { + auto PathStartsWith = [](StringRef Prefix, StringRef Path) { + auto PrefixIt = llvm::sys::path::begin(Prefix), + PrefixEnd = llvm::sys::path::end(Prefix); + for (auto PathIt = llvm::sys::path::begin(Path), + PathEnd = llvm::sys::path::end(Path); + PrefixIt != PrefixEnd && PathIt != PathEnd; ++PrefixIt, ++PathIt) { + if (*PrefixIt != *PathIt) + return false; + } + return PrefixIt == PrefixEnd; + }; + + return any_of(Directories, [&](StringRef Dir) { + return !Dir.empty() && PathStartsWith(Dir, Input); + }); +} + static CowCompilerInvocation makeCommonInvocationForModuleBuild(CompilerInvocation CI) { CI.resetNonModularOptions(); @@ -699,13 +744,15 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MD.ID.ModuleName = M->getFullModuleName(); MD.IsSystem = M->IsSystem; - // Start off with the assumption that this module is in the sysroot when there + // Start off with the assumption that this module is shareable when there // is a sysroot provided. As more dependencies are discovered, check if those - // come from the provided sysroot. - const StringRef CurrSysroot = MDC.ScanInstance.getHeaderSearchOpts().Sysroot; - MD.IsInSysroot = - !CurrSysroot.empty() && - (llvm::sys::path::root_directory(CurrSysroot) != CurrSysroot); + // come from the provided shared directories. + const llvm::SmallVector<StringRef> SharedDirs = { + MDC.ScanInstance.getHeaderSearchOpts().Sysroot, + MDC.ScanInstance.getHeaderSearchOpts().ResourceDir}; + MD.IsShareable = + !SharedDirs[0].empty() && + (llvm::sys::path::root_directory(SharedDirs[0]) != SharedDirs[0]); // For modules which use export_as link name, the linked product that of the // corresponding export_as-named module. @@ -748,10 +795,10 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MDC.ScanInstance.getASTReader()->visitInputFileInfos( *MF, /*IncludeSystem=*/true, [&](const serialization::InputFileInfo &IFI, bool IsSystem) { - if (MD.IsInSysroot) { + if (MD.IsShareable) { auto FullFilePath = ASTReader::ResolveImportedPath( PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory); - MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot); + MD.IsShareable = isPathInSharedDir(SharedDirs, *FullFilePath); PathBuf.resize_for_overwrite(256); } if (!(IFI.TopLevel && IFI.ModuleMap)) @@ -795,6 +842,10 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { } }); + // Check provided input paths from the invocation for determining IsShareable. + if (MD.IsShareable) + MD.IsShareable = areOptionsInSharedDir(CI, SharedDirs); + MDC.associateWithContextHash(CI, IgnoreCWD, MD); // Finish the compiler invocation. Requires dependencies and the context hash. @@ -836,8 +887,13 @@ void ModuleDepCollectorPP::addModulePrebuiltDeps( for (const Module *Import : M->Imports) if (Import->getTopLevelModule() != M->getTopLevelModule()) if (MDC.isPrebuiltModule(Import->getTopLevelModule())) - if (SeenSubmodules.insert(Import->getTopLevelModule()).second) + if (SeenSubmodules.insert(Import->getTopLevelModule()).second) { MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); + // Conservatively consider the module as not shareable, + // as transitive dependencies from the prebuilt module have not been + // determined. + MD.IsShareable = false; + } } void ModuleDepCollectorPP::addAllSubmoduleDeps( @@ -850,11 +906,11 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps( }); } -void ModuleDepCollectorPP::addClangModule(const Module *M, const ModuleID ID, - ModuleDeps &MD) { +void ModuleDepCollectorPP::addOneModuleDep(const Module *M, const ModuleID ID, + ModuleDeps &MD) { MD.ClangModuleDeps.push_back(ID); - if (MD.IsInSysroot) - MD.IsInSysroot = MDC.ModularDeps[M]->IsInSysroot; + if (MD.IsShareable) + MD.IsShareable = MDC.ModularDeps[M]->IsShareable; } void ModuleDepCollectorPP::addModuleDep( @@ -865,7 +921,7 @@ void ModuleDepCollectorPP::addModuleDep( !MDC.isPrebuiltModule(Import)) { if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule())) if (AddedModules.insert(Import->getTopLevelModule()).second) - addClangModule(Import->getTopLevelModule(), *ImportID, MD); + addOneModuleDep(Import->getTopLevelModule(), *ImportID, MD); } } } @@ -889,7 +945,7 @@ void ModuleDepCollectorPP::addAffectingClangModule( !MDC.isPrebuiltModule(Affecting)) { if (auto ImportID = handleTopLevelModule(Affecting)) if (AddedModules.insert(Affecting).second) - addClangModule(Affecting, *ImportID, MD); + addOneModuleDep(Affecting, *ImportID, MD); } } } diff --git a/clang/test/ClangScanDeps/modules-in-sysroot.c b/clang/test/ClangScanDeps/modules-in-shared-dirs.c similarity index 63% rename from clang/test/ClangScanDeps/modules-in-sysroot.c rename to clang/test/ClangScanDeps/modules-in-shared-dirs.c index 2ecf9c293b23d..bce927f866268 100644 --- a/clang/test/ClangScanDeps/modules-in-sysroot.c +++ b/clang/test/ClangScanDeps/modules-in-shared-dirs.c @@ -1,8 +1,9 @@ -// This test verifies modules that are entirely comprised from sysroot inputs are captured in +// This test verifies modules that are entirely comprised from shared directory inputs are captured in // dependency information. -// The first compilation verifies that transitive dependencies on non-sysroot input are captured. -// The second compilation verifies that external paths are resolved when a vfsoverlay is applied when considering sysroot-ness. +// The first compilation verifies that transitive dependencies on local input are captured. +// The second compilation verifies that external paths are resolved when a +// vfsoverlay for determining is-shareable. // REQUIRES: shell // RUN: rm -rf %t @@ -15,11 +16,11 @@ // CHECK: "modules": [ // CHECK-NEXT: { -// CHECK: "is-in-sysroot": true, +// CHECK: "is-shareable": true, // CHECK: "name": "A" // Verify that there are no more occurances of sysroot. -// CHECK-NOT: "is-in-sysroot" +// CHECK-NOT: "is-shareable" // CHECK: "name": "A" // CHECK: "USE_VFS" @@ -32,12 +33,12 @@ [ { "directory": "DIR", - "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk -IDIR/MacOSX.sdk/usr/include -IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", + "command": "clang -c DIR/client.c -isysroot DIR/Sysroot -IDIR/Sysroot/usr/include -IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", "file": "DIR/client.c" }, { "directory": "DIR", - "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk -IDIR/MacOSX.sdk/usr/include -ivfsoverlay DIR/overlay.json -DUSE_VFS -IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", + "command": "clang -c DIR/client.c -isysroot DIR/Sysroot -IDIR/Sysroot/usr/include -ivfsoverlay DIR/overlay.json -DUSE_VFS -IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps", "file": "DIR/client.c" } ] @@ -48,51 +49,51 @@ "case-sensitive": "false", "roots": [ { - "external-contents": "DIR/local/A/A_vfs.h", - "name": "DIR/MacOSX.sdk/usr/include/A/A_vfs.h", + "external-contents": "DIR/SysrootButNotReally/A/A_vfs.h", + "name": "DIR/Sysroot/usr/include/A/A_vfs.h", "type": "file" } ] } -//--- MacOSX.sdk/usr/include/A/module.modulemap +//--- Sysroot/usr/include/A/module.modulemap module A { umbrella "." } -//--- MacOSX.sdk/usr/include/A/A.h +//--- Sysroot/usr/include/A/A.h #ifdef USE_VFS #include <A/A_vfs.h> #endif typedef int A_t; -//--- local/A/A_vfs.h +//--- SysrootButNotReally/A/A_vfs.h typedef int typeFromVFS; -//--- MacOSX.sdk/usr/include/B/module.modulemap +//--- Sysroot/usr/include/B/module.modulemap module B [system] { umbrella "." } -//--- MacOSX.sdk/usr/include/B/B.h +//--- Sysroot/usr/include/B/B.h #include <C/C.h> typedef int B_t; -//--- MacOSX.sdk/usr/include/C/module.modulemap +//--- Sysroot/usr/include/C/module.modulemap module C [system] { umbrella "." } -//--- MacOSX.sdk/usr/include/C/C.h +//--- Sysroot/usr/include/C/C.h #include <D/D.h> -//--- MacOSX.sdk/usr/include/D/module.modulemap +//--- Sysroot/usr/include/D/module.modulemap module D [system] { umbrella "." } // Simulate a header that will be resolved in a local directory, from a sysroot header. -//--- MacOSX.sdk/usr/include/D/D.h +//--- Sysroot/usr/include/D/D.h #include <HeaderNotFoundInSDK.h> //--- BuildDir/module.modulemap diff --git a/clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c b/clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c new file mode 100644 index 0000000000000..dc133bb376850 --- /dev/null +++ b/clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c @@ -0,0 +1,114 @@ +/// This test validates that modules that depend on prebuilt modules resolve `is-shareable` as false. + +// REQUIRES: shell +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|DIR|%/t|g" %t/overlay.json.template > %t/overlay.json +// RUN: sed -e "s|DIR|%/t|g" %t/compile-pch.json.in > %t/compile-pch.json +// RUN: clang-scan-deps -compilation-database %t/compile-pch.json \ +// RUN: -j 1 -format experimental-full > %t/deps_pch.db +// RUN: %clang -x c-header -c %t/prebuild.h -isysroot %t/MacOSX.sdk \ +// RUN: -I%t/BuildDir -ivfsoverlay %t/overlay.json \ +// RUN: -I %t/MacOSX.sdk/usr/include -fmodules -fmodules-cache-path=%t/module-cache \ +// RUN: -fimplicit-module-maps -o %t/prebuild.pch +// RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > %t/compile-commands.json +// RUN: clang-scan-deps -compilation-database %t/compile-commands.json \ +// RUN: -j 1 -format experimental-full > %t/deps.db +// RUN: cat %t/deps_pch.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefix PCH_DEP +// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t + +// PCH_DEP: "is-shareable": true +// PCH_DEP: "name": "A" + +// Verify is-shareable is not in any module dependencies, as they all depend on prebuilt modules. +// CHECK-NOT: "is-shareable" + +//--- compile-pch.json.in +[ +{ + "directory": "DIR", + "command": "clang -x c-header -c DIR/prebuild.h -isysroot DIR/MacOSX.sdk -IDIR/BuildDir -ivfsoverlay DIR/overlay.json -IDIR/MacOSX.sdk/usr/include -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps -o DIR/prebuild.pch", + "file": "DIR/prebuild.h" +} +] + +//--- compile-commands.json.in +[ +{ + "directory": "DIR", + "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk -IDIR/BuildDir -ivfsoverlay DIR/overlay.json -IDIR/MacOSX.sdk/usr/include -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps -include-pch DIR/prebuild.pch", + "file": "DIR/client.c" +} +] + +//--- overlay.json.template +{ + "version": 0, + "case-sensitive": "false", + "roots": [ + { + "external-contents": "DIR/BuildDir/B_vfs.h", + "name": "DIR/MacOSX.sdk/usr/include/B/B_vfs.h", + "type": "file" + } + ] +} + +//--- MacOSX.sdk/usr/include/A/module.modulemap +module A [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/A/A.h +typedef int A_type; + +//--- MacOSX.sdk/usr/include/B/module.modulemap +module B [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/B/B.h +#include <B/B_vfs.h> + +//--- BuildDir/B_vfs.h +typedef int local_t; + +//--- MacOSX.sdk/usr/include/sys/sys.h +typedef int sys_t_m; + +//--- MacOSX.sdk/usr/include/sys/module.modulemap +module sys [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/B_transitive/B.h +#include <B/B.h> + +//--- MacOSX.sdk/usr/include/B_transitive/module.modulemap +module B_transitive [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/C/module.modulemap +module C [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/C/C.h +#include <B_transitive/B.h> + + +//--- MacOSX.sdk/usr/include/D/module.modulemap +module D [system] { + umbrella "." +} + +//--- MacOSX.sdk/usr/include/D/D.h +#include <C/C.h> + +//--- prebuild.h +#include <A/A.h> +#include <C/C.h> // This dependency transitively depends on a local header. + +//--- client.c +#include <D/D.h> // This dependency transitively depends on a local header. diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index f5946b30fb84d..53f77e59999cf 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -471,8 +471,8 @@ class FullDeps { for (auto &&ModID : ModuleIDs) { auto &MD = Modules[ModID]; JOS.object([&] { - if (MD.IsInSysroot) - JOS.attribute("is-in-sysroot", MD.IsInSysroot); + if (MD.IsShareable) + JOS.attribute("is-shareable", MD.IsShareable); JOS.attributeArray("clang-module-deps", toJSONSorted(JOS, MD.ClangModuleDeps)); JOS.attribute("clang-modulemap-file", _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits