Halting Problems

Swift Package Manager, same as it ever was

After working on a framework built with Objective-C, I bundled the framework variants into an XCFramework and set up a Package.swift manifest for distributing SDK releases. While doing so, I ran into the following conundrum:

I want to make releases like this: bump the version number, make a release commit; build the binaries and embed version identifier in in the binaries as Framework vM.m.p:branch@hash:config (where M is major, m is minor, and p is the patch components of the version string); create the release on GitHub with the tag vM.m.p and attach the binaries to the GitHub release. Binaries are available in both signed and unsigned variants—so no binary voodoo is possible, even if that would fix my problem.

Trouble is the Swift Package Manager expects the package manifest at the root of repository named Package.swift and to deliver binaries, the package manifest must contain URLs to the ZIP'd binaries and checksum of those ZIP files. That means I'd have to make a second separate commit to update the package manifest—now the binaries point to the commit before the package manifest was updated and the manifest tagged at M.m.p actually points to the previous release.

The framework is a commercial open source product, but I don't want to support peoples "modifications" in the wild. They're free to do so, but if they send a support ticket and the log shows a version identifier that didn't originate in my source tree, good luck. In reality I wouldn't be so harsh, just send me your changes as a PR—then I can help.

So to fix this I have two bad options, don't embed the branch and hash info for all builds, meaning M.m.p could be any built version from M.m.p ahead by some arbitrary number of commits. Or build separate Swift PM only binaries with version identifiers of the from Framework vM.m.p:branch@hash+swiftpm:config, so I know hash is probably equivalent to releasetag^.

I picked the latter option. That means Unity, CocoaPods, Carthage, and manual integrations will always be uniquely identifiable, but I have to do extra work for Swift PM and the version identifier is just a crumb trail.

Other potential options could be putting Package.swift in a separate repo, but that sucks too. Or putting Package.swift in an orphaned branch, but that would still mean the release tags are wrong for Swift PM. Nevertheless, both these options would require telling publishers that they have to do extra stuff to make Swift PM work and that's error prone at best.

Anyway, just ranting. Unless I'm overlooking and obvious way to break a cyclic graph. Package managers are great, until they're not.

Last modified: 2025-04-05 10:59:11 -0500 CDT