Swift Package Manager (SwiftPM)  Version 4 概要

この記事は、Swift Package Manager (以下 SwiftPM) の Version 3 から 4 への変更内容をまとめたものです。

有効に活用するためにはさらに掘り下げていきたいところですが、この記事では概要にとどめています。なお SwiftPM の基本的な使い方はすでに [参考になるスライド、記事、ツール](#参考) がありますのでそちらを参考にしてください。

# はじめに

SwiftPM は Swift 3 で登場しました。まだ発展途上で CocoaPods や Carthage に変わる存在とまではいかないものの、すでに Swift 製のコマンドラインツールやサーバーサイド Swift で活用されています。

さて今回の WWDC17 ではどのような発表があったのか、ビデオとスライドで確認しました。ただこれまで見た限り [Session 402「What’s New in Swift」](https://developer.apple.com/videos/play/wwdc2017/402/) で少し触れられているだけで詳しくは語られていないようです。

そこで [Swift Evolution](https://apple.github.io/swift-evolution/) を確認しました。

# Swift Evolution
https://apple.github.io/swift-evolution/

検索欄に「Package Manager」と入力して SwiftPM 関連を抽出しました。

<img width="1002" alt="SwiftEvolution.png" src="https://qiita-image-store.s3.amazonaws.com/0/105213/02d49c2d-bf17-92ec-e156-6c777ce37772.png">

14 件のプロポーザルが抽出されますが Swift 4 で実装されたものは次の 6 件です。

## Swift 4 で実装されたもの
- [SE-0146 Package Manager Product Definitions](https://github.com/apple/swift-evolution/blob/master/proposals/0146-package-manager-product-definitions.md)
- [SE-0149 Package Manager Support for Top of Tree development](https://github.com/apple/swift-evolution/blob/master/proposals/0149-package-manager-top-of-tree.md)
- [SE-0150 Package Manager Support for branches](https://github.com/apple/swift-evolution/blob/master/proposals/0150-package-manager-branch-support.md)
- [SE-0158 Package Manager Manifest API Redesign](https://github.com/apple/swift-evolution/blob/master/proposals/0158-package-manager-manifest-api-redesign.md)
- [SE-0162 Package Manager Custom Target Layouts](https://github.com/apple/swift-evolution/blob/master/proposals/0162-package-manager-custom-target-layouts.md)
- [SE-0175 Package Manager Revised Dependency Resolution](https://github.com/apple/swift-evolution/blob/master/proposals/0175-package-manager-revised-dependency-resolution.md)

このほか、すでに実装されていましたが Swift 4 に関わるものとして次のプロポーザルがあります。

## Swift 3.1 で実装されたもの
- [SE-0151 Package Manager Swift Language Compatibility Version](https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md) 
- [SE-0152 Package Manager Tools Version](https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md)

# それぞれの概要
## [SE-0151 Package Manager Swift Language Compatibility Version](https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md)
- 後方互換性維持のため Swift 3.1 で実装されました。

### Example
```swift
let package = Package(
    name: "Pancake",
    ...
    swiftLanguageVersions: [3, 4])
```

#### 事例
##### SwiftPM Version 3
- `swiftLanguageVersions: [3]`
  - Swift 3 でコンパイルされます。
- `swiftLanguageVersions: [4]`
  - SwiftPM Version 3 が Swift 4 をサポートしていないためエラーになります。
- `swiftLanguageVersions: [3, 4]`
  - Swift 3 でコンパイルされます。


##### SwiftPM Version 4
- `swiftLanguageVersions: [3]`
  - Swift 3 でコンパイルされます。
- `swiftLanguageVersions: [4]`
  - Swift 4 でコンパイルされます。
- `swiftLanguageVersions: [3, 4]`
  - Swift 4 でコンパイルされます。

## [SE-0152 Package Manager Tools Version](https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md)
- 後方互換性維持のため Swift 3.1 で実装されました。

### SwiftPM Version 4 を使用している場合
#### Package のツールバージョンを確認

```
$ swift package tools-version

4.0.0
```

#### Version 3 に設定

```
$ swift package tools-version --set 3.0.0
$ swift package tools-version

3.0.0
```

#### 使用中のツールバージョンに設定

```
$ swift package tools-version --set-current
$ swift package tools-version

4.0.0
```

## [SE-0146 Package Manager Product Definitions](https://github.com/apple/swift-evolution/blob/master/proposals/0146-package-manager-product-definitions.md)
- Product が導入されました。
  - Package 内で任意の Target を限定して公開できるようになりました。（従来は Package を分割する必要がありました）
- マニフェスト（`Package.swift`）が Version 3 の場合は既存コードへの影響はありません。

## [SE-0149 Package Manager Support for Top of Tree development](https://github.com/apple/swift-evolution/blob/master/proposals/0149-package-manager-top-of-tree.md)
- `$ swift package edit` コマンドに `--path` オプションが追加されました。
- 既存コードへの影響はありません。

## [SE-0150 Package Manager Support for branches](https://github.com/apple/swift-evolution/blob/master/proposals/0150-package-manager-branch-support.md)
- 依存する Package のブランチやリビジョンを指定できるようになりました。（従来は Version（タグ）を指定する必要がありました）
- 既存コードへの影響はありません。

### Example
```swift
import PackageDescription

let package = Package(
    name: "Pancake",
    dependencies: [
        .Package(url: "../PancakeCore", branch: "matcha"),
    ]
)
```

### Example
```swift
import PackageDescription

let package = Package(
    name: "Pancake",
    dependencies: [
        .Package(url: "../PancakeCore", revision: "0123456789012345678901234567890123456789"),
    ]
)
```

リビジョンは 40 文字のコミットハッシュを指定します。

## [SE-0158 Package Manager Manifest API Redesign](https://github.com/apple/swift-evolution/blob/master/proposals/0158-package-manager-manifest-api-redesign.md)
- マニフェストの既存 API が再設計されました。
  - Version の指定方法などが変更されました。 
- 新機能追加は別のプロポーザルで行われています。

## [SE-0162 Package Manager Custom Target Layouts](https://github.com/apple/swift-evolution/blob/master/proposals/0162-package-manager-custom-target-layouts.md)
- マニフェストで Target を明示的に宣言するようになりました。（省略不可）
- `Sources` や `Tests` のパスを任意に指定できるようになりました。（従来は規定がありました）
- `Target` クラスに 3 つのプロパティが追加されました。
  - `path`: Package のルートディレクトリを基準にソースファイルのパスを指定します。
  - `sources`: Target に含めるソースを指定します。デフォルトは `nil` ですべてのファイルが対象になります。
  - `exclude`: ソースから除外するディレクトリやファイルを指定します。`sources` の設定より優先されます。（従来は `Package` クラスで設定していましたがこちらは削除されました）
- マニフェストが Version 3 の場合は既存コードへの影響はありません。

### Example
```swift
.target(name: "Pancake", path: "Sources/Pancake", exclude: ["Tests"]),
.testTarget(name: "PancakeTests", dependencies: ["Pancake"], path: "Sources/Pancake/Tests"),
```

### Version 4 への移行

前述のとおり Package のマニフェストが Version 3 の場合は既存コードへの影響はありませんが、Version 4 へ移行する場合はマニフェストを更新する必要があります。

```
Package.swift
Sources/
Tests/
```

```swift
import PackageDescription

let package = Package(
    name: "Pancake",
    targets: [
        .target(name: "Pancake", path: "Sources"),
        .testTarget(name: "PancakeTests", dependencies: ["Pancake"], path: "Tests"),
    ]
)
```

## [SE-0175 Package Manager Revised Dependency Resolution](https://github.com/apple/swift-evolution/blob/master/proposals/0175-package-manager-revised-dependency-resolution.md)
- 依存関係解決処理の改善が図られました。
  - `$ swift package pin/unpin` コマンドが廃止されました。
  - `$ swift package fetch` コマンドが `$ swift package resolve` コマンドに置き換えられました。
  - `Package.pins` ファイルが `Package.resolved` ファイルに置き換えられました。

# 参考
- [swift-build-dev] Swift 4 Package Manager Update
  - [https://lists.swift.org/pipermail/swift-build-dev/Week-of-Mon-20170605/001019.html](https://lists.swift.org/pipermail/swift-build-dev/Week-of-Mon-20170605/001019.html)
- Swift Package Manager Manifest API Redesign
  - https://swift.org/blog/swift-package-manager-manifest-api-redesign/
- State of the Swift PM from the Swift PM PM [*@ericasadun*](https://twitter.com/ericasadun)
 - http://ericasadun.com/2017/06/06/state-of-the-swift-pm-from-the-swift-pm-pm/
- 実践 Swift Package Manager *@ikesyo*
 - https://speakerdeck.com/ikesyo/shi-jian-swift-package-manager
- Swift Package Manager (SwiftPM) で作るコマンドラインツール」*@mono0926*
 - http://qiita.com/mono0926/items/e8fdd97115780204f797
- 実践Server Side Swift [*@noppoMan722*](https://twitter.com/noppoMan722)
 - https://speakerdeck.com/noppoman/shi-jian-server-side-swift
- swift-tweets/swtws *@koher*
 - https://github.com/swift-tweets/swtws

以上、詳しくは今後別の記事で紹介します。