Swift Package Manager 清单 API 重新设计
Swift 4 中的 Package Manager 包含了重新设计的 Package.swift
清单 API。新的 API 更易于使用,并遵循了设计指南。Swift 3 Package Manager 中的目标推断规则是常见的困惑来源。我们修改了这些规则,并移除了大部分推断,倾向于在清单中显式指定 package 结构的实践。
Swift 3 的 package 将继续工作,因为 Swift 4 中的 Package Manager 是向后兼容的。清单版本由 package 的工具版本选择。工具版本在清单的第一行指定,使用特殊的注释语法:// swift-tools-version:<specifier>
。省略此特殊注释的 package 将默认使用工具版本 3.1.0。
工具版本还决定了用于编译 package 源代码的默认 Swift 语言版本。现有的 Swift 3 package 将在 Swift 3 兼容模式下编译。如果您不想要默认版本,可以选择在 Swift 3 和 Swift 4 清单中使用 swiftLanguageVersions
属性来设置用于编译该 package 的语言版本。这意味着可以在不将源代码升级到 Swift 4 的情况下,升级 package 以使用较新的清单格式。
在 Swift 4 中创建新的 Package
使用 init
子命令在 Swift 4 中创建一个新的 package
$ mkdir mytool && cd mytool
$ swift package init
$ swift build
$ swift test
上述命令生成的 Package.swift
清单如下所示。
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "mytool",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "mytool",
targets: ["mytool"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target defines a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "mytool",
dependencies: []),
.testTarget(
name: "mytoolTests",
dependencies: ["mytool"]),
]
)
上述 Swift 4 清单与之前的清单格式之间有三个主要区别
- 工具版本
4.0
使用// swift-tools-version:4.0
行指定。 - 所有 target 及其依赖项都必须显式声明。
- 公共 target 使用新的 product API 作为 product 销售。Swift 4 package 中的 target 可以依赖于其他 package 的 product,也可以依赖于同一 package 的 target。
自定义 Target 布局
新的清单支持自定义 package 的布局。Package 不再需要遵循复杂的、基于约定的布局规则。只有一个规则:如果未提供 target 路径,将搜索目录 Sources
、Source
、src
、srcs
和 Tests
(按顺序)以查找 target。
自定义布局使将 C 库移植到 Swift Package Manager 变得更容易。以下是服务器端 Swift 社区中使用的两个 C 库的清单
LibYAML
Copyright (c) 2006-2016 Kirill Simonov, licensed under MIT license (https://github.com/yaml/libyaml/blob/master/LICENSE)
// swift-tools-version:4.0
import PackageDescription
let packages = Package(
name: "LibYAML",
products: [
.library(
name: "libyaml",
targets: ["libyaml"]),
],
targets: [
.target(
name: "libyaml",
path: ".",
sources: ["src"])
]
)
Node.js http-parser
Copyright by Authors (https://github.com/nodejs/http-parser/blob/master/AUTHORS), licensed under MIT license (https://github.com/nodejs/http-parser/blob/master/LICENSE-MIT)
// swift-tools-version:4.0
import PackageDescription
let packages = Package(
name: "http-parser",
products: [
.library(
name: "httpparser",
targets: ["http-parser"]),
],
targets: [
.target(
name: "http-parser",
publicHeaders: ".",
sources: ["http_parser.c"])
]
)
依赖项解析
由于 Swift 3 Package Manager 不理解 Swift 4 清单格式,它将自动忽略包含 Swift 4 清单的 Git 标签。因此,如果 package 升级到 Swift 4 清单,Swift 3 Package Manager 将选择包含 Swift 3 清单的最后一个标签。但是,Swift 4 中的 Package Manager 将选择最新的可用版本,而无需考虑清单版本。
将现有 Package 更新到 Swift 4 清单格式
按照以下步骤更新现有 package 以使用 Swift 4 清单格式。
-
更新 package 的工具版本。
使用
tools-version
子命令更新 package 的工具版本。
$ cd mypackage
$ swift package tools-version --set-current
- 将
dependencies
标签移动到targets
标签之前,并更新 package 依赖项语法。例如
...
dependencies: [
- .Package(url: "https://github.com/apple/example-package-fisheryates.git", majorVersion: 2),
+ .package(url: "https://github.com/apple/example-package-fisheryates.git", from: "2.0.0"),
- .Package(url: "https://github.com/apple/example-package-playingcard.git", majorVersion: 3, minor: 3),
+ .package(url: "https://github.com/apple/example-package-playingcard.git", .upToNextMinor(from: "3.3.0")),
]
...
-
声明所有常规 target 和测试 target。
所有 target 及其依赖项都应显式声明。如果有两个 target,
Foo
和FooTests
,请在targets
标签中声明它们。例如
...
targets: [
.target(
name: "Foo"),
.testTarget(
name: "FooTests",
dependencies: ["Foo"]),
]
...
-
如果 package 正在使用旧的单 target 布局,请更新布局或提供 target 路径。
推荐的布局是在
Sources
下为每个 target 设置一个目录,即Sources/<target-name>
。如果 package 正在使用此布局,则将自动检测到 target 路径。否则,请提供 target 路径。例如
...
targets: [
.target(
name: "Foo",
path: "."), // The sources are located in package root.
.target(
name: "Bar",
path: "Sources") // The sources are located in directory Sources/.
]
...
-
使用 product API 导出公共 target。
库 package 应显式导出其公共 target,以允许其他 package 导入它们。避免导出诸如示例代码 target、测试支持库等 target。
...
products: [
.library(
name: "Foo",
targets: ["Foo", "Bar"]),
],
...
-
在 Swift 3 兼容模式下编译。
您可以在将 package 的源代码更新到 Swift 4 之前,将 package 清单更新为新格式。为此,请将
swiftLanguageVersions
属性设置为 3,以在 Swift 3 兼容模式下构建 package。
...
swiftLanguageVersions: [3]
...