diff --git a/CMakeLists.txt b/CMakeLists.txt index 63177e9d60..a7e42613cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,10 @@ foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) endforeach() # The following steps have to be done after all targets are registered: +# Defer generation of the StaticModules.inl file which is needed to create the AZ::Module derived class in monolithic +# builds until after all the targets are known +ly_delayed_generate_static_modules_inl() + # 1. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls # to provide applications with the filenames of gem modules to load # This must be done before ly_delayed_target_link_libraries() as that inserts BUILD_DEPENDENCIES as MANUALLY_ADDED_DEPENDENCIES diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index 28429729e1..edb6655411 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -9,6 +9,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # + +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 @@ -40,28 +42,8 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC # In the monolithic case, we need to register the gem modules, to do so we will generate a StaticModules.inl # file from StaticModules.in - + set_property(GLOBAL APPEND PROPERTY LY_STATIC_MODULE_PROJECTS_NAME ${project_name}) get_property(game_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.GameLauncher) - - unset(extern_module_declarations) - unset(module_invocations) - - foreach(game_gem_dependency ${game_gem_dependencies}) - # To match the convention on how gems targets vs gem modules are named, we remove the "Gem::" from prefix - # and remove the ".Static" from the suffix - string(REGEX REPLACE "^Gem::" "Gem_" game_gem_dependency ${game_gem_dependency}) - string(REGEX REPLACE "^Project::" "Project_" game_gem_dependency ${game_gem_dependency}) - # Replace "." with "_" - string(REPLACE "." "_" game_gem_dependency ${game_gem_dependency}) - - string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_${game_gem_dependency}();\n") - string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_${game_gem_dependency}());\n") - - endforeach() - - configure_file(StaticModules.in - ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.GameLauncher/Includes/StaticModules.inl - ) set(game_build_dependencies ${game_gem_dependencies} @@ -70,29 +52,9 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) get_property(server_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.ServerLauncher) - - unset(extern_module_declarations) - unset(module_invocations) - - foreach(server_gem_dependency ${server_gem_dependencies}) - # To match the convention on how gems targets vs gem modules are named, we remove the "Gem::" from prefix - # and remove the ".Static" from the suffix - string(REGEX REPLACE "^Gem::" "Gem_" server_gem_dependency ${server_gem_dependency}) - string(REGEX REPLACE "^Project::" "Project_" server_gem_dependency ${server_gem_dependency}) - # Replace "." with "_" - string(REPLACE "." "_" server_gem_dependency ${server_gem_dependency}) - - string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_${server_gem_dependency}();\n") - string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_${server_gem_dependency}());\n") - - endforeach() - - configure_file(StaticModules.in - ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.ServerLauncher/Includes/StaticModules.inl - ) set(server_build_dependencies - ${game_gem_dependencies} + ${server_gem_dependencies} Legacy::CrySystem ) endif() @@ -186,3 +148,63 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC endif() endforeach() + +#! Defer generation of the StaticModules.inl file needed in monolithic builds until after all the CMake targets are known +# This is that the GEM_MODULE target runtime dependencies can be parsed to discover the list of dependent modules +# to load +function(ly_delayed_generate_static_modules_inl) + if(LY_MONOLITHIC_GAME) + get_property(launcher_unified_binary_dir GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR) + get_property(project_names GLOBAL PROPERTY LY_STATIC_MODULE_PROJECTS_NAME) + foreach(project_name ${project_names}) + + unset(extern_module_declarations) + unset(module_invocations) + + unset(all_game_gem_dependencies) + ly_get_gem_load_dependencies(all_game_gem_dependencies ${project_name}.GameLauncher) + + foreach(game_gem_dependency ${all_game_gem_dependencies}) + # To match the convention on how gems targets vs gem modules are named, + # we remove the ".Static" from the suffix + # Replace "." with "_" + string(REPLACE "." "_" game_gem_dependency ${game_gem_dependency}) + + string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${game_gem_dependency}();\n") + string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${game_gem_dependency}());\n") + + endforeach() + + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in + ${launcher_unified_binary_dir}/${project_name}.GameLauncher/Includes/StaticModules.inl + ) + + if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) + get_property(server_gem_dependencies GLOBAL PROPERTY LY_STATIC_MODULE_PROJECTS_DEPENDENCIES_${project_name}.ServerLauncher) + + unset(extern_module_declarations) + unset(module_invocations) + + unset(all_server_gem_dependencies) + ly_get_gem_load_dependencies(all_server_gem_dependencies ${project_name}.ServerLauncher) + foreach(server_gem_dependency ${server_gem_dependencies}) + ly_get_gem_load_dependencies(server_gem_load_dependencies ${server_gem_dependency}) + list(APPEND all_server_gem_dependencies ${server_gem_load_dependencies} ${server_gem_dependency}) + endforeach() + foreach(server_gem_dependency ${all_server_gem_dependencies}) + # Replace "." with "_" + string(REPLACE "." "_" server_gem_dependency ${server_gem_dependency}) + + string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${server_gem_dependency}();\n") + string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${server_gem_dependency}());\n") + + endforeach() + + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in + ${launcher_unified_binary_dir}/${project_name}.ServerLauncher/Includes/StaticModules.inl + ) + + endif() + endforeach() + endif() +endfunction() diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index f6a36afc89..8aba6ccb99 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -46,6 +46,7 @@ define_property(TARGET PROPERTY GEM_MODULE # # \arg:NAME name of the target # \arg:STATIC (bool) defines this target to be a static library +# \arg:GEM_STATIC (bool) defines this target to be a static library while also setting the GEM_MODULE property # \arg:SHARED (bool) defines this target to be a dynamic library # \arg:MODULE (bool) defines this target to be a module library # \arg:GEM_MODULE (bool) defines this target to be a module library while also marking the target as a "Gem" via the GEM_MODULE property @@ -76,7 +77,7 @@ define_property(TARGET PROPERTY GEM_MODULE # \arg:AUTOGEN_RULES a set of AutoGeneration rules to be passed to the AzAutoGen expansion system function(ly_add_target) - set(options STATIC SHARED MODULE GEM_MODULE HEADERONLY EXECUTABLE APPLICATION UNKNOWN IMPORTED AUTOMOC AUTOUIC AUTORCC NO_UNITY) + set(options STATIC GEM_STATIC SHARED MODULE GEM_MODULE HEADERONLY EXECUTABLE APPLICATION UNKNOWN IMPORTED AUTOMOC AUTOUIC AUTORCC NO_UNITY) set(oneValueArgs NAME NAMESPACE OUTPUT_SUBDIRECTORY OUTPUT_NAME) set(multiValueArgs FILES_CMAKE GENERATED_FILES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES PLATFORM_INCLUDE_FILES TARGET_PROPERTIES AUTOGEN_RULES) @@ -96,6 +97,10 @@ function(ly_add_target) if(ly_add_target_GEM_MODULE) set(ly_add_target_MODULE ${ly_add_target_GEM_MODULE}) endif() + # If the GEM_STATIC tag is passed mark the target as STATIC + if(ly_add_target_GEM_STATIC) + set(ly_add_target_STATIC ${ly_add_target_GEM_STATIC}) + endif() foreach(file_cmake ${ly_add_target_FILES_CMAKE}) ly_include_cmake_file_list(${file_cmake}) @@ -199,7 +204,7 @@ function(ly_add_target) endif() - if(ly_add_target_GEM_MODULE) + if(ly_add_target_GEM_MODULE OR ly_add_target_GEM_STATIC) set_target_properties(${ly_add_target_NAME} PROPERTIES GEM_MODULE TRUE) endif() @@ -719,3 +724,23 @@ function(ly_project_add_subdirectory project_name) endif() endif() endfunction() + +# given a target name, returns the "real" name of the target if its an alias. +# this function recursively de-aliases +function(ly_de_alias_target target_name output_variable_name) + # its not okay to call get_target_property on a non-existent target + if (NOT TARGET ${target_name}) + message(FATAL_ERROR "ly_de_alias_target called on non-existent target: ${target_name}") + endif() + + while(target_name) + set(de_aliased_target_name ${target_name}) + + get_target_property(target_name ${target_name} ALIASED_TARGET) + endwhile() + + if(NOT de_aliased_target_name) + message(FATAL_ERROR "Empty de_aliased for ${target_name}") + endif() + set(${output_variable_name} ${de_aliased_target_name} PARENT_SCOPE) +endfunction() diff --git a/cmake/Monolithic.cmake b/cmake/Monolithic.cmake index db45c182fd..dfd6816dde 100644 --- a/cmake/Monolithic.cmake +++ b/cmake/Monolithic.cmake @@ -14,7 +14,7 @@ set(LY_MONOLITHIC_GAME FALSE CACHE BOOL "Indicates if the game will be built mon if(LY_MONOLITHIC_GAME) add_compile_definitions(AZ_MONOLITHIC_BUILD) ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE STATIC) - ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE STATIC) + ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE GEM_STATIC) # Disable targets that are not supported with monolithic ly_set(PAL_TRAIT_BUILD_HOST_TOOLS FALSE) ly_set(PAL_TRAIT_BUILD_HOST_GUI_TOOLS FALSE) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index fd5985a5a1..e1c07f4492 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -64,18 +64,16 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) get_target_property(load_dependencies ${ly_TARGET} MANUALLY_ADDED_DEPENDENCIES) if(load_dependencies) foreach(load_dependency ${load_dependencies}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${load_dependency} MATCHES "^::@") - get_property(dependency_type TARGET ${load_dependency} PROPERTY TYPE) - get_property(is_gem_target TARGET ${load_dependency} PROPERTY GEM_MODULE SET) - # If the dependency is a "gem module" then add it as a load dependencies - # and recurse into its manually added dependencies - if (is_gem_target) - unset(dependencies) - ly_get_gem_load_dependencies(dependencies ${load_dependency}) - list(APPEND all_gem_load_dependencies ${load_dependency}) - list(APPEND all_gem_load_dependencies ${dependencies}) - endif() + # Skip wrapping produced when targets are not created in the same directory + ly_de_alias_target(${load_dependency} dealias_load_dependency) + get_property(is_gem_target TARGET ${dealias_load_dependency} PROPERTY GEM_MODULE SET) + # If the dependency is a "gem module" then add it as a load dependencies + # and recurse into its manually added dependencies + if (is_gem_target) + unset(dependencies) + ly_get_gem_load_dependencies(dependencies ${dealias_load_dependency}) + list(APPEND all_gem_load_dependencies ${dependencies}) + list(APPEND all_gem_load_dependencies ${dealias_load_dependency}) endif() endforeach() endif() @@ -133,8 +131,8 @@ function(ly_delayed_generate_settings_registry) file(RELATIVE_PATH gem_relative_source_dir ${ly_root_folder_cmake} ${gem_relative_source_dir}) endif() - # Strip target namespace from gem targets before configuring them into the json template - ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) + # 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) list(APPEND target_gem_dependencies_names ${gem_module_json}) endforeach()