Swift Package Commands
Introduction
Swift Package Manager (SPM) is a powerful tool for managing dependencies in Swift projects. It comes with a set of commands that help developers build, test, manage dependencies, and distribute Swift packages. These commands are executed through the swift package
command-line interface.
In this guide, we'll explore the most commonly used Swift Package Manager commands, their options, and how to use them effectively in your development workflow. Whether you're new to Swift or looking to deepen your understanding of package management, this guide will help you become proficient with SPM commands.
Basic Swift Package Commands
Initializing a Package
To create a new Swift package, you can use the swift package init
command:
swift package init --type executable
This creates a new executable Swift package in the current directory with the following structure:
.
├── Package.swift
├── README.md
├── Sources
│ └── YourPackageName
│ └── main.swift
└── Tests
└── YourPackageNameTests
└── YourPackageNameTests.swift
You can specify different types of packages with the --type
flag:
executable
: Creates a package with a main.swift file (default)library
: Creates a package without a main.swift file, intended to be used as a dependency
Example output:
Creating executable package: MyPackage
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/MyPackage/main.swift
Creating Tests/
Creating Tests/MyPackageTests/
Creating Tests/MyPackageTests/MyPackageTests.swift
Building a Package
To build a Swift package, use the swift build
command:
swift build
This compiles the sources in your package and creates an executable (if it's an executable package).
Options:
-c, --configuration
: Specify the build configuration (debug
orrelease
)-v, --verbose
: Show verbose output
Example with release configuration:
swift build -c release
Testing a Package
To run the tests for a package:
swift test
Options:
--filter
: Run specific tests (e.g.,swift test --filter MyTests
)--parallel
: Run tests in parallel-v, --verbose
: Show verbose output
Example running a specific test:
swift test --filter MyPackageTests.MyTestCase/testExample
Output:
Test Suite 'Selected tests' started at 2023-09-15 14:30:45.123
Test Suite 'MyPackageTests.xctest' started at 2023-09-15 14:30:45.456
Test Suite 'MyTestCase' started at 2023-09-15 14:30:45.789
Test Case 'MyTestCase.testExample' started at 2023-09-15 14:30:45.901
Test Case 'MyTestCase.testExample' passed (0.023 seconds)
Test Suite 'MyTestCase' passed at 2023-09-15 14:30:46.012
Test Suite 'MyPackageTests.xctest' passed at 2023-09-15 14:30:46.123
Test Suite 'Selected tests' passed at 2023-09-15 14:30:46.234
Dependency Management Commands
Resolving Dependencies
To resolve dependencies without building:
swift package resolve
This updates the Package.resolved
file with the appropriate versions of dependencies.
Updating Dependencies
To update your package dependencies to their latest versions:
swift package update
This updates all dependencies to the latest allowed versions according to the constraints specified in your Package.swift
file.
Showing Dependencies
To see a list of all dependencies and their versions:
swift package show-dependencies
Example output:
example-package
├── swift-algorithms 1.0.0
└── swift-numerics 1.0.0
└── swift-system 1.0.0
Adding Dependencies
While there's no direct command to add dependencies, you need to manually edit your Package.swift
file:
// swift-tools-version: 5.7
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
.package(url: "https://github.com/apple/swift-algorithms.git", from: "1.0.0"),
],
targets: [
.executableTarget(
name: "MyPackage",
dependencies: [
.product(name: "Algorithms", package: "swift-algorithms"),
]),
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]),
]
)
After editing, run swift package resolve
to fetch the dependencies.
Advanced Commands
Cleaning the Build Directory
To clean your build directory:
swift package clean
This removes the .build
directory, which can be useful when you want to perform a clean build.
Generating an Xcode Project
To generate an Xcode project for your package:
swift package generate-xcodeproj
This creates an Xcode project file that you can open to develop your package in Xcode.
With newer Xcode versions, you can also open the package directory directly:
open Package.swift
Running Swift Tools
The Swift Package Manager can run tools provided by the package:
swift run tool-name
For example, if your package includes an executable target named "Formatter":
swift run Formatter
Checking Swift Package Manager Version
To check the version of your Swift Package Manager:
swift package --version
Output example:
Swift Package Manager - Swift 5.7.0
Real-World Examples
Example 1: Creating and Building a Command Line Tool
Let's create a simple command line tool that uses the Swift Argument Parser library:
# Create a new executable package
swift package init --type executable --name CommandLineTool
# Edit Package.swift to add dependencies
# Add the following to your dependencies array:
# .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.0"),
# And to your target dependencies:
# .product(name: "ArgumentParser", package: "swift-argument-parser"),
# Resolve dependencies
swift package resolve
# Edit Sources/CommandLineTool/main.swift
Now update main.swift
to use the ArgumentParser:
import ArgumentParser
struct Greet: ParsableCommand {
@Argument(help: "The name to greet")
var name: String
func run() throws {
print("Hello, \(name)!")
}
}
Greet.main()
Build and run the tool:
swift build
swift run CommandLineTool Alice
Output:
Hello, Alice!
Example 2: Creating a Library Package and Using It in Another Project
First, create a library:
# Create a library package
swift package init --type library --name MathLibrary
# Edit Sources/MathLibrary/MathLibrary.swift
Update MathLibrary.swift
:
public struct MathLibrary {
public init() {}
public func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
public func subtract(_ a: Int, _ b: Int) -> Int {
return a - b
}
}
Now create an executable that uses this library:
# In a different directory
swift package init --type executable --name MathApp
# Edit Package.swift to add a dependency to your local MathLibrary
# .package(path: "../MathLibrary")
Update main.swift
in the new app:
import MathLibrary
let math = MathLibrary()
print("2 + 3 = \(math.add(2, 3))")
print("5 - 2 = \(math.subtract(5, 2))")
Build and run:
swift build
swift run MathApp
Output:
2 + 3 = 5
5 - 2 = 3
Summary
Swift Package Manager commands provide a powerful set of tools for creating, building, testing, and managing Swift packages. In this guide, we've covered:
- Creating packages with
swift package init
- Building packages with
swift build
- Testing packages with
swift test
- Managing dependencies with commands like
resolve
andupdate
- Advanced commands for generating Xcode projects and running tools
- Real-world examples of creating and using packages
By mastering these commands, you can efficiently manage your Swift projects and dependencies, making your development workflow smoother and more productive.
Additional Resources
- Swift Package Manager Documentation
- Swift Package Manager on GitHub
- Swift Forums - Package Manager category
Exercises
-
Create a new library package and implement a string utility with functions like capitalizing words and counting characters.
-
Create an executable package that uses your string utility library.
-
Add a third-party dependency to your project (like Swift Algorithms) and explore how to use it in your code.
-
Write tests for your string utility functions and run them using
swift test
. -
Try building your package in release mode and compare the performance with debug mode.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)