1. 程式人生 > >(七)Unity5.0新特性------介紹IL2CPP內部構建

(七)Unity5.0新特性------介紹IL2CPP內部構建



孫廣東  2015.5.20

介紹IL2CPP內部構建

將近一年以前的事了,Unity開始談論未來在Unity中的指令碼。新的 IL2CPP 指令碼後端答應(highly-portable)給Unity帶來了高效能、 高行動式虛擬機器。今年 1 月,Unity使用 IL2CPP,嘗試的第一平臺是iOS 64-bit。Unity5 釋出帶來了另一種平臺:WebGL。由於從我們擁有的強大的社群,使用者的輸入,我們已經為 IL2CPP發運許多版本更新修補程式,穩步提高其編譯和執行時。

我們沒有計劃去制止提高 IL2CPP,但我們認為它可能是一個好的主意,後退一步來講,並告訴你一點關於 IL2CPP 從內到外的工作。在接下來的幾個月,UNity打算寫關於以下主題 (和也許還有其他人) 在這個 IL2CPP Internals 系列的帖子:
1.The basics – toolchain and command line arguments (this post)
2.A tour of generated code
3.Debugging tips for generated code
4.Method calls (normal methods, virtual methods, etc.)
5.Generic sharing implementation
6.P/invoke wrappers for types and methods
7.Garbage collection integration
8.Testing frameworks and usage

為了使這一系列的文章變成可能,我們要討論一些有關 IL2CPP的實現細節 ,肯定會在將來改變。希望我們還可以提供一些有用的、 有趣的資訊。

IL2CPP 是什麼?
IL2CPP 的技術有兩個截然不同的部分。
· An ahead-of-time (AOT) compiler
· A runtime library to support the virtual machine

AOT 編譯器將為中間語言 (IL),對 c++ 原始碼從.NET 編譯器輸出低電平。執行時庫提供服務和抽象機制,比如垃圾收集器GC,對執行緒和檔案和內部呼叫 (本機程式碼直接修改託管的資料結構) 的實現獨立於平臺的訪問。

AOT 編譯器:
IL2CPP AOT 編譯器被命名為 il2cpp.exe。在 Windows 上,你可以找到它在 Editor\Data\il2cpp 目錄中。在 OSX 上正是在Unity安裝的Contents/Frameworks/il2cpp/build目錄。Il2cpp.exe 實用程式是託管可執行檔案,完全用 C# 寫成。在Unity的 IL2CPP 的發展過程中使用.NET 和Mono編譯器編譯它。

Il2cpp.exe 實用程式接受託管程式集被Mono編譯,附帶Unity並生成 c + + 程式碼,我們將傳遞給特定於平臺的 c ++ 的編譯器編譯的。

你可以想想這樣的 IL2CPP 工具鏈:


執行時庫:
IL2CPP 技術的另一部分是一個執行時庫來支援虛擬機器。我們已幾乎完全使用 c++ 程式碼 (它有一點點的平臺特定的程式集的程式碼,但讓我們記住這兩個我們之間) 此庫。我們呼叫執行時庫 libil2cpp,和它運作為靜態庫連結到可執行檔案的player。IL2CPP 技術的主要優點之一就是這簡單的和行動式的執行時庫。

你可以找到一些關於 libil2cpp 程式碼如何組織的,看 libil2cpp 的標頭檔案的線索(你會發現他們在 Windows 上的 Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include 目錄或上 OSX 的Contents/Frameworks/il2cpp/libil2cpp 目錄中)。例如,由 il2cpp.exe 和 libil2cpp 執行時生成的 c++ 程式碼之間的介面位於程式碼codegen/il2cpp-codegen.h 標頭檔案。

執行時的一個關鍵部分是垃圾回收器GC。我們這裡工作在Unity5 與 libgc,Boehm-Demers-Weiser垃圾回收器。然而,libil2cpp 旨在允許我們使用其他的垃圾收集器。例如,我們正在研究整合微軟 GC 是開源作為 CoreCLR 的一部分。我們會有更多要說,在我們關於垃圾回收器整合在本系列的文章稍後介紹。

Il2cpp.exe 是如何執行的?
Let’s take a look at an example. I’ll be using Unity 5.0.1 on Windows, and I’ll start with a new, empty project. So that we have at least one user script to convert, I’ll add this simple MonoBehaviour component to the Main Camera game object:
讓我們看看一個例子。我會在 Windows 上,使用 Unity 5.0.1,將從一個新的空專案中入手。所以,我們有至少一個使用者指令碼,我將新增到Main Camera遊戲物體,就是如下的這個簡單的 MonoBehaviour 元件:
using UnityEngine;
public class HelloWorld : MonoBehaviour {
  void Start () {
    Debug.Log("Hello, IL2CPP!");
  }
}

當我build WebGL 平臺時,我可以使用程序資源管理器中看到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"


該命令列是相當長而可怕,所以讓我們開啟它。首先,Unity執行此可執行檔案:
"C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe"

然後在命令列上的下一個引數是 il2cpp.exe 實用程式本身。
"C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe"

其餘的命令列引數傳遞給 il2cpp.exe,不是 mono.exe。讓我們看看他們。首先,Unity將傳遞給 il2cpp.exe 的五個標記:
· –copy-level=None
 · 指定該 il2cpp.exe 不應執行生成的 c + + 程式碼的特殊檔案副本。
· –enable-generic-sharing
 · 這是一個程式碼和二進位制大小縮減功能。IL2CPP 將分享泛型方法的執行時,它可以。
· –enable-unity-event-support
 · 特別的支援,以確保Unity事件,均可以通過反射訪問,該程式碼正確生成。
· –output-format=Compact
 · 需要較少的字元的型別和方法名稱的格式生成 c + + 程式碼。這段程式碼很難除錯,因為 IL 程式碼中的名稱不保留的但是它經常編譯速度更快,因為 c + + 編譯器可以解析的程式碼更少。
· –extra-types.file=”C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt”
 · 使用預設值 (和空) 額外型別檔案。Il2cpp.exe 知道哪個泛型或陣列型別將建立在執行時,但不是存在於 IL 程式碼,可以將此檔案新增在一個Unity的專案。

它是重要的是要注意這些命令列引數可以將在以後的版本中更改。我們不是一個點還在那裡,我們有一套穩定和支援的 il2cpp.exe 的命令列引數。

最後,我們有兩個檔案和一個目錄的列表,在命令列上:
· “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”

Il2cpp.exe 實用程式接受所有它應該轉換的 IL 程式集的列表。在這種情況下,他們是我簡單的MonoBehaviour, Assembly-CSharp.dll, and the GUI assembly, UnityEngine.UI.dll。請注意有幾個顯眼的assembles在這裡缺少。很顯然,我的指令碼引用 UnityEngine.dll,並引用至少 mscorlib.dll 中和可能的其他程式集。他們在哪裡?實際上,il2cpp.exe 內部解析這些程式集。他們可以在命令列上被提及,但它們並非必要。Unity只需要明確提及的根程式集 (其中那些未引用的任何其他程式集)。

Il2cpp.exe 命令列上的最後一個引數是在其中建立輸出 c + + 檔案的目錄。如果你是好奇,看看該目錄中生成的檔案,他們將在本系列的下一篇文章的主題中介紹。你之前就知道雖然你可能想要選擇的 WebGL 的“Development Player”選項生成設定。這將刪除 –output-format=Compact 的命令列引數,並且給你更好的型別和方法名稱生成的 c + + 程式碼中。

請嘗試更改 WebGL 或 iOS Player Settings中的各種選項。你應該能夠看到不同的命令列選項傳遞給 il2cpp.exe,使不同的程式碼生成步驟。例如,更改 WebGL Player Settings中的“Enable Exceptions”設定為“Full”值,新增–emit-null-checks, –enable-stacktrace, and –enable-array-bounds-check到 il2cpp.exe 命令列引數。

IL2CPP 不做什麼?
我想指出,我們不嘗試重寫 C# 標準庫與 IL2CPP。當你建立一個Unity的專案,使用 IL2CPP 指令碼後端時,C# 標準庫中的所有程式碼 mscorlib.dll 中 System.dll,等是完全相同的程式碼用於Mono的指令碼後端。

我們依賴已經是知名的使用者和久經時間考驗Unity專案中的 C# 標準庫程式碼。所以當我們調查有關 IL2CPP 的 bug,我們可以是相當自信的 bug 是在 AOT 編譯器或執行時庫,和其它地方。


我們如何開發、 測試和運送 IL2CPP
在一月份首次公開發行的 IL2CPP 版本 4.6.1p5 以來,我們已經發運 6 個完整的版本和 7 補丁程式版本 (跨版本 4.6 和 5.0 的統一)。我們已經糾正了在發行說明中提到的超過 100 個 bug。

為了讓持續改進發生,我們內部,針對只有一個版本的 IL2CPP 程式碼開發中統一用於ship alpha 和 beta 版本的樹幹分支。只是之前每個版本,我們埠 IL2CPP 更改為特定的釋出分支,執行我們的測試,並驗證所有我們固定的 bug 在該版本中更正。我們的質量保證和持續的工程團隊做了令人難以置信的工作使交貨以這種速度成為可能。這意味著我們的使用者永遠不會超過大約一個星期從最新修補程式 IL2CPP 的 bug。

我們使用者社群已被證明非常寶貴,提交了許多高質量 bug 報告。我們從我們的使用者,以幫助不斷改進 IL2CPP,感謝所有的反饋,我們期待著更多。


More to come:
下一次,我們將深入由 il2cpp.exe,看看您的專案實際上什麼樣子 c + + 編譯器生成的程式碼。