用Unity作游戏,你须要深刻了解一下IL2CPP

http://youxiputao.com/articles/5064web

[ 转载自 IndieACE ]

wKiom1ZBQb_jBxyBAAHO_gIdGiQ935.jpg

                

此次咱们翻译了一篇Unity官方博客上的文章,原文题目为AN INTRODUCTION TO IL2CPP INTERNALS ,做者是从事Unity软件开发的Joshua Peterson。文章的看点在于,它是以IL2CPP内部开发人员的角度来说述的。后端

AN INTRODUCTION TO IL2CPP INTERNALS (做者:Joshua Peterson 翻译:Bowie)数组

大约在一年之前,咱们写了一篇博客讨论Unity中脚本未来会是个什么样子,在那篇博客中咱们提到了崭新的IL2CPP后端,并许诺其会为Unity带来更高效和更适合于各个平台的虚拟机。在2015年的一月份,咱们正式发布了第一个使用IL2CPP的平台:iOS 64-bit。而随着Unity 5的发布,又带给你们另外一个使用IL2CPP的平台:WebGL。感谢咱们社区中用户的大量宝贵的反馈,咱们在接下来的时间里根据这些反馈得以更新IL2CPP,发布补丁版本,从而持续的改进IL2CPP的编译器和运行时库。框架

咱们没有中止改进IL2CPP的打算,可是在目前这个时间点上,咱们以为能够回过头来抽出点时间告诉你们一些IL2CPP的内部工做机制。在接下来的几个月的时间里,咱们打算对如下话题(或者还有其余未列出的话题)进行讨论,来作一个IL2CPP深刻讲解系列。目前准备讨论的话题有:ide

1.基础 - 工具链和命令行参数(本篇博文)工具

2.IL2CPP生成代码介绍测试

3.IL2CPP生成代码调试小窍门webgl

4.方法调用介绍(通常方法调用和虚方法调用等)ui

5. 通用代码共享的实现spa

6.P/invoke(Platform Invocation Service)对于类型(types)和方法(methods)的封装

7.垃圾回收器的集成

8.测试框架(Testing frameworks)及其使用

为了能让这个系列的讨论成为可能,咱们会涉及到一些未来确定会进行改动的IL2CPP的实现细节。但这也没有关系,经过这些讨论,咱们但愿能给你们提供一些有用和有趣的信息。

什么是IL2CPP?

从技术层面上来讲,咱们说的IL2CPP包含了两部分:一个进行 预先编译(译注:ahead-of-time,又叫AOT,如下一概使用AOT缩写)的编译器。

一个支持虚拟机的运行时库

AOT编译器将由.NET 输出的中间语言(IL)代码生成为C++代码。运行时库则提供诸如垃圾回收,与平台无关的线程,IO以及内部调用(C++原生代码直接访问托管代码结构)这样的服务和抽象层。

AOT编译器

IL2CPP AOT编译器实际的执行文件是il2cpp.exe。在Windows平台你能够在Unity安装路径的Editor\Data\il2cpp目录下找到。对于OSX平台,它位于Unity安装路径的Contents/Frameworks/il2cpp/build目录内。 il2cpp.exe这个工具是一个托管代码可执行文件,其彻底由C#写成。在开发IL2CPP的过程当中,咱们同时使用.NET和Mono编译器对其进行编译。

il2cpp 接受来自Unity自带的或者由Mono编译器产生的托管程序集,将这些程序集转换成C++代码。这些转换出的C++代码最终由部署目标平台上的C++编译器进行编译。

你能够参照下图理解IL2CPP工具链的做用:

wKiom1ZBQcDgJqkVAAB9T2sttHo131.png

运行时库

IL2CPP的另一个部分就是对虚拟机提供支持的运行时库。咱们基本上是用C++代码来实现整个运行时库的(好吧,其实里面仍是有一些和平台相关的代码使用了程序集,这个只要你知我知便好,不要告诉别人 )。咱们把运行时库称之为libli2cpp,它是做为一个静态库被链接到最终的游戏可执行文件中。这么作的一个主要的好处是可使得整个IL2CPP技术是简单而且是可移植的。

你能经过查看随Unity一块儿发布的libil2cpp头文件来窥探其代码组织方式(Windows平台,头文件在Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include目录中。OSX平台,头文件在Contents/Frameworks/il2cpp/libil2cpp目录中)。举个例子,由il2cpp产生的C++代码和libil2cpp之间的接口API,存在于codegen/il2cpp-codegen.h这个文件中。

运行时的另一个重要的部分,就是垃圾收集器。在Unity 5中,咱们使用libgc垃圾收集器。它是一个典型的贝姆垃圾收集器(Boehm-Demers-Weiser garbage collector)。(译注:相对使用保守垃圾回收策略)。然而咱们的libil2cpp被设计成能够方便使用其余垃圾回收器。所以咱们如今也在研究集成微软开源的垃圾回收器(Microsoft GC)。对于垃圾回收器这一点,咱们会在后续的一篇中专门的讨论,这里就很少说了。

il2cpp是如何执行的?

让咱们从一个简单的例子入手。这里使用Unity的版本是5.0.1,在Windows环境而且创建一个全新的空项目。而后建立一个带MonoBehaviour的脚本文件,将其做为组件加入到Main Camera上。代码也是很是的简单,输出Hello World:

using UnityEngine;

public class HelloWorld : MonoBehaviour {

 void Start () {

   Debug.Log("Hello, IL2CPP!");

 }

}

当我切换到WebGL平台进行项目生成的时候,咱们能够用Process Explorer来对il2cpp的命令行进行观察,获得如下内容:

"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。上面的例子里传递了5个参数给il2cpp.exe:

–copy-level=None

指明il2cpp.exe不对生成的C++文件进行copy操做

告诉IL2CPP若是能够,对通用方法进行共享。这个能够减小代码并下降最后二进制文件的尺寸,确保和Unity events相关的,经过反射机制来运做的代码,可以正确生成。

在生成C++代码时为里面的类型和方法使用更短的名字。这会使得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程序集组成的列表。在上面这个例子中,程序集包含了项目中的简单脚本程序集:Assembly-CSharp.dll,和GUI程序集:UnityEngine.UI.dll。你们可能会注意到这里面明显少了什么:UnityEngine.dll到哪去了?系统底层的mscorlib.dll也不见了踪迹。实际上,il2cpp.exe会在内部自动引用这些程序集。你固然也能够把这些放入列表中,但他们不是必须的。你只须要说起那些根程序集(那些没有被其余任何程序集引用到的程序集),剩下的il2cpp.exe会根据引用关系自动加入。

裹脚布的最后一块是一个目录,il2cpp.exe会将最终的C++代码生成到这里。若是你还保持着一颗好奇的心,能够看看这个目录中产生的文件。这些文件是咱们下一个讨论的主题。在你审视这些代码前,能够考虑将WebGL构建设置中的“Development Player”选项勾上。这么作会移除–output-format=Compact命令行参数从而让C++代码中的类型和方法的名字更加可读。

尝试在WebGL或者iOS构建设置中进行些改变。这样你会发现传递给il2cpp.exe的参数也会相应的发生变化。例如,将“Enable Exceptions” 设置成“Full” 会将–emit-null-checks,–enable-stacktrace,和 –enable-array-bounds-check这三个参数加入il2cpp.exe命令行。

IL2CPP没作的事情

我想指出IL2CPP有一贯挑战咱们没有接受,并且咱们也高兴咱们忽略了它。咱们没有尝试重写整个C#标准库。当你使用IL2CPP后端构建Unity项目的时候,全部在mscorlib.dll,System.dll等中的C#标准库和原来使用Mono编译时候的如出一辙。

咱们能够依赖健壮的且久经考验的C#标准库,因此当处理有关IL2CPP的bug的时候,咱们能够很确定的说问题出在AOT编译器或者运行时库这两个地方而不是在其余地方。

咱们如何开发,测试,发布IL2CPP

自从咱们在一月份的4.6.1 p5版本中首次引入IL2CPP以来,咱们已经连续发布了6个Unity版本和7个补丁(Unity版本号跨越4.6和5.0)。在这些发布中咱们修正了超过100个bug。

为了确保持续的改进得以实施,咱们内部只保留一份最新的开发代码在主干分之(trunk branch)上,在发布各个版本以前,咱们会将IL2CPP的改动挂到一个特定的分之下,而后进行测试,确保全部的bug已经正确的修正了。咱们的QA和维护工做组为此付出了惊人的努力才得以保证发布版本的快速迭代。(译注:感受是版本管理的标准的开发流程,另外由文中提到的trunk branch来看,他们貌似还在使用SVN)

提供高质量Bug的用户社区被证实是一个无价之宝。咱们很是感谢用户的反馈来帮助咱们改进IL2CPP,而且但愿这类反馈越多越好。

咱们的IL2CPP研发组有很强烈的“测试优先”意识。咱们时常使用“Test Driven Design”方法,在没有进行足够全面的测试的状况下,几乎不会进行代码的合并工做。这个策略用在IL2CPP项目上很是的棒。咱们如今所面对的大部分bug并非意想不到的行为产生的,而是由意想不到的特殊状况产生的。(例如在一个32位的索引数组中使用了64位的指针从而致使C++编译器失败)面对这种类型的bug咱们能够快速的而且很自信的进行修正。

有了社区的帮助,咱们很是努力的让IL2CPP既快又稳定。顺便说一句,若是你对我刚才说的这些有兴趣,咱们正在招人(嗯.....我只是这么一说)

好戏连台

关于IL2CPP咱们还有不少能够说的。下一次咱们会深刻到il2cpp.exe代码生成的细节中。看看对于C++编译器来讲,由il2cpp.exe生成的代码会是个什么样子。

相关文章
相关标签/搜索