launcher_generator.cmake 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. # This will be used to turn on "PerMonitor" DPI scaling support. (Currently there is no way in CMake to specify "PerMonitorV2")
  9. set(O3DE_DPI_AWARENESS "PerMonitor")
  10. set_property(GLOBAL PROPERTY SERVER_LAUNCHER_TYPES ServerLauncher HeadlessServerLauncher)
  11. set_property(GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
  12. set(SERVER_LAUNCHER_TYPES ServerLauncher HeadlessServerLauncher)
  13. set(SERVER_LAUNCHERTYPE_ServerLauncher APPLICATION)
  14. set(SERVER_BUILD_DEPENDENCIES_ServerLauncher AZ::Launcher.Static AZ::AzGameFramework AZ::Launcher.Server.Static)
  15. set(SERVER_VARIANT_ServerLauncher Servers)
  16. set(SERVER_LAUNCHERTYPE_HeadlessServerLauncher EXECUTABLE)
  17. set(SERVER_BUILD_DEPENDENCIES_HeadlessServerLauncher AZ::Launcher.Headless.Static AZ::AzGameFramework.Headless AZ::Launcher.Server.Static)
  18. set(SERVER_VARIANT_HeadlessServerLauncher HeadlessServers)
  19. # the following controls what visibility the various target properties are set to
  20. # and allow them to be overridden to "INTERFACE" in script-only mode.
  21. set(LAUNCHER_TARGET_PROPERTY_TYPE "PRIVATE")
  22. # Launcher targets for a project need to be generated when configuring a project.
  23. # When building the engine source, this file will be included by LauncherUnified's CMakeLists.txt
  24. # When using an installed engine, this file will be included by the FindLauncherGenerator.cmake script
  25. get_property(SERVER_LAUNCHER_TYPES GLOBAL PROPERTY SERVER_LAUNCHER_TYPES)
  26. get_property(O3DE_PROJECTS_NAME GLOBAL PROPERTY O3DE_PROJECTS_NAME)
  27. # when NO project is specified, for example, when creating a pre-built version of the engine,
  28. # create a generic launcher that can be shipped with the engine
  29. set(launcher_generator_LY_PROJECTS ${LY_PROJECTS})
  30. # the following generates "generic" launchers when no project is specified
  31. # this cannot happen in script only mode, since scripts-only mode requires a prebuilt installer
  32. # and the prebuilt installer always operates on a project, so will generally only happen
  33. # when building an installer from the o3de source code, or just compiling O3DE itself with no
  34. # project specified.
  35. if (NOT launcher_generator_LY_PROJECTS)
  36. set(launcher_generator_LY_PROJECTS ":PROJECT_PATH_ONLY_FOR_GENERIC_LAUNCHER")
  37. set(O3DE_PROJECTS_NAME "O3DE")
  38. set(launcher_generator_BUILD_GENERIC TRUE) # used to skip the asset processing step
  39. # set a compile definition on the launchers themselves to let them know they are generic launchers
  40. # they can use this in their code and logic to avoid doing things like loading the burned-in
  41. # registry keys.
  42. set(GENERIC_LAUNCHER_COMPILE_DEFINITION "O3DE_IS_GENERIC_LAUNCHER")
  43. endif()
  44. foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME launcher_generator_LY_PROJECTS)
  45. if (NOT launcher_generator_BUILD_GENERIC) # generic launcher does not build assets.
  46. # Computes the realpath to the project. Only used in building assets.
  47. # If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER}
  48. # Otherwise the the absolute project_path is returned with symlinks resolved
  49. file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER})
  50. ################################################################################
  51. # Assets
  52. ################################################################################
  53. if(PAL_TRAIT_BUILD_HOST_TOOLS)
  54. add_custom_target(${project_name}.Assets
  55. COMMENT "Processing ${project_name} assets..."
  56. COMMAND "${CMAKE_COMMAND}"
  57. -DLY_LOCK_FILE=$<GENEX_EVAL:$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>>/project_assets.lock
  58. -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
  59. EXEC_COMMAND $<GENEX_EVAL:$<TARGET_FILE:AZ::AssetProcessorBatch>>
  60. --zeroAnalysisMode
  61. --project-path=${project_real_path}
  62. --platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
  63. )
  64. set_target_properties(${project_name}.Assets
  65. PROPERTIES
  66. EXCLUDE_FROM_ALL TRUE
  67. FOLDER ${project_name}
  68. )
  69. endif()
  70. endif()
  71. ################################################################################
  72. # Monolithic game
  73. ################################################################################
  74. if(LY_MONOLITHIC_GAME)
  75. # In the monolithic case, we need to register the gem modules, to do so we will generate a StaticModules.inl
  76. # file from StaticModules.in
  77. set_property(GLOBAL APPEND PROPERTY LY_STATIC_MODULE_PROJECTS_NAME ${project_name})
  78. get_property(game_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.GameLauncher)
  79. set(game_build_dependencies
  80. ${game_gem_dependencies}
  81. Legacy::CrySystem
  82. )
  83. if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
  84. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  85. get_property(server_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.${server_launcher_type})
  86. list(APPEND SERVER_BUILD_DEPENDENCIES_${server_launcher_type}
  87. ${server_gem_dependencies}
  88. Legacy::CrySystem
  89. )
  90. endforeach()
  91. endif()
  92. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  93. get_property(unified_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.UnifiedLauncher)
  94. set(unified_build_dependencies
  95. ${unified_gem_dependencies}
  96. Legacy::CrySystem
  97. )
  98. endif()
  99. else()
  100. set(game_runtime_dependencies
  101. Legacy::CrySystem
  102. )
  103. # in script only mode, which can only happen when building a project
  104. # that is using a prebuilt installer, add the generic gamelauncher as a run time dependency
  105. # of the project launcher. The project launcher is "fake" and will not get actually compiled,
  106. # but this will cause the generic game launcher and its dependencies to get deployed into the bin folder
  107. # since they are all dependencies of this fake target.
  108. if (O3DE_SCRIPT_ONLY)
  109. set(game_runtime_dependencies ${game_runtime_dependencies} O3DE.GameLauncher)
  110. endif()
  111. if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
  112. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  113. set(SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}
  114. Legacy::CrySystem
  115. )
  116. if (O3DE_SCRIPT_ONLY)
  117. set(SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}
  118. "${SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}}" O3DE.${server_launcher_type})
  119. endif()
  120. endforeach()
  121. endif()
  122. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  123. set(unified_runtime_dependencies
  124. Legacy::CrySystem
  125. )
  126. if (O3DE_SCRIPT_ONLY)
  127. set(unified_runtime_dependencies ${unified_runtime_dependencies} O3DE.UnifiedLauncher)
  128. endif()
  129. endif()
  130. endif()
  131. ################################################################################
  132. # Game
  133. ################################################################################
  134. ly_add_target(
  135. NAME ${project_name}.GameLauncher ${PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE}
  136. NAMESPACE AZ
  137. FILES_CMAKE
  138. ${CMAKE_CURRENT_LIST_DIR}/launcher_project_files.cmake
  139. PLATFORM_INCLUDE_FILES
  140. ${pal_dir}/launcher_project_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
  141. COMPILE_DEFINITIONS
  142. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  143. # Adds the name of the project/game
  144. LY_PROJECT_NAME="${project_name}"
  145. # Adds the ${project_name}_GameLauncher target as a define so for the Settings Registry to use
  146. # when loading .setreg file specializations
  147. # This is needed so that only gems for the project game launcher are loaded
  148. LY_CMAKE_TARGET="${project_name}_GameLauncher"
  149. "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
  150. INCLUDE_DIRECTORIES
  151. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  152. .
  153. ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.GameLauncher/Includes # required for StaticModules.inl
  154. BUILD_DEPENDENCIES
  155. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  156. AZ::Launcher.Static
  157. AZ::Launcher.Game.Static
  158. ${game_build_dependencies}
  159. RUNTIME_DEPENDENCIES
  160. ${game_runtime_dependencies}
  161. )
  162. # Needs to be set manually after ly_add_target to prevent the default location overriding it
  163. set_target_properties(${project_name}.GameLauncher
  164. PROPERTIES
  165. FOLDER ${project_name}
  166. LY_PROJECT_NAME ${project_name}
  167. )
  168. # Turn on DPI scaling support.
  169. set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DPI_AWARE ${O3DE_DPI_AWARENESS})
  170. if(LY_DEFAULT_PROJECT_PATH)
  171. if (TARGET ${project_name})
  172. get_target_property(project_game_launcher_additional_args ${project_name} GAMELAUNCHER_ADDITIONAL_VS_DEBUGGER_COMMAND_ARGUMENTS)
  173. if (project_game_launcher_additional_args)
  174. # Avoid pushing param-NOTFOUND into the argument in case this property wasn't found
  175. set(additional_game_vs_debugger_args "${project_game_launcher_additional_args}")
  176. endif()
  177. endif()
  178. set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS
  179. "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\" ${additional_game_vs_debugger_args}")
  180. endif()
  181. # Associate the Clients Gem Variant with each projects GameLauncher
  182. ly_set_gem_variant_to_load(TARGETS ${project_name}.GameLauncher VARIANTS Clients)
  183. ################################################################################
  184. # Server
  185. ################################################################################
  186. if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
  187. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  188. ly_add_target(
  189. NAME ${project_name}.${server_launcher_type} ${SERVER_LAUNCHERTYPE_${server_launcher_type}}
  190. NAMESPACE AZ
  191. FILES_CMAKE
  192. ${CMAKE_CURRENT_LIST_DIR}/launcher_project_files.cmake
  193. PLATFORM_INCLUDE_FILES
  194. ${pal_dir}/launcher_project_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
  195. COMPILE_DEFINITIONS
  196. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  197. # Adds the name of the project/game
  198. LY_PROJECT_NAME="${project_name}"
  199. # Adds the ${project_name}_${server_launcher_type} target as a define so for the Settings Registry to use
  200. # when loading .setreg file specializations
  201. # This is needed so that only gems for the project server launcher are loaded
  202. LY_CMAKE_TARGET="${project_name}_${server_launcher_type}"
  203. "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
  204. INCLUDE_DIRECTORIES
  205. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  206. .
  207. ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.${server_launcher_type}/Includes # required for StaticModules.inl
  208. BUILD_DEPENDENCIES
  209. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  210. ${SERVER_BUILD_DEPENDENCIES_${server_launcher_type}}
  211. RUNTIME_DEPENDENCIES
  212. ${SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}}
  213. )
  214. # Needs to be set manually after ly_add_target to prevent the default location overriding it
  215. set_target_properties(${project_name}.${server_launcher_type}
  216. PROPERTIES
  217. FOLDER ${project_name}
  218. LY_PROJECT_NAME ${project_name}
  219. )
  220. # Turn on DPI scaling support.
  221. set_property(TARGET ${project_name}.${server_launcher_type} APPEND PROPERTY VS_DPI_AWARE ${O3DE_DPI_AWARENESS})
  222. if(LY_DEFAULT_PROJECT_PATH)
  223. if (TARGET ${project_name})
  224. get_target_property(project_server_launcher_additional_args ${project_name} SERVERLAUNCHER_ADDITIONAL_VS_DEBUGGER_COMMAND_ARGUMENTS)
  225. if (project_server_launcher_additional_args)
  226. # Avoid pushing param-NOTFOUND into the argument in case this property wasn't found
  227. set(additional_server_vs_debugger_args "${project_server_launcher_additional_args}")
  228. endif()
  229. endif()
  230. set_property(TARGET ${project_name}.${server_launcher_type} APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS
  231. "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\" ${additional_server_vs_debugger_args}")
  232. endif()
  233. # Associate the Servers Gem Variant with each projects ServerLauncher
  234. ly_set_gem_variant_to_load(TARGETS ${project_name}.${server_launcher_type} VARIANTS ${SERVER_VARIANT_${server_launcher_type}})
  235. # If the Editor is getting built, it should rebuild the ServerLauncher as well. The Editor's game mode will attempt
  236. # to launch it, and things can break if the two are out of sync.
  237. if(PAL_TRAIT_BUILD_HOST_TOOLS)
  238. ly_add_dependencies(Editor ${project_name}.${server_launcher_type})
  239. endif()
  240. endforeach()
  241. endif()
  242. ################################################################################
  243. # Unified
  244. ################################################################################
  245. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  246. ly_add_target(
  247. NAME ${project_name}.UnifiedLauncher ${PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE}
  248. NAMESPACE AZ
  249. FILES_CMAKE
  250. ${CMAKE_CURRENT_LIST_DIR}/launcher_project_files.cmake
  251. PLATFORM_INCLUDE_FILES
  252. ${pal_dir}/launcher_project_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
  253. COMPILE_DEFINITIONS
  254. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  255. # Adds the name of the project/game
  256. LY_PROJECT_NAME="${project_name}"
  257. # Adds the ${project_name}_UnifiedLauncher target as a define so for the Settings Registry to use
  258. # when loading .setreg file specializations
  259. # This is needed so that only gems for the project unified launcher are loaded
  260. LY_CMAKE_TARGET="${project_name}_UnifiedLauncher"
  261. "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
  262. INCLUDE_DIRECTORIES
  263. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  264. .
  265. ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.UnifiedLauncher/Includes # required for StaticModules.inl
  266. BUILD_DEPENDENCIES
  267. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  268. AZ::Launcher.Static
  269. AZ::Launcher.Unified.Static
  270. ${unified_build_dependencies}
  271. RUNTIME_DEPENDENCIES
  272. ${unified_runtime_dependencies}
  273. )
  274. # Needs to be set manually after ly_add_target to prevent the default location overriding it
  275. set_target_properties(${project_name}.UnifiedLauncher
  276. PROPERTIES
  277. FOLDER ${project_name}
  278. LY_PROJECT_NAME ${project_name}
  279. )
  280. # Turn on DPI scaling support.
  281. set_property(TARGET ${project_name}.UnifiedLauncher APPEND PROPERTY VS_DPI_AWARE ${O3DE_DPI_AWARENESS})
  282. if(LY_DEFAULT_PROJECT_PATH)
  283. if (TARGET ${project_name})
  284. get_target_property(project_unified_launcher_additional_args ${project_name} UNIFIEDLAUNCHER_ADDITIONAL_VS_DEBUGGER_COMMAND_ARGUMENTS)
  285. if (project_unified_launcher_additional_args)
  286. # Avoid pushing param-NOTFOUND into the argument in case this property wasn't found
  287. set(additional_unified_vs_debugger_args "${project_unified_launcher_additional_args}")
  288. endif()
  289. endif()
  290. set_property(TARGET ${project_name}.UnifiedLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS
  291. "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\" ${additional_unified_vs_debugger_args}")
  292. endif()
  293. # Associate the Unified Gem Variant with each projects UnfiedLauncher
  294. ly_set_gem_variant_to_load(TARGETS ${project_name}.UnifiedLauncher VARIANTS Unified)
  295. endif()
  296. endforeach()
  297. #! Defer generation of the StaticModules.inl file needed in monolithic builds until after all the CMake targets are known
  298. # This is that the GEM_MODULE target runtime dependencies can be parsed to discover the list of dependent modules
  299. # to load
  300. function(ly_delayed_generate_static_modules_inl)
  301. get_property(SERVER_LAUNCHER_TYPES GLOBAL PROPERTY SERVER_LAUNCHER_TYPES)
  302. if(LY_MONOLITHIC_GAME)
  303. get_property(launcher_unified_binary_dir GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR)
  304. get_property(project_names GLOBAL PROPERTY LY_STATIC_MODULE_PROJECTS_NAME)
  305. foreach(project_name ${project_names})
  306. unset(extern_module_declarations)
  307. unset(module_invocations)
  308. unset(all_game_gem_dependencies)
  309. o3de_get_gem_load_dependencies(
  310. GEM_LOAD_DEPENDENCIES_VAR all_game_gem_dependencies
  311. TARGET "${project_name}.GameLauncher")
  312. foreach(game_gem_dependency ${all_game_gem_dependencies})
  313. # Sometimes, a gem's Client variant may be an interface library
  314. # which depends on multiple gem targets. The interface libraries
  315. # should be skipped; the real dependencies of the interface will be processed
  316. if(TARGET ${game_gem_dependency})
  317. get_target_property(target_type ${game_gem_dependency} TYPE)
  318. if(${target_type} STREQUAL "INTERFACE_LIBRARY")
  319. continue()
  320. endif()
  321. endif()
  322. # To match the convention on how gems targets vs gem modules are named,
  323. # we remove the ".Static" from the suffix
  324. # Replace "." with "_"
  325. string(REPLACE "." "_" game_gem_dependency ${game_gem_dependency})
  326. string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${game_gem_dependency}();\n")
  327. string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${game_gem_dependency}());\n")
  328. endforeach()
  329. configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in
  330. ${launcher_unified_binary_dir}/${project_name}.GameLauncher/Includes/StaticModules.inl
  331. )
  332. ly_target_link_libraries(${project_name}.GameLauncher PRIVATE ${all_game_gem_dependencies})
  333. if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
  334. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  335. unset(extern_module_declarations)
  336. unset(module_invocations)
  337. unset(all_server_gem_dependencies)
  338. o3de_get_gem_load_dependencies(
  339. GEM_LOAD_DEPENDENCIES_VAR all_server_gem_dependencies
  340. TARGET "${project_name}.${server_launcher_type}")
  341. foreach(server_gem_dependency ${all_server_gem_dependencies})
  342. # Skip interface libraries
  343. if(TARGET ${server_gem_dependency})
  344. get_target_property(target_type ${server_gem_dependency} TYPE)
  345. if(${target_type} STREQUAL "INTERFACE_LIBRARY")
  346. continue()
  347. endif()
  348. endif()
  349. # Replace "." with "_"
  350. string(REPLACE "." "_" server_gem_dependency ${server_gem_dependency})
  351. string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${server_gem_dependency}();\n")
  352. string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${server_gem_dependency}());\n")
  353. endforeach()
  354. configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in
  355. ${launcher_unified_binary_dir}/${project_name}.${server_launcher_type}/Includes/StaticModules.inl
  356. )
  357. ly_target_link_libraries(${project_name}.${server_launcher_type} PRIVATE ${all_server_gem_dependencies})
  358. endforeach()
  359. endif()
  360. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  361. unset(extern_module_declarations)
  362. unset(module_invocations)
  363. unset(all_unified_gem_dependencies)
  364. o3de_get_gem_load_dependencies(
  365. GEM_LOAD_DEPENDENCIES_VAR all_unified_gem_dependencies
  366. TARGET "${project_name}.UnifiedLauncher")
  367. foreach(unified_gem_dependency ${all_unified_gem_dependencies})
  368. # Skip interface libraries
  369. if(TARGET ${unified_gem_dependency})
  370. get_target_property(target_type ${unified_gem_dependency} TYPE)
  371. if(${target_type} STREQUAL "INTERFACE_LIBRARY")
  372. continue()
  373. endif()
  374. endif()
  375. # Replace "." with "_"
  376. string(REPLACE "." "_" unified_gem_dependency ${unified_gem_dependency})
  377. string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${unified_gem_dependency}();\n")
  378. string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${unified_gem_dependency}());\n")
  379. endforeach()
  380. configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in
  381. ${launcher_unified_binary_dir}/${project_name}.UnifiedLauncher/Includes/StaticModules.inl
  382. )
  383. ly_target_link_libraries(${project_name}.UnifiedLauncher PRIVATE ${all_unified_gem_dependencies})
  384. endif()
  385. endforeach()
  386. endif()
  387. endfunction()