Caching SwiftPM for iOS app build on CI env

In my testing I've been able to successfully copy the various .swiftmodule files into Packages.framework/Modules. Here's how I got it to work:

  1. Create a new Packages.xcodeproj, separate to your main project file. This is where the Swift dependencies will be added, and produces a single dynamically linked Packages.framework.

  2. Add a Run Script build phase with the following contents:

    modules_dir="$BUILT_PRODUCTS_DIR"/"$MODULES_FOLDER_PATH"
    for swiftmodule in "$BUILT_PRODUCTS_DIR"/*.swiftmodule; do
      cp -r "$swiftmodule" "$modules_dir"/
    done
    

    This will copy the generate .swiftmodule files for all your dependencies into the framework bundle.

  3. Use carthage build --no-skip-current to build Packages.framework.

  4. Link & Embed Packages.framework in your regular project.

  5. Update SWIFT_INCLUDE_PATHS to add Carthage/Build/iOS/Packages.framework/Modules so that your app can see the embedded Swift modules.

  6. (Optional) If your Swift dependency depends on any C modules, this will still not compile, because C/system modules don't produce .swiftmodule files. So, for example, I had to fork GRDB in my project and change import CSQLite to @_implementationOnly import CSQLite (and remove a bunch of @inlinable attributes that were no longer valid because the C SQLite symbols are no longer exported).

So this mostly works, depending on your specific dependencies. However I probably won't keep this setup because it adds more complexity than I'd like to my build process.

2 Likes