o3deConfigVersion.cmake 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 is included by find_package(o3de CONFIG) and will set PACKAGE_VERSION_COMPATIBLE
  9. # to TRUE or FALSE based on whether the project is compatible with this engine.
  10. # This file also sets PACKAGE_VERSION and PACKAGE_VERSION_EXACT if it can determine
  11. # that information from the engine.json, project.json and <project>/user/project.json.
  12. set(PACKAGE_VERSION_COMPATIBLE FALSE)
  13. set(PACKAGE_VERSION_EXACT FALSE)
  14. # Store the project.json with any overrides from <project>/user/project.json
  15. # in a global property to avoid the performance hit of loading multiple times
  16. # The project's CMake will likely have already set this for us, but just in case
  17. get_property(o3de_project_json GLOBAL PROPERTY O3DE_PROJECT_JSON)
  18. cmake_path(SET O3DE_PROJECT_JSON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/project.json)
  19. if(NOT o3de_project_json)
  20. if(EXISTS ${O3DE_PROJECT_JSON_PATH})
  21. file(READ "${O3DE_PROJECT_JSON_PATH}" o3de_project_json)
  22. # Allow the user to override the 'engine' value in <project>/user/project.json
  23. cmake_path(SET O3DE_USER_PROJECT_JSON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/user/project.json)
  24. if(EXISTS ${O3DE_USER_PROJECT_JSON_PATH})
  25. file(READ "${O3DE_USER_PROJECT_JSON_PATH}" o3de_user_project_json)
  26. string(JSON user_project_engine ERROR_VARIABLE json_error GET ${o3de_user_project_json} engine)
  27. if(user_project_engine AND NOT json_error)
  28. string(JSON o3de_project_json SET "${o3de_project_json}" engine "\"${user_project_engine}\"" )
  29. elseif(json_error AND ${user_project_engine} STREQUAL "NOTFOUND")
  30. # When the value is just NOTFOUND that means there is a JSON
  31. # parsing error, and not simply a missing key
  32. message(WARNING "Unable to read 'engine' from '${O3DE_USER_PROJECT_JSON_PATH}'\nError: ${json-error}")
  33. endif()
  34. endif()
  35. set_property(GLOBAL PROPERTY O3DE_PROJECT_JSON ${o3de_project_json})
  36. else()
  37. message(WARNING "Unable to read '${O3DE_PROJECT_JSON_PATH}' file necessary to determine whether the project is compatible with this engine.")
  38. return()
  39. endif()
  40. endif()
  41. # Get the engine's 'engine_name' and 'version' fields
  42. cmake_path(GET CMAKE_CURRENT_LIST_DIR PARENT_PATH this_engine_path)
  43. file(READ ${this_engine_path}/engine.json engine_json)
  44. string(JSON engine_name ERROR_VARIABLE json_error GET ${engine_json} engine_name)
  45. if(json_error OR NOT engine_name)
  46. message(WARNING "Unable to read key 'engine_name' from '${this_engine_path}/engine.json'\nError: ${json_error}")
  47. return()
  48. endif()
  49. string(JSON engine_version ERROR_VARIABLE json_error GET ${engine_json} version)
  50. if(json_error)
  51. message(WARNING "Unable to verify engine compatibility because we could not read key 'version' from '${this_engine_path}/engine.json'\nError: ${json_error}")
  52. return()
  53. endif()
  54. set(PACKAGE_VERSION ${engine_version})
  55. # Get the project.json 'engine' field
  56. string(JSON project_engine ERROR_VARIABLE json_error GET ${o3de_project_json} engine)
  57. if(json_error OR NOT project_engine)
  58. if(NOT project_engine)
  59. # Check if the project folder is a subdirectory of this engine and would
  60. # be found using scan up logic
  61. cmake_path(IS_PREFIX this_engine_path "${CMAKE_CURRENT_SOURCE_DIR}" NORMALIZE is_in_engine_tree)
  62. if(is_in_engine_tree)
  63. message(VERBOSE "The project folder is a subdirectory of this engine.")
  64. set(PACKAGE_VERSION_COMPATIBLE TRUE)
  65. return()
  66. endif()
  67. endif()
  68. message(WARNING "Unable to read 'engine' value from '${O3DE_PROJECT_JSON_PATH}'. Please verify this project is registered with an engine. \nError: ${json_error}")
  69. return()
  70. endif()
  71. # Split the engine field into engine name and version specifier
  72. unset(project_engine_name)
  73. unset(project_engine_op)
  74. unset(project_engine_version)
  75. if("${project_engine}" MATCHES "^(.*)(~=|==|!=|<=|>=|<|>|===)(.*)$")
  76. if(${CMAKE_MATCH_COUNT} GREATER_EQUAL 1)
  77. set(project_engine_name ${CMAKE_MATCH_1})
  78. endif()
  79. if(${CMAKE_MATCH_COUNT} GREATER_EQUAL 2)
  80. set(project_engine_op ${CMAKE_MATCH_2})
  81. endif()
  82. if(${CMAKE_MATCH_COUNT} GREATER_EQUAL 3)
  83. set(project_engine_version ${CMAKE_MATCH_3})
  84. endif()
  85. else()
  86. # format unknown, assume it's just the dependency name
  87. set(project_engine_name ${project_engine})
  88. endif()
  89. # Does the engine name match?
  90. if(NOT engine_name STREQUAL project_engine_name)
  91. message(VERBOSE " Engine name '${engine_name}' found in '${this_engine_path}/engine.json' does not match expected engine name '${project_engine_name}'")
  92. return()
  93. endif()
  94. # Is the version compatible?
  95. if(project_engine_op AND project_engine_version)
  96. set(contains_version FALSE)
  97. set(op ${project_engine_op})
  98. set(specifier_version ${project_engine_version})
  99. set(version ${engine_version})
  100. if(op STREQUAL "==" AND version VERSION_EQUAL specifier_version)
  101. set(contains_version TRUE)
  102. elseif(op STREQUAL "!=" AND NOT version VERSION_EQUAL specifier_version)
  103. set(contains_version TRUE)
  104. elseif(op STREQUAL "<=" AND version VERSION_LESS_EQUAL specifier_version)
  105. set(contains_version TRUE)
  106. elseif(op STREQUAL ">=" AND version VERSION_GREATER_EQUAL specifier_version)
  107. set(contains_version TRUE)
  108. elseif(op STREQUAL "<" AND version VERSION_LESS specifier_version)
  109. set(contains_version TRUE)
  110. elseif(op STREQUAL ">" AND version VERSION_GREATER specifier_version)
  111. set(contains_version TRUE)
  112. elseif(op STREQUAL "===" AND version STREQUAL specifier_version)
  113. set(contains_version TRUE)
  114. elseif(op STREQUAL "~=")
  115. # compatible versions have an equivalent combination of >= and ==
  116. # e.g. ~=2.2 is equivalent to >=2.2,==2.*
  117. if(version VERSION_GREATER_EQUAL specifier_version)
  118. string(REPLACE "." ";" specifer_version_part_list ${specifier_version})
  119. list(LENGTH specifer_version_part_list list_length)
  120. if(list_length LESS 2)
  121. # truncating would leave nothing to compare
  122. set(contains_version TRUE)
  123. else()
  124. # trim the last version part because CMake doesn't support '*'
  125. math(EXPR truncated_length "${list_length} - 1")
  126. list(SUBLIST specifer_version_part_list 0 ${truncated_length} specifier_version)
  127. string(REPLACE ";" "." specifier_version "${specifier_version}")
  128. string(REPLACE "." ";" version_part_list ${version})
  129. list(SUBLIST version_part_list 0 ${truncated_length} version)
  130. string(REPLACE ";" "." version "${version}")
  131. # compare the truncated versions
  132. if(version VERSION_EQUAL specifier_version)
  133. set(contains_version TRUE)
  134. endif()
  135. endif()
  136. endif()
  137. endif()
  138. if(NOT contains_version)
  139. message(VERBOSE "The engine ${engine_name} version ${engine_version} at ${this_engine_path} is not compatible with the project's version specifier '${project_engine_op}${project_engine_version}'")
  140. return()
  141. endif()
  142. message(VERBOSE "The engine '${engine_name}' version '${engine_version}' at '${this_engine_path}' is compatible with the project's version specifier '${project_engine_op}${project_engine_version}'")
  143. else()
  144. message(VERBOSE "The engine '${engine_name}' version '${engine_version}' at '${this_engine_path}' is compatible because the project has no engine version specifier.'")
  145. endif()
  146. set(PACKAGE_VERSION_COMPATIBLE TRUE)
  147. if(project_engine_version)
  148. if(PACKAGE_VERSION STREQUAL ${project_engine_version})
  149. set(PACKAGE_VERSION_EXACT TRUE)
  150. endif()
  151. endif()