Create A Standalone Application in UE4

虽然 UE 是个 游戏引擎 ,但并不是只能写游戏——你甚至可以用来写 Win32 GUI 程序😏.
通常,我们使用 Editor 创建一个 UE 的游戏项目,然后在其基础上构建自己的类并在游戏中使用。但是如果不想要创建一个游戏项目,UE 也支持可以独立运行的程序 (Standalone Application),能够从main 函数来自主构建自己的程序,完全控制启用哪些 Modules,而不依赖于引擎本身的逻辑架构,也可以将其作为学习和测试 UE 模块的轻便方法。

:UE 并没有提供直接创建 Standalone Application 的方法,我自己写了一个创建Program 项目的工具:hxhb/ue4program,并实现了一个独立运行工具的 Demo:hxhb/UE4Launcher

Forward

本文的内容实践需要使用 本地从源码构建出来的引擎 (源码版引擎) 而非 从 EpicGameLauncher 安装的引擎 (安装版引擎),我之前的文章里介绍过 UBT 是检测是否存在Engine/Build/InstalledBuild.txt 该文件,来判断引擎是从 Launcher 安装的还是从源码编译的,但是源码版和安装版并不是只有这么多区别,一些 ThridParty 的 build.cs 是不一样的,会造成源码版和安装版引擎对于相同的代码会有不同的编译行为(比如Engine/Source/ThirdParty/HarfBuzz),虽然这些问题也可是可以搞定的,但是我不建议你那么做。

Create Program

首先,下载 我写的hxhb/ue4program,将其添加到系统的 PATH 路径中。添加之后的用法如下:

1
2
# ue4program.exe ProgramName
$ ue4program.exe StandaloneApplication

此时会在当前目录下创建出一个 StandaloneApplication 文件夹,其目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
StandaloneApplication
│ GenerateProgramProject.bat
│ OpenProgramProject.bat
│ StandaloneApplication.Build.cs
│ StandaloneApplication.Target.cs

├─Resources
│ Icon.ico
│ Resource.h
│ Resource.rc
│ VersionResource.inl

└─Source
├─Private
│ │ RealExecutionMain.cpp
│ │ StandaloneApplication.cpp
│ │
│ ├─Console
│ │ ConsoleMain.cpp
│ │
│ └─Windows
│ WindowsMain.cpp

└─Public
RealExecutionMain.h
StandaloneApplication.h
StandaloneApplicationLog.h

本篇文章着重需要分析的是 *.target.cs*.build.cs这两个文件.
创建出来之后,需要将 StandaloneApplication 文件夹移动到 Engine\Source\Programs 下,UE 所有的辅助程序 (UHT/UBT 等) 都在这个目录之下。
然后,运行 GenerateProgramProject.bat,这是我仿照 UE 的GenerateProjectFiles.bat 写的一个脚本,通过调用 UBT 来创建 Standalone Application 程序,命令如下:

1
2
# bash path in Engine\Source\Programs\StandaloneApplication
$ UnrealBuildTool.exe -notinstallengine -ProjectFiles StandaloneApplication

注意 :直接在安装版引擎中使用上面的命令会报错(不允许创建非 Game 项目),因为虽然传入了-notinstallengine 参数,但是对 Engine/Build/InstalledBuild.txt 文件检测的优先级高于-notinstallengine

1
2
3
4
Zhalipeng MINGW64 /d/UE_4.18/Engine/Source/Programs/StandaloneApplication (master)
$ ../../../../Engine/Binaries/DotNET/UnrealBuildTool.exe -notinstallengine -ProjectFiles StandaloneApplication
ERROR: UnrealBuildTool Exception: A game project path was not specified, which is required when generating project files using an installed build or passing -game on the command line

我写的脚本中做了检测,如果使用的是安装版引擎会先重命名 InstalledBuild.txt,生产完毕后会恢复(但是我还是建议不要在安装版引擎中执行)。其执行完毕后会在Engine\Intermediate\ProjectFiles 下生成:

1
2
3
StandaloneApplication.vcxproj
StandaloneApplication.vcxproj.filters
StandaloneApplication.vcxproj.user

其实就是将当前项目添加到 UE 的解决方案,执行完毕之后,打开引擎根目录下的 UE4.sln, 就可以看到创建的项目了:

先来编译运行看一下结果:

Program *.target.cs

UBT 支持数种 Target 类型(通过枚举类型 TargetType 来指定):

  • Game: 独立运行的游戏;
  • Client: 与 Game 相同,但不包含任何服务器代码;
  • Server: 与 Game 相同,但不包含任何客户端代码;
  • Editor:UE 编辑器的扩展;
  • Program: 独立运行的程序;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs
public enum TargetType
{
// Cooked monolithic game executable (GameName.exe). Also used for a game-agnostic engine executable (UE4Game.exe or RocketGame.exe)
Game,
// Uncooked modular editor executable and DLLs (UE4Editor.exe, UE4Editor*.dll, GameName*.dll)
Editor,
// Cooked monolithic game client executable (GameNameClient.exe, but no server code)
Client,
// Cooked monolithic game server executable (GameNameServer.exe, but no client code)
Server,
// Program (standalone program, e.g. ShaderCompileWorker.exe, can be modular or monolithic depending on the program)
Program,
}

关于 .target.cs 的文档介绍:UnrealBuildTool/Targets.

hxhb/ue4program创建生成的 *.target.cs 模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using UnrealBuildTool;
using System.Collections.Generic;

[SupportedPlatforms(UnrealPlatformClass.All)]
public class StandaloneApplicationTarget : TargetRules
{
public StandaloneApplicationTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Program;
LinkType = TargetLinkType.Monolithic;
LaunchModuleName = "StandaloneApplication";
ExtraModuleNames.Add("EditorStyle");
}

public override void SetupGlobalEnvironment(
TargetInfo Target,
ref LinkEnvironmentConfiguration OutLinkEnvironmentConfiguration,
ref CPPEnvironmentConfiguration OutCPPEnvironmentConfiguration
)
{
// Lean and mean
bCompileLeanAndMeanUE = true;

// No editor or editor-only data is needed
bBuildEditor = false;

// Whether to compile WITH_EDITORONLY_DATA disabled. Only Windows will use this, other platforms force this to false.
//bBuildWithEditorOnlyData = false;

// Compile out references from Core to the rest of the engine
bCompileAgainstEngine = false;

// Enabled for all builds that include the CoreUObject project. Disabled only when building standalone apps that only link with Core.
bCompileAgainstCoreUObject = true;

// Whether to include plugin support.
bCompileWithPluginSupport = true;

// Enable exceptions for all modules
bForceEnableExceptions = false;

// Enable RTTI for all modules.
// bForceEnableRTTI = true;

// If ture the program entrance is WinMain,otherwise entrance is main
bIsBuildingConsoleApplication = false;
}
}

目前,最需要关注的参数只有三个:

  • Type:需要指定为需要构建的目标类型TargetType.Program.
  • LinkType:指定为 TargetLinkType.Monolithic 则将目标编译成一个单个的可执行文件(不依赖任何 DLL).
  • bIsBuildingConsoleApplicationture支持 Console,函数入口为 main;false 则不支持 Console,主函数入口为WinMain.

其他参数的 (RTTI/Exceptions) 均能在用到时根据需求从文档查询。

Program *.Build.cs

Program 的 *.Build.cs 与普通的游戏项目的没有区别 (因为 Game 是一个模块,Program 也是),唯一的区别就是将这些模块构建成什么样的目标类型(由*.target.cs 决定)。