PAL.cmake 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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. # PAL allows us to deal with platforms in a flexible way. In order to do that, we need
  9. # to be able to refer to the current platform in a generic way.
  10. # This cmake file provides variables and configurations for the current platform
  11. #
  12. # Variables:
  13. # PAL_PLATFORM_NAME: name of the platform (regular usage)
  14. # PAL_PLATFORM_NAME_LOWERCASE: name of the platform in lower case (part of filenames)
  15. #
  16. #! o3de_get_home_path: returns the home path
  17. #
  18. # \arg:o3de_manifest_path returns the path of the manifest
  19. function(o3de_get_home_path o3de_home_path)
  20. # The o3de_manifest.json is in the home directory / .o3de folder
  21. file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_path) # Windows
  22. if(NOT EXISTS ${home_path})
  23. file(TO_CMAKE_PATH "$ENV{HOME}" home_path) # Unix
  24. if (NOT EXISTS ${home_path})
  25. message(FATAL_ERROR "o3de Home path not found")
  26. endif()
  27. endif()
  28. set(${o3de_home_path} ${home_path} PARENT_SCOPE)
  29. endfunction()
  30. #! o3de_get_manifest_path: returns the path to the manifest
  31. #
  32. # \arg:o3de_manifest_path returns the path of the manifest
  33. function(o3de_get_manifest_path o3de_manifest_path)
  34. # The o3de_manifest.json is in the home directory / .o3de folder
  35. o3de_get_home_path(o3de_home_path)
  36. set(${o3de_manifest_path} ${o3de_home_path}/.o3de/o3de_manifest.json PARENT_SCOPE)
  37. endfunction()
  38. #! o3de_read_manifest: returns the contents of the manifest
  39. #
  40. # \arg:restricted_subdirs returns the restricted elements from the manifest
  41. function(o3de_read_manifest o3de_manifest_json_data)
  42. #get the manifest path
  43. o3de_get_manifest_path(o3de_manifest_path)
  44. if(EXISTS ${o3de_manifest_path})
  45. ly_file_read(${o3de_manifest_path} json_data)
  46. set(${o3de_manifest_json_data} ${json_data} PARENT_SCOPE)
  47. endif()
  48. endfunction()
  49. #! o3de_find_gem_with_registered_external_subdirs: Query the path of a gem using its name
  50. # IMPORTANT NOTE: This does not take into account any gem versions or dependency resolution,
  51. # which is fine if you don't need it and just want speed.
  52. # \arg:gem_name the gem name to find
  53. # \arg:output_gem_path the path of the gem to set
  54. # \arg:registered_external_subdirs a list of external subdirectories registered accross
  55. # all manifest files to look for gems
  56. function(o3de_find_gem_with_registered_external_subdirs gem_name output_gem_path registered_external_subdirs)
  57. foreach(external_subdir IN LISTS registered_external_subdirs)
  58. set(candidate_gem_path ${external_subdir}/gem.json)
  59. if(EXISTS ${candidate_gem_path})
  60. o3de_read_json_key(gem_json_name ${candidate_gem_path} "gem_name")
  61. if(gem_json_name STREQUAL gem_name)
  62. set(${output_gem_path} ${external_subdir} PARENT_SCOPE)
  63. return()
  64. endif()
  65. endif()
  66. endforeach()
  67. endfunction()
  68. #! o3de_find_gem: Query the path of a gem using its name
  69. #
  70. # \arg:gem_name the gem name to find
  71. # \arg:output_gem_path the path of the gem to set
  72. #
  73. # If the list of registered external subdirectories are available in the caller,
  74. # then slightly better more performance can be achieved by calling `o3de_find_gem_with_registered_external_subdirs` above
  75. function(o3de_find_gem gem_name output_gem_path)
  76. get_all_external_subdirectories(registered_external_subdirs)
  77. o3de_find_gem_with_registered_external_subdirs(${gem_name} gem_path "${registered_external_subdirs}")
  78. set(${output_gem_path} ${gem_path} PARENT_SCOPE)
  79. endfunction()
  80. #! o3de_manifest_restricted: returns the manifests restricted paths
  81. #
  82. # \arg:restricted returns the restricted elements from the manifest
  83. function(o3de_manifest_restricted restricted)
  84. #read the manifest
  85. o3de_read_manifest(o3de_manifest_json_data)
  86. string(JSON restricted_count ERROR_VARIABLE json_error LENGTH ${o3de_manifest_json_data} "restricted")
  87. if(json_error)
  88. # Restricted fields can never be a requirement so no warning is issued
  89. return()
  90. endif()
  91. if(restricted_count GREATER 0)
  92. math(EXPR restricted_range "${restricted_count}-1")
  93. foreach(restricted_index RANGE ${restricted_range})
  94. string(JSON restricted_entry ERROR_VARIABLE json_error GET ${o3de_manifest_json_data} "restricted" "${restricted_index}")
  95. list(APPEND restricted_entries ${restricted_entry})
  96. endforeach()
  97. endif()
  98. set(${restricted} ${restricted_entries} PARENT_SCOPE)
  99. endfunction()
  100. #! o3de_json_restricted: returns the restricted element from a json
  101. #
  102. # \arg:restricted returns the restricted element of the json
  103. function(o3de_json_restricted json_path restricted)
  104. if(EXISTS ${json_path})
  105. ly_file_read(${json_path} json_data)
  106. string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} "restricted")
  107. if(json_error)
  108. # Restricted fields can never be a requirement so no warning is issued
  109. return()
  110. endif()
  111. set(${restricted} ${restricted_entry} PARENT_SCOPE)
  112. endif()
  113. endfunction()
  114. #! o3de_restricted_id: determines the restricted object for this json
  115. #
  116. # Find this objects restricted name. If the object has a "restricted" element
  117. # If it does not have one it inherits its parents "restricted" element if it has one
  118. # If the parent does not have one it inherits its parents parent "restricted" element is it has one and so on...
  119. # We stop looking if the object or parent is in the manifest, as the manifest only has top level objects
  120. # which means they have no children.
  121. #
  122. # \arg:o3de_json_file name of the o3de json file to read the "restricted" key from
  123. # \arg:restricted returns the restricted association element from an o3de json, otherwise its doesnt change anything
  124. # \arg:o3de_json_file name of the o3de json file
  125. function(o3de_restricted_id o3de_json_file restricted parent_relative_path)
  126. # read the passed in o3de json and see if "restricted" is set
  127. o3de_json_restricted(${o3de_json_file} restricted_name)
  128. if(restricted_name)
  129. set(${parent_relative_path} "" PARENT_SCOPE)
  130. set(${restricted} ${restricted_name} PARENT_SCOPE)
  131. return()
  132. endif()
  133. # This object did not have a "restricted" set, now we must look at the parent
  134. # Stop if this is a top level object
  135. o3de_manifest_restricted(manifest_restricted_paths)
  136. cmake_path(GET o3de_json_file PARENT_PATH o3de_json_file_parent)
  137. cmake_path(GET o3de_json_file_parent FILENAME relative_path)
  138. cmake_path(GET o3de_json_file_parent PARENT_PATH o3de_json_file_parent)
  139. if(${o3de_json_file_parent} IN_LIST manifest_restricted_paths)
  140. set(${parent_relative_path} "" PARENT_SCOPE)
  141. set(${restricted} "" PARENT_SCOPE)
  142. return()
  143. endif()
  144. set(is_prev_path_segment TRUE)
  145. while(is_prev_path_segment)
  146. if(EXISTS ${o3de_json_file_parent}/engine.json)
  147. o3de_json_restricted(${o3de_json_file_parent}/engine.json restricted_name)
  148. if(restricted_name)
  149. set(${parent_relative_path} ${relative_path} PARENT_SCOPE)
  150. set(${restricted} ${restricted_name} PARENT_SCOPE)
  151. return()
  152. endif()
  153. endif()
  154. if(EXISTS ${o3de_json_file_parent}/project.json)
  155. o3de_json_restricted(${o3de_json_file_parent}/project.json restricted_name)
  156. if(restricted_name)
  157. set(${parent_relative_path} ${relative_path} PARENT_SCOPE)
  158. set(${restricted} ${restricted_name} PARENT_SCOPE)
  159. return()
  160. endif()
  161. endif()
  162. if(EXISTS ${o3de_json_file_parent}/gem.json)
  163. o3de_json_restricted(${o3de_json_file_parent}/gem.json restricted_name)
  164. if(restricted_name)
  165. set(${parent_relative_path} ${relative_path} PARENT_SCOPE)
  166. set(${restricted} ${restricted_name} PARENT_SCOPE)
  167. return()
  168. endif()
  169. endif()
  170. if(${o3de_json_file_parent} IN_LIST manifest_restricted_paths)
  171. set(${parent_relative_path} "" PARENT_SCOPE)
  172. set(${restricted} "" PARENT_SCOPE)
  173. return()
  174. endif()
  175. # Remove one path segment from the end of the o3de json candidate path
  176. cmake_path(GET o3de_json_file_parent PARENT_PATH parent_path)
  177. cmake_path(GET o3de_json_file_parent FILENAME path_segment)
  178. cmake_path(COMPARE "${o3de_json_file_parent}" NOT_EQUAL "${parent_path}" is_prev_path_segment)
  179. cmake_path(SET o3de_json_file_parent "${parent_path}")
  180. cmake_path(SET relative_path "${path_segment}/${relative_path}")
  181. endwhile()
  182. endfunction()
  183. #! o3de_find_restricted_folder:
  184. #
  185. # \arg:restricted_path returns the path of the o3de restricted folder using the restricted_name
  186. # \arg:restricted_name name of the restricted
  187. function(o3de_find_restricted_folder restricted_name restricted_path)
  188. o3de_manifest_restricted(restricted_entries)
  189. # Iterate over the restricted directories from the manifest file
  190. foreach(restricted_entry ${restricted_entries})
  191. set(restricted_json_file ${restricted_entry}/restricted.json)
  192. ly_file_read(${restricted_json_file} restricted_json)
  193. string(JSON this_restricted_name ERROR_VARIABLE json_error GET ${restricted_json} "restricted_name")
  194. if(json_error)
  195. message(WARNING "Unable to read restricted_name from '${restricted_json_file}', error: ${json_error}")
  196. else()
  197. if(this_restricted_name STREQUAL restricted_name)
  198. set(${restricted_path} ${restricted_entry} PARENT_SCOPE)
  199. return()
  200. endif()
  201. endif()
  202. endforeach()
  203. endfunction()
  204. #! o3de_restricted_path:
  205. #
  206. # \arg:o3de_json_file json file to read restricted id from
  207. # \arg:restricted_path output path of the restricted object
  208. # \arg:parent_relative_path optional output of the path relative to the parent
  209. function(o3de_restricted_path o3de_json_file restricted_path) #parent_relative_path
  210. o3de_restricted_id(${o3de_json_file} restricted_name parent_relative)
  211. if(${ARGC} GREATER 2)
  212. set(${ARGV2} ${parent_relative} PARENT_SCOPE)
  213. endif()
  214. if(restricted_name)
  215. o3de_find_restricted_folder(${restricted_name} restricted_folder)
  216. if(restricted_folder)
  217. set(${restricted_path} ${restricted_folder} PARENT_SCOPE)
  218. else()
  219. get_filename_component(o3de_json_file_parent ${o3de_json_file} DIRECTORY)
  220. set(${restricted_path} ${o3de_json_file_parent}/restricted PARENT_SCOPE)
  221. endif()
  222. endif()
  223. endfunction()
  224. # detect open platforms
  225. file(GLOB detection_files "cmake/Platform/*/PALDetection_*.cmake")
  226. foreach(detection_file ${detection_files})
  227. include(${detection_file})
  228. endforeach()
  229. # set the O3DE_ENGINE_RESTRICTED_PATH
  230. o3de_restricted_path(${LY_ROOT_FOLDER}/engine.json O3DE_ENGINE_RESTRICTED_PATH)
  231. # detect platforms in the restricted path
  232. file(GLOB detection_files ${O3DE_ENGINE_RESTRICTED_PATH}/*/cmake/PALDetection_*.cmake)
  233. foreach(detection_file ${detection_files})
  234. include(${detection_file})
  235. endforeach()
  236. ly_set(PAL_PLATFORM_NAME ${LY_PLATFORM_DETECTION_${CMAKE_SYSTEM_NAME}})
  237. string(TOLOWER ${PAL_PLATFORM_NAME} PAL_PLATFORM_NAME_LOWERCASE)
  238. ly_set(PAL_PLATFORM_NAME_LOWERCASE, ${PAL_PLATFORM_NAME_LOWERCASE})
  239. ly_set(PAL_HOST_PLATFORM_NAME ${LY_HOST_PLATFORM_DETECTION_${CMAKE_SYSTEM_NAME}})
  240. string(TOLOWER ${PAL_HOST_PLATFORM_NAME} PAL_HOST_PLATFORM_NAME_LOWERCASE)
  241. ly_set(PAL_HOST_PLATFORM_NAME_LOWERCASE ${PAL_HOST_PLATFORM_NAME_LOWERCASE})
  242. # In addition to platform name, set the platform architecture if supported
  243. if (LY_ARCHITECTURE_DETECTION_${PAL_PLATFORM_NAME})
  244. ly_set(LY_ARCHITECTURE_NAME_EXTENSION "_${LY_ARCHITECTURE_DETECTION_${PAL_PLATFORM_NAME}}")
  245. endif()
  246. if (LY_HOST_ARCHITECTURE_DETECTION_${PAL_HOST_PLATFORM_NAME})
  247. ly_set(LY_HOST_ARCHITECTURE_NAME_EXTENSION "_${LY_HOST_ARCHITECTURE_DETECTION_${PAL_HOST_PLATFORM_NAME}}")
  248. endif()
  249. set(PAL_RESTRICTED_PLATFORMS)
  250. file(GLOB pal_restricted_files ${O3DE_ENGINE_RESTRICTED_PATH}/*/cmake/PAL_*.cmake)
  251. foreach(pal_restricted_file ${pal_restricted_files})
  252. # Get relative path from restricted root directory
  253. cmake_path(RELATIVE_PATH pal_restricted_file BASE_DIRECTORY ${O3DE_ENGINE_RESTRICTED_PATH} OUTPUT_VARIABLE relative_pal_restricted_file)
  254. # Split relative restricted path into path segments
  255. string(REPLACE "/" ";" pal_restricted_segments ${relative_pal_restricted_file})
  256. # Retrieve the first path segment which should be the restricted platform
  257. list(GET pal_restricted_segments 0 platform)
  258. # Append the new restricted platform
  259. string(TOLOWER ${platform} platform_lower)
  260. list(APPEND PAL_RESTRICTED_PLATFORMS ${platform_lower})
  261. endforeach()
  262. list(REMOVE_DUPLICATES PAL_RESTRICTED_PLATFORMS)
  263. ly_set(PAL_RESTRICTED_PLATFORMS ${PAL_RESTRICTED_PLATFORMS})
  264. function(ly_get_absolute_pal_filename out_name in_name)
  265. message(DEPRECATION "ly_get_list_relative_pal_filename is being deprecated, change your code to use o3de_pal_dir instead.")
  266. # parent relative path is optional
  267. if(${ARGC} GREATER 4)
  268. if(ARGV4)
  269. set(parent_relative_path ${ARGV4})
  270. endif()
  271. endif()
  272. # The Default object path for path is the LY_ROOT_FOLDER
  273. cmake_path(SET object_path NORMALIZE "${LY_ROOT_FOLDER}")
  274. if(${ARGC} GREATER 3)
  275. if(ARGV3)
  276. # The user has supplied an object restricted path, the object path for consideration
  277. cmake_path(SET object_path NORMALIZE ${ARGV3})
  278. endif()
  279. endif()
  280. # The default restricted object path is O3DE_ENGINE_RESTRICTED_PATH
  281. cmake_path(SET object_restricted_path NORMALIZE "${O3DE_ENGINE_RESTRICTED_PATH}")
  282. if(${ARGC} GREATER 2)
  283. if(ARGV3)
  284. # The user has supplied an object restricted path
  285. cmake_path(SET object_restricted_path NORMALIZE ${ARGV2})
  286. endif()
  287. endif()
  288. if(${ARGC} GREATER 4)
  289. o3de_pal_dir(abs_name ${in_name} "${object_restricted_path}" "${object_path}" "${parent_relative_path}")
  290. else()
  291. o3de_pal_dir(abs_name ${in_name} "${object_restricted_path}" "${object_path}")
  292. endif()
  293. set(${out_name} ${abs_name} PARENT_SCOPE)
  294. endfunction()
  295. function(o3de_pal_dir out_name in_name object_restricted_path object_path) #parent_relative_path)
  296. set(full_name ${in_name})
  297. # parent relative path is optional
  298. if(${ARGC} GREATER 4)
  299. set(parent_relative_path ${ARGV4})
  300. endif()
  301. # The input path must not exist in order to form a restricted PAL path
  302. if (NOT EXISTS ${full_name})
  303. # if the file is not in the object path then we cannot determine a PAL file for it
  304. cmake_path(IS_PREFIX object_path ${full_name} is_input_path_in_root)
  305. if(is_input_path_in_root)
  306. cmake_path(RELATIVE_PATH full_name BASE_DIRECTORY ${object_path} OUTPUT_VARIABLE relative_object_path)
  307. cmake_path(SET current_object_path ${relative_object_path})
  308. # Remove one path segment from the end of the current_object_path and prepend it to the list path_segments
  309. cmake_path(GET current_object_path PARENT_PATH parent_path)
  310. cmake_path(GET current_object_path FILENAME path_segment)
  311. list(PREPEND path_segments_visited ${path_segment})
  312. cmake_path(COMPARE "${current_object_path}" NOT_EQUAL "${parent_path}" is_prev_path_segment)
  313. cmake_path(SET current_object_path "${parent_path}")
  314. set(is_prev_path_segment TRUE)
  315. while(is_prev_path_segment)
  316. # Remove one path segment from the end of the current_object_path and prepend it to the list path_segments
  317. cmake_path(GET current_object_path PARENT_PATH parent_path)
  318. cmake_path(GET current_object_path FILENAME path_segment)
  319. cmake_path(COMPARE "${current_object_path}" NOT_EQUAL "${parent_path}" is_prev_path_segment)
  320. cmake_path(SET current_object_path "${parent_path}")
  321. # The Path is in a PAL structure
  322. # Decompose the path into sections before "Platform" and after "Platform"
  323. if(path_segment STREQUAL "Platform")
  324. # The first path segment after the "<pre-platform-paths>/Platform/<post-platform-paths>"
  325. # is a potential platform name. Store it off for later checks
  326. list(GET path_segments_visited 0 candidate_platform_name)
  327. # Store off all the path segments iterated from the end in the post-"Platform" path
  328. cmake_path(APPEND post_platform_paths ${path_segments_visited})
  329. # The parent path is just the pre-"Platform" section of the path
  330. cmake_path(SET pre_platform_paths "${parent_path}")
  331. break()
  332. endif()
  333. list(PREPEND path_segments_visited ${path_segment})
  334. endwhile()
  335. # Compose a candidate restricted path and examine if it exists
  336. cmake_path(APPEND ${pre_platform_paths} "Platform" ${post_platform_paths}
  337. OUTPUT_VARIABLE candidate_PAL_path)
  338. if(NOT EXISTS ${candidate_PAL_path})
  339. string(TOLOWER ${candidate_platform_name} candidate_platform_name_lower)
  340. if("${candidate_platform_name_lower}" IN_LIST PAL_RESTRICTED_PLATFORMS)
  341. cmake_path(APPEND object_restricted_path ${candidate_platform_name} ${parent_relative_path}
  342. ${pre_platform_paths} OUTPUT_VARIABLE candidate_PAL_path)
  343. endif()
  344. endif()
  345. if(EXISTS ${candidate_PAL_path})
  346. cmake_path(SET full_name ${candidate_PAL_path})
  347. endif()
  348. endif()
  349. endif()
  350. cmake_path(ABSOLUTE_PATH full_name BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
  351. set(${out_name} ${full_name} PARENT_SCOPE)
  352. endfunction()
  353. function(ly_get_list_relative_pal_filename out_name in_name)
  354. message(DEPRECATION "ly_get_list_relative_pal_filename is being deprecated, change your code to use o3de_pal_dir instead.")
  355. # parent relative path is optional
  356. if(${ARGC} GREATER 4)
  357. if(ARGV4)
  358. set(parent_relative_path ${ARGV4})
  359. endif()
  360. endif()
  361. # The Default object path for path is the LY_ROOT_FOLDER
  362. cmake_path(SET object_path NORMALIZE "${LY_ROOT_FOLDER}")
  363. if(${ARGC} GREATER 3)
  364. if(ARGV3)
  365. # The user has supplied an object restricted path, the object path for consideration
  366. cmake_path(SET object_path NORMALIZE ${ARGV3})
  367. endif()
  368. endif()
  369. # The default restricted object path is O3DE_ENGINE_RESTRICTED_PATH
  370. cmake_path(SET object_restricted_path NORMALIZE "${O3DE_ENGINE_RESTRICTED_PATH}")
  371. if(${ARGC} GREATER 2)
  372. if(ARGV2)
  373. # The user has supplied an object restricted path
  374. cmake_path(SET object_restricted_path NORMALIZE ${ARGV2})
  375. endif()
  376. endif()
  377. if(${ARGC} GREATER 4)
  378. o3de_pal_dir(abs_name ${in_name} "${object_restricted_path}" "${object_path}" "${parent_relative_path}")
  379. else()
  380. o3de_pal_dir(abs_name ${in_name} "${object_restricted_path}" "${object_path}")
  381. endif()
  382. cmake_path(RELATIVE_PATH abs_name BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE relative_name)
  383. set(${out_name} ${relative_name} PARENT_SCOPE)
  384. endfunction()
  385. o3de_pal_dir(pal_cmake_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}")
  386. ly_include_cmake_file_list(${pal_cmake_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake)
  387. include(${pal_cmake_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  388. include(${pal_cmake_dir}/Toolchain_${PAL_PLATFORM_NAME_LOWERCASE}.cmake OPTIONAL)
  389. set(LY_DISABLE_TEST_MODULES FALSE CACHE BOOL "Option to forcibly disable the inclusion of test targets in the build")
  390. if(LY_DISABLE_TEST_MODULES)
  391. ly_set(PAL_TRAIT_BUILD_TESTS_SUPPORTED FALSE)
  392. endif()