Forráskód Böngészése

Set enable gem variants feature (#3631)

* Implemented the RFC to allow projects to need to specify the Gems

Projects no longer need to specify CMake Targets to associate a Gem
variant with.

In order to associate a CMake Target with a gem variant a new
`ly_set_gem_variant_to_load` function has been added that maps CMake
Targets -> Gem Variants.

This allows CMake Targets to self describe which gem variants they
desire to build and load

This implementation is backwards compatible:
The `ly_enable_gems` function still accepts the TARGETS and VARIANTS
arguments which it will forward to the new `ly_set_gem_variant_to_load`
function to allow the input Targets to be associated with input Gem
Variants

This changes fixes the issue with gems that are required by an
Application regardless of the Project in use, not replicating it's
"requiredness" to the SDK layout

Fixes #3430

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Added an LY_PROJECT_NAME property to the Launcher targets

The `ly_enable_gems_delayed` now command queries the LY_PROJECT_NAME property
associated with each target to determine if the gems being enabled are
match the project the target is associated with.
In this case the target only adds dependencies if the gems is being enabled
without a specific project or if the gems is being enabled for the
matching project.

If the LY_PROJECT_NAME property is not set for target, it indicates the
gems for each project can be added as dependencies to the target.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* The INSTALL step now forwards the LY_PROJECT_NAME property for a target

The Install_common.cmake has been updated to support configuring
TARGET_PROPERTIES into the generated CMakeLists.txt for install targets.

Furthermore the indentation of the generated CMakeLists.txt has been
normalized to help with readability

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Updating the Atom_Bootstrap CMakeLists.txt to enable the Atom_Bootstrap Gem


Signed-off-by: lumberyard-employee-dm <[email protected]>

* Added a deprecation message to ly_enable_gems when supplying TARGETS and
VARIANTS

Added a define_property call for the LY_PROJECT_NAME target property
Removed the .Builders alias for the PrefabBuilder and renamed the
GEM_MODULE target o PrefabBuilder.Builders.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Removed superflous space from AutomatedTesting Gem CMakeLists.txt

Signed-off-by: lumberyard-employee-dm <[email protected]>
lumberyard-employee-dm 3 éve
szülő
commit
0ad2fe2294

+ 3 - 29
AutomatedTesting/Gem/Code/CMakeLists.txt

@@ -35,37 +35,11 @@ ly_create_alias(NAME AutomatedTesting.Servers  NAMESPACE Gem TARGETS Gem::Automa
 # Gem dependencies
 ################################################################################
 
-# The GameLauncher uses "Clients" gem variants:
-ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake
-    TARGETS AutomatedTesting.GameLauncher
-    VARIANTS Clients)
+# Enable the enabled_gems for the Project:
+ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake)
 
-# If we build a server, then apply the gems to the server
+# Add project to the list server projects to create the AutomatedTesting.ServerLauncher
 if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
-    # if we're making a server, then add the "Server" gem variants to it:
-    ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake
-        TARGETS AutomatedTesting.ServerLauncher
-        VARIANTS Servers)
-    
     set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS AutomatedTesting)
 endif()
 
-if (PAL_TRAIT_BUILD_HOST_TOOLS)
-    # The Editor uses "Tools" gem variants:
-    ly_enable_gems(
-        PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake
-        TARGETS Editor
-        VARIANTS Tools)
-
-    # The Material Editor needs the Lyshine "Tools" gem variant for the custom LyShine pass
-    ly_enable_gems(
-        PROJECT_NAME AutomatedTesting GEMS LyShine
-        TARGETS MaterialEditor
-        VARIANTS Tools)
-
-    # The pipeline tools use "Builders" gem variants:
-    ly_enable_gems(
-        PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake
-        TARGETS AssetBuilder AssetProcessor AssetProcessorBatch
-        VARIANTS Builders)
-endif()

+ 2 - 0
Code/Editor/CMakeLists.txt

@@ -174,6 +174,8 @@ ly_add_target(
         Legacy::EditorLib
         ProjectManager
 )
+
+ly_set_gem_variant_to_load(TARGETS Editor VARIANTS Tools)
 set_property(SOURCE
     CryEdit.cpp
     APPEND PROPERTY

+ 9 - 1
Code/LauncherUnified/launcher_generator.cmake

@@ -6,8 +6,8 @@
 #
 #
 
-
 set_property(GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
 # Launcher targets for a project need to be generated when configuring a project.
 # When building the engine source, this file will be included by LauncherUnified's CMakeLists.txt
 # When using an installed engine, this file will be included by the FindLauncherGenerator.cmake script
@@ -121,6 +121,7 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
     set_target_properties(${project_name}.GameLauncher
         PROPERTIES 
             FOLDER ${project_name}
+            LY_PROJECT_NAME ${project_name}
     )
 
     # After ensuring that we correctly support DPI scaling, this should be switched to "PerMonitor"
@@ -129,6 +130,9 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
         set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\"")
     endif()
 
+    # Associate the Clients Gem Variant with each projects GameLauncher
+    ly_set_gem_variant_to_load(TARGETS ${project_name}.GameLauncher VARIANTS Clients)
+
     ################################################################################
     # Server
     ################################################################################
@@ -168,11 +172,15 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
             set_target_properties(${project_name}.ServerLauncher
                 PROPERTIES 
                     FOLDER ${project_name}
+                    LY_PROJECT_NAME ${project_name}
             )
 
             if(LY_DEFAULT_PROJECT_PATH)
                 set_property(TARGET ${project_name}.ServerLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\"")
             endif()
+
+            # Associate the Servers Gem Variant with each projects ServerLauncher
+            ly_set_gem_variant_to_load(TARGETS ${project_name}.ServerLauncher VARIANTS Servers)
         endif()
 
     endif()

+ 1 - 0
Code/LauncherUnified/launcher_project_files.cmake

@@ -9,4 +9,5 @@
 set(FILES
     LauncherProject.cpp
     StaticModules.in
+    launcher_generator.cmake
 )

+ 1 - 0
Code/Tools/AssetProcessor/AssetBuilder/CMakeLists.txt

@@ -39,6 +39,7 @@ ly_add_source_properties(
 )
 
 if(TARGET AssetBuilder)
+    ly_set_gem_variant_to_load(TARGETS AssetBuilder VARIANTS Builders)
     # Adds the AssetBuilder target as a C preprocessor define so that it can be used as a Settings Registry
     # specialization in order to look up the generated .setreg which contains the dependencies
     # specified for the AssetBuilder in the <Project>/Gem/Code/CMakeLists via ly_add_project_dependencies

+ 2 - 0
Code/Tools/AssetProcessor/CMakeLists.txt

@@ -81,6 +81,7 @@ ly_add_target(
 # specialization in order to look up the generated .setreg which contains the dependencies
 # specified for the target.
 if(TARGET AssetProcessor)
+    ly_set_gem_variant_to_load(TARGETS AssetProcessor VARIANTS Builders)
     set_source_files_properties(
         native/AssetProcessorBuildTarget.cpp
         PROPERTIES
@@ -130,6 +131,7 @@ endif()
 # specialization in order to look up the generated .setreg which contains the dependencies
 # specified for the target.
 if(TARGET AssetProcessorBatch)
+    ly_set_gem_variant_to_load(TARGETS AssetProcessorBatch VARIANTS Builders)
     set_source_files_properties(
         native/AssetProcessorBatchBuildTarget.cpp
         PROPERTIES

+ 1 - 2
Gems/Atom/Asset/Shader/Code/CMakeLists.txt

@@ -101,8 +101,7 @@ ly_add_target(
 
 # The Atom_Asset_Shader is a required gem for Builders in order to process the assets that come WITHOUT
 # the Atom_Feature_Common required gem
-ly_enable_gems(GEMS Atom_Asset_Shader VARIANTS Builders
-    TARGETS AssetBuilder AssetProcessor AssetProcessorBatch)
+ly_enable_gems(GEMS Atom_Asset_Shader)
 
 ################################################################################
 # Tests

+ 1 - 11
Gems/Atom/Bootstrap/Code/CMakeLists.txt

@@ -45,14 +45,4 @@ ly_create_alias(NAME Atom_Bootstrap.Clients NAMESPACE Gem TARGETS Gem::Atom_Boot
 ly_create_alias(NAME Atom_Bootstrap.Servers NAMESPACE Gem TARGETS Gem::Atom_Bootstrap)
 
 # The Atom_Bootstrap gem is responsible for making the NativeWindow handle in the launcher applications
-# Loop over each Project name to allow the ${ProjectName}.GameLauncher and ${ProjectName}.ServerLauncher
-# target to add the gem the Clients and Servers variant
-get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
-foreach(project_name IN LISTS LY_PROJECTS_TARGET_NAME)
-    # Add gem as a dependency of the Clients Launcher
-    ly_enable_gems(PROJECT_NAME ${project_name} GEMS Atom_Bootstrap VARIANTS Clients TARGETS ${project_name}.GameLauncher)
-    # Add gem as a dependency of the Servers Launcher
-    if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
-        ly_enable_gems(PROJECT_NAME ${project_name} GEMS Atom_Bootstrap VARIANTS Servers TARGETS ${project_name}.ServerLauncher)
-    endif()
-endforeach()
+ly_enable_gems(GEMS Atom_Bootstrap)

+ 3 - 0
Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt

@@ -133,6 +133,9 @@ ly_add_target_dependencies(
     DEPENDENCIES_FILES
         tool_dependencies.cmake
         Source/Platform/${PAL_PLATFORM_NAME}/tool_dependencies_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
+    # The Material Editor needs the LyShine "Tools" gem variant for the custom LyShine pass
+    DEPENDENT_TARGETS
+        Gem::LyShine.Tools
 )
 
 # Inject the project path into the MaterialEditor VS debugger command arguments if the build system being invoked

+ 5 - 22
Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt

@@ -123,27 +123,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
             Gem::AtomLyIntegration_CommonFeatures.Editor
             Gem::GradientSignal.Tools
     )
-
-    # AtomLyIntergration_CommonFeatures gem targets are required as part of the Editor and AssetProcessor
-    # due to the AZ::Render::EditorDirectionalLightComponent, AZ::Render::EditorMeshComponent,
-    # AZ::Render::EditorGridComponent, AZ::Render::EditorHDRiSkyboxComponent,
-    # AZ::Render::EditorImageBasedLightComponent being saved as part of the DefaultLevel.prefab
-    ly_enable_gems(GEMS AtomLyIntegration_CommonFeatures VARIANTS Tools
-        TARGETS Editor)
-    ly_enable_gems(GEMS AtomLyIntegration_CommonFeatures VARIANTS Builders
-        TARGETS AssetBuilder AssetProcessor AssetProcessorBatch)
 endif()
 
-
-# Added dependencies to the Client and Server Launchers
-get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
-foreach(project_name IN LISTS LY_PROJECTS_TARGET_NAME)
-    # Add gem as a dependency of the Clients Launcher
-    ly_enable_gems(PROJECT_NAME ${project_name} GEMS AtomLyIntegration_CommonFeatures VARIANTS Clients
-        TARGETS ${project_name}.GameLauncher)
-    # Add gem as a dependency of the Servers Launcher
-    if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
-        ly_enable_gems(PROJECT_NAME ${project_name} GEMS AtomLyIntegration_CommonFeatures VARIANTS Servers
-            TARGETS ${project_name}.ServerLauncher)
-    endif()
-endforeach()
+# AtomLyIntegration_CommonFeatures gem targets are required as part of the Editor and AssetProcessor
+# due to the AZ::Render::EditorDirectionalLightComponent, AZ::Render::EditorMeshComponent,
+# AZ::Render::EditorGridComponent, AZ::Render::EditorHDRiSkyboxComponent,
+# AZ::Render::EditorImageBasedLightComponent being saved as part of the DefaultLevel.prefab
+ly_enable_gems(GEMS AtomLyIntegration_CommonFeatures)

+ 2 - 17
Gems/Camera/Code/CMakeLists.txt

@@ -66,22 +66,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
     # tools and builders use the above module.
     ly_create_alias(NAME Camera.Tools NAMESPACE    Gem TARGETS Gem::Camera.Editor)
     ly_create_alias(NAME Camera.Builders NAMESPACE Gem TARGETS Gem::Camera.Editor)
-
-    # The DefaultPrefab contains an EditorCameraComponent which makes this gem required
-    ly_enable_gems(GEMS Camera VARIANTS Tools TARGETS Editor)
-    ly_enable_gems(GEMS Camera VARIANTS Builders TARGETS AssetBuilder AssetProcessor AssetProcessorBatch)
 endif()
 
-
-# Added dependencies to the Client and Server Launchers
-get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
-foreach(project_name IN LISTS LY_PROJECTS_TARGET_NAME)
-    # Add gem as a dependency of the Clients Launcher
-    ly_enable_gems(PROJECT_NAME ${project_name} GEMS Camera VARIANTS Clients
-        TARGETS ${project_name}.GameLauncher)
-    # Add gem as a dependency of the Servers Launcher
-    if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
-        ly_enable_gems(PROJECT_NAME ${project_name} GEMS Camera VARIANTS Servers
-            TARGETS ${project_name}.ServerLauncher)
-    endif()
-endforeach()
+# The DefaultPrefab contains an EditorCameraComponent which makes this gem required
+ly_enable_gems(GEMS Camera)

+ 2 - 15
Gems/Maestro/Code/CMakeLists.txt

@@ -75,23 +75,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
     ly_create_alias(NAME Maestro.Tools    NAMESPACE Gem TARGETS Gem::Maestro.Editor)
     ly_create_alias(NAME Maestro.Builders NAMESPACE Gem TARGETS Gem::Maestro.Editor)
 
-    # Maestro is still used by the CrySystem Level System and SystemInit and TrackView
-    # It is required by the GameLauncher, ServerLauncher and Editor applications
-    ly_enable_gems(GEMS Maestro VARIANTS Tools TARGETS Editor)
-
 endif()
 
-# Loop over each Project name to allow the ${ProjectName}.GameLauncher and ${ProjectName}.ServerLauncher
-# target to add the gem the Clients and Servers variant
-get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME)
-foreach(project_name IN LISTS LY_PROJECTS_TARGET_NAME)
-    # Add gem as a dependency of the Clients Launcher
-    ly_enable_gems(PROJECT_NAME ${project_name} GEMS Maestro VARIANTS Clients TARGETS ${project_name}.GameLauncher)
-    # Add gem as a dependency of the Servers Launcher
-    if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
-        ly_enable_gems(PROJECT_NAME ${project_name} GEMS Maestro VARIANTS Servers TARGETS ${project_name}.ServerLauncher)
-    endif()
-endforeach()
+# Maestro is still used by the CrySystem Level System, CSystem::SystemInit and TrackView
+ly_enable_gems(GEMS Maestro)
 
 
 ################################################################################

+ 2 - 8
Gems/Prefab/PrefabBuilder/CMakeLists.txt

@@ -23,7 +23,7 @@ ly_add_target(
 )
 
 ly_add_target(
-    NAME PrefabBuilder GEM_MODULE
+    NAME PrefabBuilder.Builders GEM_MODULE
     NAMESPACE Gem
     INCLUDE_DIRECTORIES
         PRIVATE
@@ -36,15 +36,9 @@ ly_add_target(
 )
 
 # the prefab builder only needs to be active in builders
-# use the PrefabBuilder module in Clients and Servers:
-ly_create_alias(NAME PrefabBuilder.Builders NAMESPACE Gem TARGETS Gem::PrefabBuilder)
 
 # we automatically add this gem, if it is present, to all our known set of builder applications:
-ly_enable_gems(GEMS PrefabBuilder VARIANTS Builders TARGETS AssetProcessor AssetProcessorBatch AssetBuilder)
-
-# if you have a custom builder application in your project, then use ly_enable_gems() to
-# add it to that application for your project, like this to make YOUR_TARGET_NAME load it automatically
-# ly_enable_gems(PROJECT_NAME (YOUR_PROJECT_NAME) GEMS PrefabBuilder VARIANTS Builders TARGETS (YOUR_TARGET_NAME) )
+ly_enable_gems(GEMS PrefabBuilder)
 
 if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
     ly_add_target(

+ 2 - 6
Gems/SceneProcessing/Code/CMakeLists.txt

@@ -68,14 +68,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
     ly_create_alias(NAME SceneProcessing.Builders NAMESPACE Gem TARGETS Gem::SceneProcessing.Editor)
     ly_create_alias(NAME SceneProcessing.Tools    NAMESPACE Gem TARGETS Gem::SceneProcessing.Editor)
 
-# SceneProcessing Gem is only used in Tools and builders and is a requirement for the Editor
-ly_enable_gems(GEMS SceneProcessing VARIANTS Tools
-    TARGETS Editor)
-ly_enable_gems(GEMS SceneProcessing VARIANTS Builders
-    TARGETS AssetBuilder AssetProcessor AssetProcessorBatch)
+    # SceneProcessing Gem is only used in Tools and builders and is a requirement for the Editor and AssetProcessor
+    ly_enable_gems(GEMS SceneProcessing)
 endif()
 
-
 ################################################################################
 # Tests
 ################################################################################

+ 1 - 2
Gems/ScriptCanvas/Code/CMakeLists.txt

@@ -47,8 +47,7 @@ ly_add_target(
 )
 
 # the script canvas debugger is an optional gem module
-# To Enable it: ly_enable_gems( ... TARGETS xxxyyzzz GEMS ScriptCanvasDebugger ...)
-# in any particular target.
+# To Enable it, associate it with a project
 ly_create_alias(NAME ScriptCanvasDebugger.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger)
 ly_create_alias(NAME ScriptCanvasDebugger.Tools    NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger)
 ly_create_alias(NAME ScriptCanvasDebugger.Clients  NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger)

+ 2 - 36
Templates/DefaultProject/Template/Code/CMakeLists.txt

@@ -68,46 +68,12 @@ ly_create_alias(NAME ${Name}.Servers  NAMESPACE Gem TARGETS Gem::${Name})
 # Gem dependencies
 ################################################################################
 
-# The GameLauncher uses "Clients" gem variants:
-ly_enable_gems(
-    PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-    TARGETS 
-        ${Name}.GameLauncher
-    VARIANTS 
-        Clients)
-
-if(PAL_TRAIT_BUILD_HOST_TOOLS)
-
-    # the builder type applications use the "Builders" variants of the enabled gems.
-    ly_enable_gems(
-        PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-        TARGETS
-            AssetBuilder
-            AssetProcessor
-            AssetProcessorBatch
-        VARIANTS 
-            Builders)
-    
-    # the Editor applications use the "Tools" variants of the enabled gems.
-    ly_enable_gems(
-        PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-        TARGETS
-            Editor
-        VARIANTS 
-            Tools)
-endif()
+# Enable the specified list of gems from GEM_FILE or GEMS list for this specific project:
+ly_enable_gems(PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake)
 
 if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
     # this property causes it to actually make a ServerLauncher.
     # if you don't want a Server application, you can remove this and the
     # following ly_enable_gems lines.
     set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS ${Name})
-    
-    # The ServerLauncher uses the "Servers" variants of enabled gems:
-    ly_enable_gems(
-        PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-        TARGETS
-            ${Name}.ServerLauncher
-        VARIANTS 
-            Servers)
 endif()

+ 2 - 35
Templates/MinimalProject/Template/Code/CMakeLists.txt

@@ -68,46 +68,13 @@ ly_create_alias(NAME ${Name}.Servers  NAMESPACE Gem TARGETS Gem::${Name})
 # Gem dependencies
 ################################################################################
 
-# The GameLauncher uses "Clients" gem variants:
-ly_enable_gems(
-    PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-    TARGETS 
-        ${Name}.GameLauncher
-    VARIANTS 
-        Clients)
+# Enable the specified list of gems from GEM_FILE or GEMS list for this specific project:
+ly_enable_gems(PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake)
 
-if(PAL_TRAIT_BUILD_HOST_TOOLS)
-
-    # the builder type applications use the "Builders" variants of the enabled gems.
-    ly_enable_gems(
-        PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-        TARGETS
-            AssetBuilder
-            AssetProcessor
-            AssetProcessorBatch
-        VARIANTS 
-            Builders)
-    
-    # the Editor applications use the "Tools" variants of the enabled gems.
-    ly_enable_gems(
-        PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-        TARGETS
-            Editor
-        VARIANTS 
-            Tools)
-endif()
 
 if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
     # this property causes it to actually make a ServerLauncher.
     # if you don't want a Server application, you can remove this and the
     # following ly_enable_gems lines.
     set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS ${Name})
-    
-    # The ServerLauncher uses the "Servers" variants of enabled gems:
-    ly_enable_gems(
-        PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake
-        TARGETS
-            ${Name}.ServerLauncher
-        VARIANTS 
-            Servers)
 endif()

+ 3 - 1
cmake/Dependencies.cmake

@@ -35,7 +35,9 @@ function(ly_add_dependencies TARGET)
     if(TARGET ${TARGET})
         # Target already created, add it
         ly_parse_third_party_dependencies("${extra_function_args}")
-        add_dependencies(${TARGET} ${extra_function_args})
+        # Dependencies can only be added on non-alias target
+        ly_de_alias_target(${TARGET} de_aliased_target)
+        add_dependencies(${de_aliased_target} ${extra_function_args})
     else()
         set_property(GLOBAL APPEND PROPERTY LY_DELAYED_DEPENDENCIES_${TARGET} ${extra_function_args})
     endif()

+ 193 - 121
cmake/Gems.cmake

@@ -6,7 +6,13 @@
 #
 #
 
-# This file contains utility wrappers for dealing with the Gems system. 
+# This file contains utility wrappers for dealing with the Gems system.
+
+define_property(TARGET PROPERTY LY_PROJECT_NAME
+    BRIEF_DOCS "Name of the project, this target can use enabled gems from"
+    FULL_DOCS "If set, the when iterating over the enabled gems in ly_enabled_gems_delayed
+    only a project with that name can have it's enabled gem list added as a dependency to this target.
+    If the __NOPROJECT__ placeholder is associated with a list enabled gems, then it applies to this target regardless of this property value")
 
 # ly_create_alias
 # given an alias to create, and a list of one or more targets,
@@ -34,7 +40,8 @@ function(ly_create_alias)
 
     # easy version - if its just one target and it exist at the time of this call,
     # we can directly get the target, and make both aliases,
-    # the namespaced and non namespaced one, point at it.
+    # the namespace and non namespace one, point at it.
+    set(create_interface_target TRUE)
     list(LENGTH ly_create_alias_TARGETS number_of_targets)
     if (number_of_targets EQUAL 1)
         if(TARGET ${ly_create_alias_TARGETS})
@@ -43,11 +50,7 @@ function(ly_create_alias)
             if (NOT TARGET ${ly_create_alias_NAME})
                 add_library(${ly_create_alias_NAME} ALIAS ${de_aliased_target_name})
             endif()
-            # Store off the arguments needed used ly_create_alias into a DIRECTORY property
-            # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step
-            string(REPLACE ";" " " create_alias_args "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}")
-            set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}")
-            return()
+            set(create_interface_target FALSE)
         endif()
     endif()
 
@@ -55,41 +58,48 @@ function(ly_create_alias)
     # To actually achieve this we have to create an interface library with those dependencies,
     # then we have to create an alias to that target.
     # By convention we create one without a namespace then alias the namespaced one.
+    if(create_interface_target)
+        if(TARGET ${ly_create_alias_NAME})
+            message(FATAL_ERROR "Internal alias target already exists, cannot create an alias for it: ${ly_create_alias_NAME}\n"
+                                "This could be a copy-paste error, where some part of the ly_create_alias call was changed but the other")
+        endif()
 
-    if(TARGET ${ly_create_alias_NAME})
-        message(FATAL_ERROR "Internal alias target already exists, cannot create an alias for it: ${ly_create_alias_NAME}\n"
-                            "This could be a copy-paste error, where some part of the ly_create_alias call was changed but the other")
-    endif()
-
-    add_library(${ly_create_alias_NAME} INTERFACE IMPORTED GLOBAL)
-    set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE)
+        add_library(${ly_create_alias_NAME} INTERFACE IMPORTED GLOBAL)
+        set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE)
 
-    foreach(target_name ${ly_create_alias_TARGETS})
-        if(TARGET ${target_name})
-            ly_de_alias_target(${target_name} de_aliased_target_name)
-            if(NOT de_aliased_target_name)
-                message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name")
+        foreach(target_name ${ly_create_alias_TARGETS})
+            if(TARGET ${target_name})
+                ly_de_alias_target(${target_name} de_aliased_target_name)
+                if(NOT de_aliased_target_name)
+                    message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name")
+                endif()
+            else()
+                set(de_aliased_target_name ${target_name})
             endif()
-        else()
-            set(de_aliased_target_name ${target_name})
-        endif()
-        list(APPEND final_targets ${de_aliased_target_name})
-    endforeach()
+            list(APPEND final_targets ${de_aliased_target_name})
+        endforeach()
     
-    # add_dependencies must be called with at least one dependent target
-    if(final_targets)
-        ly_parse_third_party_dependencies("${final_targets}")
-        ly_add_dependencies(${ly_create_alias_NAME} ${final_targets})
-    endif()
+        # add_dependencies must be called with at least one dependent target
+        if(final_targets)
+            ly_parse_third_party_dependencies("${final_targets}")
+            ly_add_dependencies(${ly_create_alias_NAME} ${final_targets})
+        endif()
 
-    # now add the final alias:
-    add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME})
+        # now add the final alias:
+        add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME})
+    endif()
 
     # Store off the arguments used by ly_create_alias into a DIRECTORY property
     # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step
-
-    # Replace the CMake list separator with a space to replicate the space separated TARGETS arguments
-    string(REPLACE ";" " " create_alias_args "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}")
+    # Replace the CMake list separator with a space to replicate the space separated arguments
+    # A single create_alias_args variable encodes two values. The alias NAME used to check if the target exists
+    # and the ly_create_alias arguments to replace this function call
+    unset(create_alias_args)
+    list(APPEND create_alias_args "${ly_create_alias_NAME},"
+        NAME ${ly_create_alias_NAME}
+        NAMESPACE ${ly_create_alias_NAMESPACE}
+        TARGETS ${ly_create_alias_TARGETS})
+    list(JOIN create_alias_args " " create_alias_args)
     set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${create_alias_args}")
 
     # Store the directory path in the GLOBAL property so that it can be accessed
@@ -100,13 +110,54 @@ function(ly_create_alias)
     endif()
 endfunction()
 
+# ly_set_gem_variant_to_load
+# Associates a key, value entry of CMake target -> Gem variant
+# \arg:TARGETS - list of Targets to associate with the Gem variant
+# \arg:VARIANTS - Gem variant
+function(ly_set_gem_variant_to_load)
+    set(options)
+    set(oneValueArgs)
+    set(multiValueArgs TARGETS VARIANTS)
+
+    cmake_parse_arguments(ly_set_gem_variant_to_load "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    if (NOT ly_set_gem_variant_to_load_TARGETS)
+        message(FATAL_ERROR "You must provide at least 1 target to ${CMAKE_CURRENT_FUNCTION} using the TARGETS keyword")
+    endif()
+
+    # Store a list of targets
+    foreach(target_name ${ly_set_gem_variant_to_load_TARGETS})
+        # Append the target to the list of targets with variants if it has not been added
+        get_property(ly_targets_with_variants GLOBAL PROPERTY LY_TARGETS_WITH_GEM_VARIANTS)
+        if(NOT target_name IN_LIST ly_targets_with_variants)
+            set_property(GLOBAL APPEND PROPERTY LY_TARGETS_WITH_GEM_VARIANTS "${target_name}")
+        endif()
+        foreach(variant_name ${ly_set_gem_variant_to_load_VARIANTS})
+            get_property(target_gem_variants GLOBAL PROPERTY LY_GEM_VARIANTS_"${target_name}")
+            if(NOT variant_name IN_LIST target_gem_variants)
+                set_property(GLOBAL APPEND PROPERTY LY_GEM_VARIANTS_"${target_name}" "${variant_name}")
+            endif()
+        endforeach()
+    endforeach()
+
+    # Store of the arguments used to invoke this function in order to replicate the call in the generated CMakeLists.txt
+    # in the install layout
+    unset(set_gem_variant_args)
+    list(APPEND set_gem_variant_args
+        TARGETS ${ly_set_gem_variant_to_load_TARGETS}
+        VARIANTS ${ly_set_gem_variant_to_load_VARIANTS})
+    # Replace the list separator with space to have it be stored as a single property element
+    list(JOIN set_gem_variant_args " " set_gem_variant_args)
+    set_property(DIRECTORY APPEND PROPERTY LY_SET_GEM_VARIANT_TO_LOAD_ARGUMENTS "${set_gem_variant_args}")
+endfunction()
+
 # ly_enable_gems
 # this function makes sure that the given gems, or gems listed in the variable ENABLED_GEMS
 # in the GEM_FILE name, are set as runtime dependencies (and thus loaded) for the given targets
 # in the context of the given project.
 # note that it can't do this immediately, so it saves the data for later processing.
 # Note: If you don't supply a project name, it will apply it across the board to all projects.
-# this is useful in the case of "ly_add_gems being called for so called 'mandatory gems' inside the engine.
+# this is useful in the case of "ly_enable_gems" being called for so called 'mandatory gems' inside the engine.
 # if you specify a gem name with a namespace, it will be used, otherwise it will assume Gem::
 function(ly_enable_gems)
     set(options)
@@ -115,23 +166,21 @@ function(ly_enable_gems)
 
     cmake_parse_arguments(ly_enable_gems "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 
-    if (NOT ly_enable_gems_TARGETS)
-        message(FATAL_ERROR "You must provide the targets to add gems to using the TARGETS keyword")
-    endif()
-       
-
     if (NOT ly_enable_gems_PROJECT_NAME)
         message(VERBOSE "Note: ly_enable_gems called with no PROJECT_NAME name, applying to all projects: \n"
-            "   - VARIANTS ${ly_enable_gems_VARIANTS} \n"
-            "   - GEMS     ${ly_enable_gems_GEMS} \n" 
-            "   - TARGETS  ${ly_enable_gems_TARGETS} \n"
+            "   - GEMS     ${ly_enable_gems_GEMS} \n"
             "   - GEM_FILE ${ly_enable_gems_GEM_FILE}")
         set(ly_enable_gems_PROJECT_NAME "__NOPROJECT__") # so that the token is not blank
     endif()
 
-    if (NOT ly_enable_gems_VARIANTS)
-        message(FATAL_ERROR "You must provide at least 1 variant of the gem modules (Editor, Server, Client, Builder) to "
-                            "add to your targets, using the VARIANTS keyword")
+    # Backwards-Compatibility - Delegate any TARGETS and VARIANTS arguments to the ly_set_gem_variant_to_load
+    # command. That command is used to associate TARGETS with the list of Gem Variants they desire to use
+    if (ly_enable_gems_TARGETS AND ly_enable_gems_VARIANTS)
+        message(DEPRECATION "The TARGETS and VARIANTS arguments to \"${CMAKE_CURRENT_FUNCTION}\" is deprecated.\n"
+            "Please use the \"ly_set_gem_variant_to_load\" function directly to associate a Target with a Gem Variant.\n"
+            "This function will forward the TARGETS and VARIANTS arguments to \"ly_set_gem_variant_to_load\" for now,"
+            " but this functionality will be removed.")
+        ly_set_gem_variant_to_load(TARGETS ${ly_enable_gems_TARGETS} VARIANTS ${ly_enable_gems_VARIANTS})
     endif()
 
     if ((NOT ly_enable_gems_GEMS AND NOT ly_enable_gems_GEM_FILE) OR (ly_enable_gems_GEMS AND ly_enable_gems_GEM_FILE))
@@ -153,103 +202,126 @@ function(ly_enable_gems)
     endif()
 
     # all the actual work has to be done later.
-    foreach(target_name ${ly_enable_gems_TARGETS})
-        foreach(variant_name ${ly_enable_gems_VARIANTS})
-            set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS "${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}")
-            define_property(GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}"
-                BRIEF_DOCS "List of gem names to evaluate variants against" FULL_DOCS "Names of gems that will be paired with the variant name
-                    to determine if it is valid target that should be added as an application dynamic load dependency")
-            set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}" ${ly_enable_gems_GEMS})
-        endforeach()
-    endforeach()
+    set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS "${ly_enable_gems_PROJECT_NAME}")
+    define_property(GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME}"
+        BRIEF_DOCS "List of gem names to evaluate variants against" FULL_DOCS "Names of gems that will be paired with the variant name
+            to determine if it is valid target that should be added as an application dynamic load dependency")
+    set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME}" ${ly_enable_gems_GEMS})
 
     # Store off the arguments used by ly_enable_gems into a DIRECTORY property
     # This will be used to re-create the ly_enable_gems call in the generated CMakeLists.txt at the INSTALL step
 
     # Replace the CMake list separator with a space to replicate the space separated TARGETS arguments
     if(NOT ly_enable_gems_PROJECT_NAME STREQUAL "__NOPROJECT__")
-        set(replicated_project_name ${ly_enable_gems_PROJECT_NAME})
+        set(replicated_project_name PROJECT_NAME ${ly_enable_gems_PROJECT_NAME})
     endif()
     # The GEM_FILE file is used to populate the GEMS argument via the ENABLED_GEMS variable in the file.
     # Furthermore the GEM_FILE itself is not copied over to the install layout, so make its argument entry blank and use the list of GEMS
     # stored in ly_enable_gems_GEMS
-    string(REPLACE ";" " " enable_gems_args "${replicated_project_name},${ly_enable_gems_GEMS},,${ly_enable_gems_VARIANTS},${ly_enable_gems_TARGETS}")
+    unset(enable_gems_args)
+    list(APPEND enable_gems_args
+        ${replicated_project_name}
+        GEMS ${ly_enable_gems_GEMS})
+    list(JOIN enable_gems_args " " enable_gems_args)
     set_property(DIRECTORY APPEND PROPERTY LY_ENABLE_GEMS_ARGUMENTS "${enable_gems_args}")
 endfunction()
 
-# call this before runtime dependencies are used to add any relevant targets
-# saved by the above function
-function(ly_enable_gems_delayed)
-    get_property(ly_delayed_enable_gems GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS)
-    foreach(project_target_variant ${ly_delayed_enable_gems})
-        # we expect a colon separated list of
-        # PROJECT_NAME,target_name,variant_name
-        string(REPLACE "," ";" project_target_variant_list "${project_target_variant}")
-        list(LENGTH project_target_variant_list project_target_variant_length)
-        if(project_target_variant_length EQUAL 0)
-            continue()
-        endif()
-        
-        if(NOT project_target_variant_length EQUAL 3)
-            message(FATAL_ERROR "Invalid specification of gems, expected 'project','target','variant' and got ${project_target_variant}")
-        endif()
 
-        list(POP_BACK project_target_variant_list variant)
-        list(POP_BACK project_target_variant_list target)
-        list(POP_BACK project_target_variant_list project)
-
-        get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project_target_variant}")
-        if (NOT gem_dependencies)
-            get_property(gem_dependencies_defined GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project_target_variant}" DEFINED)
-            if (gem_dependencies_defined)
-                # special case, if the LY_DELAYED_ENABLE_GEMS_"${project_target_variant}" property is DEFINED
-                # but empty, add an entry to the LY_DELAYED_LOAD_DEPENDENCIES to have the
-                # cmake_dependencies.*.setreg file for the (project, target) tuple to be regenerated
-                # This is needed if the ENABLED_GEMS list for a project goes from >0 to 0. In this case
-                # the cmake_dependencies would have a stale list of gems to load unless it is regenerated
-                get_property(delayed_load_target_set GLOBAL PROPERTY LY_DELAYED_LOAD_"${project},${target}" SET)
-                if(NOT delayed_load_target_set)
-                    set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_DEPENDENCIES "${project},${target}")
-                    set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_"${project},${target}" "")
-                endif()
-            endif()
-            # Continue to the next iteration loop regardless as there are no gem dependencies
-            continue()
-        endif()
+function(ly_add_gem_dependencies_to_project_variants)
+    set(options)
+    set(oneValueArgs PROJECT_NAME TARGET VARIANT)
+    set(multiValueArgs GEM_DEPENDENCIES)
+
+    cmake_parse_arguments(ly_add_gem_dependencies "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+    if (NOT ly_add_gem_dependencies_PROJECT_NAME)
+        message(FATAL_ERROR "Missing required PROJECT_NAME argument which is used to determine gem load prefix")
+    endif()
+    if (NOT ly_add_gem_dependencies_TARGET)
+        message(FATAL_ERROR "Missing required TARGET argument ")
+    endif()
+    if (NOT ly_add_gem_dependencies_VARIANT)
+        message(FATAL_ERROR "Missing required gem VARIANT argument needed to determine which gem variants to load for the target")
+    endif()
 
-        if(${project} STREQUAL "__NOPROJECT__")
-            # special case, apply to all
-            unset(PREFIX_CLAUSE)
-        else()
-            set(PREFIX_CLAUSE "PREFIX;${project}")
+    if(${ly_add_gem_dependencies_PROJECT_NAME} STREQUAL "__NOPROJECT__")
+        # special case, apply to all
+        unset(PREFIX_CLAUSE)
+    else()
+        set(PREFIX_CLAUSE "PREFIX;${ly_add_gem_dependencies_PROJECT_NAME}")
+    endif()
+
+    # apply the list of gem targets.  Adding a gem really just means adding the appropriate dependency.
+    foreach(gem_name ${ly_add_gem_dependencies_GEM_DEPENDENCIES})
+        set(gem_target ${gem_name}.${ly_add_gem_dependencies_VARIANT})
+
+        # if the target exists, add it.
+        if (TARGET ${gem_target})
+            # Dealias actual target
+            ly_de_alias_target(${gem_target} dealiased_gem_target)
+            ly_add_target_dependencies(
+                ${PREFIX_CLAUSE}
+                TARGETS ${ly_add_gem_dependencies_TARGET}
+                DEPENDENT_TARGETS ${dealiased_gem_target})
         endif()
+    endforeach()
+endfunction()
+
+# call this before runtime dependencies are used to add any relevant targets
+# saved by the above function
+function(ly_enable_gems_delayed)
+    # Query the list of targets that are associated with a gem variant
+    get_property(targets_with_variants GLOBAL PROPERTY LY_TARGETS_WITH_GEM_VARIANTS)
+    # Query the projects that have made calls to ly_enable_gems
+    get_property(enable_gem_projects GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS)
 
+    foreach(target ${targets_with_variants})
         if (NOT TARGET ${target})
-            message(FATAL_ERROR "ly_enable_gems specified TARGET '${target}' but no such target was found.")
+            message(FATAL_ERROR "ly_set_gem_variant_to_load specified TARGET '${target}' but no such target was found.")
         endif()
 
-        # apply the list of gem targets.  Adding a gem really just means adding the appropriate dependency.
-        foreach(gem_name ${gem_dependencies})
-            # the gem name may already have a namespace.  If it does, we use that one
-            ly_strip_target_namespace(TARGET ${gem_name} OUTPUT_VARIABLE unaliased_gem_name)
-            if (${unaliased_gem_name} STREQUAL ${gem_name})
-                # if stripping a namespace had no effect, it had no namespace
-                # and we supply the default Gem:: namespace.
-                set(gem_name_with_namespace Gem::${gem_name})
-            else()
-                # if stripping the namespace had an effect then we use the original
-                # with the namespace, instead of assuming Gem::
-                set(gem_name_with_namespace ${gem_name})
+        # Lookup if the target is scoped to a project
+        # In that case the target can only use gem targets that is
+        # - not project specific: i.e "__NOPROJECT__"
+        # - or specific to the <LY_PROJECT_NAME> project
+        get_property(target_project_association TARGET ${target} PROPERTY LY_PROJECT_NAME)
+
+        foreach(project ${enable_gem_projects})
+            if (target_project_association AND
+                (NOT (project STREQUAL "__NOPROJECT__") AND NOT (project STREQUAL target_project_association)))
+                # Skip adding the gem dependencies to this target if it is associated with a project
+                # and the current project doesn't match
+                continue()
             endif()
-            
-            # if the target exists, add it.
-            if (TARGET ${gem_name_with_namespace}.${variant})
-                ly_add_target_dependencies(
-                    ${PREFIX_CLAUSE}
-                    TARGETS ${target}
-                    DEPENDENT_TARGETS ${gem_name_with_namespace}.${variant}
-                )
+
+            get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project}")
+            if (NOT gem_dependencies)
+                get_property(gem_dependencies_defined GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project}" DEFINED)
+                if (gem_dependencies_defined)
+                    # special case, if the LY_DELAYED_ENABLE_GEMS_"${project_target_variant}" property is DEFINED
+                    # but empty, add an entry to the LY_DELAYED_LOAD_DEPENDENCIES to have the
+                    # cmake_dependencies.*.setreg file for the (project, target) tuple to be regenerated
+                    # This is needed if the ENABLED_GEMS list for a project goes from >0 to 0. In this case
+                    # the cmake_dependencies would have a stale list of gems to load unless it is regenerated
+                    get_property(delayed_load_target_set GLOBAL PROPERTY LY_DELAYED_LOAD_"${project},${target}" SET)
+                    if(NOT delayed_load_target_set)
+                        set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_DEPENDENCIES "${project},${target}")
+                        set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_"${project},${target}" "")
+                    endif()
+                endif()
+                # Continue to the next iteration loop regardless as there are no gem dependencies
+                continue()
             endif()
+
+            # Gather the Gem variants associated with this target and iterate over them to combine them with the enabled
+            # gems for the each project
+            get_property(target_gem_variants GLOBAL PROPERTY LY_GEM_VARIANTS_"${target}")
+            foreach(variant ${target_gem_variants})
+                ly_add_gem_dependencies_to_project_variants(
+                    PROJECT_NAME ${project}
+                    TARGET ${target}
+                    VARIANT ${variant}
+                    GEM_DEPENDENCIES ${gem_dependencies})
+            endforeach()
         endforeach()
     endforeach()
 endfunction()

+ 80 - 45
cmake/Platform/Common/Install_common.cmake

@@ -138,16 +138,20 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
     string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type})
     # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead
     string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER})
-    if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE")
+    # In non-monolithic mode, gem targets are MODULE libraries, In monolithic mode gem targets are STATIC libraries
+    set(GEM_LIBRARY_TYPES "MODULE" "STATIC")
+    if(TARGET_TYPE_PLACEHOLDER IN_LIST GEM_LIBRARY_TYPES)
         get_target_property(gem_module ${TARGET_NAME} GEM_MODULE)
         if(gem_module)
             set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE")
         endif()
     endif()
 
+    string(REPEAT " " 12 PLACEHOLDER_INDENT)
     get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS)
     if(COMPILE_DEFINITIONS_PLACEHOLDER)
-        string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}")
+        set(COMPILE_DEFINITIONS_PLACEHOLDER "${PLACEHOLDER_INDENT}${COMPILE_DEFINITIONS_PLACEHOLDER}")
+        list(JOIN COMPILE_DEFINITIONS_PLACEHOLDER "\n${PLACEHOLDER_INDENT}" COMPILE_DEFINITIONS_PLACEHOLDER)
     else()
         unset(COMPILE_DEFINITIONS_PLACEHOLDER)
     endif()
@@ -159,25 +163,28 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
             if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions
                 # Make the include path relative to the source dir where the target will be declared
                 cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include)
-                string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${target_include}\n")
+                string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${target_include}\n")
             endif()
         endforeach()
     endif()
 
+    string(REPEAT " " 8 PLACEHOLDER_INDENT)
     get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES)
     if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found
-        string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}")
+        set(RUNTIME_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${RUNTIME_DEPENDENCIES_PLACEHOLDER}")
+        list(JOIN RUNTIME_DEPENDENCIES_PLACEHOLDER "\n${PLACEHOLDER_INDENT}" RUNTIME_DEPENDENCIES_PLACEHOLDER)
     else()
         unset(RUNTIME_DEPENDENCIES_PLACEHOLDER)
     endif()
 
+    string(REPEAT " " 12 PLACEHOLDER_INDENT)
     get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES)
     unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
     if(inteface_build_dependencies_props)
         foreach(build_dependency ${inteface_build_dependencies_props})
             # Skip wrapping produced when targets are not created in the same directory
             if(NOT ${build_dependency} MATCHES "^::@")
-                list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}")
+                list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}")
             endif()
         endforeach()
     endif()
@@ -187,12 +194,19 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
         foreach(build_dependency ${private_build_dependencies_props})
             # Skip wrapping produced when targets are not created in the same directory
             if(NOT ${build_dependency} MATCHES "^::@")
-                list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}")
+                list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}")
             endif()
         endforeach()
     endif()
     list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
-    string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}")
+    list(JOIN INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
+
+    string(REPEAT " " 8 PLACEHOLDER_INDENT)
+    # If a target has an LY_PROJECT_NAME property, forward that property to new target
+    get_target_property(target_project_association ${TARGET_NAME} LY_PROJECT_NAME)
+    if(target_project_association)
+        list(APPEND TARGET_PROPERTIES_PLACEHOLDER "${PLACEHOLDER_INDENT}LY_PROJECT_NAME ${target_project_association}")
+    endif()
 
     # If the target is an executable/application, add a custom target so we can debug the target in project-centric workflow
     if(should_create_helper)
@@ -288,44 +302,9 @@ function(ly_setup_subdirectory absolute_target_source_dir)
         string(APPEND all_configured_targets "${configured_target}")
     endforeach()
 
-    # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt
-    string(JOIN "\n" create_alias_template
-        "if(NOT TARGET @ALIAS_NAME@)"
-        "   ly_create_alias(NAME @ALIAS_NAME@ NAMESPACE @ALIAS_NAMESPACE@ TARGETS @ALIAS_TARGETS@)"
-        "endif()"
-        ""
-    )
-    get_property(create_alias_commands_arg_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_CREATE_ALIAS_ARGUMENTS)
-    foreach(create_alias_single_command_arg_list ${create_alias_commands_arg_list})
-        # Split the ly_create_alias arguments back out based on commas
-        string(REPLACE "," ";" create_alias_single_command_arg_list "${create_alias_single_command_arg_list}")
-        list(POP_FRONT create_alias_single_command_arg_list ALIAS_NAME)
-        list(POP_FRONT create_alias_single_command_arg_list ALIAS_NAMESPACE)
-        # The rest of the list are the target dependencies
-        set(ALIAS_TARGETS ${create_alias_single_command_arg_list})
-        string(CONFIGURE "${create_alias_template}" create_alias_command @ONLY)
-        string(APPEND CREATE_ALIASES_PLACEHOLDER ${create_alias_command})
-    endforeach()
-
-
-    # Reproduce the ly_enable_gems() calls made in the the SOURCE_DIR for this target into the CMakeLists.txt that
-    # is about to be generated
-    set(enable_gems_template "ly_enable_gems(@enable_gem_PROJECT_NAME@ @enable_gem_GEMS@ @enable_gem_GEM_FILE@ @enable_gem_VARIANTS@ @enable_gem_TARGETS@)\n")
-    get_property(enable_gems_commands_arg_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_ENABLE_GEMS_ARGUMENTS)
-    foreach(enable_gems_single_command_arg_list ${enable_gems_commands_arg_list})
-        # Split the ly_enable_gems arguments back out based on commas
-        string(REPLACE "," ";" enable_gems_single_command_arg_list "${enable_gems_single_command_arg_list}")
-        foreach(enable_gem_arg_kw IN ITEMS PROJECT_NAME GEMS GEM_FILE VARIANTS TARGETS)
-            list(POP_FRONT enable_gems_single_command_arg_list enable_gem_${enable_gem_arg_kw})
-            if(enable_gem_${enable_gem_arg_kw})
-                # if the argument exist append to argument keyword to the front
-                string(PREPEND enable_gem_${enable_gem_arg_kw} "${enable_gem_arg_kw} ")
-            endif()
-        endforeach()
-
-        string(CONFIGURE "${enable_gems_template}" enable_gems_command @ONLY)
-        string(APPEND ENABLE_GEMS_PLACEHOLDER ${enable_gems_command})
-    endforeach()
+    ly_setup_subdirectory_create_alias("${absolute_target_source_dir}" CREATE_ALIASES_PLACEHOLDER)
+    ly_setup_subdirectory_set_gem_variant_to_load("${absolute_target_source_dir}" GEM_VARIANT_TO_LOAD_PLACEHOLDER)
+    ly_setup_subdirectory_enable_gems("${absolute_target_source_dir}" ENABLE_GEMS_PLACEHOLDER)
 
     ly_file_read(${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment)
 
@@ -337,6 +316,7 @@ function(ly_setup_subdirectory absolute_target_source_dir)
         "${all_configured_targets}"
         "\n"
         "${CREATE_ALIASES_PLACEHOLDER}"
+        "${GEM_VARIANT_TO_LOAD_PLACEHOLDER}"
         "${ENABLE_GEMS_PLACEHOLDER}"
     )
 
@@ -591,3 +571,58 @@ function(ly_setup_assets)
     endforeach()
 
 endfunction()
+
+
+#! ly_setup_subdirectory_create_alias: Replicates the call to the `ly_create_alias` function
+#! within the generated CMakeLists.txt in the same relative install layout directory
+function(ly_setup_subdirectory_create_alias absolute_target_source_dir output_script)
+    # Replicate the create_alias() calls made in the SOURCE_DIR into the generated CMakeLists.txt
+    string(JOIN "\n" create_alias_template
+        "if(NOT TARGET @alias_name@)"
+        "   ly_create_alias(@create_alias_args@)"
+        "endif()"
+        "")
+
+    unset(${output_script} PARENT_SCOPE)
+    get_property(create_alias_args_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_CREATE_ALIAS_ARGUMENTS)
+    foreach(create_alias_args IN LISTS create_alias_args_list)
+        # Create a list out of the comma separated arguments and store it into the same variable
+        string(REPLACE "," ";" create_alias_args ${create_alias_args})
+        # The first argument of the create alias argument list is the ALIAS NAME so pop it from the list
+        # It is used to protect against registering the same alias twice
+        list(POP_FRONT create_alias_args alias_name)
+        string(CONFIGURE "${create_alias_template}" create_alias_command @ONLY)
+        string(APPEND create_alias_calls ${create_alias_command})
+    endforeach()
+    set(${output_script} ${create_alias_calls} PARENT_SCOPE)
+endfunction()
+
+#! ly_setup_subdirectory_set_gem_variant_to_load: Replicates the call to the `ly_set_gem_variant_to_load` function
+#! within the generated CMakeLists.txt in the same relative install layout directory
+function(ly_setup_subdirectory_set_gem_variant_to_load absolute_target_source_dir output_script)
+    # Replicate the ly_set_gem_variant_to_load() calls made in the SOURCE_DIR for into the generated CMakeLists.txt
+    set(set_gem_variant_args_template "ly_set_gem_variant_to_load(@set_gem_variant_args@)\n")
+
+    unset(${output_script} PARENT_SCOPE)
+    get_property(set_gem_variant_args_lists DIRECTORY ${absolute_target_source_dir} PROPERTY LY_SET_GEM_VARIANT_TO_LOAD_ARGUMENTS)
+    foreach(set_gem_variant_args IN LISTS set_gem_variant_args_lists)
+        string(CONFIGURE "${set_gem_variant_args_template}" set_gem_variant_to_load_command @ONLY)
+        string(APPEND set_gem_variant_calls ${set_gem_variant_to_load_command})
+    endforeach()
+    set(${output_script} ${set_gem_variant_calls} PARENT_SCOPE)
+endfunction()
+
+#! ly_setup_subdirectory_enable_gems: Replicates the call to the `ly_enable_gems` function
+#! within the generated CMakeLists.txt in the same relative install layout directory
+function(ly_setup_subdirectory_enable_gems absolute_target_source_dir output_script)
+    # Replicate the ly_set_gem_variant_to_load() calls made in the SOURCE_DIR into the generated CMakeLists.txt
+    set(enable_gems_template "ly_enable_gems(@enable_gems_args@)\n")
+
+    unset(${output_script} PARENT_SCOPE)
+    get_property(enable_gems_args_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_ENABLE_GEMS_ARGUMENTS)
+    foreach(enable_gems_args IN LISTS enable_gems_args_list)
+        string(CONFIGURE "${enable_gems_template}" enable_gems_command @ONLY)
+        string(APPEND enable_gems_calls ${enable_gems_command})
+    endforeach()
+    set(${output_script} ${enable_gems_calls} PARENT_SCOPE)
+endfunction()

+ 1 - 34
cmake/Projects.cmake

@@ -53,7 +53,7 @@ function(ly_add_target_dependencies)
     # Append the DEPENDENT_TARGETS to the list of ALL_GEM_DEPENDENCIES
     list(APPEND ALL_GEM_DEPENDENCIES ${ly_add_gem_dependencies_DEPENDENT_TARGETS})
 
-    # for each target, add the dependencies and generate gems json
+    # for each target, add the dependencies and generate setreg json with the list of gems to load
     foreach(target ${ly_add_gem_dependencies_TARGETS})
         ly_add_dependencies(${target} ${ALL_GEM_DEPENDENCIES})
 
@@ -69,39 +69,6 @@ function(ly_add_target_dependencies)
     endforeach()
 endfunction()
 
-#! ly_add_project_dependencies: adds the dependencies to runtime and tools for this project.
-#
-#  Each project may have dependencies to gems. To properly define these dependencies, we are making the project to define
-#  through a "files list" cmake file the dependencies to the different targets.
-#  So for example, the game's runtime dependencies are associated to the project's launcher; the game's tools dependencies
-#  are associated to the asset processor; etc
-#
-# \arg:PROJECT_NAME name of the game project
-# \arg:TARGETS names of the targets to associate the dependencies to
-# \arg:DEPENDENCIES_FILES file(s) that contains the runtime dependencies the TARGETS will be associated to
-# \arg:DEPENDENT_TARGETS additional list of targets should be added as load-time dependencies for the TARGETS list
-#
-function(ly_add_project_dependencies)
-
-    set(options)
-    set(oneValueArgs PROJECT_NAME)
-    set(multiValueArgs TARGETS DEPENDENCIES_FILES DEPENDENT_TARGETS)
-
-    cmake_parse_arguments(ly_add_project_dependencies "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
-    # Validate input arguments
-    if(NOT ly_add_project_dependencies_PROJECT_NAME)
-        message(FATAL_ERROR "PROJECT_NAME parameter missing. If not project name is needed, then call ly_add_target_dependencies directly")
-    endif()
-
-    ly_add_target_dependencies(
-        PREFIX ${ly_add_project_dependencies_PROJECT_NAME}
-        TARGETS ${ly_add_project_dependencies_TARGETS}
-        DEPENDENCIES_FILES ${ly_add_project_dependencies_DEPENDENCIES_FILES}
-        DEPENDENT_TARGETS ${ly_add_project_dependencies_DEPENDENT_TARGETS}
-    )
-endfunction()
-
 
 #template for generating the project build_path setreg
 set(project_build_path_template [[

+ 11 - 6
cmake/SettingsRegistry.cmake

@@ -28,7 +28,7 @@ set(gems_json_template [[
  string(APPEND gem_module_template
 [=[            "@stripped_gem_target@":]=] "\n"
 [=[            {]=] "\n"
-[=[$<$<NOT:$<IN_LIST:$<TARGET_PROPERTY:@gem_target@,TYPE>,INTERFACE_LIBRARY>>:                "Modules":["$<TARGET_FILE_NAME:@gem_target@>"]]=] "$<COMMA>\n>"
+[=[$<$<IN_LIST:$<TARGET_PROPERTY:@gem_target@,TYPE>,MODULE_LIBRARY$<SEMICOLON>SHARED_LIBRARY>:                "Modules":["$<TARGET_FILE_NAME:@gem_target@>"]]=] "$<COMMA>\n>"
 [=[                "SourcePaths":["@gem_module_root_relative_to_engine_root@"]]=] "\n"
 [=[            }]=]
 )
@@ -87,7 +87,7 @@ endfunction()
 #
 # \arg:gem_target(TARGET) - Target to look upwards from using its SOURCE_DIR property
 function(ly_get_gem_module_root output_gem_module_root gem_target)
-    unset(gem_module_roots)
+    unset(${output_gem_module_root} PARENT_SCOPE)
     get_property(gem_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR)
 
     if(gem_source_dir)
@@ -96,8 +96,8 @@ function(ly_get_gem_module_root output_gem_module_root gem_target)
         while(NOT EXISTS ${candidate_gem_dir}/gem.json)
             get_filename_component(parent_dir ${candidate_gem_dir} DIRECTORY)
             if (${parent_dir} STREQUAL ${candidate_gem_dir})
-                message(WARNING "Did not find a gem.json while processing GEM_MODULE target ${gem_target}!")
-                break()
+                # "Did not find a gem.json while processing GEM_MODULE target ${gem_target}!"
+                return()
             endif()
             set(candidate_gem_dir ${parent_dir})
         endwhile()
@@ -160,11 +160,15 @@ function(ly_delayed_generate_settings_registry)
             endif()
 
             ly_get_gem_module_root(gem_module_root ${gem_target})
+            if (NOT gem_module_root)
+                # If the target doesn't have a gem.json, skip it
+                continue()
+            endif()
             file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${gem_module_root})
 
             # De-alias namespace from gem targets before configuring them into the json template
             ly_de_alias_target(${gem_target} stripped_gem_target)
-            string(CONFIGURE ${gem_module_template} gem_module_json @ONLY)
+            string(CONFIGURE "${gem_module_template}" gem_module_json @ONLY)
             list(APPEND target_gem_dependencies_names ${gem_module_json})
         endforeach()
 
@@ -177,7 +181,8 @@ function(ly_delayed_generate_settings_registry)
         string(CONFIGURE ${gems_json_template} gem_json @ONLY)
         get_target_property(is_imported ${target} IMPORTED)
         get_target_property(target_type ${target} TYPE)
-        if(is_imported OR target_type STREQUAL UTILITY)
+        set(non_loadable_types "UTILITY" "INTERFACE_LIBRARY" "STATIC_LIBRARY")
+        if(is_imported OR (target_type IN_LIST non_loadable_types))
             unset(target_dir)
             foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
                 string(TOUPPER ${conf} UCONF)

+ 2 - 0
cmake/install/InstalledTarget.in

@@ -15,6 +15,8 @@ ly_add_target(
 @INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER@
     RUNTIME_DEPENDENCIES
 @RUNTIME_DEPENDENCIES_PLACEHOLDER@
+    TARGET_PROPERTIES
+@TARGET_PROPERTIES_PLACEHOLDER@
 )
 
 @TARGET_RUN_HELPER@