ue-module-build-system

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

UE Module & Build System

UE模块与构建系统

You are an expert in Unreal Engine's module and build system. You understand Unreal Build Tool (UBT), ModuleRules, TargetRules, the .uproject manifest, plugin architecture, and the IWYU include discipline enforced by UE5.
您是Unreal Engine模块与构建系统方面的专家,熟悉Unreal Build Tool(UBT)、ModuleRules、TargetRules、.uproject清单、插件架构以及UE5强制执行的IWYU包含规范。

Before Starting

开始之前

Read
.agents/ue-project-context.md
if it exists — it provides module names, engine version, active plugins, and build targets that affect dependency and include configuration.
Ask which situation applies:
  1. Configuring dependencies in an existing Build.cs
  2. Creating a new module from scratch
  3. Creating a new plugin
  4. Resolving a build error (linker, include, or IWYU)
  5. Setting up Target.cs for a new build target

如果存在
.agents/ue-project-context.md
文件,请阅读它——其中包含模块名称、引擎版本、启用的插件以及影响依赖和包含配置的构建目标信息。
请说明您属于以下哪种场景:
  1. 在现有Build.cs中配置依赖项
  2. 从零开始创建新模块
  3. 创建新插件
  4. 解决构建错误(链接器、包含或IWYU相关)
  5. 为新构建目标设置Target.cs

Build.cs Anatomy

Build.cs 解析

Every UE module has a
ModuleName.Build.cs
file next to its
Public/
and
Private/
directories.
csharp
// Source/MyModule/MyModule.Build.cs
using UnrealBuildTool;

public class MyModule : ModuleRules
{
    public MyModule(ReadOnlyTargetRules Target) : base(Target)
    {
        // PCH settings — use IWYU in UE5
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        // Enable strict IWYU (recommended for new modules in UE5)
        bEnforceIWYU = true;

        // Types accessible to modules that depend on MyModule
        PublicDependencyModuleNames.AddRange(new string[]
        {
            "Core",
            "CoreUObject",
            "Engine",
        });

        // Types used only internally (not re-exported in public headers)
        PrivateDependencyModuleNames.AddRange(new string[]
        {
            "Slate",
            "SlateCore",
        });

        // Load at runtime but don't link at compile time
        DynamicallyLoadedModuleNames.Add("OnlineSubsystem");
    }
}
每个UE模块在其
Public/
Private/
目录旁都有一个
ModuleName.Build.cs
文件。
csharp
// Source/MyModule/MyModule.Build.cs
using UnrealBuildTool;

public class MyModule : ModuleRules
{
    public MyModule(ReadOnlyTargetRules Target) : base(Target)
    {
        // PCH设置——在UE5中使用IWYU
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        // 启用严格IWYU(推荐用于UE5中的新模块)
        bEnforceIWYU = true;

        // 可供依赖MyModule的模块访问的类型
        PublicDependencyModuleNames.AddRange(new string[]
        {
            "Core",
            "CoreUObject",
            "Engine",
        });

        // 仅内部使用的类型(不会在公共头文件中重新导出)
        PrivateDependencyModuleNames.AddRange(new string[]
        {
            "Slate",
            "SlateCore",
        });

        // 运行时加载但编译时不链接
        DynamicallyLoadedModuleNames.Add("OnlineSubsystem");
    }
}

Public vs Private Dependencies

公共依赖 vs 私有依赖

FieldWhen to use
PublicDependencyModuleNames
A type from the dependency appears in your public headers
PrivateDependencyModuleNames
The dependency is consumed only in Private/ .cpp files
A common mistake: putting everything in
PublicDependencyModuleNames
. This bloats transitive include paths for every downstream module. Only promote to public when your public headers actually
#include
headers from that module.
字段使用场景
PublicDependencyModuleNames
依赖项中的类型出现在您的公共头文件
PrivateDependencyModuleNames
依赖项仅在**Private/**下的.cpp文件中使用
常见错误:将所有内容放入
PublicDependencyModuleNames
。这会扩大所有下游模块的传递包含路径。仅当公共头文件实际
#include
该模块的头文件时,才将依赖项提升为公共依赖。

Include Paths

包含路径

csharp
// Expose extra paths to modules that depend on you
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public/Interfaces"));

// Expose extra paths only to this module's own source
PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private/Helpers"));
UBT automatically adds
Public/
and
Private/
— you rarely need to set these manually unless you have nested subdirectory headers you want to import without path prefixes.
csharp
// 向依赖您的模块暴露额外路径
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public/Interfaces"));

// 仅向当前模块自身的源代码暴露额外路径
PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private/Helpers"));
UBT会自动添加
Public/
Private/
路径——除非您有嵌套子目录中的头文件需要无需路径前缀即可导入,否则很少需要手动设置这些路径。

API Export Macro

API导出宏

UBT generates
MODULENAME_API
from the module's directory name, uppercased. Any class, function, or variable that must be visible across DLL boundaries needs this macro:
cpp
// Public/MyClass.h
#pragma once
#include "CoreMinimal.h"

class MYMODULE_API FMyClass
{
public:
    void DoSomething();
};

// Standalone exported function
MYMODULE_API void MyFreeFunction();
Missing
MYMODULE_API
on a class that another module references causes "unresolved external symbol" linker errors.
UBT会根据模块的目录名称(大写)生成
MODULENAME_API
宏。任何需要跨DLL边界可见的类、函数或变量都需要使用此宏:
cpp
// Public/MyClass.h
#pragma once
#include "CoreMinimal.h"

class MYMODULE_API FMyClass
{
public:
    void DoSomething();
};

// 独立导出函数
MYMODULE_API void MyFreeFunction();
如果其他模块引用的类缺失
MYMODULE_API
宏,会导致“未解析外部符号”链接器错误。

PCH and IWYU

PCH与IWYU

csharp
// UE5 recommended — each file includes exactly what it uses
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
bEnforceIWYU = true;

// Legacy — one monolithic PCH (avoid for new modules)
PCHUsage = PCHUsageMode.UseSharedPCHs;
With IWYU, every
.cpp
file includes its own
.h
first, then only what it directly uses:
cpp
// Private/MyClass.cpp
#include "MyClass.h"       // own header first
#include "Engine/Actor.h"  // only includes this file directly uses
csharp
// UE5推荐——每个文件仅包含其实际使用的内容
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
bEnforceIWYU = true;

// 旧模式——单一整体PCH(新模块避免使用)
PCHUsage = PCHUsageMode.UseSharedPCHs;
在IWYU模式下,每个
.cpp
文件首先包含自身的
.h
文件,然后仅包含其直接使用的内容:
cpp
// Private/MyClass.cpp
#include "MyClass.h"       // 先包含自身头文件
#include "Engine/Actor.h"  // 仅包含该文件直接使用的头文件

Compiler Flags

编译器标志

csharp
// C++ exceptions — disable unless third-party code requires them
bEnableExceptions = false;

// Runtime type information — disable unless using dynamic_cast
bUseRTTI = false;

// Third-party static libraries shipped with the engine
AddEngineThirdPartyPrivateStaticDependencies(Target, "zlib", "OpenSSL");

csharp
// C++异常——除非第三方代码需要,否则禁用
bEnableExceptions = false;

// 运行时类型信息——除非使用dynamic_cast,否则禁用
bUseRTTI = false;

// 随引擎发布的第三方静态库
AddEngineThirdPartyPrivateStaticDependencies(Target, "zlib", "OpenSSL");

Target.cs

Target.cs

Located at
Source/ProjectName.Target.cs
(and
Source/ProjectNameEditor.Target.cs
).
csharp
// Source/MyGame.Target.cs
using UnrealBuildTool;
using System.Collections.Generic;

public class MyGameTarget : TargetRules
{
    public MyGameTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
        DefaultBuildSettings = BuildSettingsVersion.Latest;
        IncludeOrderVersion = EngineIncludeOrderVersion.Latest;

        // All game modules that UBT should compile
        ExtraModuleNames.AddRange(new string[] { "MyGame", "MyGameUtilities" });
    }
}

// Source/MyGameEditor.Target.cs
public class MyGameEditorTarget : TargetRules
{
    public MyGameEditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;
        DefaultBuildSettings = BuildSettingsVersion.Latest;
        IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
        ExtraModuleNames.AddRange(new string[] { "MyGame", "MyGameEditor" });
    }
}
位于
Source/ProjectName.Target.cs
(以及
Source/ProjectNameEditor.Target.cs
)。
csharp
// Source/MyGame.Target.cs
using UnrealBuildTool;
using System.Collections.Generic;

public class MyGameTarget : TargetRules
{
    public MyGameTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
        DefaultBuildSettings = BuildSettingsVersion.Latest;
        IncludeOrderVersion = EngineIncludeOrderVersion.Latest;

        // UBT需要编译的所有游戏模块
        ExtraModuleNames.AddRange(new string[] { "MyGame", "MyGameUtilities" });
    }
}

// Source/MyGameEditor.Target.cs
public class MyGameEditorTarget : TargetRules
{
    public MyGameEditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;
        DefaultBuildSettings = BuildSettingsVersion.Latest;
        IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
        ExtraModuleNames.AddRange(new string[] { "MyGame", "MyGameEditor" });
    }
}

Target Types

目标类型

TargetTypeUse for
Game
Standalone game executable
Editor
Editor build (includes editor-only modules)
Client
Networked client without server logic
Server
Dedicated server (no renderer)
Program
Standalone non-game tool
Build configurations:
Debug
(full symbols, no optimization),
DebugGame
(engine optimized, game debug),
Development
(default; balanced),
Test
(like shipping but with console/stats),
Shipping
(final release, strips all debug).

TargetType用途
Game
独立游戏可执行文件
Editor
编辑器构建(包含仅编辑器模块)
Client
无服务器逻辑的联网客户端
Server
专用服务器(无渲染器)
Program
独立非游戏工具
构建配置
Debug
(完整符号信息,无优化)、
DebugGame
(引擎优化,游戏调试)、
Development
(默认;平衡配置)、
Test
(类似Shipping但保留控制台/统计信息)、
Shipping
(最终发布版本,移除所有调试信息)。

.uproject File

.uproject 文件

json
{
    "FileVersion": 3,
    "EngineAssociation": "5.4",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "MyGame",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        },
        {
            "Name": "MyGameEditor",
            "Type": "Editor",
            "LoadingPhase": "Default"
        }
    ],
    "Plugins": [
        {
            "Name": "ModelingToolsEditorMode",
            "Enabled": true
        },
        {
            "Name": "MyPlugin",
            "Enabled": true
        }
    ]
}
json
{
    "FileVersion": 3,
    "EngineAssociation": "5.4",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "MyGame",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        },
        {
            "Name": "MyGameEditor",
            "Type": "Editor",
            "LoadingPhase": "Default"
        }
    ],
    "Plugins": [
        {
            "Name": "ModelingToolsEditorMode",
            "Enabled": true
        },
        {
            "Name": "MyPlugin",
            "Enabled": true
        }
    ]
}

Module Types

模块类型

TypeWhen to use
Runtime
Core game logic, ships with game
RuntimeNoCommandlet
Runtime, excluded from commandlet processes
Editor
Editor-only — stripped from shipping builds
EditorNoCommandlet
Editor, excluded from commandlets
Developer
Tools usable in Editor and Development builds
DeveloperTool
Developer module, shows in editor UI
CookedOnly
Included only in cooked (packaged) builds
UncookedOnly
Included only in uncooked (development) builds
RuntimeAndProgram
Runtime module that also compiles into standalone Programs
EditorAndProgram
Editor module that also compiles into standalone Programs
Program
Standalone programs (UnrealHeaderTool etc.)
类型使用场景
Runtime
核心游戏逻辑,随游戏发布
RuntimeNoCommandlet
运行时模块,不包含在commandlet进程中
Editor
仅编辑器模块——在Shipping构建中被移除
EditorNoCommandlet
编辑器模块,不包含在commandlet中
Developer
可在编辑器和Development构建中使用的工具
DeveloperTool
开发者模块,会在编辑器UI中显示
CookedOnly
仅包含在已烘焙(打包)的构建中
UncookedOnly
仅包含在未烘焙(开发)的构建中
RuntimeAndProgram
同时编译为独立Program的运行时模块
EditorAndProgram
同时编译为独立Program的编辑器模块
Program
独立程序(如UnrealHeaderTool等)

Loading Phases

加载阶段

PhaseUse for
EarliestPossible
First possible phase — core engine modules only
PostSplashScreen
After splash screen renders
PreEarlyLoadingScreen
Before the early loading screen
PreLoadingScreen
Before the main loading screen
PostConfigInit
Systems that must configure before engine starts
PreDefault
Modules that must be ready before Default modules
Default
Standard game modules (most common)
PostDefault
Modules that depend on Default modules being up
PostEngineInit
After full engine initialization
None
Not auto-loaded — requires
FModuleManager::LoadModule()

阶段用途
EarliestPossible
最早的阶段——仅核心引擎模块使用
PostSplashScreen
启动画面渲染完成后
PreEarlyLoadingScreen
早期加载画面显示前
PreLoadingScreen
主加载画面显示前
PostConfigInit
必须在引擎启动前完成配置的系统
PreDefault
必须在Default模块就绪前准备好的模块
Default
标准游戏模块(最常用)
PostDefault
依赖于Default模块就绪的模块
PostEngineInit
引擎完全初始化后
None
不自动加载——需要调用
FModuleManager::LoadModule()

Creating a New Module

创建新模块

Directory Structure

目录结构

Source/
  MyModule/
    Public/
      MyModule.h          (optional module interface header)
      MyClass.h
    Private/
      MyModule.cpp        (module registration)
      MyClass.cpp
    MyModule.Build.cs
Source/
  MyModule/
    Public/
      MyModule.h          (可选的模块接口头文件)
      MyClass.h
    Private/
      MyModule.cpp        (模块注册)
      MyClass.cpp
    MyModule.Build.cs

Module Interface

模块接口

cpp
// Public/MyModule.h
#pragma once
#include "Modules/ModuleManager.h"

class IMyModule : public IModuleInterface
{
public:
    static IMyModule& Get()
    {
        return FModuleManager::LoadModuleChecked<IMyModule>("MyModule");
    }

    static bool IsAvailable()
    {
        return FModuleManager::Get().IsModuleLoaded("MyModule");
    }
};
cpp
// Private/MyModule.cpp
#include "MyModule.h"

class FMyModule : public IMyModule
{
public:
    virtual void StartupModule() override
    {
        // Initialize subsystems, register delegates, etc.
    }

    virtual void ShutdownModule() override
    {
        // Unregister delegates, clean up
    }
};

// Use IMPLEMENT_MODULE for non-gameplay modules
IMPLEMENT_MODULE(FMyModule, MyModule)

// Use IMPLEMENT_GAME_MODULE for modules containing UObject/gameplay code
// IMPLEMENT_GAME_MODULE(FMyModule, MyModule)

// Use IMPLEMENT_PRIMARY_GAME_MODULE for the main game module
// IMPLEMENT_PRIMARY_GAME_MODULE(FMyModule, MyGame, "MyGame")
The
IMPLEMENT_MODULE
macro (defined in
Modules/ModuleManager.h
) registers the module's initializer function. In DLL builds it registers a static
FModuleInitializerEntry
that maps the module name to its factory function. In monolithic builds it registers a static
FStaticallyLinkedModuleRegistrant
.
FDefaultModuleImpl
and
FDefaultGameModuleImpl
are provided for modules that need no startup/shutdown logic — use them to avoid writing a class body.
cpp
// Public/MyModule.h
#pragma once
#include "Modules/ModuleManager.h"

class IMyModule : public IModuleInterface
{
public:
    static IMyModule& Get()
    {
        return FModuleManager::LoadModuleChecked<IMyModule>("MyModule");
    }

    static bool IsAvailable()
    {
        return FModuleManager::Get().IsModuleLoaded("MyModule");
    }
};
cpp
// Private/MyModule.cpp
#include "MyModule.h"

class FMyModule : public IMyModule
{
public:
    virtual void StartupModule() override
    {
        // 初始化子系统、注册委托等
    }

    virtual void ShutdownModule() override
    {
        // 注销委托、清理资源
    }
};

// 非游戏模块使用IMPLEMENT_MODULE
IMPLEMENT_MODULE(FMyModule, MyModule)

// 包含UObject/游戏代码的模块使用IMPLEMENT_GAME_MODULE
// IMPLEMENT_GAME_MODULE(FMyModule, MyModule)

// 主游戏模块使用IMPLEMENT_PRIMARY_GAME_MODULE
// IMPLEMENT_PRIMARY_GAME_MODULE(FMyModule, MyGame, "MyGame")
IMPLEMENT_MODULE
宏(定义于
Modules/ModuleManager.h
)用于注册模块的初始化函数。在DLL构建中,它会注册一个静态
FModuleInitializerEntry
,将模块名称映射到其工厂函数。在单块构建中,它会注册一个静态
FStaticallyLinkedModuleRegistrant
对于无需启动/关闭逻辑的模块,可使用
FDefaultModuleImpl
FDefaultGameModuleImpl
,避免编写类主体。

Add to .uproject

添加到.uproject

json
{
    "Name": "MyModule",
    "Type": "Runtime",
    "LoadingPhase": "Default"
}

json
{
    "Name": "MyModule",
    "Type": "Runtime",
    "LoadingPhase": "Default"
}

Creating a Plugin

创建插件

Directory Structure

目录结构

Plugins/
  MyPlugin/
    MyPlugin.uplugin
    Source/
      MyPlugin/
        Public/
          IMyPlugin.h
        Private/
          MyPlugin.cpp
        MyPlugin.Build.cs
      MyPluginEditor/           (optional editor-only module)
        Public/
        Private/
          MyPluginEditor.cpp
        MyPluginEditor.Build.cs
    Content/                    (optional, for content plugins)
    Resources/
      Icon128.png
Plugins/
  MyPlugin/
    MyPlugin.uplugin
    Source/
      MyPlugin/
        Public/
          IMyPlugin.h
        Private/
          MyPlugin.cpp
        MyPlugin.Build.cs
      MyPluginEditor/           (可选的仅编辑器模块)
        Public/
        Private/
          MyPluginEditor.cpp
        MyPluginEditor.Build.cs
    Content/                    (可选,用于内容插件)
    Resources/
      Icon128.png

.uplugin File

.uplugin 文件

json
{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "My Plugin",
    "Description": "Does something useful.",
    "Category": "Gameplay",
    "CreatedBy": "MyStudio",
    "CreatedByURL": "",
    "DocsURL": "",
    "MarketplaceURL": "",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "IsExperimentalVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "MyPlugin",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        },
        {
            "Name": "MyPluginEditor",
            "Type": "Editor",
            "LoadingPhase": "Default"
        }
    ]
}
json
{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "My Plugin",
    "Description": "实现一些实用功能。",
    "Category": "Gameplay",
    "CreatedBy": "MyStudio",
    "CreatedByURL": "",
    "DocsURL": "",
    "MarketplaceURL": "",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "IsExperimentalVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "MyPlugin",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        },
        {
            "Name": "MyPluginEditor",
            "Type": "Editor",
            "LoadingPhase": "Default"
        }
    ]
}

Plugin with Runtime + Editor Modules

包含运行时+编辑器模块的插件

The runtime module must not include editor-only headers. Gate editor code:
cpp
// MyPlugin.Build.cs — runtime module
public class MyPlugin : ModuleRules
{
    public MyPlugin(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });

        // Editor-only dependency, only when compiling an editor build
        if (Target.bBuildEditor)
        {
            PrivateDependencyModuleNames.Add("UnrealEd");
        }
    }
}
cpp
// MyPluginEditor.Build.cs — editor module
public class MyPluginEditor : ModuleRules
{
    public MyPluginEditor(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "UnrealEd" });
        PrivateDependencyModuleNames.Add("MyPlugin");
    }
}
运行时模块不得包含仅编辑器头文件。需对编辑器代码进行保护:
cpp
// MyPlugin.Build.cs —— 运行时模块
public class MyPlugin : ModuleRules
{
    public MyPlugin(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });

        // 仅编辑器构建时添加仅编辑器依赖
        if (Target.bBuildEditor)
        {
            PrivateDependencyModuleNames.Add("UnrealEd");
        }
    }
}
cpp
// MyPluginEditor.Build.cs —— 编辑器模块
public class MyPluginEditor : ModuleRules
{
    public MyPluginEditor(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "UnrealEd" });
        PrivateDependencyModuleNames.Add("MyPlugin");
    }
}

Engine vs Project Plugins

引擎插件 vs 项目插件

Engine plugins (
Engine/Plugins/
): available to all projects using that engine installation. Ship with Epic or marketplace installs. Project plugins (
YourProject/Plugins/
): project-specific, travel with the project. When both exist with the same name, the project plugin wins.
Content-only plugins: No
Source/
directory, no
Modules
array in
.uplugin
. Contains only
Content/
and
Resources/
. Set
"CanContainContent": true
. Used for distributing Blueprint libraries and asset packs without C++ compilation.
Edge case -- launcher vs source builds: Launcher (binary) installs only include pre-built engine module binaries. Adding a dependency on an engine module not in the pre-built set causes LNK1104. Source builds from GitHub expose all engine modules. Use
Target.LinkType
to conditionally include source-build-only dependencies.

引擎插件
Engine/Plugins/
):对使用该引擎安装包的所有项目可用,随Epic或商城安装包发布。项目插件
YourProject/Plugins/
):特定于项目,随项目一同迁移。当两者同名时,项目插件优先级更高。
仅内容插件:无
Source/
目录,
.uplugin
中无
Modules
数组,仅包含
Content/
Resources/
目录。需设置
"CanContainContent": true
,用于分发蓝图库和资源包,无需C++编译。
边缘情况——启动器版与源码版构建:启动器版(二进制)安装包仅包含预编译的引擎模块二进制文件。如果依赖预编译集中未包含的引擎模块,会导致LNK1104错误。GitHub的源码版构建会暴露所有引擎模块。可使用
Target.LinkType
有条件地包含仅源码版构建支持的依赖项。

Resolving Build Errors

解决构建错误

Most build errors fall into a few categories: LNK2019 (missing dependency or missing
MODULENAME_API
), C1083 (missing dependency or wrong include path under IWYU), IWYU violations (include every header each file directly uses), and circular dependencies (extract a shared interface module or use
DynamicallyLoadedModuleNames
). Guard editor-only code in runtime modules with
#if WITH_EDITOR
and
if (Target.bBuildEditor)
in Build.cs. See references/common-build-errors.md for full error message lookup, causes, and fix patterns.

大多数构建错误可归为几类:LNK2019(缺失依赖项或
MODULENAME_API
)、C1083(缺失依赖项或IWYU模式下包含路径错误)、IWYU违规(每个文件必须直接包含其使用的所有头文件)以及循环依赖(提取共享接口模块或使用
DynamicallyLoadedModuleNames
)。在运行时模块中使用
#if WITH_EDITOR
和Build.cs中的
if (Target.bBuildEditor)
来保护仅编辑器代码。有关完整错误信息查询、原因及修复模式,请参考references/common-build-errors.md

Common Anti-Patterns

常见反模式

  • Putting everything in PublicDependencyModuleNames — inflates transitive include paths for every downstream module. Only promote to public when your public headers require it.
  • Missing
    MODULENAME_API
    on exported symbols
    — compiles fine within the module but causes LNK2019 for any other module that tries to call it.
  • Relying on transitive includes under IWYU — under
    bEnforceIWYU = true
    , each file must include every header it uses directly, even if another include would pull it in.
  • Referencing editor modules from runtime modules without
    #if WITH_EDITOR
    — fails in Shipping/Server builds where editor modules are excluded.
  • Wrong LoadingPhase — a module that registers asset types too late causes missing type errors at startup. Use
    PreDefault
    or
    PostConfigInit
    when needed.
  • Not adding the module to .uproject — UBT will not compile a module that isn't listed in
    .uproject
    or a
    .uplugin
    .

  • 将所有内容放入PublicDependencyModuleNames——会扩大所有下游模块的传递包含路径。仅当公共头文件需要时,才将依赖项提升为公共依赖。
  • 导出符号缺失
    MODULENAME_API
    ——在模块内部编译正常,但其他模块调用时会导致LNK2019错误。
  • 在IWYU模式下依赖传递包含——在
    bEnforceIWYU = true
    时,每个文件必须直接包含其使用的所有头文件,即使其他包含会间接引入这些头文件。
  • 未使用
    #if WITH_EDITOR
    就从运行时模块引用编辑器模块
    ——在Shipping/Server构建中会失败,因为这些构建会排除编辑器模块。
  • 错误的LoadingPhase——注册资源类型过晚的模块会在启动时导致类型缺失错误。必要时使用
    PreDefault
    PostConfigInit
    阶段。
  • 未将模块添加到.uproject中——UBT不会编译未在
    .uproject
    .uplugin
    中列出的模块。

Related Skills

相关技能

  • ue-cpp-foundations — UObject macros (UCLASS, UPROPERTY, UFUNCTION), reflection, and what must be in public headers for UHT to process
For detailed Build.cs field reference, see references/build-cs-reference.md. For error message lookup, see references/common-build-errors.md.
  • ue-cpp-foundations——UObject宏(UCLASS、UPROPERTY、UFUNCTION)、反射机制以及为让UHT处理而必须放在公共头文件中的内容
有关Build.cs字段的详细参考,请查看references/build-cs-reference.md。有关错误信息查询,请查看references/common-build-errors.md