Install_common.cmake 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  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. include(cmake/FileUtil.cmake)
  9. set(LY_INSTALL_EXTERNAL_BUILD_DIRS "" CACHE PATH "External build directories to be included in the install process. This allows to package non-monolithic and monolithic.")
  10. set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise
  11. define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET
  12. BRIEF_DOCS "Defines if a \"RUN\" targets should be created when installing this target Gem"
  13. FULL_DOCS [[
  14. Property which is set on targets that should generate a "RUN"
  15. target when installed. This \"RUN\" target helps to run the
  16. binary from the installed location directly from the IDE.
  17. ]]
  18. )
  19. # We can have elements being installed under the following components:
  20. # - Core (required for all) (default)
  21. # - Default
  22. # - Default_$<CONFIG>
  23. # - Monolithic
  24. # - Monolithic_$<CONFIG>
  25. # Debug/Monolithic are build permutations, so for a CMake run, it can only generate
  26. # one of the permutations. Each build permutation can generate only one cmake_install.cmake.
  27. # Each build permutation will generate the same elements in Core.
  28. # CPack is able to put the two together by taking Core from one permutation and then taking
  29. # each permutation.
  30. ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CORE)
  31. if(LY_MONOLITHIC_GAME)
  32. set(LY_BUILD_PERMUTATION Monolithic)
  33. else()
  34. set(LY_BUILD_PERMUTATION Default)
  35. endif()
  36. string(TOUPPER ${LY_BUILD_PERMUTATION} LY_INSTALL_PERMUTATION_COMPONENT)
  37. cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory)
  38. cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory)
  39. # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target
  40. cmake_path(RELATIVE_PATH CMAKE_ARCHIVE_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE archive_output_directory)
  41. cmake_path(APPEND archive_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
  42. cmake_path(APPEND library_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
  43. cmake_path(APPEND runtime_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
  44. #! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target
  45. function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_target_source_dir)
  46. # De-alias target name
  47. ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME)
  48. # Get the target source directory relative to the LY root folder
  49. ly_get_engine_relative_source_dir(${absolute_target_source_dir} relative_target_source_dir)
  50. # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that
  51. # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the
  52. # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory.
  53. # Instead, we install them with install(DIRECTORY)
  54. get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES)
  55. if (include_directories)
  56. unset(public_headers)
  57. foreach(include_directory ${include_directories})
  58. string(GENEX_STRIP ${include_directory} include_genex_expr)
  59. if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions
  60. unset(current_public_headers)
  61. cmake_path(NORMAL_PATH include_directory)
  62. string(REGEX REPLACE "/$" "" include_directory "${include_directory}")
  63. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${absolute_target_source_dir} NORMALIZE include_directory_child_of_o3de_root)
  64. if(NOT include_directory_child_of_o3de_root)
  65. # Include directory is outside of the O3DE root folder ${LY_ROOT_FOLDER}.
  66. # For the INSTALL step, the O3DE root folder must be a prefix of all include directories.
  67. continue()
  68. endif()
  69. unset(rel_include_dir)
  70. cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE rel_include_dir)
  71. cmake_path(APPEND rel_include_dir "..")
  72. cmake_path(NORMAL_PATH rel_include_dir OUTPUT_VARIABLE destination_dir)
  73. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  74. install(DIRECTORY ${include_directory}
  75. DESTINATION ${destination_dir}
  76. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  77. FILES_MATCHING
  78. PATTERN *.h
  79. PATTERN *.hpp
  80. PATTERN *.inl
  81. PATTERN *.hxx
  82. PATTERN *.jinja # LyAutoGen files
  83. )
  84. install(CODE "endif()")
  85. endif()
  86. endforeach()
  87. endif()
  88. get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY)
  89. if(target_runtime_output_directory)
  90. cmake_path(RELATIVE_PATH target_runtime_output_directory BASE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_runtime_output_subdirectory)
  91. endif()
  92. get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY)
  93. if(target_library_output_directory)
  94. cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory)
  95. endif()
  96. if(COMMAND ly_install_target_override)
  97. # Mac needs special handling because of a cmake issue
  98. ly_install_target_override(TARGET ${TARGET_NAME}
  99. ARCHIVE_DIR ${archive_output_directory}
  100. LIBRARY_DIR ${library_output_directory}
  101. RUNTIME_DIR ${runtime_output_directory}
  102. LIBRARY_SUBDIR ${target_library_output_subdirectory}
  103. RUNTIME_SUBDIR ${target_runtime_output_subdirectory}
  104. )
  105. else()
  106. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  107. string(TOUPPER ${conf} UCONF)
  108. install(TARGETS ${TARGET_NAME}
  109. ARCHIVE
  110. DESTINATION ${archive_output_directory}
  111. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  112. CONFIGURATIONS ${conf}
  113. LIBRARY
  114. DESTINATION ${library_output_directory}/${target_library_output_subdirectory}
  115. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  116. CONFIGURATIONS ${conf}
  117. RUNTIME
  118. DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory}
  119. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  120. CONFIGURATIONS ${conf}
  121. )
  122. endforeach()
  123. endif()
  124. # CMakeLists.txt related files
  125. string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME})
  126. if(match)
  127. set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}")
  128. set(NAME_PLACEHOLDER ${CMAKE_MATCH_2})
  129. else()
  130. set(NAMESPACE_PLACEHOLDER "")
  131. set(NAME_PLACEHOLDER ${TARGET_NAME})
  132. endif()
  133. get_target_property(should_create_helper ${TARGET_NAME} LY_INSTALL_GENERATE_RUN_TARGET)
  134. if(should_create_helper)
  135. set(NAME_PLACEHOLDER ${NAME_PLACEHOLDER}.Imported)
  136. endif()
  137. set(TARGET_TYPE_PLACEHOLDER "")
  138. get_target_property(target_type ${TARGET_NAME} TYPE)
  139. # Remove the _LIBRARY since we dont need to pass that to ly_add_targets
  140. string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type})
  141. # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead
  142. string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER})
  143. # In non-monolithic mode, gem targets are MODULE libraries, In monolithic mode gem targets are STATIC libraries
  144. set(GEM_LIBRARY_TYPES "MODULE" "STATIC")
  145. if(TARGET_TYPE_PLACEHOLDER IN_LIST GEM_LIBRARY_TYPES)
  146. get_target_property(gem_module ${TARGET_NAME} GEM_MODULE)
  147. if(gem_module)
  148. string(PREPEND TARGET_TYPE_PLACEHOLDER "GEM_")
  149. endif()
  150. endif()
  151. string(REPEAT " " 12 PLACEHOLDER_INDENT)
  152. get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS)
  153. if(COMPILE_DEFINITIONS_PLACEHOLDER)
  154. set(COMPILE_DEFINITIONS_PLACEHOLDER "${PLACEHOLDER_INDENT}${COMPILE_DEFINITIONS_PLACEHOLDER}")
  155. list(JOIN COMPILE_DEFINITIONS_PLACEHOLDER "\n${PLACEHOLDER_INDENT}" COMPILE_DEFINITIONS_PLACEHOLDER)
  156. else()
  157. unset(COMPILE_DEFINITIONS_PLACEHOLDER)
  158. endif()
  159. # Includes need additional processing to add the install root
  160. if(include_directories)
  161. foreach(include ${include_directories})
  162. string(GENEX_STRIP ${include} include_genex_expr)
  163. if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions
  164. # Make the include path relative to the source dir where the target will be declared
  165. cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include)
  166. string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${target_include}\n")
  167. endif()
  168. endforeach()
  169. endif()
  170. string(REPEAT " " 8 PLACEHOLDER_INDENT)
  171. get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES)
  172. 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
  173. set(RUNTIME_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${RUNTIME_DEPENDENCIES_PLACEHOLDER}")
  174. list(JOIN RUNTIME_DEPENDENCIES_PLACEHOLDER "\n${PLACEHOLDER_INDENT}" RUNTIME_DEPENDENCIES_PLACEHOLDER)
  175. else()
  176. unset(RUNTIME_DEPENDENCIES_PLACEHOLDER)
  177. endif()
  178. string(REPEAT " " 12 PLACEHOLDER_INDENT)
  179. get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES)
  180. unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
  181. if(inteface_build_dependencies_props)
  182. foreach(build_dependency ${inteface_build_dependencies_props})
  183. # Skip wrapping produced when targets are not created in the same directory
  184. if(NOT ${build_dependency} MATCHES "^::@")
  185. list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}")
  186. endif()
  187. endforeach()
  188. endif()
  189. # We also need to pass the private link libraries since we will use that to generate the runtime dependencies
  190. get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES)
  191. if(private_build_dependencies_props)
  192. foreach(build_dependency ${private_build_dependencies_props})
  193. # Skip wrapping produced when targets are not created in the same directory
  194. if(NOT ${build_dependency} MATCHES "^::@")
  195. list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}")
  196. endif()
  197. endforeach()
  198. endif()
  199. list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
  200. list(JOIN INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
  201. string(REPEAT " " 8 PLACEHOLDER_INDENT)
  202. # If a target has an LY_PROJECT_NAME property, forward that property to new target
  203. get_target_property(target_project_association ${TARGET_NAME} LY_PROJECT_NAME)
  204. if(target_project_association)
  205. list(APPEND TARGET_PROPERTIES_PLACEHOLDER "${PLACEHOLDER_INDENT}LY_PROJECT_NAME ${target_project_association}")
  206. endif()
  207. # If the target is an executable/application, add a custom target so we can debug the target in project-centric workflow
  208. if(should_create_helper)
  209. string(REPLACE ".Imported" "" RUN_TARGET_NAME ${NAME_PLACEHOLDER})
  210. set(target_types_with_debugging_helper EXECUTABLE APPLICATION)
  211. if(NOT target_type IN_LIST target_types_with_debugging_helper)
  212. message(FATAL_ERROR "Cannot generate a RUN target for ${TARGET_NAME}, type is ${target_type}")
  213. endif()
  214. set(TARGET_RUN_HELPER
  215. "add_custom_target(${RUN_TARGET_NAME})
  216. set_target_properties(${RUN_TARGET_NAME} PROPERTIES
  217. FOLDER \"O3DE_SDK\"
  218. VS_DEBUGGER_COMMAND \$<GENEX_EVAL:\$<TARGET_PROPERTY:${NAME_PLACEHOLDER},IMPORTED_LOCATION>>
  219. VS_DEBUGGER_COMMAND_ARGUMENTS \"--project-path=\${LY_DEFAULT_PROJECT_PATH}\"
  220. )"
  221. )
  222. endif()
  223. # Config files
  224. set(target_file_contents "# Generated by O3DE install\n\n")
  225. if(NOT target_type STREQUAL INTERFACE_LIBRARY)
  226. unset(target_location)
  227. set(runtime_types EXECUTABLE APPLICATION)
  228. if(target_type IN_LIST runtime_types)
  229. set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${target_runtime_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
  230. elseif(target_type STREQUAL MODULE_LIBRARY)
  231. set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
  232. elseif(target_type STREQUAL SHARED_LIBRARY)
  233. string(APPEND target_file_contents
  234. "set_property(TARGET ${NAME_PLACEHOLDER}
  235. APPEND_STRING PROPERTY IMPORTED_IMPLIB
  236. $<$<CONFIG:$<CONFIG>$<ANGLE-R>:\"\${LY_ROOT_FOLDER}/${archive_output_directory}/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"$<ANGLE-R>
  237. )
  238. ")
  239. string(APPEND target_file_contents
  240. "set_property(TARGET ${NAME_PLACEHOLDER}
  241. PROPERTY IMPORTED_IMPLIB_$<UPPER_CASE:$<CONFIG>>
  242. \"\${LY_ROOT_FOLDER}/${archive_output_directory}/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"
  243. )
  244. ")
  245. set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
  246. else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY
  247. set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>")
  248. endif()
  249. if(target_location)
  250. string(APPEND target_file_contents
  251. "set_property(TARGET ${NAME_PLACEHOLDER}
  252. APPEND_STRING PROPERTY IMPORTED_LOCATION
  253. $<$<CONFIG:$<CONFIG>$<ANGLE-R>:${target_location}$<ANGLE-R>
  254. )
  255. set_property(TARGET ${NAME_PLACEHOLDER}
  256. PROPERTY IMPORTED_LOCATION_$<UPPER_CASE:$<CONFIG>>
  257. ${target_location}
  258. )
  259. ")
  260. endif()
  261. endif()
  262. set(target_install_source_dir ${CMAKE_CURRENT_BINARY_DIR}/install/${relative_target_source_dir})
  263. file(GENERATE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_$<CONFIG>.cmake" CONTENT "${target_file_contents}")
  264. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  265. string(TOUPPER ${conf} UCONF)
  266. install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake"
  267. DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  268. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  269. CONFIGURATIONS ${conf}
  270. )
  271. endforeach()
  272. # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target
  273. ly_file_read(${LY_ROOT_FOLDER}/cmake/install/InstalledTarget.in target_cmakelists_template)
  274. string(CONFIGURE ${target_cmakelists_template} output_cmakelists_data @ONLY)
  275. set(${OUTPUT_CONFIGURED_TARGET} ${output_cmakelists_data} PARENT_SCOPE)
  276. endfunction()
  277. #! ly_setup_subdirectories: setups all targets on a per directory basis
  278. function(ly_setup_subdirectories)
  279. get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
  280. foreach(target_subdirectory IN LISTS all_subdirectories)
  281. ly_setup_subdirectory(${target_subdirectory})
  282. endforeach()
  283. endfunction()
  284. #! ly_setup_subdirectory: setup all targets in the subdirectory
  285. function(ly_setup_subdirectory absolute_target_source_dir)
  286. ly_get_engine_relative_source_dir(${absolute_target_source_dir} relative_target_source_dir)
  287. # The builtin BUILDSYSTEM_TARGETS property isn't being used here as that returns the de-alised
  288. # TARGET and we need the alias namespace for recreating the CMakeLists.txt in the install layout
  289. get_property(ALIAS_TARGETS_NAME DIRECTORY ${absolute_target_source_dir} PROPERTY LY_DIRECTORY_TARGETS)
  290. foreach(ALIAS_TARGET_NAME IN LISTS ALIAS_TARGETS_NAME)
  291. ly_setup_target(configured_target ${ALIAS_TARGET_NAME} ${absolute_target_source_dir})
  292. string(APPEND all_configured_targets "${configured_target}")
  293. endforeach()
  294. # Initialize the target install source directory to path underneath the current binary directory
  295. set(target_install_source_dir "${CMAKE_CURRENT_BINARY_DIR}/install/${relative_target_source_dir}")
  296. ly_file_read(${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment)
  297. # 1. Create the base CMakeLists.txt that will just include a cmake file per platform
  298. file(CONFIGURE OUTPUT "${target_install_source_dir}/CMakeLists.txt" CONTENT [[
  299. @cmake_copyright_comment@
  300. include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  301. ]] @ONLY)
  302. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  303. install(FILES "${target_install_source_dir}/CMakeLists.txt"
  304. DESTINATION ${relative_target_source_dir}
  305. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  306. )
  307. install(CODE "endif()")
  308. # 2. For this platform file, create a Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake file
  309. # that will include different configuration permutations (e.g. monolithic vs non-monolithic)
  310. file(CONFIGURE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" CONTENT [[
  311. @cmake_copyright_comment@
  312. if(LY_MONOLITHIC_GAME)
  313. include(Platform/${PAL_PLATFORM_NAME}/Monolithic/permutation.cmake)
  314. else()
  315. include(Platform/${PAL_PLATFORM_NAME}/Default/permutation.cmake)
  316. endif()
  317. ]])
  318. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  319. install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake"
  320. DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}
  321. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  322. )
  323. install(CODE "endif()")
  324. # 3. For this configuration permutation, generate a Platform/${PAL_PLATFORM_NAME}/${permutation}/permutation.cmake
  325. # that will declare the target and configure it
  326. ly_setup_subdirectory_create_alias("${absolute_target_source_dir}" CREATE_ALIASES_PLACEHOLDER)
  327. ly_setup_subdirectory_set_gem_variant_to_load("${absolute_target_source_dir}" GEM_VARIANT_TO_LOAD_PLACEHOLDER)
  328. ly_setup_subdirectory_enable_gems("${absolute_target_source_dir}" ENABLE_GEMS_PLACEHOLDER)
  329. # Write out all the aggregated ly_add_target function calls and the final ly_create_alias() calls to the target CMakeLists.txt
  330. file(WRITE "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake"
  331. "${cmake_copyright_comment}"
  332. "${all_configured_targets}"
  333. "\n"
  334. "${CREATE_ALIASES_PLACEHOLDER}"
  335. "${GEM_VARIANT_TO_LOAD_PLACEHOLDER}"
  336. "${ENABLE_GEMS_PLACEHOLDER}"
  337. )
  338. install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake"
  339. DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  340. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}
  341. )
  342. endfunction()
  343. #! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt
  344. function(ly_setup_o3de_install)
  345. ly_setup_subdirectories()
  346. ly_setup_cmake_install()
  347. ly_setup_runtime_dependencies()
  348. ly_setup_assets()
  349. # Misc
  350. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  351. install(FILES
  352. ${LY_ROOT_FOLDER}/ctest_pytest.ini
  353. ${LY_ROOT_FOLDER}/LICENSE.txt
  354. ${LY_ROOT_FOLDER}/README.md
  355. DESTINATION .
  356. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  357. )
  358. install(CODE "endif()")
  359. # Inject other build directories
  360. foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS})
  361. install(CODE "set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE)
  362. include(${external_dir}/cmake_install.cmake)"
  363. ALL_COMPONENTS)
  364. endforeach()
  365. if(COMMAND ly_post_install_steps)
  366. ly_post_install_steps()
  367. endif()
  368. endfunction()
  369. #! ly_setup_cmake_install: install the "cmake" folder
  370. function(ly_setup_cmake_install)
  371. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  372. install(DIRECTORY "${LY_ROOT_FOLDER}/cmake"
  373. DESTINATION .
  374. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  375. PATTERN "__pycache__" EXCLUDE
  376. PATTERN "Findo3de.cmake" EXCLUDE
  377. REGEX "3rdParty/Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE
  378. )
  379. install(CODE "endif()")
  380. # Connect configuration types
  381. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  382. install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake"
  383. DESTINATION cmake
  384. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  385. )
  386. install(CODE "endif()")
  387. # generate each ConfigurationType_<CONFIG>.cmake file and install it under that configuration
  388. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  389. string(TOUPPER ${conf} UCONF)
  390. configure_file("${LY_ROOT_FOLDER}/cmake/install/ConfigurationType_config.cmake.in"
  391. "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake"
  392. @ONLY
  393. )
  394. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  395. install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake"
  396. DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  397. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  398. CONFIGURATIONS ${conf}
  399. )
  400. install(CODE "endif()")
  401. endforeach()
  402. # Transform the LY_EXTERNAL_SUBDIRS list into a json array
  403. set(indent " ")
  404. foreach(external_subdir ${LY_EXTERNAL_SUBDIRS})
  405. cmake_path(RELATIVE_PATH external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE engine_rel_external_subdir)
  406. list(APPEND relative_external_subdirs "\"${engine_rel_external_subdir}\"")
  407. endforeach()
  408. list(JOIN relative_external_subdirs ",\n${indent}" LY_INSTALL_EXTERNAL_SUBDIRS)
  409. # Read the "templates" key from the source engine.json
  410. o3de_read_json_array(engine_templates ${LY_ROOT_FOLDER}/engine.json "templates")
  411. foreach(template_path ${engine_templates})
  412. list(APPEND relative_templates "\"${template_path}\"")
  413. endforeach()
  414. list(JOIN relative_templates ",\n${indent}" LY_INSTALL_TEMPLATES)
  415. configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY)
  416. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  417. install(FILES
  418. "${LY_ROOT_FOLDER}/CMakeLists.txt"
  419. "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json"
  420. DESTINATION .
  421. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  422. )
  423. install(CODE "endif()")
  424. # Collect all Find files that were added with ly_add_external_target_path
  425. unset(additional_find_files)
  426. unset(additional_platform_files)
  427. get_property(additional_module_paths GLOBAL PROPERTY LY_ADDITIONAL_MODULE_PATH)
  428. foreach(additional_module_path ${additional_module_paths})
  429. unset(find_files)
  430. file(GLOB find_files "${additional_module_path}/Find*.cmake")
  431. list(APPEND additional_find_files "${find_files}")
  432. foreach(find_file ${find_files})
  433. # also copy the Platform/<current_platform> to the destination
  434. cmake_path(GET find_file PARENT_PATH find_file_parent)
  435. unset(plat_files)
  436. file(GLOB plat_files "${find_file_parent}/Platform/${PAL_PLATFORM_NAME}/*.cmake")
  437. list(APPEND additional_platform_files "${plat_files}")
  438. endforeach()
  439. endforeach()
  440. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  441. install(FILES ${additional_find_files}
  442. DESTINATION cmake/3rdParty
  443. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  444. )
  445. install(FILES ${additional_platform_files}
  446. DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}
  447. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  448. )
  449. install(CODE "endif()")
  450. # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all
  451. # targets that are pre-built
  452. unset(FIND_PACKAGES_PLACEHOLDER)
  453. # Add to the FIND_PACKAGES_PLACEHOLDER all directories in which ly_add_target were called in
  454. get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
  455. foreach(target_subdirectory IN LISTS all_subdirectories)
  456. cmake_path(RELATIVE_PATH target_subdirectory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE relative_target_subdirectory)
  457. string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${relative_target_subdirectory})\n")
  458. endforeach()
  459. configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY)
  460. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  461. install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake"
  462. DESTINATION cmake
  463. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  464. )
  465. install(CODE "endif()")
  466. # BuiltInPackage_<platform>.cmake: since associations could happen in any cmake file across the engine. We collect
  467. # all the associations in ly_associate_package and then generate them into BuiltInPackages_<platform>.cmake. This
  468. # will consolidate all associations in one file
  469. get_property(all_package_names GLOBAL PROPERTY LY_PACKAGE_NAMES)
  470. set(builtinpackages "# Generated by O3DE install\n\n")
  471. foreach(package_name IN LISTS all_package_names)
  472. get_property(package_hash GLOBAL PROPERTY LY_PACKAGE_HASH_${package_name})
  473. get_property(targets GLOBAL PROPERTY LY_PACKAGE_TARGETS_${package_name})
  474. string(APPEND builtinpackages "ly_associate_package(PACKAGE_NAME ${package_name} TARGETS ${targets} PACKAGE_HASH ${package_hash})\n")
  475. endforeach()
  476. set(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  477. file(GENERATE OUTPUT ${pal_builtin_file}
  478. CONTENT ${builtinpackages}
  479. )
  480. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  481. install(FILES "${pal_builtin_file}"
  482. DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}
  483. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  484. )
  485. install(CODE "endif()")
  486. endfunction()
  487. #! ly_setup_runtime_dependencies: install runtime dependencies
  488. function(ly_setup_runtime_dependencies)
  489. # Common functions used by the bellow code
  490. if(COMMAND ly_install_code_function_override)
  491. ly_install_code_function_override()
  492. else()
  493. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  494. string(TOUPPER ${conf} UCONF)
  495. install(CODE
  496. "function(ly_copy source_file target_directory)
  497. cmake_path(GET source_file FILENAME file_name)
  498. if(NOT EXISTS ${target_directory}/${file_name})
  499. file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS})
  500. endif()
  501. endfunction()"
  502. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  503. )
  504. endforeach()
  505. endif()
  506. unset(runtime_commands)
  507. get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS)
  508. foreach(alias_target IN LISTS all_targets)
  509. ly_de_alias_target(${alias_target} target)
  510. # Exclude targets that dont produce runtime outputs
  511. get_target_property(target_type ${target} TYPE)
  512. if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS)
  513. continue()
  514. endif()
  515. get_target_property(target_runtime_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY)
  516. if(target_runtime_output_directory)
  517. cmake_path(RELATIVE_PATH target_runtime_output_directory BASE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_runtime_output_subdirectory)
  518. endif()
  519. # runtime dependencies that need to be copied to the output
  520. # Anywhere CMAKE_INSTALL_PREFIX is used, it has to be escaped so it is baked into the cmake_install.cmake script instead
  521. # of baking the path. This is needed so `cmake --install --prefix <someprefix>` works regardless of the CMAKE_INSTALL_PREFIX
  522. # used to generate the solution.
  523. # CMAKE_INSTALL_PREFIX is still used when building the INSTALL target
  524. set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}")
  525. set(target_file_dir "${install_output_folder}/${target_runtime_output_subdirectory}")
  526. ly_get_runtime_dependencies(runtime_dependencies ${target})
  527. foreach(runtime_dependency ${runtime_dependencies})
  528. unset(runtime_command)
  529. unset(runtime_depend) # unused, but required to be passed to ly_get_runtime_dependency_command
  530. ly_get_runtime_dependency_command(runtime_command runtime_depend ${runtime_dependency})
  531. string(CONFIGURE "${runtime_command}" runtime_command @ONLY)
  532. list(APPEND runtime_commands ${runtime_command})
  533. endforeach()
  534. endforeach()
  535. list(REMOVE_DUPLICATES runtime_commands)
  536. list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file
  537. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  538. string(TOUPPER ${conf} UCONF)
  539. install(CODE
  540. "if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^(${conf})\$\")
  541. ${runtime_commands_str}
  542. endif()"
  543. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF}
  544. )
  545. endforeach()
  546. endfunction()
  547. #! ly_setup_assets: install asset directories required by the engine
  548. function(ly_setup_assets)
  549. # Gem Source Assets and configuration files
  550. # Find all gem directories relative to the CMake Source Dir
  551. # This first loop is to filter out transient and .gitignore'd folders that should be added to
  552. # the install layout from the root directory. Such as <external-subdirectory-root>/Cache.
  553. # This is also done to avoid globbing thousands of files in subdirectories that shouldn't
  554. # be processed.
  555. foreach(gem_candidate_dir IN LISTS LY_EXTERNAL_SUBDIRS LY_PROJECTS)
  556. file(REAL_PATH ${gem_candidate_dir} gem_candidate_dir BASE_DIRECTORY ${LY_ROOT_FOLDER})
  557. # Don't recurse immediately in order to exclude transient source artifacts
  558. file(GLOB
  559. external_subdir_files
  560. LIST_DIRECTORIES TRUE
  561. "${gem_candidate_dir}/*"
  562. )
  563. # Exclude transient artifacts that shouldn't be copied to the install layout
  564. list(FILTER external_subdir_files EXCLUDE REGEX "/([Bb]uild|[Cc]ache|[Uu]ser)$")
  565. # Storing a "mapping" of gem candidate directories, to external_subdirectory files using
  566. # a DIRECTORY property for the "value" and the GLOBAL property for the "key"
  567. set_property(DIRECTORY ${gem_candidate_dir} APPEND PROPERTY directory_filtered_asset_paths "${external_subdir_files}")
  568. set_property(GLOBAL APPEND PROPERTY global_gem_candidate_dirs_prop ${gem_candidate_dir})
  569. endforeach()
  570. # Iterate over each gem candidate directories and read populate a directory property
  571. # containing the files to copy over
  572. get_property(gem_candidate_dirs GLOBAL PROPERTY global_gem_candidate_dirs_prop)
  573. foreach(gem_candidate_dir IN LISTS gem_candidate_dirs)
  574. get_property(filtered_asset_paths DIRECTORY ${gem_candidate_dir} PROPERTY directory_filtered_asset_paths)
  575. ly_get_last_path_segment_concat_sha256(${gem_candidate_dir} last_gem_root_path_segment)
  576. # Check if the gem is a subdirectory of the engine
  577. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${gem_candidate_dir} is_gem_subdirectory_of_engine)
  578. # At this point the filtered_assets_paths contains the list of all directories and files
  579. # that are non-excluded candidates that can be scanned for target directories and files
  580. # to copy over to the install layout
  581. foreach(filtered_asset_path IN LISTS filtered_asset_paths)
  582. if(IS_DIRECTORY ${filtered_asset_path})
  583. file(GLOB_RECURSE
  584. recurse_assets_paths
  585. LIST_DIRECTORIES TRUE
  586. "${filtered_asset_path}/*"
  587. )
  588. set(gem_file_paths ${recurse_assets_paths})
  589. # Make sure to prepend the current path iteration to the gem_dirs_path to filter
  590. set(gem_dir_paths ${filtered_asset_path} ${recurse_assets_paths})
  591. # Gather directories to copy over
  592. # Currently only the Assets, Registry and Config directories are copied over
  593. list(FILTER gem_dir_paths INCLUDE REGEX "/(Assets|Registry|Config|Editor/Scripts)$")
  594. set_property(DIRECTORY ${gem_candidate_dir} APPEND PROPERTY gems_assets_paths ${gem_dir_paths})
  595. else()
  596. set(gem_file_paths ${filtered_asset_path})
  597. endif()
  598. # Gather files to copy over
  599. # Currently only the gem.json file is copied over
  600. list(FILTER gem_file_paths INCLUDE REGEX "/(gem.json|preview.png)$")
  601. set_property(DIRECTORY ${gem_candidate_dir} APPEND PROPERTY gems_assets_paths "${gem_file_paths}")
  602. endforeach()
  603. # gem directories and files to install
  604. get_property(gems_assets_paths DIRECTORY ${gem_candidate_dir} PROPERTY gems_assets_paths)
  605. foreach(gem_absolute_path IN LISTS gems_assets_paths)
  606. if(is_gem_subdirectory_of_engine)
  607. cmake_path(RELATIVE_PATH gem_absolute_path BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE gem_install_dest_dir)
  608. else()
  609. # The gem resides outside of the LY_ROOT_FOLDER, so the destination is made relative to the
  610. # gem candidate directory and placed under the "External" directory"
  611. # directory
  612. cmake_path(RELATIVE_PATH gem_absolute_path BASE_DIRECTORY ${gem_candidate_dir} OUTPUT_VARIABLE gem_relative_path)
  613. unset(gem_install_dest_dir)
  614. cmake_path(APPEND gem_install_dest_dir "External" ${last_gem_root_path_segment} ${gem_relative_path})
  615. endif()
  616. cmake_path(GET gem_install_dest_dir PARENT_PATH gem_install_dest_dir)
  617. if (NOT gem_install_dest_dir)
  618. cmake_path(SET gem_install_dest_dir .)
  619. endif()
  620. if(IS_DIRECTORY ${gem_absolute_path})
  621. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  622. install(DIRECTORY "${gem_absolute_path}"
  623. DESTINATION ${gem_install_dest_dir}
  624. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  625. )
  626. install(CODE "endif()")
  627. elseif (EXISTS ${gem_absolute_path})
  628. install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)")
  629. install(FILES ${gem_absolute_path}
  630. DESTINATION ${gem_install_dest_dir}
  631. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  632. )
  633. install(CODE "endif()")
  634. endif()
  635. endforeach()
  636. endforeach()
  637. endfunction()
  638. #! ly_setup_subdirectory_create_alias: Replicates the call to the `ly_create_alias` function
  639. #! within the generated CMakeLists.txt in the same relative install layout directory
  640. function(ly_setup_subdirectory_create_alias absolute_target_source_dir output_script)
  641. # Replicate the create_alias() calls made in the SOURCE_DIR into the generated CMakeLists.txt
  642. string(JOIN "\n" create_alias_template
  643. "if(NOT TARGET @alias_name@)"
  644. " ly_create_alias(@create_alias_args@)"
  645. "endif()"
  646. "")
  647. unset(${output_script} PARENT_SCOPE)
  648. get_property(create_alias_args_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_CREATE_ALIAS_ARGUMENTS)
  649. foreach(create_alias_args IN LISTS create_alias_args_list)
  650. # Create a list out of the comma separated arguments and store it into the same variable
  651. string(REPLACE "," ";" create_alias_args ${create_alias_args})
  652. # The first argument of the create alias argument list is the ALIAS NAME so pop it from the list
  653. # It is used to protect against registering the same alias twice
  654. list(POP_FRONT create_alias_args alias_name)
  655. string(CONFIGURE "${create_alias_template}" create_alias_command @ONLY)
  656. string(APPEND create_alias_calls ${create_alias_command})
  657. endforeach()
  658. set(${output_script} ${create_alias_calls} PARENT_SCOPE)
  659. endfunction()
  660. #! ly_setup_subdirectory_set_gem_variant_to_load: Replicates the call to the `ly_set_gem_variant_to_load` function
  661. #! within the generated CMakeLists.txt in the same relative install layout directory
  662. function(ly_setup_subdirectory_set_gem_variant_to_load absolute_target_source_dir output_script)
  663. # Replicate the ly_set_gem_variant_to_load() calls made in the SOURCE_DIR for into the generated CMakeLists.txt
  664. set(set_gem_variant_args_template "ly_set_gem_variant_to_load(@set_gem_variant_args@)\n")
  665. unset(${output_script} PARENT_SCOPE)
  666. get_property(set_gem_variant_args_lists DIRECTORY ${absolute_target_source_dir} PROPERTY LY_SET_GEM_VARIANT_TO_LOAD_ARGUMENTS)
  667. foreach(set_gem_variant_args IN LISTS set_gem_variant_args_lists)
  668. string(CONFIGURE "${set_gem_variant_args_template}" set_gem_variant_to_load_command @ONLY)
  669. string(APPEND set_gem_variant_calls ${set_gem_variant_to_load_command})
  670. endforeach()
  671. set(${output_script} ${set_gem_variant_calls} PARENT_SCOPE)
  672. endfunction()
  673. #! ly_setup_subdirectory_enable_gems: Replicates the call to the `ly_enable_gems` function
  674. #! within the generated CMakeLists.txt in the same relative install layout directory
  675. function(ly_setup_subdirectory_enable_gems absolute_target_source_dir output_script)
  676. # Replicate the ly_set_gem_variant_to_load() calls made in the SOURCE_DIR into the generated CMakeLists.txt
  677. set(enable_gems_template "ly_enable_gems(@enable_gems_args@)\n")
  678. unset(${output_script} PARENT_SCOPE)
  679. get_property(enable_gems_args_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_ENABLE_GEMS_ARGUMENTS)
  680. foreach(enable_gems_args IN LISTS enable_gems_args_list)
  681. string(CONFIGURE "${enable_gems_template}" enable_gems_command @ONLY)
  682. string(APPEND enable_gems_calls ${enable_gems_command})
  683. endforeach()
  684. set(${output_script} ${enable_gems_calls} PARENT_SCOPE)
  685. endfunction()