After SPM became integrated with Xcode, Apple and others (including some contributors to the Swift.org forums) began recommending Swift Packages not only for distributing source code, but also, for local development use—creating modules as libraries and later, frameworks—a fine alternative to Xcode project files.
Today, some of us even use Swift Packages solely in this latter capacity—we only use packages as a replacement for much-hated Xcode project files, but we have yet to start using SPM to manage our remote dependencies.
Example Use Case
For example, at my org, we use Carthage to build our third-party dependencies as XCFrameworks. Our tried-and-true cacheing solution, Rome, adapted easily to these. We eventually want to switch to using SPM for our dependencies, but that's another topic.
Meanwhile we now have upwards of 20 different Swift Packages throughout our workspace, which each define one or more separate, local modules (which we would have otherwise created using Xcode Project files).
The Current Problem
So, what's the problem with using SPM to create local modules?
We have run into a multitude of bugs and difficulties when trying to use Swift Packages as a replacement for .xcproj files in our project. SPM was designed to facilitate distributing dependency libraries—not as a functional equivalent to .xcproj files.
Here's a short list of the issues:
- Xcode refuses to compile any local Xcode projects that link to a Swift package whose Package.swift contains "unsafeFlags" (workaround is an ugly hack involving a wrapper package without unsafe flags)
- Under certain circumstances, Xcode tries to statically links dynamic frameworks, resulting a build failure due to duplication of symbols
- Despite an earlier proposal claiming to add a way to link binary dependencies to a Swift package, there is still no good way to do this, because Xcode does't prioritize building binaryTargets before it tries to build the source packages that depend on them.
- For each dynamic target declared in a package, Xcode builds a static library in (BUILT_PRODUCTS_DIR) and a dynamic framework in (BUILT_PRODUCTS_DIR)/PackageFrameworks, which causes all kinds of havok if you use $(BUILT_PRODUCTS_DIR) as a Framework Search Path.
- There is no good way to specify particular build options just for iOS simulator builds.
- Swift Packages cannot link to (import) targets that are declared in an .xcproj file.
The Solution (General)
To address this, rather than continuing to try to shoehorn SPM into a role that it was never designed to fill, instead, we should make a new, similar solution called Swift Projects.
Swift Projects would share part of the same syntax as a Swift Package, making it easy to migrate existing SPM packages to being Projects. Setting up a basic module (framework or library) would be done the same way.
However, there'd be no facility at all for a Swift Prioject to reference a separate git repo or manage versions in a complex way. At most, there could be a version tag, but it would function identically to how version info is represented in Xcode projects. all the use-cases of Xcode project
Another difference: Swift Projects would have auto-complete-friendly parameters with doc comments for each and every compiler flag and build option that's currently available to set in the Xcode Project File interface.
Most critically: Swift Projects would carry the guarantee that the result of running xcodebuild on a Project target would be 100% identical to running the same xcodebuild on a framework with identical build options (many of which are currently only achievable via arcane unsafe flags).
The one exception to this "identicalness" would be file handling. Files in Swift Projects would be handled like Swift Packages handles files: whatever is in a folder, is in the darn folder. No more "group without a folder" or file references with UUIDs etc,
Thus it should be technically feasible to convert any Xcode Project File to a Swift Project, but there might be some symlinks created to make a file appear in multiple places.
Lastly, Swift Projects should play nice with playgrounds, and should be able to link to any prebuilt (cached) binary framework or static library.
The Solution (Specific)
I haven't really gotten as far as writing up what the exact syntax should look like. I'm hoping that's what this thread might discuss :D
At a later time I will link to all the various problem threads related to SPM, if anyone is interested.