Xcode
このノートについて
Xcode が採用している概念について理解して、ついでに pbxproj ファイルもなんとなく読めるようになるためのメモ。 前提知識
Build とは?
Swift においては、Swift のソースコードから実行可能バイナリを生成する過程のこと
Compile と Link の 2 ステップが存在する
Compile は、Swift ソースコードをマシンが直接扱えるオブジェクトコードにコンパイルすることで、LLVM 等の Compiler によって実行される Link は、オブジェクトコードを実行可能なバイナリにまとめることで、Linker によって実行される
概念
Xcode Project
Xcode Project の構成は、大体以下のような感じ。Project には複数の Build Configurations と Targets が紐づく。また、Build Configuration や Target、その他ビルド設定の組み合わせを Scheme として定義しておくことができる。
Project
(Project-level) Build Settings
Build Configurations
Targets
(Target-level) Build Settings
Build Phases
Xcode Scheme (Build Scheme)
Build Scheme とは、主に Build Target と Build Configuration の組み合わせで定義される。よく利用する設定の組み合わせを Scheme として保存しておくことで、Scheme の切り替えだけで即座に適切な設定に切り替えてビルドが実行できる。 例えば、以下のような組み合わせで Scheme を用意して、ビルドを実行できる。
Build Target がアプリ x Build Configuration が Debug
主に、手元でデバッグするために Run するのに利用する
Build Target がアプリ x Build Configuration が Release
主に、リリース時に Archive するのに利用する
Xcode Target (Build Target)
Xcode プロジェクトは、少なくとも 1 つの Target を持つ。Target は ビルド対象となるプロダクト を表す。プロダクトとしては、iOS/watchOS/macOS 向けのアプリケーションや、Embedded Framework のようなモジュール、ユニット/UI テスト用の Bundle なんかが該当する。Build に用いる入力 (Source code, Framework, Resource) と出力 (App, App Extension, Framework) を定義したもの、と捉えることもできる。 Target には Build System への入力となるソースファイル群やそのビルドのための設定群が紐づく。Build System はこれらを受け取ってビルドを実施し、最終的な成果物としてプロダクトを出力する。ビルドのための設定群とは、主に Build Settings と Build Phases になる。
また、Target は互いに依存関係を持つ場合がある。例えば、ある Target A のビルドのために別の Target B が必要となる場合は、Target A は Target B に依存していると言える。この依存関係は Xcode 上で明示的に設定することができ、Build System はこの依存関係を考慮してビルドを行う。 Build Configuration 毎に以下のような設定を行うことができる。
Build Configuration に Build Configuration ファイル (xcconfig) を紐づけて、設定を読み込むことができる Build Setting の値を Build Configuration 毎に行える
コード署名 の設定を Build Configuration 毎に行える また、Build Configuration 毎にソースコード上でロジックを切り替えるような活用方法もある。
概要
Build Settings はその名の通り、ビルドプロセスに関する設定である。その設定はビルドプロセス内の各種タスクに適用される。Xcode プロジェクトの内容と大半はこの Build Settings が占める。 設定の要素
Builde Setting は、Setting Title と Definition、必要に応じて Display Name の 2 or 3 つから構成される。Setting Ttile は設定の識別子であり、Definition は具体的な値もしくは Xcode が解釈可能な値を解決するのに利用できる式などが割り当てられる。Display Name は Xcode の UI 上での表示名を表す。 設定値のカスタマイズ
多くのビルド設定がカスタマイズ可能であり、カスタマイズする方法としては以下がある。
Xcode の Target and Product エディタ上で編集する (内容はプロジェクトファイルに保存される) 設定値の継承
Build Settings は、各値毎に iOS ならば iOS 固有のデフォルト値を持っているケースがある。これらはカスタムな値で上書きすることができる。カスタマイズできる設定には、主に Project-level, Build Configuration file, Target-level の 3 種類がある。Project-level の設定は全ての Build Configuration & Target-level の設定に、Build Configuration の設定は全ての Target-level の設定に継承される。これらの設定は継承した側で上書きすることができる。逆に明示的に継承したい場合は $(inherited) のような式を用いると、継承元の値を展開することができるようになっている。継承は Project-level > Build Configuration > Target-level の順に行われ、最終的にはただ 1 つの値に解決される。
Conditional Build Setting
ビルドターゲットとしている SDK (iOS, iOS Simulator, ...) やアーキテクチャ (x86, arm64, ...)、Build Configuration によってビルド設定を分岐させることができる。このようなビルド設定は conditional build setting と呼ばれる。
conditional build setting は利用できる設定値が決まっているようで、利用できる設定値では Xcode 上で以下のようなメニューで設定できる (Xcode 12.5 で確認)。
https://gyazo.com/346f7bd3c009c96aefdc130a785552db
User-Defined
あらかじめ用意されている Build Setting 以外にも設定値を追加したいケースがある。例えば、以下のようなケースが考えられる。
Build Phases で参照する値を定義しておきたい
Swift/Obj-C コードから参照可能な設定値を定義しておきたい
このような場合には、User-Defined な設定値を Build Settings に追加することができる。
デフォルトだと、Target 毎に Info.plist が用意される。この Info.plist 内には Build Settings 内の値を展開することができるようになっている。この挙動は Expand Build Settings in Info.plist Files (INFOPLIST_EXPAND_BUILD_SETTINGS) という設定により、デフォルトで有効になっている。 Tips: Expand Variables Based On
どういう設定なのか調べてみた。
Xcode 上で Target 毎に設定可能な Build Settings がいくつかある。これは Target の Build Settings タブで設定可能なもので、例えば Architectures などになる。 そのステップにて、どの Target の Build Settings を展開して利用するか?ということだと思われる。
The Expand Variables Based On menu specifieds hich executable's specific environment variables (as seen in the run logs) are to be used when expanding those that Xcode suuplies (such as ARCHS).
Xcode プロジェクトの内容は project.pbxproj ファイルとして保存されている。内容は独自のフォーマットとなっているが、これを少し読み解いてみる (Xcode 12.5 時点)。やっているのは大まかな構成の把握と、内容の大半を占める Object の種別の整理まで。ここまで理解できればあとは雰囲気で読み解けるようになっていると思う。 大まかな構成
内容をみると、以下の 4 つの Key-Value を持ち、内 objects の内容が大半を占めている。
code:text
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objects = {
...
};
objects 内には下記のように、識別子 と複数の Key-Value のペアを保持するオブジェクトのマッピングが記載されている。Xcode プロジェクトの設定はこのようなオブジェクト定義の集まりであり、オブジェクト同士は 識別子によって参照しあえるようになっているようだ。 code:text
オブジェクトはその種類によって保持できる Key がある程度決まっているように見える。さらに、オブジェクトはその種類を識別するための特別な Key として isa と言う Key を必ず保持しているようだ。さらに、pbxproj ファイルはオブジェクトの種類毎にコメントでセクション分けがされている。このセクションは、オブジェクト定義の種類毎に設けられているようだ。 code:text
/* Begin PBXBuildFile section */
...(中略)...
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
...(中略)...
/* End PBXContainerItemProxy section */
...(以下略)...
Object の種別
では、各オブジェクトの種類はどのような役割を持ったものなのか?について読み解いてみる。個人的な観点で、オブジェクト種別をさらに 3 つのグループに分けて整理してみた。
Project や Target、Build Configuration 等の設定を取りまとめるオブジェクトの種類は、下記になりそうだった。これらは設定項目として他オブジェクトを参照している場合が多い。PBXProject は複数の PBXNativeTarget を参照しているし、PBXNativeTarget は PBXBuildConfiguration や Build Phase 関連の多くのオブジェクトを参照している。
table:基本となるオブジェクト
isa Key 概要
PBXProject Project 設定。基本的に1つ?紐づく Target や言語設定など
PBXNativeTarget Target 設定。Build Phase/Rule, Configuration List, Dependency への参照など
PBXBuildConfiguration Build Configuration の設定。Build Settings や紐づく xcconfig ファイルへの参照など
XCConfigurationList Target に紐づく Build Configuration のリスト。デフォルトの Build Configuration なども含む
Xcode 上で左ペインに現れるソースツリーを構築するために必要になるようなオブジェクトの種類は、下記になりそうだった。ソースファイルやグループをはじめ、同じリソースでも別バージョンが存在する場合にはそれがグループとしてまとめて表現されるようになっている。 table:リソースを表現するオブジェクト
isa Key 概要
PBXFileReference ソースファイル。実ファイルへの参照を保持する。
PBXGroup ソースツリー内のグループ。子要素として PBXFileReference 等を持てる
PBXVariantGroup 同一リソースの別バージョンのグルーピング。localize された言語ファイルなど
XCVersionGroup バージョニング可能な要素。Core Data のモデルファイルなど オブジェクト定義の大半を占めるのは Build Phase に関連するオブジェクトだった。下記に示しているが、まだ種類は色々ありそう。大抵 Build Phase の 1 Phase に相当するケースが多い。また、他オブジェクトを参照するためのプロキシとして PBXBuildFile や PBXContainerItemProxy のようなオブジェクトを仲介しているケースが見受けられた。プロキシを介することでオブジェクトの具体的な種別を隠蔽できるとか、プロキシに情報を持たせることができるとか色々予想はできるけど、具体的になぜ必要なのか?までは掘り下げていない。
table:Build Phase 関連のオブジェクト
isa Key 概要
PBXCopyFilesBuildPhase Build Phase の Copy Files に相当する
PBXFrameworksBuildPhase Build Phase の Link Binary With Libraries に相当する
PBXHeadersBuildPhase Build Phase の Headers に相当する
PBXResourcesBuildPhase Build Phase の Copy Bundle Resources に相当する
PBXPBXShellScriptBuildPhase Build Phase のカスタムな Run Script 定義に相当する
PBXSourcesBuildPhase Build Phase の Compile Sources に相当する
PBXTargetDependency Build Phase の Dependencies 内の各行に相当する
PBXBuildFile ビルド対象ファイル。PBXFileReference への参照をもつ。Build Phase からの参照に利用されてそう
PBXContainerItemProxy 他オブジェクトを間接的に参照できるプロキシ。Dependency からの参照に利用されてそう
参考
https://www.youtube.com/watch?v=e_T1-XrYf4A