はじめに
iOSアプリ開発を行うとき、ライブラリの導入にCarthageを使うことがあると思います。
Carthageは、CocoaPodsに比べて事前にビルドを行うためコンパイル時間が短い、ワークスペースが弄られないといったメリットがあります。
前者の利用で使っているところも多いのではないでしょうか
Carthageのビルド時間は長い?
Carthageはその特性上、一度全てのライブラリをビルドしてフレームワークを作成する必要があるため、環境構築に時間がかかります。
またSwiftのABI安定化はまだなので、XcodeをアップデートしてSwiftのバージョンが変わると再度ビルドする必要があり、地獄をみます。
ライブラリのアップデートが必要になった時も同じく地獄をみます。
このビルド時間問題で影響を受けるのは、数人〜数十人のエンジニアを抱えているチームだと思っています。
個人開発など、自分だけが再ビルドすれば良いのであれば特に問題にはならないと思いますが、他の方々もビルドする必要があると、その分進捗が死にます。
実際にCarthageのビルドがボトルネックとなったことがあり、割と笑えません。
よくある解決方法として、生成されたフレームワークをGitに含めるという方法もありますが、
使っているライブラリの量によってはウンGBになることもあり、リポジトリが肥大化するという問題が発生します。
またチーム内でXcodeのバージョンを揃えていない場合、前述したSwiftバージョン問題が発生する可能性があります。
…とはいえ、何らかの方法でフレームワークをキャッシュしてうまいことできないかなぁと調べていたところ、Romeというツールがいい感じだったのでご紹介いたします。
Romeとは
Carthageの生成物をオブジェクトストレージに共有できるツールです。
現在Amazon S3, S3互換のあるMinio, Cephに対応しています。
GitHub - blender/Rome: A cache tool for Carthage
使い方
READMEに記載されている通りなのですが、HomebrewかCocoaPods経由で導入ができます。
今回はHomebrewを使います。
brew install blender/homebrew-tap/rome
AWS S3の認証情報を設定する
キャッシュ先としてS3を利用しますので、
バケットへのアクセス権限を持ったユーザーの作成とアクセスキーID, シークレットキーを入手します。
export AWS_ACCESS_KEY_ID=<ACCESS_KEY_ID>
export AWS_SECRET_ACCESS_KEY=<SECRET_ACCESS_KEY>
export AWS_REGION=<REGION>
Romeファイルの作成
次に、プロジェクトのあるディレクトリでRomefile
を作成します。中身はYAMLで書いていきます。
Cache(必須)
s3Bucket
に作成したバケット名を指定します。ローカルにキャッシュすることも可能です。
cache:
s3Bucket: ios-xxapp-carthage-cache
# local: ~/Library/Caches/Rome
Repository Map
RomeはCartfile.resolved
を参照するため、リポジトリ名とフレームワーク名が異なる場合**うまくキャッシュができません。**依存ライブラリに関しても同様です。
Repository Mapでリポジトリ名とフレームワーク名を明記する必要があります。
例えばFacebook-SDK-Swiftですと、フレームワーク名は「FacebookCore」, 「FacebookLogin」, 「FacebookShare」となるので、これらを指定する必要があります。
repositoryMap:
- Facebook-SDK-Swift:
- name: FacebookCore
- name: FacebookLogin
- name: FacebookShare
- facebook-objc-sdk:
- name: FBSDKCoreKit
- name: FBSDKLoginKit
- name: FBSDKShareKit
- xxxx-ios:
- name: XXXX
Ignore Map
キャッシュする必要のない、したくないライブラリを指定できます。
ignoreMap:
- xxxxx:
- name: xxxxx
共有されているライブラリを扱う
S3からダウンロードする
rome download --platform iOS
S3へアップロードする
rome upload --platform iOS
S3に共有されていないライブラリを表示
rome list --missing --platform iOS
--cache-prefixについて
そのまま使っていると、s3Bucket
で指定した階層にダウンロード/アップロードされてしまうため、チーム内のSwiftのバージョンが統一されていない場合Swiftバージョン問題が発生します。
これを回避するために、Romeではオプションとして--cache-prefix
が用意されており、Swiftのバージョンごとにprefixを分けることができます。
rome download --platform iOS --cache-prefix Swift4_2
READMEには、xcrun swift --version
で取得したバージョンを使う方法が記載されていました。
私はこちらを使っています。
--cache-prefix `xcrun swift --version | head -1 | sed 's/.((.)).*/\1/' | tr -d "()" | tr " " "-"`
Gitから引っ張ってきた時とかにいい感じにライブラリを揃える
S3から引っ張ってきた後、未ビルドでアップロードされていないものだけをビルドしてアップロードするようにします。
ライブラリを追加した時や、gitからcheckout/pullした時に呼び出すといい感じにやってくれるはず。
cache_prefix=`xcrun swift --version | head -1 | sed 's/.*\((.*)\).*/\1/' | tr -d "()" | tr " " "-"`
platform='iOS'
rome download --platform $platform --cache-prefix $cache_prefix
rome list --missing --platform $platform --cache-prefix $cache_prefix | awk '{print $1}' | xargs sh -c "carthage update --platform $platform --cache-builds; rome upload --platform $platform --cache-prefix $cache_prefix"
感想
Romeのおかげでビルド地獄から抜け出せそうな気がしてます。ありがとうRome