Attention: Platform Changes Ahead!

Platform Extensions (and how they may impact you)

Background

Unreal has a rich history of multi-platform support. We have had various methods of separating out the platform code from the rest of the engine but even our latest method of platform separation is not “trivial” to keep platform code nicely segregated:

  • Perforce permissions are incredibly complex
  • There are references (not API calls) to every platform hardcoded in the engine[/li][li]Adding a new platform touches many parts of the engine
  • Protecting an unreleased platform from disclosure is complicated

To this end, we are introducing Platform Extensions. A Platform Extension is similar to a plugin that can be “dropped in” next to the Engine to create a new platform. This means that we can avoid platform references in the Engine code, Epic samples, project files, shaders… you get the idea.

Most existing platforms will not be be converted to a Platform Extension. In the future, we plan to have a Stadia Platform Extension, and we are considering possibly converting Xbox and PS4 as well. Win32/64, iOS, Linux etc will remain integrated as they are today, albeit with some notable changes (below).

Who is affected?

In order to enable Platform files to be discoverable across multiple locations, big changes have been made to UBT. Implementing Platform Extensions has also required changes in general engine code. The following is a list of developers who are very likely to be impacted:

  • Developers who modify Engine code
  • Platform developers (any platform)
  • Developers who author/modify their project’s Build.cs and Target.cs files
  • Developers modifying ini hierarchy
  • Developers using the platform tables in PlatformInfo.cpp
  • Rendering programmers

When does this change take place?

These changes are checked into //UE4/Dev-Build/ and have merged to //UE4/Main/ main as of CL 6631504.

The first release branch these changes are expected to land in will be 4.23.

Note:

This article covers fundamental changes to how platform files are handled throughout UE4’s codebase. Occurrences of [Platform] herein should be treated as an appropriate platform name (ie ‘Android’, ‘PS4’ or 'Windows’). For example, the Platforms/[Platform]/ folder mentioned below would be Platforms/PS4/ for the PS4 platform.

New directory structure

The most important part of the change is how the directories are laid out. The platform extensions live in [UE4Root]/Platforms/[Platform]/… This makes provisioning Perforce permissions much easier, keeps all restricted platform code in one place and generally is much more tidy.

A project can also have [ProjectRoot]/Platforms/… , but it is optional. You may leave platform specific code and other files in their original location, but Epic projects will have their files in the new structure. (If you are distributing your project, you may want to refactor the files to keep NDAd platforms separated).

The old directory structure, whereby platform files are distributed all throughout the codebase according to the feature they implement, will remain mostly intact, except for the changes mentioned below.

Sample Platform Extension

For a very basic example of a Platform Extension, we have created a sample platform named ‘XXX’ located in the /Platforms/XXX/ directory which shows how this new approach works in practice.

Rules for Platform Extensions

Given these changes, the following assertions apply to all Platform Extensions:
All files for the Platform must live inside [Engine|Project]/Platforms/[Platform]/ , including Developer modules, .Build.cs subclasses, Plugins, .inis, etc.

  • PLATFORM_[Platform] is not defined for Engine modules!
  • A module must set bAllowConfidentialPlatformDefines to true in order to have it set
  • Any ShaderPlatforms are defined in DataDrivenPlatformInfo.ini
  • PlatformInfo objects are defined in DataDrivenPlatformInfo.ini
  • The UnrealTargetPlatform for the platform is not referenced from outside the platform-specific .cs files

Workflow Impact

UnrealBuildTool

Impacted Audience: Anyone working in Build.cs and Target.cs files

Description: UnrealTargetPlatform was previously an enum with all platforms listed. To remove the hardcoded platform names, UnrealTargetPlatform has been changed to a class with static members named the same as the enum values. Additionally, it is a partial class, so a Platform Extension can extend the class to add a member with the platform’s name.

In general, it should act the same as enum (you can compare them, assign them, etc). However, since they are static members, they are not a constant value, so they cannot be used in a switch statement. All existing uses in the engine have been converted to if statements instead. In addition, the SupportedPlatforms attribute on a Target subclass now uses strings that match the platform name instead of the UnrealTargetPlatform.

This is likely to be the single biggest impact on you as a developer, unless you have also made engine/platform code changes.

HAL Header Filename Standardization

Impacted Audience: All Platform programmers (additional notes for Windows, TVOS, PS4, XboxOne, and Android developers)

Description: Platform references have been removed from the Hardware Abstraction Layer (HAL) “uber” headers, such as PlatformTime.h (used below as an example). Platform-specific versions of these header files are now referenced in the following manner:

 #include COMPILED_PLATFORM_HEADER(PlatformTime.h)

The COMPILED_PLATFORM_HEADER macro expands to add the current being compiled as a prefix. As such, all platform header file names must be standardized to the form [Platform]PlatformTime.h

PS4, XboxOne, and Android:

Historically these platforms did not have the word “Platform” in their header file names (e.g. PS4Time.h), which was in contrast with other platforms. These headers and source files have been renamed in order to make them consistent with other platforms (e.g. PS4Time.h is now PS4PlatformTime.h).

Platforms which are not converted to Platform Extensions will still have these files renamed, so developers that have made changes to affected platform files will need to make sure to move their changes over.

Win32, Win64 and TVOS:

Since Win32 and Win64 each share common headers, and since TVOS uses the IOS headers, we have added a mechanism to override the platform name that results when expanding the COMPILED_PLATFORM_HEADER macro. The override is declared in UEBuild[Platform].cs in the SetupEnvironment method by adding a new CompileEnvironment definition with:
CompileEnvironment.Definitions.Add("OVERRIDE_PLATFORM_HEADER_NAME=[SharedPlatform]”);

Examples:

  • Win32 and Win64 override to “Windows”, so they would share “WindowsPlatformTime.h”
  • TVOS overrides to “IOS”, so it would use “IOSPlatformTime.h”

Log categories for Platforms

Impacted Audience: Anyone writing engine code

Description: Platform log statements like UE_LOG(LogWindows, …) have used hardcoded Log categories, which were globally defined for all platforms. Now, the category is generated based on a define that is only set on that platform. This means that if you use UE_LOG(LogWindows, …) on any other platform than Windows, it will no longer compile. This should be an easy fix

Ini File Specification

Impacted Audience: Anyone who has added or will add new .ini files into the ini hierarchy.

Description: We have simplified the ability to search for .ini files in deep directory structures. The current implementation used a rigid list of files, which has now been replaced with a more programmatic solution we call “Ini Layers”. This concept breaks up the ini stack into discrete layers which can each be expanded according to various factors. Consider the following ini stack, which we can describe as having 5 layers:

  • Engine/BaseEngine.ini
  • Engine/Base[Platform]Engine.ini
  • Project/DefaultEngine.ini
  • Engine/[Platform]Engine.ini
  • Project/[Platform]Engine.ini

The Ini Layer feature enables us to expand each layer of the ini stack into multiple ini files according to the permutations appropriate for that layer.

For instance, Epic uses NotForLicensees and NoRedist as directories to segregate certain confidential/secret settings into directories with reduced distribution, which increases the permutations for each of these layers.

Additionally, this new feature expands upon our existing support for Ini Platform Parents, which now allow for a chain of parents, rather than just a single platform parent.

For example, suppose you have three platforms, A, B and C which are related in a chain; Grandparent A, Parent B and Child C. Ini settings for platform A (the grandparent) should be inherited by both A and B. Likewise, platform B settings should be inherited by platform C.

Previously, we did not have a way to specify platform A, and interlacing the appropriate ini files to cause C to inherit B’s settings was a challenge. Using Ini Layers, this full chain is now possible and would result in an ini stack for platform C as follows:

  • Engine/BaseEngine.ini
  • Engine/Base[…]Engine.ini
    • Engine/Base[A]Engine.ini
    • Engine/Base[B]Engine.ini
    • Engine/Base[C]Engine.ini
  • Project/DefaultEngine.ini
  • Engine/[…]Engine.ini
    • Engine/[A]Engine.ini
    • Engine/[B]Engine.ini
    • Engine/[C]Engine.ini
  • Project/[…]Engine.ini
    • Project/[A]Engine.ini
    • Project/[B]Engine.ini
    • Project/[C]Engine.ini

The specification of these Layers (GConfigLayers) and Expansions (GConfigLayerExpansions) is in ConfigCacheIni.cpp. See also EnumerateConfigFileLocations which defined in ConfigHierarchy.cs.

Two layers from the GConfigLayers definition are shown below. These definitions use bracketed tokens which are expanded to valid permutations when generating the ini file names.


// Project/Default*.ini
{ TEXT("ProjectDefault"), TEXT("{PROJECT}{ED}{EF}Default{TYPE}.ini"), TEXT(""), Flag_AllowCommandLineOverride | Flag_GenerateCacheKey },

// Project/Platform/Platform*.ini
{ TEXT("ProjectPlatform"), TEXT("{PROJECT}{ED}{PLATFORM}/{EF}{PLATFORM}{TYPE}.ini"), TEXT("{EXTPROJECT}/{ED}{EF}{PLATFORM}{TYPE}.ini") },

Valid tokens are as follows:

  • {PROJECT}
    • The project directory
    • Has no permutations
    • Token ends in a ‘/’
  • {ENGINE}
    • The engine directory
    • Has no permutations
    • Token ends in a ‘/’
  • {TYPE}
    • The type of ini file it is
    • Expands for each ini type; Game, Input, Engine, Editor, etc
  • {ED}
    • The DirectoryPrefixs defined in GConfigLayerExpansions
      • NotForLicensees, NoRedist, etc
    • Expands for each DirectoryPrefix in GConfigLayerExpansions
    • Token ends in a ‘/’
  • {EF}
    • The FilePrefixs defined in GConfigLayerExpansions
      • DedicatedServer, etc
    • Expands for each FilePrefix specified in GConfigLayerExpansions
  • {PLATFORM}
    • The current platform and any parent platform(s) in the IniParentChain
    • Expands once for each platform in the chain

Note that your existing .ini files will still work. This only changes the way the hierarchy is specified, enabling more files to be easily added, and adds the PlatformExtension location to the search.

PlatformInfo structure

Impacted Audience: Anyone modifying the large table in PlatformInfo.cpp

Description: We currently specify information about every platform in PlatformInfo.cpp. This naturally needed to change to remove platform information from the engine. The settings are now discovered by looking for DataDrivenPlatformInfo.ini files in each platform’s Engine/Config/ directory.

Currently, the DataDrivenPlatformInfo.ini files are not project-extendable, as they are meant to simply describe a platform. However, in the future this may change.

ShaderPlatforms

Impacted Audience: Rendering programmers

Description: A ShaderPlatform is used to define characteristics of rendering capabilities of a rendering API on a platform. The information about these ShaderPlatforms have always been hard-coded in C++, which need to be removed.

A ShaderPlatform can now be specified in a DataDrivenPlatformInfo.ini via the FDataDrivenShaderPlatformInfo class. This class will have more settings added to it as the rendering code adds more capabilities to check.

Currently, the existing ShaderPlatforms have not been converted to .ini-driven, so only about half of the functions named things like RHISupportsXxxxxx make use of the new system. This is a work in progress.

From the 4.23 release notes page

this mean that HTML5 will not be supported by Epic from now and upcomming releases ?

The platform extension link there is bad. Where can we read more about it? Wait it’s this page…?

I want to believe that EPIC one day reduces Launcher version size too so download is smaller and more optimal. Currently deselecting unneeded platforms/source in launcher still keeps so much platforms stuff. There should be possible to download only chosen platform support and even possible to get “blueprint only UE” that has no headers, pdb, help, python, .lib included.

iwtb.jpg

That would be so great !

Are these changes live in 4.23? I can’t find a Platforms folder in either UE4 or Project root (I’m currently porting the game on Nintendo Switch, so the platform add-on is installed).

I still don’t get how I can export my UE4 project in HTML now.

Basically, you don’t. Stay on the version you have now for that project.

Do we have an updated estimate for when this change will be complete? As of 4.24.1, running UAT BuildGraph to build the engine for internal team distribution with platform support (PS4 in our case) in the same way as worked perfectly in 4.22 no longer works; the engine builds successfully, but platform support isn’t working (example).

The platform files are in there, just incomplete and in the wrong place.

HTML support is ALMOST the only reason I chose to get started in Unreal Engine. Imagine the possibilities… what a bummer. Are there any updates on the questions previously posted?

The HTML5 Platform now lives at GitHub - UnrealEngineHTML5/Documentation as documented (in cyan-on-brown for some reason…) on Developing HTML5 Projects | Unreal Engine Documentation

I hate to necro resurrect an old post, but this does seem like the most appropriate place to inquire.

The document mentions the idea of having multiple platforms that are descendents of an earlier platform (A, B, C) in the INI files section, but doesn’t mention anything about that in the other sections.

If, say, you had a couple of drastically different Android devices, that required the ability to have some different code in different spaces for each, would this be a good and/or recommended way of doing that? Creating a couple of platforms that are descendents of Android?