Unity將來時:IL2CPP怎麼用?
阿新 • • 發佈:2019-01-07
版本準備
IL2CPP的第二個試用平臺是iOS 64位版。大家都知道蘋果已經發了最後通牒,全新App必須在15年2月1日支援64位CPU,而已經上架的遊戲也必須在15年6月1日更新的時候支援64位。這個64位編譯就是交由IL2CPP完成的。具體到版本是 Unity 4.6.1 p5,Unity4.6.2和Unity 4.6.2 p1。本文後面都使用4.6.2 p1版本來進行演示。
建立專案,加入程式碼
建立一個空的專案,加入兩個cs檔案,一個叫IL2CPPCompatible.cs,另外一個是IL2CPPStudy.cs。前者主要用來測試程式碼在IL2CPP中的相容性,後者用來產生C++程式碼,用來做對比分析。
以下是兩個檔案的詳細內容:
1.cs的類在經過IL2CPP以後如何在CPP檔案中表達
2.C#的IO操作經過IL2CPP以後如何在CPP檔案中表達
3.當呼叫new關鍵字在堆裡產生一個例項的時候CPP檔案又是如何做的
4.開啟一個執行緒的操作IL2CPP會如何翻譯
5.呼叫cc.GetType()的行為IL2CPP如何處理
像Bulk_Generics_x.cpp和System.Collections.Generic有關。
Bulk_UnityEngine.UI_x.cpp則和Unity自帶的UI有關。
讓我們粗略的分析下在CPP檔案中前面的5條都是如何實現的:
1.cs的類在經過IL2CPP以後如何在CPP檔案中表達
我們的CoconutClassStudy類在CPP檔案中變成了一個Struct,繼承於Object_t4。那這個Object_t4又是什麼呢?
聰明的你一看註釋就知道了吧,沒錯,這個就是C#中的萬物之源,System.Object。
既然我們C#的類變成了Struct,那類裡面的函式都去哪裡了呢?帶著這個疑問,我們來看第二條。
2.C#的IO操作經過IL2CPP以後如何在CPP檔案中表達
在CoconutClassStudy類中有一個成員函式:IOTest。在CPP中,我們看到了如下的實現:
類中的函式變成了一般的全域性函式,函式名字是類名加上函式名,最後加上一個字尾而成。而原本C#中的File.Exists和File.Open函式都有了相應的C++實現。
3.當呼叫new關鍵字在堆裡產生一個例項的時候CPP檔案又是如何做的?
C#程式碼中我們在Start函式中有一個顯示的New,找到相應C++程式碼:
可以看到程式碼呼叫了一個叫il2cpp_codegen_object_new的函式。而這個函式最終呼叫了IL2CPP VM中的New函式,分配了屬於GC管理的記憶體。
接下來第四條
4.開啟一個執行緒的操作IL2CPP會如何翻譯
C#中的System.Thread,在C++中是一個Thread_t26相當巨大的結構,在New出了這個結構之後,設定執行緒入口函式,最後呼叫Thread_Start_m47啟動執行緒。這個函式就是對應System.Threading.Thread.Start()
我們看最後一條
5.呼叫cc.GetType()的行為IL2CPP如何處理。找到C++中的對應Start函式:
首先我們看到了對應C#中的Type的C++實現:Type_t28,其次是GetType()這個函式在C++中的實現,最後發現是調到了IL2CPP的VM函式:
在這些C++的實現中,細心的讀者可能會發現他們時時刻刻都在使用MethodInfo和TypeInfo這樣的資訊。這個就是Unity Script專案組提到的Metadata。Metadata指的是非邏輯程式碼,而是函式,結構,變數以及類本省的一些資訊。比如名字,型別等。這個Metadata提供C++程式碼和後臺的IL2CPP VM執行時必要的資訊。
以上5條只是很簡單的例子,大家如果對IL2CPP的轉換感興趣,可以自己寫出想要了解的測試程式碼,然後再對比CPP檔案看其實現。
前方有坑,請小心
新的事物總是伴隨著問題,特別是在軟體行業,Bug是不可避免的。就目前階段而言,IL2CPP還有不少問題。這個就是專案中IL2CPPCompatible.cs存在的意義:做相容性測試。大家在實際的專案中如果遇到了問題,可以在這個檔案中追加測試程式碼。下面的表格把我們遇到的已知問題做一個列舉,供參考。
IL2CPP總結以及我們的建議
IL2CPP是Unity核心進行的很重要的進化之一。就現在來看,好處有以下幾點:
1.執行速度加快,遊戲安裝尺寸減小,記憶體佔用降低
2.除了可以Mono除錯C#之外,我們又多了一種選擇:Native C++ 原始碼級除錯(不知道你們什麼感覺,我對Unity C#除錯頗有意見,經常連不上偵錯程式,而且除錯過程中常常宕機。換成用原生IDE除錯C++程式碼,就爽很多啦)。
3.可以快速的支援新的平臺,當然這點對我們關係不大。
帶來的問題:
1.由於原來由Mono VM的IL程式碼全部變成了CPP,導致專案中多了很多CPP程式碼,編譯時間會顯著增加。
2.IL2CPP還有各種Bug,可能會導致原來的程式碼不能很好的編譯執行。需要等待Unity版本迭代。
3.鑑於C++靜態語言的特性,我們不能使用諸如System.Reflection.Emit這樣的動態程式碼。(C# ATO方式編譯)
給使用Unity開發者的建議:
IL2CPP是大勢所趨,加上蘋果強制使用64位支援,意味著到了6月1號,所有用Unity開發的遊戲都要用到新的編譯方式。如果你的專案比較大,應該立刻開始嘗試IL2CPP,以便發現問題,並開始解決。
本文專案在:
CoconutIslandStudio/IL2CPP_Test · GitHub
前文詳細的介紹了IL2CPP的來龍去脈,這裡用一個實際的例子來看看Unity3D裡的IL2CPP都為我們做了哪些工作以及在使用的過程中會遇到哪些問題。
IL2CPP的第二個試用平臺是iOS 64位版。大家都知道蘋果已經發了最後通牒,全新App必須在15年2月1日支援64位CPU,而已經上架的遊戲也必須在15年6月1日更新的時候支援64位。這個64位編譯就是交由IL2CPP完成的。具體到版本是 Unity 4.6.1 p5,Unity4.6.2和Unity 4.6.2 p1。本文後面都使用4.6.2 p1版本來進行演示。
建立專案,加入程式碼
建立一個空的專案,加入兩個cs檔案,一個叫IL2CPPCompatible.cs,另外一個是IL2CPPStudy.cs。前者主要用來測試程式碼在IL2CPP中的相容性,後者用來產生C++程式碼,用來做對比分析。
以下是兩個檔案的詳細內容:
IL2CPPCompatible.cs
這個檔案中有兩個相容性測試函式。一個函式使用ThreadPool.QueueUserWorkItem啟動一個新的執行緒。另一個則是SSL認證函式:ssl.AuthenticateAsClient (hosturl); 之所以寫這兩個函式是因為上述4.6.x IL2CPP對他們支援的還不是很好,會產生問題,這個我們在後面會詳細講到。
IL2CPPStudy.cs
這個檔案裡面的內容就更簡單了:一個CoconutClassStudy類,裡面有一個建構函式,一個Add函式和一個IOTest函式。另外在MonoBehaviour的Start()中,建立這個類的例項,並呼叫這兩個函式。這個原始碼可以讓我們研究以下幾個方面:using UnityEngine; using System.Collections; using System.IO; using System.Threading; public class CoconutClassStudy { public int inta; public int intb; public int Add() { return inta + intb; } public CoconutClassStudy(int a, int b) { inta = a; intb = b; } public void IOTest(string filename) { if (File.Exists (filename)) { FileStream fs = File.Open(filename, FileMode.Create); fs.Close(); } } public void ThreadTest() { Thread a =new Thread(delegate(object state) { Debug.Log ("Thread Started"); }); a.Start (); } } public class IL2CPPStudy : MonoBehaviour { // Use this for initialization void Start () { Debug.Log (CoconutFuncStudy (10 , 20)); CoconutClassStudy cc = new CoconutClassStudy (50, 60); Debug.Log (cc.Add ()); cc.IOTest("test.txt"); cc.ThreadTest (); Debug.Log (cc.GetType ()); } // Update is called once per frame void Update () { } int CoconutFuncStudy(int a, int b) { return a + b; } }
1.cs的類在經過IL2CPP以後如何在CPP檔案中表達
2.C#的IO操作經過IL2CPP以後如何在CPP檔案中表達
3.當呼叫new關鍵字在堆裡產生一個例項的時候CPP檔案又是如何做的
4.開啟一個執行緒的操作IL2CPP會如何翻譯
5.呼叫cc.GetType()的行為IL2CPP如何處理
有了這連個檔案後我們要做的第一件事情是生成XCode專案:
選擇IL2CPP編譯模組,然後Build,生成XCode專案。
開啟專案,在專案結構中開啟Classes目錄,可以看到多了一個Native的子目錄。
IL2CPP轉換出的所有檔案都在其中。
我們寫的邏輯程式碼,都在Assembly-CSharp.cpp中,除了這個檔案,Native資料夾中還有很多以Bulk開頭的檔案,這些其實是IL2CPP把一些必要C#庫翻譯到CPP形成的檔案。
像Bulk_Generics_x.cpp和System.Collections.Generic有關。
Bulk_UnityEngine.UI_x.cpp則和Unity自帶的UI有關。
讓我們粗略的分析下在CPP檔案中前面的5條都是如何實現的:
1.cs的類在經過IL2CPP以後如何在CPP檔案中表達
我們的CoconutClassStudy類在CPP檔案中變成了一個Struct,繼承於Object_t4。那這個Object_t4又是什麼呢?
聰明的你一看註釋就知道了吧,沒錯,這個就是C#中的萬物之源,System.Object。
既然我們C#的類變成了Struct,那類裡面的函式都去哪裡了呢?帶著這個疑問,我們來看第二條。
2.C#的IO操作經過IL2CPP以後如何在CPP檔案中表達
在CoconutClassStudy類中有一個成員函式:IOTest。在CPP中,我們看到了如下的實現:
類中的函式變成了一般的全域性函式,函式名字是類名加上函式名,最後加上一個字尾而成。而原本C#中的File.Exists和File.Open函式都有了相應的C++實現。
3.當呼叫new關鍵字在堆裡產生一個例項的時候CPP檔案又是如何做的?
C#程式碼中我們在Start函式中有一個顯示的New,找到相應C++程式碼:
可以看到程式碼呼叫了一個叫il2cpp_codegen_object_new的函式。而這個函式最終呼叫了IL2CPP VM中的New函式,分配了屬於GC管理的記憶體。
接下來第四條
4.開啟一個執行緒的操作IL2CPP會如何翻譯
C#中的System.Thread,在C++中是一個Thread_t26相當巨大的結構,在New出了這個結構之後,設定執行緒入口函式,最後呼叫Thread_Start_m47啟動執行緒。這個函式就是對應System.Threading.Thread.Start()
我們看最後一條
5.呼叫cc.GetType()的行為IL2CPP如何處理。找到C++中的對應Start函式:
首先我們看到了對應C#中的Type的C++實現:Type_t28,其次是GetType()這個函式在C++中的實現,最後發現是調到了IL2CPP的VM函式:
在這些C++的實現中,細心的讀者可能會發現他們時時刻刻都在使用MethodInfo和TypeInfo這樣的資訊。這個就是Unity Script專案組提到的Metadata。Metadata指的是非邏輯程式碼,而是函式,結構,變數以及類本省的一些資訊。比如名字,型別等。這個Metadata提供C++程式碼和後臺的IL2CPP VM執行時必要的資訊。
以上5條只是很簡單的例子,大家如果對IL2CPP的轉換感興趣,可以自己寫出想要了解的測試程式碼,然後再對比CPP檔案看其實現。
前方有坑,請小心
新的事物總是伴隨著問題,特別是在軟體行業,Bug是不可避免的。就目前階段而言,IL2CPP還有不少問題。這個就是專案中IL2CPPCompatible.cs存在的意義:做相容性測試。大家在實際的專案中如果遇到了問題,可以在這個檔案中追加測試程式碼。下面的表格把我們遇到的已知問題做一個列舉,供參考。
IL2CPP總結以及我們的建議
IL2CPP是Unity核心進行的很重要的進化之一。就現在來看,好處有以下幾點:
1.執行速度加快,遊戲安裝尺寸減小,記憶體佔用降低
2.除了可以Mono除錯C#之外,我們又多了一種選擇:Native C++ 原始碼級除錯(不知道你們什麼感覺,我對Unity C#除錯頗有意見,經常連不上偵錯程式,而且除錯過程中常常宕機。換成用原生IDE除錯C++程式碼,就爽很多啦)。
3.可以快速的支援新的平臺,當然這點對我們關係不大。
帶來的問題:
1.由於原來由Mono VM的IL程式碼全部變成了CPP,導致專案中多了很多CPP程式碼,編譯時間會顯著增加。
2.IL2CPP還有各種Bug,可能會導致原來的程式碼不能很好的編譯執行。需要等待Unity版本迭代。
3.鑑於C++靜態語言的特性,我們不能使用諸如System.Reflection.Emit這樣的動態程式碼。(C# ATO方式編譯)
給使用Unity開發者的建議:
IL2CPP是大勢所趨,加上蘋果強制使用64位支援,意味著到了6月1號,所有用Unity開發的遊戲都要用到新的編譯方式。如果你的專案比較大,應該立刻開始嘗試IL2CPP,以便發現問題,並開始解決。
本文專案在:
CoconutIslandStudio/IL2CPP_Test · GitHub
歡迎關注IndieACE微信公眾號:IndieAce,可以看到IndieACE定期分享的好內容。
需要轉載IndieACE的文章請與我們私信聯絡。