Swift Package Manager 入门
本教程共 93 篇 · 第 88 篇 · 更新于 2026-08-08 · 约 7 分钟阅读
本节目标:搞懂 SPM 是什么,能用命令行创建一个 Swift 包,并看懂 Package.swift 里 target、product、依赖这些概念。
写代码迟早要复用别人的成果。你想用一个好用的网络库、命令行参数解析库,总不能每次都去复制粘贴源码。Swift 官方自带了一个工具,专门帮你创建工程、管理依赖、编译运行,它就是 Swift Package Manager,大家习惯叫它 SPM。
SPM 不需要你额外安装。只要你装了 Swift 工具链(macOS 上的 Xcode 命令行工具,或 Linux 上的 swift 包),swift package 这条命令就已经在手上。它既能管你自己写的库,也能从 GitHub 这类地方拉取别人发布的包。
1-1 什么是 Swift Package Manager
SPM 是苹果从 Swift 3 时代就内置的官方包管理器。它把三件事合在了一起:定义包的结构、下载并管理依赖、调用编译器构建产物。换句话说,它既是工程的”目录规范”,也是”下载器”,还是”构建器”。
Note在 Swift 6.3.2 里,SPM 已经非常成熟。日常写命令行工具、写服务端 Swift、或者把一段逻辑打成可复用库,基本都靠它。Xcode 工程也能直接用 SPM 添加依赖。
你可能听过 CocoaPods、Carthage,那是早期的第三方方案。现在苹果生态里,SPM 是官方首选,资料最多、接入也最简单。
1-2 创建一个新包
最直观的方式是敲几行命令。先建个空目录,再用 swift package init 初始化。
$ mkdir hello-pkg && cd hello-pkg
$ swift package init --type executable
$ swift build
$ swift run
Hello, world!
--type executable 表示你要做一个能直接运行的程序。如果你省略类型,默认也是创建可执行包;想做纯库则改用 --type library。
swift build 负责编译,swift run 编译并立刻运行生成的二进制文件。第一次构建会慢一点,因为要下载并编译依赖(哪怕现在还没有依赖),之后就有缓存了。
1-3 包的目录长什么样
执行完 init,目录里会出现一套约定俗成的结构。你不用死记,但得知道每样东西干嘛用。
hello-pkg/
├── Package.swift # 包的清单文件,最核心
├── Sources/ # 你的源码放这里
│ └── hello-pkg/
│ └── main.swift
├── Tests/ # 测试代码放这里
│ └── hello-pkgTests/
│ └── hello_pkgTests.swift
└── .gitignore
Package.swift 是包的”说明书”,SPM 全部行为都照它来。Sources 放正式代码,每个子目录通常对应一个 target。Tests 放单元测试,后面讲测试那章会细说。
初学者常在这里踩坑:把文件放错目录,SPM 找不到源码。记住,源码必须进 Sources 下对应 target 的文件夹,SPM 不会去外面乱翻。
1-4 读懂 Package.swift
清单文件第一行的 swift-tools-version 声明了你用的 SPM 版本特性。Swift 6.x 工具链对应 6.0。
// swift-tools-version:6.0
import PackageDescription
let package = Package(
name: "hello-pkg",
products: [
.executable(name: "hello-pkg", targets: ["hello-pkg"]),
],
dependencies: [
// .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0")
],
targets: [
.executableTarget(
name: "hello-pkg",
dependencies: []
)
]
)
最上面 import PackageDescription 是必须的,清单本身也是 Swift 代码,它调用了 Package(...) 这个构造器。name 是包名,后面 product 和依赖都靠名字引用。
1-5 target、product、dependency 三件套
这三个词是 SPM 的骨架,必须分清。
target 是编译的最小单元,对应 Sources 里的一个模块。一个 target 里的源码一起编译、一起产出。可以是可执行 target(.executableTarget),也可以是库 target(.target)。
product 是你对外”发布”的东西,是别人能 import 或用到的成果。它分两种:可执行文件(executable)和库(library)。一个 product 可以由一个或多个 target 组成。
dependency 是你要用的外部包,或者本包内部 target 之间的依赖关系。
打个比方:你开了一家餐馆(包),厨房里分了凉菜间、热菜间(target),摆在大厅卖给客人的是套餐(product),而做菜要用到的调料是从供货商进的(dependency)。target 是内部怎么组织,product 是对外给什么,dependency 是你依赖谁。
1-6 可执行包与库包的区别
可执行包有一个特殊入口:带 @main 标记的类型,或者老式的 main.swift 顶层代码。编译后它产出能直接跑的程序,swift run 就用得上。
库包没有入口,它只产出可以被别人 import 的模块。它的 product 写成 .library(name: "MyLib", targets: ["MyLib"])。别人把你的包当成依赖加进去后,就能 import MyLib 使用里面的公开 API。
// 库包的 product 写法
products: [
.library(name: "MathTools", targets: ["MathTools"]),
],
targets: [
.target(name: "MathTools", dependencies: []),
]
Tip初学阶段,先做可执行包体会 SPM 最省事:写几行
swift run立刻看到结果。等你想把一段逻辑分享给别人,再改成库包。
1-7 常用的 SPM 命令
除了 build 和 run,还有几条值得记住。
$ swift package resolve # 拉取/更新依赖到最新解析结果
$ swift package clean # 清掉构建缓存,从头编译
$ swift package update # 按版本规则更新依赖
resolve 在你刚改完 Package.swift 加依赖时很有用;clean 在构建行为诡异、怀疑缓存出错时,是排错第一招。
Warning
swift package clean会删掉编译产物,下次 build 会全量重编,比较慢,别在赶时间时随手敲。
1-8 把代码拆成多个 target
一个稍大的包,常常把功能拆成几个 target,彼此通过依赖关联。比如核心逻辑放 Core target,命令行界面放 CLI target,让 CLI 依赖 Core。
targets: [
.target(name: "Core", dependencies: []),
.executableTarget(name: "CLI", dependencies: ["Core"]),
]
这样 Core 里写纯逻辑,CLI 只管接收参数、调用 Core,结构清楚也好测试。SPM 会自动按依赖顺序编译,你不用手动管先后。
1-9 构建配置与运行参数
swift build 默认是调试模式,带优化关闭、断言生效。要打发布版,加 --configuration release,编译更慢但跑起来更快。
$ swift build -c release
$ swift run hello-pkg --verbose
swift run 后面跟的 --verbose 这类参数,会原样传给你的程序,而不是给 SPM。想看 SPM 自己的 verbose 日志,则写在 swift 和子命令之间,比如 swift package --verbose resolve。这种”参数归谁”的区分,初学时容易搞混。
Tip本地试功能用默认 debug 构建(快、断言能抓 bug);给别人用的成品再用
-c release。别把 debug 二进制当正式发布。
1-10 新手常踩的坑
第一个坑是目录结构。SPM 严格按 Sources/<target名>/ 找源码。你若把 main.swift 随手丢在 Sources 根下而不是 target 子目录,构建会告诉你找不到入口。target 名和文件夹名默认要对上。
第二个坑是 Package.swift 改了却没生效。SPM 有缓存,改完依赖后记得 swift package resolve 让它重新拉取,必要时 swift package clean 清缓存再 build。
第三个坑是把 SPM 和 Xcode 的工程文件混为一谈。纯 SPM 包不需要 .xcodeproj,它靠 Package.swift 描述一切。你在纯命令行环境(Linux、CI)里跑的就是这套,不依赖 Xcode。
1-11 什么时候该用 SPM
并不是所有代码都要包成 SPM 包。一行小脚本,直接 swift run 一个文件更轻。但凡出现下面任一情况,就该上 SPM:要复用一段逻辑、要引入第三方库、要分模块组织、要写测试。它把”工程该有的样子”标准化了,省去你自己定规范。
1-12 小结
SPM 把”建工程、拉依赖、编译运行”三件事统一了。记住四个落地点:用 swift package init 起手,Package.swift 是总管家,target 是编译单元、product 是对外成果、dependency 是外部依赖,最后用 swift build 和 swift run 看到结果。下一章我们专门讲怎么在 dependencies 里加别人的包,以及版本号该怎么写。