前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UE4的UBT编译单个cpp过程梳理

UE4的UBT编译单个cpp过程梳理

原创
作者头像
sosioshen
发布2022-07-26 20:09:08
2.4K0
发布2022-07-26 20:09:08
举报
文章被收录于专栏:菜刀的耕耘

背景问题

最近同事遇到一个编译的问题,如果书写了错误的Log语句,会导致真个unreal build无限卡死: UE_LOG(LogTemp, Debug, TEXT("Something")); 这里这个Debug等级其实是不存在的,是一个书写错误,正常情况会报一个编译错误,但在我们的case中,会出现无限等待的情况。

网上也有类似的bug情况: https://answers.unrealengine.com/questions/1003748/error-in-macro-syntax-causes-build-to-hang.html?sort=oldest

可以看到的是cl-filter.exe失去了响应,但也没有更多的线索. 于是想去看看这个过程中发生了什么?

深入UBT的过程

之前一直试用UBT编译,没有好好学习过编译一个cpp发生了什么,UE4是怎么一步步去调用到系统的cl.exe完成一个cpp的编译的

如何调试UBT

  • 设为启动项目

  • 复制启动参数

获得NMake中Build.bat 后面的参数,这些参数都会送到UnrealBuildTools.exe 中执行

  • 填入启动参数

注意要把$(SolutionDir)换成你自己的绝对路径

这样就可以调试整个UBT运行过程了

UBT处理过程

Module

  • 输入源码.cpp/.h
  • 配置build.cs 定义一些宏以及依赖关系

UBT

  • 解析各种宏定义,保存到Module.XXX.Definitions.h
  • 处理各种编译参数保存到XXX.obj.response文件中(这个就是编译的主要内容)
  • 根据Unity Build策略,合并一个Module.XXX.cpp
  • 执行一个ExcuteAction,在window上里面的内容就是一个带参数的 cl-filter命令行

cl-filter.exe

  • 本质是cl.exe的一个warp,有个warp的主要目的是通过/showIncluds命令来获取编译过程中正真的包含文件,(这个解析过程可能还存在多语言之类的问题,所以比较复杂),但最终都是把 cl.exe的 include信息其他编译日志分离
  • 我的理解:生成的includes文件,可以供UBT做进一步的优化使用(未深入)

追踪各个步骤的中间产物

Defination文件和response文件

在windows上,一般在VCToolChain.cs中产生一些全局定义和编译参数 主要是一些包含路径和宏定义 Plugin的话可以在

代码语言:javascript
复制
\Intermediate\Build\Win64\UE4Editor\Development\XXX\Module.XXX.cpp.obj.response

找到这个编译参数文件

这个文件直接决定了后面cl-filter以及cl的编译全部内容

ExcuteAction

这个构造了对应的cl-filter的命令参数 主要有 cl的路径位置,输出的log位置,以及上面提到的response文件 查看这个参数的方法可以直接断点看,

或者加-Verbose参数激活

一个命令行参数大概长这样

代码语言:javascript
复制
"G:\UnrealEngine\Engine\Build\Windows\cl-filter\cl-filter.exe"-dependencies=G:\G6\MMO-Demo\Plugins\G6Plugin\G6SkillFramework\Intermediate\Build\Win64\UE4Editor\Debug\SkillBridge\AnimationActionHandle.cpp.txt -compiler="C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\bin\HostX64\x64\cl.exe" -- "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\bin\HostX64\x64\cl.exe"  @"G:\G6\MMO-Demo\Plugins\G6Plugin\G6SkillFramework\Intermediate\Build\Win64\UE4Editor\Debug\SkillBridge\AnimationActionHandle.cpp.obj.response" /showIncludes

cl-filter

cl-filter 是cl.exe的封装,我们也可以在UnrealEngine\Engine\Extras\Windows\cl-filter找到他的源码和工程,可以attach或者加上上面的命令行参数进行调试

最终执行的cl.exe,就是使用cl-filter后面的那些参数(主要是response文件) 但是我们需要在Unreal程序的\Engine\Source的下面,无论是安装版本的UE4还是源码版本的UE4都可以,但是编译结果也和你的工作路径有关

Unity Build

通常UBT会把一堆小的cpp整合成一个大的cpp以减小编译时间(减少io次数) 这个行为就叫做Unity Build UE自己也有一些编译参数控制UnityBuild的效果,比如bUseUnityBuild/bForceUnityBuild/bUseAdaptiveUnityBuild

https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/BuildTools/UnrealBuildTool/BuildConfiguration/

Exclude from unity build

某些时候,单个文件编译单独编译比整合成一个大文件更快 1>[Adaptive unity build] Excluded from XXX unity file: XXX.cpp 那么UE是怎么识别这需要exclude呢,我一开始以为是通过修改时间,实际上看了 Unity.cs中的实现之后了解,实际上是通过git status来识别修改的文件。

相比于git修改过的文件就会标记成exclude from build。

如果你的git仓库有submodule,会导致submodule中的文件无法在根目录被git status识别到,这个需要注意

使用单个文件编译可以检查一些头文件包含缺失的方法,除了在git状态下修改,还有一种方法是配置UnrealVS插件使用快捷键进行单文件编译。 比如#include "CoreMinimal.h"这个如果忘记写,会导致单文件编译的时候DLLEXPORT无法被识别,这也是我坑了很久的问题

前面的bug解决过程

目前还没有完美解决和理解,但是通过拆解整个UBT的过程,也是弥补了自己的一些知识盲区

参考

UBT调试方法:https://blog.csdn.net/u013412391/article/details/106150390 cl-filter解释:https://papalqi.cn/ubt/ UE4单独编译一个cpp的方法:https://docs.unrealengine.com/4.26/zh-CN/ProductionPipelines/DevelopmentSetup/VisualStudioSetup/UnrealVS/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景问题
  • 深入UBT的过程
    • 如何调试UBT
      • UBT处理过程
        • Module
        • UBT
        • cl-filter.exe
      • 追踪各个步骤的中间产物
        • Defination文件和response文件
        • ExcuteAction
        • cl-filter
        • Unity Build
      • Exclude from unity build
      • 前面的bug解决过程
      • 参考
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档