ccacheを使ってFlutterのiOSビルドを高速化してみた
はじめに
FirebaseFirestoreを導入したFlutterアプリのiosビルドは非常に時間がかかるため、firestore-ios-sdk-frameworksを使ってビルドの高速化を行っているプロジェクトが多いですよね🙂
先日リリースされたfirebase_core: 2.22.0
にてfirebase_ios_sdk: 10.17.0
が要求されるようになったんですが、どうやらそのver以降iOSビルドできなくなる不具合があるっぽく、対応にまだしばらく時間がかかりそうな状況😓(2023/12/5時点)
追記:
2024/1/31にリリースされたfirestore-ios-sdk-frameworks: v10.20.0
にて、上記の問題は解決したようです!やったね!
https://github.com/invertase/firestore-ios-sdk-frameworks/issues/79#issuecomment-1919142414Podの代わりにccacheを使う理由が薄くなったわけですが、この記事は備忘録として残しておきます!
現時点で取れる対応は大きく3つ
-
firestore-ios-sdk
のversionをを10.16.0のままにする(firebase_core
のバージョンを2.21.0固定にする) -
firestore-ios-sdk
を使わない(高速化を諦める) -
ccache
を使う
高速化のためだけにfirebaseのアップデートを我慢し続けるのは嫌だけど、高速化を諦めるのも辛いし・・・。
なんかccache
とか聞いたことないものが提案されてたのでちょっくら試してみよう。という経緯です。
※「周辺知識浅い人間がとりあえずやってみたメモ」みたいな感じなので、間違ったことを書いてる可能性もあります!お気づきの点あればご指摘いただけると幸いです🙇♂️🙇♂
ccacheとは?
公式ドキュメントはこちら
ccache.dev
Ccache is a compiler cache. It speeds up recompilation by caching the result of previous compilations and detecting when the same compilation is being done again.
Ccache has been carefully written to always produce exactly the same compiler output that you would get without the cache. The only way you should be able to tell that you are using ccache is the speed. Currently known exceptions to this goal are listed under Caveats. If you discover an undocumented case where ccache changes the output of your compiler, please let us know.
要約すると、
-
ccache
は、前回のコンパイル結果をキャッシュすることで、2回目以降の再コンパイルを高速化する - キャッシュを使用しない場合と全く同じコンパイラ出力を常に生成するように作られている
ちなみにfirestore-ios-sdk-frameworks
の方は、「事前にプリコンパイルされたデータを取得してPod化する(間違ってたらごめんなさい)」みたいな感じだと思うので、同じ高速化でも実現方法がちょっと違うって感じかな〜👀
導入方法
公式ドキュメントやらGitHubやら記事やらを見ながら設定していきます
※この記事では、ローカル環境の設定のみを記載しています。
CI(GitHub Actions)ではccache-actionを使うことができるようですが、現時点では未検証です(後日検証予定)
①ccacheをインストールする
brew install ccache
ccache
コマンドが通るかテスト。
ukkey@ukimac-book ~ % ccache --version
ccache version 4.8.3
Features: file-storage http-storage redis+unix-storage redis-storage
Copyright (C) 2002-2007 Andrew Tridgell
Copyright (C) 2009-2023 Joel Rosdahl and other contributors
See <https://ccache.dev/credits.html> for a complete list of contributors.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
よさそう!
②シンボリックリンクを作成
ccache
をコンパイラとして動作させるために、/usr/local/bin/
ディレクトリ内にいくつかのシンボリックリンクを作成していきます。
sudo ln -s $(which ccache) /usr/local/bin/gcc
sudo ln -s $(which ccache) /usr/local/bin/g++
sudo ln -s $(which ccache) /usr/local/bin/cc
sudo ln -s $(which ccache) /usr/local/bin/c++
sudo ln -s $(which ccache) /usr/local/bin/clang
sudo ln -s $(which ccache) /usr/local/bin/clang++
ちゃんと作成されてるか確認・・・👀
ukkey@ukimac-book ~ % ls -l /usr/local/bin/
total 0
lrwxr-xr-x 1 root wheel 25 12 1 21:54 c++ -> /opt/homebrew/bin//ccache
lrwxr-xr-x 1 root wheel 25 12 1 21:54 cc -> /opt/homebrew/bin//ccache
lrwxr-xr-x 1 root wheel 25 12 1 21:54 clang -> /opt/homebrew/bin//ccache
lrwxr-xr-x 1 root wheel 25 12 1 21:54 clang++ -> /opt/homebrew/bin//ccache
lrwxr-xr-x 1 root wheel 25 12 1 21:54 g++ -> /opt/homebrew/bin//ccache
lrwxr-xr-x 1 root wheel 25 12 1 21:54 gcc -> /opt/homebrew/bin//ccache
PATHが通っているか確認
シンボリックリンクを作成した/usr/local/bin
ディレクトリにPATHが通っているかを確認。
ukkey@ukimac-book ~ % which gcc
/usr/local/bin/gcc
/usr/local/bin/gcc
と表示されればOK。
もし/usr/bin/gcc
と表示されてしまうときは、/usr/local/bin
にPATHが通っていない可能性があるので、以下のコマンドを実行したあと、再度確認。
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
③iOSビルドのccacheを構成する
どうやらFlutterの場合、デフォルトだとうまくキャッシュしてくれないっぽいので、以下の構成を.zshrc
に追記。
export CCACHE_SLOPPINESS=clang_index_store,file_stat_matches,include_file_ctime,include_file_mtime,ivfsoverlay,pch_defines,modules,system_headers,time_macros
export CCACHE_FILECLONE=true
export CCACHE_DEPEND=true
export CCACHE_INODECACHE=true
※.zshrc
を更新したらsource ~/.zshrc
を忘れずに!
③Podfileを編集する
Flutterプロジェクトのios/Podfile
に以下の内容を追記します
これは、Xcodeがデフォルトでツール(clang,clang++)への完全指定パスを使用しているため、先程作成したシンボリックリンクを正しく使ってくれるように設定してるみたい。
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
# --- これを追加 ---
config.build_settings["CC"] = "clang"
config.build_settings["LD"] = "clang"
config.build_settings["CXX"] = "clang++"
config.build_settings["LDPLUSPLUS"] = "clang++"
# ----------------
end
end
end
ビルド時間の比較
iOSエミュレータでのデバッグビルド速度を計測して、比較してみました。
※ストップウォッチアプリでのポチポチ計測なので厳密ではないです🙏
- | 1回目 | 2回目 | 3回目 |
---|---|---|---|
高速化なし | 7m14s78 | 7m11s63 | 6m20s43 |
ios_sdk | 1m24s79 | 1m18s93 | 1m21s25 |
ccache | 5m43s00 | 1m06s60 | 2m09s30 |
1回目はどうしても初回キャッシュを作成するために1からコンパイルされるので、それなりに時間はかかってますね〜。でも2回目以降のビルドは早くなってる😯😯
所感
まだ本格的に使ってないのでなんとも言えないけど、今の時点だとfirestore-ios-sdk-frameworks
が使えるのであればそっちのほうが方が良いかなという印象😓
- 設定箇所が多い
- 初回ビルドが遅い
やっぱりこの辺のデメリットが大きく感じました🥲
あと、シンボリックリンクで挙動を上書きしているので他の動作にも影響することも不安要素としてはあるかな〜。
ただ、今回Pod側で起こってる問題のような、内部の依存関係が原因でプリコンパイルしたデータに不具合がある、なんてことには影響されないのでそこはメリットになる・・のかな?(この辺理解浅い🫣)
まだissueの方でも議論続いてるので様子見しつつ、CI設定含め新情報あれば引き続き試してみようと思います〜〜
注意事項
ccacheの設定は全てのコンパイルに影響するため、環境によってはこれが原因で他のソフトウェアのインストールやコンパイルが失敗する可能性もみたい。
そんなときはシンボリックリンクを削除しておきましょう
sudo unlink /usr/local/bin/gcc
sudo unlink /usr/local/bin/g++
sudo unlink /usr/local/bin/cc
sudo unlink /usr/local/bin/c++
sudo unlink /usr/local/bin/clang
sudo unlink /usr/local/bin/clang++
Discussion
firestore-ios-sdk-frameworksのv10.20.0にて、ビルドできない問題は解決したようなので追記しました!