Gems.cmake 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. # This file contains utility wrappers for dealing with the Gems system.
  9. define_property(TARGET PROPERTY LY_PROJECT_NAME
  10. BRIEF_DOCS "Name of the project, this target can use enabled gems from"
  11. FULL_DOCS "If set, the when iterating over the enabled gems in ly_enabled_gems_delayed
  12. only a project with that name can have it's enabled gem list added as a dependency to this target.
  13. If the __NOPROJECT__ placeholder is associated with a list enabled gems, then it applies to this target regardless of this property value")
  14. # o3de_find_ancestor_gem_root:Searches for the nearest gem root from input source_dir
  15. #
  16. # \arg:source_dir(FILEPATH) - Filepath to walk upwards from to locate a gem.json
  17. # \return:output_gem_module_root - The directory containing the nearest gem.json
  18. # \return:output_gem_name - The name of the gem read from the gem.json
  19. function(o3de_find_ancestor_gem_root output_gem_module_root output_gem_name source_dir)
  20. unset(${output_gem_module_root} PARENT_SCOPE)
  21. if(source_dir)
  22. set(candidate_gem_path ${source_dir})
  23. # Locate the root of the gem by finding the gem.json location
  24. cmake_path(APPEND candidate_gem_path "gem.json" OUTPUT_VARIABLE candidate_gem_json_path)
  25. while(NOT EXISTS "${candidate_gem_json_path}")
  26. cmake_path(GET candidate_gem_path PARENT_PATH parent_path)
  27. # If the parent directory is the same as the candidate path then the root path has been found
  28. cmake_path(COMPARE "${candidate_gem_path}" EQUAL "${parent_path}" reached_root_dir)
  29. if (reached_root_dir)
  30. # The source directory is not under a gem path in this case
  31. return()
  32. endif()
  33. set(candidate_gem_path ${parent_path})
  34. cmake_path(APPEND candidate_gem_path "gem.json" OUTPUT_VARIABLE candidate_gem_json_path)
  35. endwhile()
  36. endif()
  37. if (EXISTS ${candidate_gem_json_path})
  38. # Update source_dir if the gem root path exists
  39. set(source_dir ${candidate_gem_path})
  40. o3de_read_json_key(gem_name ${candidate_gem_json_path} "gem_name")
  41. endif()
  42. # Set the gem module root output directory to the location with the gem.json file within it or
  43. # the supplied gem_target SOURCE_DIR location if no gem.json file was found
  44. set(${output_gem_module_root} ${source_dir} PARENT_SCOPE)
  45. # Set the gem name output value to the name of the gem as in the gem.json file
  46. if(gem_name)
  47. set(${output_gem_name} ${gem_name} PARENT_SCOPE)
  48. endif()
  49. endfunction()
  50. # o3de_add_variant_dependencies_for_gem_dependencies
  51. #
  52. # For the specified gem, creates cmake TARGET dependencies using
  53. # the gem's "dependencies" field as a prefix for each gem variant supplied to this function
  54. # \arg:GEM_NAME(STRING) - Gem name whose "dependencies" will be queried from its gem.json
  55. # \arg:VARIANTS(LIST) - List of Gem variants which will be suffixed to the input gem name and
  56. # its gem dependencies
  57. function(o3de_add_variant_dependencies_for_gem_dependencies)
  58. set(options)
  59. set(oneValueArgs GEM_NAME)
  60. set(multiValueArgs VARIANTS)
  61. cmake_parse_arguments(o3de_add_variant_dependencies_for_gem_dependencies "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  62. set(gem_name ${o3de_add_variant_dependencies_for_gem_dependencies_GEM_NAME})
  63. set(gem_variants ${o3de_add_variant_dependencies_for_gem_dependencies_VARIANTS})
  64. if(NOT gem_name OR NOT gem_variants)
  65. return() # Nothing to do
  66. endif()
  67. # Get the gem path using the gem name as a key
  68. get_property(gem_path GLOBAL PROPERTY "@GEMROOT:${gem_name}@")
  69. if(NOT gem_path)
  70. message(FATAL_ERROR "Unable to locate gem path for Gem \"${gem_name}\"."
  71. " Is the gem registered in either the ~/.o3de/o3de_manifest.json, ${LY_ROOT_FOLDER}/engine.json,"
  72. " any project.json or any gem.json which itself is registered?")
  73. endif()
  74. # Open gem.json and read "dependencies" array
  75. unset(gem_dependencies)
  76. o3de_read_json_array(gem_dependencies "${gem_path}/gem.json" "dependencies")
  77. foreach(variant IN LISTS gem_variants)
  78. set(gem_variant_target "${gem_name}.${variant}")
  79. # Continue to the next variant if the gem didn't specify
  80. # a CMake target for the current variant
  81. if(NOT TARGET ${gem_variant_target})
  82. continue()
  83. endif()
  84. # Append to the list of target dependencies for the current list
  85. # CMake targets that actually exists
  86. unset(target_dependencies_for_variant)
  87. foreach(gem_dependency IN LISTS gem_dependencies)
  88. set(gem_dependency_variant_target "${gem_dependency}.${variant}")
  89. if(TARGET ${gem_dependency_variant_target})
  90. list(APPEND target_dependencies_for_variant ${gem_dependency_variant_target})
  91. endif()
  92. endforeach()
  93. # Validate that there is at least one dependency being added
  94. if(target_dependencies_for_variant)
  95. ly_add_dependencies(${gem_variant_target} ${target_dependencies_for_variant})
  96. message(VERBOSE "Adding target dependencies for Gem \"${gem_name}\" by appending variant \"${variant}\""
  97. " to gem names found in this gem's \"dependencies\" field\n"
  98. "${gem_variant_target} -> ${gem_dependencies_for_variant}")
  99. endif()
  100. endforeach()
  101. # Store of the arguments used to invoke this function in order to replicate the call
  102. # in the SDK install layout
  103. unset(add_variant_dependencies_for_gem_dependencies_args)
  104. list(APPEND add_variant_dependencies_for_gem_dependencies_args
  105. GEM_NAME ${gem_name}
  106. VARIANTS ${gem_variants})
  107. # Replace the list separator with space to have it be stored as a single property element
  108. list(JOIN add_variant_dependencies_for_gem_dependencies_args " " add_variant_dependencies_for_gem_dependencies_args)
  109. set_property(DIRECTORY APPEND PROPERTY O3DE_ADD_VARIANT_DEPENDENCIES_FOR_GEM_DEPENDENCIES_ARGUMENTS
  110. "${add_variant_dependencies_for_gem_dependencies_args}")
  111. endfunction()
  112. # ly_create_alias
  113. # given an alias to create, and a list of one or more targets,
  114. # this creates an alias that depends on all of the given targets.
  115. function(ly_create_alias)
  116. set(options)
  117. set(oneValueArgs NAME NAMESPACE)
  118. set(multiValueArgs TARGETS)
  119. cmake_parse_arguments(ly_create_alias "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  120. if (NOT ly_create_alias_NAME)
  121. message(FATAL_ERROR "Provide the name of the alias to create using the NAME keyword")
  122. endif()
  123. if (NOT ly_create_alias_NAMESPACE)
  124. message(FATAL_ERROR "Provide the namespace of the alias to create using the NAMESPACE keyword")
  125. endif()
  126. if(TARGET ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME})
  127. message(FATAL_ERROR "Target already exists, cannot create an alias for it: ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}\n"
  128. "Make sure the target wasn't copy and pasted here or elsewhere.")
  129. endif()
  130. # Using an ALIAS target inhibits finding the ALIAS target SOURCE_DIR, which is needed to determine the gem root of the alias target
  131. # complex version - one alias to multiple targets or the alias is being made to a TARGET that doesn't exist yet.
  132. # To actually achieve this we have to create an interface library with those dependencies,
  133. # then we have to create an alias to that target.
  134. # By convention we create one without a namespace then alias the namespaced one.
  135. if(TARGET ${ly_create_alias_NAME})
  136. message(FATAL_ERROR "Internal alias target already exists, cannot create an alias for it: ${ly_create_alias_NAME}\n"
  137. "This could be a copy-paste error, where some part of the ly_create_alias call was changed but the other")
  138. endif()
  139. add_library(${ly_create_alias_NAME} INTERFACE IMPORTED GLOBAL)
  140. set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE)
  141. foreach(target_name ${ly_create_alias_TARGETS})
  142. if(TARGET ${target_name})
  143. ly_de_alias_target(${target_name} de_aliased_target_name)
  144. if(NOT de_aliased_target_name)
  145. message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name")
  146. endif()
  147. else()
  148. set(de_aliased_target_name ${target_name})
  149. endif()
  150. list(APPEND final_targets ${de_aliased_target_name})
  151. endforeach()
  152. # add_dependencies must be called with at least one dependent target
  153. if(final_targets)
  154. ly_parse_third_party_dependencies("${final_targets}")
  155. ly_add_dependencies(${ly_create_alias_NAME} ${final_targets})
  156. # copy over all the dependent target interface properties to the alias
  157. o3de_copy_targets_usage_requirements(TARGET ${ly_create_alias_NAME} SOURCE_TARGETS ${final_targets})
  158. # Register the targets this alias aliases
  159. set_property(GLOBAL APPEND PROPERTY O3DE_ALIASED_TARGETS_${ly_create_alias_NAME} ${final_targets})
  160. endif()
  161. # now add the final alias:
  162. add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME})
  163. # Store off the arguments used by ly_create_alias into a DIRECTORY property
  164. # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step
  165. # Replace the CMake list separator with a space to replicate the space separated arguments
  166. # A single create_alias_args variable encodes two values. The alias NAME used to check if the target exists
  167. # and the ly_create_alias arguments to replicate this function call
  168. unset(create_alias_args)
  169. list(APPEND create_alias_args "${ly_create_alias_NAME},"
  170. NAME ${ly_create_alias_NAME}
  171. NAMESPACE ${ly_create_alias_NAMESPACE}
  172. TARGETS ${ly_create_alias_TARGETS})
  173. list(JOIN create_alias_args " " create_alias_args)
  174. set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${create_alias_args}")
  175. # Store the directory path in the GLOBAL property so that it can be accessed
  176. # in the layout install logic. Skip if the directory has already been added
  177. get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
  178. if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
  179. set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
  180. endif()
  181. endfunction()
  182. # ly_set_gem_variant_to_load
  183. # Associates a key, value entry of CMake target -> Gem variant
  184. # \arg:TARGETS - list of Targets to associate with the Gem variant
  185. # \arg:VARIANTS - Gem variant
  186. function(ly_set_gem_variant_to_load)
  187. set(options)
  188. set(oneValueArgs)
  189. set(multiValueArgs TARGETS VARIANTS)
  190. cmake_parse_arguments(ly_set_gem_variant_to_load "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  191. if (NOT ly_set_gem_variant_to_load_TARGETS)
  192. message(FATAL_ERROR "You must provide at least 1 target to ${CMAKE_CURRENT_FUNCTION} using the TARGETS keyword")
  193. endif()
  194. # Store a list of targets
  195. foreach(target_name ${ly_set_gem_variant_to_load_TARGETS})
  196. # Append the target to the list of targets with variants if it has not been added
  197. get_property(ly_targets_with_variants GLOBAL PROPERTY LY_TARGETS_WITH_GEM_VARIANTS)
  198. if(NOT target_name IN_LIST ly_targets_with_variants)
  199. set_property(GLOBAL APPEND PROPERTY LY_TARGETS_WITH_GEM_VARIANTS "${target_name}")
  200. endif()
  201. foreach(variant_name ${ly_set_gem_variant_to_load_VARIANTS})
  202. get_property(target_gem_variants GLOBAL PROPERTY LY_GEM_VARIANTS_"${target_name}")
  203. if(NOT variant_name IN_LIST target_gem_variants)
  204. set_property(GLOBAL APPEND PROPERTY LY_GEM_VARIANTS_"${target_name}" "${variant_name}")
  205. endif()
  206. endforeach()
  207. endforeach()
  208. # Store of the arguments used to invoke this function in order to replicate the call in the generated CMakeLists.txt
  209. # in the install layout
  210. unset(set_gem_variant_args)
  211. list(APPEND set_gem_variant_args
  212. TARGETS ${ly_set_gem_variant_to_load_TARGETS}
  213. VARIANTS ${ly_set_gem_variant_to_load_VARIANTS})
  214. # Replace the list separator with space to have it be stored as a single property element
  215. list(JOIN set_gem_variant_args " " set_gem_variant_args)
  216. set_property(DIRECTORY APPEND PROPERTY LY_SET_GEM_VARIANT_TO_LOAD_ARGUMENTS "${set_gem_variant_args}")
  217. endfunction()
  218. # ly_enable_gems
  219. # this function makes sure that the given gems, or gems listed in the variable ENABLED_GEMS
  220. # in the GEM_FILE name, are set as runtime dependencies (and thus loaded) for the given targets
  221. # in the context of the given project.
  222. # note that it can't do this immediately, so it saves the data for later processing.
  223. # Note: If you don't supply a project name, it will apply it across the board to all projects.
  224. # this is useful in the case of "ly_enable_gems" being called for so called 'mandatory gems' inside the engine.
  225. # if you specify a gem name with a namespace, it will be used, otherwise it will assume Gem::
  226. function(ly_enable_gems)
  227. set(options)
  228. set(oneValueArgs PROJECT_NAME GEM_FILE)
  229. set(multiValueArgs GEMS TARGETS VARIANTS)
  230. cmake_parse_arguments(ly_enable_gems "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  231. if (NOT ly_enable_gems_PROJECT_NAME)
  232. message(VERBOSE "Note: ly_enable_gems called with no PROJECT_NAME name, applying to all projects: \n"
  233. " - GEMS ${ly_enable_gems_GEMS} \n"
  234. " - GEM_FILE ${ly_enable_gems_GEM_FILE}")
  235. set(ly_enable_gems_PROJECT_NAME "__NOPROJECT__") # so that the token is not blank
  236. endif()
  237. # Backwards-Compatibility - Delegate any TARGETS and VARIANTS arguments to the ly_set_gem_variant_to_load
  238. # command. That command is used to associate TARGETS with the list of Gem Variants they desire to use
  239. if (ly_enable_gems_TARGETS AND ly_enable_gems_VARIANTS)
  240. message(DEPRECATION "The TARGETS and VARIANTS arguments to \"${CMAKE_CURRENT_FUNCTION}\" is deprecated.\n"
  241. "Please use the \"ly_set_gem_variant_to_load\" function directly to associate a Target with a Gem Variant.\n"
  242. "This function will forward the TARGETS and VARIANTS arguments to \"ly_set_gem_variant_to_load\" for now,"
  243. " but this functionality will be removed.")
  244. ly_set_gem_variant_to_load(TARGETS ${ly_enable_gems_TARGETS} VARIANTS ${ly_enable_gems_VARIANTS})
  245. endif()
  246. if ((NOT ly_enable_gems_GEMS AND NOT ly_enable_gems_GEM_FILE) OR (ly_enable_gems_GEMS AND ly_enable_gems_GEM_FILE))
  247. message(FATAL_ERROR "Provide exactly one of either GEM_FILE (filename) or GEMS (list of gems) keywords.")
  248. endif()
  249. if (ly_enable_gems_GEM_FILE)
  250. set(store_temp ${ENABLED_GEMS})
  251. include(${ly_enable_gems_GEM_FILE} RESULT_VARIABLE was_able_to_load_the_file)
  252. if(NOT was_able_to_load_the_file)
  253. message(FATAL_ERROR "could not load the GEM_FILE ${ly_enable_gems_GEM_FILE}")
  254. endif()
  255. if(NOT DEFINED ENABLED_GEMS)
  256. message(WARNING "GEM_FILE ${ly_enable_gems_GEM_FILE} did not set the value of ENABLED_GEMS.\n"
  257. "Gem Files should contain set(ENABLED_GEMS ... <list of gem names>)")
  258. endif()
  259. set(ly_enable_gems_GEMS ${ENABLED_GEMS})
  260. set(ENABLED_GEMS ${store_temp}) # restore value of ENABLED_GEMS just in case...
  261. endif()
  262. # Remove any version specifiers before looking for variants
  263. # e.g. "Atom==1.2.3" becomes "Atom"
  264. unset(GEM_NAMES)
  265. foreach(gem_name_with_version_specifier IN LISTS ly_enable_gems_GEMS)
  266. o3de_get_name_and_version_specifier(${gem_name_with_version_specifier} gem_name spec_op spec_version)
  267. list(APPEND GEM_NAMES "${gem_name}")
  268. endforeach()
  269. set(ly_enable_gems_GEMS ${GEM_NAMES})
  270. # all the actual work has to be done later.
  271. set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS "${ly_enable_gems_PROJECT_NAME}")
  272. define_property(GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME}"
  273. BRIEF_DOCS "List of gem names to evaluate variants against" FULL_DOCS "Names of gems that will be paired with the variant name
  274. to determine if it is valid target that should be added as an application dynamic load dependency")
  275. set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME}" ${ly_enable_gems_GEMS})
  276. # Store off the arguments used by ly_enable_gems into a DIRECTORY property
  277. # This will be used to re-create the ly_enable_gems call in the generated CMakeLists.txt at the INSTALL step
  278. # Replace the CMake list separator with a space to replicate the space separated TARGETS arguments
  279. if(NOT ly_enable_gems_PROJECT_NAME STREQUAL "__NOPROJECT__")
  280. set(replicated_project_name PROJECT_NAME ${ly_enable_gems_PROJECT_NAME})
  281. endif()
  282. # The GEM_FILE file is used to populate the GEMS argument via the ENABLED_GEMS variable in the file.
  283. # Furthermore the GEM_FILE itself is not copied over to the install layout, so make its argument entry blank and use the list of GEMS
  284. # stored in ly_enable_gems_GEMS
  285. unset(enable_gems_args)
  286. list(APPEND enable_gems_args
  287. ${replicated_project_name}
  288. GEMS ${ly_enable_gems_GEMS})
  289. list(JOIN enable_gems_args " " enable_gems_args)
  290. set_property(DIRECTORY APPEND PROPERTY LY_ENABLE_GEMS_ARGUMENTS "${enable_gems_args}")
  291. endfunction()
  292. function(ly_add_gem_dependencies_to_project_variants)
  293. set(options)
  294. set(oneValueArgs PROJECT_NAME TARGET VARIANT)
  295. set(multiValueArgs GEM_DEPENDENCIES)
  296. cmake_parse_arguments(ly_add_gem_dependencies "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  297. if (NOT ly_add_gem_dependencies_PROJECT_NAME)
  298. message(FATAL_ERROR "Missing required PROJECT_NAME argument which is used to determine gem load prefix")
  299. endif()
  300. if (NOT ly_add_gem_dependencies_TARGET)
  301. message(FATAL_ERROR "Missing required TARGET argument ")
  302. endif()
  303. if (NOT ly_add_gem_dependencies_VARIANT)
  304. message(FATAL_ERROR "Missing required gem VARIANT argument needed to determine which gem variants to load for the target")
  305. endif()
  306. if(${ly_add_gem_dependencies_PROJECT_NAME} STREQUAL "__NOPROJECT__")
  307. # special case, apply to all
  308. unset(PREFIX_CLAUSE)
  309. else()
  310. set(PREFIX_CLAUSE "PREFIX;${ly_add_gem_dependencies_PROJECT_NAME}")
  311. endif()
  312. # apply the list of gem targets. Adding a gem really just means adding the appropriate dependency.
  313. foreach(gem_name ${ly_add_gem_dependencies_GEM_DEPENDENCIES})
  314. set(gem_target ${gem_name}.${ly_add_gem_dependencies_VARIANT})
  315. # if the target exists, add it.
  316. if (TARGET ${gem_target})
  317. # Dealias actual target
  318. ly_de_alias_target(${gem_target} dealiased_gem_target)
  319. ly_add_target_dependencies(
  320. ${PREFIX_CLAUSE}
  321. TARGETS ${ly_add_gem_dependencies_TARGET}
  322. DEPENDENT_TARGETS ${dealiased_gem_target}
  323. GEM_VARIANT ${ly_add_gem_dependencies_VARIANT})
  324. else()
  325. message(VERBOSE "Gem \"${gem_name}\" does not expose a variant of ${ly_add_gem_dependencies_VARIANT}")
  326. endif()
  327. endforeach()
  328. endfunction()
  329. # call this before runtime dependencies are used to add any relevant targets
  330. # saved by the above function
  331. function(ly_enable_gems_delayed)
  332. # Query the list of targets that are associated with a gem variant
  333. get_property(targets_with_variants GLOBAL PROPERTY LY_TARGETS_WITH_GEM_VARIANTS)
  334. # Query the projects that have made calls to ly_enable_gems
  335. get_property(enable_gem_projects GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS)
  336. foreach(target ${targets_with_variants})
  337. if (NOT TARGET ${target})
  338. message(FATAL_ERROR "ly_set_gem_variant_to_load specified TARGET '${target}' but no such target was found.")
  339. endif()
  340. get_property(target_gem_variants GLOBAL PROPERTY LY_GEM_VARIANTS_"${target}")
  341. message(VERBOSE "Adding gem dependencies for \"${target}\" associated with the Gem variants of \"${target_gem_variants}\"")
  342. # Lookup if the target is scoped to a project
  343. # In that case the target can only use gem targets that is
  344. # - not project specific: i.e "__NOPROJECT__"
  345. # - or specific to the <LY_PROJECT_NAME> project
  346. get_property(target_project_association TARGET ${target} PROPERTY LY_PROJECT_NAME)
  347. foreach(project ${enable_gem_projects})
  348. if (target_project_association AND
  349. (NOT (project STREQUAL "__NOPROJECT__") AND NOT (project STREQUAL target_project_association)))
  350. # Skip adding the gem dependencies to this target if it is associated with a project
  351. # and the current project doesn't match
  352. continue()
  353. endif()
  354. get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project}")
  355. if (NOT gem_dependencies)
  356. get_property(gem_dependencies_defined GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project}" DEFINED)
  357. if (gem_dependencies_defined)
  358. # special case, if the LY_DELAYED_ENABLE_GEMS_"${project_target_variant}" property is DEFINED
  359. # but empty, add an entry to the LY_DELAYED_LOAD_DEPENDENCIES to have the
  360. # cmake_dependencies.*.setreg file for the (project, target) tuple to be regenerated
  361. # This is needed if the ENABLED_GEMS list for a project goes from >0 to 0. In this case
  362. # the cmake_dependencies would have a stale list of gems to load unless it is regenerated
  363. foreach(variant IN LISTS target_gem_variants)
  364. get_property(delayed_load_target_set GLOBAL PROPERTY LY_DELAYED_LOAD_"${project},${target},${variant}" SET)
  365. if(NOT delayed_load_target_set)
  366. set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_DEPENDENCIES "${project},${target},${variant}")
  367. set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_"${project},${target},${variant}" "")
  368. endif()
  369. endforeach()
  370. endif()
  371. # Continue to the next iteration loop regardless as there are no gem dependencies
  372. continue()
  373. endif()
  374. # Gather the Gem variants associated with this target and iterate over them to combine them with the enabled
  375. # gems for the each project
  376. foreach(variant IN LISTS target_gem_variants)
  377. ly_add_gem_dependencies_to_project_variants(
  378. PROJECT_NAME ${project}
  379. TARGET ${target}
  380. VARIANT ${variant}
  381. GEM_DEPENDENCIES ${gem_dependencies})
  382. endforeach()
  383. endforeach()
  384. endforeach()
  385. endfunction()