Vico Bill< 刘 利 波 > 的个人网站

记录关于学习、工作中的技术点滴

C,C++,Rust,Ruby爱好者;热衷于游戏开发、任务自动化与跨平台;沉迷于游戏引擎与图形表现;深信'简单、多元'哲学的力量。


访问主页

游戏引擎-UE4-构建工具

在谈论构建工具之前,快速回顾一下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 使用本地存储作为存储目录
最近的文章

笔记集锦-Lisp

语法:() 空表(obj1 obj2 ...)(procedure arg ...)(car (list)) 取第一个元素(cdr (list)) 取列表剩余元素(cons a b) 将2个参数构建成列表(list a b ...) 与cons相同,构建列表,但可允许任意参数(quote (expr)) 将表达式当作列表 '(expr) 引用的语法糖((car (list + - * /)) 2 3)(let ((var expr) ...) bo...…

继续阅读
更早的文章

笔记集锦-Windows10SDK

术语win10SDK基于C++/WinRT进行开发,跨设备(PC,MOBILE)、跨语言(C++,C#,VB,JS等)、跨架构(Arm,x86,x64)。 WinRT(Windows Runtime): 是微软基于Win8 Metro下的开发框架,是面向对象、跨语言的Native库。主要使用微软的扩展语言:C++/WinRT,以前是C++/CX,以支持.Net和C++两种语言开发。与之对应的技术是: COM + C++/WINRT + WINMD winmd(Win...…

继续阅读