diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake index caa5b74c93..a90cf09639 100644 --- a/cmake/Gems.cmake +++ b/cmake/Gems.cmake @@ -47,6 +47,10 @@ function(ly_create_alias) if (NOT TARGET ${ly_create_alias_NAME}) add_library(${ly_create_alias_NAME} ALIAS ${de_aliased_target_name}) endif() + # Store off the arguments needed used ly_create_alias into a DIRECTORY property + # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step + string(REPLACE ";" " " create_alias_args "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}") + set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}") return() endif() @@ -75,6 +79,13 @@ function(ly_create_alias) # now add the final alias: add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME}) + + # Store off the arguments needed used ly_create_alias into a DIRECTORY property + # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step + + # Replace the CMake list separator with a space to replicate the space separated TARGETS arguments + string(REPLACE ";" " " create_alias_args "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}") + set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${create_alias_args}") endfunction() # ly_enable_gems @@ -143,7 +154,7 @@ endfunction() function(ly_enable_gems_delayed) get_property(ly_delayed_enable_gems GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS) foreach(project_target_variant ${ly_delayed_enable_gems}) - # we expect a colon seperated list of + # we expect a colon separated list of # PROJECT_NAME,target_name,variant_name string(REPLACE "," ";" project_target_variant_list "${project_target_variant}") list(LENGTH project_target_variant_list project_target_variant_length) @@ -152,7 +163,7 @@ function(ly_enable_gems_delayed) endif() if(NOT project_target_variant_length EQUAL 3) - message(FATAL_ERROR "Invalid specificaiton of gems, expected 'project','target','variant' and got ${project_target_variant}") + message(FATAL_ERROR "Invalid specification of gems, expected 'project','target','variant' and got ${project_target_variant}") endif() list(POP_BACK project_target_variant_list variant) diff --git a/cmake/O3DEJson.cmake b/cmake/O3DEJson.cmake index 5d748e9681..ab5f95bc8c 100644 --- a/cmake/O3DEJson.cmake +++ b/cmake/O3DEJson.cmake @@ -14,35 +14,42 @@ include_guard() set(LY_EXTERNAL_SUBDIRS "" CACHE STRING "List of subdirectories to recurse into when running cmake against the engine's CMakeLists.txt") #! read_json_external_subdirs -# Read the "external_subdirectories" array from a *.json file -# External subdirectories are any folders with CMakeLists.txt in them -# This could be regular subdirectories, Gems(contains an additional gem.json), -# Restricted folders(contains an additional restricted.json), etc... -# -# \arg:output_external_subdirs name of output variable to store external subdirectories into -# \arg:input_json_path path to the *.json file to load and read the external subdirectories from -# \return: external subdirectories as is from the json file. +# Read the "external_subdirectories" array from a *.json file +# External subdirectories are any folders with CMakeLists.txt in them +# This could be regular subdirectories, Gems(contains an additional gem.json), +# Restricted folders(contains an additional restricted.json), etc... +# +# \arg:output_external_subdirs name of output variable to store external subdirectories into +# \arg:input_json_path path to the *.json file to load and read the external subdirectories from +# \return: external subdirectories as is from the json file. function(read_json_external_subdirs output_external_subdirs input_json_path) + o3de_read_json_array(json_array ${input_json_path} "external_subdirectories") + set(${output_external_subdirs} ${json_array} PARENT_SCOPE) +endfunction() + +#! read_json_array +# Reads the a json array field into a cmake list variable +function(o3de_read_json_array read_output_array input_json_path array_key) file(READ ${input_json_path} manifest_json_data) - string(JSON external_subdirs_count ERROR_VARIABLE manifest_json_error - LENGTH ${manifest_json_data} "external_subdirectories") + string(JSON array_count ERROR_VARIABLE manifest_json_error + LENGTH ${manifest_json_data} ${array_key}) if(manifest_json_error) - # There is "external_subdirectories" key, so theire are no subdirectories to read + # There is no key, return return() endif() - if(external_subdirs_count GREATER 0) - math(EXPR external_subdir_range "${external_subdirs_count}-1") - foreach(external_subdir_index RANGE ${external_subdir_range}) - string(JSON external_subdir ERROR_VARIABLE manifest_json_error - GET ${manifest_json_data} "external_subdirectories" "${external_subdir_index}") + if(array_count GREATER 0) + math(EXPR array_range "${array_count}-1") + foreach(array_index RANGE ${array_range}) + string(JSON array_element ERROR_VARIABLE manifest_json_error + GET ${manifest_json_data} ${array_key} "${array_index}") if(manifest_json_error) - message(FATAL_ERROR "Error reading field at index ${external_subdir_index} in \"external_subdirectories\" JSON array: ${manifest_json_error}") + message(FATAL_ERROR "Error reading field at index ${array_index} in \"${array_key}\" JSON array: ${manifest_json_error}") endif() - list(APPEND external_subdirs ${external_subdir}) + list(APPEND array_elements ${array_element}) endforeach() endif() - set(${output_external_subdirs} ${external_subdirs} PARENT_SCOPE) + set(${read_output_array} ${array_elements} PARENT_SCOPE) endfunction() function(o3de_read_json_key output_value input_json_path key) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 7bf71d7e01..27b8d83a9c 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -155,6 +155,25 @@ function(ly_setup_target ALIAS_TARGET_NAME) list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt + string(JOIN "\n" create_alias_template + "if(NOT TARGET @ALIAS_NAME@)" + " ly_create_alias(NAME @ALIAS_NAME@ NAMESPACE @ALIAS_NAMESPACE@ TARGETS @ALIAS_TARGETS@)" + "endif()" + "" + ) + get_property(create_alias_commands_arg_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_CREATE_ALIAS_ARGUMENTS) + foreach(create_alias_single_command_arg_list ${create_alias_commands_arg_list}) + # Split the ly_create_alias arguments back out based on commas + string(REPLACE "," ";" create_alias_single_command_arg_list "${create_alias_single_command_arg_list}") + list(POP_FRONT create_alias_single_command_arg_list ALIAS_NAME) + list(POP_FRONT create_alias_single_command_arg_list ALIAS_NAMESPACE) + # The rest of the list are the target dependencies + set(ALIAS_TARGETS ${create_alias_single_command_arg_list}) + string(CONFIGURE "${create_alias_template}" create_alias_command @ONLY) + string(APPEND CREATE_ALIASES_PLACEHOLDER ${create_alias_command}) + endforeach() + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt @ONLY) @@ -225,14 +244,19 @@ function(ly_setup_cmake_install) ) # Transform the LY_EXTERNAL_SUBDIRS list into a json array - set(LY_INSTALL_EXTERNAL_SUBDIRS "[]") - set(external_subdir_index "0") + set(indent " ") foreach(external_subdir ${LY_EXTERNAL_SUBDIRS}) - math(EXPR external_subdir_index "${external_subdir_index} + 1") file(RELATIVE_PATH engine_rel_external_subdir ${LY_ROOT_FOLDER} ${external_subdir}) - string(JSON LY_INSTALL_EXTERNAL_SUBDIRS ERROR_VARIABLE external_subdir_error SET ${LY_INSTALL_EXTERNAL_SUBDIRS} - ${external_subdir_index} "\"${engine_rel_external_subdir}\"") + list(APPEND relative_external_subdirs "\"${engine_rel_external_subdir}\"") + endforeach() + list(JOIN relative_external_subdirs ",\n${indent}" LY_INSTALL_EXTERNAL_SUBDIRS) + + # Read the "templates" key from the source engine.json + o3de_read_json_array(engine_templates ${LY_ROOT_FOLDER}/engine.json "templates") + foreach(template_path ${engine_templates}) + list(APPEND relative_templates "\"${template_path}\"") endforeach() + list(JOIN relative_templates ",\n${indent}" LY_INSTALL_TEMPLATES) configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index b42d29c9c2..a1fd66a06d 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -20,6 +20,7 @@ set(FILES EngineJson.cmake FileUtil.cmake Findo3de.cmake + Gems.cmake GeneralSettings.cmake Install.cmake LyAutoGen.cmake diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index b2c8b9b6f6..06cd022898 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -27,6 +27,7 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) +@CREATE_ALIASES_PLACEHOLDER@ set(configs @CMAKE_CONFIGURATION_TYPES@) foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in index 1cfb1826ce..ce2e1be25c 100644 --- a/cmake/install/engine.json.in +++ b/cmake/install/engine.json.in @@ -5,7 +5,7 @@ "O3DEVersion": "@LY_VERSION_STRING@", "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, "O3DEBuildNumber": @LY_VERSION_BUILD_NUMBER@, - "external_subdirectories": @LY_INSTALL_EXTERNAL_SUBDIRS@, + "external_subdirectories": [@LY_INSTALL_EXTERNAL_SUBDIRS@], "projects": [@LY_INSTALL_PROJECTS@], "templates": [@LY_INSTALL_TEMPLATES@] } diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index f4d2b63cff..63dec3e765 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -1338,6 +1338,10 @@ def create_project(project_path: str, if template_name and not template_path: template_path = manifest.get_registered(template_name=template_name) + if not template_path: + logger.error(f'Could not find the template path using name {template_name}.\n' + f'Has the engine been registered yet. It can be registered via the "o3de.py register --this-engine" command') + return 1 if not os.path.isdir(template_path): logger.error(f'Could not find the template {template_name}=>{template_path}') return 1