Quellcode durchsuchen

[Mac] Generate O3DE SDK app bundle that can be notarized and distributed (#4150)

* [Mac] Initial support for building with hardened runtime enabled and code signing the binaries and bundles generated by the CMake install process.

Signed-off-by: amzn-sj <[email protected]>

* 1. Move call to ly_post_install_step
2. Entitlements should only be added for executables
3. Change use of CMake exec_program to newer execute_process
4. Remove broken symlinks from embedded Python frameworks
5. Run post install code signing only if hardened runtime is enabled

Signed-off-by: amzn-sj <[email protected]>

* Remove unnecessary flag

Signed-off-by: amzn-sj <[email protected]>

* Remove unnecessary additional call to condesign python inside a bundle

Signed-off-by: amzn-sj <[email protected]>

* 1. Move commonly used install functions for codesigning, copying files, and fixing frameworks to a utility script
2. Remove unnecessary wait in the Editor/AP launchers I added earlier.
3. Codesign 3rd party libraries for distribution.

Signed-off-by: amzn-sj <[email protected]>

* 1. Codesigning on 3rd party libs should only happen when hardened runtime is enabled.
2. Change the order of the if blocks in Editor's main_dummy.cpp. This was causing strange notarization issues because it wass too similar to AP's main executable.

Signed-off-by: amzn-sj <[email protected]>

* Add new line to end of file

Signed-off-by: amzn-sj <[email protected]>

* 1. Move architecture specification to PAL_mac cmake file. 2. Codesign failure should be fatal.

Signed-off-by: amzn-sj <[email protected]>

* Address some PR feedback

Signed-off-by: amzn-sj <[email protected]>

* Remove unnecessary comment. Change if to use IN_LIST.

Signed-off-by: amzn-sj <[email protected]>

* HOME may not always be defined. Adding alternate POSIX way of determining HOME.

Signed-off-by: amzn-sj <[email protected]>

* Checking in partial work to get O3DE SDK built as an app bundle. Has a bunch of debug code that needs to be cleaned up.

Signed-off-by: amzn-sj <[email protected]>

* Remove this and add it back later with fixed casing.

Signed-off-by: amzn-sj <[email protected]>

* Adding file back with fixed case

Signed-off-by: amzn-sj <[email protected]>

* 1. Add entitlements sparingly(only when necessary)
2. Convert entitlements to plist files which we can directly pass to codesign
3. Install python site-packages in the o3de_sdk launcher and then launch the project manger.

Signed-off-by: amzn-sj <[email protected]>

* 1. Move hardened runtime check to codesigning functions only. This way, non-hardened runtime install is identical to the former except for codesign. Makes it easy for QA to test internally.
2. Move cmake min version for install to the pre-install steps.

Signed-off-by: amzn-sj <[email protected]>

* 1. Remove the dummy launchers for AssetProcessor and Editor
2. Add loader_path to the rpaths of binaries outside an app bundle so that the dynamic loader can load their dependencies if any.

Signed-off-by: amzn-sj <[email protected]>

* Remove file named main_dummy.cpp

Signed-off-by: amzn-sj <[email protected]>

* Add O3DE SDK launcher

Signed-off-by: amzn-sj <[email protected]>

* Add missing runtime dependencies to gems

Signed-off-by: amzn-sj <[email protected]>

* 1. Update the path to binaries when codesigning to the correct one.
2. Remove some debug messages.
3. Move installed binary path setreg generation to the target install function. This way, we get the correct path to the bundle accounting for different configs and subdirectories.

Signed-off-by: amzn-sj <[email protected]>

* Add explanatory comments.

Signed-off-by: amzn-sj <[email protected]>

* 1. ly_install_add_install_path_setreg cannot be called during install target because the runtime dependencies are already processed by then.
2. The SDK launcher now uses the ProjectManager's bundle setreg to find the path to the installed binaries

Signed-off-by: amzn-sj <[email protected]>

* Update path to install relative binaries after merge from dev

Signed-off-by: amzn-sj <[email protected]>

* Only one config of the SDK launcher needs to be installed. Preinstall steps should not be run per config, but only once.

Signed-off-by: amzn-sj <[email protected]>

* 1. Install python dependencies using the get_python.sh script.
2. Replace any reference to hard-coded package name/version numbers with variables.
3. Add one more missing runtime dependency.
4. Misc. PR feedback.

Signed-off-by: amzn-sj <[email protected]>

* 1. Remove the need for setreg files in all tool bundle. Project binary path can be used instead.
2. Move O3DE_SDK_Launcher to Code/Tools/BundleLauncher
3. Add ly_install_run_script() function for install(SCRIPT) functionality.
4. Address some other PR feedback.

Signed-off-by: amzn-sj <[email protected]>

* Add source permission when installing O3DE_SDK executable.

Signed-off-by: amzn-sj <[email protected]>

* Rename setreg file to add specialization tag.

Signed-off-by: amzn-sj <[email protected]>

* Remove LY_BUILD_PERMUTATION that's not needed

Signed-off-by: amzn-sj <[email protected]>

* 1. Add BinariesInstallPath.setreg to all our bundles like before. This is now only added during the install process though.
2. Fix path in Install_common.cmake

Signed-off-by: amzn-sj <[email protected]>

* Fix comment

Signed-off-by: amzn-sj <[email protected]>
SJ vor 3 Jahren
Ursprung
Commit
1f542838bb
34 geänderte Dateien mit 555 neuen und 246 gelöschten Zeilen
  1. 1 1
      CMakeLists.txt
  2. 10 0
      Code/Editor/Platform/Mac/EditorEntitlements.plist
  3. 1 24
      Code/Editor/Platform/Mac/editor_mac.cmake
  4. 1 1
      Code/Editor/Platform/Mac/gui_info.plist
  5. 0 75
      Code/Editor/Platform/Mac/main_dummy.cpp
  6. 1 0
      Code/Editor/Plugins/EditorCommon/CMakeLists.txt
  7. 18 0
      Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp
  8. 9 0
      Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp
  9. 10 0
      Code/Tools/AssetProcessor/Platform/Mac/AssetProcessorEntitlements.plist
  10. 1 24
      Code/Tools/AssetProcessor/Platform/Mac/assetprocessor_mac.cmake
  11. 1 1
      Code/Tools/AssetProcessor/Platform/Mac/gui_info.plist
  12. 0 75
      Code/Tools/AssetProcessor/Platform/Mac/main_dummy.cpp
  13. 24 0
      Code/Tools/BundleLauncher/CMakeLists.txt
  14. 63 0
      Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp
  15. 11 0
      Code/Tools/BundleLauncher/O3DE_SDK_files.cmake
  16. 18 0
      Code/Tools/BundleLauncher/info.plist
  17. 1 0
      Code/Tools/CMakeLists.txt
  18. 1 0
      Code/Tools/ProjectManager/Platform/Mac/PAL_mac.cmake
  19. 2 0
      Gems/Atom/Feature/Common/Code/CMakeLists.txt
  20. 1 0
      Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt
  21. 2 0
      Gems/Camera/Code/CMakeLists.txt
  22. 17 0
      cmake/Install.cmake
  23. 3 0
      cmake/LYPython.cmake
  24. 14 11
      cmake/Platform/Common/Install_common.cmake
  25. 1 3
      cmake/Platform/Mac/Configurations_mac.cmake
  26. 168 0
      cmake/Platform/Mac/InstallUtils_mac.cmake.in
  27. 62 26
      cmake/Platform/Mac/Install_mac.cmake
  28. 22 0
      cmake/Platform/Mac/LYWrappers_mac.cmake
  29. 3 0
      cmake/Platform/Mac/PAL_mac.cmake
  30. 39 0
      cmake/Platform/Mac/PreInstallSteps_mac.cmake.in
  31. 2 3
      cmake/Platform/Mac/runtime_dependencies_mac.cmake.in
  32. 34 0
      cmake/Platform/Mac/runtime_install_mac.cmake.in
  33. 10 0
      python/Platform/Mac/PythonEntitlements.plist
  34. 4 2
      python/get_python.sh

+ 1 - 1
CMakeLists.txt

@@ -29,11 +29,11 @@ include(cmake/PAL.cmake)
 include(cmake/PALTools.cmake)
 include(cmake/RuntimeDependencies.cmake)
 include(cmake/Configurations.cmake) # Requires to be after PAL so we get platform variable definitions
-include(cmake/Install.cmake)
 include(cmake/Dependencies.cmake)
 include(cmake/Deployment.cmake)
 include(cmake/3rdParty.cmake)
 include(cmake/LYPython.cmake)
+include(cmake/Install.cmake)
 include(cmake/LYWrappers.cmake)
 include(cmake/Gems.cmake)
 include(cmake/UnitTest.cmake)

+ 10 - 0
Code/Editor/Platform/Mac/EditorEntitlements.plist

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+    <true/>
+    <key>com.apple.security.cs.disable-library-validation</key>
+    <true/>
+</dict>
+</plist>

+ 1 - 24
Code/Editor/Platform/Mac/editor_mac.cmake

@@ -12,28 +12,5 @@ set_target_properties(Editor PROPERTIES
     MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_LIST_DIR}/gui_info.plist
     RESOURCE ${CMAKE_CURRENT_LIST_DIR}/Images.xcassets
     XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME EditorAppIcon
+    ENTITLEMENT_FILE_PATH ${CMAKE_CURRENT_LIST_DIR}/EditorEntitlements.plist
 )
-
-# We cannot use ly_add_target here because we're already including this file from inside ly_add_target
-# So we need to setup target, dependencies and install logic manually.
-add_executable(EditorDummy Platform/Mac/main_dummy.cpp)
-add_executable(AZ::EditorDummy ALIAS EditorDummy)
-
-ly_target_link_libraries(EditorDummy
-    PRIVATE
-        AZ::AzCore
-        AZ::AzFramework)
-
-ly_add_dependencies(Editor EditorDummy)
-
-# Store the aliased target into a DIRECTORY property
-set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS AZ::EditorDummy)
-
-# Store the directory path in a GLOBAL property so that it can be accessed
-# in the layout install logic. Skip if the directory has already been added
-get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
-if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
-    set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
-endif()
-
-ly_install_add_install_path_setreg(Editor)

+ 1 - 1
Code/Editor/Platform/Mac/gui_info.plist

@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>CFBundleExecutable</key>
-	<string>EditorDummy</string>
+	<string>Editor</string>
 	<key>CFBundleIdentifier</key>
 	<string>org.O3DE.Editor</string>
 	<key>CFBundlePackageType</key>

+ 0 - 75
Code/Editor/Platform/Mac/main_dummy.cpp

@@ -1,75 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/Component/ComponentApplication.h>
-#include <AzCore/Memory/SystemAllocator.h>
-#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
-#include <AzCore/Utils/Utils.h>
-#include <AzFramework/Process/ProcessWatcher.h>
-
-#include <cstdlib>
-
-int main(int argc, char* argv[])
-{
-    // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
-    AZ::ComponentApplication::Descriptor desc;
-    AZ::ComponentApplication application;
-    application.Create(desc);
-    
-    AZStd::vector<AZStd::string> envVars;
-    
-    const char* homePath = std::getenv("HOME");
-    envVars.push_back(AZStd::string::format("HOME=%s", homePath));
-    
-    if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
-    {
-        const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
-        AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
-        if (AZ::IO::FixedMaxPath projectModulePath;
-            settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
-        {
-            dyldSearchPath.append(":");
-            dyldSearchPath.append(projectModulePath.c_str());
-        }
-        
-        if (AZ::IO::FixedMaxPath installedBinariesFolder;
-            settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
-        {
-            if (AZ::IO::FixedMaxPath engineRootFolder;
-                settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
-            {
-                installedBinariesFolder = engineRootFolder / installedBinariesFolder;
-                dyldSearchPath.append(":");
-                dyldSearchPath.append(installedBinariesFolder.c_str());
-            }
-        }
-        envVars.push_back(dyldSearchPath);
-    }
-    
-    AZStd::string commandArgs;
-    for (int i = 1; i < argc; i++)
-    {
-        commandArgs.append(argv[i]);
-        commandArgs.append(" ");
-    }
-    
-    AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
-    AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
-    processPath /= "Editor";
-    processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
-    processLaunchInfo.m_commandlineParameters = commandArgs;
-    processLaunchInfo.m_environmentVariables = &envVars;
-    processLaunchInfo.m_showWindow = true;
-
-    AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
-
-    application.Destroy();
-
-    return 0;
-}
-

+ 1 - 0
Code/Editor/Plugins/EditorCommon/CMakeLists.txt

@@ -51,4 +51,5 @@ ly_add_target(
         AZ::AzCore
         AZ::AzToolsFramework
         AZ::AzQtComponents
+        Legacy::EditorCore
 )

+ 18 - 0
Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp

@@ -72,6 +72,7 @@ namespace AZ
             {
                 if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
                 {
+                    bool fileFound = false;
                     if (AZ::IO::FixedMaxPath projectModulePath;
                         settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
                     {
@@ -79,6 +80,23 @@ namespace AZ
                         if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
                         {
                             m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size());
+                            fileFound = true;
+                        }
+                    }
+                    if (!fileFound)
+                    {
+                        if (AZ::IO::FixedMaxPath installedBinariesPath;
+                            settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
+                        {
+                            if (AZ::IO::FixedMaxPath engineRootFolder;
+                                settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
+                            {
+                                installedBinariesPath = engineRootFolder / installedBinariesPath / fullFilePath;
+                                if (AZ::IO::SystemFile::Exists(installedBinariesPath.c_str()))
+                                {
+                                    m_fileName.assign(installedBinariesPath.c_str(), installedBinariesPath.Native().size());
+                                }
+                            }
                         }
                     }
                 }

+ 9 - 0
Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp

@@ -9,6 +9,7 @@
 #include <AzCore/Utils/Utils.h>
 
 #include <cstdlib>
+#include <pwd.h>
 
 namespace AZ
 {
@@ -39,6 +40,14 @@ namespace AZ
                 AZ::IO::FixedMaxPath path{homePath};
                 return path.Native();
             }
+
+            struct passwd* pass = getpwuid(getuid());
+            if (pass)
+            {
+                AZ::IO::FixedMaxPath path{pass->pw_dir};
+                return path.Native();
+            }
+            
             return {};
         }
 

+ 10 - 0
Code/Tools/AssetProcessor/Platform/Mac/AssetProcessorEntitlements.plist

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+    <true/>
+    <key>com.apple.security.cs.disable-library-validation</key>
+    <true/>
+</dict>
+</plist>

+ 1 - 24
Code/Tools/AssetProcessor/Platform/Mac/assetprocessor_mac.cmake

@@ -12,28 +12,5 @@ set_target_properties(AssetProcessor PROPERTIES
     MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Platform/Mac/gui_info.plist
     RESOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Platform/Mac/Images.xcassets
     XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AssetProcessorAppIcon
+    ENTITLEMENT_FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Platform/Mac/AssetProcessorEntitlements.plist
 )
-
-# We cannot use ly_add_target here because we're already including this file from inside ly_add_target
-# So we need to setup target, dependencies and install logic manually.
-add_executable(AssetProcessorDummy Platform/Mac/main_dummy.cpp)
-add_executable(AZ::AssetProcessorDummy ALIAS AssetProcessorDummy)
-
-ly_target_link_libraries(AssetProcessorDummy
-    PRIVATE
-        AZ::AzCore
-        AZ::AzFramework)
-
-ly_add_dependencies(AssetProcessor AssetProcessorDummy)
-
-# Store the aliased target into a DIRECTORY property
-set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS AZ::AssetProcessorDummy)
-
-# Store the directory path in a GLOBAL property so that it can be accessed
-# in the layout install logic. Skip if the directory has already been added
-get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
-if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
-    set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
-endif()
-
-ly_install_add_install_path_setreg(AssetProcessor)

+ 1 - 1
Code/Tools/AssetProcessor/Platform/Mac/gui_info.plist

@@ -11,7 +11,7 @@
 	<key>CFBundleSignature</key>
 	<string>ASPR</string>
 	<key>CFBundleExecutable</key>
-	<string>AssetProcessorDummy</string>
+	<string>AssetProcessor</string>
 	<key>CFBundleIdentifier</key>
 	<string>com.Amazon.AssetProcessor</string>
 </dict>

+ 0 - 75
Code/Tools/AssetProcessor/Platform/Mac/main_dummy.cpp

@@ -1,75 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/Component/ComponentApplication.h>
-#include <AzCore/Memory/SystemAllocator.h>
-#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
-#include <AzCore/Utils/Utils.h>
-#include <AzFramework/Process/ProcessWatcher.h>
-
-#include <cstdlib>
-
-int main(int argc, char* argv[])
-{
-    // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
-    AZ::ComponentApplication::Descriptor desc;
-    AZ::ComponentApplication application;
-    application.Create(desc);
-    
-    AZStd::vector<AZStd::string> envVars;
-    
-    const char* homePath = std::getenv("HOME");
-    envVars.push_back(AZStd::string::format("HOME=%s", homePath));
-    
-    if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
-    {
-        const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
-        AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
-        if (AZ::IO::FixedMaxPath projectModulePath;
-            settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
-        {
-            dyldSearchPath.append(":");
-            dyldSearchPath.append(projectModulePath.c_str());
-        }
-        
-        if (AZ::IO::FixedMaxPath installedBinariesFolder;
-            settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
-        {
-            if (AZ::IO::FixedMaxPath engineRootFolder;
-                settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
-            {
-                installedBinariesFolder = engineRootFolder / installedBinariesFolder;
-                dyldSearchPath.append(":");
-                dyldSearchPath.append(installedBinariesFolder.c_str());
-            }
-        }
-        envVars.push_back(dyldSearchPath);
-    }
-    
-    AZStd::string commandArgs;
-    for (int i = 1; i < argc; i++)
-    {
-        commandArgs.append(argv[i]);
-        commandArgs.append(" ");
-    }
-    
-    AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
-    AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
-    processPath /= "AssetProcessor";
-    processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
-    processLaunchInfo.m_commandlineParameters = commandArgs;
-    processLaunchInfo.m_environmentVariables = &envVars;
-    processLaunchInfo.m_showWindow = true;
-
-    AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
-
-    application.Destroy();
-
-    return 0;
-}
-

+ 24 - 0
Code/Tools/BundleLauncher/CMakeLists.txt

@@ -0,0 +1,24 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+# This is the launcher that will be used by the O3DE_SDK.app bundle
+# generated by the cmake install process for Mac. 
+if(NOT ${PAL_PLATFORM_NAME} STREQUAL Mac)
+    return()
+endif()
+
+ly_add_target(
+    NAME O3DE_SDK EXECUTABLE
+    NAMESPACE AZ
+    FILES_CMAKE
+        O3DE_SDK_files.cmake
+    BUILD_DEPENDENCIES
+        PRIVATE
+            AZ::AzCore
+            AZ::AzFramework
+)

+ 63 - 0
Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp

@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzCore/Component/ComponentApplication.h>
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
+#include <AzCore/Utils/Utils.h>
+#include <AzFramework/Process/ProcessWatcher.h>
+
+#include <cstdlib>
+#include <mach-o/dyld.h>
+
+int main(int argc, char* argv[])
+{
+    // We need to pass in the engine path since we won't be able to find it by searching upwards.
+    // We can't use any containers that use our custom allocator till after the call to ComponentApplication::Create()
+    AZ::IO::FixedMaxPath processPath = AZ::Utils::GetExecutableDirectory();
+    AZ::IO::FixedMaxPath enginePath = (processPath / "../Engine").LexicallyNormal();
+    auto enginePathParam = AZ::SettingsRegistryInterface::FixedValueString::format(R"(--engine-path="%s")", enginePath.c_str());
+    // Uses the fixed_vector deduction guide to determine the type is AZStd::fixed_vector<char*, 2>
+    AZStd::fixed_vector commandLineParams{ processPath.Native().data(), enginePathParam.data() };
+
+
+    // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
+    AZ::ComponentApplication application(static_cast<int>(commandLineParams.size()), commandLineParams.data());
+    application.Create(AZ::ComponentApplication::Descriptor());
+ 
+    AZ::IO::FixedMaxPath installedBinariesFolder;
+    if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+    {
+        if (settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
+        {
+            installedBinariesFolder = enginePath / installedBinariesFolder;
+        }
+    }
+
+    AZ::IO::FixedMaxPath shellPath = "/bin/sh";
+    AZStd::string parameters = AZStd::string::format("-c \"export LY_CMAKE_PATH=/usr/local/bin && \"%s/python/get_python.sh\"\"", enginePath.c_str());
+    AzFramework::ProcessLauncher::ProcessLaunchInfo shellProcessLaunch;
+    shellProcessLaunch.m_processExecutableString = AZStd::move(shellPath.Native());
+    shellProcessLaunch.m_commandlineParameters = parameters;
+    shellProcessLaunch.m_showWindow = true;
+    shellProcessLaunch.m_workingDirectory = enginePath.String();
+    AZStd::unique_ptr<AzFramework::ProcessWatcher> shellProcess(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE));
+    shellProcess->WaitForProcessToExit(120);
+    shellProcess.reset();
+    
+    AZ::IO::FixedMaxPath projectManagerPath = installedBinariesFolder/"o3de.app"/"Contents"/"MacOS"/"o3de";
+    AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
+    processLaunchInfo.m_processExecutableString = AZStd::move(projectManagerPath.Native());
+    processLaunchInfo.m_showWindow = true;
+    AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
+
+    application.Destroy();
+
+    return 0;
+}
+

+ 11 - 0
Code/Tools/BundleLauncher/O3DE_SDK_files.cmake

@@ -0,0 +1,11 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(FILES
+    O3DE_SDK_Launcher.cpp
+)

+ 18 - 0
Code/Tools/BundleLauncher/info.plist

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleExecutable</key>
+	<string>O3DE_SDK</string>
+	<key>CFBundleIdentifier</key>
+	<string>org.O3DE.O3DE_SDK</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright (c) Contributors to the Open 3D Engine Project.</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>

+ 1 - 0
Code/Tools/CMakeLists.txt

@@ -20,3 +20,4 @@ add_subdirectory(GridHub)
 add_subdirectory(Standalone)
 add_subdirectory(TestImpactFramework)
 add_subdirectory(ProjectManager)
+add_subdirectory(BundleLauncher)

+ 1 - 0
Code/Tools/ProjectManager/Platform/Mac/PAL_mac.cmake

@@ -5,3 +5,4 @@
 # SPDX-License-Identifier: Apache-2.0 OR MIT
 #
 #
+

+ 2 - 0
Gems/Atom/Feature/Common/Code/CMakeLists.txt

@@ -40,6 +40,8 @@ ly_add_target(
             Gem::Atom_Feature_Common.Public
             Gem::ImGui.imguilib
             #3rdParty::lux_core # AZ_TRAIT_LUXCORE_SUPPORTED is disabled in every platform, Issue #3915 will remove
+    RUNTIME_DEPENDENCIES
+        Gem::ImGui.imguilib
 )
 
 ly_add_target(

+ 1 - 0
Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt

@@ -109,6 +109,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
         RUNTIME_DEPENDENCIES
             Gem::Atom_RPI.Editor
             Gem::Atom_Feature_Common.Editor
+            Legacy::EditorCommon
     )
 
     # The AtomLyIntegration_CommonFeatures.Editor module is used for Builders and Tools

+ 2 - 0
Gems/Camera/Code/CMakeLists.txt

@@ -61,6 +61,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
                 Legacy::EditorCommon
                 AZ::AzToolsFramework
                 Gem::Camera.Static
+        RUNTIME_DEPENDENCIES
+            Legacy::EditorCommon
     )
 
     # tools and builders use the above module.

+ 17 - 0
cmake/Install.cmake

@@ -152,3 +152,20 @@ function(ly_install_run_code CODE)
     )
 
 endfunction()
+
+#! ly_install_run_script: specifies path to script to be added to the install process (will run at install time)
+#
+# \notes: 
+#  - refer to cmake's install(SCRIPT documentation for more information
+#
+function(ly_install_run_script SCRIPT)
+
+    if(NOT LY_INSTALL_ENABLED)
+        return()
+    endif()
+
+    install(SCRIPT ${SCRIPT}
+        COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being
+    )
+
+endfunction()

+ 3 - 0
cmake/LYPython.cmake

@@ -21,14 +21,17 @@ include(cmake/LySet.cmake)
 # CMAKE_HOST_SYSTEM_NAME is  "Windows", "Darwin", or "Linux" in our cases..
 if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux" )
     ly_set(LY_PYTHON_VERSION 3.7.10)
+    ly_set(LY_PYTHON_VERSION_MAJOR_MINOR 3.7)
     ly_set(LY_PYTHON_PACKAGE_NAME python-3.7.10-rev2-linux)
     ly_set(LY_PYTHON_PACKAGE_HASH 6b9cf455e6190ec38836194f4454bb9db6bfc6890b4baff185cc5520aa822f05)
 elseif  (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin" )
     ly_set(LY_PYTHON_VERSION 3.7.10)
+    ly_set(LY_PYTHON_VERSION_MAJOR_MINOR 3.7)
     ly_set(LY_PYTHON_PACKAGE_NAME python-3.7.10-rev1-darwin)
     ly_set(LY_PYTHON_PACKAGE_HASH 3f65801894e4e44b5faa84dd85ef80ecd772dcf728cdd2d668a6e75978a32695)
 elseif  (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows" )
     ly_set(LY_PYTHON_VERSION 3.7.10)
+    ly_set(LY_PYTHON_VERSION_MAJOR_MINOR 3.7)
     ly_set(LY_PYTHON_PACKAGE_NAME python-3.7.10-rev2-windows)
     ly_set(LY_PYTHON_PACKAGE_HASH 06d97488a2dbabe832ecfa832a42d3e8a7163ba95e975f032727331b0f49d280)
 endif()

+ 14 - 11
cmake/Platform/Common/Install_common.cmake

@@ -21,15 +21,21 @@ define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET
 
 ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core)
 
-cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory)
-cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory)
-
 if(LY_MONOLITHIC_GAME)
     set(LY_BUILD_PERMUTATION Monolithic)
 else()
     set(LY_BUILD_PERMUTATION Default)
 endif()
 
+cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory)
+cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory)
+# Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target
+cmake_path(RELATIVE_PATH CMAKE_ARCHIVE_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE archive_output_directory)
+
+cmake_path(APPEND archive_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
+cmake_path(APPEND library_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
+cmake_path(APPEND runtime_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
+
 #! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target
 function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_target_source_dir)
     # De-alias target name
@@ -78,9 +84,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
         endforeach()
     endif()
 
-    # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target
-    cmake_path(RELATIVE_PATH CMAKE_ARCHIVE_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE archive_output_directory)
-
     get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY)
     if(target_runtime_output_directory)
         cmake_path(RELATIVE_PATH target_runtime_output_directory BASE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_runtime_output_subdirectory)
@@ -91,10 +94,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
         cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory)
     endif()
 
-    cmake_path(APPEND archive_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
-    cmake_path(APPEND library_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
-    cmake_path(APPEND runtime_output_directory "${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
-
     if(COMMAND ly_install_target_override)
         # Mac needs special handling because of a cmake issue
         ly_install_target_override(TARGET ${TARGET_NAME}
@@ -372,6 +371,10 @@ function(ly_setup_o3de_install)
         COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
     )
 
+    if(COMMAND ly_post_install_steps)
+        ly_post_install_steps()
+    endif()
+
 endfunction()
 
 #! ly_setup_cmake_install: install the "cmake" folder
@@ -528,7 +531,7 @@ endfunction()"
         # of baking the path. This is needed so `cmake --install --prefix <someprefix>` works regardless of the CMAKE_INSTALL_PREFIX
         # used to generate the solution.
         # CMAKE_INSTALL_PREFIX is still used when building the INSTALL target
-        set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${LY_BUILD_PERMUTATION}")
+        set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}")
         set(target_file_dir "${install_output_folder}/${target_runtime_output_subdirectory}")
         ly_get_runtime_dependencies(runtime_dependencies ${target})
         foreach(runtime_dependency ${runtime_dependencies})

+ 1 - 3
cmake/Platform/Mac/Configurations_mac.cmake

@@ -29,9 +29,7 @@ else()
 endif()
 
 # Signing
-# The "-o linker-signed" flag is required as a work-around for the following CMake issue:
-# https://gitlab.kitware.com/cmake/cmake/-/issues/21854
-ly_set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--deep -o linker-signed")
+ly_set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--deep")
 
 # Generate scheme files for Xcode
 ly_set(CMAKE_XCODE_GENERATE_SCHEME TRUE)

+ 168 - 0
cmake/Platform/Mac/InstallUtils_mac.cmake.in

@@ -0,0 +1,168 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+function(fixup_qt_framework lib_name framework_path)
+
+    file(REMOVE_RECURSE
+        ${framework_path}/Headers
+        ${framework_path}/Resources
+        ${framework_path}/${lib_name}
+        ${framework_path}/Versions/Current
+        ${framework_path}/Versions/5/Headers
+    )
+
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink 5 Current
+        WORKING_DIRECTORY ${framework_path}/Versions
+    )
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/${lib_name} ${lib_name}
+        WORKING_DIRECTORY ${framework_path}
+    )
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Resources Resources
+        WORKING_DIRECTORY ${framework_path}
+    )
+
+endfunction()
+
+function(fixup_python_framework framework_path)
+
+    file(REMOVE_RECURSE
+        ${framework_path}/Versions/Current
+        ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/Headers
+        ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/Python
+        ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/python@LY_PYTHON_VERSION_MAJOR_MINOR@/test
+        ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/python@LY_PYTHON_VERSION_MAJOR_MINOR@/site-packages/scipy/io/tests
+        ${framework_path}/Python
+        ${framework_path}/Resources
+        ${framework_path}/Headers
+    )
+    
+    file(GLOB_RECURSE exe_file_list "${framework_path}/**/*.exe")
+    if(exe_file_list)
+        file(REMOVE_RECURSE ${exe_file_list})
+    endif()
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink include/python@LY_PYTHON_VERSION_MAJOR_MINOR@m Headers
+        WORKING_DIRECTORY ${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@
+    )
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink @LY_PYTHON_VERSION_MAJOR_MINOR@ Current
+        WORKING_DIRECTORY ${framework_path}/Versions/
+    )
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Python Python
+        WORKING_DIRECTORY ${framework_path}
+    )
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Headers Headers
+        WORKING_DIRECTORY ${framework_path}
+    )
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Resources Resources
+        WORKING_DIRECTORY ${framework_path}
+    )
+    file(CHMOD ${framework_path}/Versions/Current/Python 
+        PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE 
+    )
+
+endfunction()
+
+function(codesign_file file entitlement_file)
+
+    if (NOT @LY_ENABLE_HARDENED_RUNTIME@)
+        return()
+    endif()
+
+    if(EXISTS ${entitlement_file})
+
+        execute_process(COMMAND "/usr/bin/codesign" "--force" "--sign" "@LY_CODE_SIGN_IDENTITY@" "--deep" "-o" "runtime" "--timestamp" "--entitlements" "${entitlement_file}" "${file}"
+            TIMEOUT 300
+            OUTPUT_VARIABLE codesign_out
+            RESULT_VARIABLE codesign_ret
+        )
+    else()
+        execute_process(COMMAND "/usr/bin/codesign" "--force" "--sign" "@LY_CODE_SIGN_IDENTITY@" "--deep" "-o" "runtime" "--timestamp" "${file}"
+            TIMEOUT 300
+            OUTPUT_VARIABLE codesign_out
+            RESULT_VARIABLE codesign_ret
+        )
+    endif()
+
+    if(NOT ${codesign_ret} EQUAL "0")
+        message(FATAL_ERROR "Codesign operation for ${file_path} returned ${codesign_ret} with message ${codesign_out}")
+    endif()
+
+endfunction()
+
+function(codesign_python_framework_binaries framework_path)
+
+    if (NOT @LY_ENABLE_HARDENED_RUNTIME@)
+        return()
+    endif()
+
+    # The codesign "--deep" flag will only codesign binaries in folders with specific names.
+    # We need to codesign all the binaries that the "--deep" flag will miss.
+    file(GLOB_RECURSE files
+        LIST_DIRECTORIES false
+        "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/bin/**"
+        "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/lib/**"
+        "${framework_path}/Versions/@LY_PYTHON_VERSION_MAJOR_MINOR@/Resources/**")
+
+    foreach(file ${files})
+        if(NOT EXISTS ${file})
+            file(REMOVE ${file})
+            continue()
+        endif()
+        cmake_path(SET path_var "${file}")
+        cmake_path(GET path_var EXTENSION LAST_ONLY extension)
+        set(should_codesign FALSE)
+        set(extension_skip_list ".dylib" ".so" ".7m")
+        if (NOT extension)
+            set(should_codesign TRUE)
+        elseif(extension IN_LIST extension_skip_list)
+            set(should_codesign TRUE)
+        endif()
+        if(${should_codesign})
+            codesign_file("${file}" "@LY_ROOT_FOLDER@/python/Platform/Mac/PythonEntitlements.plist")
+        endif()
+    endforeach()
+
+endfunction()
+
+function(ly_copy source_file target_directory)
+    
+    if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]")
+
+        # fixup origin to copy the whole Framework folder
+        string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}")
+
+    endif()
+    get_filename_component(target_filename "${source_file}" NAME)
+    file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN)
+
+    # Our Qt and Python frameworks aren't in the correct bundle format to be codesigned.
+    if("${target_filename}" MATCHES "(Qt[^.]+)\\.[Ff]ramework")
+        fixup_qt_framework(${CMAKE_MATCH_1} "${target_directory}/${target_filename}")
+        # For some Qt frameworks(QtCore), signing the bundle doesn't work because of bundle
+        # format issues(despite the fixes above). But once we've patched the framework above, there's
+        # only one executable that we need to sign so we can do it directly.
+        set(target_filename "${target_filename}/Versions/5/${CMAKE_MATCH_1}")
+    elseif("${target_filename}" MATCHES "Python.framework")
+        fixup_python_framework("${target_directory}/${target_filename}")
+        codesign_python_framework_binaries("${target_directory}/${target_filename}")
+    endif()
+    codesign_file("${target_directory}/${target_filename}" "none")
+
+endfunction()
+
+function(ly_download_and_codesign_sdk_python)
+    execute_process(COMMAND ${CMAKE_COMMAND} -DPAL_PLATFORM_NAME=Mac -DLY_3RDPARTY_PATH=${CMAKE_INSTALL_PREFIX}/python -P ${CMAKE_INSTALL_PREFIX}/python/get_python.cmake)
+    fixup_python_framework(${CMAKE_INSTALL_PREFIX}/python/runtime/@LY_PYTHON_PACKAGE_NAME@/Python.framework)
+    codesign_python_framework_binaries(${CMAKE_INSTALL_PREFIX}/python/runtime/@LY_PYTHON_PACKAGE_NAME@/Python.framework)
+    codesign_file(${CMAKE_INSTALL_PREFIX}/python/runtime/@LY_PYTHON_PACKAGE_NAME@/Python.framework @LY_ROOT_FOLDER@/python/Platform/Mac/PythonEntitlements.plist)
+endfunction()
+
+function(ly_codesign_sdk)
+    codesign_file(${LY_INSTALL_PATH_ORIGINAL}/O3DE_SDK.app "none")
+endfunction()
+
+

+ 62 - 26
cmake/Platform/Mac/Install_mac.cmake

@@ -6,6 +6,8 @@
 #
 #
 
+include(cmake/Platform/Common/Install_common.cmake)
+
 # This is used to generate a setreg file which will be placed inside the bundle
 # for targets that request it(eg. AssetProcessor/Editor). This is the relative path
 # to the bundle from the installed engine's root. This will be used to compute the
@@ -16,7 +18,7 @@ set(installed_binaries_path_template [[
         "AzCore": {
             "Runtime": {
                 "FilePaths": {
-                    "InstalledBinariesFolder": "bin/Mac/$<CONFIG>"
+                    "InstalledBinariesFolder": "@runtime_output_directory@"
                 }
             }
         }
@@ -24,15 +26,20 @@ set(installed_binaries_path_template [[
 }]]
 )
 
-unset(target_conf_dir)
-foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
-    string(TOUPPER ${conf} UCONF)
-    string(APPEND target_conf_dir $<$<CONFIG:${conf}>:${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${UCONF}}>)
-endforeach()
-
-set(installed_binaries_setreg_path ${target_conf_dir}/Registry/installed_binaries_path.setreg)
+# This setreg file will be used by all of our installed app bundles to locate installed
+# runtime dependencies. It contains the path to binary install directory relative to 
+# the installed engine root.
+string(CONFIGURE "${installed_binaries_path_template}" configured_setreg_file)
+file(GENERATE
+    OUTPUT ${CMAKE_BINARY_DIR}/runtime_install/$<CONFIG>/BinariesInstallPath.setreg
+    CONTENT "${configured_setreg_file}"
+)
 
-file(GENERATE OUTPUT ${installed_binaries_setreg_path} CONTENT ${installed_binaries_path_template})
+# ly_install_run_script isn't defined yet so we use install(SCRIPT) directly.
+# This needs to be done here because it needs to update the install prefix 
+# before cmake does anything else in the install process.
+configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake @ONLY)
+install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
 
 #! ly_install_target_override: Mac specific target installation
 function(ly_install_target_override)
@@ -70,33 +77,62 @@ function(ly_install_target_override)
             COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
     )
 
+    set(install_relative_binaries_path "${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR}")
+
     if (${is_bundle})
         set_property(TARGET ${ly_platform_install_target_TARGET} PROPERTY RESOURCE ${cached_resources_dir})
+        set(runtime_output_filename "$<TARGET_FILE_NAME:${ly_platform_install_target_TARGET}>.app")
+    else()
+        set(runtime_output_filename "$<TARGET_FILE_NAME:${ly_platform_install_target_TARGET}>")
+    endif()
+    
+    get_target_property(target_type ${ly_platform_install_target_TARGET} TYPE)
+    if(target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS)
+        get_target_property(entitlement_file ${ly_platform_install_target_TARGET} ENTITLEMENT_FILE_PATH)
+        if (NOT entitlement_file)
+            set(entitlement_file "none")
+        endif()
+        
+        ly_file_read(${LY_ROOT_FOLDER}/cmake/Platform/Mac/runtime_install_mac.cmake.in template_file)
+        string(CONFIGURE "${template_file}" configured_template_file @ONLY)
+        file(GENERATE
+            OUTPUT ${CMAKE_BINARY_DIR}/runtime_install/$<CONFIG>/${ly_platform_install_target_TARGET}.cmake
+            CONTENT "${configured_template_file}"
+        )
     endif()
-endfunction()
-
-#! ly_install_add_install_path_setreg: Adds the install path setreg file as a dependency
-function(ly_install_add_install_path_setreg NAME)
-    set_property(TARGET ${NAME} APPEND PROPERTY INTERFACE_LY_TARGET_FILES "${installed_binaries_setreg_path}\nRegistry")
 endfunction()
 
 #! ly_install_code_function_override: Mac specific copy function to handle frameworks
 function(ly_install_code_function_override)
 
-    install(CODE
-"function(ly_copy source_file target_directory)
-    if(\"\${source_file}\" MATCHES \"\\\\.[Ff]ramework[^\\\\.]\")
+    configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/InstallUtils_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake @ONLY)
+    ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake)
 
-        # fixup origin to copy the whole Framework folder
-        string(REGEX REPLACE \"(.*\\\\.[Ff]ramework).*\" \"\\\\1\" source_file \"\${source_file}\")
-        get_filename_component(target_filename \"\${source_file}\" NAME)
+endfunction()
 
-    endif()
-    file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS})
-endfunction()"
-    COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
-    )
+#! ly_post_install_steps: Any additional platform specific post install steps
+function(ly_post_install_steps)
+
+    # On Mac, after CMake is done installing, the code signatures on all our built binaries will be invalid.
+    # We need to now codesign each dynamic library, executable, and app bundle. It's specific to each target
+    # because there could potentially be different entitlements for different targets.
+    get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS)
+    foreach(alias_target IN LISTS all_targets)
+        ly_de_alias_target(${alias_target} target)
+        # Exclude targets that dont produce runtime outputs
+        get_target_property(target_type ${target} TYPE)
+        if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS)
+            continue()
+        endif()
+        
+        ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/$<CONFIG>/${target}.cmake)
+    endforeach()
+
+    ly_install_run_code("
+        ly_download_and_codesign_sdk_python()
+        ly_codesign_sdk()
+        set(CMAKE_INSTALL_PREFIX ${LY_INSTALL_PATH_ORIGINAL})
+    ")
 
 endfunction()
 
-include(cmake/Platform/Common/Install_common.cmake)

+ 22 - 0
cmake/Platform/Mac/LYWrappers_mac.cmake

@@ -6,6 +6,16 @@
 #
 #
 
+set(LY_ENABLE_HARDENED_RUNTIME OFF CACHE BOOL "Enable hardened runtime capability for Mac builds. This should be ON when building the engine for notarization/distribution.")
+
+define_property(TARGET PROPERTY ENTITLEMENT_FILE_PATH
+    BRIEF_DOCS "Path to the entitlement file"
+    FULL_DOCS [[
+        On MacOS, entitlements are used to grant certain privileges
+        to applications at runtime. Use this propery to specify the
+        path to a .plist file containing entitlements.
+    ]]
+)
 
 function(ly_apply_platform_properties target)
 
@@ -14,6 +24,18 @@ function(ly_apply_platform_properties target)
         INSTALL_RPATH "@executable_path/;@executable_path/../Frameworks"
     )
 
+    get_property(is_imported TARGET ${target} PROPERTY IMPORTED)
+    if((NOT is_imported) AND (LY_ENABLE_HARDENED_RUNTIME))
+        get_property(target_type TARGET ${target} PROPERTY TYPE)
+        set(runtime_types_list "MODULE_LIBRARY" "SHARED_LIBRARY" "EXECUTABLE")
+        if (target_type IN_LIST runtime_types_list)
+            set_target_properties(${target} PROPERTIES
+                XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES
+                XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS NO
+            )
+        endif()
+    endif()
+
 endfunction()
 
 

+ 3 - 0
cmake/Platform/Mac/PAL_mac.cmake

@@ -39,3 +39,6 @@ set(LY_ASSET_DEPLOY_ASSET_TYPE "mac" CACHE STRING "Set the asset type for deploy
 
 # Set the python cmd tool
 ly_set(LY_PYTHON_CMD ${CMAKE_CURRENT_SOURCE_DIR}/python/python.sh)
+
+# Only x86_64 is currently supported on Mac
+ly_set(CMAKE_OSX_ARCHITECTURES "x86_64")

+ 39 - 0
cmake/Platform/Mac/PreInstallSteps_mac.cmake.in

@@ -0,0 +1,39 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+cmake_minimum_required(VERSION 3.20)
+
+# The O3DE SDK will be shipped as an app bundle. So we create an O3DE_SDK.app directory
+# and install SDK into the app's Contents/Engine directory.
+set(LY_INSTALL_PATH_ORIGINAL ${CMAKE_INSTALL_PREFIX})
+
+file(INSTALL @LY_ROOT_FOLDER@/Code/Tools/BundleLauncher/info.plist
+    DESTINATION ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents
+)
+
+# This SDK launcher will install python site-packages and then launch the ProjectManager
+# when a user double clicks on the SDK from Finder. We're only going to need one version
+# of the SDK launcher regardless of what configs of the engine are installed.
+if (EXISTS @CMAKE_BINARY_DIR@/bin/profile/O3DE_SDK)
+    set(sdk_launcher_config profile)
+elseif (EXISTS @CMAKE_BINARY_DIR@/bin/debug/O3DE_SDK)
+    set(sdk_launcher_config debug)
+elseif (EXISTS @CMAKE_BINARY_DIR@/bin/release/O3DE_SDK)
+    set(sdk_launcher_config release)
+endif()
+file(INSTALL @CMAKE_BINARY_DIR@/bin/${sdk_launcher_config}/O3DE_SDK
+    DESTINATION ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/MacOS
+    USE_SOURCE_PERMISSIONS
+)
+file(INSTALL @CMAKE_BINARY_DIR@/runtime_install/${sdk_launcher_config}/BinariesInstallPath.setreg
+    DESTINATION ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/MacOS/Registry
+)
+
+# We need to update the CMAKE_INSTALL_PREFIX so that the engine is installed inside the app bundle.
+file(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/Engine)
+set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/O3DE_SDK.app/Contents/Engine)

+ 2 - 3
cmake/Platform/Mac/runtime_dependencies_mac.cmake.in

@@ -73,8 +73,8 @@ function(ly_copy source_file target_directory)
                 return()
             endif()
 
-            # fixup the destination so it ends up in Contents/Plugins
-            string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/plugins" target_directory "${target_directory}")
+            # fixup the destination so it ends up in Contents/PlugIns
+            string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/PlugIns" target_directory "${target_directory}")
 
             set(local_plugin_dirs ${plugin_dirs})
             list(APPEND local_plugin_dirs "${target_directory}")
@@ -212,7 +212,6 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS")
             file(REMOVE_RECURSE ${remove_file_list})
         endif()
 
-
     endif()
 
 else() # Non-bundle case

+ 34 - 0
cmake/Platform/Mac/runtime_install_mac.cmake.in

@@ -0,0 +1,34 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+cmake_path(SET file_path "${CMAKE_INSTALL_PREFIX}/@install_relative_binaries_path@/@runtime_output_filename@")
+cmake_path(GET file_path EXTENSION LAST_ONLY file_ext)
+
+if(file_ext STREQUAL .app)
+
+    file(INSTALL @CMAKE_BINARY_DIR@/runtime_install/$<CONFIG>/BinariesInstallPath.setreg
+        DESTINATION ${file_path}/Contents/MacOS/Registry
+    )
+
+    if(EXISTS "${file_path}/Contents/Frameworks/Python.framework")
+        codesign_python_framework_binaries("${file_path}/Contents/Frameworks/Python.framework")
+    endif()
+
+else()
+
+    find_program(LY_INSTALL_NAME_TOOL install_name_tool)
+    if (NOT LY_INSTALL_NAME_TOOL)
+        message(FATAL_ERROR "Unable to locate 'install_name_tool'")
+    endif()
+
+    execute_process(COMMAND
+        ${LY_INSTALL_NAME_TOOL} -add_rpath @loader_path ${file_path})
+
+endif()
+
+codesign_file("${file_path}" "@entitlement_file@")

+ 10 - 0
python/Platform/Mac/PythonEntitlements.plist

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.security.cs.disable-library-validation</key>
+	<true/>
+	<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+	<true/>
+</dict>
+</plist>

+ 4 - 2
python/get_python.sh

@@ -30,7 +30,8 @@ cd $DIR
 python_exitcode=$?
 if [ $python_exitcode == 0 ]; then
     echo get_python.sh: Python is already downloaded: $(./python.sh --version)
-    $DIR/pip.sh install -r $DIR/requirements.txt --quiet --disable-pip-version-check
+    $DIR/pip.sh install -r $DIR/requirements.txt --disable-pip-version-check --no-warn-script-location
+    $DIR/pip.sh install -e $DIR/../scripts/o3de --no-deps --disable-pip-version-check  --no-warn-script-location
     exit 0
 fi
 if [[ "$OSTYPE" = *"darwin"* ]];
@@ -73,5 +74,6 @@ if [ $retVal -ne 0 ]; then
 fi
 
 echo installing via pip...
-$DIR/pip.sh install -r $DIR/requirements.txt --disable-pip-version-check
+$DIR/pip.sh install -r $DIR/requirements.txt --disable-pip-version-check --no-warn-script-location
+$DIR/pip.sh install -e $DIR/../scripts/o3de --no-deps --disable-pip-version-check  --no-warn-script-location
 exit $?