Swift 4.2 日本語化計画 : Swift 4.2
パッケージマネージャ
Swift Package Manager は、Swift コードの配布を管理するためのツールです。ダウンロード、コンパイル、および依存関係リンクのプロセスを自動化するために、Swift ビルドシステムと統合されています。
パッケージマネージャは、Swift 3.0 以上に含まれています。
概念の概要
このセクションでは、Swift Package Manager の機能を動機付ける基本的な概念について説明します。
モジュール
Swift は、コードを モジュール に整理します。各モジュールは名前空間を指定し、そのコードの一部をモジュール外で使用できるアクセス制御を強制します。
プログラムは、すべてのコードを 1 つのモジュール内に持つこともあれば、他のモジュールを 依存関係 としてインポートすることもあります。MacOS 上の Darwin や Linux 上の Glibc など、システムが提供するいくつものモジュールのほかに、ほとんどの依存関係では、コードをダウンロードして使用するためにビルドする必要があります。
特定の問題を解決するコードに別のモジュールを使用すると、そのコードは他の状況で再利用できます。例えば、ネットワーク要求を作成するための機能を提供するモジュールは、写真共有アプリと天気アプリとの間で共有することができます。モジュールを使用すると、同じ機能を自分自身で再実装するのではなく、他の開発者のコードの上にビルドできます。
パッケージ
パッケージ は Swift ソースファイルとマニフェストファイルで構成されます。Package.swift というマニフェストファイルは、PackageDescription モジュールを使用してパッケージの名前とその内容を定義します。
パッケージには 1 つ以上のターゲットがあります。各ターゲットは製品を指定し、1 つ以上の依存関係を宣言することができます。
製品
ターゲットは、その製品としてライブラリまたは実行可能ファイルのいずれかをビルドできます。ライブラリ には、他の Swift コードでインポートできるモジュールが含まれています。実行可能ファイル は、オペレーティングシステムによって実行できるプログラムです。
依存関係
ターゲットの依存関係は、パッケージ内のコードによって必要とされるモジュールです。依存関係は、パッケージのソースへの相対 URL または絶対 URL と、使用可能なパッケージのバージョンに対する一連の要件で構成されます。パッケージマネージャの役割は、プロジェクトのすべての依存関係をダウンロードしてビルドするプロセスを自動化することによって、調整コストを削減することです。これは再帰的プロセスです。依存関係には独自の依存関係を持たせることができ、それぞれの依存関係も依存関係を持つ事ができ、依存関係グラフを作成することもできます。パッケージマネージャは、依存関係グラフ全体を満たすために必要なすべてをダウンロードしてビルドします。
コード例を踏襲したい場合は、Swift をインストールしておく必要があります。Swift をインストールする方法については、入門 を参照してください。
例の使用法
Swift 入門 では、Swift Package Manager を使用して簡単な "Hello、world!" プログラムをビルドします。
Swift Package Manager ができることをより完全に理解するために、以下の例は 4 つの相互依存するパッケージで構成されています。
- PlayingCard - PlayingCard、Suit、および Rank の型を定義します。
- FisherYates - shuffle() および shuffleInPlace() メソッドを実装する拡張を定義します。
- DeckOfPlayingCards - PlayingCard 値の配列をシャッフルして扱う Deck 型を定義します。
- Dealer - DeckOfPlayingCards を作成し、シャッフルして最初の 10 枚のカードを処理する実行可能ファイルを定義します。
$ git clone https://github.com/apple/example-package-dealer.git $ cd example-package-dealer $ swift run Dealer
ライブラリパッケージの作成
標準の 52 枚のカードデッキにトランプを表すターゲットを作成する事から始めます。PlayingCard ターゲットは、Suit 列挙値 (Clubs、Diamonds、Hearts、Spades) と Rank 列挙値 (Ace、Two、Three、...、Jack、Queen、King) からなる PlayingCard 型を定義します。
public enum Rank : Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King } public enum Suit: String { case Spades, Hearts, Diamonds, Clubs } public struct PlayingCard { let rank: Rank let suit: Suit }
慣例として、ターゲットには、Sources/<target-name> ディレクトリにある全てののソースファイルが含まれます。
example-package-playingcard ├─ Sources │ ├── PlayingCard.swift │ ├── Rank.swift │ └── Suit.swift └── Package.swift
PlayingCard ターゲットは実行可能ファイルを生成しないため、ライブラリ として記述できます。ライブラリとは、他のパッケージからインポートできるモジュールをビルドするターゲットです。デフォルトでは、ライブラリモジュールは、Sources/<target-name> ディレクトリにあるソースコードで宣言されているすべての public 型とメソッドを公開します。
Swift ビルドプロセスを開始するために swift build を実行します。すべて正常に動作した場合、PlayingCard の Swift モジュールをコンパイルします。
ビルド構成文の使用
ビルドする次のモジュールは FisherYates です。PlayingCard とは異なり、このモジュールは新しい型を定義しません。その代わりに、既存の型、特に CollectionType と MutableCollectionType のプロトコルを拡張して、 shuffle() メソッドとそれに対応する変更可能な shuffleInPlace() メソッドを追加します。
shuffleInPlace() の実装では、Fisher-Yates アルゴリズムを使用して、コレクション内の要素をランダムに並べ替えます。Swift 標準ライブラリは乱数発生器を提供しないため、このメソッドはシステムモジュールからインポートされた関数を呼び出さなければなりません。この関数が macOS と Linux の両方と互換性があるために、コードはビルド構成文を使用します。
macOS では、システムモジュールは Darwin であり、これは arc4random_uniform(_:) 関数を提供します。Linux では、システムモジュールは Glibc であり、random() 関数を提供します:
#if os(Linux) import Glibc #else import Darwin.C #endif public extension MutableCollectionType where Index == Int { mutating func shuffleInPlace() { if count <= 1 { return } for i in 0..<count - 1 { #if os(Linux) let j = Int(random() % (count - i)) + i #else let j = Int(arc4random_uniform(UInt32(count - i))) + i #endif if i == j { continue } swap(&self[i], &self[j]) } } }
依存関係のインポート
DeckOfPlayingCards パッケージは、前の 2 つのパッケージを一緒にします。これは、PlayCard 値の配列に対して FisherYates からの shuffle() メソッドを使用する Deck 型を定義します。
FisherYates および PlayingCards モジュールを使用するには、DeckOfPlayingCards パッケージは、そのパッケージをその Package.swift マニフェストファイルの依存関係として宣言しなければなりません。
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "DeckOfPlayingCards",
products: [
.library(name: "DeckOfPlayingCards", targets: ["DeckOfPlayingCards"]),
],
dependencies: [
.package(url: "https://github.com/apple/example-package-fisheryates.git", from: "2.0.0"),
.package(url: "https://github.com/apple/example-package-playingcard.git", from: "3.0.0"),
],
targets: [
.target(
name: "DeckOfPlayingCards",
dependencies: ["FisherYates", "PlayingCard"]),
.testTarget(
name: "DeckOfPlayingCardsTests",
dependencies: ["DeckOfPlayingCards"]),
]
)
各々の依存関係は、ソースの URL とバージョン要件を指定します。ソースの URL は、現在のユーザーにアクセス可能な URL で、Git リポジトリに解決します。セマンティックバージョニング (SemVer) 規約に従うバージョン要件は、どの Git タグをチェックアウトして依存関係をビルドするのかを決定するために使用されます。FisherYates の依存関係では、メジャーバージョンが 2 (たとえば、2.0.4) の最新バージョンが使用されます。同様に、PlayingCard の依存関係は、メジャーバージョンが 3 の最新バージョンを使用します。
swift build コマンドを実行すると、パッケージマネージャはすべての依存関係をダウンロードし、それをコンパイルしてパッケージモジュールにリンクします。これにより、DeckOfPlayingCards は、import 文を使用して、依存モジュールのパブリックメンバーにアクセスできます。
ダウンロードしたソースは、プロジェクトのルートにある .build/checkouts ディレクトリ、およびプロジェクトのルートにある .build ディレクトリにある中間ビルドプロダクトで確認できます。
副依存関係の解決
他のすべてが整ったら、Dealer モジュールをビルドすることができます。Dealer モジュールは、 DeckOfPlayingCards パッケージに依存し、これは、PlayingCard パッケージと FisherYates パッケージに順番に依存します。ただし、Swift Package Manager は副依存関係を自動的に解決するため、DeckOfPlayingCards パッケージを依存関係として宣言するだけで済みます。
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "dealer",
products: [
.executable(name: "Dealer", targets: ["Dealer"]),
],
dependencies: [
.package(url: "https://github.com/apple/example-package-deckofplayingcards.git", from: "3.0.0"),
],
targets: [
.target(
name: "Dealer",
dependencies: ["DeckOfPlayingCards"]),
]
)
Swift では、コードで参照される全ての型のモジュールはソースファイルがインポートする必要があります。 Dealer モジュールの main.swift ファイルでは、DeckOfPlayingCards から Deck 型と PlayingCard から PlayingCard 型が参照されます。Deck 型の shuffle() メソッドは FisherYates モジュールを内部的に使用しますが、そのモジュールは main.swift にインポートする必要はありません。
import PlayingCard import DeckOfPlayingCards let numberOfCards = 10 var deck = Deck.standard52CardDeck() deck.shuffle() for _ in 1...numberOfCards { guard let card = deck.deal() else { print("No More Cards!") break } print(card) }
通常、そのディレクトリに main.swift という名前のファイルを含むターゲットは、実行可能ファイルを生成します。
swift build コマンドを実行すると、Swift ビルドシステムが起動され、.build/debug ディレクトリから実行可能な Dealer 実行可能ファイルを生成します。
$ swift build $ ./.build/debug/Dealer ♠︎6 ♢K ♢2 ♡8 ♠︎7 ♣︎10 ♣︎5 ♢A ♡Q ♡7
Dealer パッケージの完全なコードは https://github.com/apple/example-package-dealer にあります。
Swift Package Manager の使用方法の詳細については、GitHub の Swift Package Manager プロジェクト で提供されているマニュアルを参照してください。