What's new in Swift Package Manager in Swift 5.4
Along with the brand new Xcode 12.5, Swift 5.4 and its associated Swift Package Manager (SPM from now on) are now officially released. While 5.4 might look like a small release for SPM, there are actually a lot of changes, in this article let's have a look at the main ones.
The biggest release so far (?)
Even before talking about the actual changes, this release is one of the biggest (if not the biggest) for SPM to date, this is also justified by the recent expansion of the dedicated team at Apple and the new support for Windows.
Here are all the stats of the most recent releases:
- Swift 5.4 vs 5.3: 527 changed files with 34,434 additions and 36,806 deletions.
- Swift 5.3 vs 5.2: 411 changed files with 19,920 additions and 8,186 deletions.
- Swift 5.2 vs 5.1: 441 changed files with 21,714 additions and 11,442 deletions.
- Swift 5.1 vs 5.0: 169 changed files with 8,560 additions and 4,276 deletions.
- Swift 5.0 vs 4.2: 420 changed files with 23,256 additions and 11,635 deletions.
- Swift 4.2 vs 4.1: 232 changed files with 6,831 additions and 2,117 deletions.
- Swift 4.1 vs 4.0: 326 changed files with 7,286 additions and 4,344 deletions.
- Swift 4.0 vs 3.1: 319 changed files with 25,852 additions and 11,848 deletions.
- Swift 3.1 vs 3.0: 331 changed files with 28,945 additions and 5,210 deletions.
Since we're at it, here's a sneak peek at SPM 5.5, which is still a few months away:
- Swift 5.5 vs 5.4: 374 changed files with 28,185 additions and 6,539 deletions (at the time of writing).
While these stats alone don't mean much, it's clear that a lot is happening on this project, let's have a look at the actual changes next.
External changes
Targets declaration
Up to Swift 5.3 targets declarations were separated in:
.target(...)
for regular and executable targets.binaryTarget(...)
for binary targets that reference an artifact on disk.testTarget(...)
for testing targets.systemLibrary(...)
for system library targets
Where the difference between a regular target and an executable one was the presence (or not) of a main.swift
file, which was then used as the entry point for an executable target.
In Swift 5.3 we've seen the introduction of the @main
attribute, explicitly defining a new application entry point, regardless of the where its declaration is located.
In Swift 5.4 SPM gains a new .executableTarget(...)
target, exclusively dedicated to executables, where SPM will support either having a main.swift
entry point or a @main
declaration (at any location).
From now on .target(...)
will be used only for regular targets and nothing else, improving the package manifest readability.
(Linux) Test discovery
Until Swift 5.3 every package supporting Linux needed to have a LinuxMain.swift
file in the Tests
folder root: this file was needed to explicitly declare/list all the tests to be executed. From SPM 5.4 this LinuxMain.swift
is no longer necessary.
This same file was previously not needed/used in macOS platforms, as macOS relies on the Objective-C runtime for such discovery, like it does for .xcodeproj
test suites.
The way it now works is by building an IndexStore
of the tests and run the outcome through a TestDiscoveryCommand
, which will then generate the LinuxMain.swift
file at build time.
This functionality was previously available via a
--enable-test-discovery
flag to be passed on a$ swift test
command, it's now enabled by default.
Package dependency cache
Prior to Swift 5.4, if we had two completely separate packages with the same dependency, that dependency would have been downloaded twice and put in the .build
folder of each of our packages.
From Swift 5.4 SPM keeps a per-user cache in a new ~/.swiftpm/cache
folder (or equivalent in other platforms), which will then be queried before fetching anything from the Internet: this will be a huge time/data saver, especially when using the same dependency in multiple, independent packages.
Internal changes
Argument parser
Apple's ArgumentParser
has been released a little over an year ago, during this time it became the de-facto standard for every swift CLI tool out there: it should come with no surprise that SPM has now adopted it.
Previously SPM used TSCUtility
's ArgumentParser
which we covered here.
Good bye swift-tools-support-core
swift-tools-support-core
is a collection of utilities used within SPM and llbuild
: SPM kept a vendored copy of this package in its own repository, for CI/testing purposes.
Keeping this copy meant that every change had to be synced between the two repositories: fortunately this is no longer the case, as SPM no longer needs such vendored copy.
New module: Basics
Basics is a new module that contains SPM specific utilities that shouldn't be part of swift-tools-support-core
. For example the per-user cache location can be found in this module.
This module name is a blast from the past: swift-tools-support-core
's TSCBasic
was originally called Basic
.
New module: PackageCollections
Package Collections is the first module out of three of a new package discovery functionality being added into SPM, the other two being Package Registry and Package Index.
Package Collections focuses on handpicked packages lists, and provides a CLI tool, $ swift package-collection
, in order to read and explore such lists.
While this functionality is officially being added in Swift 5.5, the ground work is already part of SPM as of Swift 5.4 (note that $ swift package-collection
is not exposed in 5.4, making it inaccessible)
For more details on PackageCollections
, refer to its Swift Evolution proposal and documentation.
Conclusions
SPM has gotten a lot of attention in the last couple of years, and its development pace seems to be only increasing!
In this article we took a sneak peek to its main changes of the upcoming release, however there are many other changes not highlighted here: feel free to explore them yourself!
What are you most excited about SPM future? Let me know via email or twitter!