Dec 6, 2021.Knowledge
What are modules in Unreal Engine?
Modules are the basic structural building block of Unreal Engine’s software architecture.
They are independent units of code and usually compiled as one compilation unit. A user can think of each module as a library. Each module should define a clear public interface and keep private logic internal. A module can depend upon other modules from the engine, game or plugins, additionally modules can include third-party libraries. It is possible to restrict modules to specific build types (e.g. editor only) and they can be white- and blacklisted to restrict the platforms they are available for.
There are several benefits from using modules in Unreal. They enforce good code separation and provide a mechanism to group related code and provide encapsulation that hides the internal parts of such code. This structure also improves compilation times as there is a clear dependency graph and header includes are limited to the code that is actually used. Previous versions of Unreal Engine included many monolithic header files that included large parts of their modules and significantly increased the amount of headers that were included.
In recent versions IWYU (Include What You Use) has been favored to further reduce header dependencies in Unreal projects.
The recommended file system structure of a module is illustrated in this image:
The module always contains a root directory by the name of the module, “ImageWrapper” in this example. The module root should contain the module’s build system configuration in a file named .Build.cs.
If the module is a regular C++ module (ModuleType was not set to external) then all the code in the module should be contained in two folders: Public and Private.
If these folders are present the build system will expose the Public folder as an include directory to any other module that specifies a dependency on the current module.
The Private folder will not be exposed to any other modules and no symbol defined in the private part of a module is allowed to be accessed from other modules.
To export any symbols (variables, classes, functions) in the Public part of a module for usage in other modules it is required to use the MODULENAME_API macro.
This macro will be expanded to the appropriate compiler intrinsic that defines linkage for public libraries (for example __declspec(dllexport) on Windows).
An example from the AssetTags module (part of the plugin of the same name):
If this macro is not specified the user of such a plugin will experience “Undefined symbol” errors by the linker.
Caution: If using a monolithic build it is possible to use a symbol even without the proper macro, because all code will be linked into a single executable and the dll export statements generated by the macro will have no effect. This can hide certain errors if a module is only used in the packaged game and never in the editor.
Modules are configured in two ways:
- Game or Project relevant Settings:
Options such as the module Type, LoadingPhase, and Platform Support are usually defined outside of the module itself, through the uproject or uplugin files of their “parent” project.
- Settings related to the module’s compilation environment:
The ModuleName.Build.cs file exists for every module and defines all configuration values that are relevant for compiling the module and the code it contains.
That includes setting up dependencies, compiler options (defines, include directories, C++ version, …) and linker options (module dependencies, external libraries to link).
The engine can be built in two major ways, as a modular and as a monolithic build.
Which one is used depends on whether the editor or the game is compiled and on any manual overrides present in the .Target.cs files.
A modular build means all modules will be compiled into shared libraries (.dlls on windows, .so on linux) and the editor/engine executable will load any libraries on startup. This setup is more flexible and allows adding more libraries or updating existing ones without rebuilding the engine.
In a monolithic build, all modules will be compiled into static libraries (.lib or .a) and those will be linked into the final executable. This means there will be only one executable and all libraries are put into this single file by the linker. This strategy is used by default when building game targets.
The module type will be specified through their parent game or plugin.
This is an example of how a module will be listed in a plugin:
Common module types are: Editor, Runtime, ClientOnly, ServerOnly.
The full list including descriptions can be found in the documentation here.
Most used are Editor and Runtime modules. An Editor module will only be available (=built) in Editor builds (In-Editor, PIE, or standalone launched application) while a runtime module will be available both in Editor and in the packaged game.
Common loading phases are: PreLoadingScreen, Default, PostEngineInit.
The full list including descriptions can be found in the documentation here.
Both of these options are defined in the engine source for each version at “Engine/Source/Runtime/Projects/Public/ModuleDescriptor.h”
The BlacklistPlatforms and WhitelistPlatforms arrays are used to define a list of (un)supported platforms per module. This can be relevant for anything that is using external libraries or functionality which is not available on all platforms.
The available configuration options for the .Build.cs file are listed in the documentation.
Public dependencies are used when the external module will be used and exposed in the public interface of the dependent module. This also implies that public dependencies are transient, that means if module A has a public dependency on module B, and module C is depending on module A, then module C will depend indirectly on module B. Unreal’s build system will resolve those transient dependencies automatically for the user and they do not have to be specified explicitly (i.e. module C will only list module A as dependency, not module B).
Private Dependencies are dependencies that are only used in private code of a module. As such they are not transient and modules depending on a module will never know or be influenced by its private dependencies.
There is one special module type used to include third-party libraries without custom code. An external module should specify an external moduletype in the modules .Build.cs file (by setting “Type = ModuleType.External”). This will tell the build system that there is no custom code in the module, but there will be additional include directories and library dependencies specified that refer to an external library.
There is a full walkthrough on how to include third-party libraries in our documentation.
The distinction between Modules and Plugins can be confusing for beginners in Unreal C++.
A module is strictly a unit of code, while a plugin contains one or more modules and an optional content folder. Modules under Engine/Source and Project/Source will always be active and loaded, while plugins (and their modules) can be disabled or enabled by the user as required.
Both modules and plugins can specify dependencies on their respective types. A plugin can only list other plugins as dependencies, a module can only list other modules as dependencies.
There are several configuration options for modules that are only defined through either the plugin they are in or the game they are part of. Both a .uproject file and a .uplugin list the modules that are contained in the game or plugin, and they can specify the Type and LoadingPhase for their modules. Additionally for a game the modules that are part of the game will be listed in the game’s .Target.cs files.
Documentation on the .uplugin files can be found here.