はじめに
iOSアプリ開発のためのパッケージマネージャー別のリンク指定を整理しておきます。
勘違いしやすいポイントとしては、Carthageを使ってもデフォルトでdynamicリンクなのでstaticリンクするよりもアプリ起動は遅くなります。つまりCarthageを使って事前にビルドしておくことで都度のビルド時間を短縮しても、何もしないとアプリ起動が遅くなるわけです。その他、ちょっとややこしい話ですが、CocoaPodsではuse_frameworks!
にするとdynamicリンクなフレームワークになりますが、これはstaticリンクにすることもできます。
この記事では、自分のアプリでどのように設定するかのプラクティスではなく、それぞれのパッケージマネージャーのデフォルトがどうなっていて、設定でそれを変える方法とビルドされたライブラリ/フレームワークが本当に意図通りになってるか確認する方法について書いておきます。
StaticやDynamicとはなにかということについてはiOSアプリ開発のための外部ライブラリのリンクの種類や配布/利用方法として別にまとめています。
私自身が勘違いしている可能性も高いし、もっといいまとめ方もあるかもしれないのでそれはそれでコメントか別にアウトプットしてもらえれば助かります。
パッケージマネージャー別のリンク
概要
- Carthage
- デフォルト動作
- dynamicリンク
- staticリンクにするには?
- 公式のドキュメントを参考
- 参考
- デフォルト動作
- CocoaPods
- デフォルト動作
- (おそらく)staticリンク
- かつてSwiftがstaticリンクでのライブラリをサポートしていなかったため
use_frameworks!
ができた
- かつてSwiftがstaticリンクでのライブラリをサポートしていなかったため
- (おそらく)staticリンク
- 設定
-
use_frameworks!
- Pods v1.5.0から
- デフォルト動作
- dynamicリンク のフレームワーク化
-
- staticリンクにするには?
-
use_frameworks! :linkage => :static
- Pods v1.9.0から
- ターゲットごとにstaticリンク にできる
- plugin
- プラグインでさらに細かくPodごとにも指定できる
-
- 参考
- デフォルト動作
- Swift Package Manager
- デフォルト動作
-
自動でstaticかdynamic かが決まる
- 現状、基本staticになる
- ライブラリ作成者側がPackage.swiftでtype指定し static/dynamicリンクの強制 はできる
-
自動でstaticかdynamic かが決まる
- 参考
- デフォルト動作
CocoaPodsでのstatic/dynamicリンクを混在させる
Pods v1.9.0からターゲットごとにフレームワークをstaticにできるようになりました。
以下は実例。
source 'https://cdn.cocoapods.org/'
target :DynamicTarget do
use_frameworks! :linkage => :dynamic
pod 'DynamicPod' # This will be linked dynamically
end
target :StaticTarget do
use_frameworks! :linkage => :static
pod 'StaticPod' # This will be linked statically
end
参考
ライブラリが指定のリンク形式かを調べる
- otoolでアプリのバイナリから調べる
- otool
- ビルドされたライブラリから調べる
- file
otoolでビルドされたアプリのバイナリからDynamic Linkしているファイルを調べる
例
$ otool -L DerivedData/実行アプリバイナリ
fileコマンドで確認する
例
$ file ./Carthage/Build/iOS/ReactiveCocoa.framework/ReactiveCocoa
- staticリンクになってれば
current ar archive
- dynamicリンク
Mach-O dynamically linked shared library
アプリの起動時間を計測する
- DYLD_PRINT_STATISTICS
- (Xcode 13からは使えなくなった)
- Instruments
DYLD_PRINT_STATISTICSで起動時の時間表示
(DYLD_PRINT_STATISTICSはXcode 13から使えなくなりました)
ライブラリ/フレームワークによってはめちゃくちゃ遅いのがstaticリンクにすることでかなり起動速度が改善したりもしますが、どのDynamicリンクが遅いのがわかる方法もあります。
Xcodeのスキーマ設定のあたりから、Environment VariablesにてDYLD_PRINT_STATISTICS
に1かYESを設定してビルド後にアプリ起動すると、Xcodeのコンソールにdynamicリンク時間を計測して下記のような表示がされます。
Total pre-main time: <ここがトータル> milliseconds (100.0%)
dylib loading time: 188.92 milliseconds (38.6%)
rebase/binding time: 141.32 milliseconds (28.9%)
ObjC setup time: 9.88 milliseconds (2.0%)
initializer time: 148.68 milliseconds (30.4%)
slowest intializers :
libSystem.B.dylib : 3.18 milliseconds (0.6%)
libMainThreadChecker.dylib : 42.47 milliseconds (8.6%)
HogeHogeSample : 69.27 milliseconds (14.1%)
... : 23.87 milliseconds (4.8%)
...
例えば上記だとHogeHogeSampleというのがが遅いことがわかります。
XcodeのInstrumentsを使う
- 注意点
- 実機でないとWWDC19のApp Lifecycleは測定されません
- dynamicリンクを調べようとしてもUnknownになって項目名が見えないプロジェクトもある