EngineFinder.cmake 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. # {BEGIN_LICENSE}
  2. #
  3. # Copyright (c) Contributors to the Open 3D Engine Project.
  4. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  5. #
  6. # SPDX-License-Identifier: Apache-2.0 OR MIT
  7. #
  8. #
  9. # {END_LICENSE}
  10. # Edits to this file may be lost in upgrades. Instead of changing this file, use
  11. # the 'engine_finder_cmake_path' key in your project.json or user/project.json to specify
  12. # an alternate .cmake file to use instead of this one.
  13. include_guard()
  14. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/project.json)
  15. # Option 1: Use engine manually set in CMAKE_MODULE_PATH
  16. # CMAKE_MODULE_PATH must contain a path to an engine's cmake folder
  17. if(CMAKE_MODULE_PATH)
  18. foreach(module_path ${CMAKE_MODULE_PATH})
  19. cmake_path(SET module_engine_version_cmake_path "${module_path}/o3deConfigVersion.cmake")
  20. if(EXISTS "${module_engine_version_cmake_path}")
  21. include("${module_engine_version_cmake_path}")
  22. if(PACKAGE_VERSION_COMPATIBLE)
  23. message(STATUS "Selecting engine from CMAKE_MODULE_PATH '${module_path}'")
  24. return()
  25. else()
  26. message(WARNING "Not using engine from CMAKE_MODULE_PATH '${module_path}' because it is not compatible with this project.")
  27. endif()
  28. endif()
  29. endforeach()
  30. message(VERBOSE "No compatible engine found from CMAKE_MODULE_PATH '${CMAKE_MODULE_PATH}'.")
  31. endif()
  32. # Option 2: Use the engine from the 'engine_path' field in <project>/user/project.json
  33. cmake_path(SET O3DE_USER_PROJECT_JSON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/user/project.json)
  34. if(EXISTS "${O3DE_USER_PROJECT_JSON_PATH}")
  35. file(READ "${O3DE_USER_PROJECT_JSON_PATH}" user_project_json)
  36. if(user_project_json)
  37. string(JSON user_project_engine_path ERROR_VARIABLE json_error GET ${user_project_json} engine_path)
  38. if(user_project_engine_path AND NOT json_error)
  39. cmake_path(SET user_engine_version_cmake_path "${user_project_engine_path}/cmake/o3deConfigVersion.cmake")
  40. if(EXISTS "${user_engine_version_cmake_path}")
  41. include("${user_engine_version_cmake_path}")
  42. if(PACKAGE_VERSION_COMPATIBLE)
  43. message(STATUS "Selecting engine '${user_project_engine_path}' from 'engine_path' in '<project>/user/project.json'.")
  44. list(APPEND CMAKE_MODULE_PATH "${user_project_engine_path}/cmake")
  45. return()
  46. else()
  47. message(FATAL_ERROR "The engine at '${user_project_engine_path}' from 'engine_path' in '${O3DE_USER_PROJECT_JSON_PATH}' is not compatible with this project. Please register this project with a compatible engine, or remove the local override by running:\nscripts\\o3de edit-project-properties -pp ${CMAKE_CURRENT_SOURCE_DIR} --user --engine-path \"\"")
  48. endif()
  49. else()
  50. message(FATAL_ERROR "This project cannot use the engine at '${user_project_engine_path}' because the version cmake file '${user_engine_version_cmake_path}' needed to check compatibility is missing. \nPlease register this project with a compatible engine, or remove the local override by running:\nscripts\\o3de edit-project-properties -pp ${CMAKE_CURRENT_SOURCE_DIR} --user --engine-path \"\"\nIf you want this project to use an older engine(not recommended), provide a custom EngineFinder.cmake using the o3de CLI's --engine-finder-cmake-path option. ")
  51. endif()
  52. elseif(json_error AND ${user_project_engine_path} STREQUAL "NOTFOUND")
  53. # When the value is just NOTFOUND that means there is a JSON
  54. # parsing error, and not simply a missing key
  55. message(FATAL_ERROR "Unable to read 'engine_path' from '${user_project_engine_path}'\nError: ${json-error}")
  56. endif()
  57. endif()
  58. endif()
  59. # Option 3: Find a compatible engine registered in ~/.o3de/o3de_manifest.json
  60. if(DEFINED ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE})
  61. set(manifest_path $ENV{USERPROFILE}/.o3de/o3de_manifest.json) # Windows
  62. else()
  63. set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix
  64. endif()
  65. set(registration_error [=[
  66. To enable more verbose logging, run the cmake command again with '--log-level VERBOSE'
  67. Engine registration is required before configuring a project.
  68. Run 'scripts/o3de register --this-engine' from the engine root.
  69. ]=])
  70. # Create a list of all engines
  71. if(EXISTS ${manifest_path})
  72. file(READ ${manifest_path} manifest_json)
  73. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${manifest_path})
  74. string(JSON engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines)
  75. if(json_error)
  76. message(FATAL_ERROR "Unable to read key 'engines' from '${manifest_path}'\nError: ${json_error}\n${registration_error}")
  77. endif()
  78. string(JSON engines_type ERROR_VARIABLE json_error TYPE ${manifest_json} engines)
  79. if(json_error OR NOT ${engines_type} STREQUAL "ARRAY")
  80. message(FATAL_ERROR "Type of 'engines' in '${manifest_path}' is not a JSON ARRAY\nError: ${json_error}\n${registration_error}")
  81. endif()
  82. math(EXPR engines_count "${engines_count}-1")
  83. foreach(array_index RANGE ${engines_count})
  84. string(JSON manifest_engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines "${array_index}")
  85. if(json_error)
  86. message(FATAL_ERROR "Unable to read 'engines/${array_index}' from '${manifest_path}'\nError: ${json_error}\n${registration_error}")
  87. endif()
  88. list(APPEND O3DE_ENGINE_PATHS ${manifest_engine_path})
  89. endforeach()
  90. elseif(NOT CMAKE_MODULE_PATH)
  91. message(FATAL_ERROR "O3DE Manifest file not found at '${manifest_path}'.\n${registration_error}")
  92. endif()
  93. # We cannot just run find_package() on the list of engine paths because
  94. # CMAKE_FIND_PACKAGE_SORT_ORDER sorts based on file name and chooses
  95. # the first package that returns PACKAGE_VERSION_COMPATIBLE
  96. set(O3DE_MOST_COMPATIBLE_ENGINE_PATH "")
  97. set(O3DE_MOST_COMPATIBLE_ENGINE_VERSION "")
  98. foreach(manifest_engine_path IN LISTS O3DE_ENGINE_PATHS)
  99. # Does this engine have a config version cmake file?
  100. cmake_path(SET version_cmake_path "${manifest_engine_path}/cmake/o3deConfigVersion.cmake")
  101. if(NOT EXISTS "${version_cmake_path}")
  102. message(VERBOSE "Ignoring '${manifest_engine_path}' because no config version cmake file was found at '${version_cmake_path}'")
  103. continue()
  104. endif()
  105. unset(PACKAGE_VERSION)
  106. unset(PACKAGE_VERSION_COMPATIBLE)
  107. include("${version_cmake_path}")
  108. # Follow the version checking convention from find_package(CONFIG)
  109. if(PACKAGE_VERSION_COMPATIBLE)
  110. if(NOT O3DE_MOST_COMPATIBLE_ENGINE_PATH)
  111. set(O3DE_MOST_COMPATIBLE_ENGINE_PATH "${manifest_engine_path}")
  112. set(O3DE_MOST_COMPATIBLE_ENGINE_VERSION ${PACKAGE_VERSION})
  113. message(VERBOSE "Found compatible engine '${manifest_engine_path}' with version '${PACKAGE_VERSION}'")
  114. elseif(${PACKAGE_VERSION} VERSION_GREATER ${O3DE_MOST_COMPATIBLE_ENGINE_VERSION})
  115. set(O3DE_MOST_COMPATIBLE_ENGINE_PATH "${manifest_engine_path}")
  116. set(O3DE_MOST_COMPATIBLE_ENGINE_VERSION ${PACKAGE_VERSION})
  117. message(VERBOSE "Found more compatible engine '${manifest_engine_path}' with version '${PACKAGE_VERSION}' because it has a greater version number.")
  118. else()
  119. message(VERBOSE "Not using engine '${manifest_engine_path}' with version '${PACKAGE_VERSION}' because it doesn't have a greater version number or has a different engine name.")
  120. endif()
  121. else()
  122. message(VERBOSE "Ignoring '${manifest_engine_path}' because it is not a compatible engine.")
  123. endif()
  124. endforeach()
  125. if(O3DE_MOST_COMPATIBLE_ENGINE_PATH)
  126. message(STATUS "Selecting engine '${O3DE_MOST_COMPATIBLE_ENGINE_PATH}'")
  127. # Make sure PACKAGE_VERSION_COMPATIBLE is set so Findo3de.cmake knows
  128. # compatibility was checked
  129. set(PACKAGE_VERSION_COMPATIBLE True)
  130. set(PACKAGE_VERSION O3DE_MOST_COMPATIBLE_ENGINE_VERSION)
  131. list(APPEND CMAKE_MODULE_PATH "${O3DE_MOST_COMPATIBLE_ENGINE_PATH}/cmake")
  132. return()
  133. endif()
  134. # No compatible engine was found.
  135. # Read the 'engine' field in project.json or user/project.json for more helpful messages
  136. if(user_project_json)
  137. string(JSON user_project_engine ERROR_VARIABLE json_error GET ${user_project_json} engine)
  138. endif()
  139. if(NOT user_project_engine)
  140. file(READ ${CMAKE_CURRENT_SOURCE_DIR}/project.json o3de_project_json)
  141. string(JSON project_engine ERROR_VARIABLE json_error GET ${o3de_project_json} engine)
  142. if(json_error AND ${project_engine} STREQUAL "NOTFOUND")
  143. message(FATAL_ERROR "Unable to read key 'engine' from 'project.json'\nError: ${json_error}")
  144. endif()
  145. endif()
  146. if(user_project_engine)
  147. message(FATAL_ERROR "The local '${O3DE_USER_PROJECT_JSON_PATH}' engine is '${user_project_engine}' but no compatible engine with that name and version was found. Please register the compatible engine, or remove the local engine override.\n${registration_error}")
  148. elseif(project_engine)
  149. message(FATAL_ERROR "The project.json engine is '${project_engine}' but no engine with that name and version was found.\n${registration_error}")
  150. else()
  151. set(project_registration_error [=[
  152. Project registration is required before configuring a project.
  153. Run 'scripts/o3de register -pp PROJECT_PATH --engine-path ENGINE_PATH' from the engine root.
  154. ]=])
  155. message(FATAL_ERROR "${project_registration_error}")
  156. endif()