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:
- Having to resort to unsafe flags with frameworks: Override for "unsafeFlags" in Swift Package Manager?
- Main Q&A thread on using unsafe flags to link frameworks, with the google firebase guy: Binary Frameworks with SwiftPM - #18 by 1oo7
- Old file-specific build options where people talked about, some of which never got implemented File specific build options in SwiftPM - #4 by 1oo7
- Confused by unsafe flags being disallowed in dependencies - Development / Package Manager - Swift Forums
Issues related to .binaryTarget
- 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.
- Bugs and issues using .binaryTarget XCFramework: Use xcodebuild swift package with binaryTarget logic flaw - #10 by 1oo7
- Question I posted that never got answered yet, How can local Swift packages' dynamic library targets dynamically link to local XCFrameworks that are in the Carthage/Build directory—without causing Xcode to synthesize any copy-frameworks steps for the linked XCFramework—and without causing Xcode to build and place static versions of any of these dynamic libraries into $(BUILT_PRODUCTS_DIR)/Frameworks? [Question] How can local Swift packages' dynamic library targets dynamically link to local XCFrameworks that are in the Carthage/Build directory?
- Thread I started that never got replies, about the .binaryTarget issues: Bug with .binaryTarget in Swift Packages with Xcode? - #2 by 1oo7
Issues related to weak linking:
Issues related to headers:
Issues related to dynamic library package targets being treated as static:
- "Unexpected Duplicate Tasks" bug, predominant in 12.5 betas: Swift package with resources in iOS project won't compile test targets Update: evolved into a discussion of a workaround involving my trick with unsafe flags. [Link]
- "Swift package target 'A' is linked as a static library by 'C' and 'A-stub'. This will result in duplication of library code" i.e. Bug where dynamic libraries declared in the same package, link statically instead of dynamically Swift Packages in multiple targets results in “This will result in duplication of library code.” errors - #8 by davidharris
- initial workaround was DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC=YES
- but DTS told me another solution (see those emails)
- Users say this makes SPM useless with Xcode
- Open question as to whether 12.5 actually fixes this: Xcode 12.5 and automatic dynamic linking of products - Development / Package Manager - Swift Forums
- update: 12.5 does not fix this issue
Issues related to both the static linking thing and XCFrameworks:
- XCFramework binaryTarget can't be found after build. Headers not found for an XCFramework packaging a static lib for iOS (critical)
- Anything dynamic that gets built by Xcode from a Swift package, also gets built as a static library; and Xcode synthesizes a copy-frameworks step for any of these, even if it duplicates a copy-frameworks step the app already has; these dupe static libraries get put into Frameworks/ folder whereas the actual dyanmic frameworks get put into Frameworks/PackageFrameworks/... WITH POSSIBLE SOLUTION SCRIPTS Packaging static library in SPM Package for iOS Executable - #20 by yang
Bugs related to Sanitizers
- Swift Packages fail to build if Undefined Behavior Sanitizer or Thread Sanitizer are enabled bugs.swift.org link forums.swift.org link
Issures related to ObjectiveC compatibility:
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
- forum post
- Swift bug report
- FB8751233
- rdar://8802612
- FB8893830 [
- example project](GitHub - username0x0a/xcode-12.5-spm-deps-issue)
- supposedly solved in 12.5 RC
- SPM resources in test use wrong bundle path (duplicate of above?)
- Swift forum post
- Seems to be expected based on that WWDC talk linked 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