Install_common.cmake 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  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. unset(normalized_external_build_dirs)
  11. foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS})
  12. cmake_path(ABSOLUTE_PATH external_dir BASE_DIRECTORY ${LY_ROOT_FOLDER} NORMALIZE)
  13. list(APPEND normalized_external_build_dirs ${external_dir})
  14. endforeach()
  15. set(LY_INSTALL_EXTERNAL_BUILD_DIRS ${normalized_external_build_dirs})
  16. set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise
  17. define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET
  18. BRIEF_DOCS "Defines if a \"RUN\" targets should be created when installing this target Gem"
  19. FULL_DOCS [[
  20. Property which is set on targets that should generate a "RUN"
  21. target when installed. This \"RUN\" target helps to run the
  22. binary from the installed location directly from the IDE.
  23. ]]
  24. )
  25. # We can have elements being installed under the following components:
  26. # - Core (required for all) (default)
  27. # - Default
  28. # - Default_$<CONFIG>
  29. # - Monolithic
  30. # - Monolithic_$<CONFIG>
  31. # Debug/Monolithic are build permutations, so for a CMake run, it can only generate
  32. # one of the permutations. Each build permutation can generate only one cmake_install.cmake.
  33. # Each build permutation will generate the same elements in Core.
  34. # CPack is able to put the two together by taking Core from one permutation and then taking
  35. # each permutation.
  36. ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CORE)
  37. if(LY_MONOLITHIC_GAME)
  38. set(LY_BUILD_PERMUTATION Monolithic)
  39. else()
  40. set(LY_BUILD_PERMUTATION Default)
  41. endif()
  42. string(TOUPPER ${LY_BUILD_PERMUTATION} LY_INSTALL_PERMUTATION_COMPONENT)
  43. cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory)
  44. cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory)
  45. # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target
  46. cmake_path(RELATIVE_PATH CMAKE_ARCHIVE_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE archive_output_directory)
  47. cmake_path(APPEND archive_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
  48. cmake_path(APPEND library_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
  49. cmake_path(APPEND runtime_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
  50. #! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target
  51. function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_target_source_dir)
  52. # De-alias target name
  53. ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME)
  54. # Get the target source directory relative to the LY root folder
  55. ly_get_engine_relative_source_dir(${absolute_target_source_dir} relative_target_source_dir)
  56. # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that
  57. # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the
  58. # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory.
  59. # Instead, we install them with install(DIRECTORY)
  60. get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES)
  61. if (include_directories)
  62. unset(public_headers)
  63. foreach(include_directory ${include_directories})
  64. string(GENEX_STRIP ${include_directory} include_genex_expr)
  65. if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions
  66. unset(current_public_headers)
  67. cmake_path(NORMAL_PATH include_directory)
  68. string(REGEX REPLACE "/$" "" include_directory "${include_directory}")
  69. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${absolute_target_source_dir} NORMALIZE include_directory_child_of_o3de_root)
  70. if(NOT include_directory_child_of_o3de_root)
  71. # Include directory is outside of the O3DE root folder ${LY_ROOT_FOLDER}.
  72. # For the INSTALL step, the O3DE root folder must be a prefix of all include directories.
  73. continue()
  74. endif()
  75. # For some cases (e.g. codegen) we generate headers that end up in the BUILD_DIR. Since the BUILD_DIR
  76. # is per-permutation, we need to install such headers per permutation. For the other cases, we can install
  77. # under the default component since they are shared across permutations/configs.
  78. cmake_path(IS_PREFIX CMAKE_BINARY_DIR ${include_directory} NORMALIZE include_directory_child_of_build)
  79. # In order to combine profile and release monolithic, we use the CORE component
  80. # because CPack will fail if it finds duplicated content in CORE and DEFAULT/MONOLITHIC
  81. set(include_directory_component ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
  82. unset(rel_include_dir)
  83. if(include_directory_child_of_build)
  84. # We need to use the path relative to the binary folder otherwise you will get an invalid
  85. # relative path if the build folder is outside the engine root.
  86. cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE rel_include_dir)
  87. else()
  88. cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE rel_include_dir)
  89. endif()
  90. cmake_path(APPEND rel_include_dir "..")
  91. cmake_path(NORMAL_PATH rel_include_dir OUTPUT_VARIABLE destination_dir)
  92. ly_install(DIRECTORY ${include_directory}
  93. DESTINATION ${destination_dir}
  94. COMPONENT ${include_directory_component}
  95. FILES_MATCHING
  96. PATTERN *.h
  97. PATTERN *.hpp
  98. PATTERN *.inl
  99. PATTERN *.hxx
  100. PATTERN *.jinja # LyAutoGen files
  101. )
  102. endif()
  103. endforeach()
  104. endif()
  105. get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY)
  106. if(target_runtime_output_directory)
  107. cmake_path(RELATIVE_PATH target_runtime_output_directory BASE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_runtime_output_subdirectory)
  108. endif()
  109. get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY)
  110. if(target_library_output_directory)
  111. cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory)
  112. endif()
  113. if(COMMAND ly_setup_target_install_targets_override)
  114. # Mac needs special handling because of a cmake issue
  115. ly_setup_target_install_targets_override(TARGET ${TARGET_NAME}
  116. ARCHIVE_DIR ${archive_output_directory}
  117. LIBRARY_DIR ${library_output_directory}
  118. RUNTIME_DIR ${runtime_output_directory}
  119. LIBRARY_SUBDIR ${target_library_output_subdirectory}
  120. RUNTIME_SUBDIR ${target_runtime_output_subdirectory}
  121. )
  122. else()
  123. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  124. string(TOUPPER ${conf} UCONF)
  125. ly_install(TARGETS ${TARGET_NAME}
  126. ARCHIVE
  127. DESTINATION ${archive_output_directory}
  128. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  129. CONFIGURATIONS ${conf}
  130. LIBRARY
  131. DESTINATION ${library_output_directory}/${target_library_output_subdirectory}
  132. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  133. CONFIGURATIONS ${conf}
  134. RUNTIME
  135. DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory}
  136. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  137. CONFIGURATIONS ${conf}
  138. )
  139. endforeach()
  140. endif()
  141. # CMakeLists.txt related files
  142. string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME})
  143. if(match)
  144. set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}")
  145. set(NAME_PLACEHOLDER ${CMAKE_MATCH_2})
  146. else()
  147. set(NAMESPACE_PLACEHOLDER "")
  148. set(NAME_PLACEHOLDER ${TARGET_NAME})
  149. endif()
  150. get_target_property(should_create_helper ${TARGET_NAME} LY_INSTALL_GENERATE_RUN_TARGET)
  151. if(should_create_helper)
  152. set(NAME_PLACEHOLDER ${NAME_PLACEHOLDER}.Imported)
  153. endif()
  154. set(TARGET_TYPE_PLACEHOLDER "")
  155. get_target_property(target_type ${TARGET_NAME} TYPE)
  156. # Remove the _LIBRARY since we dont need to pass that to ly_add_targets
  157. string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type})
  158. # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead
  159. string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER})
  160. # In non-monolithic mode, gem targets are MODULE libraries, In monolithic mode gem targets are STATIC libraries
  161. set(GEM_LIBRARY_TYPES "MODULE" "STATIC")
  162. if(TARGET_TYPE_PLACEHOLDER IN_LIST GEM_LIBRARY_TYPES)
  163. get_target_property(gem_module ${TARGET_NAME} GEM_MODULE)
  164. if(gem_module)
  165. string(PREPEND TARGET_TYPE_PLACEHOLDER "GEM_")
  166. endif()
  167. endif()
  168. string(REPEAT " " 12 PLACEHOLDER_INDENT)
  169. get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS)
  170. if(COMPILE_DEFINITIONS_PLACEHOLDER)
  171. set(COMPILE_DEFINITIONS_PLACEHOLDER "${PLACEHOLDER_INDENT}${COMPILE_DEFINITIONS_PLACEHOLDER}")
  172. list(JOIN COMPILE_DEFINITIONS_PLACEHOLDER "\n${PLACEHOLDER_INDENT}" COMPILE_DEFINITIONS_PLACEHOLDER)
  173. else()
  174. unset(COMPILE_DEFINITIONS_PLACEHOLDER)
  175. endif()
  176. # Includes need additional processing to add the install root
  177. foreach(include IN LISTS include_directories)
  178. string(GENEX_STRIP ${include} include_genex_expr)
  179. if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions
  180. # Make the include path relative to the source dir where the target will be declared
  181. cmake_path(IS_PREFIX CMAKE_BINARY_DIR ${include} NORMALIZE include_directory_child_of_build)
  182. if(include_directory_child_of_build)
  183. # Some autogen files are placed in the build folder so remove the build folder prefix
  184. # and use it to calculate the relative path
  185. cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE rel_include)
  186. cmake_path(SET base_path ${LY_ROOT_FOLDER})
  187. cmake_path(APPEND base_path ${rel_include} OUTPUT_VARIABLE absolute_include)
  188. cmake_path(RELATIVE_PATH absolute_include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include)
  189. else()
  190. cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include)
  191. endif()
  192. list(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${target_include}")
  193. endif()
  194. endforeach()
  195. list(JOIN INCLUDE_DIRECTORIES_PLACEHOLDER "\n" INCLUDE_DIRECTORIES_PLACEHOLDER)
  196. string(REPEAT " " 12 PLACEHOLDER_INDENT)
  197. get_property(interface_build_dependencies_props TARGET ${TARGET_NAME} PROPERTY LY_DELAYED_LINK)
  198. unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
  199. # We can have private build dependencies that contains direct or indirect runtime dependencies.
  200. # Since imported targets cannot contain build dependencies, we need another way to propagate the runtime dependencies.
  201. # We dont want to put such dependencies in the interface because a user can mistakenly use a symbol that is not available
  202. # when using the engine from source (and that the author of the target didn't want to set public).
  203. # To overcome this, we will actually expose the private build dependencies as runtime dependencies. Our runtime dependency
  204. # algorithm will walk recursively also through static libraries and will only copy binaries to the output.
  205. unset(RUNTIME_DEPENDENCIES_PLACEHOLDER)
  206. if(interface_build_dependencies_props)
  207. cmake_parse_arguments(build_deps "" "" "PRIVATE;PUBLIC;INTERFACE" ${interface_build_dependencies_props})
  208. # Interface and public dependencies should always be exposed
  209. set(build_deps_target ${build_deps_INTERFACE})
  210. if(build_deps_PUBLIC)
  211. set(build_deps_target "${build_deps_target};${build_deps_PUBLIC}")
  212. endif()
  213. # Private dependencies should only be exposed if it is a static library, since in those cases, link
  214. # dependencies are transfered to the downstream dependencies
  215. if("${target_type}" STREQUAL "STATIC_LIBRARY")
  216. set(build_deps_target "${build_deps_target};${build_deps_PRIVATE}")
  217. endif()
  218. # But we will also pass the private dependencies as runtime dependencies (as long as they are targets, note the comment above)
  219. foreach(build_dep_private IN LISTS build_deps_PRIVATE)
  220. if(TARGET ${build_dep_private})
  221. list(APPEND RUNTIME_DEPENDENCIES_PLACEHOLDER "${build_dep_private}")
  222. endif()
  223. endforeach()
  224. foreach(build_dependency IN LISTS build_deps_target)
  225. # Skip wrapping produced when targets are not created in the same directory
  226. if(build_dependency)
  227. list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${build_dependency}")
  228. endif()
  229. endforeach()
  230. endif()
  231. list(JOIN INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER)
  232. string(REPEAT " " 8 PLACEHOLDER_INDENT)
  233. get_target_property(manually_added_dependencies ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES)
  234. if(manually_added_dependencies) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found
  235. list(APPEND RUNTIME_DEPENDENCIES_PLACEHOLDER ${manually_added_dependencies})
  236. endif()
  237. if(RUNTIME_DEPENDENCIES_PLACEHOLDER)
  238. set(RUNTIME_DEPENDENCIES_PLACEHOLDER "${PLACEHOLDER_INDENT}${RUNTIME_DEPENDENCIES_PLACEHOLDER}")
  239. list(JOIN RUNTIME_DEPENDENCIES_PLACEHOLDER "\n${PLACEHOLDER_INDENT}" RUNTIME_DEPENDENCIES_PLACEHOLDER)
  240. else()
  241. unset(RUNTIME_DEPENDENCIES_PLACEHOLDER)
  242. endif()
  243. string(REPEAT " " 8 PLACEHOLDER_INDENT)
  244. # If a target has an LY_PROJECT_NAME property, forward that property to new target
  245. get_target_property(target_project_association ${TARGET_NAME} LY_PROJECT_NAME)
  246. if(target_project_association)
  247. list(APPEND TARGET_PROPERTIES_PLACEHOLDER "${PLACEHOLDER_INDENT}LY_PROJECT_NAME ${target_project_association}")
  248. endif()
  249. # If the target is an executable/application, add a custom target so we can debug the target in project-centric workflow
  250. if(should_create_helper)
  251. string(REPLACE ".Imported" "" RUN_TARGET_NAME ${NAME_PLACEHOLDER})
  252. set(target_types_with_debugging_helper EXECUTABLE APPLICATION)
  253. if(NOT target_type IN_LIST target_types_with_debugging_helper)
  254. message(FATAL_ERROR "Cannot generate a RUN target for ${TARGET_NAME}, type is ${target_type}")
  255. endif()
  256. set(TARGET_RUN_HELPER
  257. "add_custom_target(${RUN_TARGET_NAME})
  258. set_target_properties(${RUN_TARGET_NAME} PROPERTIES
  259. FOLDER \"O3DE_SDK\"
  260. VS_DEBUGGER_COMMAND \$<GENEX_EVAL:\$<TARGET_PROPERTY:${NAME_PLACEHOLDER},IMPORTED_LOCATION>>
  261. VS_DEBUGGER_COMMAND_ARGUMENTS \"--project-path=\${LY_DEFAULT_PROJECT_PATH}\"
  262. )
  263. set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGETS ${RUN_TARGET_NAME})
  264. "
  265. )
  266. endif()
  267. # Config files
  268. set(target_file_contents "# Generated by O3DE install\n\n")
  269. if(NOT target_type STREQUAL INTERFACE_LIBRARY)
  270. unset(target_location)
  271. set(runtime_types EXECUTABLE APPLICATION)
  272. if(target_type IN_LIST runtime_types)
  273. set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${target_runtime_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
  274. elseif(target_type STREQUAL MODULE_LIBRARY)
  275. set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
  276. elseif(target_type STREQUAL SHARED_LIBRARY)
  277. string(APPEND target_file_contents
  278. "set_property(TARGET ${NAME_PLACEHOLDER}
  279. APPEND_STRING PROPERTY IMPORTED_IMPLIB
  280. $<$<CONFIG:$<CONFIG>$<ANGLE-R>:\"\${LY_ROOT_FOLDER}/${archive_output_directory}/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"$<ANGLE-R>
  281. )
  282. ")
  283. string(APPEND target_file_contents
  284. "set_property(TARGET ${NAME_PLACEHOLDER}
  285. PROPERTY IMPORTED_IMPLIB_$<UPPER_CASE:$<CONFIG>>
  286. \"\${LY_ROOT_FOLDER}/${archive_output_directory}/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>\"
  287. )
  288. ")
  289. set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${target_library_output_subdirectory}/$<TARGET_FILE_NAME:${TARGET_NAME}>")
  290. elseif(target_type STREQUAL STATIC_LIBRARY) # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY
  291. set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/$<TARGET_LINKER_FILE_NAME:${TARGET_NAME}>")
  292. else() # OBJECT_LIBRARY has no output target
  293. endif()
  294. if(target_location)
  295. string(APPEND target_file_contents
  296. "set_property(TARGET ${NAME_PLACEHOLDER}
  297. APPEND_STRING PROPERTY IMPORTED_LOCATION
  298. $<$<CONFIG:$<CONFIG>$<ANGLE-R>:${target_location}$<ANGLE-R>
  299. )
  300. set_property(TARGET ${NAME_PLACEHOLDER}
  301. PROPERTY IMPORTED_LOCATION_$<UPPER_CASE:$<CONFIG>>
  302. ${target_location}
  303. )
  304. ")
  305. endif()
  306. endif()
  307. set(target_install_source_dir ${CMAKE_CURRENT_BINARY_DIR}/install/${relative_target_source_dir})
  308. file(GENERATE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_$<CONFIG>.cmake" CONTENT "${target_file_contents}")
  309. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  310. string(TOUPPER ${conf} UCONF)
  311. ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake"
  312. DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  313. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  314. CONFIGURATIONS ${conf}
  315. )
  316. endforeach()
  317. # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target
  318. ly_file_read(${LY_ROOT_FOLDER}/cmake/install/InstalledTarget.in target_cmakelists_template)
  319. string(CONFIGURE ${target_cmakelists_template} output_cmakelists_data @ONLY)
  320. set(${OUTPUT_CONFIGURED_TARGET} ${output_cmakelists_data} PARENT_SCOPE)
  321. endfunction()
  322. #! ly_setup_subdirectories: setups all targets on a per directory basis
  323. function(ly_setup_subdirectories)
  324. get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
  325. foreach(target_subdirectory IN LISTS all_subdirectories)
  326. ly_setup_subdirectory(${target_subdirectory})
  327. endforeach()
  328. endfunction()
  329. #! ly_setup_3p_target: Export enough data such that the script-only mode knows about the runtime dependencies
  330. #! for the given target. This function returns a string which is a setup function that can be called
  331. #! in script only mode to create a fake target for the 3p library that just includes its copy dependencies.
  332. function(ly_setup_3p_target OUTVAR_GENERATED_DATA_FILENAME OUTVAR_FILE_NAME_TO_GENERATE ALIAS_TARGET_NAME)
  333. ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME)
  334. o3de_get_dependencies_for_target(
  335. TARGET "${TARGET_NAME}"
  336. COPY_DEPENDENCIES_VAR target_copy_dependencies
  337. TARGET_DEPENDENCIES_VAR target_target_dependencies
  338. )
  339. # note that we want to actually create and register the aliased target name
  340. # but get the data from the de-aliased target. So except for the call above
  341. # we use the aliased target name.
  342. string(REPLACE "::" "__" CLEAN_TARGET_NAME "${ALIAS_TARGET_NAME}")
  343. unset(copy_dependencies_target_rel_path)
  344. unset(copy_dependencies_source_file_path)
  345. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  346. unset(copy_dependencies_${conf})
  347. endforeach()
  348. foreach(dependency_for_target IN LISTS target_target_dependencies)
  349. if (NOT TARGET ${dependency_for_target})
  350. # Sometimes, things set actual shared libraries as a target dependency instead of a copy dependency.
  351. list(APPEND target_copy_dependencies "${dependency_for_target}\n")
  352. endif()
  353. endforeach()
  354. # note that the copy dependencies are actually in pairs newline delimited, so
  355. # file_to_copy_a\nwhere_to_copy_a;file_to_copy_b\nwhere_to_copy_b;...
  356. foreach(copy_dependency IN LISTS target_copy_dependencies)
  357. string(REPLACE "\n" ";" copy_dep_pair "${copy_dependency}")
  358. list(POP_FRONT copy_dep_pair source_filepath destination_relpath)
  359. list(APPEND copy_dependencies_source_file_path "${source_filepath}")
  360. # a quirk of list append is that if you give it an empty element, it does nothing.
  361. # use dummy element (0) to indicate its an empty path
  362. if (NOT destination_relpath)
  363. set(destination_relpath "0")
  364. endif()
  365. list(APPEND copy_dependencies_target_rel_path "${destination_relpath}")
  366. endforeach()
  367. # sanity check
  368. if (copy_dependencies_source_file_path OR copy_dependencies_target_rel_path)
  369. list(LENGTH copy_dependencies_source_file_path source_list_length)
  370. list(LENGTH copy_dependencies_target_rel_path relpath_list_lenth)
  371. if (NOT source_list_length EQUAL relpath_list_lenth)
  372. message(FATAL_ERROR "Programmer error - for target ${ALIAS_TARGET_NAME}, lists are supposed to be same length, but\n\
  373. ${source_list_length} source and ${relpath_list_lenth} relpath\n\
  374. source:'${copy_dependencies_source_file_path}'\n\
  375. relpath: '${copy_dependencies_target_rel_path}'")
  376. endif()
  377. endif()
  378. unset(${OUTVAR_GENERATED_DATA_FILENAME} PARENT_SCOPE)
  379. # the absolute source paths of files to copy can have generator expressions that are per-config.
  380. # use file(GENERATE ...) to evaluate the genexes, by writing it as a build file
  381. # since GENERATE only happens during generate step, this is as far as we can go during
  382. # configure. It will be up to a build step to read these generated files back and
  383. # do a final transform that removes things like absolute paths.
  384. # note that we generate a file for every 3p target, as they must exist.
  385. set(generate_content "set(target_name ${ALIAS_TARGET_NAME})\n")
  386. if (copy_dependencies_source_file_path)
  387. string(APPEND generate_content "set(copy_dependencies_source_file_path \"${copy_dependencies_source_file_path}\")\n")
  388. string(APPEND generate_content "set(copy_dependencies_target_rel_path \"${copy_dependencies_target_rel_path}\")\n")
  389. endif()
  390. file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/install/$<CONFIG>/${PAL_PLATFORM_NAME}/${CLEAN_TARGET_NAME}.cmake"
  391. CONTENT "${generate_content}")
  392. set(${OUTVAR_GENERATED_DATA_FILENAME} "${CMAKE_BINARY_DIR}/install/$<CONFIG>/${PAL_PLATFORM_NAME}/${CLEAN_TARGET_NAME}.cmake" PARENT_SCOPE)
  393. set(${OUTVAR_FILE_NAME_TO_GENERATE} ${CLEAN_TARGET_NAME} PARENT_SCOPE)
  394. endfunction()
  395. # In "Script only mode", the 3p libraries are not downloaded at all.
  396. # But some of them (not all) have extraneous .so or .dll files that need to be deployed
  397. # into the final runtime package if you intend to ship a script-only runtime.
  398. # This function exports a file that is used only in script-only mode to supply that list
  399. # of extra DLLs to copy along with the game.
  400. function(ly_setup_3p_dependencies)
  401. # 3p dependency generation is only relevant to installer builds, which is expected to happen only if no project is being built
  402. # prevent this code from running in non-instlaler-builds, otherwise it will try to hang these commands off a non-existant generic
  403. # game launcher target (which itself is also only relevant to installer builds for script-only mode.)
  404. if (LY_PROJECTS)
  405. return()
  406. endif()
  407. unset(list_of_files_to_process)
  408. unset(expected_output_files)
  409. set(final_3p_output_dir "${CMAKE_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}")
  410. get_property(o3de_all_3rdparty_targets GLOBAL PROPERTY O3DE_ALL_3RDPARTY_TARGETS)
  411. # call the ly_setup_3p_target for each 3p target. It will create a GENERATE step
  412. # that will output a file, and also return the file name of the generated file.
  413. foreach(target_3p IN LISTS o3de_all_3rdparty_targets)
  414. ly_setup_3p_target(file_to_process output_filename ${target_3p})
  415. if (file_to_process)
  416. list(APPEND list_of_files_to_process ${file_to_process})
  417. list(APPEND expected_output_files ${final_3p_output_dir}/${output_filename}.cmake)
  418. endif()
  419. endforeach()
  420. # note that generate only occurs during the generate step. The above file will not be available until the build step
  421. # so a finalization build step needs to run a script to finalize it.
  422. if (list_of_files_to_process)
  423. add_custom_command(
  424. COMMAND ${CMAKE_COMMAND} -P
  425. "${LY_ROOT_FOLDER}/cmake/3rdParty/script-only-mode/PostProcessScriptOnlyMappings.cmake" # Script to run
  426. "${final_3p_output_dir}" # the output file to make
  427. ${list_of_files_to_process}
  428. OUTPUT ${expected_output_files}
  429. COMMENT "Updating script-only mode 3rd Party library mappings..."
  430. DEPENDS ${list_of_files_to_process}
  431. "${LY_ROOT_FOLDER}/cmake/3rdParty/script-only-mode/PostProcessScriptOnlyMappings.cmake"
  432. VERBATIM
  433. )
  434. # make a custom target that depends on the above output file.
  435. add_custom_target(GenerateScriptOnlyMappings DEPENDS ${expected_output_files})
  436. # make it so that at least one real target that actually gets built depends on the above target.
  437. # or else cmake won't evaluate it since nothing hangs off it.
  438. add_dependencies(O3DE.GameLauncher GenerateScriptOnlyMappings)
  439. ly_install(FILES ${expected_output_files}
  440. DESTINATION "cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}"
  441. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT})
  442. endif()
  443. endfunction()
  444. #! ly_setup_subdirectory: setup all targets in the subdirectory
  445. function(ly_setup_subdirectory absolute_target_source_dir)
  446. ly_get_engine_relative_source_dir(${absolute_target_source_dir} relative_target_source_dir)
  447. # The builtin BUILDSYSTEM_TARGETS property isn't being used here as that returns the de-alised
  448. # TARGET and we need the alias namespace for recreating the CMakeLists.txt in the install layout
  449. get_property(ALIAS_TARGETS_NAME DIRECTORY ${absolute_target_source_dir} PROPERTY LY_DIRECTORY_TARGETS)
  450. foreach(ALIAS_TARGET_NAME IN LISTS ALIAS_TARGETS_NAME)
  451. ly_setup_target(configured_target ${ALIAS_TARGET_NAME} ${absolute_target_source_dir})
  452. string(APPEND all_configured_targets "${configured_target}")
  453. endforeach()
  454. # Initialize the target install source directory to path underneath the current binary directory
  455. set(target_install_source_dir "${CMAKE_CURRENT_BINARY_DIR}/install/${relative_target_source_dir}")
  456. ly_file_read(${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment)
  457. # 1. Create the base CMakeLists.txt that will just include a cmake file per platform
  458. string(CONFIGURE [[
  459. @cmake_copyright_comment@
  460. if(LY_MONOLITHIC_GAME)
  461. include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake OPTIONAL)
  462. else()
  463. include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  464. endif()
  465. ]] subdirectory_cmakelist_content @ONLY)
  466. # Store off the generated CMakeLists.txt into a DIRECTORY property based on the subdirectory being visited
  467. # In the ly_setup_assets() function, it generates an empty CMakeLists.txt into the gem root directory
  468. # if one does not exist by checking if this property is set
  469. set_property(DIRECTORY "${absolute_target_source_dir}" APPEND_STRING PROPERTY O3DE_SUBDIRECTORY_CMAKELIST_CONTENT "${subdirectory_cmakelist_content}")
  470. file(WRITE "${target_install_source_dir}/CMakeLists.txt" "${subdirectory_cmakelist_content}")
  471. ly_install(FILES "${target_install_source_dir}/CMakeLists.txt"
  472. DESTINATION ${relative_target_source_dir}
  473. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  474. )
  475. # 2. For this platform file, create a Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake file
  476. # that will include different configuration permutations (e.g. monolithic vs non-monolithic)
  477. file(CONFIGURE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" CONTENT [[
  478. @cmake_copyright_comment@
  479. if(LY_MONOLITHIC_GAME)
  480. include(Platform/${PAL_PLATFORM_NAME}/Monolithic/permutation.cmake OPTIONAL)
  481. else()
  482. include(Platform/${PAL_PLATFORM_NAME}/Default/permutation.cmake)
  483. endif()
  484. ]])
  485. ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake"
  486. DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}
  487. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  488. )
  489. # 3. For this configuration permutation, generate a Platform/${PAL_PLATFORM_NAME}/${permutation}/permutation.cmake
  490. # that will declare the target and configure it
  491. ly_setup_subdirectory_create_alias("${absolute_target_source_dir}" CREATE_ALIASES_PLACEHOLDER)
  492. ly_setup_subdirectory_set_gem_variant_to_load("${absolute_target_source_dir}" GEM_VARIANT_TO_LOAD_PLACEHOLDER)
  493. ly_setup_add_variant_dependencies_for_gem_dependencies("${absolute_target_source_dir}" O3DE_ADD_VARIANT_DEPS_FOR_GEM_DEPS)
  494. ly_setup_subdirectory_enable_gems("${absolute_target_source_dir}" ENABLE_GEMS_PLACEHOLDER)
  495. ly_setup_subdirectory_install_code("${absolute_target_source_dir}" O3DE_INSTALL_CODE_PLACEHOLDER)
  496. # Write out all the aggregated ly_add_target function calls and the final ly_create_alias() calls to the target CMakeLists.txt
  497. file(WRITE "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake"
  498. "${cmake_copyright_comment}"
  499. "${O3DE_INSTALL_CODE_PLACEHOLDER}"
  500. "${all_configured_targets}"
  501. "\n"
  502. "${CREATE_ALIASES_PLACEHOLDER}"
  503. "${GEM_VARIANT_TO_LOAD_PLACEHOLDER}"
  504. "${O3DE_ADD_VARIANT_DEPS_FOR_GEM_DEPS}"
  505. "${ENABLE_GEMS_PLACEHOLDER}"
  506. )
  507. ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake"
  508. DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  509. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}
  510. )
  511. endfunction()
  512. #! ly_setup_cmake_install: install the "cmake" folder
  513. function(ly_setup_cmake_install)
  514. ly_install(DIRECTORY "${LY_ROOT_FOLDER}/cmake"
  515. DESTINATION .
  516. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  517. PATTERN "__pycache__" EXCLUDE
  518. PATTERN "Findo3de.cmake" EXCLUDE
  519. PATTERN "cmake/ConfigurationTypes.cmake" EXCLUDE
  520. REGEX "3rdParty/Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE
  521. )
  522. # Connect configuration types
  523. ly_install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake"
  524. DESTINATION cmake
  525. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  526. )
  527. # generate each ConfigurationType_<CONFIG>.cmake file and install it under that configuration
  528. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  529. string(TOUPPER ${conf} UCONF)
  530. configure_file("${LY_ROOT_FOLDER}/cmake/install/ConfigurationType_config.cmake.in"
  531. "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake"
  532. @ONLY
  533. )
  534. ly_install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake"
  535. DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  536. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  537. CONFIGURATIONS ${conf}
  538. )
  539. endforeach()
  540. # Transform the list of all external subdirectories used by the engine + projects into a json array
  541. set(indent " ")
  542. get_external_subdirectories_in_use(external_subdirs)
  543. foreach(external_subdir ${external_subdirs})
  544. # If an external subdirectory is not a subdirectory of the engine root, then
  545. # prepend "External" to its subdirectory root
  546. ly_get_root_subdirectory_which_is_parent(${external_subdir} root_subdir_of_external_subdir)
  547. cmake_path(RELATIVE_PATH external_subdir BASE_DIRECTORY ${root_subdir_of_external_subdir} OUTPUT_VARIABLE engine_rel_external_subdir)
  548. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${external_subdir} is_subdirectory_of_engine)
  549. if(NOT is_subdirectory_of_engine)
  550. cmake_path(GET root_subdir_of_external_subdir FILENAME root_subdir_dirname)
  551. set(relative_subdir ${engine_rel_external_subdir})
  552. unset(engine_rel_external_subdir)
  553. cmake_path(APPEND engine_rel_external_subdir "External" ${root_subdir_dirname} ${relative_subdir})
  554. endif()
  555. set(quoted_engine_rel_external_subdir "\"${engine_rel_external_subdir}\"")
  556. if (quoted_engine_rel_external_subdir IN_LIST relative_external_subdirs)
  557. message(WARNING "An external subdirectory \"${external_subdir}\" has been found twice when generating the engine.json for the install layout")
  558. else()
  559. list(APPEND relative_external_subdirs "\"${engine_rel_external_subdir}\"")
  560. endif()
  561. endforeach()
  562. # Sort the external subdirectories before joining them with commas
  563. list(SORT relative_external_subdirs CASE INSENSITIVE)
  564. list(JOIN relative_external_subdirs ",\n${indent}" O3DE_INSTALL_EXTERNAL_SUBDIRS)
  565. # Use the cache list of "gem_names" from the engine.json to populate
  566. # the generated engine.json file
  567. # The O3DE_INSTALL_ENGINE_GEMS is the configure placeholder that needs to be set
  568. # at the end
  569. get_property(active_engine_gems GLOBAL PROPERTY "O3DE_EXPLICIT_ACTIVE_GEMS_ENGINE")
  570. if (active_engine_gems)
  571. foreach(active_engine_gem IN LISTS active_engine_gems)
  572. list(APPEND quoted_active_engine_gems "\"${active_engine_gem}\"")
  573. endforeach()
  574. list(SORT quoted_active_engine_gems CASE INSENSITIVE)
  575. list(JOIN quoted_active_engine_gems ",\n${indent}" O3DE_INSTALL_ENGINE_GEMS)
  576. endif()
  577. # Read the "templates" key from the source engine.json
  578. o3de_read_json_array(engine_templates ${LY_ROOT_FOLDER}/engine.json "templates")
  579. if(engine_templates)
  580. foreach(template_path IN LISTS engine_templates)
  581. list(APPEND relative_templates "\"${template_path}\"")
  582. endforeach()
  583. list(SORT relative_templates CASE INSENSITIVE)
  584. list(JOIN relative_templates ",\n${indent}" O3DE_INSTALL_TEMPLATES)
  585. endif()
  586. # Read the "repos" key from the source engine.json
  587. o3de_read_json_array(engine_repos ${LY_ROOT_FOLDER}/engine.json "repos")
  588. if(engine_repos)
  589. foreach(repo_uri ${engine_repos})
  590. list(APPEND repos "\"${repo_uri}\"")
  591. endforeach()
  592. list(SORT repos CASE INSENSITIVE)
  593. list(JOIN repos ",\n${indent}" O3DE_INSTALL_REPOS)
  594. endif()
  595. # Read the "api_versions" key from the source engine.json
  596. o3de_read_json_key(O3DE_INSTALL_API_VERSIONS ${LY_ROOT_FOLDER}/engine.json "api_versions")
  597. configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY)
  598. ly_install(FILES
  599. "${LY_ROOT_FOLDER}/CMakeLists.txt"
  600. "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json"
  601. DESTINATION .
  602. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  603. )
  604. # Collect all Find files that were added with ly_add_external_target_path
  605. unset(additional_find_files)
  606. unset(additional_platform_files)
  607. get_property(additional_module_paths GLOBAL PROPERTY LY_ADDITIONAL_MODULE_PATH)
  608. foreach(additional_module_path ${additional_module_paths})
  609. unset(find_files)
  610. file(GLOB find_files "${additional_module_path}/Find*.cmake")
  611. list(APPEND additional_find_files "${find_files}")
  612. foreach(find_file ${find_files})
  613. # also copy the Platform/<current_platform> to the destination
  614. cmake_path(GET find_file PARENT_PATH find_file_parent)
  615. unset(plat_files)
  616. file(GLOB plat_files "${find_file_parent}/Platform/${PAL_PLATFORM_NAME}/*.cmake")
  617. list(APPEND additional_platform_files "${plat_files}")
  618. endforeach()
  619. endforeach()
  620. ly_install(FILES ${additional_find_files}
  621. DESTINATION cmake/3rdParty
  622. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  623. )
  624. ly_install(FILES ${additional_platform_files}
  625. DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}
  626. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  627. )
  628. # Findo3de.cmake file: we generate a different Findo3de.cmake file than the one we have in the source dir.
  629. configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY)
  630. ly_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake"
  631. DESTINATION cmake
  632. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  633. )
  634. unset(find_subdirectories)
  635. # Add to find_subdirectories all directories in which ly_add_target were called in
  636. get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
  637. foreach(target_subdirectory IN LISTS all_subdirectories)
  638. # If the subdirectory is an external_subdirectory, then it is being added in the engine.json file
  639. # Therefore it is not added to the o3de_subdirectories_<Platform>.cmake file to avoid
  640. # invoking add_subdirectory twice
  641. get_property(is_external_subdir GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${target_subdirectory}" SET)
  642. if(is_external_subdir)
  643. continue()
  644. endif()
  645. ly_get_root_subdirectory_which_is_parent(${target_subdirectory} root_subdir_of_target)
  646. cmake_path(RELATIVE_PATH target_subdirectory BASE_DIRECTORY ${root_subdir_of_target} OUTPUT_VARIABLE relative_target_subdirectory)
  647. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${target_subdirectory} is_subdirectory_of_engine)
  648. if(NOT is_subdirectory_of_engine)
  649. cmake_path(GET root_subdir_of_target FILENAME root_subdir_dirname)
  650. set(relative_subdir ${relative_target_subdirectory})
  651. unset(relative_target_subdirectory)
  652. cmake_path(APPEND relative_target_subdirectory "External" ${root_subdir_dirname} ${relative_subdir})
  653. endif()
  654. string(APPEND find_subdirectories "add_subdirectory(${relative_target_subdirectory})\n")
  655. endforeach()
  656. set(permutation_find_subdirectories ${CMAKE_CURRENT_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  657. file(GENERATE OUTPUT ${permutation_find_subdirectories}
  658. CONTENT
  659. "# Generated by O3DE install\n
  660. ${find_subdirectories}
  661. "
  662. )
  663. ly_install(FILES "${permutation_find_subdirectories}"
  664. DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  665. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}
  666. )
  667. set(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}${LY_ARCHITECTURE_NAME_EXTENSION}.cmake)
  668. file(GENERATE OUTPUT ${pal_builtin_file}
  669. CONTENT
  670. "# Generated by O3DE install\n
  671. if(LY_MONOLITHIC_GAME)
  672. include(cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/Monolithic/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}${LY_ARCHITECTURE_NAME_EXTENSION}.cmake)
  673. else()
  674. include(cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/Default/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}${LY_ARCHITECTURE_NAME_EXTENSION}.cmake)
  675. endif()
  676. "
  677. )
  678. ly_install(FILES "${pal_builtin_file}"
  679. DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}
  680. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  681. )
  682. # ${LY_BUILD_PERMUTATION}/BuiltInPackage_<platform>.cmake: since associations could happen in any cmake file across the engine. We collect
  683. # all the associations in ly_associate_package and then generate them into BuiltInPackages_<platform>.cmake. This will consolidate all
  684. # associations in one file
  685. # Associations are sensitive to platform and build permutation, so we make different files for each.
  686. get_property(all_package_names GLOBAL PROPERTY LY_PACKAGE_NAMES)
  687. list(REMOVE_DUPLICATES all_package_names)
  688. set(builtinpackages "# Generated by O3DE install\n\n")
  689. foreach(package_name IN LISTS all_package_names)
  690. get_property(package_hash GLOBAL PROPERTY LY_PACKAGE_HASH_${package_name})
  691. get_property(targets GLOBAL PROPERTY LY_PACKAGE_TARGETS_${package_name})
  692. list(REMOVE_DUPLICATES targets)
  693. string(APPEND builtinpackages "ly_associate_package(PACKAGE_NAME ${package_name} TARGETS ${targets} PACKAGE_HASH ${package_hash})\n")
  694. endforeach()
  695. # Allow the BuiltinPackages_<platform>.cmake script to propagate additional cmake code to be executed in the Install layout configure step
  696. get_property(builtin_packages_inject_code GLOBAL PROPERTY O3DE_BUILTIN_PACKAGES_INSTALL_CODE)
  697. if (builtin_packages_inject_code)
  698. string(APPEND builtinpackages "${builtin_packages_inject_code}\n")
  699. endif()
  700. set(permutation_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}${LY_ARCHITECTURE_NAME_EXTENSION}.cmake)
  701. file(GENERATE OUTPUT ${permutation_builtin_file}
  702. CONTENT "${builtinpackages}"
  703. )
  704. ly_install(FILES "${permutation_builtin_file}"
  705. DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}
  706. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}
  707. )
  708. endfunction()
  709. #! ly_setup_runtime_dependencies: install runtime dependencies
  710. function(ly_setup_runtime_dependencies)
  711. # Common functions used by the below code
  712. if(COMMAND ly_setup_runtime_dependencies_copy_function_override)
  713. ly_setup_runtime_dependencies_copy_function_override()
  714. else()
  715. # despite this copy function being the same, we need to install it per component that uses it
  716. # (which is per-configuration per-permutation component)
  717. # The template is needed to replace the @LY_COPY_PERMISSIONS@ variable with the permissions
  718. # that should be used for the copied file
  719. set(install_runtime_ly_copy_template [[
  720. function(ly_copy source_files relative_target_directory)
  721. set(options)
  722. set(oneValueArgs TARGET_FILE_DIR SOURCE_TYPE SOURCE_GEM_MODULE)
  723. set(multiValueArgs)
  724. cmake_parse_arguments("${CMAKE_CURRENT_FUNCTION}" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  725. set(target_file_dir "${${CMAKE_CURRENT_FUNCTION}_TARGET_FILE_DIR}")
  726. set(source_type "${${CMAKE_CURRENT_FUNCTION}_SOURCE_TYPE}")
  727. set(source_is_gem "${${CMAKE_CURRENT_FUNCTION}_SOURCE_GEM_MODULE}")
  728. # Create the full path to the target directory
  729. cmake_path(APPEND target_directory "${target_file_dir}" "${relative_target_directory}")
  730. foreach(source_file IN LISTS source_files)
  731. cmake_path(GET source_file FILENAME target_filename)
  732. cmake_path(APPEND full_target_directory "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}" "${target_directory}")
  733. cmake_path(APPEND target_file "${full_target_directory}" "${target_filename}")
  734. if("${source_file}" IS_NEWER_THAN "${target_file}")
  735. message(STATUS "Copying ${source_file} to ${full_target_directory}...")
  736. file(COPY "${source_file}" DESTINATION "${full_target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN)
  737. file(TOUCH_NOCREATE "${target_file}")
  738. endif()
  739. endforeach()
  740. endfunction()
  741. ]])
  742. # replace the @...@ placeholders
  743. string(CONFIGURE "${install_runtime_ly_copy_template}" install_runtime_ly_copy @ONLY)
  744. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  745. string(TOUPPER ${conf} UCONF)
  746. ly_install(CODE "${install_runtime_ly_copy}"
  747. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  748. )
  749. endforeach()
  750. endif()
  751. unset(runtime_commands)
  752. get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS)
  753. foreach(alias_target IN LISTS all_targets)
  754. ly_de_alias_target(${alias_target} target)
  755. # Exclude targets that dont produce runtime outputs
  756. get_target_property(target_type ${target} TYPE)
  757. if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS)
  758. continue()
  759. endif()
  760. get_target_property(target_runtime_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY)
  761. if(target_runtime_output_directory)
  762. cmake_path(RELATIVE_PATH target_runtime_output_directory BASE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_runtime_output_subdirectory)
  763. endif()
  764. # runtime dependencies that need to be copied to the output
  765. set(target_file_dir "${runtime_output_directory}/${target_runtime_output_subdirectory}")
  766. unset(target_copy_dependencies)
  767. unset(target_target_dependencies)
  768. unset(target_link_dependencies)
  769. unset(target_imported_dependencies)
  770. o3de_get_dependencies_for_target(
  771. TARGET "${target}"
  772. COPY_DEPENDENCIES_VAR target_copy_dependencies
  773. TARGET_DEPENDENCIES_VAR target_target_dependencies
  774. LINK_DEPENDENCIES_VAR target_link_dependencies
  775. IMPORTED_DEPENDENCIES_VAR target_imported_dependencies
  776. )
  777. foreach(dependency_for_target IN LISTS target_copy_dependencies target_target_dependencies
  778. target_link_dependencies target_imported_dependencies)
  779. unset(runtime_command)
  780. o3de_get_command_for_dependency(COMMAND_VAR runtime_command
  781. DEPENDENCY ${dependency_for_target})
  782. string(CONFIGURE "${runtime_command}" runtime_command @ONLY)
  783. list(APPEND runtime_commands ${runtime_command})
  784. endforeach()
  785. endforeach()
  786. list(REMOVE_DUPLICATES runtime_commands)
  787. list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file
  788. foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
  789. string(TOUPPER ${conf} UCONF)
  790. ly_install(CODE "${runtime_commands_str}"
  791. COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}
  792. )
  793. endforeach()
  794. endfunction()
  795. #! ly_setup_assets: install asset directories required by the engine
  796. function(ly_setup_assets)
  797. # Gem Source Assets and configuration files
  798. # Find all gem directories relative to the CMake Source Dir
  799. # this first loop real-path-izes all the paths to avoid doing so repeatedly.
  800. get_external_subdirectories_in_use(external_subdirs_non_realpath)
  801. foreach(gem_candidate_dir IN LISTS external_subdirs_non_realpath)
  802. file(REAL_PATH ${gem_candidate_dir} gem_candidate_dir BASE_DIRECTORY ${LY_ROOT_FOLDER})
  803. list(APPEND external_subdirs ${gem_candidate_dir})
  804. endforeach()
  805. # This next loop is to filter out transient and .gitignore'd folders that should be added to
  806. # the install layout from the root directory. Such as <external-subdirectory-root>/Cache.
  807. # This is also done to avoid globbing thousands of files in subdirectories that shouldn't
  808. # be processed.
  809. # It also filters out subdirectories that are themselves gem candidate directories so they are
  810. # not double-visited.
  811. foreach(gem_candidate_dir IN LISTS external_subdirs)
  812. unset(external_subdir_files)
  813. unset(external_subdir_files_tenative)
  814. # Don't recurse immediately in order to exclude transient source artifacts
  815. file(GLOB
  816. external_subdir_files_tenative
  817. LIST_DIRECTORIES TRUE
  818. "${gem_candidate_dir}/*"
  819. )
  820. # Exclude transient artifacts that shouldn't be copied to the install layout
  821. list(FILTER external_subdir_files_tenative EXCLUDE REGEX "/([Bb]uild|[Cc]ache|[Uu]ser)$")
  822. # Exclude folders that themselves are gem_candidate_dirs with their own gem.json
  823. foreach(check_file IN LISTS external_subdir_files_tenative)
  824. if(IS_DIRECTORY ${check_file})
  825. list(FIND external_subdirs ${check_file} is_gem_candidate_dir)
  826. if(is_gem_candidate_dir EQUAL -1)
  827. # it is not already in the list, so it is unique to this gem folder.
  828. list(APPEND external_subdir_files ${check_file})
  829. endif()
  830. else()
  831. list(APPEND external_subdir_files ${check_file})
  832. endif()
  833. endforeach()
  834. # Storing a "mapping" of gem candidate directories, to external_subdirectory files using
  835. # a DIRECTORY property for the "value" and the GLOBAL property for the "key"
  836. set_property(DIRECTORY ${gem_candidate_dir} APPEND PROPERTY directory_filtered_asset_paths "${external_subdir_files}")
  837. set_property(GLOBAL APPEND PROPERTY global_gem_candidate_dirs_prop ${gem_candidate_dir})
  838. endforeach()
  839. # Iterate over each gem candidate directories and populate a directory property
  840. # containing the files to copy over
  841. get_property(gem_candidate_dirs GLOBAL PROPERTY global_gem_candidate_dirs_prop)
  842. foreach(gem_candidate_dir IN LISTS gem_candidate_dirs)
  843. get_property(filtered_asset_paths DIRECTORY ${gem_candidate_dir} PROPERTY directory_filtered_asset_paths)
  844. # Check if the gem is a subdirectory of the engine
  845. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${gem_candidate_dir} is_gem_subdirectory_of_engine)
  846. # At this point the filtered_assets_paths contains the list of all directories and files
  847. # that are non-excluded candidates that can be scanned for target directories and files
  848. # to copy over to the install layout
  849. foreach(filtered_asset_path IN LISTS filtered_asset_paths)
  850. if(IS_DIRECTORY ${filtered_asset_path})
  851. file(GLOB_RECURSE
  852. recurse_assets_paths
  853. LIST_DIRECTORIES TRUE
  854. "${filtered_asset_path}/*"
  855. )
  856. set(gem_file_paths ${recurse_assets_paths})
  857. # Make sure to prepend the current path iteration to the gem_dirs_path to filter
  858. set(gem_dir_paths ${filtered_asset_path} ${recurse_assets_paths})
  859. # Gather directories to copy over
  860. # Currently only the Assets, Registry and Config directories are copied over
  861. list(FILTER gem_dir_paths INCLUDE REGEX "/(Assets|Registry|Config|Editor/Scripts)$")
  862. set_property(DIRECTORY ${gem_candidate_dir} APPEND PROPERTY gems_assets_paths ${gem_dir_paths})
  863. else()
  864. set(gem_file_paths ${filtered_asset_path})
  865. endif()
  866. # Gather files to copy over
  867. # Currently only the gem.json file is copied over
  868. list(FILTER gem_file_paths INCLUDE REGEX "/(gem.json|preview.png)$")
  869. set_property(DIRECTORY ${gem_candidate_dir} APPEND PROPERTY gems_assets_paths "${gem_file_paths}")
  870. endforeach()
  871. # gem directories and files to install
  872. get_property(gems_assets_paths DIRECTORY ${gem_candidate_dir} PROPERTY gems_assets_paths)
  873. foreach(gem_absolute_path IN LISTS gems_assets_paths)
  874. # If an external subdirectory is not a subdirectory of the engine root, then
  875. # prepend "External" to its subdirectory root
  876. ly_get_root_subdirectory_which_is_parent(${gem_candidate_dir} root_subdir_of_gem)
  877. cmake_path(RELATIVE_PATH gem_absolute_path BASE_DIRECTORY ${root_subdir_of_gem} OUTPUT_VARIABLE gem_install_dest_dir)
  878. if(NOT is_gem_subdirectory_of_engine)
  879. cmake_path(GET root_subdir_of_gem FILENAME root_subdir_dirname)
  880. set(relative_subdir ${gem_install_dest_dir})
  881. unset(gem_install_dest_dir)
  882. cmake_path(APPEND gem_install_dest_dir "External" ${root_subdir_dirname} ${relative_subdir})
  883. endif()
  884. cmake_path(GET gem_install_dest_dir PARENT_PATH gem_install_dest_dir)
  885. if (NOT gem_install_dest_dir)
  886. cmake_path(SET gem_install_dest_dir .)
  887. endif()
  888. if(IS_DIRECTORY ${gem_absolute_path})
  889. ly_install(DIRECTORY "${gem_absolute_path}"
  890. DESTINATION ${gem_install_dest_dir}
  891. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  892. )
  893. elseif (EXISTS ${gem_absolute_path})
  894. # Special case for the gem.json file, generate an empty CMakeLists.txt with the gem.json file
  895. # if there is not already a CMakeLists.txy being installed to gem root directory
  896. cmake_path(GET gem_absolute_path FILENAME filename)
  897. cmake_path(COMPARE "${filename}" EQUAL "gem.json" is_gem_root)
  898. get_property(has_gem_root_cmakelist_content DIRECTORY "${gem_candidate_dir}" PROPERTY O3DE_SUBDIRECTORY_CMAKELIST_CONTENT SET)
  899. if (is_gem_root AND NOT has_gem_root_cmakelist_content)
  900. ly_file_read(${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment)
  901. # Generate an empty CMakeLists.txt inside the cmake binary directory
  902. # to allow it to be installed next to the gem.json
  903. set(gem_scratch_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/install/${gem_install_dest_dir}")
  904. # 1. Create the base CMakeLists.txt that will just include a cmake file per platform
  905. string(CONFIGURE [[
  906. @cmake_copyright_comment@
  907. o3de_read_json_key(GEM_TYPE ${CMAKE_CURRENT_SOURCE_DIR}/gem.json "type")
  908. if (GEM_TYPE STREQUAL "Asset")
  909. if(LY_MONOLITHIC_GAME)
  910. include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake OPTIONAL)
  911. else()
  912. include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  913. endif()
  914. endif()
  915. ]] subdirectory_cmakelist_content @ONLY)
  916. # Store off the generated CMakeLists.txt into a DIRECTORY property based on the subdirectory being visited
  917. # In the ly_setup_assets() function, it generates an empty CMakeLists.txt into the gem root directory
  918. # if one does not exist by checking if this property is set
  919. set_property(DIRECTORY "${absolute_target_source_dir}" APPEND_STRING PROPERTY O3DE_SUBDIRECTORY_CMAKELIST_CONTENT "${subdirectory_cmakelist_content}")
  920. # copy the empty CMakeList.txt into the gem root directory, to allow add_subdirectory
  921. # calls to succeed on the gem root in the install layout
  922. file(WRITE "${gem_scratch_binary_dir}/CMakeLists.txt" "${subdirectory_cmakelist_content}")
  923. ly_install(FILES "${gem_scratch_binary_dir}/CMakeLists.txt"
  924. DESTINATION ${gem_install_dest_dir}
  925. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  926. )
  927. endif()
  928. ly_install(FILES ${gem_absolute_path}
  929. DESTINATION ${gem_install_dest_dir}
  930. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  931. )
  932. endif()
  933. endforeach()
  934. endforeach()
  935. endfunction()
  936. #! ly_setup_add_variant_dependencies_for_gem_dependencies: Replicates the call to
  937. #! the `o3de_add_variant_dependencies_for_gem_dependencies` function
  938. #! within the generated CMakeLists.txt in the same relative install layout directory
  939. function(ly_setup_add_variant_dependencies_for_gem_dependencies absolute_target_source_dir output_script)
  940. # Replicate the create_alias() calls made in the SOURCE_DIR into the generated CMakeLists.txt
  941. string(JOIN "\n" add_variant_dependencies_for_gem_dependencies_template
  942. "o3de_add_variant_dependencies_for_gem_dependencies(@add_variant_dependencies_for_gem_dependencies_args@)"
  943. "")
  944. unset(${output_script} PARENT_SCOPE)
  945. get_property(add_variant_dependencies_for_gem_dependencies_args_list
  946. DIRECTORY ${absolute_target_source_dir}
  947. PROPERTY O3DE_ADD_VARIANT_DEPENDENCIES_FOR_GEM_DEPENDENCIES_ARGUMENTS)
  948. unset(add_variant_dependencies_for_gem_dependencies_calls)
  949. foreach(add_variant_dependencies_for_gem_dependencies_args IN LISTS add_variant_dependencies_for_gem_dependencies_args_list)
  950. string(CONFIGURE "${add_variant_dependencies_for_gem_dependencies_template}" add_variant_dependencies_for_gem_dependencies_command @ONLY)
  951. string(APPEND add_variant_dependencies_for_gem_dependencies_calls ${add_variant_dependencies_for_gem_dependencies_command})
  952. endforeach()
  953. set(${output_script} ${add_variant_dependencies_for_gem_dependencies_calls} PARENT_SCOPE)
  954. endfunction()
  955. #! ly_setup_subdirectory_create_alias: Replicates the call to the `ly_create_alias` function
  956. #! within the generated CMakeLists.txt in the same relative install layout directory
  957. function(ly_setup_subdirectory_create_alias absolute_target_source_dir output_script)
  958. # Replicate the create_alias() calls made in the SOURCE_DIR into the generated CMakeLists.txt
  959. string(JOIN "\n" create_alias_template
  960. "if(NOT TARGET @alias_name@)"
  961. " ly_create_alias(@create_alias_args@)"
  962. "endif()"
  963. "")
  964. unset(${output_script} PARENT_SCOPE)
  965. get_property(create_alias_args_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_CREATE_ALIAS_ARGUMENTS)
  966. foreach(create_alias_args IN LISTS create_alias_args_list)
  967. # Create a list out of the comma separated arguments and store it into the same variable
  968. string(REPLACE "," ";" create_alias_args ${create_alias_args})
  969. # The first argument of the create alias argument list is the ALIAS NAME so pop it from the list
  970. # It is used to protect against registering the same alias twice
  971. list(POP_FRONT create_alias_args alias_name)
  972. string(CONFIGURE "${create_alias_template}" create_alias_command @ONLY)
  973. string(APPEND create_alias_calls ${create_alias_command})
  974. endforeach()
  975. set(${output_script} ${create_alias_calls} PARENT_SCOPE)
  976. endfunction()
  977. #! ly_setup_subdirectory_set_gem_variant_to_load: Replicates the call to the `ly_set_gem_variant_to_load` function
  978. #! within the generated CMakeLists.txt in the same relative install layout directory
  979. function(ly_setup_subdirectory_set_gem_variant_to_load absolute_target_source_dir output_script)
  980. # Replicate the ly_set_gem_variant_to_load() calls made in the SOURCE_DIR for into the generated CMakeLists.txt
  981. set(set_gem_variant_args_template "ly_set_gem_variant_to_load(@set_gem_variant_args@)\n")
  982. unset(${output_script} PARENT_SCOPE)
  983. get_property(set_gem_variant_args_lists DIRECTORY ${absolute_target_source_dir} PROPERTY LY_SET_GEM_VARIANT_TO_LOAD_ARGUMENTS)
  984. foreach(set_gem_variant_args IN LISTS set_gem_variant_args_lists)
  985. string(CONFIGURE "${set_gem_variant_args_template}" set_gem_variant_to_load_command @ONLY)
  986. string(APPEND set_gem_variant_calls ${set_gem_variant_to_load_command})
  987. endforeach()
  988. set(${output_script} ${set_gem_variant_calls} PARENT_SCOPE)
  989. endfunction()
  990. #! ly_setup_subdirectory_enable_gems: Replicates the call to the `ly_enable_gems` function
  991. #! within the generated CMakeLists.txt in the same relative install layout directory
  992. function(ly_setup_subdirectory_enable_gems absolute_target_source_dir output_script)
  993. # Replicate the ly_set_gem_variant_to_load() calls made in the SOURCE_DIR into the generated CMakeLists.txt
  994. set(enable_gems_template "ly_enable_gems(@enable_gems_args@)\n")
  995. unset(${output_script} PARENT_SCOPE)
  996. get_property(enable_gems_args_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_ENABLE_GEMS_ARGUMENTS)
  997. foreach(enable_gems_args IN LISTS enable_gems_args_list)
  998. string(CONFIGURE "${enable_gems_template}" enable_gems_command @ONLY)
  999. string(APPEND enable_gems_calls ${enable_gems_command})
  1000. endforeach()
  1001. set(${output_script} ${enable_gems_calls} PARENT_SCOPE)
  1002. endfunction()
  1003. #! ly_setup_subdirectory_install_code: Add the CMake code specified in the O3DE_SUBDIRECTORY_INSTALL_CODE
  1004. #! DIRECTORY property to the beginning of the generated CMakeLists.txt in the same relative install layout diredctory
  1005. #! within the generated CMakeLists.txt in the same relative install layout directory
  1006. function(ly_setup_subdirectory_install_code absolute_target_source_dir output_script)
  1007. unset(${output_script} PARENT_SCOPE)
  1008. get_property(subdirectory_install_code DIRECTORY ${absolute_target_source_dir} PROPERTY O3DE_SUBDIRECTORY_INSTALL_CODE)
  1009. set(${output_script} ${subdirectory_install_code} PARENT_SCOPE)
  1010. endfunction()
  1011. #! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt
  1012. function(ly_setup_o3de_install)
  1013. ly_setup_subdirectories()
  1014. ly_setup_cmake_install()
  1015. ly_setup_runtime_dependencies()
  1016. ly_setup_assets()
  1017. ly_setup_3p_dependencies()
  1018. # Misc
  1019. ly_install(FILES
  1020. ${LY_ROOT_FOLDER}/pytest.ini
  1021. ${LY_ROOT_FOLDER}/LICENSE.txt
  1022. ${LY_ROOT_FOLDER}/README.md
  1023. ${LY_ROOT_FOLDER}/CMakePresets.json
  1024. DESTINATION .
  1025. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  1026. )
  1027. if("$ENV{O3DE_PACKAGE_TYPE}" STREQUAL "DEB")
  1028. ly_install(FILES
  1029. ${LY_ROOT_FOLDER}/Code/Tools/ProjectManager/Resources/o3de_desktop.svg
  1030. DESTINATION .
  1031. COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
  1032. )
  1033. endif()
  1034. # Inject other build directories
  1035. foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS})
  1036. ly_install(CODE
  1037. "set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE)
  1038. include(${external_dir}/cmake_install.cmake)
  1039. set(LY_CORE_COMPONENT_ALREADY_INCLUDED FALSE)"
  1040. ALL_COMPONENTS
  1041. )
  1042. endforeach()
  1043. if(COMMAND ly_post_install_steps)
  1044. ly_post_install_steps()
  1045. endif()
  1046. endfunction()