From a9e0a58b4667099286037003cef13b3217c92247 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 22 May 2025 09:28:27 -0700 Subject: [PATCH] [Dependency Scanning] Add ClangImporter's mandatory path remaps to dependency scanning query filesystem On creation, 'ClangImporter' adds overlay modulemap files for non-modular platform libraries (e.g. glibc, libstdc++), which allows Swift code to import and use those libraries. This change adds the same filesystem overlay to dependency scanning queries by applying them to the filesystem instantiated for each depndency scanning worker. Without these overlays EBM builds cannot discover and use non-modular system libraries on non-Darwin platforms. Resolves rdar://151780437 --- include/swift/AST/ModuleDependencies.h | 9 +-- include/swift/ClangImporter/ClangImporter.h | 11 +++- lib/AST/ModuleDependencies.cpp | 12 ++++ lib/ClangImporter/ClangImporter.cpp | 40 +------------ lib/ClangImporter/ClangIncludePaths.cpp | 57 +++++++++++++++++-- .../ModuleDependencyScanner.cpp | 3 +- ...cxx-overlay-underlying-module-lookup.swift | 3 - 7 files changed, 80 insertions(+), 55 deletions(-) diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 1b47cdafea1..86e8071aad3 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -1097,13 +1097,8 @@ public: return SwiftDependencyTracker(CAS, Mapper.get(), CI); } - llvm::IntrusiveRefCntPtr getClangScanningFS() const { - if (CAS) - return llvm::cas::createCASProvidingFileSystem( - CAS, llvm::vfs::createPhysicalFileSystem()); - - return llvm::vfs::createPhysicalFileSystem(); - } + llvm::IntrusiveRefCntPtr + getClangScanningFS(ASTContext &ctx) const; bool hasPathMapping() const { return Mapper && !Mapper->getMappings().empty(); diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 0862c3c94df..74514879e7b 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -873,10 +873,19 @@ struct ClangInvocationFileMapping { /// `suppressDiagnostic` prevents us from emitting warning messages when we /// are unable to find headers. ClangInvocationFileMapping getClangInvocationFileMapping( - ASTContext &ctx, + const ASTContext &ctx, llvm::IntrusiveRefCntPtr vfs = nullptr, bool suppressDiagnostic = false); +/// Apply the given file mapping to the specified 'fileSystem', used +/// primarily to inject modulemaps on platforms with non-modularized +/// platform libraries. +ClangInvocationFileMapping applyClangInvocationMapping( + const ASTContext &ctx, + llvm::IntrusiveRefCntPtr baseVFS, + llvm::IntrusiveRefCntPtr &fileSystem, + bool suppressDiagnostics = false); + /// Information used to compute the access level of inherited C++ members. class ClangInheritanceInfo { /// The cumulative inheritance access specifier, that is used to compute the diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index 149a85e514e..dbd5e44c65f 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -499,6 +499,18 @@ SwiftDependencyScanningService::SwiftDependencyScanningService() { SharedFilesystemCache.emplace(); } +llvm::IntrusiveRefCntPtr +SwiftDependencyScanningService::getClangScanningFS(ASTContext &ctx) const { + llvm::IntrusiveRefCntPtr baseFileSystem = + llvm::vfs::createPhysicalFileSystem(); + ClangInvocationFileMapping fileMapping = + applyClangInvocationMapping(ctx, nullptr, baseFileSystem, false); + + if (CAS) + return llvm::cas::createCASProvidingFileSystem(CAS, baseFileSystem); + return baseFileSystem; +} + bool swift::dependencies::checkImportNotTautological(const ImportPath::Module modulePath, const SourceLoc importLoc, diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 1db2ba6a5a8..d04eeffe381 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -1300,49 +1300,11 @@ ClangImporter::create(ASTContext &ctx, ctx.SourceMgr.getFileSystem(); ClangInvocationFileMapping fileMapping = - getClangInvocationFileMapping(ctx, nullptr, ignoreFileMapping); + applyClangInvocationMapping(ctx, nullptr, VFS, ignoreFileMapping); importer->requiresBuiltinHeadersInSystemModules = fileMapping.requiresBuiltinHeadersInSystemModules; - // Avoid creating indirect file system when using include tree. - if (!ctx.CASOpts.HasImmutableFileSystem) { - // Wrap Swift's FS to allow Clang to override the working directory - VFS = llvm::vfs::RedirectingFileSystem::create( - fileMapping.redirectedFiles, true, *ctx.SourceMgr.getFileSystem()); - if (importerOpts.DumpClangDiagnostics) { - llvm::errs() << "clang importer redirected file mappings:\n"; - for (const auto &mapping : fileMapping.redirectedFiles) { - llvm::errs() << " mapping real file '" << mapping.second - << "' to virtual file '" << mapping.first << "'\n"; - } - llvm::errs() << "\n"; - } - - if (!fileMapping.overridenFiles.empty()) { - llvm::IntrusiveRefCntPtr overridenVFS = - new llvm::vfs::InMemoryFileSystem(); - for (const auto &file : fileMapping.overridenFiles) { - if (importerOpts.DumpClangDiagnostics) { - llvm::errs() << "clang importer overriding file '" << file.first - << "' with the following contents:\n"; - llvm::errs() << file.second << "\n"; - } - auto contents = ctx.Allocate(file.second.size() + 1); - std::copy(file.second.begin(), file.second.end(), contents.begin()); - // null terminate the buffer. - contents[contents.size() - 1] = '\0'; - overridenVFS->addFile(file.first, 0, - llvm::MemoryBuffer::getMemBuffer(StringRef( - contents.begin(), contents.size() - 1))); - } - llvm::IntrusiveRefCntPtr overlayVFS = - new llvm::vfs::OverlayFileSystem(VFS); - VFS = overlayVFS; - overlayVFS->pushOverlay(overridenVFS); - } - } - // Create a new Clang compiler invocation. { if (auto ClangArgs = importer->getClangCC1Arguments(ctx, VFS)) diff --git a/lib/ClangImporter/ClangIncludePaths.cpp b/lib/ClangImporter/ClangIncludePaths.cpp index d2185fd152d..948b99876f0 100644 --- a/lib/ClangImporter/ClangIncludePaths.cpp +++ b/lib/ClangImporter/ClangIncludePaths.cpp @@ -197,7 +197,7 @@ ClangImporter::createClangArgs(const ClangImporterOptions &ClangImporterOpts, } static SmallVector, 2> -getLibcFileMapping(ASTContext &ctx, StringRef modulemapFileName, +getLibcFileMapping(const ASTContext &ctx, StringRef modulemapFileName, std::optional> maybeHeaderFileNames, const llvm::IntrusiveRefCntPtr &vfs, bool suppressDiagnostic) { @@ -263,7 +263,7 @@ getLibcFileMapping(ASTContext &ctx, StringRef modulemapFileName, } static void getLibStdCxxFileMapping( - ClangInvocationFileMapping &fileMapping, ASTContext &ctx, + ClangInvocationFileMapping &fileMapping, const ASTContext &ctx, const llvm::IntrusiveRefCntPtr &vfs, bool suppressDiagnostic) { assert(ctx.LangOpts.EnableCXXInterop && @@ -454,7 +454,7 @@ GetPlatformAuxiliaryFile(StringRef Platform, StringRef File, } void GetWindowsFileMappings( - ClangInvocationFileMapping &fileMapping, ASTContext &Context, + ClangInvocationFileMapping &fileMapping, const ASTContext &Context, const llvm::IntrusiveRefCntPtr &driverVFS, bool &requiresBuiltinHeadersInSystemModules) { const llvm::Triple &Triple = Context.LangOpts.Target; @@ -585,7 +585,7 @@ void GetWindowsFileMappings( } // namespace ClangInvocationFileMapping swift::getClangInvocationFileMapping( - ASTContext &ctx, llvm::IntrusiveRefCntPtr vfs, + const ASTContext &ctx, llvm::IntrusiveRefCntPtr vfs, bool suppressDiagnostic) { ClangInvocationFileMapping result; if (!vfs) @@ -655,3 +655,52 @@ ClangInvocationFileMapping swift::getClangInvocationFileMapping( result.requiresBuiltinHeadersInSystemModules); return result; } + +ClangInvocationFileMapping swift::applyClangInvocationMapping(const ASTContext &ctx, + llvm::IntrusiveRefCntPtr baseVFS, + llvm::IntrusiveRefCntPtr &fileSystem, + bool suppressDiagnostics) { + if (ctx.CASOpts.HasImmutableFileSystem) + return ClangInvocationFileMapping(); + + ClangInvocationFileMapping fileMapping = + getClangInvocationFileMapping(ctx, baseVFS, suppressDiagnostics); + + auto importerOpts = ctx.ClangImporterOpts; + // Wrap Swift's FS to allow Clang to override the working directory + fileSystem = llvm::vfs::RedirectingFileSystem::create( + fileMapping.redirectedFiles, true, *fileSystem); + if (importerOpts.DumpClangDiagnostics) { + llvm::errs() << "clang importer redirected file mappings:\n"; + for (const auto &mapping : fileMapping.redirectedFiles) { + llvm::errs() << " mapping real file '" << mapping.second + << "' to virtual file '" << mapping.first << "'\n"; + } + llvm::errs() << "\n"; + } + + if (!fileMapping.overridenFiles.empty()) { + llvm::IntrusiveRefCntPtr overridenVFS = + new llvm::vfs::InMemoryFileSystem(); + for (const auto &file : fileMapping.overridenFiles) { + if (importerOpts.DumpClangDiagnostics) { + llvm::errs() << "clang importer overriding file '" << file.first + << "' with the following contents:\n"; + llvm::errs() << file.second << "\n"; + } + auto contents = ctx.Allocate(file.second.size() + 1); + std::copy(file.second.begin(), file.second.end(), contents.begin()); + // null terminate the buffer. + contents[contents.size() - 1] = '\0'; + overridenVFS->addFile(file.first, 0, + llvm::MemoryBuffer::getMemBuffer(StringRef( + contents.begin(), contents.size() - 1))); + } + llvm::IntrusiveRefCntPtr overlayVFS = + new llvm::vfs::OverlayFileSystem(fileSystem); + fileSystem = overlayVFS; + overlayVFS->pushOverlay(overridenVFS); + } + + return fileMapping; +} diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index 5e0848c7760..b7f7529d881 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -31,6 +31,7 @@ #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "swift/Subsystems.h" +#include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SetOperations.h" #include "llvm/CAS/CachingOnDiskFileSystem.h" @@ -267,7 +268,7 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker( const SILOptions &SILOptions, ASTContext &ScanASTContext, swift::DependencyTracker &DependencyTracker, DiagnosticEngine &Diagnostics) : clangScanningTool(*globalScanningService.ClangScanningService, - globalScanningService.getClangScanningFS()) { + globalScanningService.getClangScanningFS(ScanASTContext)) { // Create a scanner-specific Invocation and ASTContext. workerCompilerInvocation = std::make_unique(ScanCompilerInvocation); diff --git a/test/ScanDependencies/cxx-overlay-underlying-module-lookup.swift b/test/ScanDependencies/cxx-overlay-underlying-module-lookup.swift index 26605cd9747..d509ab559c3 100644 --- a/test/ScanDependencies/cxx-overlay-underlying-module-lookup.swift +++ b/test/ScanDependencies/cxx-overlay-underlying-module-lookup.swift @@ -3,9 +3,6 @@ // RUN: %target-swift-frontend -scan-dependencies -o %t/deps.json %s -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import // RUN: %validate-json %t/deps.json | %FileCheck %s -// rdar://151780437: libstdc++ VFS modulemap redirects not functioning with EBM enabled -// REQUIRES: OS=macosx - import CxxStdlib // CHECK: "mainModuleName": "deps"