在谈论构建工具之前,快速回顾一下C/C++的构建工具史。
在Unix C或早期时代,一直到现在,C语言的构建,通常由以下指令处理:
./configure
make
make install
完成从源码编译,到安装完成的过程。其中以make工具为主,Makefile是核心配置,用来设置:编译选项、编译目标、依赖文件、库管理等等。Makefile写得了,一气呵成感觉好。
Makefile可
- 跨编译器:clang,gcc(cygwin/gcc,mingw/gcc), msvc,watcom等
- 跨架构编译:x86,x64,arm,arm64等
- 跨平台:Windows,Linux, OSX, IOS, Android,PS4/5, Switch, XBOX等
后来演化,出现autotools(autoconf,automake,m4)等,自动生成Makefile的工具链。但make工具并不跨平台,它在Linux平台如鱼得水,但在Windows平台却如履薄冰。
但对于Unreal来说,Unreal是在Windows平台开发,主要游戏发布也是Windows和主机平台,工具链以Windows + Visual Studio + DirectX 为主,对于以Make工具为主Linux系的C/C++语言构建系统天生不搭。
后来出现很多其他跨平台的构建工具,如:Ninja, cmake, premake(lua),meson(py),bazel,gradle(groovy),waf(py),cake,xmake,rake(ruby),scons(py)等跨平台,Unreal是一个也没看上。
所以,Unreal基于一身傲气,开发了以C#为基础的Unreal Build Tool。实现原理与一众跨平台工具相差无几,但完全基于自家需求开发。
Unreal作为跨平台游戏引擎,在编译时需要解决以下问题:
- 跨平台:PC(Windows,Linux, OSX), Mobile(Android,iOS)以及其他如HoloLens、Lumin、TVOS等
- 跨架构:armv7,armv8,x86,x64等
- 跨编译器: msvc,clang,gcc。
- 对不同的项目设置不同的编译参数、库依赖、头文件搜索路径。Unreal有自己的头文件目录结构(Public,Private,Class),代码以模块进行划分,头文件相对于模块进行包含,对Public、Private之分透明。
- 自动生成游戏工程项目,供IDE使用。
- 自动构建并打包/部署。
与UnrealBuildTool很相似,而且同样采用C#编写的构建工具是Cake。
CMake最多是构建IDE工程,编译依靠IDE,部署那就比较难了。
Ninja更聚焦于快速编译
xmake更像UBT要解决的工具,但xmake使用的人比较少,而且使用Lua作为DSL
whatever, UBT诞生了,而且满足Unreal需求。
UBT Unreal Build Tool 构建工具
主要聚焦模块构建和Target构建。
UBT以Target.cs和Build.cs为编译规则配置文件。名词:Target:目标,编译目标,即指定的目标平台。
- Target.cs定义了TargetRules,用于对不同构建目标(平台)指定编译选项、头文件搜索路径、库依赖等。
- Build.cs定义了ModuleRules,用于编译Module时指定的编译选项、头文件搜索路径、库依赖等
UBT的构建,有以下几种:
- BuildBinary: 构建二进制可执行文件。
- BuildModule:构建一个模块。Unreal中的功能是通过模块进行划分、组合。
- BuildModuleCPP:构建C++代码的模块。包括构建PCH、SharePCH、Unity构建文件、查找源文件目录等
- BuildTarget: 为目标创建makefile、生成头文件、生成manifest
UAT:Unreal Automation Tool 自动化工具
主要用于一键式运行、打包等。类似于 代码同步-构建-烘焙-打包-运行-部署 这样的pipeline。
自动化工具,UAT。UAT主要以解析命令行参数为主,每个命令行参数都可能对应一个命令。每个命令有其自己的作用与逻辑。
命令派生自BuildCommand,实现执行构建函数:ExcuteBuild
.命令主要存放于AutomationTool/Scripts/
- AnalyzeThirdPartyLibs: 分析第三方库大文件
- BlameKeyword: 查找所有文件中对应的关键字,并分析由谁创建了此关键字。主要用于责任归咎?
- BuildCMakeLib: 通过cmake构建第三方库
- BuildCommonTools: 构建通用工具。
- BuildCookRun: 实则为3个命令Build->Cook->Run 。对于非uproject项目目标,如果-map未指定,命令会从项目的DefaultEngine.ini查找DefaultMap入口,如果未找到,从BaseEngine.ini中查找。如果找不到DefaultMap,此命令会回滚到/Engine/Maps/Entry。
- BuildDerivedDataCache: 构建DerivedDataCache。
- BuildHlslcc: 使用CMake构建Hlslcc.
- BuildPhysX: 使用CMake构建PhysX/APEX。
- BuildPluginCommand: 构建一个plugin,并将其打包以分发。
- BuildTarget:为指定项目构建指定目标和配置。
- BuildThirdpartyLibs: 构建第三方库,并把它们放入changelist
- CheckBalancedMacros:检测所有源文件,是否有平衡的宏,以作为启用/禁用优化、警告等
- CheckCsprojDotNetVersion: 检测csproj使用的dotnet版本
- CheckRestrictedFolders: 检测目录下不应分发的文件夹。
- CheckTargetExists: 通过查看有关证据(receipt),检测给定的目标是否存在
- CheckXcodeVersion: 检测XCode的版本
- CleanAutomationReports: 移除Automation报告目录下的旧文件夹。
- CleanFormalBuilds: 移除匹配搜索模式的文件夹。
- CodeSurgery: 重构C++源码以适应新的stats系统
- CopyUAT : 将所有UAT和UBT构建的结果复制到指定目录。
- CryptoKeys:通过读取 DefaultCrypto.ini 按照指定加密键加密pak。
- ExtractPaks: 解压pak。通过指定加密键和压缩器解压pak。
- FinalizeInstalled: 执行附加的步骤
- FixupRedirects:修正重定向
- GenerateDSYM: 为远程项目生成IOS调试符号
- IPhonePackager: iPhone打包
- ListMobileDevices: 列出已连接的设备(Android,ios)
- ListThirdPartySoftware: 列出用于构建指定目标所关联的任意source,content,engine shader等
- Localisation:更新外部本地化数据。
- MegaXGE:通过megaxge编译
- OpenEditor:打开指定项目(uproject)
- ParseMsvcTimingInfo: 解析VC++计时信息(由UBT的-Timing标志生成),并转换成JSON格式,可供chrome://tracing可视化
- RebasePublicIncludePaths:重写包含的头文件,以使它们相对于Public文件夹
- RebuildHLOD: 重建项目的继承式LOD
- RebuildLightMaps: 重建项目的光照映射图
- RecordPerformance: UAT使用不同RHI执行性能测试demo,并比较结果。执行的测试项目:SubwaySequencer,InfiltratorDemo,ElementalDemo,ShowdownDemo
- ReplaceAssetsUsingManifest:使用清单替换Assets
- ResavePluginDescriptors: 重新保存给定目录下的所有插件描述,可选应用标准metadata
- ResaveProjectDescriptors: 重新保存给定路径下的所有项目描述
- StashTarget: 复制所有二进制文件到不同文件夹,可通过UnstashTarget命令恢复。在A/B测中非常有用
- SyncDDC: 合并1+远程DDC共享到本地共享
- SyncProject:同步并构建项目所有必需的二进制
- UpdateLocalVersion:更新本地版本(P4)
- UploadDDCToAWS: 上传DDC到AWS中。主要用于CDN分发
- ZipUtils:用于zip/unzip(如RunUAT.bat ZipUtils -archive=D:/Content.zip -add=D:/UE/Projects/SampleGame/Content)或(如RunUAT.bat ZipUtils -archive=D:/Content.zip -extract=D:/UE/Pojects/SampleGame/Content/))
通用的命令:
- UE4BuildUtils:
- BuildPatchTool: 构建补丁工具
- BuildUnrealHeaderTool: 构建UnrealHeaderTool
- BuildProduct: 构建产品。通过UE4Build和UE4Build.BuildAgenda进行构建。
针对Project,主要过程有:
- Archive:创建归档Manifest
- Build: 构建项目
- 设置editor目标。即:UHT,ShaderCompilerWorker,UnrealFileServer
- 构建所有必需的工具。如UnrealPak
- 读取ini,覆盖配置
- 设置烘培目标
- 设置Agenda
- SwarmAgent
- SwarmCoordinator
- *.csproj
- 调用并行编译
- 复制UAT文件到预编译位置,添加到构建产品步骤中。UAT文件: AutomationTool.exe,AutomationTool.exe.config, UnrealBuildTool.exe,UnrealBuildTool.exe.config,AutomationUtils.Automation.dll,DotNETUtilities.dll,MobileDeviceInterface.dll
- 签名(Sign)所有exe,dll,dle,msi。主要针对MAC和XboxOne
-
Cook: 烘培。分常规模式和CookOnTheFly模式。
-
CopyBuildToStagingDirectory: 将构建暂存
-
Deploy:部署
-
GetFile:获取部署文件
-
Package: 打包
- Run: 执行项目。执行模式有:RunDedicatedServer,RunFileServer,RunClientWithServer,RunStandaloneClient
针对不同平台和服务,在构建的每个阶段都有不同的处理
[附录] UBT命令行参数
[CommandLine],请在项目中搜索CommandLine全词匹配
全局参数 参数 | 描述 — | — -Verbose,-VeryVerbose | 指定日志细节等级,取值Fatal,Error,Warning,Console,Log,Verbose,VeryVerbose -Log | 指定日志路径 -Timestamps | 日志中是否包含时间戳 -FromMsBuild | 是否格式化成MSBuild消息格式 -Progress | 是否写入进度标记 -NoMutex | 是否忽略mutex -WaitMutex | 等待mutex,而非立即终止 -RemoteIni | 指定远程ini -Mode | 构建模式 -Clean,-ProjectFiles,-ProjectFileFormat,-Makefile,-CMakefile,-QMakefile,-KDevelopfile,-CodeliteFiles,-XCodeProjectFile,-EdditProjectFile,-VSCode,-VSMac,CLion,-Rider | 构建工具执行模式。默认取值:GenerateProjectFiles。生成或清理对应IDE项目工程文件
BuildMode的参数 参数 | 描述 — | — -IgnoreJunk | -SkipBuild | 跳过构建,只setup就结束 -SkipPreBuildTargets | 跳过预构建目标。只处理主目标 -XGEExport | 是否只导出XGE XML -NoEngineChanges | -WriteOutdatedActions= | -LogSuffix= -NoLog | -TargetList= | -Target= | -Project= | 指定带.uproject后缀的项目 ShaderCompileWorker | LiveCodingConsole |
构建配置: 参数 | 描述 — | — -UsePrecompiled | -NoXGE | -NoFASTBuild | -NoUBTMakefiles | -MaxParallelActions | -ForceHeaderGeneration | -NoBuildUHT | -FailIfGeneratedCodeChanges | -NoHotReloadFromIDE | -SkipRulesCompile |
目标描述 参数 | 描述 — | — -Plugin= | -Module= | 设置编译的模块名称 -SingleFile= | -NoHotReload,-ForceHotReload,-LiveCoding | -WriteActions= | -LiveCodingModules= | -LiveCodingManifest= | -Quiet |
TargetRules
参数 | 描述
— | —
-AllModules
-BuildPlugin= | 通过+号隔开
-EnablePlugin= |
-DisablePlugin= |
-CompileAsDll | 是否编译为dll
-NoCompileChaos,-CompileChaos |
-NoUseChaos, -UseChaos |
-rtti | 所有模块启用RTTI
-IWYU | 启用Include What You Use
-Precompile | 所有静态库作为此目标的中间结果
-DisableUnity |
-ForceUnity |
-ShadowVariableErrors |
-FastMonoCalls,-NoFastMonoCalls |
-StressTestUnity |
-ForceDebugInfo |
-NoDebugInfo |
-NoPDB |
-NoPCH |
-Preprocess |
-IncrementalLinking,-NoIncrementalLinking |
-LTCG | Link Time Code Generation
-PGOProfile | Profile Guided Optimization
-PGOOptimize |
-NoSharedPCH | 默认false
-FastPDB |
-MapFile |
-BundleVersion |
-Deploy,-SkipDeploy |
-NoLink |
-Formal |
-FlushMac |
-Timing |
-Tracing |
-PublicSymbolsByDefault |
-ToolChain |
-CppStd | C++标准,Cpp14,Cpp17,Latest
-NoManifestChanges |
-BuildVersion | 构建版本
-Monolithic,-Modular | 所有模块是整合成一个还是为独立的动态库
-Define: | 整个Target的宏定义
-ProjectDefine: | 项目的宏定义
-Manifest |
-DependencyList |
-SharedBuildEnvironment,-UniqueBuildEnvironment |
-OverrideBuildEnvironment |
-CompilerArguments= |
-LinkerArguments= |
CleanMode的参数 参数 | 描述 — | — -SkipRulesCompile | -SkipPreBuildTargets |
DeployMode的参数 参数 | 描述 — | — -Receipt |
ExcuteMode的参数 参数 | 描述 — | — -Actions= |
[附录] UAT命令行参数
在Automation.cs
中搜索CommandLineArg。
参数 | 描述 |
---|---|
verbose | 启用冗余日志 |
nop4 | 禁用Perforce功能 |
compileonly | 不执行任何命令,只编译它们 |
help | 显示help |
list | 显示所有可用的命令 |
submit | 允许UAT命令提交改变 |
nosubmit | 阻止任何提交尝试 |
nokill | 退出时不kill任意产生的进程 |
ignorejunk | 阻止UBT清理垃圾文件 |
UseLocalBuildStorage | 使用本地存储作为存储目录 |