Open6

Unity でプリプロセッサを使わずビルド環境を分ける方法

sukemoritechsukemoritech
#if DEVELOPMENT_BUILD
    // ...
#endif

これをやるとリファクタリングがし辛くなってしゃあない。
けど変数で分岐するといらんコードが入ってしまう…。
どうすればいい?

sukemoritechsukemoritech

JIT 環境ではコンパイラが賢くコードストリップをしてくれるおかげで、変数によるプラットフォーム分岐ができるようだ。

https://ikorin2.hatenablog.jp/entry/2020/06/27/065646

たしかに、コンパイル結果をみてみると IL では残っている分岐が JIT Asm ではなくなっている。

https://sharplab.io/#v2:C4LghgzgtgPgAgJgIwFgBQ64GYAEicCCEEAplAEYA2AngMrBjAnoDe6OHeucSAbDuQD2gyjgCSEACIlyAVwDm7TmzQBiAJYAzHJICiAIQCqAcSWdO8ksBws8AdhzAATrJIBuHAF90qkpVJm5jiW1rZwDppg/u5ePiQAdgAmWoHeaGmY3Ah4SHasgdh4ACw4AGLCABQAlIEqQZxaOBVEpBQ09IwkAHQS0nLyNWj1HHXD5jwAnBUARAAqABbqEDhLOjIKXdNVboHmaWN+AUPDo2MckzMLq6sASn4kkN1bO8f1+5xpaUA==

ん、でも IL2CPP ってたしか AOT だったよな…。

sukemoritechsukemoritech

今後は Mono については考えずに IL2CPP を前提とする。(たぶんもう使わない)

https://docs.unity3d.com/ja/2021.1/Manual/IL2CPP-HowItWorks.html

IL2CPP ではこんな感じでコンパイルが進んでいく。
Unity の Stripping Level は Managed code stripping についての設定。

https://docs.unity3d.com/ja/2022.3/Manual/ManagedCodeStripping.html

Managed code stripping について調べた。

  • 最初にいくつかのクラスやメソッドをマーキングする
  • 静的解析を行いマーキングした個所から辿っていってさらにマーキングを進める
  • マーキングされていない部分を削除する

ストリップのレベルを選択することで、最初のマーキングやほかのクラスを辿っていくときのやり方を選ぶことができる。

リフレクションを使っていたりバックエンドから呼び出すコードはマーキングから外れてしまうので、手動でマーキングする必要がある。
属性を記述したり link.xml に追加したりすることで手動でマーキングすることができる。


さて、読んでみてわかったけど、クラスとかメソッドとかそういう単位でのストリップはしてくれるみたいだけど、どうやら「不要な分岐の削除」はここではやってくれないみたいだ。
たしかに、JIT 環境でも IL の段階では残っていたわけだから、そりゃそうか…。
ということは頼れるのは C++ コードになった後の C++ コンパイラということになるけど、ここはプラットフォーム依存らしくて、どうしたらいいのか…?

sukemoritechsukemoritech

Android 環境でビルドを行い apk の中身をのぞいてみた。

https://github.com/Perfare/Il2CppDumper

上記のツールで apk の中の libil2cpp.so と global-metadata.dat を展開してみる。

const で分岐

cpp の段階で不要な分岐は削除されていた。

readonly static で分岐

不要な分岐は残っていた。

getter で分岐

不要な分岐は残っていた。

あれ…。期待していたのと違うなぁ…。
もっと激しく最適化してもらうためには、なにかオプションの設定がいるのだろうか。

sukemoritechsukemoritech

試しに Mono でビルドしてみて、dnSpy で Assembly-CSharp の中身をのぞいてみたら、普通に分岐残ってたぞ…?どういうこと…?

SharpLab の JIT コンパイラとは別物ってこと?