Open3

iOSビルドについて学習ログ

matsuchiyomatsuchiyo

読んでみた: [iOSDC Japan 2019 リポート]「ライブラリのインポートとリンクの仕組み完全解説」というセッションを聞いてきました

  • この記事は、セッションSwiftにおけるインポートとリンクの仕組みを探るのレポート
  • 「ライブラリの形式と違い」
    • ?: ダイナミックフレームワーク、スタティックフレームワークの区別って、単純に、ダイナミックライブラリを保持しているかスタティックライブラリを保持しているか?両方保持することも可能?
    • ?: 「モジュールを含む...フレームワーク」「モジュールを含まない...フレームワーク」のモジュールとは?
      • ?: モジュールなしだとどうなる?Swiftからは呼べない?けどObjective-Cからは呼べる?
    • フレームワークとライブラリの違い:バンドルを持つか持たないか。
      • ?: バンドルは何が嬉しい?リソースをもてるとか、ライブラリをラップして使いやすくできるとかなのかな。
      • ?: バンドルを持たないライブラリをSwiftから呼び出す方法。
    • スタティックリンク、ダイナミックリンク
      • ?: スタティックライブラリ、ダイナミックライブラリをSwiftから利用する方法
      • fileコマンドで調べることができる。
  • 「インポートとリンク(Xcodeを使用して設定)」
    • インポート
      • ライブラリが公開しているシンボル(クラス・関数など)を自分のコードで参照できるようにする。
      • 各ファイル(コンパイル単位)をコンパイルする時点で解決される。
    • リンク
      • ソースコードをコンパイルして生成されたオブジェクトファイル、および外部ライブラリをすべて連結(リンク)して1つの実行形式ファイル、あるいはライブラリを生成する
        • オブジェクトファイルとは?
          • ソースコードから生成されるバイナリコード(機械語)のファイル。単体だと動かなくてリンカでリンクすると実行できるようになる。

            オブジェクトファイル (object file) またはオブジェクトコード (object code) とは、コンパイラがソースコードを処理した結果生成される(たいていはアセンブリ言語による assembler code file と、アセンブラによるそれのアセンブルを経由している)、コード生成の結果にしてバイナリコードを含む中間的なデータ表現のファイルである。オブジェクトファイルは共有ライブラリのようにも使われることがある。
            https://ja.wikipedia.org/wiki/オブジェクトファイル

      • 全てのソースコードをコンパイルした後に行われる
    • (Embedded Binariesに.frameworkをドラッグアンドドロップすると)「Xcodeが設定するもの」
      • FRAMEWORK_SEARCH_PATHSにフレームワークがあるディレクトリの親ディレクトリを追加
        • これを削除すると、import LoggerNo such module 'Logger'のコンパイルエラー。
      • Linked Frameworks and Librariesにフレームワークを追加
        • Xcode11からは、Frameworks, Libraries, and Embedded Contentにドラッグアンドドロップし、Embeddedかどうかはプルダウンから選ぶ。
          • ?: このEmbeddedとは?バンドルに含めるということなのだろうか。
            • その通りみたい。static frameworks and librariesはリンクされるからembedしなくていい。dynamic frameworks and librariesはする必要がある。

              Do not embed static frameworks and libraries (linking happens at build time), only shared ones (dynamic linking happens at run time, so they need to be in your bundle).
              https://stackoverflow.com/a/58860158/8834586

        • Xcode10までは、スライドのように、Embedded BinariesとLinked Frameworks and Librariesとで分かれていた。分かれている方がわかりやすい気がする...。
      • Build PhaseにCopy Files Phaseを追加してフレームワークをアプリケーションバンドルのFrameworksディレクトリにコピーする
        • このCopy Files Phaseを削除すると、実行時にdyld: Library not loaded: @rpath/Logger.framework/Loggerエラー。リンクは通っている。
      • ?: ここで、Embedded Binariesにdrag & dropしているのは、dynamic frameworkのはず。static frameworkは、どうやって追加するのか。
        • Xcode10までの場合、Embedded BinariesではなくLinked Frameworks and Librariesにdrag & dropするのかな。
        • Xcode11以降なら、Frameworks, Libraries, and Embedded Contentにdrag & dropして、embeddedは選択しない。
    • -disable-autolink-frameworkOTHER_SWIFT_FLAGSに指定しAutomatic LInkingを無効にすると、ビルドのldコマンド実行中にリンクエラー。Undefined symbol: ...
    • 大まかにまとめると...
      • FRAMEWORK_SEARCH_PATH -> import文の解決に使われる
      • automatic linking(デフォルトON) -> import文の解決と同じ方法でリンク先を探して?自動でリンク。
        • 例のLogger.frameworkでも必要なことから、ダイナミックフレームワークでもリンクの処理は行われるみたい。
        • スライドでautomatic linkingを無効にする前にLinked Frameworks and Librariesを消しているけど、このLinked Frameworks and Librariesは意味がないのかな?
      • Copy Files Phase -> 実行時にダイナミックリンクできるよう、バンドルに組み込む
  • 「インポートとリンク(マニュアル作業で設定)」
    • フレームワークからLogger.framework/Modules/Logger.swiftmoduleディレクトリの.swiftmoduleだけ残して他を削除すると、import Loggerでコンパイルエラーにならないが、ビルドのldコマンド実行時にld: framework not found Loggerエラーになる。
  • モジュールとは
    • Logger.framework/Modules/Logger.swiftmoduleディレクトリ(内の.swiftmodule等)がモジュール
      • アーキテクチャごとに作られているみたい。arm64.swiftmoduleとx86_64.swiftmoduleみたいな。
      • .swiftdocとは?名前通りAPIのドキュメントかな。
      • ?: .swiftmodule内はどうなっているのか?
    • BUILD_LIBRARY_FOR_DISTRIBUTION = YESを指定すると.swiftinterfaceが生成される。
      • ?: これの目的がよくわからない。これがなくても利用側でimport Loggerできていたので。
      • ライブラリに使ったコンパイラバージョンと違うコンパイラからも使えるようになるModule Stabilityを使うためのものらしい。もともとできなかったのか。コンパイルする時にimport対象をコンパイルしたコンパイラのバージョンをチェックしていた?

        Module Stability は異なるバージョンのコンパイラから生成された Module をコンパイル(≒インポート)できるようにするための機能で、Swift5.1 からサポートされました。これにより、Swift5.1 以降でコンパイルされた Module は、Swift5.1 以降に違うバージョンのコンパイラから正常にインポートできるようになります。ただし、これには、.swiftinterface というモジュール記述ファイルが必要で、ライブラリ側で BUILD_LIBRARY_FOR_DISTRIBUTION が Yes に設定されていない場合には、.swiftinterface が生成されず、Module Stability の恩恵を受けることができません。
        https://yamatooo.blog/entry/2020/10/08/083000

    • Swift以外だと(スライドではObjective-Cのフレームワークが挙げられている)、xxx.framework/Modules/module.modulemapのようになる。
      • ?: なぜ、アーキテクチャごとにファイルを用意しなくていいのか?
    • 「独自モジュールを定義する」によると、SwiftのAPIがないライブラリについても、独自にmodule.modulemapを用意して、そこにheader "../...省略.../hoge.h"のように指定すれば、swiftから呼べる?
      • フレームワークを使う場合FRAMEWORK_SEARCH_PATHSを指定すれば、そこにあるフレームワーク内のmoduleを使ってくれる。しかし、独自モジュールを定義する場合、SWIFT_INCLUDE_PATHSにmodule.modulemapの(ディレクトリの?)パスを指定する必要がある。
    • Bridging Headerとの違い
      • Module MapはBridging Headerの上位互換
      • Bridgin Headerはアプリケーションターゲットでしか使えない(フレームワークの開発では使えない)
      • プロジェクトにObjective-Cのファイルが混ざる場合にだけ使うのがよい(その場合でもModule Mapは使える)
        • ?: ↑よくわからない。
    • モジュールの役割
      • Swiftがライブラリをインポートするにはモジュールが必要(=インポートはモジュール鵜だけあれば良い)
      • Objecctive-C?Cのライブラリをインポートするには、ヘッダファイルをModulemapでモジュールに変換する
      • Swift製のライブラリではモジュールはコンパイラが自動的に生成する
  • リンクとは
    • フレームワークをリンクするには(以下のどちらか?)
      • FRAMEWORK_SEARCH_PATHSに...略
      • OTHER_LDFLAGSに -framework <FrameworkName>と指定する。(e.g. -framework RxSwift, -framework "Alamofire")
    • ライブラリをリンクするには(以下のどちらか?)
      • LIBRARY_SEARCH_PATHSに...略
      • OTHER_LDFLAGSに -l <LibraryName>と指定する。(e.g. -lsqlite3, -l"crypto")
    • アーキテクチャ・プラットフォームが一致しなければならない(そのための方法が以下の通り?)
      • サーチパスの変数化
      • Universal (Fat) Binary
        • xcrun lipoで作成
        • carthageも使っているぽい。スクショのCarthage/Build/iOS/keychainAccess.frameworkにファットバイナリが入っているのかな?実機とsimulator両対応の。
      • XCFramework。単にplatformとarchitectureごとにフォルダに分けたもの?
matsuchiyomatsuchiyo

?: opencvをiOSから使った時に利用したlibc++.tbdの.tbdとは?
→ libc++のダイナミックライブラリをインストールしてくるためのテキストベースのファイルらしい。SDKの容量を減らすため?

これを開いてみると単なるテキストファイルだということがわかりました。tbd = Text Based Dynamic Library といったところでしょうか。
install-name: /usr/lib/libz.1.dylib という記述があるので、どうやら実体として dylib が SDK の外側に別にあり、tbd はそれらをロードするための設定を記述したテキストファイルのようです。SDK の容量を減らす目的で Mac 側のライブラリを参照する仕組みにしたということでしょうか?(詳しい資料が見つからないので憶測ですが。)
https://qiita.com/usagimaru/items/82cf2a1fb8399c5a1be1