ConstFieldRemover

DLLやexeに含まれるILからconstフィールドを取り除くツール

説明

クラスのフィールドにconstを使ったコードをビルドしてDLLを生成する。

using System;

namespace TestDLL
{
    public class Test
    {
        const string text = "hogehoge";
        public void Test1()
        {
            Console.WriteLine(text);
        }
        public void Test2()
        {
            Console.WriteLine(text);
        }
    }
}

生成されたDLLをildasmでILをダンプするとliteralフィールドが含まれる。

.class public auto ansi beforefieldinit TestDLL.Test
       extends [System.Runtime]System.Object
{
  .field private static literal string text = "hogehoge"
  .method public hidebysig instance void 
          Test1() cil managed
  {
    // コード サイズ       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "hogehoge"
    IL_0006:  call       void [System.Console]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method Test::Test1

  .method public hidebysig instance void 
          Test2() cil managed
  {
    // コード サイズ       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "hogehoge"
    IL_0006:  call       void [System.Console]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method Test::Test2

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // コード サイズ       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [System.Runtime]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Test::.ctor

} // end of class TestDLL.Test

DLLからconstフィールドを取り除く。

> ConstFieldRemover.exe TestDLL.dll -o TestDLL_fix.DLL

変換後のDLLのILダンプからはliteralフィールドが取り除かれる。 取り除かれたliteralフィールドの分だけDLLのサイズが削減できる。

.class public auto ansi beforefieldinit TestDLL.Test
       extends [System.Runtime]System.Object
{
  .method public hidebysig instance void 
          Test1() cil managed
  {
    // コード サイズ       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "hogehoge"
    IL_0006:  call       void [System.Console]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method Test::Test1

  .method public hidebysig instance void 
          Test2() cil managed
  {
    // コード サイズ       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "hogehoge"
    IL_0006:  call       void [System.Console]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method Test::Test2

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // コード サイズ       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [System.Runtime]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Test::.ctor

} // end of class TestDLL.Test

UnityのIL2CPPビルドで使用する

IL2CPPの前処理として呼び出される IIl2CppProcessor.OnBeforeConvertRun でconstフィールドを取り除いてビルドをする。 https://docs.unity3d.com/ScriptReference/Build.IIl2CppProcessor.OnBeforeConvertRun.html

using UnityEngine;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.Il2Cpp;
using UnityEditor;

public class PreIL2CPP : IIl2CppProcessor
{
    public int callbackOrder => 0;

    public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
    {
        string dllPath = data.inputDirectory + "/Assembly-CSharp.dll";
        if (System.IO.File.Exists(dllPath))
        {
            var proc = System.Diagnostics.Process.Start("ConstFieldRemover.exe", dllPath);
            proc.WaitForExit();
            Debug.Log(proc.ExitCode);
        }
    }
}