モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

Cocoapods から Carthage にして,CI でのビルドを高速化した

 Carthage 導入した理由から,色々変更した点について

1. Carthage 導入した理由

 Xcode 10 からは new build system がデフォルトになっています。

 それにより static framework 作るのに,ld.py 自体は不要になっていましたね。

github.com

 今のプロジェクトは armv7s (iPhone 5, 5c) 向けにビルドを吐き出すため,そして O3 にするために微妙にコンパイルオプションもいじってビルドしています。

#!/bin/sh -e

xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
trap 'rm -f "$xcconfig"' INT TERM HUP EXIT

echo "ARCHS=x86_64 armv7s arm64" >> $xcconfig
echo "IPHONEOS_DEPLOYMENT_TARGET=10.0" >> $xcconfig
echo "GCC_OPTIMIZATION_LEVEL=3" >> $xcconfig

echo "MACH_O_TYPE=staticlib" >> $xcconfig
echo "DEBUG_INFORMATION_FORMAT=dwarf" >> $xcconfig

export XCODE_XCCONFIG_FILE="$xcconfig"

carthage build "$@"

 UI でしか使わない,UI ライブラリー系 PinLayout, Hero, Eureka と一部の層でしか使っていない CryptoSwift を static にしました。

 なお static library を採用する理由はここらあたりを見てみるといいです。iPhone 5 とかだと顕著に差が出ます。

medium.com

2. CI で 50% の確率で失敗する 45 分の壁。

 なんか処理が早く終わったらうまくいってそうでない場合失敗するってわかりました。

 armv7s と arm64 両方のコードを O3, Link-Time Optimization してるから仕方ないんですけども……

 で,それが時間がかかりすぎるので,事前にビルドしてしまえばいいじゃないか! っていう理由で dynamic library として当面の間組み込むのも,Carthage でビルドしてしまいました。

 まず,事前調査で

  • RealmCocoa
  • RealmSwift
  • RxSwift
  • RxSwiftExt
  • RxGesture
  • RxRealmDataSources (公式が Carthage 非対応なため,PierrePerrin氏の develop ブランチのものを採用した)
  • Starscream

という感じで,赤字のものは static library 不可能でした。

 とりあえずこれらを自前でビルドします。O3 かつ armv7s 対応のものとして。static library の Shell Script から MACH_O_TYPEDEBUG_INFORMATION_FORMAT のオプション取り除くだけですね。

3. 結果

 bitrise でのビルド時間が 19 分になりました!

 もう少し早くしたいですね。ボトルネック解消すれば 12 分前後に収められるかな?

CocoaPods

  • Fabric
  • Crashlytics
  • Starscream (Carthage でそもそもビルドが通らない)
  • URLEncodedForm

Carthage (Static)

  • CryptoSwift
  • Eureka
  • Hero
  • PinLayout
  • RxGesture
  • RxSwiftExt
  • RxRealmDataSources

Carthage (Dynamic)

  • Realm (RealmCocoa, RealmSwift)
  • RxSwift (RxAtomic, RxCocoa, RxSwift)

コマンド例

$ pod install
$ carthage bootstrap --no-build --no-use-binaries
$ ./carthage-build-static.sh CryptoSwift Eureka Hero PinLayout RxSwiftExt RxGesture RxRealmDataSources --platform ios
$ ./carthage-build-dynamic.sh realm-cocoa RxSwift --platform ios --no-use-binaries

※ Realm や Rx はあらかじめバイナリーが用意されているようなので --no-use-binaries した。結果的にファイルサイズ小さくなった気がする。 ※ Rx 本体だけは dynamic と static が生成されますが,このオーバーヘッドは仕方ないです。めんどくさいので改善する気もないですがw

まとめ

 事前ビルドしておけば,成果物のみのビルドとなり,CI での遅延も大幅に減らすことができます。

 zip ファイルであらかじめ framework ファイルを準備しておく必要はありますが,基本的に少しの手間で,開発自体かなりスピードアップできるんじゃないんでしょうか?

 また,iPhone XS, XS Max から arm64e という命令セットアーキテクチャーに対応していますが,これらへの対応も問題なくできますね。

 具体的に知りたい人は ARMv8.3 とか見てみるといいかも。さわりだけでいい人は stackoverflow で

stackoverflow.com