swift package init
モジュールと言えばswift package manager(略称SPM)で、本連載でも第38回をはじめあちこちで紹介しているのですが、今回は実践編ということで実際に筆者がGitHubで公開しているモジュールを通して解説を進めていくことにします。
パッケージをサポートしたたいていの言語では、最初のパッケージのひな形を一発作成してくれるコマンドが存在します。Swiftのそれはswift package init
。MyModule
というパッケージを作成するとしたら、
とコマンドを3つ打つと、MyModule
ディレクトリ以下に、
と最低限必要なファイルが生成されるわけですが、トップディレクトリの作成自体は行わないのがちょっと不思議ではあります。筆者ならswift package init MyModule
とディレクトリ名が指定されている場合は1コマンドで済むようにして、指定がなければカレントディレクトリをトップにするという仕様にしたのですが。
それはさておき、この状態ですでにパッケージとしてはビルドしてテストに成功する状態になっています(図1)。
あとはここから.swift
なファイルを編集したり、Sources/MyExample
ディレクトリ以下にSwiftソースファイルを追加したり、Tests/MyModuleTests
以下にテストコードを追加したりしていくわけですが、最初にやっておくべきなのが.gitignore
の差し替え。SPMが生成してくれるものは、
しかないのですが、実際にXcodeも併用する場合はプロジェクト自体はリポジトリに含めつつプロジェクト内の不要なファイルだけを外すようにしたいですし、SPMだけでなくCocoaPodsやCarthageなどの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というモジュールを利用するので、
が追加されています。これはexp
やsin
といった、Foundation
で追加される数学関数をFloatingPointMath
というプロトコルに準拠する型T
の型関数、つまりT.exp
やT.sin
として明示的に指定して使えるようにする、つまり名前空間をプロトコルとして提供するためだけのモジュールですが、これを別モジュールとして分離したことで、swift-bignumなどとのコードの重複を防いでいます。
また名前空間をプロトコルとして提供することで、Double.sqrt
がComplex.sqrt
と別物として利用できてコードの見通しが向上します。
余談かつ私見ですが、Foundation
はあまりに多くの関数をトップレベルにimport
してくれるおかげで小さなプログラムを手軽に書ける反面、見通しはよろしくない。log
は対数なのかログなのか……JavaScriptでもMath.log
とconsole.log
と一目瞭然なのに。もっともFoundation
はObjective-Cのレガシィを背負ったモジュールである以上、よりモジュラーなFoundation
相当は別途用意すべきなのかもしれませんが。
リリース版をビルド
SPMの各コマンドは、デフォルトではテスト版をビルドします。リリース版をビルドするには、-crelease
を付けます。さらに-Xswiftc -enabletesting
を付けると、リリース版でテストもできます。swift-bignumの開発では、これが実際に必要になりました。任意精度有理数型BigRat
と任意精度浮動小数点数型BigFloat
を提供するモジュールですが、エッジケースが多いのでテストケースが1万5,000を超え、その結果普通にswift testすると筆者の環境で200秒以上かかります(図2)。
Travis CIではもっとかかるので、-c release-Xswiftc -enable-testing
を指定するようにしたところ10秒で完了するようになりました(図3)。
未サポートのiOSでもSPMしたい
SPMはCPANやRuby Gemsといったほかの言語のパッケージマネージャーにおける開発に慣れた人には非常にとっつきやすいツールですが、Swiftという言語の性格上、1つ重大な問題があります。現時点ではiOSにまったく対応していないのです。前述のswift-complexはもともとほかのモジュールに依存しなかったのですが、swift-floatingpointmathを分離した途端に「オレのiOSどうしてくれるんだ!」という文句が押し寄せました。筆者がとった苦肉の策は、依存ファイルを全部まとめたファイルを自動生成するというもので、scripts/makemono.pl
というPerlスクリプトでそれを実現しています(リスト1)。
swift-complex程度の小さなモジュールであればまだいいのですが、これがswift-bignumのような大きくかつ最適化を施さないと実用的な速度が出ないものだと、この手法には無理があります。SPM自体がiOSをサポートしてくれることを首を長くして待っています。
モバイルコンピューティングにモバイルプログラミングを
iOSにネイティブ開発環境がない辛さ。今まで「あればうれしい」だったのが「ないと辛い」になったと一段と強く実感するようになったのが、位置ゲーの隆盛。Ingressで芽吹き、Pokémon GOで花開いた位置ゲーは街角の様相を一変させました。何もなさそうなところに人だかりができても「ああポケモンのジムがあるよね」とお巡りさんも納得する現在、フィールドテストでフィールドデバッグができないもどかしさはどれほどのものか。
その位置ゲーも、テクテクテクテクでNiantic社の寡占状態がいよいよ崩れようとしています(図4、図5)。ポケストップやジムといった点から点への移動が街区という面を塗りつぶすという同ゲームのメインテーマは画期的で、移動軌跡を後で塗る「予約塗り」と、塗り終わった街区に隣接していればTTPというコストを支払うことでそこにいなくても塗れる「となり塗り」という機能を用意したのは実に見事です。後発だけあってPokémon GOの痒いところがかなり解消されているのですが、それでも実際にフィールドテストすればすぐわかる問題が残っていたのが実に印象的でした。
「街区が広過ぎて、お邪魔モンスターが見つけられない」、「街区が小さ過ぎて、99%から進まない」。これは実際に行けばたちどころにわかるけど室内ではなかなか実感できないことの典型で、現状ではその場でできるのは報告だけで、ちょっとした手直しも難しい。すべてのロジックをサーバ側に持たせてSSHでログインして修正を加えるのは理論的にはできますが現実離れも甚だしい。アプリ全体のリビルドはさておき、その場でパラメータを調整するぐらいのことはできてほしい。iOSアプリをクロスコンパイルしていたのはMacよりも非力だからという技術的な課題はとうの昔に解決しています。位置ゲーに限らず「現場で直したい」課題は増えることはあっても減ることはありません。船上で直せるものは直せるようにしませんか、クック船長?
次回予告
話を戻して、swift-floatingmathではDouble
やFloat
を直接extendするのではなく、Float ingPointMath
というプロトコルを用意したうえでそれらの型を準拠させるようにしています。なぜそうしたのか?――次回はモジュールとプロトコルの関係について解説します。
- 第1特集
MySQL アプリ開発者の必修5科目
不意なトラブルに困らないためのRDB基礎知識
- 第2特集
「知りたい」「使いたい」「発信したい」をかなえる
OSSソースコードリーディングのススメ
- 特別企画
企業のシステムを支えるOSとエコシステムの全貌
[特別企画]Red Hat Enterprise Linux 9最新ガイド
- 短期連載
今さら聞けないSSH
[前編]リモートログインとコマンドの実行
- 短期連載
MySQLで学ぶ文字コード
[最終回]文字コードのハマりどころTips集
- 短期連載
新生「Ansible」徹底解説
[4]Playbookの実行環境(基礎編)