Version:

Settings Registry Gem Loading

The Settings Registry is linked with the CMake in order to facilitate the automatic loading of Gem modules based on the set of active Gems within a project. When CMake is configured for a project, it generates a set of cmake_dependencies.<project-name>.<target>.setreg files which are used to list the names of Gems that are active. It contains any shared Gem modules filenames, which load the Gems shared libraries into the O3DE application associated with the CMake Target.

Loading Gems

CMake is used to output a list of tagged .setreg files (cmake_dependencies.<target>.setreg), which contain the build dependencies of a CMake Target that loads through the O3DE module system. This is used to automatically load Gems based on the build dependencies of a CMake Target. This section demonstrates how to generate a .setreg file that contains a list of Gem build dependencies.

The following is the CMakeLists.txt for a hypothetical voxel editor feature:

CMakeLists.txt (Voxel Editor)

# Associate the VoxelEditor CMake target with the ".Tools" variant of Gems to load.
# This will generate a "cmake_dependencies.voxeleditor.setreg" file that contains the path to the shared
# libraries that will need to be loaded by the VoxelEditor, as well as the list paths to the Gem source directory
ly_set_gem_variant_to_load(TARGETS VoxelEditor VARIANTS Tools)

# Adds the VoxelEditor target as a C preprocessor define so that it can be used as a Settings Registry
# specialization to look up the generated .setreg, which contains the dependencies
# specified for the target.
set_source_files_properties(
    Source/VoxelEditorApplication.cpp
    PROPERTIES
        COMPILE_DEFINITIONS LY_CMAKE_TARGET="VoxelEditor"
)

Running the CMake command generates a solution and a cmake_dependencies.voxeleditor.setreg. It recurses through the list of the Gem’s RUNTIME_DEPENDENCIES and looks for a GEM_MODULE target property to determine the list of required Gems.

For example, the following is how the Atom Bridge Gem is configured in CMake:

CMakeLists.txt (AtomBridge)

if(PAL_TRAIT_BUILD_HOST_TOOLS)
    ly_add_target(
        NAME Atom_AtomBridge.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
        NAMESPACE Gem
        ...
        RUNTIME_DEPENDENCIES
            Gem::Atom_RHI.Private
            Gem::Atom_RHI_DX12.Private
            Gem::Atom_RHI_DX12.Builders
            Gem::Atom_Asset_Shader.Builders
            Gem::ImageProcessingAtom.Editor
            Gem::ImguiAtom
            Gem::AtomToolsFramework.Editor
    )


    # Any 'tool' and 'builder' type applications should use Gem::Atom_AtomBridge.Editor:
    ly_create_alias(NAME Atom_AtomBridge.Builders NAMESPACE Gem TARGETS Gem::Atom_AtomBridge.Editor)
    ly_create_alias(NAME Atom_AtomBridge.Tools    NAMESPACE Gem TARGETS Gem::Atom_AtomBridge.Editor)
endif()

Configuring CMake for the voxel editor generates the following .setreg file in the executable directory Registry directory:

cmake_dependencies.voxeleditor.setreg (Voxel Editor)

{
    "O3DE": {
        "Gems": {
            "Atom_AtomBridge": {
                "Targets": {
                    "Atom_AtomBridge.Editor": {
                        "Modules":["Atom_AtomBridge.Editor.dll"]
                    },
                    "Atom_AtomBridge.Builders": {
                    }
                }
            },
            "AtomShader": {
                "Targets": {
                    "Atom_Asset_Shader.Builders": {
                        "Modules":["Atom_Asset_Shader.Builders.dll"]
                    }
                }
            },
            "ImageProcessingAtom": {
                "Targets": {
                    "ImageProcessingAtom.Editor": {
                        "Modules":["ImageProcessingAtom.Editor.dll"]
                    }
                }
            },
            "AtomToolsFramework": {
                "Targets": {
                    "AtomToolsFramework.Editor": {
                        "Modules":["AtomToolsFramework.Editor.dll"]
                    }
                }
            },
            "Atom_RHI_DX12": {
                "Targets": {
                    "Atom_RHI_DX12.Builders": {
                        "Modules":["Atom_RHI_DX12.Builders.dll"]
                    },
                    "Atom_RHI_DX12.Private": {
                        "Modules":["Atom_RHI_DX12.Private.dll"]
                    }
                }
            }
        }
    }
}

You then add a Settings Registry specialization that is used to load the cmake_dependencies.voxeleditor.setreg file. This is done in C++ code via the SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization function as in the following example:

    //! This function returns the build system target name
    AZStd::string_view GetBuildTargetName()
    {
#if !defined (LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
        return AZStd::string_view{ LY_CMAKE_TARGET };
    }

    VoxelEditorApplication::VoxelEditorApplication(int* argc, char*** argv)
        : Application(argc, argv)
        , QApplication(*argc, *argv)
    {
        // The Settings Registry has been created at this point, so add the CMake target "voxeleditor"
        // as a specialization into the Settings Registry
        AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
            *AZ::SettingsRegistry::Get(), GetBuildTargetName());
    }

The AZ::ComponentApplication uses the Gem modules filenames stored within the Settings Registry to load the Gems from the filesystem. It also merges <GemRootPath>/Registry/*.setreg files for each Gem. CMake targets based on the game project can also generate a .setreg file by using the ly_enable_gems function.

The AtomTest project Gem uses the ly_enable_gems function to generate cmake_dependencies.atomtest.<target>.setreg files. That file contains the list of shared library file paths and Gem source directory to load as shown in the following example:

CMakeLists.txt (AtomTest)

ly_add_target(
    NAME AtomTest ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
    NAMESPACE Gem
    FILES_CMAKE
        atomtest_files.cmake
    INCLUDE_DIRECTORIES
        PUBLIC
            Include
    BUILD_DEPENDENCIES
        PRIVATE
            AZ::AzGameFramework
            Gem::Atom_LyIntegration.Static
)

# if enabled, AtomTest Gem is used by the Client and Server Launchers as well as Tools
# But it isn't needed in Builders
ly_create_alias(NAME AtomTest.Clients NAMESPACE Gem TARGETS Gem::AtomTest)
ly_create_alias(NAME AtomTest.Servers NAMESPACE Gem TARGETS Gem::AtomTest)
ly_create_alias(NAME AtomTest.Tools   NAMESPACE Gem TARGETS Gem::AtomTest)

################################################################################
# Gem dependencies
################################################################################
# The GameLauncher uses "Clients" Gem variants:
ly_enable_gems(PROJECT_NAME AtomTest GEM_FILE enabled_gems.cmake)

The ly_enable_gems function adds build and load dependencies to the AtomTest project.

During CMake generation, the Settings Registry files are generated in the <CMakeBuildDir>/bin/$<CONFIG> directory based on the ly_enable_gems functions. For example, configuring CMake for Windows with only the AtomTest project enabled generates the following .setreg files:

<CMakeBuildDir>\bin\profile\Registry\cmake_dependencies.atomtest.editor.setreg
<CMakeBuildDir>\bin\profile\Registry\cmake_dependencies.atomtest.assetprocessor.setreg
<CMakeBuildDir>\bin\profile\Registry\cmake_dependencies.atomtest.atomtest_gamelauncher.setreg
...

The generated project .setreg files are formatted as cmake_dependencies.<ProjectNameLower>.<CMakeTargetNameLower>.setreg. The project name is part of the generated cmake_dependencies.*.setreg file name because O3DE allows configuring multiple projects at once. The same applications, such as O3DE Editor and Asset Processor, are used for each game project, but the applications need to load a different set of Gems based on the active game project, so the project name is added as part of the CMake build dependencies Settings Registry files.

For example, if CMake is configured with the value of -DLY_PROJECTS="./AutomatedTesting;D:/o3de/AtomSampleViewer", the following .setreg files are generated:

D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.atomsampleviewer.assetbuilder.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.atomsampleviewer.assetprocessor.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.atomsampleviewer.assetprocessorbatch.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.atomsampleviewer.atomsampleviewer_gamelauncher.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.atomsampleviewer.editor.setreg

D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.automatedtesting.assetbuilder.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.automatedtesting.assetprocessor.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.automatedtesting.assetprocessorbatch.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.automatedtesting.automatedtesting_gamelauncher.setreg
D:\o3de\o3de\windows_vs2019\bin\profile\Registry\cmake_dependencies.automatedtesting.editor.setreg

Gems outside of <EngineRoot>/Gems

The list of Gem root directory paths is populated by CMake when it generates the build files for a platform. Since CMake knows the CMakeLists.txt location for each Gem, it’s able to generate a .setreg file with a list of Gems for each CMake target that sets a “Gem Variant” to load. This done by using the ly_set_gem_variant_to_load command. This list includes the filename of the Gem and the relative path to the Gem directory based on the source directory supplied to CMake during configuration.

The benefit of this is that if a Gem is added outside of the <EngineRoot> location using the cmake add_subdirectory command, then the Settings Registry can load any .setreg files within the <GemRoot>/Registry directory.

This can be used to include a specific Gem outside of the O3DE <EngineRoot> directory, as in the following example:

add_subdirectory(<AbsolutePathToMoleculeGem> <AbsolutePathToMoleculeGem>) # This doesn't have to be in the O3DE engine root
add_subdirectory(../<RelativePathToElectronGem> ../<RelativePathToElectronGem>)

Platform-specific Gem loading

Gems can be built and loaded on a per-platform basis by calling the ly_enable_gems function multiple times for a given variant with Platform Abstraction Layer (PAL) paths. CMake supports several Platform Abstraction variables that can be used to include specific enabled Gems based on the current platform (Windows, Linux, Android, and so on).

The following example demonstrates how to specify general and platform-specific Gem dependencies together:

o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_parent_relative_path}")
# Read a platform-specific CMake file that contains the names of Gems to activate
ly_enable_gems(PROJECT_NAME AtomTest GEM_FILE ${pal_dir}/enabled_gems.cmake)

Explicit Gem activation

As mentioned in Loading gems, Gem builds are determined by the list of Gems in the enabled_gems.cmake file. This file should not be manually modified. Instead, use the o3de.py, enable-gem, and disable-gem commands or Project Manager to add or remove Gems. This section explains how to enable and disable a Gem for building, as well as how to turn off autoloading of Gems using the Settings Registry.

The following example demonstrates using the o3de.py Python script commands to add and remove explicit Gem activation for a Gem named “Sponza” in the AutomatedTesting project:

# The following command adds explicit activation of the Sponza Gem within the AutomatedTesting project
# It will modify the enabled_gems.cmake file and conditionally the project.json file if the Gem being activated is registered with the global o3de_manifest.json
[engine-root]> scripts\o3de.bat enable-gem --gem-name Sponza --project-path AutomatedTesting
# The following command removes explicit activation of the Sponza Gem within the AutomatedTesting project
# It will modify the enabled_gems.cmake file and conditionally the project.json file if the Gem being activated is registered with the global o3de_manifest.json
[engine-root]> scripts\o3de.bat disable-gem --gem-name Sponza --project-path AutomatedTesting

Disable Gem autoloading

During the CMake project generation step, a cmake_dependencies.*.setreg file that contains a list of Gems to load is generated. To prevent autoloading of a specific Gem, set a JSON boolean value of false at the in JSON pointer format for the Gem using the path of "/O3DE/Gems/${GemName}/${TargetModule}/AutoLoad". For example, you can add a .setreg file in the "<project-root>/Registry/" directory that sets the "/O3DE/Gems/${GemName}/${TargetModule}/AutoLoad=false" value.

The following is a snippet of the generated cmake_dependencies.automatedtesting.assetproccessor.setreg that is generated when O3DE is configured with for the Automated Testing project (-DLY_PROJECTS=AutomatedTesting).

cmake_dependencies.automatedtesting.assetproccessor.setreg


{
    "O3DE": {
        "Gems": {
            "ChatPlay": {
                "ChatPlay": {
                    "Modules": ["ChatPlay.dll"]
                }
            },
            "QtForPython": {
                "QtForPython.Editor": {
                    "Modules": ["QtForPython.Editor.dll"]
                }
            },
            //...
        }
    }
}

The ChatPlay Client and QtForPython Tools modules can be disabled from autoloading on a per user basis by placing a .setreg file either in the <project_root>/User/Registry (per project override) or in the ~/.o3de/Registry global user override as in the following example:

gem_autoload.setreg

{
    "O3DE": {
        "Gems": {
            "ChatPlay": {
                "ChatPlay": {
                    "AutoLoad": false
                }
            },
            "QtForPython": {
                "QtForPython.Editor": {
                    "AutoLoad": false
                }
            }
        }
    }
}

To disable Gem autoloading at the project level, a .setreg file, such as the preceding example, can be placed in <project_root>/Registry, the project’s Registry directory.

To disable Gem autoloading at the platform level, a .setreg file, such as the preceding example, can be placed in the <O3DE root>/Registry/Platform/${PAL_PLATFORM_NAME} directory.

Load Gems in C++

You can manually load Gems in an application through C++ if needed. SettingsRegistryMergeUtils.cpp contains a function, MergeSettingsToRegistry_TargetBuildDependencyRegistry , that loads the cmake_dependencies.<tag1>.<tag2>.setreg files that contains the list of Gems to load. Gems are loaded based on the values in the “specialization” tag structure. The list of Gem modules is stored in the Setting Registry.

void MergeSettingsToRegistry_TargetBuildDependencyRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
    const SettingsRegistryInterface::Specializations& specializations, AZStd::vector<char>* scratchBuffer);

ComponentApplication.cpp is responsible for loading the required Gems through the LoadDynamicModule function, which reads the Settings Registry for all array keys at the paths of /O3DE/Gems/${GemName}/Modules and aggregates them into a list of Gems to load.

void ComponentApplication::LoadDynamicModules()
{
    // Queries the Settings Registry to get the list of Gem modules to load
    struct GemModuleLoadData
    {
        AZ::OSString m_gemName;
        AZStd::vector<AZ::OSString> m_dynamicLibraryPaths;
        bool m_autoLoad{ true };
    };
    // ...
}

Add a Gems scan folder

The Settings Registry supports configuring settings for Asset Processor. The AssetProcessorPlatformConfig.setreg file can be used as a reference for available settings: AssetProcessorPlatformConfig.setreg .

Gem asset scan folders

To add additional Scan Folders for an active Gem, a .setreg file can add a “ScanFolder <name>” under the the “/Amazon/AssetProcessor/Settings” field. The “<name>” portion can be anything as long as it doesn’t collide with another scan folder entry.

The following example adds the <Blast Gem Root>/Editor/Scripts folder as a Scan Folder for the Asset Processor:

{
    "Amazon": {
        "AssetProcessor": {
            "Settings": {
                "ScanFolder Blast/Scripts": {
                    "watch": "@GEMROOT:Blast@/Editor/Scripts",
                    "display": "Blast/Scripts",
                    "recursive": 1,
                    "order": 101
                }
            }
        }
    }
}