Open4

mergeable libraryについて

kamimikamimi

WWDC の Meet mergeable libraries

前提知識

  • static library
    • オブジェクトファイルの集まり
    • ビルドタイムに、リンカーは使うAPIを探し、アプリのバイナリにコードをコピーする
    • コピーされ、ビルドされたあとは、ライブラリは不要となる
ライブラリの種類 特徴 メリット デメリット
スタティックライブラリ ・オブジェクトファイルの集まり
・ビルドタイムに、リンカーは使うAPIを探し、アプリのバイナリにコードをコピーする
アプリの起動はダイナミックライブラリよりも早い ライブラリに変更が入ると、ビルド時間が増える
ダイナミックライブラリ ・dylibs
・Xcodeのフレームワークターゲットのバイナリファイル
・フレームワークのコードは実行可能なものにコピーはされず、ライブラリへのパスがアプリのバイナリに記録される
・AppleのSDK以外は、アプリのバンドルにembededされていなければいけない
ビルドが早い(コードをコピーしていないため) メモリを消費し、アプリの起動に時間がかかる(dyldと呼ばれるダイナミックリンカーがフレームワークの依存関係を探して、読み込むため)
(Appleはこれを考慮した最適化を行っているが、それはアプリに埋め込まれているフレームワークには適用されない)

参考

https://zenn.dev/link/comments/4cf0be89de280a

mergeable libraries

「Mergeable libraries unlock the best of both linking strategies.」

  • 実行可能なものかダイナミックライブラリになりうる
  • マージは、スタティックライブラリリンキングに似ている
  • 最後に出力されるバイナリは、同じファイルタイプ

新しいスタティックリンカー

  • これがmergeable libraryを可能にしている

  • -make_mergeableオプションを使用する

    • リンカーにメタデータの記録を伝える
  • -merge_library-merge_frameworkオプションを使用する

    • バイナリが全てのインプットをマージする
  • Xcodeがよしなにやってくれるが、これらはビルドログで確認することができる

  • ライブラリとメタデータは不要なので、マージされたバイナリの大きさのみ気にすれば良い

  • マージされるとき、全てのライブラリを通じたコンテンツの重複排除を行う

  • 元々あるオプションや最適化は適用されうる

有効にする方法

  1. Automatic Merging
  • フレームワークターゲットを埋め込んでいる全ての直接的な依存関係をマージする
  • アプリターゲットに対して特に役にたつ

  • mergeable libraryの出力は、アプリに保存されるため、アプリのサイズやビルド時間に影響が出る
    • それを防ぐため、-no_exported_symbols

  • エントリポイントがApp extensionで必要な場合、export listで定義することもできる

  1. Manual Merging
  • 全てではなく、フレームワークのいくつかをマージしたい場合

  • 方法

    • MERGED_BINARY_TYPEmanualにする
    • マージしたいdylib(ダイナミックライブラリ)をMERGEABLE_LIBRARYYESにする(ディスクに置いたままにしたければ、NOにする)
  • デバッグモードでは、マージしない

注意点

Autolinking
  • デフォルトでオンのオプション
  • mergeable libraryからモジュールをインポートしていると、ダイナミックリンキングの問題が発生する可能性がある
    • マージされたフレームワークに対してリンクする
      • マージされたフレームワークをXcodeのLink Binary With Librariesに追加し、マージされたものは取り除く
  • ほとんどのケースでは、ダイナミックリンキングのAPIであるdlopenは使わないが、必要な場合、パスにマージされたバイナリのパスを定義する必要がある

Runtime APIs
  • リソースのlookupもマージの際に影響を受ける
  • mergeable librariesを使うには、iOS12以降にアップデートが必要だが、使用しない場合-Wl, -no_merged_libraries_hookを使って無効にできる
    • そうすることでバージョンを上げる必要はなくなる
    • mergeable libraryにバンドルリソースを含まない場合も使える
    • アプリの起動時間の短縮につながる
Xcode 15のリンカー
  • マージは新しいリンカーで有効
  • 古いリンカーは広報互換性のために残る
  • 新しいリンカーは、armv7k(watchOS8など)のアーキテクチャをサポートしない
フレームワークの配布
  • XCFrameworkとしてmergeable libraryを配布する
  • クライアントがマージするかどうかを決める
推奨するmergeable libraryへの対処
  • マージされたターゲットに対してリンクすること
  • Script Phasesでバイナリを使用するツールがある場合、インプットを更新する必要がある
  • マージするには、Xcodeのターゲットレベルでで設定する必要がある
  • スタティックライブラリをダイナミックライブラリに変更する
    • それによってmergeable libraryの対象となりうるから