Files
o3de/cmake/Gems.cmake
T
lumberyard-employee-dm 7dabe8b6e9 Updated Several Engine Gem's CMakeLists.txt to add themselves as required Gems (#1262)
* Fixed organization of the AssetProcessor SourceAssetBrowser

Assets within the Engine Root were grouped under a '/' entry.
That has been fixed to use the relative path within the engine root for
those assets
Assets outside of the Engine Root, but on the same drive were using
absolute paths before. Now there are child entries that navigate up the
directory hierarchy to those asset locations

* Added ly_enable_gems call to Atom gems targets that are required

The DefaultLevel.prefab contains several Atom components, that require
the Atom RHI, RPI, Common_Feature, ShaderBuilder and AtomLyIntegration CommonFeatures
gems to be enabled in order to successfully process in the
AssetProcessor.

* Added ly_enable_gems call to make the Camera gem required in Tools,
Builders and Clients.

This is needed as the DefaultLevel.prefab contains an Editor Camera
Component

* Adding the ly_enable_gem call to make the Maestro gem required

CrySystem currently requires Maestro to be enabled in order to
initialize

* Added ly_enable_gems call to the SceneProcessing gem to make it required

The SceneCore and SceneData libraries that are part of the core engine
Code folder requires the SceneProcessing gem to be enabled in order to
invoke the InitializeDynamicModule hooks in DllMain.cpp in order to
initialize those libraries.

* Fixed bad argument in comment for Prefab CMakeLists.txt

* Fixed Assert in Asset Builders due to the Atom RPI Builder

The Atom RPI Builder was enabling the Asset Catalog for the ScriptAsset a second time

The Atom Feature Common EditorSystemCommonComponent.cpp which also loads
in the AssetBuilder is enabling the Asset Catalog for the ScriptAsset

Added BehaviorContext reflection to the OutputDeviceTransformType enum
to fix the BehaviorContext errors about reflecting a method that returns
such an enum

* Added TypeId output to the JsonDeserializer report message about missing
ClassData

Previously the report callback would indicate that the target type was
missing Serialization class data, but didn't indicate the TypeId of the
target type

* Added support to the ly_enable_gems function to be able to support
0 gems being enabled.

Updated the Install step for CMake to propagate any ly_enable_gems
within a CMakeLists.txt for a target into the generated CMakeLists.txt
that is made for each installed IMPORTED target

* Adding newline to the end of the Camera Gem CMakeLists.txt

* Fixing target TYPE parameter for actual Gem Modules to use the GEM_MODULE tag instead of MODULE

* Reverting change to the DESTINATION directory for the installed CMakeLists.txt to use the relative path to the installed directory

* Adding the Atom_Bootstrap gem as a required gem

The Client and GameLaunchers required the Atom_Bootstrap gem in order to create the NativeWindow
Added Atom_Feature_Common client module as a runtime dependency of the AtomLyIntegration CommonsFeature client module

* Fixed register.py --all-projects-path and --all-gems-path arguments to
NOT register projects or gems that are within a template folder
Fixed reading of old pre-1.0 o3de_manifest.json files where the
"engines" key was a json array

* Changed how the relative target source directory is calculated when that source directroy resides outside of the engine root.
The final dirname component is used with a unique SHA256 has to form a <dirname>-<8 char SHA256> folder for installing files into

* Adding newline to the end of Atom_Bootstrap CMakeLists.txt

* Moving ly_enable_gems variants for Tools and Builders inside of PAL_TRAIT_BUILD_HOST_TOOLS block

* Adding a comment to AWSCore.ResourceMappingTool target to indicate that it is not a GEM_MODULE.
Furthermore it cannot be loaded with the Gem system because the library is in a different directory the executable
2021-06-17 13:58:20 -05:00

241 lines
13 KiB
CMake

#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# This file contains utility wrappers for dealing with the Gems system.
# ly_create_alias
# given an alias to create, and a list of one or more targets,
# this creates an alias that depends on all of the given targets.
function(ly_create_alias)
set(options)
set(oneValueArgs NAME NAMESPACE)
set(multiValueArgs TARGETS)
cmake_parse_arguments(ly_create_alias "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT ly_create_alias_NAME)
message(FATAL_ERROR "Provide the name of the alias to create using the NAME keyword")
endif()
if (NOT ly_create_alias_NAMESPACE)
message(FATAL_ERROR "Provide the namespace of the alias to create using the NAMESPACE keyword")
endif()
if(TARGET ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME})
message(FATAL_ERROR "Target already exists, cannot create an alias for it: ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}\n"
"Make sure the target wasn't copy and pasted here or elsewhere.")
endif()
# easy version - if its juts one target, we can directly get the target, and make both aliases,
# the namespaced and non namespaced one, point at it.
list(LENGTH ly_create_alias_TARGETS number_of_targets)
if (number_of_targets EQUAL 1)
ly_de_alias_target(${ly_create_alias_TARGETS} de_aliased_target_name)
add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${de_aliased_target_name})
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()
# more complex version - one alias to multiple targets. To actually achieve this
# we have to create an interface library with those dependencies, then we have to create an alias to that target.
# by convention we create one without a namespace then alias the namespaced one.
if(TARGET ${ly_create_alias_NAME})
message(FATAL_ERROR "Internal alias target already exists, cannot create an alias for it: ${ly_create_alias_NAME}\n"
"This could be a copy-paste error, where some part of the ly_create_alias call was changed but the other")
endif()
add_library(${ly_create_alias_NAME} INTERFACE IMPORTED GLOBAL)
set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE)
foreach(target_name ${ly_create_alias_TARGETS})
if(TARGET ${target_name})
ly_de_alias_target(${target_name} de_aliased_target_name)
if(NOT de_aliased_target_name)
message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name")
endif()
else()
set(de_aliased_target_name ${target_name})
endif()
list(APPEND final_targets ${de_aliased_target_name})
endforeach()
# add_dependencies must be called with at least one dependent target
if(final_targets)
ly_parse_third_party_dependencies("${final_targets}")
ly_add_dependencies(${ly_create_alias_NAME} ${final_targets})
endif()
# now add the final alias:
add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME})
# Store off the arguments used by 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
# this function makes sure that the given gems, or gems listed in the variable ENABLED_GEMS
# in the GEM_FILE name, are set as runtime dependencies (and thus loaded) for the given targets
# in the context of the given project.
# note that it can't do this immediately, so it saves the data for later processing.
# Note: If you don't supply a project name, it will apply it across the board to all projects.
# this is useful in the case of "ly_add_gems being called for so called 'mandatory gems' inside the engine.
# if you specify a gem name with a namespace, it will be used, otherwise it will assume Gem::
function(ly_enable_gems)
set(options)
set(oneValueArgs PROJECT_NAME GEM_FILE)
set(multiValueArgs GEMS TARGETS VARIANTS)
cmake_parse_arguments(ly_enable_gems "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT ly_enable_gems_TARGETS)
message(FATAL_ERROR "You must provide the targets to add gems to using the TARGETS keyword")
endif()
if (NOT ly_enable_gems_PROJECT_NAME)
message(VERBOSE "Note: ly_enable_gems called with no PROJECT_NAME name, applying to all projects: \n"
" - VARIANTS ${ly_enable_gems_VARIANTS} \n"
" - GEMS ${ly_enable_gems_GEMS} \n"
" - TARGETS ${ly_enable_gems_TARGETS} \n"
" - GEM_FILE ${ly_enable_gems_GEM_FILE}")
set(ly_enable_gems_PROJECT_NAME "__NOPROJECT__") # so that the token is not blank
endif()
if (NOT ly_enable_gems_VARIANTS)
message(FATAL_ERROR "You must provide at least 1 variant of the gem modules (Editor, Server, Client, Builder) to "
"add to your targets, using the VARIANTS keyword")
endif()
if ((NOT ly_enable_gems_GEMS AND NOT ly_enable_gems_GEM_FILE) OR (ly_enable_gems_GEMS AND ly_enable_gems_GEM_FILE))
message(FATAL_ERROR "Provide exactly one of either GEM_FILE (filename) or GEMS (list of gems) keywords.")
endif()
if (ly_enable_gems_GEM_FILE)
set(store_temp ${ENABLED_GEMS})
include(${ly_enable_gems_GEM_FILE} RESULT_VARIABLE was_able_to_load_the_file)
if(NOT was_able_to_load_the_file)
message(FATAL_ERROR "could not load the GEM_FILE ${ly_enable_gems_GEM_FILE}")
endif()
if(NOT DEFINED ENABLED_GEMS)
message(WARNING "GEM_FILE ${ly_enable_gems_GEM_FILE} did not set the value of ENABLED_GEMS.\n"
"Gem Files should contain set(ENABLED_GEMS ... <list of gem names>)")
endif()
set(ly_enable_gems_GEMS ${ENABLED_GEMS})
set(ENABLED_GEMS ${store_temp}) # restore value of ENABLED_GEMS just in case...
endif()
# all the actual work has to be done later.
foreach(target_name ${ly_enable_gems_TARGETS})
foreach(variant_name ${ly_enable_gems_VARIANTS})
set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS "${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}")
define_property(GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}"
BRIEF_DOCS "List of gem names to evaluate variants against" FULL_DOCS "Names of gems that will be paired with the variant name
to determine if it is valid target that should be added as an application dynamic load dependency")
set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}" ${ly_enable_gems_GEMS})
endforeach()
endforeach()
# Store off the arguments used by ly_enable_gems into a DIRECTORY property
# This will be used to re-create the ly_enable_gems call in the generated CMakeLists.txt at the INSTALL step
# Replace the CMake list separator with a space to replicate the space separated TARGETS arguments
string(REPLACE ";" " " enable_gems_args "${ly_enable_gems_PROJECT_NAME},${ly_enable_gems_GEMS},${ly_enable_gems_GEM_FILE},${ly_enable_gems_VARIANTS},${ly_enable_gems_TARGETS}")
set_property(DIRECTORY APPEND PROPERTY LY_ENABLE_GEMS_ARGUMENTS "${enable_gems_args}")
endfunction()
# call this before runtime dependencies are used to add any relevant targets
# saved by the above function
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 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)
if(project_target_variant_length EQUAL 0)
continue()
endif()
if(NOT project_target_variant_length EQUAL 3)
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)
list(POP_BACK project_target_variant_list target)
list(POP_BACK project_target_variant_list project)
get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project_target_variant}")
if (NOT gem_dependencies)
get_property(gem_dependencies_defined GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project_target_variant}" DEFINED)
if (gem_dependencies_defined)
# special case, if the LY_DELAYED_ENABLE_GEMS_"${project_target_variant}" property is DEFINED
# but empty, add an entry to the LY_DELAYED_LOAD_DEPENDENCIES to have the
# cmake_dependencies.*.setreg file for the (project, target) tuple to be regenerated
# This is needed if the ENABLED_GEMS list for a project goes from >0 to 0. In this case
# the cmake_dependencies would have a stale list of gems to load unless it is regenerated
get_property(delayed_load_target_set GLOBAL PROPERTY LY_DELAYED_LOAD_"${project},${target}" SET)
if(NOT delayed_load_target_set)
set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_DEPENDENCIES "${project},${target}")
set_property(GLOBAL APPEND PROPERTY LY_DELAYED_LOAD_"${project},${target}" "")
endif()
endif()
# Continue to the next iteration loop regardless as there are no gem dependencies
continue()
endif()
if(${project} STREQUAL "__NOPROJECT__")
# special case, apply to all
unset(PREFIX_CLAUSE)
else()
set(PREFIX_CLAUSE "PREFIX;${project}")
endif()
if (NOT TARGET ${target})
message(FATAL_ERROR "ly_enable_gems specified TARGET '${target}' but no such target was found.")
endif()
# apply the list of gem targets. Adding a gem really just means adding the appropriate dependency.
foreach(gem_name ${gem_dependencies})
# the gem name may already have a namespace. If it does, we use that one
ly_strip_target_namespace(TARGET ${gem_name} OUTPUT_VARIABLE unaliased_gem_name)
if (${unaliased_gem_name} STREQUAL ${gem_name})
# if stripping a namespace had no effect, it had no namespace
# and we supply the default Gem:: namespace.
set(gem_name_with_namespace Gem::${gem_name})
else()
# if stripping the namespace had an effect then we use the original
# with the namespace, instead of assuming Gem::
set(gem_name_with_namespace ${gem_name})
endif()
# if the target exists, add it.
if (TARGET ${gem_name_with_namespace}.${variant})
ly_add_target_dependencies(
${PREFIX_CLAUSE}
TARGETS ${target}
DEPENDENT_TARGETS ${gem_name_with_namespace}.${variant}
)
endif()
endforeach()
endforeach()
endfunction()