Version: 2023.1
言語: 日本語
マネージコードストリッピング
Unity エディターでコードを再ロード

Unity リンカー

Unity のビルドプロセスでは、マネージコードを削除するために Unity リンカーというツールを使用します。Unity リンカーは IL Linker のバージョンの 1 つで、Unity で動作するようにカスタマイズされています。カスタムの Unity エンジン特有の部分は、公開されていません。

Unity リンカーは、マネージコードストリッピングとエンジンコードストリッピングの一部の処理の両方を担当します。エンジンコードストリッピングの一部の処理は IL2CPP スクリプトバックエンドを通じて利用できる別のプロセスで、使用されていないエンジン コードを削除します。詳しくは、PlayerSettings.StripEngineCode を参照してください。

Unity リンカーのしくみ

Unity リンカーは、プロジェクト内のすべてのアセンブリを解析します。最初に、ルートタイプ、メソッド、プロパティ、フィールドなどをマークします。例えば、シーン内のゲームオブジェクトに加える MonoBehaviour からの派生クラスはルートタイプです。

次に、Unity リンカーは、マークしたルートを解析して識別し、これらのルートが依存するマネージコードをマークします。この静的解析が完了すると、マークされていない残りのコードは、アプリケーションコードを通るどの実行パスからも到達できなくなり、Unity リンカーはアセンブリからそれを削除します。

Unity リンカーがアセンブリを除去する方法

Unity エディターは、Unity プロジェクトのシーンで使用されるタイプを含むアセンブリのリストを作成し、Unity リンカーに渡します。Unity リンカーはそれらのアセンブリ、それらのアセンブリの参照、link.xml ファイルで宣言されたアセンブリ、AlwaysLinkAssembly 属性を持つアセンブリを処理します。大概、これらのカテゴリに該当しないプロジェクト内のアセンブリは Unity リンカーで処理されず、プレイヤービルドには含まれません。

Unity リンカーが処理する各アセンブリに対し、それはアセンブリの分類 (アセンブリにシーンで使用される型が含まれているかどうか) と、ビルド用に選択した Managed Stripping Level に基づいた一群の規則に従います。

これらの規則の目的のために、アセンブリは以下のように分類されます。

  • .NET Class Library アセンブリ — mscorlib.dll や System.dll などの Mono クラスライブラリと、netstandard.dll などの .NET クラスライブラリファサード (facade) アセンブリが含まれます。
  • Platform SDK アセンブリ — プラットフォーム SDK 固有のマネージアセンブリが含まれます。例えば、ユニバーサル Windows プラットフォーム SDK の一部である windows.winmd アセンブリなど。
  • Unity Engine Module アセンブリ — UnityEngine.Core.dll など、Unity エンジンを構成するマネージアセンブリを含みます。
  • Project assemblies — 以下のようなプロジェクト固有のアセンブリを含みます。

マーキングの規則

Unity でプロジェクトをビルドすると、ビルドプロセスは C# コードを共通中間言語 (Common Intermediate Language、CIL) と呼ばれる .NET バイトコード形式にコンパイルします。Unity は、この CIL バイトコードをアセンブリと呼ばれるファイルに梱包します。プロジェクトで使用するプラグインの .NET Framework ライブラリと C# ライブラリも、CIL バイトコードのアセンブリとして事前にパッケージ化されます。

Unity リンカーが静的解析を行うとき、CIL バイトコードのどの部分をビルドに必要なものとしてマークするかは、決定するための規則に従います。ルートのマーキング規則は、Unity リンカーがビルドで最高位のアセンブリをどのように識別して保存するかを決定します。依存関係のマーキングの規則は、ルートアセンブリが依存するコードを Unity リンカーが識別し、保存する方法を決定します。

Managed Stripping Level プロパティは、Unity リンカーが使用する一群の規則を変更します。以下のセクションでは、Managed Stripping Level プロパティで可能な各設定のマークの規則について説明します。

ルートマーキングの規則

次の表は、Unity リンカーがアセンブリの最高位のタイプを識別する方法を説明したものです。

アセンブリタイプ マーキングの規則
最低限
.NET クラス & Platform SDK と UnityEngine アセンブリ 予防的保存と任意の link.xml ファイルで定義された保存を適用します。 予防的保存と任意の link.xml ファイルで定義された保存を適用します。 link.xml ファイルで定義された保存を適用します。 link.xml ファイルで定義された保存を適用します。
シーンで参照される型を持つアセンブリ アセンブリ内のすべての型とメンバーをマークします。 アセンブリ内のすべての型とメンバーをマークします。 以下をマークします。
[RuntimeInitializeOnLoadMethod] または [Preserve] 属性を持つすべてのメソッド。
•link.xml ファイルで定義される保存。
•プリコンパイル、パッケージ、Unity スクリプト、またはアセンブリ定義アセンブリの MonoBehaviour と ScriptableObject から派生したすべての型。
以下をマークします。
[RuntimeInitializeOnLoadMethod] または [Preserve] 属性を持つすべてのメソッド。
•link.xml ファイルで定義される保存。
•プリコンパイル、パッケージ、Unity スクリプト、またはアセンブリ定義アセンブリの MonoBehaviour と ScriptableObject から派生したすべての型。
その他すべて アセンブリ内のすべての型とメンバーをマークします。 以下をマークします。
•これらの型のすべての public 型と public メンバー。
[RuntimeInitializeOnLoadMethod] または [Preserve] 属性を持つすべてのメソッド。
•link.xml ファイルで定義される保存。
•プリコンパイル、パッケージ、Unity スクリプト、またはアセンブリ定義アセンブリの MonoBehaviour と ScriptableObject から派生したすべての型。
以下をマークします。
•これらの型のすべての public 型と public メンバー。
[RuntimeInitializeOnLoadMethod] または [Preserve] 属性を持つすべてのメソッド。
•link.xml ファイルで定義される保存。
•プリコンパイル、パッケージ、Unity スクリプト、またはアセンブリ定義アセンブリの MonoBehaviour と ScriptableObject から派生したすべての型。
以下をマークします。
[RuntimeInitializeOnLoadMethod] または [Preserve] 属性を持つすべてのメソッド。
•link.xml ファイルで定義される保存。
•プリコンパイル、パッケージ、Unity スクリプト、またはアセンブリ定義アセンブリの MonoBehaviour と ScriptableObject から派生したすべての型。
テスト [UnityTest] 属性を持つメソッド、および NUnit.Framework で定義された属性のアノテーションを持つすべてのメソッドをマークします。

依存性のマーキング規則

Unity リンカーは、アセンブリのルートを特定した後、それらのルートが依存するコードを特定する必要があります。以下の表は、Unity リンカーがアセンブリ内のルート型の依存関係を識別する方法を説明します。

規則のターゲット 各ストリッピングレベルでの動作
最低限
MonoBehaviour Unity リンカーは、型をマークするときに MonoBehavior 型のすべてのメンバをマークします。
ScriptableObject Unity リンカーは、型をマークするときに ScriptableObject 型のすべてのメンバをマークします。
属性 Unity リンカーがアセンブリ、型、またはその他のコードの構造体をマークするときに、それらの構造体のすべての属性もマークします。 Unity リンカーがアセンブリ、型、またはその他のコードの構造体をマークするときに、それらの構造体のすべての属性もマークします。 Unity リンカーがアセンブリ、型、またはその他のコード構造をマークするとき、その属性の型もマークされている場合にのみこれらの構造体の属性もマークします。 Unity リンカーがアセンブリ、型、またはその他のコード構造をマークするとき、その属性の型もマークされている場合にのみこれらの構造体の属性もマークします。
デバッグ用属性 スクリプトのデバッグが有効な場合、Unity リンカーは、たとえ、メンバーを使用するコードパスがない場合にも[DebuggerDisplay] 属性を持つすべてのメンバーをマークします。 スクリプトのデバッグが有効な場合、Unity リンカーは、たとえ、メンバーを使用するコードパスがない場合にも[DebuggerDisplay] 属性を持つすべてのメンバーをマークします。 Unity リンカーは常に、DebuggerDisplayAttribute や DebuggerTypeProxyAttribute などのデバッグ属性を削除します。 Unity リンカーは常に、DebuggerDisplayAttribute や DebuggerTypeProxyAttribute などのデバッグ属性を削除します。
.NET ファサードクラスライブラリ ランタイムに必要ないため、ファサードアセンブリは削除されます。

Link XML 機能タグの除去

Link.xml ファイルは、一般的に使用されていない “features” XML 属性をサポートしています。この例では、mscorlib.dll に埋め込まれた mscorlib.xml ファイルがこの属性を使用していますが、適切であれば、どの link.xml ファイルでも使用することができます。

レベルのストリッピングでは、Unity リンカーは、現在のビルドの設定に基づいて、サポートされていない機能の保持を除外します。

  1. remoting – IL2CPP スクリプティングバックエンドをターゲットにする場合に除去されます。
  2. sre – IL2CPP スクリプティングバックエンドをターゲットにする場合に除去されます。
  3. com – COM をサポートしないプラットフォームをターゲットにする場合は除去されます。

例えば、以下の link.xml ファイルは、COM をサポートするプラットフォーム上で FeatureOne メソッドを保持し、すべてのプラットフォームで FeatureTwo メソッドを保持します。

<linker>

    <assembly fullname="Foo">

        <type fullname="Type1">

            <!--Preserve FeatureOne on platforms that support COM-->

            <method signature="System.Void FeatureOne()" feature="com"/>

            <!--Preserve FeatureTwo on all platforms-->

            <method signature="System.Void FeatureTwo()"/>

        </type>

    </assembly>

</linker>

メソッド本体の編集

ストリッピングレベルを設定すると、Unity リンカーはコードサイズをさらに削減するためにメソッドのボディを編集します。このセクションでは、Unity リンカーがメソッドのボディに対して行う注意すべき編集をまとめています。

Unity リンカーは、.NET クラスライブラリアセンブリのメソッドの本体のみを編集します。メソッド本体編集後は、アセンブリのソースコードとアセンブリ内のコンパイル済みコードが一致しなくなり、デバッグが困難になる場合があります。

以下のリストは、Unity リンカーがメソッド本体を編集するために実行するアクションを説明したものです。

  • アクセスできないブランチを削除 - Unity リンカーは、System.Environment.OSVersion.Platform をチェックして、現在適応するプラットフォーム用のアクセスできない If ステートメントのブロックを削除します。
  • フィールドにのみアクセスするインラインメソッド - Unity リンカーは、フィールドを取得または設定するメソッドへの呼び出しを、フィールドへの直接アクセスに置き換えます。これにより、多くの場合、メソッドを完全に取り除くことが可能になります。Mono バックエンドを使用する場合、Unity リンカーは、フィールドの可視性に基づいて、メソッドの呼び出し元が直接フィールドにアクセスすることが許可されている場合にのみ、この変更を実行します。IL2CPP の場合、可視性のルールは適用されません。そのため、Unity リンカーは適切な場所でこの変更を行います。
  • const 値を返すメソッドをインラインにする - Unity リンカーは const 値のみを返すメソッドの呼び出しをインラインにします。
  • 空の戻り値のない呼び出しを削除 - Unity リンカーは、空で戻り値が void の型を持つメソッドへの呼び出しを削除します。
  • 空のスコープを削除 - Unity リンカーは、Finally ブロックが空の場合、Try/Finally ブロックを削除します。空の呼び出し を削除すると、空の Finally ブロックを作成します。メソッド編集中にこのようなことが起こると、Unity リンカーは Try/Finally ブロック全体を削除します。これが発生する可能性のあるシナリオの 1 つは、コンパイラーが Dispose() を呼び出すために foreach ループの一部として Try/Finally ブロックを生成する場合です。
マネージコードストリッピング
Unity エディターでコードを再ロード