可可西

UE4编译模块系统

模块(Module)是构成Unreal Engine的基本元素,每个Module(build.cs)封装和实现了一组功能,并且可以供其他的Module使用。

整个Unreal Engine就是靠各个Module组合来构成一个插件(uplugin)、项目(uproject)和目标(Target.cs)。

build.cs

一个模块是UE4的一个编译块,在windows编辑器中对应一个dll模块,在mac编辑器中对一个dylib模块

每个模块有一个build.cs文件,控制的是Module编译过程,由它来控制所属Module的对其他Module的依赖、文件包含、链接、宏定义等相关的操作

开发人员通过编写该文件来定义不同平台下模块的编译选项(如:头文件查找目录,预编译宏,依赖模块列表等)

如Protobuf.Build.cs的配置内容如下:

using UnrealBuildTool;
using System;
using System.IO;

public class Protobuf : ModuleRules  // ModuleRules类型详见:ModuleRules.cs
{
    public Protobuf(ReadOnlyTargetRules Target) : base(Target)
    {
// ModuleType.CPlusPlus 表示c++源码集成,会参与编译、链接、打包等
// ModuleType.External 表示第三方库形式集成,不参与编译,参加链接、打包等
Type = ModuleType.CPlusPlus;

// ModuleRules.PCHUsageMode.Default Engine modules use shared PCHs, game modules do not
// ModuleRules.PCHUsageMode.NoPCHs Never use any PCHs
// ModuleRules.PCHUsageMode.NoSharedPCHs Never use shared PCHs.  Always generate a unique PCH for this module if appropriate
// ModuleRules.PCHUsageMode.UseSharedPCHs Shared PCHs are OK
// ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs Shared PCHs may be used if an explicit private PCH is not set through PrivatePCHHeaderFile. In either case, none of the source files manually include a module PCH, and should include a matching header instead.
PCHUsage
= PCHUsageMode.NoSharedPCHs; string MFProtobufHeadDir = Path.Combine(ModuleDirectory, "Public"); PublicSystemIncludePaths.Add(MFProtobufHeadDir); bEnableUndefinedIdentifierWarnings = false; Definitions.AddRange( new string[] { "HAVE_PTHREAD", "PROTOBUF_INLINE_NOT_IN_HEADERS=1", "GOOGLE_PROTOBUF_NO_RTTI" }); if (Target.Platform == UnrealTargetPlatform.Win32 || Target.Platform == UnrealTargetPlatform.Win64) { Definitions.Add("PROTOBUF_USE_DLLS"); Definitions.Add("_CRT_SECURE_NO_WARNINGS"); } PublicDependencyModuleNames.AddRange(new string[] { "Core", }); } }

 

Definitions:存放所有定义的宏。这些宏会被写入Intermediate\Build\Win64\UE4Editor\Debug\<Module>\Definitions.<Module>.h中

                    编译器在编译每个c/cpp文件时,会带上/FI "Intermediate\Build\Win64\UE4Editor\Debug\<Module>\Definitions.<Module>.h"参数,将在c/cpp文件的第一行上#include该文件

 

每个模块中必须定义一个从IModuleInterface派生的类:

/*** UnrealEngine\Engine\Source\Runtime\Core\Public\Modules\ModuleInterface.h  ***/
class IModuleInterface
{

public:

    // 析构函数
    virtual ~IModuleInterface()
    {
    }

    // 模块加载创建时被调用
    virtual void StartupModule()
    {
    }

    // 模块卸载前被调用
    virtual void PreUnloadCallback()
    {
    }

    // 模块加载后被调用
    virtual void PostLoadCallback()
    {
    }

    // 模块销毁前被嗲用
    virtual void ShutdownModule()
    {
    }

    // 模块在运行时是否支持动态加载和卸载
    virtual bool SupportsDynamicReloading()
    {
        return true;
    }

    // 进程退出时,模块是否也自动Shutdown
    virtual bool SupportsAutomaticShutdown()
    {
        return true;
    }

    // 是否为Gameplay的模块
    virtual bool IsGameModule() const
    {
        return false;
    }
};

 

并通过IMPLEMENT_MODULE宏(或IMPLEMENT_GAME_MODULE宏,注:两个宏为同一个东西)来创建该类的实例

/*** UnrealEngine\Engine\Source\Runtime\Core\Public\Modules\ModuleManager.h ***/
#if
IS_MONOLITHIC // Monolithic,宏IS_MONOLITHIC为1,即:代码会编译到一个模块中 如:cook后的pc和手机版本 // If we're linking monolithically we assume all modules are linked in with the main binary. #define IMPLEMENT_MODULE( ModuleImplClass, ModuleName ) \ /** Global registrant object for this module when linked statically */ \ static FStaticallyLinkedModuleRegistrant< ModuleImplClass > ModuleRegistrant##ModuleName( TEXT(#ModuleName) ); \ /* Forced reference to this function is added by the linker to check that each module uses IMPLEMENT_MODULE */ \ extern "C" void IMPLEMENT_MODULE_##ModuleName() { } \ PER_MODULE_BOILERPLATE_ANYLINK(ModuleImplClass, ModuleName) #else // 非Monolithic,宏IS_MONOLITHIC为0,即:代码会编译到多个dll中 如:在编辑器或standalone下 #define IMPLEMENT_MODULE( ModuleImplClass, ModuleName ) \ \ /**/ \ /* InitializeModule function, called by module manager after this module's DLL has been loaded */ \ /**/ \ /* @return Returns an instance of this module */ \ /**/ \ extern "C" DLLEXPORT IModuleInterface* InitializeModule() \ { \ return new ModuleImplClass(); \ // 创建模块对象的实例 } \ /* Forced reference to this function is added by the linker to check that each module uses IMPLEMENT_MODULE */ \ extern "C" void IMPLEMENT_MODULE_##ModuleName() { } \ PER_MODULE_BOILERPLATE \ PER_MODULE_BOILERPLATE_ANYLINK(ModuleImplClass, ModuleName) #endif //IS_MONOLITHIC

如:Protobuf\Protobuf.cpp

#include "Protobuf.h"
#include "Modules/ModuleManager.h"

IMPLEMENT_GAME_MODULE(FDefaultGameModuleImpl, Protobuf);

 

 

模块的加载逻辑在FModuleManager::LoadModule函数中。FModuleManager类详见:

/*** UnrealEngine\Engine\Source\Runtime\Core\Public\Modules\ModuleManager.h  ***/
class CORE_API FModuleManager
    : private FSelfRegisteringExec  // 自动注册Exec函数来支持控制台命令
{
    // 析构函数
    ~FModuleManager();

public:

    // 获取FModuleManager单例
    static FModuleManager& Get( );

    // 销毁FModuleManager单例
    static void TearDown();

    // 抛弃模块
    void AbandonModule( const FName InModuleName );

    // 添加模块
    void AddModule( const FName InModuleName );

#if !IS_MONOLITHIC
    void RefreshModuleFilenameFromManifest(const FName InModuleName);
#endif    // !IS_MONOLITHIC

    // 得到指定模块指针
    IModuleInterface* GetModule( const FName InModuleName );

    // 指定模块是否加载
    bool IsModuleLoaded( const FName InModuleName ) const;

    // 加载指定模块
    IModuleInterface* LoadModule( const FName InModuleName );

    // 加载指定模块,并check检查它是否加载成功
    IModuleInterface& LoadModuleChecked( const FName InModuleName );

    // 加载指定模块,并调用该模块的PostLoadCallback函数
    bool LoadModuleWithCallback( const FName InModuleName, FOutputDevice &Ar );

    // 加载指定模块,如果失败则返回原因
    IModuleInterface* LoadModuleWithFailureReason( const FName InModuleName, EModuleLoadResult& OutFailureReason );

    // 查询指定模块的信息
    bool QueryModule( const FName InModuleName, FModuleStatus& OutModuleStatus ) const;

    // 查询指定多个模块的信息
    void QueryModules( TArray<FModuleStatus>& OutModuleStatuses ) const;

    // 卸载指定模块
    bool UnloadModule( const FName InModuleName, bool bIsShutdown = false );

     // 卸载或抛弃指定模块,在此之前调用PreUnloadCallback函数
    void UnloadOrAbandonModuleWithCallback( const FName InModuleName, FOutputDevice &Ar);

    // 抛弃指定模块,在此之前调用PreUnloadCallback函数
    void AbandonModuleWithCallback( const FName InModuleName );

    // 增加额外的搜索路径
    void AddExtraBinarySearchPaths();

    // 获取指定模块,并对它进行check检查
    template<typename TModuleInterface>
    static TModuleInterface& GetModuleChecked( const FName ModuleName )
    {
        FModuleManager& ModuleManager = FModuleManager::Get();

        checkf(ModuleManager.IsModuleLoaded(ModuleName), TEXT("Tried to get module interface for unloaded module: '%s'"), *(ModuleName.ToString()));
        return static_cast<TModuleInterface&>(*ModuleManager.GetModule(ModuleName));
    }

private:
    static IModuleInterface* GetModulePtr_Internal(FName ModuleName);

public:

    // 获取指定模块
    template<typename TModuleInterface>
    static FORCEINLINE TModuleInterface* GetModulePtr( const FName ModuleName )
    {
        return static_cast<TModuleInterface*>(GetModulePtr_Internal(ModuleName));
    }

    // 加载指定模块,并check检查它是否加载成功
    template<typename TModuleInterface>
    static TModuleInterface& LoadModuleChecked( const FName InModuleName)
    {
        IModuleInterface& ModuleInterface = FModuleManager::Get().LoadModuleChecked(InModuleName);
        return static_cast<TModuleInterface&>(ModuleInterface);
    }

    // 加载指定模块
    template<typename TModuleInterface>
    static TModuleInterface* LoadModulePtr( const FName InModuleName)
    {
        return static_cast<TModuleInterface*>(FModuleManager::Get().LoadModule(InModuleName));
    }

    // 使用通配符来查找模块
    void FindModules( const TCHAR* WildcardWithoutExtension, TArray<FName>& OutModules ) const;

    // 模块名的模块是否存在
    bool ModuleExists(const TCHAR* ModuleName) const;

    // 当前加载的模块数
    int32 GetModuleCount( ) const;

    // 关闭进程时卸载模块
    void UnloadModulesAtShutdown( );


    // ... ...// FSelfRegisteringExec interface. 控制台命令执行函数
    virtual bool Exec( UWorld* Inworld, const TCHAR* Cmd, FOutputDevice& Ar ) override;


    // ... ...

    /**
     * Information about a single module (may or may not be loaded.)
     */
    class FModuleInfo
    {
    public:

        /** The original file name of the module, without any suffixes added */
        FString OriginalFilename;

        /** File name of this module (.dll file name) */
        FString Filename;

        /** Handle to this module (DLL handle), if it's currently loaded */
        void* Handle;

        /** The module object for this module.  We actually *own* this module, so it's lifetime is controlled by the scope of this shared pointer. */
        TUniquePtr<IModuleInterface> Module;

        /** True if this module was unloaded at shutdown time, and we never want it to be loaded again */
        bool bWasUnloadedAtShutdown;

        /** True if this module is full loaded and ready to be used */
        TAtomic<bool> bIsReady;

        /** Arbitrary number that encodes the load order of this module, so we can shut them down in reverse order. */
        int32 LoadOrder;

        /** static that tracks the current load number. Incremented whenever we add a new module*/
        static int32 CurrentLoadOrder;

    public:

        /** Constructor */
        FModuleInfo()
            : Handle(nullptr)
            , bWasUnloadedAtShutdown(false)
            , bIsReady(false)
            , LoadOrder(CurrentLoadOrder++)
        { }

        ~FModuleInfo()
        {
        }
    };

    // ... ...
};

 

每个模块的c++代码中都可以使用 {全大写的模块名}_API的宏来在本模块中导出类和函数给其他模块使用

进行动态链接库类型(dll, dylib)编译时,UBT会将当前模块的宏定义为DLLEXPORT来导出模块的类或函数,将非当前模块的宏定义为DLLIMPORT来导入其他模块的类或函数

DLLEXPORTDLLIMPORT在不同的平台会被定义为如下内容:

系统平台

#include"HAL/Platform.h"

宏定义

windows

见“WIndowsPlatform.h”

#define DLLEXPORT __declspec(dllexport)
#define DLLIMPORT __declspec(dllimport)

Unix/Linux

见“UnixPlatform.h”

#define DLLEXPORT __attribute__((visibility("default")))
#define DLLIMPORT __attribute__((visibility("default")))

Mac

见“MacPlatform.h”

#define DLLEXPORT
#define DLLIMPORT

Android

见“AndroidPlatform.h”

#define DLLEXPORT __attribute__((visibility("default")))
#define DLLIMPORT __attribute__((visibility("default")))

iOS

见“IOSPlatform.h”

#define DLLEXPORT
#define DLLIMPORT

 

uproject、plugin

游戏可以有多个模块(需配置在MyTest1.uproject),插件也可以有多个模块(需配置在plugin文件中)。

游戏和插件中定义了其内部的模块及依赖的第三方plugin,并能拥有自己独立的资源(放在Content目录中)和配置文件(放在Config目录中)。

另外,plugin还能拥有自己独立的着色器文件(放在Shaders目录中)和编辑器资源(放在Resources目录中)。

插件可在plugin文件中设置自己缺省是否启用。   注1:设置EnabledByDefault为false,表示缺省不启用插件   注2:如果没有显示设置EnabledByDefault的值,为引擎插件则不启用,为项目插件则启用

也可以在项目的MyTest1.uproject和项目的其他plugin文件中将某个Plugin关闭。

"Plugins": [
    {
        "Name": "MyPlugin",
        "Enabled": false
    }
]

注1:即使将plugin文件EnabledByDefault配置为false,当该plugin中module被其他的module引用到,插件会自动被启用

注2:项目的MyTest1.uproject或plugin依赖某个Plugin时,可以不用显示地配置在uproject或Plugin文件中,但在对应Module的build.cs中必须配置好依赖的外部Module

 

MyTest1.uproject对应ProjectDescriptor类型(见UnrealBuildTool中的ProjectDescriptor.cs文件),其配置内容如下:

{
    "FileVersion": 3, // Descriptor version number.
    "EngineAssociation": "{CDEC017E-4B01-7570-44D6-02937BB1A0A4}", // The engine to open this project with.
    "Category": "", // Category to show under the project browser
    "Description": "", // Description to show in the project browser
    "Modules": [ // List of all modules associated with this project
        {
            "Name": "MyTest1",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "Engine",
                "CoreUObject"
            ]
        }
    ],
    "Plugins": [ // List of plugins for this project (may be enabled/disabled)
        {
            "Name": "MobilePatchingUtils",
            "Enabled": true
        },
        {
            "Name": "Wwise",
            "Enabled": true
        },
        {
            "Name": "GooglePAD",
            "Enabled": false
        }
    ],

    // A hash that is used to determine if the project was forked from a sample
    "EpicSampleNameHash": 125662,
    // Indicates if this project is an Enterprise project
    "IsEnterpriseProject": false,
    // Indicates that enabled by default engine plugins should not be enabled unless explicitly enabled by the project or target files.
    "DisableEnginePluginsByDefault": false,

    // Steps to execute before building targets in this project
    "PreBuildSteps": {
        "Win64": [
            "\"$(PluginDir)\\Source\\AkAudio\\WwisePostBuildSteps.bat\" \"$(EngineDir)\\Binaries\\Win64\\UE4Editor-cmd.exe\" \"$(ProjectFile)\" $(TargetType) -run=AkPluginActivator -platform=$(TargetPlatform) -configuration=Profile -targetconfig=$(TargetConfiguration)"
        ],
        "Mac": [
            "\"$(PluginDir)/Source/AkAudio/WwisePostBuildSteps.sh\" \"$(EngineDir)/Binaries/Mac/UE4Editor.app/Contents/MacOS/UE4Editor\" \"$(ProjectFile)\" $(TargetType) -run=AkPluginActivator -platform=$(TargetPlatform) -configuration=Profile -targetconfig=$(TargetConfiguration)"
        ]
    },

    // Steps to execute after building targets in this project
    "PostBuildSteps": {
        "Win64": [
            "\"$(PluginDir)\\Source\\AkAudio\\WwisePostBuildSteps.bat\" \"$(EngineDir)\\Binaries\\Win64\\UE4Editor-cmd.exe\" \"$(ProjectFile)\" $(TargetType) -run=AkPluginActivator -platform=$(TargetPlatform) -configuration=Profile -targetconfig=$(TargetConfiguration)"
        ],
        "Mac": [
            "\"$(PluginDir)/Source/AkAudio/WwisePostBuildSteps.sh\" \"$(EngineDir)/Binaries/Mac/UE4Editor.app/Contents/MacOS/UE4Editor\" \"$(ProjectFile)\" $(TargetType) -run=AkPluginActivator -platform=$(TargetPlatform) -configuration=Profile -targetconfig=$(TargetConfiguration)"
        ]
    },

    "AdditionalRootDirectories": [ // Array of additional root directories
        "MyRoot/Dir1", // -->D:\svn\MyTest1\MyRoot\Dir1
        "MyRoot/Dir2" // -->D:\svn\MyTest1\MyRoot\Dir2
    ],
    "AdditionalPluginDirectories": [ // List of additional plugin directories to scan for available plugins
        "MyPluginRoot/Dir1", // -->D:\svn\MyTest1\MyPluginRoot\Dir1
        "MyPluginRoot/Dir2" // -->D:\svn\MyTest1\MyPluginRoot\Dir1
    ],
    "TargetPlatforms": [ //Array of platforms that this project is targeting
        "Win64",
        "Android",
        "IOS",
        "Mac",
        "Linux"
    ]
} 

 

MyTest1.uplugin对应PluginDescriptor类型(见UnrealBuildTool中的PluginDescriptor.cs文件)。如:引擎的WebMMoviePlayer.uplugin插件:

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "Movie Player for WebM files",
    "Description": "Movie Player for WebM files",
    "Category": "Movie Players",
    "CreatedBy": "Epic Games, Inc.",
    "CreatedByURL": "http://epicgames.com",
    "DocsURL": "",
    "MarketplaceURL": "",
    "SupportURL": "",
    "EnabledByDefault": true,
    "CanContainContent": false,
    "IsBetaVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "WebMMoviePlayer",
            "Type": "RuntimeNoCommandlet",
            "LoadingPhase": "PreLoadingScreen",
            "WhitelistPlatforms": [
                "Win64",
                "Linux",
                "Mac"
            ],
            "BlacklistTargets": [
                "Server"
            ]
        }
    ],
    "Plugins": [
        {
            "Name": "WebMMedia",
            "Enabled": true
        }
    ]
}

 

MyTest1.uproject和MyTest1.uplugin中Modules配置的Module,见UnrealBuildTool中的ModuleDescriptor.cs文件:

/// <summary>
/// The type of host that can load a module
/// </summary>
public enum ModuleHostType
{
    /// <summary>
    /// 
    /// </summary>
    Default,

    /// <summary>
    /// Any target using the UE4 runtime
    /// </summary>
    Runtime,

    /// <summary>
    /// Any target except for commandlet
    /// </summary>
    RuntimeNoCommandlet,

    /// <summary>
    /// Any target or program
    /// </summary>
    RuntimeAndProgram,

    /// <summary>
    /// Loaded only in cooked builds
    /// </summary>
    CookedOnly,

    /// <summary>
    /// Loaded only in uncooked builds
    /// </summary>
    UncookedOnly,

    /// <summary>
    /// Loaded only when the engine has support for developer tools enabled
    /// </summary>
    Developer,

    /// <summary>
    /// Loads on any targets where bBuildDeveloperTools is enabled
    /// </summary>
    DeveloperTool,

    /// <summary>
    /// Loaded only by the editor
    /// </summary>
    Editor,

    /// <summary>
    /// Loaded only by the editor, except when running commandlets
    /// </summary>
    EditorNoCommandlet,

    /// <summary>
    /// Loaded by the editor or program targets
    /// </summary>
    EditorAndProgram,

    /// <summary>
    /// Loaded only by programs
    /// </summary>
    Program,

    /// <summary>
    /// Loaded only by servers
    /// </summary>
    ServerOnly,

    /// <summary>
    /// Loaded only by clients, and commandlets, and editor....
    /// </summary>
    ClientOnly,

    /// <summary>
    /// Loaded only by clients and editor (editor can run PIE which is kinda a commandlet)
    /// </summary>
    ClientOnlyNoCommandlet,
}

/// <summary>
/// Indicates when the engine should attempt to load this module
/// </summary>
public enum ModuleLoadingPhase
{
    /// <summary>
    /// Loaded at the default loading point during startup (during engine init, after game modules are loaded.)
    /// </summary>
    Default,

    /// <summary>
    /// Right after the default phase
    /// </summary>
    PostDefault,

    /// <summary>
    /// Right before the default phase
    /// </summary>
    PreDefault,

    /// <summary>
    /// Loaded as soon as plugins can possibly be loaded (need GConfig)
    /// </summary>
    EarliestPossible,

    /// <summary>
    /// Loaded before the engine is fully initialized, immediately after the config system has been initialized.  Necessary only for very low-level hooks
    /// </summary>
    PostConfigInit,

    /// <summary>
    /// The first screen to be rendered after system splash screen
    /// </summary>
    PostSplashScreen,

    /// <summary>
    /// After PostConfigInit and before coreUobject initialized. used for early boot loading screens before the uobjects are initialized
    /// </summary>
    PreEarlyLoadingScreen,

    /// <summary>
    /// Loaded before the engine is fully initialized for modules that need to hook into the loading screen before it triggers
    /// </summary>
    PreLoadingScreen,

    /// <summary>
    /// After the engine has been initialized
    /// </summary>
    PostEngineInit,

    /// <summary>
    /// Do not automatically load this module
    /// </summary>
    None,
}


/// <summary>
/// Class containing information about a code module
/// </summary>
[DebuggerDisplay("Name={Name}")]
public class ModuleDescriptor
{
    /// <summary>
    /// Name of this module
    /// </summary>
    public readonly string Name;

    /// <summary>
    /// Usage type of module
    /// </summary>
    public ModuleHostType Type;

    /// <summary>
    /// When should the module be loaded during the startup sequence?  This is sort of an advanced setting.
    /// </summary>
    public ModuleLoadingPhase LoadingPhase = ModuleLoadingPhase.Default;

    /// <summary>
    /// List of allowed platforms
    /// </summary>
    public List<UnrealTargetPlatform> WhitelistPlatforms;

    /// <summary>
    /// List of disallowed platforms
    /// </summary>
    public List<UnrealTargetPlatform> BlacklistPlatforms;

    /// <summary>
    /// List of allowed targets
    /// </summary>
    public TargetType[] WhitelistTargets;

    /// <summary>
    /// List of disallowed targets
    /// </summary>
    public TargetType[] BlacklistTargets;

    /// <summary>
    /// List of allowed target configurations
    /// </summary>
    public UnrealTargetConfiguration[] WhitelistTargetConfigurations;

    /// <summary>
    /// List of disallowed target configurations
    /// </summary>
    public UnrealTargetConfiguration[] BlacklistTargetConfigurations;

    /// <summary>
    /// List of allowed programs
    /// </summary>
    public string[] WhitelistPrograms;

    /// <summary>
    /// List of disallowed programs
    /// </summary>
    public string[] BlacklistPrograms;

    /// <summary>
    /// List of additional dependencies for building this module.
    /// </summary>
    public string[] AdditionalDependencies;
}

 

Target.cs

Target.cs控制的是生成的可执行程序。如:生成的是什么Type(Game/Client/Server/Editor/Program),开不开启 RTTI (bForceEnableRTTI),CRT 使用什么方式链接 (bUseStaticCRT)等等。

不同Target(MyTest1.Target.cs、MyTest1Client.Target.cs、MyTest1Editor.Target.cs、MyTest1Server.Target.cs)中配置当前项目下属于自己Target的模块列表。

MyTest1Target.cs

using UnrealBuildTool;
using System.Collections.Generic;
using Tools.DotNETCommon;
using System;
using System.IO;

public class MyTest1Target : TargetRules
{
    public MyTest1Target(TargetInfo Target) : base(Target)
    {
        // Enable PSO Collection miss report
        if(Target.Platform == UnrealTargetPlatform.Android ||
            Target.Platform == UnrealTargetPlatform.IOS)
        {
            System.Environment.SetEnvironmentVariable("ENABLE_PSO_REPORT", "FALSE");
        }

        Type = TargetType.Game;

        ExtraModuleNames.AddRange( new string[] {
            "MyCommon",
            "MyGame",
        } );

        if (Configuration == UnrealTargetConfiguration.Shipping
         || Configuration == UnrealTargetConfiguration.Test)
        {
            bUseLoggingInShipping = true;
        }
    }
}

 

MyTest1ClientTarget.cs

using UnrealBuildTool;
using System.Collections.Generic;
using Tools.DotNETCommon;
using System;
using System.IO;

public class MyTest1ClientTarget : TargetRules
{
    public MyTest1ClientTarget(TargetInfo Target) : base(Target)
    {
        // Enable PSO Collection miss report
        if(Target.Platform == UnrealTargetPlatform.Android ||
            Target.Platform == UnrealTargetPlatform.IOS)
        {
            System.Environment.SetEnvironmentVariable("ENABLE_PSO_REPORT", "FALSE");
        }
// TargetLinkType.Default Use the default link type based on the current target type
// TargetLinkType.Monolithic Link all modules into a single binary
// TargetLinkType.Modular Link modules into individual dynamic libraries
LinkType = TargetLinkType.Default; Type
= TargetType.Client; ExtraModuleNames.AddRange( new string[] { "MyCommon", "MyGame", } ); if (Configuration == UnrealTargetConfiguration.Shipping || Configuration == UnrealTargetConfiguration.Test) { bUseLoggingInShipping = true; } } }

 

MyTest1EditorTarget.cs

using UnrealBuildTool;
using System.Collections.Generic;

public class MyTest1EditorTarget : TargetRules
{
    public MyTest1EditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;

        ExtraModuleNames.AddRange( new string[] {
            "MyCommon",
            "MyGame",
            "MyGameEditor",
        } );

        bUseUnityBuild = true;
        bUsePCHFiles = true;

        //for debugging on a different machine
        bUseFastPDBLinking = false;

        bCompileForSize = false;
        bAllowLTCG = false;

        //Win64开启变量初始化顺序约束,会引发编译引擎和编译项目的参数不同,导致重新编译,放到引擎里面导致引擎通用化减弱,先关闭
        if (Target.Platform == UnrealTargetPlatform.Win64)
        {
            //bOverrideBuildEnvironment = true;
            //AdditionalLinkerArguments += " /release";
            //AdditionalCompilerArguments += " /we5038";
        }
    }
}

 

MyTest1ServerTarget.cs

using UnrealBuildTool;
using System.Collections.Generic;

public class MyTest1ServerTarget : TargetRules
{
    public MyTest1ServerTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Server;

        ExtraModuleNames.AddRange( new string[] {
            "MyCommon",
            "MyGame",
        });//for debugging on a different machine
        bUseFastPDBLinking = false;

        if (Configuration == UnrealTargetConfiguration.Shipping
         || Configuration == UnrealTargetConfiguration.Test)
        {
            bUseLoggingInShipping = true;
        }

        // enable push model
        bWithPushModel = true;

        LinuxPlatform.bEnableThinLTO = false;
    }
}

 

参考

虚幻引擎模块

如何在虚幻引擎中创建Gameplay模块

虚幻编译工具

UE Build System:Target and Module

Build flow of the Unreal Engine4 project

UE4 Modules:Load and Startup 

UE4 Modules:Find the DLL and load it 

 

posted on 2022-08-08 20:58  可可西  阅读(3471)  评论(1编辑  收藏  举报

导航