UE 代码构建(BuildSystem)与源码编译相关

年底了,把之前的草稿文章整理一下,整理好的发出来

UnrealBuildTool简介

参考:https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/BuildTools/UnrealBuildTool/

UE里的项目代码、包括UE本身的源码,都是划分成一个个module的dll的,每个Module用build.cs文件来控制对应module的相关信息,比如对其他module的依赖、include路径等,然后这些dll会一起编译成最后的single executable里,后面还会详细介绍下。



关于build.cs与target.cs文件

看到一个新创建的名为MyDemo的C++工程,里面的这三个文件让我产生了疑惑,它们的路径如下:

  • F:\UnrealProjects\MyDemo\Source\MyDemo.Target.cs
  • F:\UnrealProjects\MyDemo\Source\MyDemoEditor.Target.cs
  • F:\UnrealProjects\MyDemo\Source\MyDemo\MyDemo.Build.cs

Source文件夹下出现了X和XEditor名字的target.cs文件,而Source\X文件夹下出现了X名字的build.cs文件。俩target.cs文件内容差不多:

// MyDemo.Target.cs
using UnrealBuildTool;
using System.Collections.Generic;public class MyDemoTarget : TargetRules
{public MyDemoTarget(TargetInfo Target) : base(Target){Type = TargetType.Game;// build目标类型为GameDefaultBuildSettings = BuildSettingsVersion.V2;IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1;ExtraModuleNames.Add("MyDemo");}
}// MyDemoEditor.Target.cs
using UnrealBuildTool;
using System.Collections.Generic;public class MyDemoEditorTarget : TargetRules
{public MyDemoEditorTarget(TargetInfo Target) : base(Target){Type = TargetType.Editor;// build目标类型为EditorDefaultBuildSettings = BuildSettingsVersion.V2;IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1;ExtraModuleNames.Add("MyDemo");}
}

build.cs文件则貌似是个runtime only的东西:

using UnrealBuildTool;public class MyDemo : ModuleRules
{public MyDemo(ReadOnlyTargetRules Target) : base(Target){PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" });}
}

看了下它们的内容,可以大概了解这些文件的干啥的了。Visual Studio里,一个正常的Solution会有多个projects,在这里,相当于每个Module对应一个project,而且Module的output类型都是dll,这里的文件作用分别为:

  • .uproject文件:记录项目引用了哪些module
  • target.cs文件:负责设置project的Configuration Type,还额外添加了UHT的一些版本信息
  • build.cs文件:负责设置project的依赖、include路径等

大概意思是,像Configuration、引擎版本、编译器这种所有Module对应的dll都共享的内容,可以放到Target.cs文件里,至于各自Module的依赖关系、PCH引用关系,则使用各自Module的Build.cs文件来记录

所以这里的target.cs表示了项目的build类型,一共也没多少种,无非就是类似于Debug、Release这种类型的设置,而build.cs则相当于记录了每个module的project的相关project settings信息。比如说我新创建的UE C++工程,自然会有Runtime的Game类型和Editor下的编辑类型,所以会有MyDemo.Target.csMyDemoEditor.Target.cs俩文件产生。而我如果是创建一个Plugin,那不需要创建任何.Target.cs文件,只需要创建Runtime和Editor下各自对应的Build.cs文件即可

在UE源码里,有四种主要的引擎对应的Target.cs文件:

  • UnrealClient.Target.cs
  • UnrealEditor.Target.cs
  • UnrealGame.Target.cs
  • UnreamServer.Target.cs

引擎里的所有Plugin和各自Module,应该都是随着引擎一起共享Target.cs文件,所以项目里,build.cs文件应该是更多的,UE源码里我验证了一下,确实是这样,里面的build.cs文件有1923个,但target.cs只有124个



BuildConfiguration.cs

另外,可以在BuildConfiguration.cs文件里选择一些全局的引擎build设置,这个文件属于引擎源码级别的代码,里面基本都是一堆bool值,具体路径为:

  • D:\UE_5.1\Engine\Source\Programs\UnrealBuildTool\Configuration\BuildConfiguration.cs


查看生成VS项目失败的log

参考:https://community.gamedev.tv/t/could-not-be-compiled-try-rebuilding-from-source-manually/7953/25
加了点新东西常常就会编译失败,提示could not be compiled Try rebuilding from source,如果是生成VS项目失败,可以打开对应的LOG文件:

MyDemo\Saved\Logs\MyDemo.log

.uproject文件里的AdditionalDependencies与.Build.cs里的PublicDependencyModuleNames

参考:https://forums.unrealengine.com/t/what-does-the-additionaldependencies-field-mean-in-uproject-modules-section/589091

貌似都是用来描述Module之间的依赖情况的,貌似在.uproject文件里写AdditionalDependencies的方式已经过时了


Attach到项目

多的不说了,网上都有,主要是源码Attach到具体的项目的设置:
在这里插入图片描述

我发现路径里好像不能有空格,而且Epic Games这玩意儿可开可不开,attach之后如果还让选择项目,应该就是前面输入的路径不对了


Debug蓝图工程和C++工程

二者好像Debug方法不一样,参考:https://answers.unrealengine.com/questions/449653/how-to-run-visual-studio-debugger-on-ue4-source.html

如果用对应的UE4的exe(应该是源码搞出来的exe)打开了项目,然后用vs源码工程attach到对应的process即可

如果要Debug蓝图项目,直接在UE4的C++工程里,F5,打开对应的项目即可。如果是Debug C++项目,这样做好像不行,不知道为啥会报错。这种情况下,好像只能在Source里创建对应的C++工程,然后打开对应C++工程的sln文件,在里面可以Debug UE4的源码,不过这里好像要rebuild ue4源码

感觉很麻烦,不知道有没有更好的方法


UE4的icon路径

E:\UnrealEngine\Engine\Content\Editor\Slate\


UE4的Build方式

参考:https://www.reddit.com/r/unrealengine/comments/d2dqen/unreal_engine_source_code_overviewguidestutorials/

在Runtime或者Editor文件夹里,里面有很多文件夹,每一个都包含一个或者多个modules,每个module都有一个build.cs文件来表明如何build这个模块,它也表明了模块之间的依赖关系。

当编译和启动UE4引擎时,它会启动一个UnreaBuildTool工具,它会去寻找所有modules里的build.cs文件,使用它来Compile和Link模块,感觉这玩意儿类似于CmakeList和Premake5.lua文件,对于每个module,它生成的东西会放到Binary文件夹里,比如dll、obj等文件,会在run Editor的时候加载这些玩意儿。把引擎module化是为了防止每次修改内容,都需要rebuild整个引擎,而是
只会rebuild对应的module,和受其影响的其他部分。

I recommend looking at Rama’s tutorials on the wiki for building modules and looking at his plugins he’s released. You’ll get a good idea about how the editor works.

详细的参考:https://www.cnblogs.com/FlyingZiming/p/15017445.html

这玩意儿还挺恶心的,比如我引入了一个类的头文件,然后编译报错,提示找不到对应类的函数定义,然后查了半天才发现,要在项目对应的Build.cs文件里添加对应的模块的引用,而这玩意儿貌似是不会反映到VS的项目属性上的


为什么模块代码文件要区分Public和Private目录?

参考:https://zhuanlan.zhihu.com/p/107270501

由于有的API是可以暴露出去的,有的不可以,所以UE4把所有导出的API的对应头文件放到了Public文件夹下,如果这里的模块不会被任何模块引用,那么可以不区分Public和Private目录


UE4哪些文件被包含在PCH里

最近很容易一不小心改了代码,就改到了PCH里的东西,就要全部Rebuild,很头疼

看了下UE4的核心Engine.Build.cs文件,发现里面有这个:

PrivatePCHHeaderFile = "Private/EnginePrivatePCH.h";
SharedPCHHeaderFile = "Public/EngineSharedPCH.h";

然后发现我改动的一个文件叫AnimationAsset.h,在两个文件里都出现了,表示它是PCH里的东西,好吧,下次不改这个了。

不过PrivatePCH和SharedPCH有啥区别呢?

PrivatePCH是给本模块用的PCH,Shared PCH是给依赖本模块的模块用的PCH,可以看到EngineSharedPCH里的内容比EnginePrivatePCH的内容略多


UE源码工程每次都重新编译

参考:https://forums.unrealengine.com/t/how-to-compile-in-non-unity-mode/94863/3
参考:https://forums.unrealengine.com/t/waiting-for-git-status-command-to-complete-making-for-long-compile-times/412358/3

就算我有一个不重要的cpp的微小改动,也会重新编译整个工程,耗时很久。看了下,好像跟UE默认的unity build有关。Build信息如下所示:

19>------ Build started: Project: SlateViewer, Configuration: Development_Program x64 ------
7>Log file: D:\UnrealSource\UnrealEngine\Engine\Programs\UnrealBuildTool\Log.txt
7>Using 'git status' to determine working set for adaptive non-unity build (D:\UnrealSource\UnrealEngine).

上面提示,可以使用git status来决定使用non-unity build,查了下,好像跟引擎默认的Build设置有关,默认设置是只要有git,就会使用它,把它记录的这些文件从unity build里排除掉,从而减少编译时间。

排除掉之后,应该是走的正常的Build流程了,不过看他这个意思,开着这玩意儿不是能减少编译时间的?

具体做法如下,在路径UnrealSource\UnrealEngine\Engine\Saved\UnrealBuildTool下,把文件改成:

<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<SourceFileWorkingSet> 
<Provider>None</Provider> 
<RepositoryPath></RepositoryPath> 
<GitPath></GitPath> 
</SourceFileWorkingSet>
</Configuration>

还有一些类似的设置:

<?xml version="1.0" encoding="utf-8" ?><Configuration xmlns="https://www.unrealengine.com/BuildConfiguration"><BuildConfiguration><bUseUnityBuild>false</bUseUnityBuild><bUsePCHFiles>false</bUsePCHFiles></BuildConfiguration>
</Configuration>

然后又要重新整个编译。。。。。

试了下这个黑科技http://www.morecpp.cn/ue-opensource-project-trigger-compile/,没用


关于Makefile类型的C++ Project

主要是看到UE里创建的C++项目类型为Makefile,而且相关的属性配置设置非常少,所以有这个疑问,如下图所示:
在这里插入图片描述

参考:https://learn.microsoft.com/en-us/cpp/build/reference/creating-a-makefile-project?view=msvc-170

A makefile is a text file that contains instructions for how to compile and link (or build) a set of source code files. A program (often called a make program) reads the makefile and invokes a compiler, linker, and possibly other programs to make an executable file. The Microsoft program is called NMAKE.

什么是Makefile,其实我是知道的,早在没有VS这种大型IDE之前,就是使用makefile来把各个cpp和头文件整合到一起,编译出结果的,Makefile本质就是个text文件。但这里的Makefile Project,我就不是特别清楚了。

这里创建一个Windows上的起始Makefile项目看看,需要输入这些东西:
在这里插入图片描述

创建之后,发现仍然可以加入cpp文件:
在这里插入图片描述
但是加入cpp之后,直接编译项目,并没有什么东西生成,而是提示我没有加commandline:

 warning MSB8005: The property 'NMakeReBuildCommandLine' doesn't exist.  Skipping...

所以我理解的是,VS里的makefile project,应该就是把传统makefile的规则,存到了vsproject里,用于自定义命令行的项目构建,就是套了VS的壳,再用makefile的方式去构建项目。

拿我这个UE项目对应的makefile project举例,它的两个重要设置为:

  • Commandline Argumens:“$(SolutionDir)MyProject.uproject” -skipcompile
  • Build Commandline:D:\UE_5.1\Engine\Build\BatchFiles\Build.bat MyProjectEditor Win64 DebugGame -Project=“$(SolutionDir)MyProject.uproject” -WaitMutex -FromMsBuild

最后我rebuild工程时执行的命令是这样的:

Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" MyProjectEditor Win64 DebugGame -Project="F:\UnrealProjects\MyProject\MyProject.uproject" -WaitMutex -FromMsBuild -Rebuild

就是调用UnrealBuildTool去分析这个MyProject.uproject文件而已,后续应该做了具体的项目build设置。

总结下来就是,这个Makefile Project没有做真正的build工作,在build这个工程时,它只是调用了UE的UnrealBuildTool,然后基于项目的uproject文件,让UnrealBuildTool去进行真正的build工作。


UE的IWYU

参考:https://docs.unrealengine.com/5.2/en-US/include-what-you-use-iwyu-for-unreal-engine-programming/

我之前搭建引擎的时候,引擎用到的核心头文件,都放到hzpch.h文件里,然后引擎里的每个cpp都要在第一行#include "hzpch.h",大概是这样:

#pragma once
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <memory>
#include <map>
#include <unordered_map>
#include <set>
#include <functional>
#include "Hazel/Core/Log.h" // include了引擎自定义的头文件
#include <fstream>#include <filesystem>
...

老版本的UE里,比如UE4.0的引擎源码里,基本也是这种模式,它把核心常用的文件全部放到了Engine.h里,内部有众多Include文件:

// 它这里应该没用啥标准库的东西, 所以都是include的自定义头文件
#include "BlueprintUtilities.h"
#include "Tickable.h"						// FTickableGameObject interface.
#include "RenderingThread.h"				// for FRenderCommandFence
#include "GenericOctreePublic.h"			// for FOctreeElementId
#include "RenderResource.h"					// for FRenderResource
#include "HitProxies.h"						// Hit proxy definitions.
#include "Engine/EngineBaseTypes.h"
...

然后每个cpp都在第一行引用Engine,h,也就是常用的pch模式,Editor模块下的代码应该是统一引用UnrealEd.h


这种做法,叫做including monolithic header files,对于引擎里的cpp而言,很多时候其实没必要include这么多内容,所以UE引入了IWYU,Include What You Use,这项技术一般只有引擎内部会使用IMYU,而项目是禁用IMYU的。注意IMYU并不是传统的cpp include header的方法,它仍然使用了PCH文件,只不过是不再需要在cpp的第一行include pch文件了,相关操作会借助UBT在命令行参数里执行

相关要点如下:

  1. 如果需要启用IMYU,需要:在module的build.cs里,在ModuleRules的构造函数里,设置PCHUsage类型为UseExplicitOrSharedPCHs
  2. 使用IMYU的前提有:cpp里不再include pch对应的Monolithic文件,而是要在第一行Include对应的头文件
  3. UE源码默认开IMYU,UE C++项目默认禁用IMYU,可以在项目里开启IMYU加快编译速度

>[Adaptive Build] Excluded from PoseSearch unity file: xxx.cpp

编译源码工程的时候出现的提示,貌似只是说这些代码不在原本的联合编译里,需要单独编译而已,应该不影响最终编译结果


UE Rebuild的头疼问题

参考:https://forums.unrealengine.com/t/how-to-prevent-plugin-recompilation/473557/5
参考:https://forums.unrealengine.com/t/engine-constantly-recompiles/438846/3

分为以下几种细分情况:

  • 改变源码时Rebuild,如果是改了PCH文件也还可以理解,但是改动插件里东西也全部Rebuild就不合理了
  • 用源码创建的VS工程,再去Build,会连带重新Rebuild依赖的源码工程
  • UE游戏项目工程里从Market上,或者外部放进去的Plugin,即使没改动,也每次都随游戏工程Rebuild

有几个疑问:

  • 在对应Module的Build.cs文件里可以设置bUsePrecompiled = true,貌似可以防止Plugin Rebuild,这个参数怎么用?

使用源码工程创建的VS项目需要Rebuild

仔细看看Configuration,需要确保VS项目跟源码工程的Configuration Type相同,如果不是,改下VS项目的Configuration即可,应该就不需要Rebuild了



关于UE的Unreal Build Tool(UBT)

参考:https://docs.unrealengine.com/5.0/en-US/unreal-engine-build-tool-target-reference/

几个问题:

  • UBT是不是用于打包项目的设置?
  • 插件对应intermediate文件夹下的Module.PoseSearchEditor.cpp代码是由谁生成的、有什么用

前言

正常Build VS工程时,拿我写的游戏引擎举例,里面有这么些项目,除了Glad和GLFW里都是c语言的文件,其他的都是cpp工程:

  • imgui
  • YAML_CPP
  • Glad
  • GLFW
  • 2DPhysicsEngine
  • Hazel
  • HazelEditor

一共七个项目,其中HazelEditor为启动项目,它依赖Hazel,而Hazel又依赖其他的五个项目

如果此时从零开始Build,此时会多线程一起开始build这五个前置项目,命令行输出的为:

Build started...
1>------ Build started: Project: imgui, Configuration: Debug x64 ------
2>------ Build started: Project: YAML_CPP, Configuration: Debug x64 ------
3>------ Build started: Project: Glad, Configuration: Debug x64 ------
4>------ Build started: Project: GLFW, Configuration: Debug x64 ------
5>------ Build started: Project: 2DPhysicsEngine, Configuration: Debug x64 ------
1>imgui.cpp
2>binary.cpp
3>glad.c
4>context.c
5>b2_broad_phase.cpp
5>b2_chain_shape.cpp
4>egl_context.c
2>graphbuilder.cpp
5>b2_circle_shape.cpp
5>b2_collide_circle.cpp
...
3>Glad.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\Glad\bin\Debug-windows-x86_64\Glad\Glad.lib
...
1>Generating Code...
...
1>imgui.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\imgui\bin\Debug-windows-x86_64\imgui\imgui.lib
5>Generating Code...
...
4>Generating Code...
...
5>Generating Code...
5>Compiling...
5>b2_weld_joint.cpp
4>GLFW.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\GLFW\bin\Debug-windows-x86_64\GLFW\GLFW.lib
5>Generating Code...
5>2DPhysicsEngine.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\box2D\bin\Debug-windows-x86_64\2DPhysicsEngine\2DPhysicsEngine.lib
...
2>Generating Code...
2>Compiling...
2>Generating Code...
2>YAML_CPP.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\yaml-cpp\bin\Debug-windows-x86_64\YAML_CPP\YAML_CPP.lib.

大概流程应该是:

  • Build Start:xxx项目
  • 输出Generating Code...、或者Compiling...之类的指令,应该是隔一段时间或编译一些文件就会打一次这个Log
  • 最后打印xxx.vcxproj -> Path\output

接下来也是类似的:

6>------ Build started: Project: Hazel, Configuration: Debug x64 ------
hzpch.cpp
...
6>Generating Code...
...
6>Compiling...
6>Ws2_32.lib(WS2_32.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored
6>Bcrypt.lib(bcrypt.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored
6>Version.lib(VERSION.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored
6>Winmm.lib(WINMM.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored
6>shaderc_sharedd.lib(shaderc_sharedd.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored
6>Hazel.vcxproj -> D:\GitRepositories\Hazel\bin\Debug-windows-x86_64\Hazel\Hazel.lib
6>Done building project "Hazel.vcxproj".
7>------ Build started: Project: HazelEditor, Configuration: Debug x64 ------
xxx.cpp
...
7>Defining YAML_CPP_API for DLL import
...
7>Generating Code...
7>D:\GitRepositories\Hazel\Hazel\Src\Hazel\Scripting\Scripting.h(36): warning C4172: returning address of local variable or temporary: value
7>Hazel.lib(object.obj) : warning LNK4099: PDB '' was not found with 'Hazel.lib(object.obj)' or at ''; linking object as if no debug info
...
7>HazelEditor.vcxproj -> D:\GitRepositories\Hazel\bin\Debug-windows-x86_64\HazelEditor\HazelEditor.exe
7>Done building project "HazelEditor.vcxproj".
========== Build: 7 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build started at 4:25 PM and took 44.797 seconds ==========

当每个单独的Project build完毕后,打印一个总结


再来看看UE的build日志,UE5的build start project就叫UE5,它只依赖UnrealBuildTool,如下图所示:
在这里插入图片描述

由于它使用了UBT,其Build Log会不太一样,因为工程太大了,这里选择Build而不是Rebuild,开头如下所示:

Build started...
1>------ Build started: Project: UE5, Configuration: Debug_Editor x64 ------
1>Using bundled DotNet SDK version: 6.0.302
1>Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" -Target="UnrealEditor Win64 Debug" -Target="ShaderCompileWorker Win64 Development -Quiet" -WaitMutex -FromMsBuild

第三行并没有直接编译cpp的log信息,是因为UE5的Project Configuration Type并不是exe或者lib,而是Makefile类型,可以看到当前项目下的它的build命令行:
在这里插入图片描述
这意味着它会去调用Build.bat文件,看了下该文件,大概是以下步骤:

  1. 检查一些文件夹的存在、CD到对应路径
  2. 检查.NET的SDK
  3. 检查UnrealBuildTool.dll的存在,若不存在,则用Visual Studio build UnrealBuildTool项目
  4. 调用UnrealBuildTool.exe

Build.bat文件信息如下,可以参考下:


setlocal enabledelayedexpansion// 1. cd到Source文件夹
if not exist "%~dp0..\..\Source" goto Error_BatchFileInWrongLocationpushd "%~dp0\..\..\Source"
if not exist ..\Build\BatchFiles\Build.bat goto Error_BatchFileInWrongLocation// UBTPath为UnrealBuildTool.dll的相对路径
set UBTPath="..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll"// 2. 调用当前目录的GetDotnetPath.bat,获取.NET
call "%~dp0GetDotnetPath.bat"
if errorlevel 1 goto Error_NoDotnetSDK
REM ## Skip msbuild detection if using dotnet as this is done for us by dotnet-clirem ## If this is an installed build, we don't need to rebuild UBT. Go straight to building.
if exist ..\Build\InstalledBuild.txt goto ReadyToBuildrem ## Compile UBT if the project file exists
:ReadyToBuildUBT
set ProjectFile="Programs\UnrealBuildTool\UnrealBuildTool.csproj"
if not exist %ProjectFile% goto NoProjectFilerem ## Only build if UnrealBuildTool.dll is missing, as Visual Studio or GenerateProjectFiles should be building UnrealBuildTool
rem ## Note: It is possible UnrealBuildTool will be out of date if the solution was generated with -NoDotNet or is VS2019
rem ##       Historically this batch file did not compile UnrealBuildTool
if not exist %UBTPath% (rem ## If this script was called from Visual Studio 2022, build UBT with Visual Studio to prevent unnecessary rebuilds.if "%VisualStudioVersion%" GEQ "17.0" (echo Building UnrealBuildTool with %VisualStudioEdition%..."%VSAPPIDDIR%..\..\MSBuild\Current\Bin\MSBuild.exe" %ProjectFile% -t:Build -p:Configuration=Development -verbosity:quiet -noLogoif errorlevel 1 goto Error_UBTCompileFailed) else (echo Building UnrealBuildTool with dotnet...dotnet build %ProjectFile% -c Development -v quietif errorlevel 1 goto Error_UBTCompileFailed)
)
:NoProjectFilerem ## Run UBT
:ReadyToBuild
if not exist %UBTPath% goto Error_UBTMissing
echo Running UnrealBuildTool: dotnet %UBTPath% %*
dotnet %UBTPath% %*
EXIT /B !ERRORLEVEL!:Error_BatchFileInWrongLocation
echo ERROR: The batch file does not appear to be located in the Engine/Build/BatchFiles directory. This script must be run from within that directory.
EXIT /B 999:Error_NoDotnetSDK
echo ERROR: Unable to find an install of Dotnet SDK.  Please make sure you have it installed and that `dotnet` is a globally available command.
EXIT /B 999:Error_UBTCompileFailed
echo ERROR: Failed to build UnrealBuildTool.
EXIT /B 999:Error_UBTMissing
echo ERROR: UnrealBuildTool.dll not found in %UBTPath%
EXIT /B 999

总的来说,在Build UE5这个project时,它这个Makefile工程所做的,其实就是调用UnrealBuildTool.exe而已,只是个空壳子,我试了下,可以直接在Build.bat路径下,直接在命令行输入以下指令,一样会触发编译:

F:\UnrealEngine\Engine\Build\BatchFiles>dotnet "..\..\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll"  -Target="UnrealEditor Win64 Debug" -Target="ShaderCompileWorker Win64 Development -Quiet" -WaitMutex -FromMsBuild

这里的dotnet貌似是.NET Core提供的命令行关键字,用于调用.NET程序,不过这里居然调用的是dll,不是exe,也是挺奇怪的,如下图所示是该命令的介绍:
在这里插入图片描述


UnrealBuildTool

参考:UE4 UnrealBuildTool 执行流程
参考:Build flow of the Unreal Engine4 project

Build.bat会把参数都传给UnrealBuildTool.exe,参数可以在bat里看到:

rem ##     %1 is the game name
rem ##     %2 is the platform name
rem ##     %3 is the configuration name
rem ##     additional args are passed directly to UnrealBuildTool

命令行举例:

三个参数分别为:game name、 platform name、configuration name
UnrealBuildTool.exe MyTest Win64 Development "C:\Users\visionsmile\Documents\Unreal Projects\Examples\MyTest \MyTest .uproject" -WaitMutex -FromMsBuild

对应到下面的参数,就是这上面的六个参数,最后一个为-FromMsBuild

/// <summary>
/// Main entry point. Parses any global options and initializes the logging system, then invokes the appropriate command.
/// NB: That the entry point is deliberately NOT async, since we have a single-instance mutex that cannot be disposed from a different thread.
/// </summary>
/// <param name="ArgumentsArray">Command line arguments</param>
/// <returns>Zero on success, non-zero on error</returns>
private static int Main(string[] ArgumentsArray)
{...

虽然这里的Build.bat传入了三个参数,但UBT实际需要四个参数:
%1 is the game name
%2 is the platform name
%3 is the configuration name
%4 is the ProjectPath

直接打开UBT对应的.sln文件,在Main函数里可以输入Commandline参数,直接Debug进行编译:

private static int Main(string[] ArgumentsArray)
{ArgumentsArray = new string[]{"-Target=UnrealEditor Win64 Debug","-Target=ShaderCompileWorker Win64 Development -Quiet","-WaitMutex","-FromMsBuild"};...
}

UBT会创建帮助编译的Makefile.bin文件,比如生成以下路径的MakeFile:

F:\UnrealEngine\Engine\Intermediate\Build\Win64\x64\UnrealEditor\Debug\Makefile.bin

这玩意儿是个二进制文件,很难直接阅读,这里来研究一下UBT写入了什么内容。为了生成MakeFile,UBT首先要确定build的目标,因而创建一个UEBuildTarget类的对象,如下所示:

// If we couldn't load a makefile, create a new one
if(Makefile == null)
{// Create the targetUEBuildTarget Target;...
}

看了下创建出来的BuildTarget对象,貌似它要Build的分为四种Module

  • Binary Module:最终打出的exe对象,只有一个,即这里的UnrealEditor.exe,也叫做Launch Module
  • Project Module:每个引擎内的Plugin,一般要出至少两个dll,一个用在Editor下,一个用于Runtime,这里应该是每个Build.cs文件对应一个dll
  • Plugin Module:每个引擎内的Module,也应该是每个Build.cs文件对应一个dll
  • ExtraModule:特殊的引擎Module,比如Build UnrealEditor.exe需要"UnrealGame"这个ExtraModule

这个Extra Module是在Target.cs里决定的,如下所示是引擎的UnrealEditor.Target.cs

public class UnrealEditorTarget : TargetRules
{public UnrealEditorTarget( TargetInfo Target ) : base(Target){Type = TargetType.Editor;IncludeOrderVersion = EngineIncludeOrderVersion.Latest;BuildEnvironment = TargetBuildEnvironment.Shared;bBuildAllModules = true;ExtraModuleNames.Add("UnrealGame");}
}

各自的Module都对应了各自的Build.cs文件,路径依次为:

  • ModuleNameToModuleFile["Launch"] {F:\UnrealEngine\Engine\Source\Runtime\Launch\Launch.Build.cs} EpicGames.Core.FileReference
    ·

数了下引擎里有1743个Build.cs文件,这里创建的BuildTarget里的Binaries数组有1453个元素,感觉是差不多对应的上的,这里会先处理Launch Module,处理的过程应该是个DFS的过程,如下图所示,可以看到它依赖了63个Module,应该是全游戏需要的Module的Root
在这里插入图片描述

Launch Module对应了文件,也即UE提供的四个引擎Target.cs文件之一,

  •   TargetRulesFile	{F:\UnrealEngine\Engine\Source\UnrealEditor.Target.cs}	EpicGames.Core.FileReference
    

intermediate文件夹下的Module.PoseSearchEditor.cpp代码

这个cpp是由UBT生成的,可以看下里面的内容:

// This file is automatically generated at compile-time to include some subset of the user-created cpp files.
#include "../Plugins/Experimental/Animation/PoseSearch/Intermediate/Build/Win64/UnrealEditor/Inc/PoseSearchEditor/UHT/AnimationBlendStackGraph.gen.cpp"
...
#include "../Plugins/Experimental/Animation/PoseSearch/Source/Editor/Private/AnimationBlendStackGraphSchema.cpp"
...

貌似是把项目里所有的cpp文件和.gen.cpp文件,都include进来了,这里有几个问题:

  • 为啥cpp也要include进来,它们不是自身就会被编译吗,搞这个联合编译cpp是做啥的

我顺便查了下我之前写的AnimationPreviewLibrary的Editor Plugin,里面创建了四个cpp,UE的UBT同样在对应的intermediate文件夹里生成了Module.AnimationPreviewLibrary.cpp,如下所示:

// This file is automatically generated at compile-time to include some subset of the user-created cpp files.
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/AnimationPreviewLibrary.cpp"
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/AnimationPreviewLibraryCommands.cpp"
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/AnimationPreviewLibraryStyle.cpp"
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/SAnimPreviewLibraryWindowMenu.cpp"

我理解这个文件,就是为了方便编译的,搞个unity file,把一个模块的所有的cpp都引入进去,方便管理,这样一来,比如UE有130个Module,那就只需要编译和link这130个各自Module对应的cpp文件(类似于Translation Unit)即可

如下是UBT的流程
在这里插入图片描述


UBT生成的Definition.xxx.h文件

UBT会为Module生成一个特殊的cpp文件,Build的时候去编译这个cpp,Link对应的object即可,在此过程中,UBT还生成了涉及到宏的Definition.xxx.h文件,如下图所示:
在这里插入图片描述

几个问题:

  • 此文件是基于什么生成的,是Build.cs文件吗

这个文件还有别于这里的Module.xxxx.cpp,因为实际工程里是不需要后者这个unity file的,而这个Definitions.xxx.h里的宏则是实际工程里需要的,如下图所示,我这里的工程貌似没找到此文件,所以辨认不出这个宏:
在这里插入图片描述
宏的颜色应该是紫色的,这里的intellisense都没辨认出来是宏,所以相关的intellisense都失效了,虽然build是没有任何问题的,但这个问题很影响我看代码了,我可以临时参照Definition文件加一句这个:

#ifndef POSESEARCH_API
#define POSESEARCH_API DLLIMPORT
#endif

但还是挺难受的,所以这里的问题是,这里面定义的宏,是如何影响到VS项目里的高亮的,为啥有的项目里F12能直接跳转到Definition.xxx.h文件,但是工程里又搜不到此文件:
在这里插入图片描述


UE Editor添加C++的Plugin失败

C++工程创建插件时报错,显示Unable to create plugin,如下图所示:
在这里插入图片描述
有时候删除所有的中间文件(包括Plugin的中间文件)、在Regenerate Sln文件后,就可以打开了。但我在创建第三方插件时,怎么做都会报这个错。图中的Output log应该指的是Console,重点信息如下:

Building 5 actions with 5 processes...
[1/5] Resource Default.rc2
[2/5] Link [x64] UnrealEditor-ffff3213213-Win64-DebugGame.dll cancelled
[3/5] Link [x64] UnrealEditor-ffff3213213-Win64-DebugGame.lib cancelled
[4/5] Compile [x64] ffff3213213.cpp
F:\UnrealProjects\MotionMatchingDemoDebug\Plugins\ffff3213213\Source\ffff3213213\Private\ffff3213213.cpp(7): fatal error C1083: Cannot open include file: 'ffff3213213Library/ExampleLibrary.h': No such file or directory
[5/5] WriteMetadata MotionMatchingDemoEditor-Win64-DebugGame.target cancelled

最后大概找到原因了,我是用自己的引擎版本创建的VS工程,然后我删除中间文件后,右键uproject Regenerate Sln文件却是用的安装好的UE引擎,此时去创建就会有问题(具体原因是为什么,我还不确定,中间文件不是都删除了么,跟引擎版本应该没有关系啊?)

我把中间文件全删了,然后源码直接attach uproject文件,再在Editor里生成VS工程,再去创建第三方插件,就可以了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

flv视频格式批量截取封面图(不占内存版)--其他视频格式也通用

flv视频格式批量截取封面图&#xff08;不占内存版&#xff09;--其他视频格式也通用 需求&#xff08;实现的效果&#xff09;功能实现htmlcssjs 需求&#xff08;实现的效果&#xff09; 批量显示视频&#xff0c;后端若返回有imgUrl,则直接显示图1&#xff0c; 若无&#xf…

Socket套接字类编译测试

目录 类设计 类实现 测试 测试服务器 测试客户端 测试结果 这一节相当于整合了之前的一些东西&#xff0c;重新过了一遍&#xff0c;这个就显得相对之前的版本更加完善一点 类设计 // 套接字类 #define MAX_LISTEN 1024 class Socket {private:int _sockfd;public:Socke…

闲人闲谈PS之五十三——离散制造中的魔鬼--物料套裁

惯例闲话&#xff1a;最近和老婆大人商议买车事宜&#xff0c;闲人以为会陷入买油车还是电车的纠结&#xff0c;没想到老婆大人无比坚定&#xff0c;买电车。在买车这方面&#xff0c;老婆的想法居然比闲人超前。闲人对车定位在代步工具&#xff0c;2年前&#xff0c;对车还是印…

SAP下载word

事务代码&#xff1a;STRANS 启动转换器 步骤 1. 将参数填入模板&#xff0c;并另存为word 2003 xml文档 2.使用网页打开xml文档&#xff0c;并将xml拷贝到转换器tt:template中&#xff0c;添加参数 3.替换参数&#xff0c;部分xml可能存在错误或者跑偏根据实际情况检查修改 …

洛谷 P1980 [NOIP2013 普及组] 计数问题

题目背景 NOIP2013 普及组 T1 题目描述 试计算在区间 1 到 n 的所有整数中&#xff0c;数字 x&#xff08;0≤x≤9&#xff09;共出现了多少次&#xff1f;例如&#xff0c;在 1 到 11 中&#xff0c;即在 1,2,3,4,5,6,7,8,9,10,11 中&#xff0c;数字 1 出现了 4 次。 输入…

Ubuntu18.04安装Matlab流程笔记

提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 Ubuntu18.04 安装Matlab流程 下载安装包和破解文件安装Matlab注册并运行 下载安装包和破解文件 matlabR2019A源码 提取码:2ztb 下载的Linux matlab2018a文件夹内有三个文件&#xff1a; # 解压Matlab201…

<网络安全>《15 移动安全管理系统》

1 概念 移动安全管理系统&#xff0c;MSM&#xff0c;Mobile security management,提供大而全的功能解决方案&#xff0c;覆盖了企业移动信息化中所涉及到安全沙箱、数据落地保护、威胁防护、设备管理、应用管理、文档管理、身份认证等各个维度。移动安全管理系统将设备管理和…

freeswitch对接FunASR实时语音听写

1、镜像启动 通过下述命令拉取并启动FunASR软件包的docker镜像&#xff1a; sudo docker pull \registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.7 mkdir -p ./funasr-runtime-resources/models sudo docker run -p 10096:10095 -i…

elementUI中el-tree组件单选没有复选框时,选中、current-node-key高亮、刷新后保留展开状态功能的实现

目录 一、代码实现1. 属性了解 &#xff08;[更多](https://element.eleme.cn/#/zh-CN/component/tree)&#xff09;2. 实现步骤3.代码示例 二、 效果图 一、代码实现 1. 属性了解 &#xff08;更多&#xff09; node-key 每个树节点用来作为唯一标识的属性&#xff0c;整棵树…

Linux 磁盘空间占用率100%的排查

&#x1f4d1;前言 使用 Linux 操作系统时&#xff0c;可能会遇到磁盘空间不足的错误&#xff0c;这种错误通常会导致系统运行缓慢或崩溃。本文将介绍磁盘排查的方法。⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1…

rust gui开发框架选择

作为一个系统编程强大语言&#xff0c;怎么能少得了图形界面的开发 实际上写这篇前我也不知道&#xff0c;于是我问了ai大模型&#xff0c;文心3.5和chatgpt4.0 答案实际上不能满意&#xff0c;最后我做了下筛选 参考博文&#xff1a; rust开发环境配置&#xff1a;链接 一、…

MacOS安装JDK+Maven+Idea插件+nvm等

Java安装环境(MacOS)JDKMavenIdea插件nvm等 背景&#xff1a;新机安装开发环境发现需要找很多文章&#xff0c;&#xff0c;&#xff0c;&#xff0c;这里一篇文章安装所有环境 文章目录 Java安装环境(MacOS)JDKMavenIdea插件nvm等一、安装JDK①&#xff1a;下载②&#xff1a;…

阿里云a10GPU,centos7,cuda11.2环境配置

Anaconda3-2022.05-Linux-x86_64.sh gcc升级 centos7升级gcc至8.2_centos7 yum gcc8.2.0-CSDN博客 paddlepaddle python -m pip install paddlepaddle-gpu2.5.1.post112 -f https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html 报错 ImportError: libssl.so…

C++ pair+map+set+multimap+multiset+AVL树+红黑树(深度剖析)

文章目录 1. 前言2. 关联式容器3. pair——键值对4. 树形结构的关联式容器4.1 set4.1.1 set 的介绍4.1.2 set 的使用 4.2 map4.2.1 map 的介绍4.2.2 map 的使用 4.3 multiset4.3.1 multiset 的介绍4.3.2 multiset 的使用 4.4 multimap4.4.1 multimap 的介绍4.4.2 multimap 的使…

Latex学习记录

目录 1.Latex各种箭头符号总结 2.[Latex]公式编辑&#xff0c;编号、对齐 3.Latex公式编号: 多行公式多编号&#xff0c;多行公式单编号 4.LaTex中输入空格以及换行 1.Latex各种箭头符号总结 箭头符号 - ➚ (piliapp.com)https://cn.piliapp.com/symbol/arrow/Latex各种箭头…

Flutter 开发3:创建第一个Flutter应用

Step 1: 安装Flutter 1.1 下载Flutter SDK 首先&#xff0c;你需要访问Flutter官方网站下载最新的Flutter SDK。选择适合你操作系统的安装包。 $ cd ~/development $ unzip ~/Downloads/flutter_macos_2.2.3-stable.zip1.2 更新环境变量 接下来&#xff0c;你需要将Flutter…

网络异常案例四_IP异常

问题现象 终端设备离线&#xff0c;现场根据设备ip&#xff0c;ping不通。查看路由器。 同一个路由器显示的终端设备&#xff08;走同一个wifi模块接入&#xff09;&#xff0c;包含不同网段的ip。 现场是基于三层的无线漫游&#xff0c;多个路由器wifi配置了相同的ssid信息&a…

springBoot静态资源文件夹以及文件夹之间的优先级

1、springBoot静态资源文件夹&#xff0c;系统默认路径&#xff0c;优先级由大到小 classpath:/META-INF/resources/ classpath:/resources/ classpath:/static/ classpath:/public/ 比如当static文件夹中和public文件夹中都存在a.html 浏览器访问localhost:8080/a.html将访问…

ref和reactive

看尤雨溪说&#xff1a;为什么Vue3 中应该使用 Ref 而不是 Reactive&#xff1f;

pintia6-2符号函数 6-1两点距离

pintia的函数题&#xff0c;只需要把函数写上去就可以了&#xff0c;6-2函数题比较简单&#xff0c;三个if就可以解决: 6-1则套用数学公式即可&#xff0c;注意把函数名复制粘贴过去&#xff0c;以免抄错