Use SwiftPM to build iOS target

Hi,

Since Xcode 11 landed with SPM support and is able to target other platforms like iOS, I wonder what is the recipe to archive the same from SPM.

Swift Package Manager includes a build system that can build for macOS and Linux. Xcode 11 integrates with libSwiftPM to provide support for iOS, watchOS, and tvOS platforms.

I wonder how to use SPM build system to build for iOS. Is it possible at all for anything that is not Xcode? is it planned to make it available outside Xcode? (having Xcode installed)

9 Likes

thank you. that's not what I asked about though.

It's pretty clear that Xcode is (still) required to build the IOS package, do the signing, and all the other moving parts needed to create the combined bundle there. I don't expect, and recommend not expecting, SPM to ever attempt to accommodate those elements.

SPM is great for swift, tests, package those up, giving structure to them, and ordering dependencies - and that's where it ends. For the further pieces of assembling a Mac, IOS, etc app - you need the broader tooling of Xcode.

1 Like

if swift build can build for macOS, and can build crossplatform, building for iOS doesn't sound that different. (signing is another thing) Just like for macOS, it needs SDK from Xcode. Hence my question if there is plan to add other platforms, or iOS support will not be added.

5 Likes

It's quite different, because swift build only builds standalone command-line executables for macOS. iOS (as well as macOS, for non-command-line apps) requires handling assets/resources (invoking tools like actool and ibtool), compiling localized strings files, configuring Info.plist files, and then copying them into the appropriate .app bundle structure, in addition to signing that you already metioned. Then, if they wanted to support other targets than just basic iOS apps (like app extensions, or framework bundles), then they'd have to handle the differences between those kinds of bundles as well.

Could all of those features be added to SwiftPM? Technically, sure. But it's probably out of scope for the Swift project, since none of those features above are strictly about Swift, and it would require the SPM team to constantly chase new OS product types and duplicate work already done in Xcode. If you want to see a bit of how complex reinventing this can be, a good place to look would be the Bazel rules for bundling Apple apps.

It wouldn't surprise me at some point to see some kind of support for included assets/runtime data files as part of a Swift package, but that's a lot less complexity than building full apps.

I haven't watched the sessions from this week yet, but now that packages are supported for iOS in Xcode, is there a way to use swift build or xcodebuild without an xcodeproj to build or test your library with the iOS configuration?

the point is to build a library. SPM in Xcode can't do the app by itself too.

2 Likes

I'd imagine all that would be possible should this SPM proposal advance further: Extensible Build Tools

Latching onto the “library” keyword, and assuming a transient Xcode project file is allowed, that has already been possible for quite some time:

swift package generate-xcodeproj
xcodebuild build -sdk iphoneos -scheme 'MyPackage-Package'
xcodebuild test -destination 'name=iPhone 8' -scheme 'MyPackage-Package'

(but replace “MyPackage” with the actual package name declared in the manifest.)

1 Like

xcodebuild doesn't work without an .xcodeproj.

xcodebuild can build Swift Package without .xcodeproj with passing product name to -scheme option and also recognizes -destination option.
e.g.

6 Likes

That's Xcode-11, and according to the WWDC videos, if the .xcodeproj file is re-generated, xcodebuild will re-generate it from the Package.swift manifest. So, xcodebuild still needs a .xcodeproj to build a target or targets. If you are not using Swift packages (for example, an all Objective-C/C++) application, not very helpful.

xcodebuild archive on a Swift package's "scheme" doesn't produce the same result than running xcodebuild archive on an Xcode project... to be specific, they both create a .framework but the Swift package doesn't export headers.

Just in case anyone is still interested, it is possible to build SwiftPM libraries and executables for iOS (yes, even executables).

swift build --arch arm64 -Xswiftc -sdk -Xswiftc /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.4.sdk -Xswiftc -target -Xswiftc arm64-apple-ios14.0

It does have some quirks, for example it outputs the built products to the .build/arm64-apple-macosx directory (meaning that swift package clean is required when switching from building for macOS to building for iOS and vice versa. But the built executable does successfully run on iOS which is all that really matters.

I am using this capability in swift-bundler, my tool for creating macOS apps without Xcode (and soon iOS apps too). The ios branch of swift-bundler can successfully build, bundle, sign and run an executable Swift package product as an iOS app on a physical iPhone.

9 Likes

Is it possible to configure this in the Package.swift file somehow? Does this also work on a simulator by selecting a scheme and a device and running from inside Xcode?

This is a big step forward since the original post.

Currently Xcode has no support for running Swift packages as proper apps (it just compiles the code into an executable file and runs that, which works semi fine on macos, but doesn’t work at all on iOS due to it’s restricted nature). And I haven’t tried to use this technique to build for the simulator yet (the target triple and sdk would probably both need changing).

I’ll post back here once Swift Bundler can run swift package executable products as apps on physical ios devices and simulators, and can generate xcode schemes for doing so through xcode :)

2 Likes

Oh wow, that would have been super handy to know when we built the build system for the Swift Package Index. Right now, we’re having an awkward bifurcation of using SPM and xcodebuild depending on the platform.

It’s probably not worth switching now that we have a working system but perhaps it’d be a way to handle legacy build once SPM gains proper support for iOS builds etc. Thanks for sharing this!

Do you have any idea how reliable it is?

That's probably good :) Doing this is not a supported way to target iOS which may lead to various features not working as expected, e.g. binary dependencies or plugins.

I guess that answers my question :smile:

(Although it’d have been only for the purpose of building, not running, but I can see how unreliable a signal that would likely be, across all packages.)