書いて覚えるSwift入門

第45回 swift package manager

この記事を読むのに必要な時間:およそ 4 分

swift package init

モジュールと言えばswift package manager(略称SPM)で,本連載でも第38回をはじめあちこちで紹介しているのですが,今回は実践編ということで実際に筆者がGitHubで公開しているモジュールを通して解説を進めていくことにします。

パッケージをサポートしたたいていの言語では,最初のパッケージのひな形を一発作成してくれるコマンドが存在します。Swiftのそれはswift package initMyModuleというパッケージを作成するとしたら,

$ mkdir MyModule
$ cd MyModule
$ swift package init

とコマンドを3つ打つと,MyModuleディレクトリ以下に,

Creating library package: MyModule
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/MyModule/MyModule.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/MyModuleTests/
Creating Tests/MyModuleTests/MyModuleTests.swift
Creating Tests/MyModuleTests/XCTestManifests.swift

と最低限必要なファイルが生成されるわけですが,トップディレクトリの作成自体は行わないのがちょっと不思議ではあります。筆者ならswift package init MyModuleとディレクトリ名が指定されている場合は1コマンドで済むようにして,指定がなければカレントディレクトリをトップにするという仕様にしたのですが。

それはさておき,この状態ですでにパッケージとしてはビルドしてテストに成功する状態になっています図1)⁠

図1 モジュールのテストを実施

$ swift test
% swift test
Compile Swift Module 'MyModule' (1 sources)
Compile Swift Module 'MyModuleTests' (2 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/MyModulePackageTests.xctest/Contents/MacOS/MyModulePackageTests
Test Suite 'All tests' started at 2018-12-17 11:01:49.690
Test Suite 'MyModulePackageTests.xctest' started at 2018-12-17 11:01:49.690
Test Suite 'MyModuleTests' started at 2018-12-17 11:01:49.690
Test Case '-[MyModuleTests.MyModuleTests testExample]' started.
Test Case '-[MyModuleTests.MyModuleTests testExample]' passed (0.231 seconds).
Test Suite 'MyModuleTests' passed at 2018-12-17 11:01:49.921.
   Executed 1 test, with 0 failures (0 unexpected) in 0.231 (0.231) seconds
Test Suite 'MyModulePackageTests.xctest' passed at 2018-12-17 11:01:49.921.
   Executed 1 test, with 0 failures (0 unexpected) in 0.231 (0.231) seconds
Test Suite 'All tests' passed at 2018-12-17 11:01:49.921.
   Executed 1 test, with 0 failures (0 unexpected) in 0.231 (0.231) seconds

あとはここから.swiftなファイルを編集したり,Sources/MyExampleディレクトリ以下にSwiftソースファイルを追加したり,Tests/MyModuleTests以下にテストコードを追加したりしていくわけですが,最初にやっておくべきなのが.gitignoreの差し替え。SPMが生成してくれるものは,

.DS_Store
/.build
/Packages
/*.xcodeproj

しかないのですが,実際にXcodeも併用する場合はプロジェクト自体はリポジトリに含めつつプロジェクト内の不要なファイルだけを外すようにしたいですし,SPMだけでなくCocoaPodsCarthageなどのSPMの「先輩」たちとも共存させたい。幸いGitHub自身がメンテナンスしているgithub/gitignoreにSwiftが含まれているので,ここにあるSwift.gitignoreと差し替えるのがよいでしょう。あるいははじめからGitHubでの公開を前提にするのであれば,あらかじめGitHubで新規リポジトリ作成でSwiftを指定してから,それをgit cloneしたあと,cd MyModule && swift package initとしてもよいでしょう。

そこまで終わったらトップディレクトリからgit add .してgit commit -aしておきましょう。

モジュールはなるべくモジュラーに

次に行うべきは,Package.swiftの編集。ほかのパッケージを使わない場合はそのままでもたいていOKですが,そうでない場合はここのdependencies: []の中に.packageを追加しておきます。拙Gitリポジトリでは,swift-floatingpointmathというモジュールを利用するので,

.package(
        url: "https://github.com/dankogai/swift-floatingpointmath.git", from: "0.0.8"
      )

が追加されています。これはexpsinといった,Foundationで追加される数学関数をFloatingPointMathというプロトコルに準拠する型Tの型関数,つまりT.expT.sinとして明示的に指定して使えるようにする,つまり名前空間をプロトコルとして提供するためだけのモジュールですが,これを別モジュールとして分離したことで,swift-bignumなどとのコードの重複を防いでいます。

また名前空間をプロトコルとして提供することで,Double.sqrtComplex.sqrtと別物として利用できてコードの見通しが向上します。

% scripts/run-repl.sh
Welcome to Apple Swift version 4.2.1
(swiftlang-1000.11.42 clang-1000.11.45.1). Type
:help for assistance.
  1> import Complex
  2> Double.sqrt(-1)
$R0: Double = NaN
  3> Complex.sqrt(-1)
$R1: Complex.Complex<Double> = {
  real = 0
  imag = 1
}

余談かつ私見ですが,Foundationはあまりに多くの関数をトップレベルにimportしてくれるおかげで小さなプログラムを手軽に書ける反面,見通しはよろしくない。logは対数なのかログなのか……JavaScriptでもMath.logconsole.logと一目瞭然なのに。もっともFoundationはObjective-Cのレガシィを背負ったモジュールである以上,よりモジュラーなFoundation相当は別途用意すべきなのかもしれませんが。

著者プロフィール

小飼弾(こがいだん)

1969年生まれ,東京都出身。元ライブドア取締役の肩書きよりも,最近はPokemon GOのガチトレーナーのほうが有名になりつつある……かもしれない永遠のエンジニアオヤジ。

活躍の場はIT業界だけでなく,サブカルからアカデミックまで多方面にわたり,ネットからの情報発信は気の向くまま毎日毎秒! https://twitter.com/dankogai,ニコニコチャンネルは,http://ch.nicovideo.jp/dankogai,blogはhttp://blog.livedoor.jp/dankogai/

当社刊行書籍は『小飼弾のアルファギークに逢ってきた』『小飼弾のコードなエッセイ』など。他にも著書多数。