3rdParty.cmake 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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. set(O3DE_RADEON_GPU_ANALYZER_ENABLED FALSE CACHE BOOL "Whether to download Radeon GPU Analyzer from Github.")
  9. define_property(TARGET PROPERTY LY_SYSTEM_LIBRARY
  10. BRIEF_DOCS "Defines a 3rdParty library as a system library"
  11. FULL_DOCS [[
  12. Property which is set on third party targets that should be considered
  13. as provided by the system. Such targets are excluded from the runtime
  14. dependencies considerations, and are not distributed as part of the
  15. O3DE SDK package. Instead, users of the SDK are expected to install
  16. such a third party library themselves.
  17. ]]
  18. )
  19. # Do not overcomplicate searching for the 3rdParty path, if it is not easy to find,
  20. # the user should define it.
  21. #! get_default_third_party_folder: Stores the default 3rdParty directory into the supplied output variable
  22. #
  23. # \arg:output_third_party_path name of variable to set the default project directory into
  24. # It defaults to the ~/.o3de/3rdParty directory
  25. function(get_default_third_party_folder output_third_party_path)
  26. # 1. Highest priority, cache variable, that will override the value of any of the cases below
  27. # 2. if defined in an env variable, take it from there
  28. if(DEFINED ENV{LY_3RDPARTY_PATH})
  29. set(${output_third_party_path} $ENV{LY_3RDPARTY_PATH} PARENT_SCOPE)
  30. return()
  31. endif()
  32. # 3. If defined in the o3de_manifest.json, take it from there
  33. cmake_path(SET home_directory "$ENV{USERPROFILE}") # Windows
  34. if(NOT EXISTS ${home_directory})
  35. cmake_path(SET home_directory "$ENV{HOME}") # Unix
  36. if (NOT EXISTS ${home_directory})
  37. return()
  38. endif()
  39. endif()
  40. set(manifest_path ${home_directory}/.o3de/o3de_manifest.json)
  41. if(EXISTS ${manifest_path})
  42. file(READ ${manifest_path} manifest_json)
  43. string(JSON default_third_party_folder ERROR_VARIABLE json_error GET ${manifest_json} default_third_party_folder)
  44. if(NOT json_error)
  45. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${manifest_path})
  46. set(${output_third_party_path} ${default_third_party_folder} PARENT_SCOPE)
  47. return()
  48. endif()
  49. endif()
  50. # 4. Lowest priority, use the home directory as the location for 3rdparty
  51. set(${output_third_party_path} ${home_directory}/.o3de/3rdParty PARENT_SCOPE)
  52. endfunction()
  53. get_default_third_party_folder(o3de_default_third_party_path)
  54. set(LY_3RDPARTY_PATH "${o3de_default_third_party_path}" CACHE PATH "Path to the 3rdParty folder")
  55. if(LY_3RDPARTY_PATH)
  56. file(TO_CMAKE_PATH ${LY_3RDPARTY_PATH} LY_3RDPARTY_PATH)
  57. if(NOT EXISTS ${LY_3RDPARTY_PATH})
  58. file(MAKE_DIRECTORY ${LY_3RDPARTY_PATH})
  59. endif()
  60. endif()
  61. if(NOT EXISTS ${LY_3RDPARTY_PATH})
  62. message(FATAL_ERROR "3rdParty folder: ${LY_3RDPARTY_PATH} does not exist, call cmake defining a valid LY_3RDPARTY_PATH or use cmake-gui to configure it")
  63. endif()
  64. #! ly_add_external_target_path: adds a path to module path so 3rdparty Find files can be added from paths different than cmake/3rdParty
  65. #
  66. # \arg:PATH path to add
  67. #
  68. function(ly_add_external_target_path PATH)
  69. list(APPEND CMAKE_MODULE_PATH ${PATH})
  70. set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE)
  71. set_property(GLOBAL APPEND PROPERTY LY_ADDITIONAL_MODULE_PATH ${PATH})
  72. endfunction()
  73. #! ly_add_external_target: adds a library interface that exposes external libraries to be used as cmake dependencies.
  74. #
  75. # \arg:NAME name of the external library
  76. # \arg:VERSION version of the external library. Location will be defined by 3rdPartyPath/NAME/VERSION
  77. # \arg:3RDPARTY_DIRECTORY overrides the path to use when searching in the 3rdPartyPath (instead of NAME).
  78. # If not indicated, PACKAGE will be used, if not indicated, NAME will be used.
  79. # \arg:3RDPARTY_ROOT_DIRECTORY overrides the root path to the external library directory. This will be used instead of ${LY_3RDPARTY_PATH}.
  80. # \arg:INCLUDE_DIRECTORIES include folders (relative to the root path where the external library is: ${LY_3RDPARTY_PATH}/${NAME}/${VERSION})
  81. # \arg:PACKAGE if defined, defines the name of the external library "package". This is used when a package exposes multiple interfaces
  82. # if not defined, NAME is used
  83. # \arg:COMPILE_DEFINITIONS compile definitions to be added to the interface
  84. # \arg:BUILD_DEPENDENCIES list of interfaces this target depends on (could be a compilation dependency if the dependency is only
  85. # exposing an include path, or could be a linking dependency is exposing a lib)
  86. # \arg:RUNTIME_DEPENDENCIES list of files this target depends on (could be a dynamic libraries, text files, executables,
  87. # applications, other 3rdParty targets, etc)
  88. # \arg:OUTPUT_SUBDIRECTORY Subdirectory within bin/<Profile/Debug>/ where the ${PACKAGE_AND_NAME}_RUNTIME_DEPENDENCIES exported by the target will be copied to.
  89. # If not specified, then the ${PACKAGE_AND_NAME}_RUNTIME_DEPENDENCIES will be copied directly under bin/<Profile/Debug>/.
  90. # Each file listed in runtime dependencies can also customize its own output subfolder
  91. # by adding "\n<subfolder path>" at the end of each listed file. OUTPUT_SUBDIRECTORY only works
  92. # if such customized subfolder per file is NOT specified.
  93. # Examples:
  94. # 1- If there are 5 files listed in ${PACKAGE_AND_NAME}_RUNTIME_DEPENDENCIES, and all of them
  95. # should be copied to the same output subfolder named "My/Output/Subfolder" then it is advisable
  96. # to set OUTPUT_SUBDIRECTORY to "My/Output/Subfolder" instead of appending: "\nMy/Output/Subfolder"
  97. # at the end of each listed file.
  98. # 2- Assume there are 2 files listed in ${PACKAGE_AND_NAME}_RUNTIME_DEPENDENCIES, "fileA" must go to
  99. # subdirectory "My/Output/Subfolder/lib" and "fileB" must go to subdirectory "My/Output/Subfolder/bin".
  100. # In this case OUTPUT_SUBDIRECTORY should NOT be used, instead the files can be listed as:
  101. # "fileA\nMy/Output/Subfolder/lib"
  102. # "fileB\nMy/Output/Subfolder/bin"
  103. #
  104. # \arg:SYSTEM If specified, the library is considered a system library, and is not copied to the build output directory
  105. function(ly_add_external_target)
  106. set(options SYSTEM)
  107. set(oneValueArgs NAME VERSION 3RDPARTY_DIRECTORY PACKAGE 3RDPARTY_ROOT_DIRECTORY OUTPUT_SUBDIRECTORY)
  108. set(multiValueArgs HEADER_CHECK COMPILE_DEFINITIONS INCLUDE_DIRECTORIES BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES)
  109. cmake_parse_arguments(ly_add_external_target "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  110. # Validate input arguments
  111. if(NOT ly_add_external_target_NAME)
  112. message(FATAL_ERROR "You must provide a name for the 3rd party library")
  113. endif()
  114. if(NOT ly_add_external_target_PACKAGE)
  115. set(ly_add_external_target_PACKAGE ${ly_add_external_target_NAME})
  116. set(PACKAGE_AND_NAME "${ly_add_external_target_NAME}")
  117. set(NAME_WITH_NAMESPACE "${ly_add_external_target_NAME}")
  118. set(has_package FALSE)
  119. else()
  120. set(PACKAGE_AND_NAME "${ly_add_external_target_PACKAGE}_${ly_add_external_target_NAME}")
  121. set(NAME_WITH_NAMESPACE "${ly_add_external_target_PACKAGE}::${ly_add_external_target_NAME}")
  122. set(has_package TRUE)
  123. endif()
  124. string(TOUPPER ${PACKAGE_AND_NAME} PACKAGE_AND_NAME)
  125. string(TOUPPER ${ly_add_external_target_PACKAGE} PACKAGE)
  126. if(NOT TARGET 3rdParty::${NAME_WITH_NAMESPACE})
  127. if(NOT DEFINED ly_add_external_target_VERSION AND NOT VERSION IN_LIST ly_add_external_target_KEYWORDS_MISSING_VALUES)
  128. message(FATAL_ERROR "You must provide a version of the \"${ly_add_external_target_PACKAGE}\" 3rd party library")
  129. endif()
  130. if(NOT ly_add_external_target_3RDPARTY_ROOT_DIRECTORY)
  131. if(NOT ly_add_external_target_3RDPARTY_DIRECTORY)
  132. if(ly_add_external_target_PACKAGE)
  133. set(ly_add_external_target_3RDPARTY_DIRECTORY ${ly_add_external_target_PACKAGE})
  134. else()
  135. set(ly_add_external_target_3RDPARTY_DIRECTORY ${ly_add_external_target_NAME})
  136. endif()
  137. endif()
  138. set(BASE_PATH "${LY_3RDPARTY_PATH}/${ly_add_external_target_3RDPARTY_DIRECTORY}")
  139. else()
  140. # only install external 3rdParty that are within the source tree
  141. cmake_path(IS_PREFIX LY_ROOT_FOLDER ${ly_add_external_target_3RDPARTY_ROOT_DIRECTORY} NORMALIZE is_in_source_tree)
  142. if(is_in_source_tree)
  143. ly_install_external_target(${ly_add_external_target_3RDPARTY_ROOT_DIRECTORY})
  144. endif()
  145. set(BASE_PATH "${ly_add_external_target_3RDPARTY_ROOT_DIRECTORY}")
  146. endif()
  147. if(ly_add_external_target_VERSION)
  148. set(BASE_PATH "${BASE_PATH}/${ly_add_external_target_VERSION}")
  149. endif()
  150. # Setting BASE_PATH variable in the parent scope to allow for the Find<3rdParty>.cmake scripts to use them
  151. set(BASE_PATH ${BASE_PATH} PARENT_SCOPE)
  152. add_library(3rdParty::${NAME_WITH_NAMESPACE} INTERFACE IMPORTED GLOBAL)
  153. if(ly_add_external_target_INCLUDE_DIRECTORIES)
  154. list(TRANSFORM ly_add_external_target_INCLUDE_DIRECTORIES PREPEND ${BASE_PATH}/)
  155. foreach(include_path ${ly_add_external_target_INCLUDE_DIRECTORIES})
  156. if(NOT EXISTS ${include_path})
  157. message(FATAL_ERROR "Cannot find include path ${include_path} for 3rdParty::${NAME_WITH_NAMESPACE}")
  158. endif()
  159. endforeach()
  160. ly_target_include_system_directories(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  161. INTERFACE ${ly_add_external_target_INCLUDE_DIRECTORIES}
  162. )
  163. endif()
  164. # Check if there is a pal file
  165. o3de_pal_dir(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}")
  166. if(NOT EXISTS ${pal_file})
  167. set(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
  168. endif()
  169. if(EXISTS ${pal_file})
  170. include(${pal_file})
  171. endif()
  172. if(${PACKAGE_AND_NAME}_INCLUDE_DIRECTORIES)
  173. list(TRANSFORM ${PACKAGE_AND_NAME}_INCLUDE_DIRECTORIES PREPEND ${BASE_PATH}/)
  174. foreach(include_path ${${PACKAGE_AND_NAME}_INCLUDE_DIRECTORIES})
  175. string(GENEX_STRIP ${include_path} include_genex_expr)
  176. if(include_genex_expr STREQUAL include_path AND NOT EXISTS ${include_path}) # Exclude include paths that have generation expressions from validation
  177. message(FATAL_ERROR "Cannot find include path ${include_path} for 3rdParty::${NAME_WITH_NAMESPACE}")
  178. endif()
  179. endforeach()
  180. ly_target_include_system_directories(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  181. INTERFACE ${${PACKAGE_AND_NAME}_INCLUDE_DIRECTORIES}
  182. )
  183. endif()
  184. if(has_package AND ${PACKAGE}_LIBS)
  185. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  186. APPEND PROPERTY
  187. INTERFACE_LINK_LIBRARIES "${${PACKAGE}_LIBS}"
  188. )
  189. endif()
  190. if(${PACKAGE_AND_NAME}_LIBS)
  191. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  192. APPEND PROPERTY
  193. INTERFACE_LINK_LIBRARIES "${${PACKAGE_AND_NAME}_LIBS}"
  194. )
  195. endif()
  196. if(has_package AND ${PACKAGE}_LINK_OPTIONS)
  197. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  198. APPEND PROPERTY
  199. INTERFACE_LINK_OPTIONS "${${PACKAGE}_LINK_OPTIONS}"
  200. )
  201. endif()
  202. if(${PACKAGE_AND_NAME}_LINK_OPTIONS)
  203. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  204. APPEND PROPERTY
  205. INTERFACE_LINK_OPTIONS "${${PACKAGE_AND_NAME}_LINK_OPTIONS}"
  206. )
  207. endif()
  208. if(has_package AND ${PACKAGE}_COMPILE_OPTIONS)
  209. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  210. APPEND PROPERTY
  211. INTERFACE_COMPILE_OPTIONS "${${PACKAGE}_COMPILE_OPTIONS}"
  212. )
  213. endif()
  214. if(${PACKAGE_AND_NAME}_COMPILE_OPTIONS)
  215. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  216. APPEND PROPERTY
  217. INTERFACE_COMPILE_OPTIONS "${${PACKAGE_AND_NAME}_COMPILE_OPTIONS}"
  218. )
  219. endif()
  220. unset(all_dependencies)
  221. if(ly_add_external_target_RUNTIME_DEPENDENCIES)
  222. list(APPEND all_dependencies ${ly_add_external_target_RUNTIME_DEPENDENCIES})
  223. endif()
  224. if(has_package AND ${PACKAGE}_RUNTIME_DEPENDENCIES)
  225. list(APPEND all_dependencies ${${PACKAGE}_RUNTIME_DEPENDENCIES})
  226. endif()
  227. if(${PACKAGE_AND_NAME}_RUNTIME_DEPENDENCIES)
  228. list(APPEND all_dependencies ${${PACKAGE_AND_NAME}_RUNTIME_DEPENDENCIES})
  229. endif()
  230. unset(locations)
  231. unset(manual_dependencies)
  232. if(all_dependencies)
  233. foreach(dependency ${all_dependencies})
  234. if(dependency MATCHES "3rdParty::")
  235. list(APPEND manual_dependencies ${dependency})
  236. else()
  237. if(ly_add_external_target_OUTPUT_SUBDIRECTORY)
  238. string(APPEND dependency "\n${ly_add_external_target_OUTPUT_SUBDIRECTORY}")
  239. endif()
  240. list(APPEND locations ${dependency})
  241. endif()
  242. endforeach()
  243. endif()
  244. if(locations)
  245. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  246. APPEND PROPERTY
  247. INTERFACE_IMPORTED_LOCATION "${locations}"
  248. )
  249. endif()
  250. if(manual_dependencies)
  251. ly_add_dependencies(3rdParty::${NAME_WITH_NAMESPACE} ${manual_dependencies})
  252. endif()
  253. get_property(additional_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_3rdParty::${NAME_WITH_NAMESPACE})
  254. if(additional_dependencies)
  255. ly_add_dependencies(3rdParty::${NAME_WITH_NAMESPACE} ${additional_dependencies})
  256. # Clear the variable so we can track issues in case some dependency is added after
  257. set_property(GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_3rdParty::${NAME_WITH_NAMESPACE})
  258. endif()
  259. if(ly_add_external_target_COMPILE_DEFINITIONS)
  260. target_compile_definitions(3rdParty::${NAME_WITH_NAMESPACE}
  261. INTERFACE ${ly_add_external_target_COMPILE_DEFINITIONS}
  262. )
  263. endif()
  264. if(has_package AND ${PACKAGE}_COMPILE_DEFINITIONS)
  265. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  266. APPEND PROPERTY
  267. INTERFACE_COMPILE_DEFINITIONS "${${PACKAGE}_COMPILE_DEFINITIONS}"
  268. )
  269. endif()
  270. if(${PACKAGE_AND_NAME}_COMPILE_DEFINITIONS)
  271. set_property(TARGET 3rdParty::${NAME_WITH_NAMESPACE}
  272. APPEND PROPERTY
  273. INTERFACE_COMPILE_DEFINITIONS "${${PACKAGE_AND_NAME}_COMPILE_DEFINITIONS}"
  274. )
  275. endif()
  276. if(has_package AND ${PACKAGE}_BUILD_DEPENDENCIES)
  277. list(APPEND ly_add_external_target_BUILD_DEPENDENCIES "${${PACKAGE}_BUILD_DEPENDENCIES}")
  278. list(REMOVE_DUPLICATES ly_add_external_target_BUILD_DEPENDENCIES)
  279. endif()
  280. if(${PACKAGE_AND_NAME}_BUILD_DEPENDENCIES)
  281. list(APPEND ly_add_external_target_BUILD_DEPENDENCIES "${${PACKAGE_AND_NAME}_BUILD_DEPENDENCIES}")
  282. list(REMOVE_DUPLICATES ly_add_external_target_BUILD_DEPENDENCIES)
  283. endif()
  284. # Interface dependencies may require to find_packages. So far, we are just using packages for 3rdParty, so we will
  285. # search for those and automatically bring those packages. The naming convention used is 3rdParty::PackageName::OptionalInterface
  286. foreach(dependency ${ly_add_external_target_BUILD_DEPENDENCIES})
  287. string(REPLACE "::" ";" dependency_list ${dependency})
  288. list(GET dependency_list 0 dependency_namespace)
  289. if(${dependency_namespace} STREQUAL "3rdParty")
  290. list(GET dependency_list 1 dependency_package)
  291. ly_download_associated_package(${dependency_package})
  292. find_package(${dependency_package} REQUIRED MODULE)
  293. endif()
  294. endforeach()
  295. if(ly_add_external_target_BUILD_DEPENDENCIES)
  296. target_link_libraries(3rdParty::${NAME_WITH_NAMESPACE}
  297. INTERFACE
  298. ${ly_add_external_target_BUILD_DEPENDENCIES}
  299. )
  300. endif()
  301. if(ly_add_external_target_SYSTEM)
  302. set_target_properties(3rdParty::${NAME_WITH_NAMESPACE} PROPERTIES LY_SYSTEM_LIBRARY TRUE)
  303. endif()
  304. endif()
  305. endfunction()
  306. #! ly_install_external_target: external libraries which are not part of 3rdParty need to be installed
  307. #
  308. # \arg:3RDPARTY_ROOT_DIRECTORY custom 3rd party directory which needs to be installed
  309. function(ly_install_external_target 3RDPARTY_ROOT_DIRECTORY)
  310. # Install the Find file to our <install_location>/cmake/3rdParty directory
  311. ly_install_files(FILES ${CMAKE_CURRENT_LIST_FILE}
  312. DESTINATION cmake/3rdParty
  313. )
  314. ly_install_directory(DIRECTORIES "${3RDPARTY_ROOT_DIRECTORY}")
  315. endfunction()
  316. # Add the 3rdParty folder to find the modules
  317. list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/3rdParty)
  318. o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}")
  319. list(APPEND CMAKE_MODULE_PATH ${pal_dir})
  320. if(NOT INSTALLED_ENGINE)
  321. # Add the 3rdParty cmake files to the IDE
  322. ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake)
  323. o3de_pal_dir(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}")
  324. ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake)
  325. if(O3DE_RADEON_GPU_ANALYZER_ENABLED)
  326. include(cmake/3rdParty/FetchRGA.cmake)
  327. endif()
  328. endif()