View in English

  • Apple Developer
    • 今すぐ始める

    「今すぐ始める」を詳しく見る

    • 概要
    • 学ぶ
    • Apple Developer Program

    最新情報

    • 最新ニュース
    • Hello Developer
    • プラットフォーム

    プラットフォームを詳しく見る

    • Appleプラットフォーム
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    特集

    • デザイン
    • 配信
    • ゲーム
    • アクセサリ
    • Web
    • Home
    • CarPlay
    • テクノロジー

    テクノロジーを詳しく見る

    • 概要
    • Xcode
    • Swift
    • SwiftUI

    特集

    • アクセシビリティ
    • App Intent
    • Apple Intelligence
    • ゲーム
    • 機械学習とAI
    • セキュリティ
    • Xcode Cloud
    • コミュニティ

    コミュニティを詳しく見る

    • 概要
    • 「Appleに相談」イベント
    • コミュニティによるイベント
    • デベロッパフォーラム
    • オープンソース

    特集

    • WWDC
    • Swift Student Challenge
    • デベロッパストーリー
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Center
    • ドキュメント

    ドキュメントを詳しく見る

    • ドキュメントライブラリ
    • テクノロジー概要
    • サンプルコード
    • ヒューマンインターフェイスガイドライン
    • ビデオ

    リリースノート

    • 注目のアップデート
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • ダウンロード

    ダウンロードを詳しく見る

    • すべてのダウンロード
    • オペレーティングシステム
    • アプリ
    • デザインリソース

    特集

    • Xcode
    • TestFlight
    • フォント
    • SF Symbols
    • Icon Composer
    • サポート

    サポートを詳しく見る

    • 概要
    • ヘルプガイド
    • デベロッパフォーラム
    • フィードバックアシスタント
    • お問い合わせ

    特集

    • アカウントヘルプ
    • App Reviewガイドライン
    • App Store Connectヘルプ
    • 近日導入予定の要件
    • 契約およびガイドライン
    • システムステータス
  • クイックリンク

    • イベント
    • ニュース
    • Forum
    • サンプルコード
    • ビデオ
 

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • すべてのビデオ
  • 利用方法

その他のビデオ

  • 概要
  • トランスクリプト
  • Xcodeのビルドプロセスの舞台裏

    Xcodeでプロジェクトをビルドする際、どのようなことが起こっているのか考えたことはありますか?Appのビルドに必要な手順がXcodeによってどのように自動化されているか、入力したソースコードが実際のプログラムとして稼働するためにClang、swiftc、リンカーがどのように連携しているか、その舞台裏について紹介します。

    リソース

      • HDビデオ
      • SDビデオ
    • プレゼンテーションスライド(PDF)

    関連ビデオ

    WWDC22

    • Xcodeビルドでの並列化に関する解説

    WWDC20

    • Swift用にObjective-Cフレームワークを洗練させる

    WWDC18

    • Swiftの新機能
    • Xcodeでビルドスピードを上げる
  • このビデオを検索

    (音楽)

    (拍手) こんにちは 今日はXcodeの ビルドプロセスを解説します 私はビルドシステム部門の ジェイクです これから交代で 解説していきます

    まずXcode 10の新たな ビルドシステムを説明します 全面的に再構築され 進化しました Command + Bを押すと 何が起きるのでしょう? どんな順番で どうやって プロジェクトの情報を使い― ビルドプロセスを 決定するのでしょうか?

    次にコンパイラの領域です オブジェクトファイルへと コンパイルされる過程や― ヘッダとモジュールの 動きを説明します コンパイラが 宣言を見つける方法とは? Swiftのコンパイルは 他の言語とは大きく異なります

    プロセスの最終段階である リンカーも解説します シンボルの役割を 確認しましょう また コンパイラで生成した オブジェクトファイルが― 実行可能ファイルとなる 過程を説明します

    アプリケーションの サンプルを用意しました ペットの写真を表示する PetWallです

    では ビルドプロセスの 解説を始めます Xcodeがアプリケーションを ビルドする方法とは? アプリケーションは 多数の ソースコードで成り立っており― 記述言語も異なります

    さて…

    ビルドとは― ソースコードやリソースを パッケージ化することです ユーザに配信するまでには 多くのステップがあります コンパイルや リンク作業の他に― ヘッダを始めとした リソースの管理も必要です そしてコード署名します 場合によっては シェルスクリプトや― APIドキュメントや 検証ツールの準備もするでしょう

    こうした処理には コマンドラインツールが必要です 例えば ClangやLD ACツールなどです 正常に実行させるには プロジェクト内の引数を― 正しい順序で 構成する必要があります

    ビルドシステムは 指示されたタスクを― 自動的に処理します タスクは何万にも及びます しかも 互いが複雑に 依存しているのです ビルドのたびに 手動で処理していられません

    ビルドシステムに 任せましょう

    ビルドシステムの実行に際し 大事なのは順序です 順序の決定方法と その理由を説明します

    タスクの実行順序は 依存関係によって決まります タスクはインプットを受け アウトプットを生成します 例えば PetViewController.mを コンパイルすると― PetViewController.oが 生成されます コンパイラが生成したものを リンカーにインプットすると― 実行可能ファイルや ライブラリが生成されます そして 実行可能ファイルは Appバンドルへ収めます パターンが見えてきましたね 依存関係に従った 流れになっています これが実行順序にも なるわけです この図を交通に見立て コンパイルを考えてみます 各コンパイル過程は 独立した道路です 並列処理が可能です 全インプットの終着点 リンクタスクは最後ですね

    依存関係を定義することで タスクの実行順序が決まります 並列化も可能です これが依存性順序です 以上が ビルドプロセスの概要です 続いて詳しく見ていきます ビルドを開始したら 何が起こるか? ビルドシステムは まず プロジェクトファイルを参照します プロジェクトに記述してある ターゲットや依存関係― さらにビルド設定などを 解析します 続いて その結果を 有向グラフにします 全ファイルの依存関係を 表しています 実行すべきタスクも 表示されています

    下層処理エンジンが グラフを整理します タスクの実行順序は 依存関係により決定されます 並列処理するタスクも この時に判断されます そして実行に移します ところで Xcode 10の 下層処理エンジンllbuildは― オープンソースです 興味があれば 実物を確認できます セッションの最後に URLを紹介します 次に依存関係の発見について 説明します 依存関係の定義は 多い方がいいので― システムが新情報を 発見することがあります すると コンパイル時に オブジェクトファイルと共に― 別のファイルも生成されます ヘッダファイルの リストなどが含まれます このリストは 再度ビルドする時に使います これでヘッダを変更しても コンパイルが可能になります ご覧のとおり PetController.hから .oファイルまで つながっています

    さて 説明してきたとおり― ビルドシステムの主な役割は タスク処理です プロジェクトが大きければ 処理も長くなります 毎回 全タスクを 実行するのは大変です 代わりに サブセットだけ実行します

    前回のビルドからの 更新部分だけ処理するのです 増分ビルドといいます 正常に処理するためには― 依存情報の正確性が 非常に重要です

    更新の影響と増分ビルドの 話をしましたが― 更新部分を検知する仕組みとは? 各タスクには 関連する情報に基づいて― ハッシュ値のような署名が ひも付いています

    インプットのstat情報が 含まれます 具体的にはファイルのパスや 更新日時― コマンドラインによる 指示などです さらに コンパイラの バージョン情報も入ります

    前回 ビルドした時の署名と 合わせて追跡することで― タスクの再実行が必要か 判断します

    現在の署名が 前回と異なる場合には― 再びタスクを実行します 署名が同じなら スキップします これが増分ビルドの基本です

    ビルドの流れと仕組みが 分かってきましたね 次にシステムの負担を 軽減しましょう

    振り返ってみます ビルドとは順序に沿った 一連のタスク処理です でも 有向グラフの話を 思い出しましょう 人間は順序を 考える必要はありません ビルドシステムの仕事です 私たちはタスクの依存関係を 考えればいいのです システムに順序良く 正常に処理させましょう 可能な場合には 並列処理もしてくれます マルチコアを フル活用してください

    依存関係の出どころは? ビルドシステムが 作る場合もあります コンパイラやリンカー用の ルールが― あらかじめ 備わっているのです ルールに従ってインプットや アウトプットが決定されます

    ターゲットの生成順序を決める 依存関係もあります 別ターゲットのソースの 並列コンパイルも可能です Xcode 9での ターゲットのビルドは― 依存する別ターゲットの 処理完了後のみ可能でした Xcode 10では ビルド開始が早くなりました コンパイル開始も早くなり 並列処理も可能です ただし 並列処理させたい場合― Run Script Phaseは 先に終了してください

    ターゲット関連の依存は 暗黙の依存関係です 例えばLink Binary With Libraryに ターゲットを入れた時です Find Implicit Dependenciesを 有効にしておけば― Target Dependenciesにない 依存関係が発見できます

    続いて ビルドフェーズによる 依存関係です エディタ内には 多数のフェーズがあります 内容はヘッダのコピーや ソースのコンパイルなどです タスクは基本的には リストの順に実行されます Link Binary With Libraryが コンパイルソースの前にあるなど 場合によっては 順序は入れ替わります この順序が不正な場合 ビルドの失敗もあり得ます 依存関係を理解し 正しい順序で組んでください

    スキームの順序による 依存関係もあります Parallelize Buildを スキーム設定で有効にすると― 並列処理できるので 順序は関係なくなります しかし Prallelize Buildを 無効にすると― リスト順に 1つずつ処理されます ターゲットの依存関係は 優先度が高いですが― それ以外は リスト順が優先されます それなら人間が 依存関係を定義せず― 任せてしまえばいいのか? 1つずつの処理では 時間が掛かりすぎます よって Parallelize Buildは 有効にしつつ― 自分でも依存関係を 正確に定義しましょう

    依存関係を生み出す 最後の要素は あなたです

    シェルスクリプトのビルドや ビルドルールを作成する場合― インプットとアウトプットを 明確に定義しましょう タスクの不要な再実行を 予防でき― 正しい順序での実行に 役立ちます 定義はRun Script Phaseの エディタで行います パスを作れば 環境変化にも 対応しやすくなります

    依存関係を自動リンクに 頼ってはいけません 自動リンク機能は― Link Frameworks Automaticallyの 設定で有効にできます Link Binary With Libraryで リンクしていなくても― モジュールに対応し フレームワークにリンクします ただ ビルドシステムのように 依存関係は定義されず― 依存するターゲットがリンク前に ビルドされていない場合があります

    自動リンクに頼っていいのは SDKフレームワーク使用時だけです UIKitなどが 依存関係を 付加してくれるからです Xcodeプロジェクトには 依存関係を明示してください

    依存関係を明示したい 別プロジェクトがあれば― ファイルナビゲータに ドロップしてください リファレンスを作成できます

    繰り返しますが 重要なのは 正確な依存関係です 並列処理と安定した結果に つながります ビルドを短縮し 開発に時間を割きましょう ビルドをより高速化し iMac Proの性能を生かすには― Building Faster in Xcodeを ご覧ください 次はユルゲンが コンパイラを解説します (拍手) ありがとう

    これから お話しするのは― XcodeがClangを 呼び出す時の挙動です

    こんにちは 私はユルゲン Clangのエンジニアです 主に2つの内容を お話しします 1つ目はヘッダマップです XcodeからClangへの 情報の伝達方法を説明します 2つ目はClang Modulesです ビルドの高速化に関わります

    Swiftしか触らない人も いるでしょう でも実際には Clangも関わりがあります ぜひ お聞きください

    Clangとは?

    AppleのC言語コンパイラです Cだけでなく すべてのC言語ファミリーです C++や― よく使用される Objective-Cも含みます

    ジェイクの話の確認です

    1つのインプットファイルごとに コンパイラが呼び出され― アウトプットを リンカーに渡します 例えば OSからAPIへアクセス― または自分のコードの実装に アクセスするとします すると通常 ヘッダファイルも インクルードされます

    ヘッダファイルとは約束です つまり 実装ファイルが 存在するとの約束です 普通は約束どおりです 実装ファイルだけ更新し ヘッダを忘れると― 約束を破ることになります コンパイラは約束を信じ 処理を完了しますが― リンク時に問題が起きます

    コンパイラは大抵 複数のヘッダをインクルードします これを いくつも処理します アプリケーションの サンプルを使って― ヘッダの扱いを確認します

    PetWallは複数の言語で 記述されています アプリケーション自体は Swiftで書かれています フレームワークの言語は Objective-Cです サポートライブラリは C++での記述です

    近頃 ファイルが 多くなってきたので― 探し物を楽にするため 整理してみます Catの関連ファイルを サブフォルダに移します

    実装ファイルを 更新していないのに― 動作は正常です ここで疑問が生じます

    Clangはどうやって ヘッダを見つけるのか?

    例で確認します これが私たちが使っている― 実装ファイルです ヘッダファイルCat.hを インクルードしています

    Clangの動きを 知る方法とは? ビルドログからも 確認できます ビルドシステムの コンパイル時の動作ログです 呼び出しのログを コピーします ターミナルに貼り付けて -vを付けます 詳細を表示するコマンドです 多くの情報を教えてくれます 今はパスの検索だけに しておきましょう

    パスの検索と聞くと ソースまでのパスが― 表示されると思うでしょう

    でも そうではありません これで表示されるのは ヘッダマップです

    Xcodeのビルドシステムは ヘッダマップによって― ヘッダファイルを見つけます では続きです 確認するのは 2つのヘッダマップファイルです

    上の2つのヘッダは― フレームワーク名と ヘッダ名だけですね これでパブリックヘッダだと 分かります

    ただ この機能に 頼ってはいけません 動作させ続けるために 必要な機能ですが― これに頼るとClangModules使用時に 問題が起こる場合があります このようなヘッダファイルを インクルードする場合は― フレームワーク名を 記述しておきましょう

    3つ目は プロジェクトのヘッダです 今回は触れません ヘッダマップの役割とは ソースコードへの案内です

    パブリックだけでなく プライベートヘッダでも― 必ずソースコードが 見つかります Clangはソースディレクトリの ファイルに関して― 役立つエラーや警告を 出してくれます 一方 ビルドディレクトリの ファイルは対象外です

    ヘッダマップの存在を 意識しておかないと― 問題が起きます よくあるのがプロジェクトに ヘッダを付け忘れることです ソースディレクトリには 存在するのにです プロジェクトには 必ずヘッダを付けましょう こんな問題もあります

    同名のヘッダが 影響し合うトラブルです 必ずユニークな名前を 付けましょう システムのヘッダにも 言えることです ローカルヘッダと 同じ名前になっていると― やはり影響が出るので 避けてください ところでシステムヘッダを 見つけるには?

    PetWallで確認します SDKのヘッダ Foundation.hを インクルードしています

    先ほどの手順では― システムヘッダは 見つけられません ヘッダマップは 自分のヘッダ用なので― 今は必要ありません インクルードのパスを 見ていきます デフォルト状態なら ディレクトリは2つです 1つ目は/usr/includeです 2つ目は /System/Library/Frameworksです 1つ目を確認します

    普通のインクルード ディレクトリなので― 検索したい対象を 付けるだけです この場合は Foundation/Faoudation.hです ヘッダはないようですね では2つ目を確認します /System/Library/Frameworksです

    こちらはフレームワーク ディレクトリですから― Clangの挙動が異なります まずフレームワーク名を 特定し― 存在の有無を確認します

    その後 ヘッダディレクトリを 調べに行きます 無事にヘッダが見つかりました もしもヘッダがない場合は? 存在しないヘッダ名で 探させてみます

    ディレクトリ内では 見つかりません

    次はプライベートヘッダの ディレクトリを探しています

    プライベートヘッダは SDKにはありませんが― 他のフレームワークには 含まれる場合があるからです 必ず探しに行きます でも やっぱり 見つかりません

    すると検索が中断されました 延々と 検索するわけではないのです すでにフレームワークが 見つかっているからです 次はフレームワークの ディレクトリで検索します それでも見つからなければ 検索終了です

    ヘッダのインポートと プリプロセスが終わってから― 実装ファイルを見る方法を 紹介します Xcodeで確認します プリプロセス済みの 実装ファイルを出力しましょう

    たくさん表示されました

    どのくらい あるのか?

    分かりやすい例です Foundation.hは― このシステムの 基本的なヘッダです そのため 直接あるいは間接的に― 他のヘッダに インポートされやすいのです コンパイラの呼び出しごとに かなりの確率で参照されます

    すると どうなるか? 一度のインクルードで 約800個ものヘッダファイルを― 処理することになります

    実に9MB以上のソースコードを 解析し検証するのです コンパイラを 呼び出すたびにですよ あまりに冗長な処理です では― 改善策は?

    プリコンパイル済みヘッダも 1つの手です 改善できるでしょう もっといいのは― 数年前に導入した Clang Modulesです

    これを使うと フレームワークごとに― 1度しかヘッダを参照しません ディスク上にキャッシュし 再利用するからです ビルド時間が短縮できます

    これを実現するため― いくつか必要な要素を 開発しました

    中でも重要なのが コンテキストフリーです 詳しく説明します

    これはコードの一部です どちらもPetKitモジュールを インポートします しかし その前の マクロ定義が異なります

    従来のやり方で インポートすると― このまま インクルードされます プリプロセッサは定義どおり ヘッダを処理します そのため ヘッダごとに モジュールが生成され― 再利用できません つまり― 使い回すには 別の方法が必要でした どの実装ファイルにも 再利用できるように― コンテキストに関する情報を 無視させるのです

    他にも 必要だったのが― モジュールの自己完結力です モジュールに依存関係を 記述させるのです 便利な機能ですよね 一度 モジュールを インポートしてしまえば― ヘッダの追加を 意識する必要がなくなります

    モジュールが必要か どうやって判断するのでしょう?

    サンプルで確認します NSString.hです Clangはフレームワーク内で このヘッダを探します

    先ほどと同じです Foundation.frameworkの ディレクトリへ ここでClangが探すのは― モジュールディレクトリの モジュールマップです ひも付き先が ヘッダディレクトリです ありました

    モジュールマップとは? 一連のヘッダファイルが モジュールに変換される過程を― 記述したマップです

    ご覧ください

    モジュールマップは簡単です Foundationのマップは これで全部です

    まずは モジュール名の Foundationです その下に モジュールの ヘッダ名があります これは いつも必ず Foundation.hです 特別なヘッダです これは umbrellaヘッダといいます Clangは このヘッダファイルを参照し― NSString.hがあるかを確認します

    ありましたね NSString.hは Foundationモジュールの一部です Clangは このヘッダを― 言語からモジュール形式に 変換します Foundationモジュールの ビルドが必要ですね

    Foundationモジュールの ビルド方法は? Clangは まず 別の領域を作成します Foundationモジュールの 全ヘッダを収める場所です

    最初のコンパイルで残っている コンテキストを― 変更する必要はありません コンテキストフリーですからね 変更するのは Clangに渡した コマンドライン引数です Clangが持っています

    Foundationモジュールを ビルドしました

    しかし このフレームワークは― 別のフレームワークを インクルードします そのモジュールも ビルドする必要があります

    さらなるインクルードに備え これを繰り返していきます これにはメリットがあります 同様のインポートが ある場合に― 再利用できますよね

    モジュールキャッシュとして ディスク上に格納されます

    先に言ったとおり― コマンドライン引数が Clangに渡されたままです このままでは― モジュールの中身にも 引数が影響してしまいます そのため 引数は ハッシュ化しておきます また 作成したモジュールは ハッシュ値と一致する― ディレクトリに格納します

    異なる制限の ファイルのために― 引数を変更したら? ここではENABLE CATです ハッシュ値が変わります 新たなハッシュ値と一致する ディレクトリに― 全インプットを 再ビルドする必要があります モジュールのキャッシュを 最大限活用したいなら― 引数の変更は できるだけ 避けた方がいいですね

    システムフレームワークの モジュールの話でしたが― 自分のフレームワークで 同じことをするには?

    サンプルのCatで 確認しましょう

    再びヘッダマップを使い― ソースディレクトリへ 行きます

    ここで問題が発覚します モジュールディレクトリが ありません フレームワークらしくないですね Clangも 対処に困ってしまいます 解決手段をご紹介しましょう Clangの 仮想ファイルシステムです 仮想フレームワークを 作成するものです Clangは ここで モジュールを作成します ただし― 対象は自分のディレクトリ内の ファイルだけです Clangが教えてくれるエラーも 自分のソースコードだけでしたね

    以上 自分のフレームワークの モジュールビルド方法でした

    初めに言ったように― フレームワーク名がないと 問題が起こり得ます 失敗例を見てみましょう

    インポートが2つだけの 簡単な例です 1行目は PetKitのモジュールです

    次もモジュールの一部だと 私たちは知っています Clangには判断できません フレームワーク名が ないからです

    この場合 定義の重複による エラーが起こり得ます 主に 同一のヘッダを 再インポートする時です

    Clangは こうしたエラーを 懸命に修復してくれます

    でも すべては無理です 例で見てみます 少しだけ変更しましょう

    コンテキストを変えます モジュールのインポートには 影響しません 先ほど見たとおり コンテキストは無視されます

    でも Cat.hは モジュール化されていないのに― 変更に反応しません これでは 定義の重複以前の問題です 定義の矛盾が 発生してしまいます これは修復不可能です パブリックやプライベートの ヘッダをインポートするなら― 必ずフレームワーク名を 付けましょう 続いて デヴィンが話すのは Swiftと― Clang Modulesの関係です (拍手) ありがとう

    これから ご説明するのは― Swiftとビルドシステムが協力して 宣言を見つける方法です

    ユルゲンの話を 振り返りましょう Objective-Cファイルは 個別にコンパイルされます 別のファイルを探すのに クラスを参照したい場合― クラスを宣言したヘッダを インポートします

    でも Swiftではヘッダを 記述する必要がありません 初めて開発言語を学ぶ人に 親切ですね 別々のファイルで 宣言を繰り返す必要もありません

    ただ コンパイラにとっては 記録管理の手間が増えます どうやって記録するのか 説明します

    PetWallで見てみましょう ViewControllerに view変数を持っています 続いて Objective-Cの AppDelegateと― Swiftのユニットテストです PetViewControllerを コンパイルするだけでも― 4つの処理が必要になります まずは宣言の参照です Swiftのターゲット内と― Objective-Cからも受け取ります

    次に ファイルの内容を記述する インターフェイスを生成します そのインターフェイスの宣言を 今度は― Objective-Cや 別のターゲットが参照します このスライドの 例を使って― 4つのタスクを 説明していきます 初めに ターゲット自身の 宣言を見つけます

    PetViewController.swiftを コンパイルするには― イニシャライザの タイプを調べます 呼び出せるかの確認です しかし その前に PetView.swiftを解析します イニシャライザの宣言が適切か 検証するためです イニシャライザのボディを 確認する必要はありません でも インターフェイス用に 情報は必要です

    つまり 1つのSwiftファイルを コンパイルするために― ターゲットのSwiftファイルを すべて解析するのです インターフェイスとの関連部分を 検証するためです

    Xcode 9では 増分デバッグビルドが― 繰り返し行われていました ファイルを個別に コンパイルしていたからです これは並列処理を 可能にする一方― 各ファイルを何度も 解析する必要があります 1つの実装が .oを生成するごとに― インターフェイスは何度も 宣言を参照します

    Xcode 10では オーバーヘッドが軽減されました ファイルは グループ化され― 可能な限りの処理を 共有します

    しかも並列処理も可能です グループ内で 解析結果を共有すれば― 繰り返し行うのは グループ間の処理のみです 個別コンパイルよりも 処理が少なくて済みます 増分デバッグビルド時間は かなり短縮されました

    Swiftコードが呼び出すのは Swiftコードだけでなく― Objective-Cも呼び出します

    PetWallで確認すると その必要性が分かります システムのフレームワークは Objective-Cだからです

    Swiftは 他の開発言語と違い― 他言語の関数型インターフェイスを 用意する必要がありません

    つまり Objective-CのAPIごとに― Swiftで 宣言を書かずに済みます コンパイラにClangの大部分が 埋め込まれており― ライブラリとして 使用されます 私たちはフレームワークを インポートするだけです

    続いて Objective-Cの宣言です ターゲットのタイプに基づき ヘッダを確認します

    Objective-Cのフレームワークを インポートする場合― インポータが ヘッダの宣言を参照します モジュールマップを 使うのです

    SwiftとObjective-Cが 混在するフレームワークでは― umbrellaヘッダ内で 宣言を見つけます

    パブリックインターフェイスを 定義するヘッダです これでフレームワーク内の Swiftコードが― パブリックのObjective-Cコードを 呼び出せます

    最後にアプリケーションと ユニットテスト内で― ターゲットのブリッジングヘッダに importを付加します これで Swiftから 宣言が呼び出せますね

    さて… インポータが 取り込んだ宣言は― よりSwiftらしい形に 変換されます 例えば NSErrorを使う Objective-Cのメソッドが― throwを使用した Swiftらしい エラー処理になります

    Objective-Cでは タイプ名のパラメータが― 動詞や前置詞の後に続きます 例は drawPetと atPointメソッドです Petという単語があります タイプのパラメータ Petが 動詞drawの後にあります 同じく タイプのパラメータである CGPointのPointも― 前置詞atの後にありますね

    しかし Swiftに インポートされると― 単にdrawとatになります

    その仕組みは 意外に思うかもしれません 英語の動詞と前置詞の リストがあるのです

    しかし 人間の言語は あまりに複雑です リストにない単語もあります そして Swiftの慣例に 合わせるために― インポータは品詞によって 不要な単語を判断しています 例えば feedは 単語リストにありません このため feedPetは 例外的な形に変換されます 任意の名前で インポートさせるには― NS SWIFT NAMEの注釈を 使いましょう

    どうインポートされるのか 確認したい場合には― XcodeのRelated Itemsを 開いてください ソースエディタの 左上にあります Generated Interfaceを 選択してください インターフェイスが Swiftで どう表示されるか確認できます

    これが SwiftがObjective-Cを インポートする場合です では逆に Objective-Cが Swiftをインポートする場合は?

    インポート可能なヘッダを Swiftが生成します つまり Swiftでクラスを記述し― Objective-Cから 呼び出すことが可能です 挙動を見てみましょう

    コンパイラはObjective-Cの 宣言を生成します Swift側のNSObjectと @objcが付いたメソッドを― 拡張するためです

    このヘッダは― パブリックとインターナル両方の 宣言を含んでいます これで インターナルのSwiftを― Objective-Cが使用できます

    ただし フレームワーク用には― ヘッダはパブリックの宣言しか 提供しません これ自体が ビルド結果に含まれる― パブリックインターフェイスの 一部だからです

    さて Objective-Cクラスが ひも付く先は― Swiftクラスの マングル名になっています 一部はモジュールの名前 PetWallです

    モジュールについて 少し説明した後― ルイスが この現象を解説します 同じ名前で定義すると 実行時に競合が発生します それを防ぐための マングル名です

    Objective-Cの attribute に 識別子を持たせれば― 任意の名前を 指定することも可能です ただし 競合が起きないよう 注意してください 私自身はPWLと付けることで 競合を回避しています これでObjective-C側で― PWLPetCollarとして クラスを参照できます

    他のSwiftターゲットが 参照できるように― 同様の手法で インターフェイスを生成します

    Swiftでのビルドは Clangのモジュールと似ています ユルゲンが説明しましたね そして より深く 言語に溶け込みます Swiftのモジュールは 配信可能な宣言の集合です この宣言を 使用可能にするには― モジュールの インポートが必要です この例ではObjective-Cの XCTestをインポートしました XcodeではSwiftのターゲットは 独立したモジュールを作ります アプリケーションもです アプリケーション本体の モジュールも― ユニットテストをするには インポートが必要です

    インポート時 コンパイラは Swiftモジュールを― デシリアライズします タイプを確認するためです この例でも コンパイラは PetWall.swiftmoduleの― PetViewControllerを 読み込みます 整合性を確認するためです コンパイラがターゲット内の 宣言を見つける方法と― 似ていますよね 今回はSwiftファイルを 直接 解析するのではなく― モジュールの要約を 読み込みます

    コンパイラが作る Swiftのモジュールは― Objective-Cのヘッダに よく似ています ただし 言語ではなく バイナリ形式です また インライナブル関数の ボディをインクルードします Objective-Cでの スタティックインライン関数や― C++でのヘッダ内の実装と 似ています 特徴としては― プライベート宣言の名前とタイプも インクルードすることです デバッガで 参照するのに便利です ここで注意です 見られて恥ずかしい 適当な名前を付けないこと

    増分ビルドを行うため ファイルは まず部分ごとに生成され― その後 モジュール全体を表す 1つのファイルになります この時 Objective-Cのヘッダも 1つ生成されます

    似たような働きをするのが リンカーで― オブジェクトファイルを 1つの実行ファイルにします 次は このリンカーを ルイスが解説します ルイス ありがとう (拍手) リンカー担当のルイスです これがビルドの最終段階です さっそく始めましょう

    今から話す内容は こちらです リンカーの役割を説明します 次にインプットとなる ファイルの種類を確認します その一部であるシンボルも 説明します 最後に サンプルを使って 話をまとめます 難解ですからね 最後まで聞けば 分かってくるはずです

    まず リンカーとは何か? ビルドプロセスの 最終段階ですね 2つのコンパイラが 構築した― .oファイルをまとめ上げ 実行可能ファイルにします リンカーはコードを 作ることはできません 重要なポイントなので サンプルで確認します

    インプットファイルは 2種類です .dylibなどは ライブラリの拡張子です オブジェクトファイルは ビルドの過程で生成されましたね ライブラリには いくつか種類があります .dylibや.tbdなどに加え スタティックライブラリもあります

    シンボルとは? コードやデータを 参照するための名前です

    別の関数を呼び出すための 関数を書くと― 他のシンボルを参照する フラグメントも出てきます

    シンボルの特性は リンカーの挙動に大きく影響します ウィークシンボルの例を お話しします ウィークシンボルは 別のシンボル上の注釈です 実行可能ファイルの実行時に そのシンボルが― そこにない方が いいという注釈です これが 可用性の マークアップの正体です 特定のAPIがiOS 12で 使用可能かなどを表します 内容はリンカーに着くまでに 固まっています リンカーはどのシンボルを 付けるべきで― 実行に必要なシンボルは何か 決定できます

    言語もマングリングにより データをエンコードし― シンボルを作ります

    それはC++でもSwiftでも 起こります

    今 言ったように シンボルとは― コードやデータの名前です そして コンパイラが生成する オブジェクトファイルは― コードやデータの集合です コンパイルされただけでは 実行はできません 不完全なのです リンカーが結び付けて 整えていきます

    ファイルの各フラグメントに シンボルが付きます 例えば printf関数も― シンボル付きの コードになります これから見るPetKitの どの関数でも同じことが起きます

    フラグメントが未定義シンボルを 参照する場合もあります 未定義の.oファイルの関数を 参照する場合は― リンカーが未定義シンボルを見つけ リンクします

    .oファイルはコンパイルの アウトプットでしたね では ライブラリは? シンボルを 定義するファイルで― ターゲットの一部では ありません まずは ダイナミックライブラリです これはMach-Oファイルで― 実行可能ファイルが使用する フラグメントが入っています これは 私たちのシステムの一部です 他のフレームワークを 併用している人もいるでしょう

    次にTBDファイル つまり Text Based Dylib Stubsです ここで―

    SDKを開発した時の 話をします MapKitやWebKitといった 機能と共に― ダイナミックライブラリも 開発しました しかし サイズが大きく 全部は組み込めませんでした しかも 実行時にしか 必要ありません そこでシンボルのボディは 省略し― シンボル名だけの スタブを作成したのです その後― 使いやすい言語形式へと 改良しました 現在 TBDの役割は― SDK配信時の サイズ削減だけです プロジェクト内にあっても 気にしないでください シンボルが 入っているだけです 最後は スタティックライブラリです スタティックライブラリには― .oファイルばかりが 入っています arツールやlibtoolで ビルドされたものです arのmanページに従って― arユーティリティが ファイルを作成し 保守しています TARやZIPに似ていますよね それもそのはず .aはUNIXの初期の アーカイブフォーマットです より強力なツールが 登場した時には―

    コンパイラなどは すでに.aに適応していたのです .aはアーカイブファイルです

    特徴としては ダイナミックリンクです 昔は全コードがアーカイブで 配信されていました そのため― C言語のライブラリ全体を インクルードしたくなかったのです 対処はこうです シンボル付きの.oファイルだけ アーカイブから抜き取ります 他のファイルは そのままです 参照は可能で 必要なものは手に入ります シンボルに関係なく動く スタティックイニシャライザなどは 使用や再エクスポートの時に 注意が必要です -force loadや-all loadで 対象に入れてください リンクを行わなくてもです

    では サンプルを使って 復習します

    スライドをご覧ください playSound関数の事例です 音は欠かせませんね

    さて… playSoundを呼び出す関数が Cat内にあります シンプルな例ですね 生成されたアセンブリを 見てみましょう

    Cat.oが生成されました こちらにある purr.aacというのが― 私たちが用意した AACサウンドファイルです Cat.oにもコピーされました でも purrFileという名前は ありませんね 静的だからです C言語を扱う皆さんなら もう お分かりですよね 他者は参照できないものです 必要ありません

    では 次へ これがシンボルです -

    想像どおりでしょう

    その下の変数を 今からplaySoundに渡します 命令が2つ付いています この文字列が 実行可能ファイルの どこに入るか不明だからです 決まった場所はありません このアセンブリ arm64には― コンパイラは最大で 2つの命令を残せます オフセットのPAGEとPAGEOFFが 付いています リンカーが後で補完します こうして 文字列が x0に読み込まれました これで playSoundを呼び出せます ただし その名前は Z9playSoundPKcです これは マングリングで 生成されたシンボルです Cat.mmの記述言語は Objective-C++です しかし playSoundは C++関数なのです 判断できない場合―

    実際にターミナルで ツールを使ってみましょう swift-demangleの後に シンボルを付けて実行します Swiftのシンボルでは ありませんね では C++のデマングラ c++filtではどうでしょう? playSoundのシンボルだと 分かるだけでなく― 引数も分かりました const char *です C++はマングル名に情報も エンコードしているのです

    プロジェクトのビルド時には .oファイルが多数できます これを どうするのか? システムは そのすべてを リンカーに渡します リンカーは受け入れ用の ファイルを作ります PetWallのフレームワーク PetKitをビルドしてみます

    TEXTセグメントを作り コピーしていきます すべてのコードを 保管する場所です まず Cat.oのコピーですが 上下に分かれました 先ほどの文字列と 実行可能コードです 絶対アドレスが分かったので リンカーは参照しに行きます Cat.oを書き換え― 具体的なオフセットにします 2つ目の命令が消えましたね null値の命令に置き換えます リンカーはコードを作ったり 消したりはしません ファイルのサイズが変わるからです だから この場合にも― 何もしない値に 置き換えるだけです 最後にブランチです そう ブランチ しかし…

    未定義シンボルは どうするのでしょう? この時点で.oファイルは 全部インクルード済みです

    スタティックライブラリ PetSupport.aを見てみましょう PetSupport.aの中には― PetSounds.oなど いくつかファイルがあります playSoundのシンボルも あります 取り込みましょう

    PetCare.oは取り込みません 他から参照されるシンボルが 付いていないからです

    取り込んだはいいものの―

    openとあるのは 未定義のシンボルです open$stubはコピーした時に 付いたものです なぜでしょう? openがどこにあるか調べます

    ありました libSystem.tbdファイルです

    これは システムライブラリの一部で― アプリケーションには 含まれません 呼び出せるように 情報を与える必要があります そこで仮の関数を作ります これはテンプレートで― ライブラリから呼び出す どの関数にも適用できます 関数を見てみましょう ポインタから読み込むのですね open$pointerです そこへ飛びます つまり 他のC言語と同様の 関数ポインタが必要です

    DATAセグメントに 作りましょう グローバル変数が入る セグメントです ゼロになっています nullに飛ぶと クラッシュしてしまいます

    LINKEDITを追加します メタデータのセグメントです リンカーツールは ここにOS用の情報を入れます これでダイナミックリンカーが 実行時に補完できます 詳しく知りたい方は― Optimizing App Startup Timeを ご覧ください

    では―

    今日の復習をしましょう ジェイクは ビルドシステムと 依存関係を説明しました ビルドをマルチコアに 最適化できますね

    ユルゲンはClangや― ビルドを最適化する モジュールを紹介しました

    デヴィンはSwiftの モジュールを解説し― 高速処理を実現する新機能を お見せしました そのアウトプットを受けた リンカーが― アプリケーションを 完成させました あとはコード署名をし 必要なものを付け加え― アプリケーションを 配信するだけです そして― こちらはオープンソースです SwiftやClangやllbuildに 興味があれば―

    こちらのURLへ ご参加に感謝します WWDCを楽しめたでしょうか ありがとうございました (拍手)

Developer Footer

  • ビデオ
  • WWDC18
  • Xcodeのビルドプロセスの舞台裏
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • Apple Intelligence
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習とAI
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • Mini Apps Partner Program
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    最新ニュースを読む。
    Apple Developerアプリを入手する。
    Copyright © 2026 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン