Windows上源码编译并使用Unreal Engine 5.1

起因

接手一个使用Unreal Engine 5.1 进行3D渲染的直播项目。开发过程中发现,用于3D渲染的程序,在生成时使用了Development配置,导致最终产物在性能表现和分发处理时均存在一些问题,需要切换Shipping配置重新生成。
原程序使用Unreal Engine官方提供的SDK生成,切换到Shipping配置后重新生成,发现了下列问题:

  1. 无日志输出。
  2. Shipping配置中加载场景的Actor的Display Name,与Debug/Developmen模式不一致。

一番调研后确认,上述问题无法通过修改配置文件解决,官方文档建议修改源码后重新编译SDK。

过程

获取源码

参考官网文档

  1. 关联Epic账号和GitHub账号
    Unreal Engine相关源码托管在GitHub上,需要加入@EpicGames组织才能下载。
    在GitHub上访问虚幻引擎源代码
  2. 克隆源码,切换分支
    1
    2
    3
    git clone https://github.com/EpicGames/UnrealEngine.git
    cd UnrealEngine
    git checkout 5.1.1-release # 使用5.1.1分支对应代码进行编译

注意:

因为服务商问题,仓库中部分二进制文件的下载链接失效,导致checkout时会出现报错:

1
Failed to download 'http://cdn.unrealengine.com/dependencies/UnrealEngine-16624087/135d2dfcfa4bbe7dd725f03f844323624525ed4a': The remote server returned an error: (403) Forbidden. (WebException)

官方给出的解决方案是,下载并更新仓库中的Engine/Build/Commit.gitdeps.xml 文件后,再重新执行checkout。
TAG对应的Commit.gitdeps.xml文件可以在GitHub上对应TAG的Release页面下载。
https://github.com/EpicGames/UnrealEngine/releases/tag/5.1.1-release

编译

  1. 生成工程
    1. 执行根目录下的Setup.bat
    2. 执行根目录下的GenerateProjectFiles.bat
  2. 编译工程
    打开根目录下的UE5.sln,设置配置为Development,平台为Win64,选择编译工程/Build Solution。

错误处理

因为工具链及版本的差异,编译时会出现一些错误,需要单独处理。

  • Error NU1904 Warning As Error: Package ‘System.Drawing.Common’ 4.7.0 has a known critical severity vulnerability
    部分三方库被发现了一些安全问题。Unreal Engine工程通过Nuget引入这些三方库时会触发警告。而工程本身又配置了将Nuget的警告视为报错,停止编译。
    考虑到之前用的官方SDK也存在这些安全问题,继续使用不会带来更坏的结果,但升级三方库可能会导致其他问题,重新编译时选择忽略这些警告。
    在VS中双击Error List对应错误,跳转到出错的.csproj文件。将
    1
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    修改为
    1
    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
  • SteamVRInputDeviceFunctionLibrary.cpp(513): error C4834: discarding return value of function with ‘nodiscard’ attribute
    参考https://forums.unrealengine.com/t/build-from-source-fails-with-errors-c4834-and-msb3073/1266696,修改```Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRInputDevice/Private/SteamVRInputDeviceFunctionLibrary.cpp```
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRInputDevice/Private/SteamVRInputDeviceFunctionLibrary.cpp b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRInputDevice/Private/SteamVRInputDeviceFunctionLibrary.cpp
    index 9277039ae4c589e0e741536b030dff40e8dbb3bd..ab43dd0fbf2bc595afa975d9a140391343cc4b29 100644
    --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRInputDevice/Private/SteamVRInputDeviceFunctionLibrary.cpp
    +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRInputDevice/Private/SteamVRInputDeviceFunctionLibrary.cpp
    @@ -510,7 +510,7 @@ bool UDEPRECATED_USteamVRInputDeviceFunctionLibrary::FindSteamVR_ActionOrigin(FN
    return true;
    }

    - GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, (TEXT("Unable to find Action [%s] for Action Set [%s]"), *ActionName.ToString(), *ActionSet.ToString()));
    + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Unable to find Action [%s] for Action Set [%s]"), *ActionName.ToString(), *ActionSet.ToString()));
    return false;
    }
  • ChaosUserDataPT.h(105): error C4458: declaration of ‘Solver’ hides class member
    修改Engine/Plugins/Experimental/ChaosUserDataPT/Source/ChaosUserDataPT/Public/ChaosUserDataPT.h
1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/Engine/Plugins/Experimental/ChaosUserDataPT/Source/ChaosUserDataPT/Public/ChaosUserDataPT.h b/Engine/Plugins/Experimental/ChaosUserDataPT/Source/ChaosUserDataPT/Public/ChaosUserDataPT.h
index b66e2b93fa70d894c1eb45d5084b8056ec8a5886..20b0a11a141e72cc05dc43ac386d09756b489817 100644
--- a/Engine/Plugins/Experimental/ChaosUserDataPT/Source/ChaosUserDataPT/Public/ChaosUserDataPT.h
+++ b/Engine/Plugins/Experimental/ChaosUserDataPT/Source/ChaosUserDataPT/Public/ChaosUserDataPT.h
@@ -102,7 +102,7 @@ namespace Chaos
{
SCOPE_CYCLE_COUNTER(STAT_UserDataPT_SetData_GT);

- if (const FPhysicsSolverBase* Solver = this->GetSolver())
+ if (this->GetSolver())
{
if (TInput* Input = this->GetProducerInputData_External())
{

代码修改

  • 分发模式下启用日志输出
    修改Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs,始终添加USE_LOGGING_IN_SHIPPING宏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs
index ecfa98e2c746dd15fb195261806b2a05e5c72a74..45b2632995a45deef609e3877f57b0a1b4468aa9 100644
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs
@@ -4099,14 +4099,7 @@ namespace UnrealBuildTool
GlobalCompileEnvironment.Definitions.Add("WITH_PERFCOUNTERS=0");
}

- if (Rules.bUseLoggingInShipping)
- {
- GlobalCompileEnvironment.Definitions.Add("USE_LOGGING_IN_SHIPPING=1");
- }
- else
- {
- GlobalCompileEnvironment.Definitions.Add("USE_LOGGING_IN_SHIPPING=0");
- }
+ GlobalCompileEnvironment.Definitions.Add("USE_LOGGING_IN_SHIPPING=0");

if (Rules.bLoggingToMemoryEnabled)
{
  • 分发模式下启用Actor的Display Name
    修改Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h,定义ACTOR_HAS_LABELS始终为1
1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
index 1632662a7825b5d6abf5ea7d95117e325454921f..830853e7bb3bd1a4bdf477e6bd470c5b0daadb89 100644
--- a/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
+++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
@@ -53,7 +53,7 @@ class UActorFolder;

// By default, debug and development builds (even cooked) will keep actor labels. Manually define this if you want to make a local build
// that keep actor labels for Test or Shipping builds.
-#define ACTOR_HAS_LABELS (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT || WITH_PROFILEGPU)
+#define ACTOR_HAS_LABELS 1

/** Chooses a method for actors to update overlap state (objects it is touching) on initialization, currently only used during level streaming. */
UENUM(BlueprintType)

分发

参考制作安装构建版本,在CMD中执行下列命令:

1
2
3
4
5
6
Engine\Build\BatchFiles\RunUAT.bat BuildGraph ^
-target="Make Installed Build Win64" ^
-script="Engine/Build/InstalledEngineBuild.xml" ^
-set:HostPlatformOnly=true ^
-set:WithDDC=false ^
-clean

之后在LocalBuilds目录下可以找到编译完成的Unreal Engine SDK。可以将目录打成7z包,分发给团队成员。
使用者解压后,运行一次Engine\Windows\Engine\Binaries\Win64\UnrealEditor.exe,会自动在系统中注册该版本的SDK。之后就可以正常使用切换版本/生成工程文件/打开编辑器等功能。