Version: Unity 6.0 (6000.0)
言語 : 日本語
Mono の概要
Introduction to IL2CPP

IL2CPP の概要

IL2CPP (Intermediate Language To C++) スクリプティングバックエンドは、Mono バックエンドの代替品です。IL2CPP は、広範なプラットフォームのアプリケーションに対し、優れたサポートを提供します。IL2CPP バックエンドは、MSIL (Microsoft Intermediate Language) コード (スクリプト内の C# コードなど) を C++ コードに変換し、その C++ コードを使って選択したプラットフォーム用のネイティブのバイナリファイル (.exe、.apk、.xap など) を作成します。

このように、Unity がネイティブバイナリをビルドする際に、ターゲットプラットフォームに合わせてコードをコンパイルすることを、事前 (AOT、Ahead-of-Time) コンパイルと呼びます。一方、Mono のバックエンド は、実行時 (JIT) コンパイルと呼ばれる手法で、コードをランタイムにコンパイルします。

このページには以下の情報が含まれています。

プラットフォームによっては AOT コンパイルをサポートしていないものもあります。そのため、IL2CPP バックエンドはすべてのプラットフォームで動作するわけではありません。その他のプラットフォームは、AOT と IL2CPP をサポートしますが、JIT コンパイルを許可しないため、Mono バックエンドをサポートできません。プラットフォームが両方のバックエンドをサポートできる場合、Mono がデフォルトです。詳細については、スクリプトの制限 を参照してください。

IL2CPP は、さまざまなプラットフォームのパフォーマンスを向上させることができますが、ビルドされたアプリケーションにマシンコードを置く必要があるため、ビルド時間と最終的にビルドされたアプリケーションのサイズの両方が増加します。詳細については、IL2CPP のしくみおよびブログシリーズ An introduction to IL2CPP internals を参照してください

IL2CPP は、Mono スクリプティングバックエンドと同じ方法でマネージコードのデバッグをサポートします。詳細については、Unity での C# コードのデバッグ を参照してください。

IL2CPP を使用してプロジェクトをビルドする

IL2CPP を使ってプロジェクトをビルドするには、Unity のインストール時にバックエンドがインストールされる必要があります。Unity を最初にインストールするときに、必須でないモジュールとして IL2CPP を選択するか、Unity Hub を通じて既存のインストールに IL2CPP のサポートを加えることができます。詳細については、Unity Hub のインストール および Unity エディターへのモジュールの追加 を参照してください。

また、IL2CPP では、C++ コードを生成するために、ターゲットプラットフォームに固有のいくつかのシステムが必要です。つまり、特定のプラットフォームで IL2CPP を使用するには、そのプラットフォームでアプリケーションをビルドする必要があります。例えば、 MacOS をビルドターゲットとして IL2CPP を使用するには、MacOS を使用しているマシンでアプリケーションをビルドする必要があります。個々のプラットフォームの IL2CPP 要件など、デスクトッププラットフォームのシステム要件の詳細については、Unity のシステム要件 のデスクトップのセクションを参照してください。

Unity がアプリケーションのビルドに使用するスクリプティングバックエンドを変更するには、次の 2 つの方法があります。

  • エディターの Player Settings メニューから。以下の手順で、Player Settings メニューからスクリプティングバックエンドを変更します。

    1. Edit > Project Settings に移動します。
    2. Player Settings ボタンをクリックして、Inspector で現在のプラットフォームの Player 設定を開きます。
    3. Other SettingsConfiguration セクションに移動します。
    4. Scripting Backend ドロップダウンをクリックして、IL2CPP を選択します。

    Player Settings メニューは、Build Profiles ウィンドウから開くこともできます。File > Build Profiles を順に選択し、Player Settings タブをクリックしてください。

  • エディターのスクリプティング API を通じて。PlayerSettings.SetScriptingBackend プロパティを使用して、Unity が使用するスクリプティングバックエンドを変更します。

Player 設定の Configuration セクション
Player 設定の Configuration セクション

ビルドプロセスを開始するには、Build Profiles ウィンドウを開き、Build ボタンをクリックします。その後、Unity は C# コードとアセンブリを C++ に変換し、最終的にターゲットプラットフォーム用のバイナリファイルを生成します。

IL2CPP のしくみ

IL2CPP を使用してビルドを開始すると、Unity は自動的に以下の手順を実行します。

  1. Roslyn C# コンパイラーは、アプリケーションの C# コードと必要なすべてのパッケージコードを .NET DLL (マネージアセンブリ) にコンパイルします。
  2. Unity はマネージ バイトコードストリッピング を適用します。この手順により、ビルドされたアプリケーションのサイズを大幅に削減することができます。
  3. IL2CPP バックエンドは、すべてのマネージアセンブリを標準の C++ コードに変換します。
  4. C++ コンパイラーは、生成された C++ コードと IL2CPP のランタイム部分をネイティブのプラットフォームのコンパイラーでコンパイルします。
  5. そのコードをターゲットとするプラットフォームによって、実行ファイルか DLL のいずれかにリンクします。

IL2CPP と Mono 両方とも、スクリプトの属性で制御できる便利なオプションをいくつか提供します。詳細は、プラットフォーム依存のコンパイル を参照してください。

IL2CPP は、Unity が特定のプラットフォーム用にコードを事前にコンパイルすることを可能にします。このプロセスの最後に Unity が生成するバイナリファイルには、ターゲットプラットフォームに必要なマシンコードがすでに含まれていますが、Mono はこのマシンコードをランタイムにコンパイルしなければなりません。AOT コンパイルは、ビルド時間を増加させますが、ターゲットプラットフォームとの互換性を高め、パフォーマンスを向上させることができます。

どちらのスクリプティングバックエンドも、ターゲットとするプラットフォームごとに新規にビルドする必要があります。例えば、Android と iOS の両方のプラットフォームをサポートするためには、アプリケーションを 2 回ビルドし、2 つのバイナリファイルを作成する必要があります。

アセンブリストリッピングステージでは、最終的なバイナリサイズを小さくすることができます。Unity は、最終的にビルドされるアプリケーションが使用しないバイトコードを削除します。

IL2CPP ビルド時間の最適化

IL2CPP を使用するプロジェクトのビルド時間は、Mono を使用する場合よりも大幅に長くなることがあります。しかし、ビルド時間を短縮するためにいくつか工夫できます。

マルウェア対策ソフトのスキャンからプロジェクトを除外する

プロジェクトをビルドする前に、Unity のプロジェクトフォルダーとターゲットのビルドフォルダーをマルウェア対策ソフトのスキャン対象から除外します。

プロジェクトとターゲットビルドフォルダーをソリッドステートドライブ (SSD) に保存する

Solid State Drive (SSD) は以前からあるハードディスクドライブ (HDD) に比べ、より速く読み込み、書き込みを行えます。IL コードを C++ に変換しそれをコンパイルすることは、大量の読み込み、書き込み操作を伴います。ストレージデバイスのスピードが速いと、この処理も高速化されます。

プレイヤー設定で IL2CPP コード生成オプションを変更する

IL2CPP のコード生成方法を変更するには、Player Settings を開き、IL2CPP コード生成オプションを設定します。デフォルトでは、Faster ランタイム オプションが有効になっています。これによって、より多くのマシンコードが生成され、ランタイム時の IL2CPP の影響が軽減されます。ビルド時間を短縮するために、このオプションを Faster (smaller) builds に設定できます。この方法は、バイナリ実行ファイルで生成され、含まれるマシンコードが少ないため、ランタイムのパフォーマンスが低下する可能性がありますが、ビルド時間とバイナリサイズも大幅に削減されます。

Il2CppSetOption を使用したランタイムチェックの有効化

IL2CPP スクリプティングバックエンドを使用すると、il2cpp.exe が C++ コードを生成する方法を制御できます。Il2CppSetOption 属性を使用して、以下のランタイムチェックを有効または無効にすることができます。

プロパティ 説明: デフォルト
Null checks このオプションを有効にすると、IL2CPP が生成する C++ コードには null チェックが加えられ、必要に応じてマネージ NullReferenceException 例外がスローされます。このオプションを無効にすると、IL2CPP は生成される C++ コードに null チェックを生成しません。プロジェクトによっては、このオプションを無効にすることでランタイムパフォーマンスが向上する場合があります。

この設定が無効になっていると、Unity は生成されたコード内の null 値へのアクセス試行を防止しないため、誤動作が引き起こされる可能性があります。null 値を参照解除すると、その直後にアプリケーショがクラッシュする可能性があります。Unityでは、このオプションを無効にしないことを推奨します。
有効
Array bounds checks このオプションを有効にすると、IL2CPP が生成する C++ コードには配列の境界チェックが加えられ、必要に応じてマネージ IndexOutOfRangeException 例外がスローされます。このオプションを無効にすると、IL2CPP は生成される C++ コードに配列の境界チェックを生成しません。

プロジェクトによっては、このオプションを無効にすることでランタイムパフォーマンスが向上する場合があります。ただし、このオプションを無効にすると、生成されたコード内で無効なインデックスを持つ配列にアクセスしようとする試みが阻止されないため、任意のメモリ位置からの読み取りまたは任意のメモリへの書き込みなど、不正な動作が発生する可能性があります。ほとんどの場合、このようなメモリアクセスは直ちに悪影響を生じることなく発生し、明らかな警告がないままアプリケーションの状態を破壊することがあります。このため、これらのエラーのデバッグは非常に困難になります。Unityでは、このオプションを有効にしておくことを推奨します。
有効
Divide by zero checks このオプションを有効にすると、IL2CPP によって生成される C++ コードには、整数のゼロ除算チェックが加えられ、必要に応じて管理された DivideByZeroException 例外を投げます。このオプションを無効にすると、IL2CPP は生成される C++ コードに整数のゼロ除算チェックを加えません。

これらのチェックは、ランタイム時のパフォーマンスに影響を与えます。このオプションは、ゼロ除算チェックを実行する必要がある場合にのみ有効にし、そうでない場合は無効のままにしてください。
Disabled

Il2CppSetOption 属性を使用する手順は以下の通りです。

  1. Unity バージョンがインストールされているディレクトリで、Windows の場合は Data\il2cpp ディレクトリ、OS X の場合は Contents/Frameworks/il2cpp ディレクトリに移動してください。
  2. Il2CppSetOptionAttribute.cs のソースファイルを探します。
  3. ソースファイルをプロジェクトの Assets ディレクトリにコピーします。

以下の例では、Il2CppSetOption 属性の使い方を説明します。

[Il2CppSetOption(Option.NullChecks, false)]
public static string MethodWithNullChecksDisabled()
{
    var tmp = new object();
    return tmp.ToString();
}

Il2CppSetOption 属性を、アセンブリ、型、メソッド、プロパティに適用できます。Unity はもっともローカルなスコープから属性を使用します。

[Il2CppSetOption(Option.NullChecks, false)]
public class TypeWithNullChecksDisabled
{
    public static string AnyMethod()
    {
        // Unity doesn’t perform null checks in this method.
        var tmp = new object();
        return tmp.ToString();
    }

    [Il2CppSetOption(Option.NullChecks, true)]
    public static string MethodWithNullChecksEnabled()
    {
        // Unity performs null checks in this method.
        var tmp = new object();
        return tmp.ToString();
    }
}

public class SomeType
{
    [Il2CppSetOption(Option.NullChecks, false)]
    public string PropertyWithNullChecksDisabled
    {
        get
        {
            // Unity doesn’t perform null checks here.
            var tmp = new object();
            return tmp.ToString();
        }
        set
        {
            // Unity doesn’t perform null checks here.
            value.ToString();
        }
    }

    public string PropertyWithNullChecksDisabledOnGetterOnly
    {
        [Il2CppSetOption(Option.NullChecks, false)]
        get
        {
            // Unity doesn’t perform null checks here.
            var tmp = new object();
            return tmp.ToString();
        }
        set
        {
            // Unity performs null checks here.
            value.ToString();
        }
    }
}

追加リソース

Mono の概要
Introduction to IL2CPP