1. 程式人生 > >IL2CPP深入詳解-總覽

IL2CPP深入詳解-總覽

 

導語

該系列將會分為以下幾個部分:
1. 總覽(本文)
2. c++程式碼解析
3. 除錯c++程式碼
4. 方法呼叫(一般方法,虛方法等)
5. 泛型共享
6. 型別與方法的 P/invoke 封裝
7. 垃圾回收
8. 測試框架與使用

什麼是IL2CPP

IL2CPP 是 Unity 自 4.6.1p5版本 提出的一種新的 scripting backend 方式,為Unity提供了更加高效、更加便攜的虛擬機器,IL2CPP分為兩個獨立的部分:

  • AOT(靜態編譯)編譯器
  • 執行時庫

其中AOT編譯器將 IL(由.Net編譯器輸出的中間語言)轉換為C++原始碼,而執行時庫則會提供諸如 垃圾回收、執行緒/檔案獲取(獨立於平臺,與平臺無關)、內部呼叫直接修改託管資料結構的原生程式碼

的服務與抽象。

AOT編譯器

所謂AOT編輯器即 il2cpp.exe
在 Windows 系統中你可以在 Editor\Data\il2cpp 目錄中找到它,
在 OSX 系統中你可以在 Contents/Frameworks/il2cpp/build,即Unity的安裝目錄中找到它。
il2cpp.exe 是由C#編寫的受託管的可執行程式,它接受我們在Unity中通過Mono編譯器生成的託管程式集,並生成指定平臺下的C++程式碼。

IL2CPP的工具鏈如下圖所示:

il2cpp-toolchain

執行時庫

IL2CPP技術的另一部分是執行時庫(libil2cpp),它的存在是為了支援IL2CPP虛擬機器的執行,執行時庫幾乎完全由C++程式碼編寫,並作為一個靜態庫與最終的可執行程式連結。(值得一提的是,IL2CPP技術十分得益於使用了libil2cpp這一更輕便的執行時庫)

你可以通過檢視 libil2cpp 的標頭檔案瞭解其的程式碼構成(Windows 系統下的目錄為Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include,OSX 系統下的目錄為 Contents/Frameworks/il2cpp/libil2cpp),例如你可以在 codegen/il2cpp-codegen.h 檔案中看到 il2cpp.exe 生成C++程式碼的介面以及 執行時庫 的介面。

執行時庫的另一關鍵功能是提供了垃圾回收,這一塊內容將在後續的文章裡再詳細探討。

AOT編譯器是如何執行的

讓我們來看一個例子(該例子執行在 Windows 系統下 Unity 5.0.1版本中)
開啟一個新的工程,將如下指令碼新增至主相機上:

using UnityEngine;

public class HelloWorld : MonoBehaviour 
{
  void Start () 
  {
    Debug.Log("Hello, IL2CPP!")
  }
}

此時我們釋出一個WebGL平臺下的程式,並使用 Process Explorer 工具檢視Unity通過什麼命令列對 il2cpp.exe 進行了呼叫:

"C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe" 
"C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe" 
--copy-level=None 
--enable-generic-sharing 
--enable-unity-event-support 
--output-format=Compact 
--extra-types.file="C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt" 
"C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll" 
"C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll" 
"C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput"

這個命令列看起來又複雜又嚇人,不用擔心,讓我們逐步來解析它,

"C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe"

首先,Unity啟動 mono.exe

"C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe

接著啟動 il2cpp.exe


剩下的命令列則是傳遞給 il2cpp.exe ,而非傳遞給 mono.exe的引數,首先這裡傳遞了5個識別符號給 il2cpp.exe:


–copy-level=None

告訴 il2cpp.exe 不要複製生成的C++程式碼.

–enable-generic-sharing

IL2CPP將會共享泛型以此來減少最終包體的大小。

–enable-unity-event-support

支援通過反射獲取的Unity事件,保證程式碼能夠正確生成。

–output-format=Compact

在生成的C++程式碼中,為類與方法使用更少的字元數來命名,這樣會使得程式碼更難以除錯,因為IL程式碼的命名將會發生改變(筆者注:應該類似於程式碼混淆),但是卻能夠被編譯器更快編譯,因為編譯器所需要解析的字元數變少了。

–extra-types.file=”C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt”

使用預設的 額外型別檔案 ,這個檔案會被加入到你的Unity工程裡,並告知 il2cpp.exe 哪些泛型型別或者陣列型別沒有在IL程式碼中出現,卻會在執行時被建立。


值得注意的是這些命令列也許會在後續的Unity版本中發生變化。最後,讓我們看看剩下的三條命令列。


“C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll”
“C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll”

il2cpp.exe 接受所有應該被轉換的 IL 程式集,在這裡例子中它應該包含我的 MonoBehaviour指令碼Assembly-CSharp.dll 以及 GUI assemblyUnityEngine.UI.dll ,很顯然,上面的命令列裡似乎少了些什麼, 我的指令碼引用了 UnityEngine.dll 和 mscorlib.dll,但是它們卻沒有被包含在上述的命令列中,那麼它們在哪兒呢?事實上,il2cpp.exe 在內部對這些程式集進行了處理,因此在上述的命令列中它們不是必須的,Unity只顯式地需要 根程式集(不被任何程式集引用的程式集)在命令列中被提及。

“C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput”

最後的一個引數表示 il2cpp.exe 的輸出目錄,即 il2cpp.exe 生成程式碼的輸出位置,如果你對此感興趣的話,可以看一看生成目錄下的C++檔案,而這一塊內容我們也會在後續的文章中對其進行詳解。此外,如果你希望瀏覽生成目錄下的程式碼的話,推薦在出包的時候選擇 Development Player 模式,這樣一來將會移除 –output-format=Compact 命令列,使得你的程式碼更具可讀性。

PS:你可以通過改變 Player Settings 中的設定來觀察 Unity 傳遞給 il2cpp.exe 的命令列的差異,例如將
Enable Exceptions 設定為 Full,那麼命令列中就會增加 –emit-null-checks–enable-stacktrace–enable-array-bounds-check 三項.

IL2CPP沒有做的工作

Unity官方並沒有重寫C#的標準庫,因此當你釋出一個Unity工程的時候,即使你選擇了 IL2CPP 的方式來生成你的程式碼,所有在 mscorlib.dll、System.dll 等標準庫中的程式碼都將使用Mono2X的方式來生成。



作者:StalkerME
連結:https://www.jianshu.com/p/7cfcb7b0cfe7
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。