虚幻基础之编译

虚幻基础之编译,第1张

虽然不像Unity3D那样以多平台支持作为宣传点,虚幻本身依然是多平台支持的,如Windows,IOS,安卓等等。同时为了应对开发和部署的需要,编译的配置也是一个花样繁多的过程。

本篇文章就初步得从概念和工具的角度对虚幻的编译做一定的总结。

文章目录
    • 编译系统
      • UnrealBuildTool
      • UnrealHeaderTool
    • 编译类型
    • 总结
    • 参考

本文使用的环境和工具为:

  • Windows 10
  • ue5
  • Rider or Unreal Engine 2021.3
编译系统

编译是指从源程序到产生目标程序的过程,是指从高级语言翻译成机器可以识读的二进制语言的过程,更通俗来讲,它可以是把我们编写的代码、资源,整合成一个可以运行的可以玩的游戏的过程。

编译通常会涉及到一项强有力的工具——编译器,当然标准的编译流程中还会又预处理阶段(由预处理器负责,是和编译器分开的),现在各种功能强大的IDE通常会把这些工作整合到一起在后台做掉,我们一般只需要点一下Build或者Debug又或者Run即可。

当然,虚幻引擎本身及其游戏内容都是由c++写成,其项目编译当然也会遵循这个过程。只不过,虚幻引擎本身的代码量非常之巨大,属性和方法组成了类,类和类相互配合搭建起模块,模块和模块相互依赖构成了系统,而虚幻引擎中类和模块的数量已经难以计数,所以它也推出了自己的一套管理代码的工具():UnrealBuildTool(UBT,C#,编译虚幻的各个模块,处理依赖),和UnrealHeaderTool(UHT,C++,头文件解析和代码生成,为反射系统提供支持)。

UnrealBuildTool

UBT的源码位于:

UE_5.0\Engine\Source\Programs\UnrealBuildTool

代码是用C#写成,完整开发的话需要安装相应的.Net桌面开发框架,需要的可以到相应位置查找(一般我们不会去动这个工具,但是相应的,如果需要做一些轻量的修改,可以到BuildConfiguration.cs中探索可供用户配置的编译选项)。而对应的可执行程序的位置在:

UE_5.0\Engine\Binaries\DotNET\AutomationTool

这个才是真正编译好的,发挥作用的工具。

对于UBT,我们需要知道的是,当我们去Build或者Rebuild项目时(以及右键点击项目的.uproject文件选择Generate Visual Studio project files时),就会去运行UnrealBuildTool.exe,并传入几个参数(Main函数的参数):

static class UnrealBuildTool
{
    ...
    private static int Main(string[] ArgumentsArray)
    {
        ...
    }
}

这里的ArgumentsArray即是通过采样C++构建系统NMake的Build Command Line来确定几个参数,主要是项目名称,编译的Target(目标),目标平台等等。

然后读取build.cs,确定模块与模块之间的依赖关系(需要去编译哪些模块,需要忽略哪些模块的编译工作,模块的没有变动的话会跳过)。

随后,UBT调用UHT执行头文件解析和代码生成的工作,UHT会根据反射标签生成相应的代码(如对应GENERATED_BODY()的宏替换代码就位于生成的.generated.h中,又如UPROPERTY()标记的属性被序列化到蓝图中,等等,详情参考讲解反射的相关文章)。

最后,UBT通过确定好的依赖关系调用编译器编译变更模块的C++代码。

UnrealHeaderTool

UHT的源码位于:

UE_5.0\Engine\Source\Programs\UnrealHeaderTool

UHT工具与虚幻的反射机制息息相关,可以这样说,UHT是构建于虚幻UObject系统基础上的宏生成和替换工具(当然,还是用原文“头文件解析工具”更贴切)。

反射是很多游戏引擎都依赖的特性,像Unity3D借用了C#的反射。当然不同的是,C++本身并不支持反射(原生C++有RTTI,Runtime Type Identification,即运行时类型识别),而是虚幻在普通C++上实现了这样的一套反射机制。这样,便使运行时获取类的元数据变得简单,从实现GC,序列化等一些引擎需要的功能。

举个例子,用UPROPERTY()标记的属性,可以序列化在蓝图中,通过其中的说明符可以进一步定制该属性的特性(详情参阅说明符关键字相关文章)。

编译类型

编译虚幻项目时,可以是简单的选择项目,然后右键Build,然后运行Debug;但是此时可能就会遇到一些问题,为什么有些代码我打了断点,却无法进入断点呢?

这个就是虚幻C++项目的一个小坑了,关键就在于编译的配置。

我们可以发现在每个模块都有对应的.Target.cs,包括我们的游戏模块。其内容就是对该模块应该面向哪一种编译的目标。

这里这个编译的Target,我们可以理解为我们出于什么目的来编译这个模块,是为了让别人在游戏中直接使用?还是别人可以在编辑器中应用调整该模块?等等。

例如我们的游戏模块,我们知道这个游戏是冲着打成包给别人玩的,那么就有专门的.Target.cs

Type = TargetType.Game;

这里的Target为[empty]

此外,这个游戏模块还要供我们在编辑器内编辑使用,可能还会用到调试,那么还有另外一个__Editor.Target.cs

Type = TargetType.Editor;

这里的Target为Editor。

此外Target的可选项还有Client和Server,分别对应着客户端和服务器的编译目标。

Target描述
[empty]不带编辑器的一个独立可执行版本,需要提前打包烘培内容资源
Editor在虚幻编辑器里打开并可编辑游戏项目,所有代码的更改也会反映到编辑器中
Client多人联网功能中的客户端版本,需要在项目中提供__Client.Target.cs(参照__Editor.Target.cs的写法)
Server多人联网功能中的服务器版本,需要在项目中提供__Server.Target.cs(参照__Editor.Target.cs的写法)

除了Target外,还有另外一关键字需要注意——State(通常State在前,Target在后,即[State] [Target])。

State是用来描述我们当前引擎和游戏项目的状态,我们的游戏要准备打包发行了,就使用Shipping;我还处在游戏开发阶段,需要通过代码进行某些游戏代码的调试,就使用DebugGame;而若是只需要通过编辑器的反射来查看代码的更改的话,那么Development一般就可满足条件(这也是默认的状态,虚幻官方推荐新手以蓝图开发为主,代码开发为辅)。

StateEngineGame描述
DebugDebugDebug会同时去构建引擎和游戏两者的代码,是最全面的构建,但同时也会比较费时间
DebugGameReleaseDebug以最优的方式构建引擎,同时保持游戏部分的代码支持调试,适用于仅调试代码的模式
DevelopmentReleaseRelease可以在编辑器内通过反射的方式查看代码所带来的更改,是开发和性能最平衡的模式
ShippingReleaseRelease最佳性能配置,用于交付游戏,无控制台命令、统计数据和性能分析工具
TestReleaseRelease同Shipping模式,但是启用了控制台命令、统计数据和性能分析工具

这两个关键字大部分情况都可以组合使用,但是还是有一些例外情况。

编译配置——编译解决方案(有引擎源码版),此时是将引擎源代码和游戏项目的源代码一同编译,其可选配置如下:

DebugDebugGameDevelopmentShippingTest
[empty]
Editor
Client
Server

编译配置——编译项目(无引擎源码版),此时是将游戏项目的源代码单独编译,其可选配置如下:

DebugDebugGameDevelopmentShippingTest
[empty]
Editor
Client
Server
总结

UBT也好,UHT也好,甚至于IDE也好,作为工具来说是他们都是非常强大可靠的,同时其强大的代价就是其内部项目的驳杂,会在我们希望深入内部时造成一定的阅读学习困难。

好在,一方面,作为游戏开发者、引擎使用者来说,我们不是必须要把这些工具的内部代码理解通透,而是掌握其基本特性和工作流程已是不错,随着分工不断得细化,我们程序也会走向不同的分工,可能确实有一些同时需要切实掌握并且具备修改的能力,但是对于大部分Gameplay和System的编程者来说,能够完全掌握本文及链接所述内容已是不俗。

另一方面,网络上也越来越多得出现技术和知识的共享者,本文的成文就是综合多方阅读资源进行总结的结果,这里也表达我的谢意。

最后,如果文中有一些技术性或者表述性的错误,还请大家多予指点。

参考

虚幻 5.0 Documentation - Build Configurations Reference

虚幻 5.0 Documentation - Compiling Game Projects

知乎作者 大钊 的文章《InsideUE4》

知乎作者 雪流星 的文章《虚幻编译系统总结》

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/872535.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存