How to build Swift Package as XCFramework

Hey all, there actually is a solution, but it's a bit more complicated.

Firstly, build the framework using

xcodebuild archive -scheme {SchemeName} -destination {Destination} -archivePath Release-iphoneos.xcarchive -derivedDataPath {DerivedDataPath} SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES

Where the SchemeName is name of the scheme (package product name) that you are building, and the Destination is one of generic/platform=iOS, generic/platform=iOS Simulator or generic/platform=macOS.

Secondly, copy the generated Swift module files from derived data. BUILD_LIBRARY_FOR_DISTRIBUTION=YES in the previous command will ensue that the module gets generated, but you need to copy it manually.

cp -r {DerivedDataPath}/Build/Intermediates.noindex/ArchiveIntermediates/{SchemeName}/BuildProductsPath/Release-iphoneos/{SchemeName}.swiftmodule Release-iphoneos.xcarchive/Products/usr/local/lib/{SchemeName}.framework/Modules/{SchemeName}.swiftmodule

Thirdly, if the product has resources, you need to copy the resources bundle manually as well!

cp -r {DerivedDataPath}/Build/Intermediates.noindex/ArchiveIntermediates/{SchemeName}/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/{SchemeName}_{SchemeName}.bundle Release-iphoneos.xcarchive/Products/usr/local/lib/{SchemeName}.framework/{SchemeName}_{SchemeName}.bundle

Finally, repeat this process for each {Destination} you support and then generate an xcframework. Here you can also embed dSYMs if you want to.

xcodebuild -create-xcframework 
    -framework Release-iphoneos.xcarchive/Products/usr/local/lib/{SchemeName}.framework 
    -debug-symbols Release-iphoneos.xcarchive/dSYMs/{SchemeName}.framework.dSYM 
    -framework Release-iphonesimulator.xcarchive/Products/usr/local/lib/{SchemeName}.framework 
    -debug-symbols Release-iphonesimulator.xcarchive/dSYMs/{SchemeName}.framework.dSYM -output {SchemeName}.xcframework

Note that if you are dealing with C/ObjC package product, you'll also need to copy headers manually and generate the modulemap manually.

Note as well that all this only works if you mark the package products as dynamic libraries:

.library(
    name: "Test",
    type: .dynamic,
    targets: ["Test"]
)
15 Likes