背景
我之前写了一篇文档,大意是使用 UAT 来调试 BuildCookRun 命令:
(图1)
但发现某一些cs代码(代码1)无法断点调试,配置如图1所示,图中马赛克的参数如代码2所示。
//代码1:
private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, FileReference SingleFileToCompile, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, TargetMakefile Makefile)
{
……
Log.TraceInformation("Compile target:{0}, module:{1}, LinkType:{2} ", Target.Name, Module.Name, Target.LinkType);
LinkInputFiles = Module.Compile(Target, ToolChain, BinaryCompileEnvironment, SingleFileToCompile, WorkingSet, Makefile);
……
}
//代码2:
-ScriptsForProject=j:\Light_Check_MyGame\MyGame_Mini\MyGame_Mini.uproject BuildCookRun -nop4 -project=j:\Light_Check_MyGame\MyGame_Mini\MyGame_Mini.uproject -cook -stage -archive -archivedirectory=j:\Light_Check_MyGame\MyGame_Mini\Saved\Archived -package -ue4exe=j:\Light_Check_MyGame\EngineSource/Engine/Binaries/Win64/UE4Editor-Cmd.exe -compressed -pak -prereqs -nodebuginfo -manifests -targetplatform=Win64 -build -target=MyGame_Mini -clientconfig=Development -utf8output -compile
原因分析
原来,我的调试需求其实是想要调试“编译代码”的步骤,这只是 BuildCookRun 功能中的一部分,体现在 -build 参数这儿。BuildCookRun 是由 UAT 直接实现的,它调用UBT 去跑一系列动作,包括 Build Cook Archive 等,如代码3所示。
//代码3: EngineSource\Engine\Source\Programs\AutomationTool\Scripts\BuildCookRun.Automation.cs
protected void DoBuildCookRun(ProjectParams Params)
{
const ProjectBuildTargets ClientTargets = ProjectBuildTargets.ClientCooked | ProjectBuildTargets.ServerCooked;
Project.Build(this, Params, WorkingCL, bGenerateNativeScripts ? (ProjectBuildTargets.All & ~ClientTargets) : ProjectBuildTargets.All);
Project.Cook(Params);
Project.CopyBuildToStagingDirectory(Params);
Project.Package(Params, WorkingCL);
Project.Archive(Params);
Project.Deploy(Params);
PrintRunTime();
Project.Run(Params);
Project.GetFile(Params);
}
其中,Project.Build() ,我们今天的主角,调用的是另外一个程序 exe (神秘程序X),代码中的 Run 的底层是调用 IProcessResult Result = ProcessManager.CreateProcess ,即操作系统的进程调用。
// 代码4:J:\\EngineSource\Engine\Source\Programs\AutomationTool\AutomationUtils\UBTUtils.cs
public static void RunUBT(CommandEnvironment Env, string UBTExecutable, string CommandLine)
{
……
IProcessResult Result = Run(UBTExecutable, CommandLine, Options: ERunOptions.AllowSpew | ERunOptions.NoStdOutCapture); // 调用操作系统里的命令行
if(Result.ExitCode != 0)
{
throw new AutomationException((ExitCode)Result.ExitCode, "UnrealBuildTool failed. See log for more details. ({0})", CommandUtils.CombinePaths(Env.FinalLogFolder, LogName)) { OutputFormat = AutomationExceptionOutputFormat.Minimal };
}
}
这个神秘程序 X (代码4中的 UBTExecutable),及其参数(代码4中的 CommandLine),就是:
程序:J:\Light_Check_MyGame\EngineSource\Engine\Binaries\DotNET\UnrealBuildTool.exe
参数:UnrealHeaderTool Win64 Development -Project=j:\Light_Check_MyGame\_MyGame_Mini\_MyGame_Mini.uproject j:\Light_Check_MyGame\_MyGame_Mini\_MyGame_Mini.uproject -NoUBTMakefiles -Manifest=J:\Light_Check_MyGame\EngineSource\Engine\Intermediate\Build\Manifest.xml -NoHotReload -log="J:\Light_Check_MyGame\EngineSource\Engine\Programs\AutomationTool\Saved\Logs\UBT-UnrealHeaderTool-Win64-Development.txt"
由此,我们得知,UAT 调用了 UBT 。所以我们如果要看代码的编译过程,就应该调试UBT,参考这篇文章: UBT如何编译UE4工程代码_编译ue4工程的文件-CSDN博客。 那么下图6中的所有代码范围,都属于 UBT 的范围,因此都应该按 UBT 来调试。这就是本文标题 《UE4调试UAT时为何断点不了BuildCookRun的部分代码》的答案了。
(图6)
下面贴出堆栈方便作为参考。
BuildCookRun的执行堆栈
BuildCookRun.DoBuildCookRun() at J:/Light_Check_UHD/EngineSource/Engine/Source/Programs/AutomationTool/Scripts/BuildCookRun.Automation.cs:line 198 BuildCookRun.ExecuteBuild() at J:/Light_Check_UHD/EngineSource/Engine/Source/Programs/AutomationTool/Scripts/BuildCookRun.Automation.cs:line 39 BuildCommand.Execute() Automation.Execute() Automation.Process() Program.MainProc() Program.<>c__DisplayClass1_0.<Main>b__2() InternalUtils.RunSingleInstance() Program.Main() [External code: 2 frames] Launcher.Main()
RunUBT的执行堆栈
CommandUtils.RunUBT() at EngineSource/Engine/Source/Programs/AutomationTool/AutomationUtils/UBTUtils.cs:line 23 CommandUtils.RunUBT() at EngineSource/Engine/Source/Programs/AutomationTool/AutomationUtils/UBTUtils.cs:line 89 UE4Build.BuildWithUBT() UE4Build.Build() Project.Build() BuildCookRun.DoBuildCookRun() BuildCookRun.ExecuteBuild() BuildCommand.Execute() Automation.Execute() Automation.Process() Program.MainProc() Program.<>c__DisplayClass1_0.<Main>b__2() InternalUtils.RunSingleInstance() Program.Main() [External code: 2 frames] Launcher.Main()