Newbie: SPM with or without a project file?

I'd always assumed you needed an .xcodeproj file to develop a package, but after watching the WWDC talk I noticed you can create a Swift Package from within Xcode (which doesn't generate a .xcodeproj file) and then simply double-click the Package.swift file and the package opens in Xcode you get a scheme to build your code and test it.

Are there any drawbacks to this approach? It's quite unusual not being able to see targets and build settings, but then I realised you get a framework target with an .xcodeproj file too. So it might depend on your deliverables. Would anyone like to share their experiences, good or bad? I'm really not sure which option to go for.

Also I noticed the WWDC talk seemed to advocate for keeping your package in a subfolder of your original (app) project folder, if you're splitting up your code like that and working on both code bases togther. Is that a good idea? Initially I thought the package code would be stored in your app's repo (which is obviously horrible), but if you choose to create a git repo with Package creation I guess you end up with a git repo inside a git repo. I chose to store my toy/test/dummy package outside my app's folder and it seemed to work ok.

If you are vending your package for others to use, I would not recommend maintaining a separate Xcode project alongside it, since many adjustments you make in Xcode will not affect clients. Xcode is still convenient to use while you are writing code, but any project settings not reflected in the Package.swift file aren’t actually part of the package. That should not be much of a surprise, since your package might be used places Xcode can’t—such as on Linux. Before Xcode could open a package directly, you could do $ swift package generate-xcodeproj to work on a package in Xcode. But since the beginning, there has been a *.xcodeproj entry in the template’s .gitignore file. Do $ swift package init in an empty directory and take a look for yourself.

If you are not vending your package further, but just using it as a means of collecting dependencies to build an application, then you probably should check in an Xcode project. SwiftPM cannot specify things like the application icon or the Info.plist file. You don’t want to have to set those back up again each time you check out the repository, so you will need an Xcode project to keep record of those sorts of things.

Unless you are vending it to clients separately, the package code (i.e. the manifest and any top‐level code) may as well be checked into the same repository. Wherever it fetches the dependencies to should be properly .gitignored. I assume that happens automatically when Xcode is managing it for you. If you see build artifacts or any dependency sources getting checked in then something is wrong with your .gitignore file.

3 Likes

Thanks for the advice! I appreciate the time taken to respond. The package is for my own internal use. I'm wanting to separate out my CloudKit related functionality and isolate that from the rest of my app code. I do however want it in a separate repo, and want to be able to just check it out and run the tests so it's completely independent of the app it'll be used in.

I did find that super weird when I was doing some trial and error work and couldn't understand why the project file was missing from my git status output.

Then a separate package is exactly what you are looking for. The way I mean the terminology before, I would consider you to be your own client in this case. It is the separation of interests and the reusability by other projects I was getting at, whether they are your own or someone else’s.

If what you are doing relies on Info.plist or .entitlements entries, you might not be able to test it separately from an application, because the package’s tests won’t have those. (You can still create a dummy Xcode application in the separate package’s repository if you have to. Then you can attach the tests to it when running them in Xcode. It’s just that $ swift test won’t be meaningful.)

That's a good point actually. Learning how to unit test CloudKit code is on my todo list, so I'm sure there are others out there who have got a workable solution.