From e7590072569f267bb4885657e84c591d69505899 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Fri, 9 Jun 2023 16:33:51 -0700 Subject: [PATCH] [Immediate] Workaround for loading merged frameworks in immediate mode Some frameworks that previously had a separate swift overlay have been merged in macOS 14. This is causing symbols to not resolve if using the new SDK but running on an older OS in immediate mode. Ideally we would handle this automatically in JITLink as is done by the system linker, but in the meantime add a workaround to load the correct libraries manually. rdar://110371405 --- lib/Immediate/Immediate.cpp | 63 +++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index 5e20fe1485b25..e2d9f2d089b36 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -191,6 +191,50 @@ bool swift::immediate::tryLoadLibraries(ArrayRef LinkLibraries, [](bool Value) { return Value; }); } +/// Workaround for rdar://94645534. +/// +/// The framework layout of some frameworks have changed over time, causing +/// unresolved symbol errors in immediate mode when running on older OS versions +/// with a newer SDK. This workaround scans through the list of dependencies and +/// manually adds the right libraries as necessary. +/// +/// FIXME: JITLink should emulate the Darwin linker's handling of ld$previous +/// mappings so this is handled automatically. +static void addMergedLibraries(SmallVectorImpl &AllLinkLibraries, + const llvm::Triple &Target) { + assert(Target.isMacOSX()); + + struct MergedLibrary { + StringRef OldLibrary; + llvm::VersionTuple MovedIn; + }; + + using VersionTuple = llvm::VersionTuple; + + static const llvm::StringMap MergedLibs = { + // Merged in macOS 14.0 + {"AppKit", {"libswiftAppKit.dylib", VersionTuple{14}}}, + {"HealthKit", {"libswiftHealthKit.dylib", VersionTuple{14}}}, + {"Network", {"libswiftNetwork.dylib", VersionTuple{14}}}, + {"Photos", {"libswiftPhotos.dylib", VersionTuple{14}}}, + {"PhotosUI", {"libswiftPhotosUI.dylib", VersionTuple{14}}}, + {"SoundAnalysis", {"libswiftSoundAnalysis.dylib", VersionTuple{14}}}, + {"Virtualization", {"libswiftVirtualization.dylib", VersionTuple{14}}}, + // Merged in macOS 13.0 + {"Foundation", {"libswiftFoundation.dylib", VersionTuple{13}}}, + }; + + SmallVector NewLibs; + for (auto &Lib : AllLinkLibraries) { + auto I = MergedLibs.find(Lib.getName()); + if (I != MergedLibs.end() && Target.getOSVersion() < I->second.MovedIn) + NewLibs.push_back(I->second.OldLibrary); + } + + for (StringRef NewLib : NewLibs) + AllLinkLibraries.push_back(LinkLibrary(NewLib, LibraryKind::Library)); +} + bool swift::immediate::autolinkImportedModules(ModuleDecl *M, const IRGenOptions &IRGenOpts) { // Perform autolinking. @@ -201,24 +245,9 @@ bool swift::immediate::autolinkImportedModules(ModuleDecl *M, M->collectLinkLibraries(addLinkLibrary); - // Workaround for rdar://94645534. - // - // The framework layout of Foundation has changed in 13.0, causing unresolved symbol - // errors to libswiftFoundation in immediate mode when running on older OS versions - // with a 13.0 SDK. This workaround scans through the list of dependencies and - // manually adds libswiftFoundation if necessary. auto &Target = M->getASTContext().LangOpts.Target; - if (Target.isMacOSX() && Target.getOSMajorVersion() < 13) { - bool linksFoundation = std::any_of(AllLinkLibraries.begin(), - AllLinkLibraries.end(), [](auto &Lib) { - return Lib.getName() == "Foundation"; - }); - - if (linksFoundation) { - AllLinkLibraries.push_back(LinkLibrary("libswiftFoundation.dylib", - LibraryKind::Library)); - } - } + if (Target.isMacOSX()) + addMergedLibraries(AllLinkLibraries, Target); tryLoadLibraries(AllLinkLibraries, M->getASTContext().SearchPathOpts, M->getASTContext().Diags);