diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index b2fe4417d3..c93f825a2c 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -916,27 +916,49 @@ namespace AZ SetSettingsRegistrySpecializations(specializations); AZStd::vector scratchBuffer; - // Retrieves the list gem module build targets that the active project depends on - SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, - AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) // In development builds apply the o3de registry and the command line to allow early overrides. This will // allow developers to override things like default paths or Asset Processor connection settings. Any additional // values will be replaced by later loads, so this step will happen again at the end of loading. SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); + // Project User Registry is merged after the command line here to allow make sure the any command line override of the project path + // is used for merging the project's user registry SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); #endif + //! Retrieves the list gem targets that the project has load dependencies on + //! This populates the /Amazon/Gems//SourcePaths array entries which is required + //! by the MergeSettingsToRegistry_GemRegistry() function below to locate the gem's root folder + //! and merge in the gem's registry files. + //! But when running from a pre-built app from the O3DE SDK(Editor/AssetProcessor), the projects binary + //! directory is needed in order to located the load dependency registry files + //! That project binary folder is generated with the /user/Registry when CMake is configured + //! for the project + //! Therefore the order of merging must be as follows + //! 1. MergeSettingsToRegistry_ProjectUserRegistry - Populates the /Amazon/Project/Settings/Build/project_build_path + //! which contains the path to the project binary directory + //! 2. MergeSettingsToRegistry_TargetBuildDependencyRegistry - Loads the cmake_dependencies...setreg + //! file from the locations in order of + //! 1. /Registry + //! 2. /Registry + //! 3. /bin/$/Registry + //! 3. MergeSettingsToRegistry_GemRegistries - Merges the settings registry files from each gem's /Registry directory + + SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, + AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); } void ComponentApplication::SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 56dfbdcb71..bd73162498 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -599,6 +599,34 @@ namespace AZ::SettingsRegistryMergeUtils ? devWriteStorage.value() : projectUserPath.Native()); + // Set the project in-memory build path if the ProjectBuildPath key has been supplied + if (AZ::IO::FixedMaxPath projectBuildPath; registry.Get(projectBuildPath.Native(), ProjectBuildPath)) + { + registry.Remove(FilePathKey_ProjectBuildPath); + registry.Remove(FilePathKey_ProjectConfigurationBinPath); + AZ::IO::FixedMaxPath buildConfigurationPath = normalizedProjectPath / projectBuildPath; + if (IO::SystemFile::Exists(buildConfigurationPath.c_str())) + { + registry.Set(FilePathKey_ProjectBuildPath, buildConfigurationPath.LexicallyNormal().Native()); + } + + // Add the specific build configuration paths to the Settings Registry + // First try /bin/$ and if that path doesn't exist + // try /bin/$/$ + buildConfigurationPath /= "bin"; + if (IO::SystemFile::Exists((buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).c_str())) + { + registry.Set(FilePathKey_ProjectConfigurationBinPath, + (buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native()); + } + else if (IO::SystemFile::Exists((buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).c_str())) + { + registry.Set(FilePathKey_ProjectConfigurationBinPath, + (buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native()); + } + + } + // Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name. auto projectNameKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) @@ -689,6 +717,14 @@ namespace AZ::SettingsRegistryMergeUtils mergePath /= SettingsRegistryInterface::RegistryFolder; registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer); } + + AZ::IO::FixedMaxPath projectBinPath; + if (registry.Get(projectBinPath.Native(), FilePathKey_ProjectConfigurationBinPath)) + { + // Append the project build path path to the project root + projectBinPath /= SettingsRegistryInterface::RegistryFolder; + registry.MergeSettingsFolder(projectBinPath.Native(), specializations, platform, "", scratchBuffer); + } } void MergeSettingsToRegistry_EngineRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, @@ -934,7 +970,8 @@ namespace AZ::SettingsRegistryMergeUtils "project-path", AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}, OptionKeyToRegsetKey{ "project-cache-path", - AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}}; + AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}, + OptionKeyToRegsetKey{"project-build-path", ProjectBuildPath} }; AZStd::fixed_vector overrideArgs; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h index 4e00c0e6ec..576066c29f 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h @@ -52,6 +52,14 @@ namespace AZ::SettingsRegistryMergeUtils //! project settings can be stored inline static constexpr char FilePathKey_ProjectUserPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectUserPath"; + //! User facing key which represents the root of a project cmake build tree. i.e the ${CMAKE_BINARY_DIR} + //! A relative path is taking relative to the *project* root, NOT *engine* root. + inline constexpr AZStd::string_view ProjectBuildPath = "/Amazon/Project/Settings/Build/project_build_path"; + //! In-Memory only key which stores an absolute path to the project build directory + inline constexpr AZStd::string_view FilePathKey_ProjectBuildPath = "/Amazon/AzCore/Runtime/FilePaths/ProjectBuildPath"; + //! In-Memory only key which stores the configuration directory containing the built binaries + inline constexpr AZStd::string_view FilePathKey_ProjectConfigurationBinPath = "/Amazon/AzCore/Runtime/FilePaths/ProjectConfigurationBinPath"; + //! Development write storage path may be considered temporary or cache storage on some platforms inline static constexpr char FilePathKey_DevWriteStorage[] = "/Amazon/AzCore/Runtime/FilePaths/DevWriteStorage"; @@ -128,7 +136,7 @@ namespace AZ::SettingsRegistryMergeUtils //! Callback function that is after a has been filtered through the CommentPrefixFunc //! to determine if the text matches a section header //! returns a view of the section name if the line contains a section - //! Otherwise an empty view is returend + //! Otherwise an empty view is returned using SectionHeaderFunc = AZStd::function; //! Root JSON pointer path to place all key=values pairs of configuration data within diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp index 169a4db6ff..30ec08538a 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp @@ -17,8 +17,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { + return {}; } void* OpenModule(const AZ::OSString& fileName, bool&) @@ -26,10 +27,9 @@ namespace AZ // Android 19 does not have RTLD_NOLOAD but it should be OK since only the Editor expects to reopen modules return dlopen(fileName.c_str(), RTLD_NOW); } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&) { - fullPath = path + fileName; } } } diff --git a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp index 8457ff14a6..7dd889e94d 100644 --- a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp +++ b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp @@ -10,7 +10,6 @@ * */ -#include // for AZ_MAX_PATH_LEN #include #include #include @@ -19,15 +18,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { - char exePath[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) == - AZ::Utils::ExecutablePathResult::Success) - { - path = exePath; - path.push_back('/'); - } + return AZ::Utils::GetExecutableDirectory(); } void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen) @@ -40,10 +33,9 @@ namespace AZ } return handle; } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&) { - fullPath = path + fileName; } } } diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp index 1c16f50203..8e2b40aaca 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp @@ -11,9 +11,11 @@ */ #include -#include // for AZ_MAX_PATH_LEN +#include +#include #include +#include #include #include @@ -21,9 +23,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path); + AZ::IO::FixedMaxPath GetModulePath(); void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen); - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath); + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath& fullPath); } class DynamicModuleHandleUnixLike @@ -36,40 +38,55 @@ namespace AZ : DynamicModuleHandle(fullFileName) , m_handle(nullptr) { - AZ::OSString path; - AZ::OSString fileName; - AZ::OSString fullPath = ""; - AZ::OSString::size_type finalSlash = m_fileName.find_last_of("/"); - if (finalSlash != AZ::OSString::npos) + AZ::IO::FixedMaxPath fullFilePath(AZStd::string_view{m_fileName}); + if (fullFilePath.HasFilename()) { - // Path up to and including final slash - path = m_fileName.substr(0, finalSlash + 1); - // Everything after the final slash - // If m_fileName ends in /, the end result is path/lib.dylib, which just fails to load. - fileName = m_fileName.substr(finalSlash + 1); - } - else - { - // If no slash found, assume empty path, only file name - path = ""; - Platform::GetModulePath(path); - fileName = m_fileName; + AZ::IO::FixedMaxPathString fileNamePath{fullFilePath.Filename().Native()}; + if (!fileNamePath.starts_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX)) + { + fileNamePath = AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX + fileNamePath; + } + + if (!fileNamePath.ends_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION)) + { + fileNamePath += AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; + } + + fullFilePath.ReplaceFilename(AZStd::string_view(fileNamePath)); } - if (fileName.substr(0, 3) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX) + Platform::ConstructModuleFullFileName(fullFilePath); + + // Check if the module exist at the given path within the current working directory + // If it doesn't attempt to append the path to the executable path + if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str())) { - fileName = AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX + fileName; + auto candidatePath = Platform::GetModulePath() / fullFilePath; + if (AZ::IO::SystemFile::Exists(candidatePath.c_str())) + { + fullFilePath = candidatePath; + } } - size_t extensionLen = strlen(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION); - if (fileName.substr(fileName.length() - extensionLen, extensionLen) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION) + // If the path still doesn't exist at this point, check the SettingsRegistryMergeUtils + // FilePathKey_ProjectBuildPath key to see if a project-build-path argument has been supplied + if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str())) { - fileName = fileName + AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if(AZ::IO::FixedMaxPath projectModulePath; + settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath)) + { + projectModulePath /= fullFilePath; + if (AZ::IO::SystemFile::Exists(projectModulePath.c_str())) + { + fullFilePath = projectModulePath; + } + } + } } - - Platform::ConstructModuleFullFileName(path, fileName, fullPath); - m_fileName = fullPath; + m_fileName = AZStd::string_view{fullFilePath.Native()}; } ~DynamicModuleHandleUnixLike() override @@ -81,9 +98,9 @@ namespace AZ { AZ::Debug::Trace::Printf("Module", "Attempting to load module:%s\n", m_fileName.c_str()); bool alreadyOpen = false; - + m_handle = Platform::OpenModule(m_fileName, alreadyOpen); - + if(m_handle) { if (alreadyOpen) diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp index 49d5360faa..9daabfb86b 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AZ @@ -31,13 +32,13 @@ namespace AZ { // Ensure filename ends in ".dll" // Otherwise filenames like "gem.1.0.0" fail to load (.0 is assumed to be the extension). - if (m_fileName.substr(m_fileName.length() - 4) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION) + if (!m_fileName.ends_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION)) { - m_fileName = m_fileName + AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; + m_fileName += AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; } AZ::IO::PathView modulePathView{ m_fileName }; - // If the module path doesn't have a directory within it, prepend it to the path + // If the module path doesn't have a directory within it, prepend the executable directory to the path // and check if the new path exist if (modulePathView.HasFilename() && !modulePathView.HasParentPath()) { @@ -54,6 +55,27 @@ namespace AZ } } } + + // If the module file path does not exist, attempt to search for the module within + // the project's build directory + if (!AZ::IO::SystemFile::Exists(m_fileName.c_str())) + { + // The Settings Registry may not exist in early startup if modules are loaded + // before the ComponentApplication is crated(such as in the Editor main.cpp) + // Therefore an existence check is needed + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if(AZ::IO::FixedMaxPath projectModulePath; + settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath)) + { + projectModulePath /= AZStd::string_view(m_fileName); + if (AZ::IO::SystemFile::Exists(projectModulePath.c_str())) + { + m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size()); + } + } + } + } } ~DynamicModuleHandleWindows() override diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp b/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp index 8457ff14a6..7dd889e94d 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp @@ -10,7 +10,6 @@ * */ -#include // for AZ_MAX_PATH_LEN #include #include #include @@ -19,15 +18,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { - char exePath[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) == - AZ::Utils::ExecutablePathResult::Success) - { - path = exePath; - path.push_back('/'); - } + return AZ::Utils::GetExecutableDirectory(); } void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen) @@ -40,10 +33,9 @@ namespace AZ } return handle; } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&) { - fullPath = path + fileName; } } } diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp b/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp index 8a082a01a6..569aae6f53 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp @@ -10,7 +10,6 @@ * */ -#include // for AZ_MAX_PATH_LEN #include #include #include @@ -19,15 +18,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { - char exePath[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) == - AZ::Utils::ExecutablePathResult::Success) - { - AZ::OSString frameworks = "/Frameworks/"; - path = exePath + frameworks; - } + return AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "Frameworks"; } void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen) @@ -40,10 +33,15 @@ namespace AZ } return handle; } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath& fullPath) { - fullPath = path + fileName + ".framework/" + fileName; + // Append .framework to the name of full path + // Afterwards use the AZ::IO::Path Append function append the filename as a child + // of the framework directory + AZ::IO::FixedMaxPathString fileName = fullPath.Filename().Native(); + fullPath.ReplaceFilename(fileName + ".framework"); + fullPath /= fileName; } } } diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index edd4af293d..1fb440e6e5 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -57,13 +57,16 @@ namespace AzGameFramework AZStd::vector scratchBuffer; - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); #endif + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + // Used the lowercase the platform name since the bootstrap.game...setreg is being loaded // from the asset cache root where all the files are in lowercased from regardless of the filesystem case-sensitivity static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE "." AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER ".setreg"; @@ -77,6 +80,7 @@ namespace AzGameFramework #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp index 37c8d0adee..523e39d622 100644 --- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp +++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp @@ -297,20 +297,28 @@ namespace AssetProcessor AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, platform, specialization, &scratchBuffer); // Merge the Project User and User home settings registry only in non-release builds + constexpr bool executeRegDumpCommands = false; + AZ::CommandLine* commandLine{}; + AZ::ComponentApplicationBus::Broadcast([®istry, &commandLine](AZ::ComponentApplicationRequests* appRequests) + { + commandLine = appRequests->GetAzCommandLine(); + }); + if (!specialization.Contains("release")) { AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, platform, specialization, &scratchBuffer); + if (commandLine) + { + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands); + } AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, platform, specialization, &scratchBuffer); } - AZ::ComponentApplicationBus::Broadcast([®istry](AZ::ComponentApplicationRequests* appRequests) + if (commandLine) { - if (AZ::CommandLine* commandLine = appRequests->GetAzCommandLine(); commandLine != nullptr) - { - constexpr bool executeRegDumpCommands = false; - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands); - } - }); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands); + } + if (registry.Visit(exporter, "")) { diff --git a/Registry/application_options.setreg b/Registry/application_options.setreg index 06ccdc9b41..8dbb6fe418 100644 --- a/Registry/application_options.setreg +++ b/Registry/application_options.setreg @@ -6,6 +6,7 @@ "project-path", "engine-path", "project-cache-path", + "project-build-path", "regset", "regremove", "regdump", diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 139c2a24d1..781fee3711 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -105,9 +105,54 @@ function(ly_add_project_dependencies) ) endfunction() +#template for generating the project build_path setreg +set(project_build_path_template [[ +{ + "Amazon": { + "Project": { + "Settings": { + "Build": { + "project_build_path": "@project_bin_path@" + } + } + } + } +}]] +) + + +#! ly_generate_project_build_path_setreg: Generates a .setreg file that contains an absolute path to the ${CMAKE_BINARY_DIR} +# This allows locate the directory where the project it's binaries are built to be located within the engine. +# Which are the shared libraries and launcher executables +# When an a pre-built engine application runs from a directory other than the project build directory, it needs +# to be able to locate the project build directory to determine the list of gems that the project depends on to load +# as well the location of those gems. +# For example if the project uses an external gem not associated with the engine, that gem's dlls/so/dylib files +# would be located within the project build directory and the engine SDK binary directory would need that info + +# NOTE: This only needed for non-monolithic host platforms. +# This is because there are no dynamic gems to load on monolithic builds +# Furthermore the pre-built SDK engine applications such as the Editor and AssetProcessor +# can only run on the host platform +# \arg:project_real_path Full path to the o3de project directory +function(ly_generate_project_build_path_setreg project_real_path) + # The build path isn't needed on non-monolithic platforms + # Nor on any non-host platforms + if (LY_MONOLITHIC_GAME OR NOT PAL_TRAIT_BUILD_HOST_TOOLS) + return() + endif() + + # Set the project_bin_path to the ${CMAKE_BINARY_DIR} to provide the configure template + # with the project build directory + set(project_bin_path ${CMAKE_BINARY_DIR}) + string(CONFIGURE ${project_build_path_template} project_build_path_setreg_content @ONLY) + set(project_user_build_path_setreg_file ${project_real_path}/user/Registry/Platform/${PAL_PLATFORM_NAME}/build_path.setreg) + file(GENERATE OUTPUT ${project_user_build_path_setreg_file} CONTENT ${project_build_path_setreg_content}) +endfunction() + # Add the projects here so the above function is found foreach(project ${LY_PROJECTS}) - get_filename_component(full_directory_path ${project} REALPATH ${CMAKE_SOURCE_DIR}) + file(REAL_PATH ${project} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR}) string(SHA256 full_directory_hash ${full_directory_path}) # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit @@ -117,5 +162,6 @@ foreach(project ${LY_PROJECTS}) get_filename_component(project_folder_name ${project} NAME) list(APPEND LY_PROJECTS_FOLDER_NAME ${project_folder_name}) add_subdirectory(${project} "${project_folder_name}-${full_directory_hash}") + ly_generate_project_build_path_setreg(${full_directory_path}) endforeach() ly_set(LY_PROJECTS_FOLDER_NAME ${LY_PROJECTS_FOLDER_NAME})