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目标类型为Game
		DefaultBuildSettings = 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目标类型为Editor
		DefaultBuildSettings = 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_BatchFileInWrongLocation

pushd "%~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-cli

rem ## If this is an installed build, we don't need to rebuild UBT. Go straight to building.
if exist ..\Build\InstalledBuild.txt goto ReadyToBuild

rem ## Compile UBT if the project file exists
:ReadyToBuildUBT
set ProjectFile="Programs\UnrealBuildTool\UnrealBuildTool.csproj"
if not exist %ProjectFile% goto NoProjectFile

rem ## 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 -noLogo
		if errorlevel 1 goto Error_UBTCompileFailed
	) else (
		echo Building UnrealBuildTool with dotnet...
		dotnet build %ProjectFile% -c Development -v quiet
		if errorlevel 1 goto Error_UBTCompileFailed
	)
)
:NoProjectFile

rem ## 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 target
	UEBuildTarget 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工程,再去创建第三方插件,就可以了。

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要设置UE源码编译平台,需要按照以下步骤进行操作。 1. 获取Unreal Engine代码。可以通过Epic Games的GitHub仓库或者Unreal Engine官网下载源代码压缩包。 2. 解压缩源代码到本地计算机的合适位置。 3. 安装必要的软件和工具。编译Unreal Engine需要一些依赖软件和工具,例如Visual Studio(推荐使用VS2017或更高版本)、Windows SDK、DirectX、CMake等。根据Unreal Engine版本和所需功能进行适当安装。 4. 打开解压缩后的源代码目录,找到Setup.bat文件并运行。此脚本将执行一系列设置和配置操作,以确保编译环境的正确性。 5. 选择要编译的目标平台。根据项目需求,使用Setup.bat脚本提供的选项选择要编译的目标平台,例如Windows、Mac、Linux等。 6. 使用CMake生成项目文件。在源代码目录中,找到GenerateProjectFiles.bat文件并运行。此脚本将使用CMake生成项目文件。 7. 打开生成的项目文件。根据所用的开发工具,例如Visual Studio,使用生成的项目文件打开Unreal Engine。这将加载Unreal Engine代码,并准备进行编译。 8. 编译Unreal Engine。使用开发工具进行编译,确保选择正确的编译配置和目标平台。编译过程可能需要一些时间,具体时间取决于计算机性能和项目大小。 9. 完成编译后,可以开始使用编译后的Unreal Engine。根据需要,可以运行自己的项目或者使用Unreal Engine进行开发或测试。 需要注意的是,UE源码编译平台的设置过程可能会因个人计算机的配置和项目需求而略有差异。建议在参考官方文档和社区参考资料的基础上进行设置,并根据实际情况调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值