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. set(server_runtime_dependencies
  113. Legacy::CrySystem
  114. )
  115. if (O3DE_SCRIPT_ONLY)
  116. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  117. set(SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type} "${SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}}" O3DE.${server_launcher_type})
  118. endforeach()
  119. endif()
  120. endif()
  121. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  122. set(unified_runtime_dependencies
  123. Legacy::CrySystem
  124. )
  125. if (O3DE_SCRIPT_ONLY)
  126. set(unified_runtime_dependencies ${unified_runtime_dependencies} O3DE.UnifiedLauncher)
  127. endif()
  128. endif()
  129. endif()
  130. ################################################################################
  131. # Game
  132. ################################################################################
  133. ly_add_target(
  134. NAME ${project_name}.GameLauncher ${PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE}
  135. NAMESPACE AZ
  136. FILES_CMAKE
  137. ${CMAKE_CURRENT_LIST_DIR}/launcher_project_files.cmake
  138. PLATFORM_INCLUDE_FILES
  139. ${pal_dir}/launcher_project_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
  140. COMPILE_DEFINITIONS
  141. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  142. # Adds the name of the project/game
  143. LY_PROJECT_NAME="${project_name}"
  144. # Adds the ${project_name}_GameLauncher target as a define so for the Settings Registry to use
  145. # when loading .setreg file specializations
  146. # This is needed so that only gems for the project game launcher are loaded
  147. LY_CMAKE_TARGET="${project_name}_GameLauncher"
  148. "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
  149. INCLUDE_DIRECTORIES
  150. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  151. .
  152. ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.GameLauncher/Includes # required for StaticModules.inl
  153. BUILD_DEPENDENCIES
  154. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  155. AZ::Launcher.Static
  156. AZ::Launcher.Game.Static
  157. ${game_build_dependencies}
  158. RUNTIME_DEPENDENCIES
  159. ${game_runtime_dependencies}
  160. )
  161. # Needs to be set manually after ly_add_target to prevent the default location overriding it
  162. set_target_properties(${project_name}.GameLauncher
  163. PROPERTIES
  164. FOLDER ${project_name}
  165. LY_PROJECT_NAME ${project_name}
  166. )
  167. # Turn on DPI scaling support.
  168. set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DPI_AWARE ${O3DE_DPI_AWARENESS})
  169. if(LY_DEFAULT_PROJECT_PATH)
  170. if (TARGET ${project_name})
  171. get_target_property(project_game_launcher_additional_args ${project_name} GAMELAUNCHER_ADDITIONAL_VS_DEBUGGER_COMMAND_ARGUMENTS)
  172. if (project_game_launcher_additional_args)
  173. # Avoid pushing param-NOTFOUND into the argument in case this property wasn't found
  174. set(additional_game_vs_debugger_args "${project_game_launcher_additional_args}")
  175. endif()
  176. endif()
  177. set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS
  178. "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\" ${additional_game_vs_debugger_args}")
  179. endif()
  180. # Associate the Clients Gem Variant with each projects GameLauncher
  181. ly_set_gem_variant_to_load(TARGETS ${project_name}.GameLauncher VARIANTS Clients)
  182. ################################################################################
  183. # Server
  184. ################################################################################
  185. if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
  186. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  187. ly_add_target(
  188. NAME ${project_name}.${server_launcher_type} ${SERVER_LAUNCHERTYPE_${server_launcher_type}}
  189. NAMESPACE AZ
  190. FILES_CMAKE
  191. ${CMAKE_CURRENT_LIST_DIR}/launcher_project_files.cmake
  192. PLATFORM_INCLUDE_FILES
  193. ${pal_dir}/launcher_project_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
  194. COMPILE_DEFINITIONS
  195. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  196. # Adds the name of the project/game
  197. LY_PROJECT_NAME="${project_name}"
  198. # Adds the ${project_name}_${server_launcher_type} target as a define so for the Settings Registry to use
  199. # when loading .setreg file specializations
  200. # This is needed so that only gems for the project server launcher are loaded
  201. LY_CMAKE_TARGET="${project_name}_${server_launcher_type}"
  202. "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
  203. INCLUDE_DIRECTORIES
  204. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  205. .
  206. ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.${server_launcher_type}/Includes # required for StaticModules.inl
  207. BUILD_DEPENDENCIES
  208. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  209. ${SERVER_BUILD_DEPENDENCIES_${server_launcher_type}}
  210. RUNTIME_DEPENDENCIES
  211. ${SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}}
  212. )
  213. # Needs to be set manually after ly_add_target to prevent the default location overriding it
  214. set_target_properties(${project_name}.${server_launcher_type}
  215. PROPERTIES
  216. FOLDER ${project_name}
  217. LY_PROJECT_NAME ${project_name}
  218. )
  219. # Turn on DPI scaling support.
  220. set_property(TARGET ${project_name}.${server_launcher_type} APPEND PROPERTY VS_DPI_AWARE ${O3DE_DPI_AWARENESS})
  221. if(LY_DEFAULT_PROJECT_PATH)
  222. if (TARGET ${project_name})
  223. get_target_property(project_server_launcher_additional_args ${project_name} SERVERLAUNCHER_ADDITIONAL_VS_DEBUGGER_COMMAND_ARGUMENTS)
  224. if (project_server_launcher_additional_args)
  225. # Avoid pushing param-NOTFOUND into the argument in case this property wasn't found
  226. set(additional_server_vs_debugger_args "${project_server_launcher_additional_args}")
  227. endif()
  228. endif()
  229. set_property(TARGET ${project_name}.${server_launcher_type} APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS
  230. "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\" ${additional_server_vs_debugger_args}")
  231. endif()
  232. # Associate the Servers Gem Variant with each projects ServerLauncher
  233. ly_set_gem_variant_to_load(TARGETS ${project_name}.${server_launcher_type} VARIANTS ${SERVER_VARIANT_${server_launcher_type}})
  234. # If the Editor is getting built, it should rebuild the ServerLauncher as well. The Editor's game mode will attempt
  235. # to launch it, and things can break if the two are out of sync.
  236. if(PAL_TRAIT_BUILD_HOST_TOOLS)
  237. ly_add_dependencies(Editor ${project_name}.${server_launcher_type})
  238. endif()
  239. endforeach()
  240. endif()
  241. ################################################################################
  242. # Unified
  243. ################################################################################
  244. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  245. ly_add_target(
  246. NAME ${project_name}.UnifiedLauncher ${PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE}
  247. NAMESPACE AZ
  248. FILES_CMAKE
  249. ${CMAKE_CURRENT_LIST_DIR}/launcher_project_files.cmake
  250. PLATFORM_INCLUDE_FILES
  251. ${pal_dir}/launcher_project_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
  252. COMPILE_DEFINITIONS
  253. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  254. # Adds the name of the project/game
  255. LY_PROJECT_NAME="${project_name}"
  256. # Adds the ${project_name}_UnifiedLauncher target as a define so for the Settings Registry to use
  257. # when loading .setreg file specializations
  258. # This is needed so that only gems for the project unified launcher are loaded
  259. LY_CMAKE_TARGET="${project_name}_UnifiedLauncher"
  260. "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
  261. INCLUDE_DIRECTORIES
  262. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  263. .
  264. ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.UnifiedLauncher/Includes # required for StaticModules.inl
  265. BUILD_DEPENDENCIES
  266. ${LAUNCHER_TARGET_PROPERTY_TYPE}
  267. AZ::Launcher.Static
  268. AZ::Launcher.Unified.Static
  269. ${unified_build_dependencies}
  270. RUNTIME_DEPENDENCIES
  271. ${unified_runtime_dependencies}
  272. )
  273. # Needs to be set manually after ly_add_target to prevent the default location overriding it
  274. set_target_properties(${project_name}.UnifiedLauncher
  275. PROPERTIES
  276. FOLDER ${project_name}
  277. LY_PROJECT_NAME ${project_name}
  278. )
  279. # Turn on DPI scaling support.
  280. set_property(TARGET ${project_name}.UnifiedLauncher APPEND PROPERTY VS_DPI_AWARE ${O3DE_DPI_AWARENESS})
  281. if(LY_DEFAULT_PROJECT_PATH)
  282. if (TARGET ${project_name})
  283. get_target_property(project_unified_launcher_additional_args ${project_name} UNIFIEDLAUNCHER_ADDITIONAL_VS_DEBUGGER_COMMAND_ARGUMENTS)
  284. if (project_unified_launcher_additional_args)
  285. # Avoid pushing param-NOTFOUND into the argument in case this property wasn't found
  286. set(additional_unified_vs_debugger_args "${project_unified_launcher_additional_args}")
  287. endif()
  288. endif()
  289. set_property(TARGET ${project_name}.UnifiedLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS
  290. "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\" ${additional_unified_vs_debugger_args}")
  291. endif()
  292. # Associate the Unified Gem Variant with each projects UnfiedLauncher
  293. ly_set_gem_variant_to_load(TARGETS ${project_name}.UnifiedLauncher VARIANTS Unified)
  294. endif()
  295. endforeach()
  296. #! Defer generation of the StaticModules.inl file needed in monolithic builds until after all the CMake targets are known
  297. # This is that the GEM_MODULE target runtime dependencies can be parsed to discover the list of dependent modules
  298. # to load
  299. function(ly_delayed_generate_static_modules_inl)
  300. get_property(SERVER_LAUNCHER_TYPES GLOBAL PROPERTY SERVER_LAUNCHER_TYPES)
  301. if(LY_MONOLITHIC_GAME)
  302. get_property(launcher_unified_binary_dir GLOBAL PROPERTY LAUNCHER_UNIFIED_BINARY_DIR)
  303. get_property(project_names GLOBAL PROPERTY LY_STATIC_MODULE_PROJECTS_NAME)
  304. foreach(project_name ${project_names})
  305. unset(extern_module_declarations)
  306. unset(module_invocations)
  307. unset(all_game_gem_dependencies)
  308. o3de_get_gem_load_dependencies(
  309. GEM_LOAD_DEPENDENCIES_VAR all_game_gem_dependencies
  310. TARGET "${project_name}.GameLauncher")
  311. foreach(game_gem_dependency ${all_game_gem_dependencies})
  312. # Sometimes, a gem's Client variant may be an interface library
  313. # which depends on multiple gem targets. The interface libraries
  314. # should be skipped; the real dependencies of the interface will be processed
  315. if(TARGET ${game_gem_dependency})
  316. get_target_property(target_type ${game_gem_dependency} TYPE)
  317. if(${target_type} STREQUAL "INTERFACE_LIBRARY")
  318. continue()
  319. endif()
  320. endif()
  321. # To match the convention on how gems targets vs gem modules are named,
  322. # we remove the ".Static" from the suffix
  323. # Replace "." with "_"
  324. string(REPLACE "." "_" game_gem_dependency ${game_gem_dependency})
  325. string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${game_gem_dependency}();\n")
  326. string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${game_gem_dependency}());\n")
  327. endforeach()
  328. configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in
  329. ${launcher_unified_binary_dir}/${project_name}.GameLauncher/Includes/StaticModules.inl
  330. )
  331. ly_target_link_libraries(${project_name}.GameLauncher PRIVATE ${all_game_gem_dependencies})
  332. if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
  333. foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
  334. unset(extern_module_declarations)
  335. unset(module_invocations)
  336. unset(all_server_gem_dependencies)
  337. o3de_get_gem_load_dependencies(
  338. GEM_LOAD_DEPENDENCIES_VAR all_server_gem_dependencies
  339. TARGET "${project_name}.${server_launcher_type}")
  340. foreach(server_gem_dependency ${all_server_gem_dependencies})
  341. # Skip interface libraries
  342. if(TARGET ${server_gem_dependency})
  343. get_target_property(target_type ${server_gem_dependency} TYPE)
  344. if(${target_type} STREQUAL "INTERFACE_LIBRARY")
  345. continue()
  346. endif()
  347. endif()
  348. # Replace "." with "_"
  349. string(REPLACE "." "_" server_gem_dependency ${server_gem_dependency})
  350. string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${server_gem_dependency}();\n")
  351. string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${server_gem_dependency}());\n")
  352. endforeach()
  353. configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in
  354. ${launcher_unified_binary_dir}/${project_name}.${server_launcher_type}/Includes/StaticModules.inl
  355. )
  356. ly_target_link_libraries(${project_name}.${server_launcher_type} PRIVATE ${all_server_gem_dependencies})
  357. endforeach()
  358. endif()
  359. if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
  360. unset(extern_module_declarations)
  361. unset(module_invocations)
  362. unset(all_unified_gem_dependencies)
  363. o3de_get_gem_load_dependencies(
  364. GEM_LOAD_DEPENDENCIES_VAR all_unified_gem_dependencies
  365. TARGET "${project_name}.UnifiedLauncher")
  366. foreach(unified_gem_dependency ${all_unified_gem_dependencies})
  367. # Skip interface libraries
  368. if(TARGET ${unified_gem_dependency})
  369. get_target_property(target_type ${unified_gem_dependency} TYPE)
  370. if(${target_type} STREQUAL "INTERFACE_LIBRARY")
  371. continue()
  372. endif()
  373. endif()
  374. # Replace "." with "_"
  375. string(REPLACE "." "_" unified_gem_dependency ${unified_gem_dependency})
  376. string(APPEND extern_module_declarations "extern \"C\" AZ::Module* CreateModuleClass_Gem_${unified_gem_dependency}();\n")
  377. string(APPEND module_invocations " modulesOut.push_back(CreateModuleClass_Gem_${unified_gem_dependency}());\n")
  378. endforeach()
  379. configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/StaticModules.in
  380. ${launcher_unified_binary_dir}/${project_name}.UnifiedLauncher/Includes/StaticModules.inl
  381. )
  382. ly_target_link_libraries(${project_name}.UnifiedLauncher PRIVATE ${all_unified_gem_dependencies})
  383. endif()
  384. endforeach()
  385. endif()
  386. endfunction()