@@ -771,6 +771,9 @@ final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBase
771771 let packageTargetBundleAccessorResult = await generatePackageTargetBundleAccessorResult ( scope)
772772 tasks += packageTargetBundleAccessorResult? . tasks ?? [ ]
773773
774+ let bundleLookupHelperResult = await generateBundleLookupHelper ( scope)
775+ tasks += bundleLookupHelperResult? . tasks ?? [ ]
776+
774777 let embedInCodeAccessorResult : GeneratedResourceAccessorResult ?
775778 if scope. evaluate ( BuiltinMacros . GENERATE_EMBED_IN_CODE_ACCESSORS) , let configuredTarget = context. configuredTarget, buildPhase. containsSwiftSources ( context. workspaceContext. workspace, context, scope, context. filePathResolver) {
776779 let ownTargetBuildFilesToEmbed = ( ( context. workspaceContext. workspace. target ( for: configuredTarget. target. guid) as? StandardTarget ) ? . buildPhases. compactMap { $0 as? BuildPhaseWithBuildFiles } . flatMap { $0. buildFiles } . filter { $0. resourceRule == . embedInCode } ) ?? [ ]
@@ -868,6 +871,10 @@ final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBase
868871 result. append ( ( packageTargetBundleAccessorResult. fileToBuild, packageTargetBundleAccessorResult. fileToBuildFileType, /* shouldUsePrefixHeader */ false ) )
869872 }
870873
874+ if let bundleLookupHelperResult {
875+ result. append ( ( bundleLookupHelperResult. fileToBuild, bundleLookupHelperResult. fileToBuildFileType, /* shouldUsePrefixHeader */ false ) )
876+ }
877+
871878 if let embedInCodeAccessorResult {
872879 result. append ( ( embedInCodeAccessorResult. fileToBuild, embedInCodeAccessorResult. fileToBuildFileType, /* shouldUsePrefixHeader */ false ) )
873880 }
@@ -1192,11 +1199,17 @@ final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBase
11921199 let buildFilesContext = BuildFilesProcessingContext ( scope, belongsToPreferredArch: preferredArch == nil || preferredArch == arch, currentArchSpec: currentArchSpec)
11931200 var perArchTasks : [ any PlannedTask ] = [ ]
11941201 await groupAndAddTasksForFiles ( self , buildFilesContext, scope, filterToAPIRules: isForAPI, filterToHeaderRules: isForHeaders, & perArchTasks, extraResolvedBuildFiles: {
1202+ var result : [ ( Path , FileTypeSpec , Bool ) ] = [ ]
1203+
11951204 if let packageTargetBundleAccessorResult {
1196- return [ ( packageTargetBundleAccessorResult. fileToBuild, packageTargetBundleAccessorResult. fileToBuildFileType, /* shouldUsePrefixHeader */ false ) ]
1197- } else {
1198- return [ ]
1205+ result. append ( ( packageTargetBundleAccessorResult. fileToBuild, packageTargetBundleAccessorResult. fileToBuildFileType, /* shouldUsePrefixHeader */ false ) )
1206+ }
1207+
1208+ if let bundleLookupHelperResult {
1209+ result. append ( ( bundleLookupHelperResult. fileToBuild, bundleLookupHelperResult. fileToBuildFileType, /* shouldUsePrefixHeader */ false ) )
11991210 }
1211+
1212+ return result
12001213 } ( ) )
12011214
12021215 // Add all the collected per-arch tasks.
@@ -1725,7 +1738,43 @@ final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, FilesBase
17251738 return GeneratedResourceAccessorResult ( tasks: tasks, fileToBuild: filePath, fileToBuildFileType: context. lookupFileType ( fileName: " sourcecode.swift " ) !)
17261739 }
17271740
1741+ /// Generates a task for creating the `__BundleLookupHelper` class to enable `#bundle` support in mergeable libraries.
1742+ private func generateBundleLookupHelper( _ scope: MacroEvaluationScope ) async -> GeneratedResourceAccessorResult ? {
1743+ // We generate a __BundleLookupHelper class that Foundation's #bundle macro can use to lookup the resource bundle.
1744+ // ld will inject a mapping of class pointers to the correct resource bundle so that BundleForClass works at runtime.
1745+
1746+ // We only need this treatment for mergeable libraries at this time.
1747+ // Package targets do something similar but they generate the Bundle.module extensions and #bundle calls that.
1748+
1749+ // We need to do this for all mergeable libraries, even if it will just be re-exported in this build.
1750+ guard scope. evaluate ( BuiltinMacros . MERGEABLE_LIBRARY) else {
1751+ return nil
1752+ }
1753+
1754+ let workspace = self . context. workspaceContext. workspace
1755+
1756+ // #bundle is a Swift macro, so this is only needed for Swift code.
1757+ guard buildPhase. containsSwiftSources ( workspace, context, scope, context. filePathResolver) else {
1758+ return nil
1759+ }
1760+
1761+ let filePath = scope. evaluate ( BuiltinMacros . DERIVED_SOURCES_DIR) . join ( " bundle_lookup_helper.swift " )
1762+
1763+ // We need one class with a relatively unique name that #bundle can use for bundle lookup.
1764+ // It cannot be less visible than internal since the #bundle expansion needs to be able to resolve it AND so ld will record the class->bundle mapping.
1765+ // We intentionally do not want a Foundation dependency in this generated code, so don't import Foundation.
1766+ let content = " internal class __BundleLookupHelper {} "
1767+
1768+ var tasks = [ any PlannedTask ] ( )
1769+ await appendGeneratedTasks ( & tasks) { delegate in
1770+ context. writeFileSpec. constructFileTasks ( CommandBuildContext ( producer: context, scope: context. settings. globalScope, inputs: [ ] , output: filePath) , delegate, contents: ByteString ( encodingAsUTF8: content) , permissions: nil , preparesForIndexing: true , additionalTaskOrderingOptions: [ . immediate, . ignorePhaseOrdering] )
1771+ }
1772+ return GeneratedResourceAccessorResult ( tasks: tasks, fileToBuild: filePath, fileToBuildFileType: context. lookupFileType ( fileName: " sourcecode.swift " ) !)
1773+ }
1774+
17281775 /// Generates a task for creating the resource bundle accessor for package targets.
1776+ ///
1777+ /// This produces the `Bundle.module` accessor.
17291778 private func generatePackageTargetBundleAccessorResult( _ scope: MacroEvaluationScope ) async -> GeneratedResourceAccessorResult ? {
17301779 let bundleName = scope. evaluate ( BuiltinMacros . PACKAGE_RESOURCE_BUNDLE_NAME)
17311780 let isRegularPackage = scope. evaluate ( BuiltinMacros . PACKAGE_RESOURCE_TARGET_KIND) == . regular
0 commit comments