From df8a6928d643fcaedcb9473c2e3115c1276d3786 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Thu, 11 Dec 2025 13:51:21 -0800 Subject: [PATCH 1/2] Fix the swiftCxxStdlib link with explicit module build on Windows We currently support static linking swiftCxxStdlib only on Windows. When C++ interop is enabled but swiftCxxStdlib isn't actually used or only when its underlying std module is used, we incorrectly emitted the dynamic version of the lib name and caused the link error. This change fixes it by always adding it to the dependency. Issue https://github.com/swiftlang/swift/issues/85876 --- .../ModuleDependencyScanner.cpp | 18 ++++++++ .../win-explicit-cxx-interop-cxxstdlib.swift | 43 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 test/ScanDependencies/win-explicit-cxx-interop-cxxstdlib.swift diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index f40137d3e6f7..fffa1683539b 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -620,6 +620,24 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) { break; } + if (ScanASTContext.LangOpts.EnableCXXInterop) { + StringRef mainModuleName = mainModule->getName().str(); + if (mainModuleName != CXX_MODULE_NAME) + mainDependencies.addModuleImport(CXX_MODULE_NAME, /* isExported */ false, + AccessLevel::Public, + &alreadyAddedModules); + if (llvm::none_of(llvm::ArrayRef{CXX_MODULE_NAME, + ScanASTContext.Id_CxxStdlib.str(), "std"}, + [mainModuleName](StringRef Name) { + return mainModuleName == Name; + })) + if (ScanASTContext.LangOpts.Target.getOS() == llvm::Triple::Win32) + mainDependencies.addModuleImport(ScanASTContext.Id_CxxStdlib.str(), + /* isExported */ false, + AccessLevel::Public, + &alreadyAddedModules); + } + // Add any implicit module names. for (const auto &import : importInfo.AdditionalUnloadedImports) { mainDependencies.addModuleImport( diff --git a/test/ScanDependencies/win-explicit-cxx-interop-cxxstdlib.swift b/test/ScanDependencies/win-explicit-cxx-interop-cxxstdlib.swift new file mode 100644 index 000000000000..c36be1e30a2b --- /dev/null +++ b/test/ScanDependencies/win-explicit-cxx-interop-cxxstdlib.swift @@ -0,0 +1,43 @@ +// REQUIRES: OS=windows-msvc + +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %target-swift-frontend -scan-dependencies -module-name NoCpp \ +// RUN: -module-cache-path %t/clang-module-cache -disable-objc-interop \ +// RUN: -cxx-interoperability-mode=default \ +// RUN: %t/NoCpp.swift -o %t/NoCpp-deps.json -I %t 2>&1 +// RUN: %target-swift-frontend -scan-dependencies -module-name Cpp \ +// RUN: -module-cache-path %t/clang-module-cache -disable-objc-interop \ +// RUN: -cxx-interoperability-mode=default \ +// RUN: %t/Cpp.swift -o %t/Cpp-deps.json -I %t 2>&1 +// RUN: %target-swift-frontend -scan-dependencies -module-name Crt \ +// RUN: -module-cache-path %t/clang-module-cache -disable-objc-interop \ +// RUN: -cxx-interoperability-mode=default \ +// RUN: %t/Crt.swift -o %t/Crt-deps.json -I %t 2>&1 +// RUN: %FileCheck %s --check-prefix=NOCPP < %t/NoCpp-deps.json +// RUN: %FileCheck %s --check-prefix=CPP < %t/Cpp-deps.json +// RUN: %FileCheck %s --check-prefix=CRT < %t/Crt-deps.json + +// NOCPP: "mainModuleName": "NoCpp" +// NOCPP: "linkName": "swiftCxxStdlib", +// NOCPP-NEXT: "isStatic": true, + +// CPP: "mainModuleName": "Cpp" +// CPP: "linkName": "swiftCxxStdlib", +// CPP-NEXT: "isStatic": true, + +// CRT: "mainModuleName": "Crt" +// CRT: "linkName": "swiftCxxStdlib", +// CRT-NEXT: "isStatic": true, + +//--- NoCpp.swift +// Empty + +//--- Cpp.swift +import CxxStdlib + +//--- Crt.swift +import CRT + + + From 70cf2d5e00410bcc3edf9c10b137d7801978573d Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Fri, 12 Dec 2025 18:19:56 -0800 Subject: [PATCH 2/2] Test --- .../ModuleDependencyScanner.cpp | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index fffa1683539b..cf9eebd37362 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -631,7 +631,6 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) { [mainModuleName](StringRef Name) { return mainModuleName == Name; })) - if (ScanASTContext.LangOpts.Target.getOS() == llvm::Triple::Win32) mainDependencies.addModuleImport(ScanASTContext.Id_CxxStdlib.str(), /* isExported */ false, AccessLevel::Public, @@ -1601,60 +1600,6 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( for (const auto &clangDep : visibleClangDependencies) recordResult(clangDep.getKey().str()); - // C++ Interop requires additional handling - bool lookupCxxStdLibOverlay = - ScanCompilerInvocation.getLangOptions().EnableCXXInterop; - if (lookupCxxStdLibOverlay && - moduleID.Kind == ModuleDependencyKind::SwiftInterface) { - const auto &moduleInfo = DependencyCache.findKnownDependency(moduleID); - const auto commandLine = moduleInfo.getCommandline(); - // If the textual interface was built without C++ interop, do not query - // the C++ Standard Library Swift overlay for its compilation. - if (llvm::find(commandLine, "-formal-cxx-interoperability-mode=off") != - commandLine.end()) - lookupCxxStdLibOverlay = false; - } else if (lookupCxxStdLibOverlay && - moduleID.Kind == ModuleDependencyKind::SwiftBinary) { - const auto &moduleDetails = - DependencyCache.findKnownDependency(moduleID).getAsSwiftBinaryModule(); - // If the binary module was built without C++ interop, do not query - // the C++ Standard Library Swift overlay. - if (!moduleDetails->isBuiltWithCxxInterop) - lookupCxxStdLibOverlay = false; - } - - // FIXME: We always declare the 'Darwin' module as formally having been built - // without C++Interop, for compatibility with prior versions. Once we are certain - // that we are only building against modules built with support of - // '-formal-cxx-interoperability-mode', this hard-coded check should be removed. - if (lookupCxxStdLibOverlay && moduleID.ModuleName == "Darwin") - lookupCxxStdLibOverlay = false; - - if (lookupCxxStdLibOverlay) { - for (const auto &clangDepNameEntry : visibleClangDependencies) { - auto clangDepName = clangDepNameEntry.getKey().str(); - - // If this Clang module is a part of the C++ stdlib, and we haven't - // loaded the overlay for it so far, it is a split libc++ module (e.g. - // std_vector). Load the CxxStdlib overlay explicitly. - const auto &clangDepInfo = - DependencyCache.findDependency(clangDepName, - ModuleDependencyKind::Clang) - .value() - ->getAsClangModule(); - if (importer::isCxxStdModule(clangDepName, clangDepInfo->IsSystem) && - !swiftOverlayDependencies.contains( - {clangDepName, ModuleDependencyKind::SwiftInterface}) && - !swiftOverlayDependencies.contains( - {clangDepName, ModuleDependencyKind::SwiftBinary})) { - scanForSwiftDependency( - getModuleImportIdentifier(ScanASTContext.Id_CxxStdlib.str())); - recordResult(ScanASTContext.Id_CxxStdlib.str().str()); - break; - } - } - } - // Resolve the dependency info with Swift overlay dependency module // information. DependencyCache.setSwiftOverlayDependencies(