2015年12月3日のオープンソースSwift言語でのリリースに伴い、Appleは分散型依存関係マネージャーSwift Package Managerを導入しました。
Homebrewの作成者である悪名高いMax HowellとAFNetworkingを書いたMatt Thompsonは、公開版に手を携えていた。 SwiftPMは、依存関係のインストールプロセスを自動化するように設計されており、利用可能なすべてのオペレーティングシステムでSwiftでプロジェクトをさらにテストおよびビルドしますが、これまでサポートしているのはmacOSとLinuxのみです。 興味がある場合は、猫の下に行きます。
最小要件はSwift 3.0です。 プロジェクトファイルを開くには、Xcode 8.0以降が必要です。 SwiftPMでは、xcodeprojファイルなしでプロジェクトを操作できるため、OS XのXcodeはオプションですが、Linuxではそうではありません。
疑問を払拭する価値があります-プロジェクトはまだ活発に開発されています。 SwiftPMはソースコードの形式で依存関係を接続し、収集するため、UIKit、AppKit、およびその他のiOSおよびOS X SDKフレームワークを依存関係として使用することはできません。 したがって、iOSでSwiftPM、watchOS、およびtvOSを使用することは可能ですが、Foundationとサードパーティライブラリの依存関係を使用するのはオープンアクセスのみです。 単一のインポートUIKitにより、SwiftPMでライブラリを使用できなくなります。
この記事のすべての例は、バージョン4.0.0-devを使用して記述されています。ターミナルのコマンドを使用してバージョンを確認できます。
swift package —version
Ideology Swift Package Manager
プロジェクトで作業するために、* .xcodprojファイルは不要になりました-補助ツールとして使用できるようになりました。 モジュールのアセンブリに関係するファイルは、ディスク上の場所によって異なります。SwiftPMにとって、プロジェクト内のディレクトリ名と階層は重要です。 プロジェクトディレクトリの初期構造は次のとおりです。
- ソース-パッケージをアセンブルするためのソースファイル。製品ディレクトリごとに内部的に分割され、各製品には個別のフォルダーがあります。
- テスト-開発された製品のテスト、フォルダーへの分割はSourcesフォルダーに似ています。
- Package.swift-パッケージの説明を含むファイル。
- README.md-パッケージドキュメントファイル。
SourcesおよびTestsフォルダー内で、SwiftPMはすべての* .swiftファイルを再帰的に検索し、それらをルートフォルダーに関連付けます。 少し後で、ファイルを含むサブフォルダーを作成します。
主なコンポーネント
次に、SwiftPMの主要コンポーネントを見てみましょう。
- モジュール -* .swiftのセット–特定のタスクを実行するファイル。 1つのモジュールは、依存関係として接続する別のモジュールの機能を使用できます。 プロジェクトは、単一のモジュールに基づいて組み立てることができます。 ソースコードをモジュールに分割すると、別のプロジェクトをビルドするときに再利用できる別のモジュールの関数を選択できます。 たとえば、ネットワーククエリモジュールまたはデータベースモジュール。 モジュールは内部レベルのカプセル化しきい値を使用し、プロジェクトに接続できるライブラリー(ライブラリー)です。 モジュールは、同じパッケージ(別のターゲットとして表示)と別のパッケージ(別の製品として表示)の両方から接続できます。
- 製品 (製品)-プロジェクトのアセンブリターゲット(ターゲット)の結果。 ライブラリ(ライブラリ)または実行可能ファイル(実行可能ファイル)のいずれかです。 製品には、この製品に直接関連するソースコードと、それが依存するモジュールのソースコードが含まれています。
- パッケージ (パッケージ)-* .swift –ファイルのセットと、パッケージの名前とソースファイルのセットを定義するマニフェストファイルPackage.swift。 パッケージには1つ以上のモジュールが含まれます。
- 依存関係は、パッケージ内のソースコードに必要なモジュールです。 依存関係には、パス(gitリポジトリへの相対ローカルまたはリモート)、バージョン、依存関係のリストが必要です。 SwiftPMは、メインモジュールにコンパイルして接続するために、依存関係のソースコードにアクセスできる必要があります。 ターゲット依存関係は、同じパッケージまたは依存パッケージからのターゲットにすることができます。
依存関係がグラフに配置されていることを取得します-各依存関係は独自のものを持つことができます。 依存関係グラフの解決は、依存関係マネージャーの主なタスクです。
すべてのソースファイルはSwiftで作成する必要があり、Objective-Cを使用する可能性はありません。
各パッケージは自己完結型で隔離されている必要があります。 そのデバッグは、開始(実行)ではなく、論理テスト(テスト)によって実行されます。
以下は、Alamofire依存関係をプロジェクトに接続する簡単な例です。
テストプロジェクト開発
ターミナルを介して、プロジェクトのあるフォルダーに移動し、そのディレクトリを作成して、そこに移動します。
mkdir IPInfoExample cd IPInfoExample/
次に、コマンドを使用してパッケージを初期化します
swift package init
その結果、次のソースファイルの階層が作成されます。
├── Package.swift ├── README.md ├── Sources │ └── IPInfoExample │ └── main.swift └── Tests └── IPInfoExampleTests ├ LinuxMain.swift └── IPInfoExampleTests └── IPInfoExampleTests.swift
* .xcodeprojプロジェクトファイルのインデックスがない場合、依存関係マネージャーは、ビルドプロセスに含める必要があるソースファイルと、それらを含めるターゲットを知る必要があります。 したがって、SwiftPMはフォルダーの厳密な階層とファイルのリストを定義します。
- パッケージファイル
- READMEファイル。
- ソースファイルのあるSourcesフォルダー-各ターゲットの個別のフォルダー。
- テストフォルダー-各テストターゲット用の個別のフォルダー。
これでコマンドを実行できます
swift build swift test
パッケージをビルドするか、テストを実行するにはHello、world!
ソースファイルを追加する
Application.swiftファイルを作成し、IPInfoExampleフォルダーに配置します。
public struct Application {}
迅速なビルドを実行し、2つのファイルがモジュールで既にコンパイルされていることを確認します。
Compile Swift Module 'IPInfoExample' (2 sources)
IPInfoExampleフォルダーにModelディレクトリを作成し、IPInfo.swiftファイルを作成し、不要な場合はIPInfoExample.swiftファイルを削除します。
// Codable JSON public struct IPInfo: Codable { let ip: String let city: String let region: String let country: String }
その後、swift buildコマンドを実行して確認します。
依存関係を追加
Package.swiftファイルを開いてみましょう。コンテンツはパッケージを完全に説明しています:パッケージ名、依存関係、ターゲット。 Alamofire依存関係を追加します。
// swift-tools-version:4.0 import PackageDescription // , let package = Package( name: "IPInfoExample", // products: [ .library( name: "IPInfoExample", targets: ["IPInfoExample"]), ], dependencies: [ // - Alamofire, GitHub .package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.0.0") ], targets: [ .target( name: "IPInfoExample", // – , // Alamofire dependencies: ["Alamofire"]), .testTarget( name: "IPInfoExampleTests", dependencies: ["IPInfoExample"]), ] )
再度、迅速なビルドが行われ、依存関係がダウンロードされ、インストールされた依存関係の説明を含むPackage.resolvedファイルが作成されます(Podfile.lockと同様)。
パッケージに製品が1つしかない場合、パッケージ名、製品、およびターゲットに同じ名前を使用できます。 このIPInfoExampleがあります。 したがって、製品のパラメーターを省略することで、パッケージの説明を短縮できます。 Alamofireパッケージの説明を見ると、ターゲットがそこに記述されていないことがわかります。 デフォルトでは、Sourcesフォルダーのパッケージ名とソースコードファイルを使用して1つのターゲットが作成され、パッケージ記述ファイル(PackageDescription)を使用して1つのターゲットが作成されます。 SwiftPMを使用する場合、テストターゲットは関係しないため、テストフォルダーは除外されます。
import PackageDescription let package = Package(name: "Alamofire", dependencies : [], exclude: [“Tests"])
モジュール、ターゲット、製品が正しく作成されたことを確認するために、コマンドを実行できます
swift package describe
その結果、Alamofireの場合、次のログが取得されます。
Name: Alamofire Path: /Users/ivanvavilov/Documents/Xcode/Alamofire Modules: Name: Alamofire C99name: Alamofire Type: library Module type: SwiftTarget Path: /Users/ivanvavilov/Documents/Xcode/Alamofire/Source Sources: AFError.swift, Alamofire.swift, DispatchQueue+Alamofire.swift, MultipartFormData.swift, NetworkReachabilityManager.swift, Notifications.swift, ParameterEncoding.swift, Request.swift, Response.swift, ResponseSerialization.swift, Result.swift, ServerTrustPolicy.swift, SessionDelegate.swift, SessionManager.swift, TaskDelegate.swift, Timeline.swift, Validation.swift
パッケージに複数の製品がある場合、依存関係として依存関係パッケージを指定し、既にターゲット依存関係にあるパッケージモジュールへの依存関係を示します。 たとえば、これはSourceKittenがSynopsisライブラリでどのように接続されるかです。
import PackageDescription let package = Package( name: "Synopsis", products: [ Product.library( name: "Synopsis", targets: ["Synopsis"] ), ], dependencies: [ Package.Dependency.package( // SourceKitten url: "https://github.com/jpsim/SourceKitten", from: "0.18.0" ), ], targets: [ Target.target( name: "Synopsis", // SourceKittenFramework dependencies: ["SourceKittenFramework"] ), Target.testTarget( name: "SynopsisTests", dependencies: ["Synopsis"] ), ] )
これは、 SourceKittenパッケージの説明です。 パッケージには2つの製品が記載されています
.executable(name: "sourcekitten", targets: ["sourcekitten"]), .library(name: "SourceKittenFramework", targets: ["SourceKittenFramework"])
概要では、SourceKittenFramework製品ライブラリを使用します。
プロジェクトファイルを作成する
次のコマンドを実行して、便利なプロジェクトファイルを作成できます。
swift package generate-xcodeproj
その結果、プロジェクトのルートフォルダーにIPInfoExample.xcodeprojファイルを取得します。
それを開いて、Sourcesフォルダー内のすべてのソース(Modelサブフォルダーを持つソースを含む)、およびDependenciesフォルダー内の依存関係ソースを確認します。
このステップは製品開発中のオプションであり、SwiftPM操作メカニズムに影響を与えないことに注意することが重要です。 すべてのソースファイルはディスクと同じ方法で配置されることに注意してください。
接続された依存関係の確認
依存関係が正しく接続されているかどうかを確認してください。 この例では、現在のIPアドレスに関するデータを取得するために、ipinfoサービスに非同期要求を行います。 応答JSONをモデルオブジェクト(IPInfo構造)にデコードします。 簡単にするために、JSONマッピングエラーまたはサーバーエラーは処理しません。
// , cocoapods carthage import Alamofire import Foundation public typealias IPInfoCompletion = (IPInfo?) -> Void public struct Application { public static func obtainIPInfo(completion: @escaping IPInfoCompletion) { Alamofire .request("https://ipinfo.io/json") .responseData { result in var info: IPInfo? if let data = result.data { // JSON info = try? JSONDecoder().decode(IPInfo.self, from: data) } completion(info) } } }
次に、Xcodeでbuildコマンドを使用し、ターミナルでswift buildコマンドを実行できます。
実行可能ファイルを含むプロジェクト
上記は、ライブラリプロジェクトを初期化する例です。 SwiftPMを使用すると、実行可能ファイルプロジェクトを操作できます。 これを行うには、初期化時に次のコマンドを使用します
swift package init —type executable.
Sources / IPInfoExampleディレクトリにmain.swiftファイルを作成して、現在のプロジェクトをこのフォームに取り込むこともできます。 実行可能ファイルを実行すると、main.swiftがエントリポイントになります。
その中に1行書きましょう
print("Hello, world!”)
そして、swift runコマンドを実行すると、大切な文がコンソールに表示されます。
パッケージ記述構文
一般的なパッケージの説明は次のとおりです。
Package( name: String, pkgConfig: String? = nil, providers: [SystemPackageProvider]? = nil, products: [Product] = [], dependencies: [Dependency] = [], targets: [Target] = [], swiftLanguageVersions: [Int]? = nil )
- name-パッケージの名前。 パッケージに必要な唯一の引数。
- pkgConfig-システムにインストールされているモジュールパッケージ(システムモジュールパッケージ)に使用され、 pkg-configファイルの名前を定義します 。
- プロバイダー -システムモジュールパッケージに使用され、サードパーティの依存関係マネージャー(brew、aptなど)を介して不足している依存関係をインストールするためのヒントを説明します。
import PackageDescription let package = Package( name: "CGtk3", pkgConfig: "gtk+-3.0", providers: [ .brew(["gtk+3"]), .apt(["gtk3"]) ] )
- products-プロジェクトターゲットのアセンブリの結果の説明-実行可能ファイルまたはライブラリ(静的または動的)。
let package = Package( name: "Paper", products: [ .executable(name: "tool", targets: ["tool"]), .library(name: "Paper", targets: ["Paper"]), .library(name: "PaperStatic", type: .static, targets: ["Paper"]), .library(name: "PaperDynamic", type: .dynamic, targets: ["Paper"]) ], targets: [ .target(name: "tool") .target(name: "Paper") ] )
上記のパッケージには、ツールターゲットからの実行可能ファイル、Paperライブラリ(SwiftPMが自動的にタイプを選択する)、静的PaperStaticライブラリ、1つのPaperターゲットからの動的PaperDynamicの4つの製品があります。
- 依存関係-依存関係の説明。 パス(ローカルまたはリモート)とバージョンを指定する必要があります。
SwiftPMのバージョン管理は、gitタグを通じて行われます。 バージョニング自体は非常に柔軟に構成できます。言語のバージョン、git-branches、最小メジャー、マイナーバージョンのパッケージ、またはコミットのハッシュを修正します。 @ swift-3という形式のオプションのサフィックスがタグに追加されるため、古いバージョンをサポートできます。 たとえば、1.0 @ swift-3、2.0、2.1という形式のバージョンでは、バージョン1.0のみがSwiftPMバージョン3、最新バージョン4の2.0および2.1で使用できます。
package@swift-3.swiftという名前のサフィックスを指定することにより、マニフェストファイルのSwiftPMバージョンのサポートを指定することもできます。 バージョン表示は、ブランチまたはコミットハッシュに置き換えることができます。
// 1.0.0 ..< 2.0.0 .package(url: "/SwiftyJSON", from: "1.0.0"), // 1.2.0 ..< 2.0.0 .package(url: "/SwiftyJSON", from: "1.2.0"), // 1.5.8 ..< 2.0.0 .package(url: "/SwiftyJSON", from: "1.5.8"), // 1.5.8 ..< 2.0.0 .package(url: "/SwiftyJSON", .upToNextMajor(from: "1.5.8")), // 1.5.8 ..< 1.6.0 .package(url: "/SwiftyJSON", .upToNextMinor(from: "1.5.8")), // 1.5.8 .package(url: "/SwiftyJSON", .exact("1.5.8")), // . .package(url: "/SwiftyJSON", "1.2.3"..<"1.2.6"), // . .package(url: "/SwiftyJSON", .branch("develop")), .package(url: "/SwiftyJSON", .revision("e74b07278b926c9ec6f9643455ea00d1ce04a021"))
- ターゲット-ターゲットの説明。 この例では、2つのターゲットを宣言します。2番目のターゲット-最初のターゲットのテストでは、依存関係でテスト済みのターゲットを示します。
let package = Package( name: "FooBar", targets: [ .target(name: "Foo", dependencies: []), .testTarget(name: "Bar", dependencies: ["Foo"]) ] )
- swiftLanguageVersions-サポートされている言語のバージョンの説明。 バージョン[3]がインストールされている場合、swift 3および4コンパイラはバージョン3を選択します;バージョン[3、4]、swift 3コンパイラは3番目のバージョンを選択し、swift 4コンパイラは4番目を選択します。
チームインデックス
swift package init // swift package init --type executable // swift package --version // SwiftPM swift package update // swift package show-dependencies // swift package describe //