[Pitch] Swift Projects

What might be useful here is to identify the capabilities or changes package definitions would need in order to fix these issues, beyond what Xcode does. If certain things seem beyond what SPM should provide, then start thinking about some sort of intermediate format.

Apple's the one who started pushing the idea of using Swift Packages in place of Xcode project files for local use.

I don't know which of these issues and problems is due to Xcode and which is due to SPM. All I know is that I want to be able to press a button, and have it convert any Xcode project directly into a Swift package, and have it just work.

Currently, we are very far away from something like this due to all the issues.

Here is a short list of some of the problems:

Issues with Unsafe Flags

  • Currently, Xcode projects will fail to build if they directly link to a Swift Package that uses any unsafe flags. The only known workaround (other than just using an Xcode Project instead of a Swift Package) is to make another Swift Package that doesn't use unsafe flags, and have it import the one that does use unsafe flags, then in this "wrapper" package have a single .swift file that has @_exported import UnsafePackage and then link the wrapper to the other Xcode projects.

Issues related to linking external frameworks to a Swift Package NOT using .binaryTarget:

Issues related to .binaryTarget

Issues related to weak linking:

Issues related to headers:

Issues related to dynamic library package targets being treated as static:

Issues related to both the static linking thing and XCFrameworks:

Bugs related to Sanitizers

Bugs related to Resources

  • A resources bundle that's inside a Swift Package cannot be directly accessed by consumers.
    • This seems to be a known issue mentioned by Apple in the WWDC talk about using resources in a Swift package.
    • The workaround is for the package to provide public accessor methods that provide the resources from the bundle to consumers.
    • However, because you cannot have mixed Swift/Obj.C SPM targets, and because of the above issue where @objc code in a Swift SPM target can't be used by actual Obj. C code in modules declared in Xcode projects, no SPM target can provide resources to both Objective C code and to Swift code, making it not really worthwhile to try migrating Xcode projects that vend resources to being Swift packages, and causing us a lot of wasted time in trying but failing to do so.
  • Swift Package with resources causing test targets not to compile
  • SPM resources in test use wrong bundle path (duplicate of above?)

Issues related to Unsafe Flags

  • 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)

Performance issues with Xcode

  • package resolution always runs when you open Xcode, taking sometimes over a minute
  • In Xcode 12.5, the initial step of pasting in the link to Google Firebase package to add it as a dependency incurs a 10–15 minute delay before the next screen loads (which shows which various libraries you can add as dependencies)
    • This seems to be due to the fact that SPM performs a deep clone of all the related repos before it lets you do anything else, which for a repo like Firebase is frickin' huge
  • In Xcode 12.5, initially loading a project that has Firebase as a package dependency requires nearly 20 minutes for package resolution to succceed due the deep cloning of all the dependency repos
  • Xcode does not support loading a project without performing package resolution even if your Derived Data folder already contains all the build products of all the packages depended on by your app and frameworks

Various other issues with the SPM/Xcode integration

  • 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 solely for iOS simulator builds.
  • Swift Packages cannot link to (import) targets that are declared in an .xcproj file.
  • lack of support for mixed source targets
  • confusing Package manifest
    • how are we supposed to know which build setting goes in swiftSettings and which settings go in cSettings and which settings go in linkerSettings?
    • How are we supposed to know what counts as an unsafe flag and what can be defined?
    • Why isn't there just a Config struct that has all the possible settings already defined as variables with doc comments that you can simply change the value of, similar to how you fill out that big spreadsheet of build settings for Xcode projects?
  • editing a package manifest for 2 seconds causes it to recompile, often even if you didn't press "save"
    • if you haven't finished editing it yet this will cause your currently selected build device in Xcode to switch to Mac instead of iOS Simulator even if the Package manifest explicitly only supports iOS. This is supremely annoying!
  • SPM does not support custom config names in a coherent manner -- it just has "Debug" and "Release".
    • If your Xcode project uses any custom config names, SPM uses a secret, hidden "heuristic" to decide whether to use its Debug or Release config based on the custom name of your config. This "heuristic" tends to pick the wrong thing—for example if you have a config named "Testing", SPM will build the "Release" config instead of "Debug" and thus not actually build the package with testability enabled!
  • If you use SPM's .linkedFramework build option to link a target to another build product, Xcode's Find Implicit Dependencies fails to realize that this linkedFramework has to be built first before trying to build the package, and so your build can fail intermittently unless you turn off "Find Implicit Dependencies" and "Parallelize Build" and explicitly specify a build order that guarantees the package won't be built until the linked framework has been built.
    • This issue is extraordinarily frustrating
3 Likes