ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
明示的にビルドされたモジュールについて
明示的にビルドされたモジュールにより、Xcode 16でビルドがどのように変化するかを見ていきます。モジュールを使用してコードをビルドする方法、明示的にビルドされたモジュールによってコンパイル作業の透明性がどのように向上するか、複数のターゲット間でモジュールを共有することでビルドを最適化する方法について説明します。
関連する章
- 0:00 - Introduction
- 0:17 - Agenda
- 0:34 - What are modules?
- 3:57 - Using modules
- 8:37 - Module build log
- 11:28 - Optimize your build
- 14:45 - Wrap up
リソース
関連ビデオ
WWDC22
-
ダウンロード
こんにちは今日ご紹介するのは Swift/ClangモジュールをXcodeでビルドする 新しい方法です 明示的にビルドされたモジュールと呼ばれます まず モジュールとは何かという 概要から始めて 次にコードをビルドするために モジュールがどのように使用されるかと 新しいXcodeに見られる違いを 説明してから 最後に すでにビルドしたモジュールを 最大限再利用することで ビルドを最適化する方法を 紹介します
モジュールの核心は ライブラリやフレームワークの インターフェイスを記述する コード配信の単位です Swiftターゲットには複数の Swiftファイルが含まれています これらが1つになってモジュールとなります 一般的に言って 単一のターゲットまたはフレームワークの Swiftソースファイルはすべて 同じモジュールの一部です これらが表すインターフェイスはSwiftで アクセス指定子により明示的にマークされます クラスとその変数は パブリックとマークされ インポーターから 見えるようになっています
モジュールはほかのモジュールを インポートすることができ プロジェクト全体の 非巡回モジュールグラフを形成します Swiftコンパイラは皆さんが記述した 外部インターフェイスを受け取って テキスト形式の .swiftinterfaceファイルにまとめます ここにはインターフェイスのみが 含まれます
Objective-Cのモジュールは 表現が異なります Cの言語ではSwiftと違って モジュールのインターフェイスは 手作業で制作されます
まず よく知られた ヘッダの概念から説明し それらのヘッダがどのように モジュールを構成するかを記述した モジュールマップと呼ばれるファイルを サイドに追加します これはUIKitモジュールの例です まずUIKitのヘッダから始めて 次にUIKitのモジュールマップを追加します このモジュールマップはUIKitモジュールに 関する様々なことをコンパイラに伝えます まずこれがフレームワークモジュールであること 次に名前がUIKitであることです @importはこの名前によって機能します ソースコード自体は 名前を定義しないからです
次に UIKit.hにはこのモジュールを構成する すべてのヘッダが含まれること そして このモジュールがインポートする すべてのモジュールは UIKitをインポートするコードで 使用できることが示されます
名前付きモジュールのimportや モジュールに属するヘッダのincludeが コードに含まれている場合は 必ずモジュールを使用します これはResearchKitという プロジェクトです モジュールを使用するSwiftと Objective-Cの両方のコードを含んでいます
ResearchKitのSwiftソースファイルを 見てみましょう まずSwiftモジュールである SwiftUIをインポートし 次にResearchKitモジュールを インポートします これはプロジェクト自体のObjective-Cに 実装されているClangモジュールです もう一方のタブには Objective-Cファイルがあります これにはいくつかのプロジェクトヘッダの import UIKitのimport そしてClangでモジュールのimportに変換される SDKヘッダのincludeが含まれます
またモジュールにより コンパイラは様々な ソースファイル間でインターフェイスの解析を 共有できるようになります これを行うには プロジェクトソースを コンパイルする際に コンパイラで読み込まれるよう 各モジュールを 個別にバイナリファイルにコンパイルし そのモジュールが参照されるたびにモジュールの パブリックインターフェイスをインポートします Swiftではこのコンパイル済みフォームは *.swiftモジュールファイルとして表され Clangではこれは*.pcmまたはプリコンパイル済み モジュールファイルとして表されます
この再利用を可能にするためには それらのモジュールを見つけて コンパイルする必要があります やり方を説明します
コンパイラはimportを検出すると そのimportがどのモジュールを 参照しているのかを検出し そのモジュールのコンパイル済み表現を 取得します コンパイラは @import UIKitを検出すると 最初にSDKでUIKitの モジュールマップを検索します これでUIKitモジュールが 何であるかわかったので 次にUIKitのためにコンパイル済みの .pcmファイルを見つける必要があります しかしそのファイルが存在しない場合は どうなるでしょうか
そこでモジュールをビルドする 2つの大まかな方法と Xcode 16の違いを説明します 1つ目は暗黙的にビルドされたモジュールで コンパイラ同士が協調して モジュールのビルドを管理します Xcodeのほかの部分はその存在を 意識しません これがSwiftとClangの導入当初からの モジュールのビルド方法です Swift、C Objective-Cのコードを含む プロジェクトで 暗黙的にビルドされたモジュールが使われる場合 ビルドに多くの長時間実行されるタスクが 含まれることがよくあります 各行はそれぞれ 個別の実行レーンを表し Xcodeはそのレーン上で ビルドタスクを実行できます ビルドシステムはコンパイルタスクを開始し それぞれのコンパイラは 暗黙のうちにモジュールを検出して 最初に到達したモジュールをビルドします もしくは すでに存在するモジュールは そのままロードします
タイムライン表示では このようになります ビルドの開始時のコンパイルタスクは 終了時近くのタスクよりも 時間がかかります
暗黙的に構築されるモジュールでは あるコンパイルタスクが暗黙的に モジュールをビルドしている間 そのモジュールを必要とする別のタスクが そのビルドの完了を待って ブロックされてしまうことがあります これはビルドの様々な部分で 発生する可能性があります Xcode 16ではモジュールを明示的に ビルドすることでこれを変えており Xcodeはコンパイラと連携して モジュールを見つけ ビルドします 明示的にビルドされたモジュールは モジュールをビルドする暗黙の作業を 明示的なビルドシステムの タスクに引き上げます
そのために Xcodeは 各ソースファイルのコンパイルを 3つのフェーズに分解します これはスキャン モジュールのビルド そして元のコードのビルドです
Xcodeではまず 各ソースファイルがスキャンされ それを使ってプロジェクト全体の モジュールグラフが作成されます ターゲット間でのモジュール共有もあります モジュールグラフを構築する時には モジュールのコンパイルタスクの ディスパッチも開始できます これらは依存する コンパイル済みのモジュールと 一緒に直接提供される ビルドログの明示的なタスクです 最後のステップは元のコンパイルタスクの 実行です これはそのタスクが依存する コンパイル済みモジュールを そのタスクに追加して修正した後に行われます
明示的なビルドのモジュールの場合 タイムライン表示には 明示的なスキャンタスク モジュールのコンパイルタスク 元の ソースファイルのタスクが含まれますが かかる時間は大幅に短縮されました
ビルドシステムがモジュールを 認識していることの利点は 実行の準備ができていないタスクで 実行レーンが 埋まってしまうのを避けられることです 代わりに 必要なモジュールの準備が整うまでタスクの実行を待ちます そのためビルドシステムは 利用可能な実行レーンを 効率的に利用できます
モジュールをビルドするこのアプローチには いくつかの利点があります 1つ目はビルドの信頼性の向上です 正確な依存関係と 決定論的なビルドグラフが ビルドシステムに公開されているため コンパイラは毎回同じように実行され ビルドに失敗しても失敗したタスクを 単独で再度実行するだけで その失敗を再現できます 他の場所で暗黙の状態が 維持されることはありません これはクリーンビルドでモジュールが リビルドされるようになったことも意味します これでビルドの効率アップも 可能になります ビルドシステムがモジュールグラフを 完全に認識できるようになったことで モジュールのビルド待ちの コンパイルタスクによって 実行レーンがブロックされる代わりに より情報に基づく確かなスケジュールの 選択ができるようになりました ビルドシステムがモジュールのビルドを 調整することのもう1つのメリットは Xcodeでのデバッグの際 デバッガに Swiftモジュールが渡されることです
暗黙的に構築されたモジュールを使って プロジェクトがビルドされると Xcodeビルドとデバッガは全く別々の モジュールグラフを持つようになります 明示的に構築されるモジュールにより デバッガはビルド済みのモジュールを 再利用できるようになりました それによりデバッガが pやpoを使用した式を評価する時など Swiftの型について知る必要がある時に モジュールの再構築を避けることができます 明示的ビルドのモジュールは ビルドログでの タスクの表示方法にも影響を与えます Xcode 16では明示的ビルドのモジュールは 全てのCとObjective-Cのコードで使用されるため Swiftのプレビューとして有効化できます まず プロジェクトナビゲータで ResearchKitプロジェクトを選択し Swift用に明示的にビルドされたモジュールを 有効にします
を選択し フィルタボックスに 「explicitly built」と入力します
次に の 設定を選択してに設定します
これで明示的にビルドされたモジュールが ClangとSwiftの両方で有効になったので ビルドを開始します
ビルドログには多くの スキャンタスクが含まれています これらはプロジェクトの各ソースファイルに 対して1回だけ実行され ビルドシステム用のモジュール インポートグラフを生成します これは組み込みのタスクであり 新しいプロセスは生成されません これによりビルドシステムは スキャンするソースファイル間の 情報をキャッシュできます
2つ目の新しいタスクは コンパイルモジュールタスクです これらのタスクが特定のプロジェクトや ターゲットに付随することはありません これらは最上位レベルのタスクであり 複数のターゲット間で共有できます これらについてはビルドシステムがそれぞれに 別個のコンパイラプロセスを生成します このタスクは指定モジュールを コンパイル済み モジュールファイルにビルドします これは暗黙的にビルドされた モジュールの通常のコンパイル時に 起こっていた作業ですが 現在は分割されています モジュールのビルド中に発生した診断結果は 最初にビルドしたソースファイルではなく ここに添付されます 単一のモジュールが複数回 ビルドされることにお気づきでしょうか このビルドではUIKitモジュールが 複数回表示されます これは様々なターゲットの ビルドの設定によって ビルドされるモジュールの バリアントが異なるからです このビルドには2種類のSwiftモジュールと 4種類のClangモジュールがあります
そのうち2つをよく見ると Xcodeはそれらに 異なるハッシュがあることを示しています このハッシュはこのモジュールバリアントを ビルドするのに必要な コマンドライン引数のセットを表します これらのフラグは多くの場合 言語標準 機能マクロ インクルードパスの違いなどです これはよく目にすることで 暗黙的にビルドされたモジュールでも 発生しますが モジュールのビルドシステムで 公開されていなかったため 気づくのがより難しくなっていました コンパイラはスキャン中に この引数リストを最適化し モジュールのビルド方法に 影響がなかったものを削除します 例えば 未使用のヘッダ検索パスなどです ではResearchKitに戻って 余分なバリアントを削除しましょう まず自分のプロジェクトでビルドした モジュールの追加情報を収集したいと思います
ビルドフォルダを消去して プロジェクトの すべてのモジュールを再構築します
> > を使用して ビルドのパフォーマンスについての 追加情報を収集します (ビルド中) 複数のモジュールバリアントは 様々なソースファイルのビルド設定に 互換性がないため生じています 例えばCソースファイルと Objective-Cソースファイルは モジュールによって解析方法が 大きく異なります 不要なモジュールバリアントによって ビルドでの実行が必要な 追加作業が発生してしまいます
モジュールバリアントの一般的な発生源には プリプロセッサマクロの追加 言語モードの追加による問題 例えば 単一のCファイルとObjective-Cの混在など また言語バージョンの問題 例えば Objective-Cと C17のような 新しいCバージョンの併用など そして 自動参照カウントの無効化などがあります ではビルドが完了したので フィルタに 「modules report」と入力します
Clangモジュールレポートを選択すると 2種類のUIKitやその他多くの モジュールがあることがわかります
Swiftモジュールレポートを選択すると バリアントが2つあることが表示されます これらを総合すると 以前ビルドログで確認した UIKitの4つのバリアントが説明できます バリアントの数を減らすには バリアントがよく発生する ビルド設定をチェックします プロジェクトナビゲータで ResearchKitを選択し フィルタボックスに「macros」と入力して 余分なマクロの設定がないか確認します プロジェクトレベルには何もないので ビルド設定でResearchKitターゲットを 確認します
ここには他のターゲットにない余分な ENABLE_FEATUREマクロがあります
ここではモードを選択して プロジェクトのレベル設定も同時に確認します
このマクロをターゲットから削除し ResearchKitプロジェクトに配置します
もう一度 > > を選択します
今度はビルドログに3種類のUIKitの バリアントしか表示されていません Objective-Cのものが1つ Swiftのものが2つです 1つはClangモジュール用 もう1つはSwiftモジュール用です
プロジェクト設定を統一することで 別々のグラフを1つに まとめることができます 一般に ビルド設定は プロジェクトに妥当な範囲で 動かすのがよいでしょう 言語標準はターゲットレベルに 合わせて設定するのではなく プロジェクトまたはワークスペースのレベルに 引き上げるべきです そうすることで モジュールをできるだけ ソースファイル間で共有できるようになります 明示的にビルドされたモジュールについては 以上です
このセッションで覚えておくべき主な事項は モジュールを 明示的にビルドすることで ビルドシステムが モジュールのビルドを制御できることです 今後はビルドログの見た目が変わり モジュールビルドのコンパイル時間が 独自のタスクとして表示され コンパイルタスクには 含められなくなります プロジェクト全体で設定を統一することで ビルドするモジュールバリアントの数を 減らすことができます これで特定のソースファイル用にビルドされた モジュールをターゲット間で共有できます ご視聴ありがとうございました
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。