Unity 构建过程使用一个名为 Unity 链接器的工具来剥离托管代码。Unity 链接器是 IL 链接器 的一个定制版本,专门用于与 Unity 协同工作。Unity 链接器中 Unity 引擎特有的定制部分不公开提供。
Unity 链接器负责托管代码剥离和引擎代码剥离过程的一部分,后者是一个独立的过程,可通过 IL2CPPUnity 开发的脚本后端,可作为构建某些平台项目的 Mono 替代方案。 更多信息
参见 术语表 脚本后端使用,该后端会删除未使用的引擎代码。有关更多信息,请参见 PlayerSettings.StripEngineCode。
Unity 链接器会分析项目中的所有程序集。首先,它会标记根类型、方法、属性和字段。例如,您添加到 游戏对象Unity 场景中的基本对象,可以代表角色、道具、场景、摄像机、航路点等。游戏对象的功能由附加到它的组件定义。 更多信息
参见 术语表 的 MonoBehaviour 派生类 场景场景包含游戏环境和菜单。将每个独特的场景文件视为一个独特的关卡。在每个场景中,您可以放置环境、障碍物和装饰,本质上是分段设计和构建游戏。 更多信息
参见 术语表 中的根类型。然后,Unity 链接器会分析它标记的根,识别并标记这些根所依赖的任何托管代码。完成此静态分析后,任何剩余的未标记代码都无法通过应用程序代码的任何执行路径访问,Unity 链接器会将其从程序集中删除。
Unity 编辑器会创建一个包含 Unity 项目中任何场景使用的类型的程序集列表,并将此列表传递给 Unity 链接器。然后,Unity 链接器会处理这些程序集、这些程序集的任何引用、link.xml 文件中声明的任何程序集以及具有 AlwaysLinkAssembly 属性的任何程序集。一般来说,Unity 链接器不会处理项目中包含的但不属于这些类别的程序集,并将它们从 Player 构建中排除。
对于 Unity 链接器处理的每个程序集,它会根据程序集的分类、程序集是否包含场景中使用的类型以及为构建选择的 托管剥离级别 来遵循一组规则。
为了这些规则的目的,程序集分为以下分类
在 Unity 中构建项目时,构建过程会将您的 C# 代码编译成名为通用中间语言 (CIL) 的 .NET 字节码格式。Unity 将此 CIL 字节码打包到称为程序集的文件中。您在项目中使用的插件中的 .NET 框架库和任何 C# 库也作为 CIL 字节码的程序集预先打包。
当 Unity 链接器执行其静态分析时,它会遵循一组规则来确定 Unity 链接器标记为构建必要的 CIL 字节码的部分。根标记规则确定 Unity 链接器如何识别和保留构建中的顶级程序集。依赖项标记规则确定 Unity 链接器如何识别和保留根程序集所依赖的任何代码。
托管剥离级别 属性会更改 Unity 链接器使用的规则集。以下部分描述了 托管剥离级别 属性的每个可能设置的标记规则。
下表描述了 Unity 链接器如何识别程序集中的顶级类型
程序集类型 | 标记规则 | ||||
---|---|---|---|---|---|
最小 | 低 | 中 | 高 | ||
.NET 类库和平台 SDK 以及 UnityEngine 程序集 | 应用预防性保留以及任何 link.xml 文件中定义的保留。 | 应用预防性保留以及任何 link.xml 文件中定义的保留。 | 应用任何 link.xml 文件中定义的保留。 | 应用任何 link.xml 文件中定义的保留。 | |
包含场景中引用的类型的程序集 | 标记程序集中的所有类型和成员。 | 标记程序集中的所有类型和成员。 | 标记以下内容: • 所有具有 [RuntimeInitializeOnLoadMethod] 或 [Preserve] 属性的方法。• 任何 link.xml 文件中定义的保留。 • 标记预编译、包、Unity 脚本或程序集定义程序集中从 MonoBehaviour 和 ScriptableObject 派生的所有类型。 |
标记以下内容: • 所有具有 [RuntimeInitializeOnLoadMethod] 或 [Preserve] 属性的方法。• 任何 link.xml 文件中定义的保留。 • 标记预编译、包、Unity 脚本或程序集定义程序集中从 MonoBehaviour 和 ScriptableObject 派生的所有类型。 |
|
所有其他 | 标记程序集中的所有类型和成员。 | 标记以下内容: • 所有公共类型以及这些类型的公共成员。 • 所有具有 [RuntimeInitializeOnLoadMethod] 或 [Preserve] 属性的方法。• 任何 link.xml 文件中定义的保留。 • 标记预编译、包、Unity 脚本或程序集定义程序集中从 MonoBehaviour 和 ScriptableObject 派生的所有类型。 |
标记以下内容: • 所有公共类型以及这些类型的公共成员。 • 所有具有 [RuntimeInitializeOnLoadMethod] 或 [Preserve] 属性的方法。• 任何 link.xml 文件中定义的保留。 • 标记预编译、包、Unity 脚本或程序集定义程序集中从 MonoBehaviour 和 ScriptableObject 派生的所有类型。 |
标记以下内容: • 所有具有 [RuntimeInitializeOnLoadMethod] 或 [Preserve] 属性的方法。• 任何 link.xml 文件中定义的保留。 • 标记预编译、包、Unity 脚本或程序集定义程序集中从 MonoBehaviour 和 ScriptableObject 派生的所有类型。 |
|
测试 | 标记任何具有 [UnityTest] 属性的方法以及任何使用 NUnit.Framework 中定义的属性进行注释的方法。 |
Unity 链接器识别程序集中的根后,它需要识别这些根所依赖的任何代码。下表描述了 Unity 链接器如何识别程序集中根类型的依赖项
规则目标 | 每个剥离级别的操作 | ||||
---|---|---|---|---|---|
最小 | 低 | 中 | 高 | ||
MonoBehaviour | 当 Unity 链接器标记类型时,它也会标记 MonoBehaviour 类型的全部成员。 | ||||
ScriptableObject | 当 Unity 链接器标记类型时,它也会标记 ScriptableObject 类型的全部成员。 | ||||
属性 | 当 Unity 链接器标记程序集、类型或其他代码结构时,它也会标记这些结构的所有属性。 | 当 Unity 链接器标记程序集、类型或其他代码结构时,它也会标记这些结构的所有属性。 | 当 Unity 链接器标记程序集、类型或其他代码结构时,它只会标记这些结构的属性,前提是属性类型也已标记。 | 当 Unity 链接器标记程序集、类型或其他代码结构时,它只会标记这些结构的属性,前提是属性类型也已标记。 | |
调试属性 | 启用脚本调试时,Unity 链接器会标记所有具有 [DebuggerDisplay] 属性的成员,即使没有使用这些成员的代码路径。 |
启用脚本调试时,Unity 链接器会标记所有具有 [DebuggerDisplay] 属性的成员,即使没有使用这些成员的代码路径。 |
Unity 链接器始终会删除调试属性(如 DebuggerDisplayAttribute 和 DebuggerTypeProxyAttribute)。 | Unity 链接器始终会删除调试属性(如 DebuggerDisplayAttribute 和 DebuggerTypeProxyAttribute)。 | |
.NET 外观类库 | 删除外观程序集,因为它们在运行时不需要。 |
Link.xml
文件支持很少使用的“features”XML 属性。例如,mscorlib.dll
中嵌入的 mscorlib.xml
文件使用此属性,但您可以在需要时将其用于任何 link.xml
文件中。
使用 高 剥离级别时,Unity 链接器会排除针对当前构建设置不支持的功能的保留。
例如,以下 link.xml 文件在支持 COM 的平台上保留类型的其中一种方法,在所有平台上保留一种方法
<linker>
<assembly fullname="Foo">
<type fullname="Type1">
<!--Preserve FeatureOne on platforms that support COM-->
<method signature="System.Void FeatureOne()" feature="com"/>
<!--Preserve FeatureTwo on all platforms-->
<method signature="System.Void FeatureTwo()"/>
</type>
</assembly>
</linker>
使用 高 剥离级别时,Unity 链接器会编辑方法主体以进一步减小代码大小。本节总结了 Unity 链接器对方法主体进行的一些值得注意的编辑。
Unity 链接器只编辑 .NET 类库程序集中的方法主体。编辑方法主体后,程序集的源代码将不再与程序集中的编译代码匹配,这可能会使调试更加困难。
以下列表描述了 Unity 链接器可以执行的操作以编辑方法主体