CIでSPMのキャッシュを行うのは難しい
Swift Package Managerの内部構造にはあまり詳しくなかったのですが、CI上でFirebaseのような大きなパッケージを毎回ビルドするのが非効率に感じたため、キャッシュに挑戦してみました。 しかし結論としては、うまくいきませんでした。
なぜうまくいかないのか
Bitriseには Save SPM Cache / Restore SPM Cache というステップがあります。これを見つけて「お、これでいけるのでは?」と思ってしまったのが落とし穴でした。
このステップは ~/Library/Developer/Xcode/DerivedData/**/SourcePackages
を保存・復元対象にしています。
SourcePackages
の中身を確認すると、artifacts
・checkouts
・repositories
の3つのディレクトリがあります。
ざっくり言うと、Swift Package Managerは依存パッケージのソースコードを~/Library/Developer/Xcode/DerivedData/**/SourcePackages
に丸ごとチェックアウトして毎回ビルドする仕組みです(XCFrameworkは例外)
ローカルでのビルドが速く感じるのは、SPMがバイナリキャッシュを持っているからではなく、Xcodeの intermediates.noindex
を使ったインクリメンタルビルドのおかげです。
つまり、そもそもSPMはCIでキャッシュできる仕様が現在ない(CarthageのバイナリだとかRomeのような仕組みがない)ので、CIでSPMのキャッシュを行うのは難しいということです。この仕様を理解していなかったため、Bitriseのステップに過剰な期待をしてしまいました。
最初に挙げた保存・復元ステップはリモートからのフェッチ速度を早めるためのもので、ビルド速度に貢献するものではありません。
それでもキャッシュしたい場合
どうしてもCIでSPMをキャッシュしたい場合、下記の記事のように DerivedData
をまるごとキャッシュする方法もあります。
ただし、DerivedData
は中間生成物のため、キャッシュすることでCI環境がどんどん汚れていくリスクがあります。
CIのメリットは「クリーンな環境で非同期にテストやビルドを実行できること」なので、それを犠牲にして速度を取るのは大きなトレードオフだと思います。
それでもビルド時間短縮が最優先であれば、上記のような方針を検討するのが現実的でしょう。
Discussion