Pārlūkot izejas kodu

Fix Linux Python Installer issues (#18406) (#18454)

Fixes for Linux installer

- Disable python bytecode generation (through pybind and the python script calls)
- Fix example python file's use of print
- Fix installed SDK issue with EditorPythonBindings where pybind is unable to run python scripts that import math resulting in `_ctypes.cpython-39-x86_64-linux-gnu.so: undefined symbol: PyFloat_Type`
- Fixed by applying the same approach as QtForPython gem where the module will preload into memory the python shared library (in Linux)
- double quote path for python activate for linux

---------

Signed-off-by: Steve Pham <[email protected]>
Steve Pham 8 mēneši atpakaļ
vecāks
revīzija
c98435a95b

+ 1 - 1
Assets/Editor/Scripts/TrackView/example.py

@@ -12,4 +12,4 @@ This example script prints info of all TrackView sequences
 numTracks = trackview.get_num_sequences()
 
 for i in range(numTracks):
-    print "Sequence '", trackview.get_sequence_name(i), "':"
+    print(f"Sequence '{trackview.get_sequence_name(i)}':")

+ 1 - 1
Code/Framework/AzFramework/AzFramework/Application/Application.cpp

@@ -663,7 +663,7 @@ namespace AzFramework
         if (attemptNumber >= maxAttempts)
         {
             userCachePath.ReplaceFilename(userCachePathFilename);
-            AZ_TracePrintf("Application", "Couldn't find a valid asset cache folder after %i attempts."
+            AZ_WarningOnce("Application", false, "Couldn't find a valid asset cache folder after %i attempts."
                 " Setting cache folder to %s\n", maxAttempts, userCachePath.c_str());
         }
 #endif

+ 62 - 0
Code/Tools/ProjectManager/Resources/o3de_desktop.svg

@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" enable-background="new 0 0 32 32" version="1.1" xml:space="preserve">
+ <style type="text/css">.st0{fill:#1E70EB;}
+	.st1{fill:#4B8DEF;}
+	.st2{fill:#D2E2FB;}
+	.st3{fill:#A5C6F7;}
+	.st4{fill:#78A9F3;}
+	.st5{fill:#FFFFFF;}</style>
+ <g class="layer">
+  <title>Layer 1</title>
+  <g id="Layer_2_00000105401350261555836710000004394938160100456581_" transform="translate(-1 0) translate(-1 0) translate(-1 0) translate(-1 0)"/>
+  <g id="svg_1" transform="translate(-0.125 0) translate(-0.125 0) matrix(1 0 0 1 -3.125 0)">
+   <g id="Gem">
+    <g id="svg_2">
+     <g id="svg_3">
+      <path class="st0" d="m29.6,21.9l0.8,2.3l0.8,2.3c1.5,-1.6 2.6,-3.5 3.3,-5.7l-2.4,0.5l-2.5,0.6z" id="svg_4"/>
+      <path class="st0" d="m21.8,27.5l-1.2,2.1l-1.2,2.1c2.3,0 4.4,-0.5 6.4,-1.4l-2,-1.4l-2,-1.4z" id="svg_5"/>
+      <path class="st0" d="m26.3,25.5l-0.3,2.4l-0.3,2.4c2,-0.9 3.8,-2.2 5.3,-3.8l-2.3,-0.5l-2.4,-0.5z" id="svg_6"/>
+     </g>
+     <g id="svg_7">
+      <path class="st1" d="m9.2,21.9l-2.4,-0.5l-2.4,-0.5c0.7,2.1 1.8,4 3.3,5.7l0.8,-2.3l0.7,-2.4z" id="svg_8"/>
+      <path class="st1" d="m31.1,17.3l1.6,1.8l1.6,1.8c0.5,-1.5 0.8,-3.2 0.8,-4.9c0,-0.6 0,-1.1 -0.1,-1.6l-2,1.4l-1.9,1.5z" id="svg_9"/>
+      <path class="st1" d="m30.6,12.4l2.2,1l2.2,1c-0.2,-2.2 -0.9,-4.3 -2,-6.2l-1.2,2.1l-1.2,2.1z" id="svg_10"/>
+      <path class="st1" d="m12.5,25.5l-2.4,0.5l-2.4,0.5c1.5,1.6 3.3,2.9 5.3,3.8l-0.3,-2.4l-0.2,-2.4z" id="svg_11"/>
+      <path class="st1" d="m17,27.5l-2,1.4l-2,1.4c2,0.9 4.1,1.4 6.4,1.4c0,0 0,0 0,0l-1.2,-2.1l-1.2,-2.1z" id="svg_12"/>
+      <path class="st1" d="m21.8,27.5l0,0l2,1.4l2,1.4l0.3,-2.4l0.3,-2.4l0,0c-1.4,1 -2.9,1.7 -4.6,2z" id="svg_13"/>
+      <path class="st1" d="m29.6,21.9l0,0c-0.8,1.4 -1.9,2.7 -3.3,3.6l0,0l2.4,0.5l2.4,0.5c0,0 0,0 0,0l-0.8,-2.3l-0.7,-2.3z" id="svg_14"/>
+     </g>
+     <g id="svg_15">
+      <path class="st2" d="m24.2,5.3l0,0l-0.8,-2.3l-0.8,-2.3l-1.6,1.8l-1.6,1.8l0,0c1.7,0 3.3,0.4 4.8,1z" id="svg_16"/>
+      <path class="st2" d="m19.4,4.3l0,0l-1.6,-1.8l-1.6,-1.8l-0.8,2.3l-0.8,2.3l0,0c1.5,-0.6 3.1,-1 4.8,-1z" id="svg_17"/>
+      <path class="st2" d="m10.7,8.2l0,0c1.1,-1.2 2.4,-2.2 3.9,-2.9l0,0l-2.2,-1l-2.2,-1c0,0 0,0 0,0l0.3,2.4l0.2,2.5z" id="svg_18"/>
+      <path class="st2" d="m10.7,8.2l0,0l-2.4,0l-2.5,0l1.2,2.1l1.2,2.1l0,0c0.6,-1.6 1.4,-3 2.5,-4.2z" id="svg_19"/>
+      <path class="st2" d="m3.8,14.4l2,1.4l2,1.4l0,0c0,-0.4 -0.1,-0.8 -0.1,-1.2c0,-1.3 0.2,-2.5 0.6,-3.6l0,0l-2.2,1l-2.3,1c0,0 0,0 0,0z" id="svg_20"/>
+     </g>
+     <g id="svg_21">
+      <path class="st3" d="m10.7,8.2l0,0l0,0l-0.3,-2.4l-0.3,-2.4c-1.7,1.2 -3.2,2.9 -4.3,4.8l2.4,0l2.5,0z" id="svg_22"/>
+      <path class="st3" d="m6,13.4l2.2,-1l0,0l0,0l-1.2,-2.1l-1.2,-2.1c-1.1,1.9 -1.8,4 -2,6.2l2.2,-1z" id="svg_23"/>
+      <path class="st3" d="m14.6,5.3l0.8,-2.3l0.8,-2.3c-2.2,0.5 -4.2,1.4 -6,2.7l2.2,1l2.2,0.9z" id="svg_24"/>
+      <path class="st3" d="m19.4,4.3l1.6,-1.8l1.6,-1.8c-1.1,-0.2 -2.1,-0.3 -3.3,-0.3c-1.1,0 -2.2,0.1 -3.3,0.3l1.6,1.8l1.8,1.8z" id="svg_25"/>
+      <path class="st3" d="m30.6,12.4l0,0l1.2,-2.1l1.2,-2.1l-2.4,0l-2.4,0l0,0c1,1.2 1.8,2.6 2.4,4.2z" id="svg_26"/>
+      <path class="st3" d="m24.2,5.3l0,0c1.5,0.7 2.8,1.7 3.9,2.9l0,0l0.3,-2.4l0.3,-2.4c0,0 0,0 0,0l-2.2,1l-2.3,0.9z" id="svg_27"/>
+      <path class="st3" d="m7.7,17.3l0,0l-1.6,1.8l-1.6,1.8l2.4,0.5l2.4,0.5l0,0c-0.9,-1.4 -1.4,-3 -1.6,-4.6z" id="svg_28"/>
+      <path class="st3" d="m12.5,25.5l0,0c-1.3,-1 -2.4,-2.2 -3.3,-3.6l0,0l-0.8,2.3l-0.8,2.3c0,0 0,0 0,0l2.4,-0.5l2.5,-0.5z" id="svg_29"/>
+     </g>
+     <g id="svg_30">
+      <path class="st4" d="m7.7,17.3l-2,-1.4l-2,-1.4c-0.1,0.5 -0.1,1.1 -0.1,1.6c0,1.7 0.3,3.3 0.8,4.9l1.6,-1.8l1.7,-1.9z" id="svg_31"/>
+      <path class="st4" d="m28.1,8.2l2.4,0l2.4,0c-1.1,-1.9 -2.6,-3.6 -4.4,-4.9l-0.3,2.4l-0.1,2.5z" id="svg_32"/>
+      <path class="st4" d="m24.2,5.3l2.2,-1l2.2,-1c-1.7,-1.3 -3.8,-2.2 -6,-2.7l0.8,2.4l0.8,2.3z" id="svg_33"/>
+      <path class="st4" d="m21.8,27.5l0,0c-0.8,0.2 -1.6,0.3 -2.4,0.3c-0.8,0 -1.7,-0.1 -2.4,-0.3l0,0l1.2,2.1l1.2,2.1l1.2,-2.1l1.2,-2.1z" id="svg_34"/>
+      <path class="st4" d="m29.6,21.9l0,0l2.4,-0.5l2.4,-0.5l-1.6,-1.8l-1.6,-1.8l0,0c-0.3,1.6 -0.8,3.2 -1.6,4.6z" id="svg_35"/>
+      <path class="st4" d="m31.1,16c0,0.4 0,0.8 -0.1,1.2l0,0l2,-1.4l2,-1.4c0,0 0,0 0,0l-2.2,-1l-2.2,-1l0,0c0.3,1.1 0.5,2.4 0.5,3.6z" id="svg_36"/>
+      <path class="st4" d="m12.5,25.5l0,0l0.2,2.4l0.3,2.4l2,-1.4l2,-1.4l0,0c-1.7,-0.3 -3.2,-1 -4.5,-2z" id="svg_37"/>
+     </g>
+    </g>
+   </g>
+   <g id="Letters">
+    <path class="st5" d="m19.4,4.3c-6.5,0 -11.7,5.2 -11.7,11.7s5.3,11.7 11.7,11.7s11.7,-5.2 11.7,-11.7s-5.2,-11.7 -11.7,-11.7zm0,19.3c-4.2,0 -7.6,-3.4 -7.6,-7.6s3.4,-7.6 7.6,-7.6s7.6,3.4 7.6,7.6s-3.4,7.6 -7.6,7.6z" id="svg_38"/>
+   </g>
+  </g>
+ </g>
+</svg>

+ 7 - 6
Code/Tools/ProjectManager/Source/PythonBindings.cpp

@@ -295,12 +295,6 @@ namespace O3DE::ProjectManager
         AZStd::to_wstring(pyHomePath, pyBasePath);
         Py_SetPythonHome(pyHomePath.c_str());
 
-        // display basic Python information
-        AZ_TracePrintf("python", "Py_GetVersion=%s \n", Py_GetVersion());
-        AZ_TracePrintf("python", "Py_GetPath=%ls \n", Py_GetPath());
-        AZ_TracePrintf("python", "Py_GetExecPrefix=%ls \n", Py_GetExecPrefix());
-        AZ_TracePrintf("python", "Py_GetProgramFullPath=%ls \n", Py_GetProgramFullPath());
-
         PyImport_AppendInittab("azlmbr_redirect", RedirectOutput::PyInit_RedirectOutput);
 
         try
@@ -308,10 +302,17 @@ namespace O3DE::ProjectManager
             // ignore system location for sites site-packages
             Py_IsolatedFlag = 1; // -I - Also sets Py_NoUserSiteDirectory.  If removed PyNoUserSiteDirectory should be set.
             Py_IgnoreEnvironmentFlag = 1; // -E
+            Py_DontWriteBytecodeFlag = 1; // Do not generate precompiled bytecode
 
             const bool initializeSignalHandlers = true;
             pybind11::initialize_interpreter(initializeSignalHandlers);
 
+            // display basic Python information
+            AZ_Trace("python", "Py_GetVersion=%s \n", Py_GetVersion());
+            AZ_Trace("python", "Py_GetPath=%ls \n", Py_GetPath());
+            AZ_Trace("python", "Py_GetExecPrefix=%ls \n", Py_GetExecPrefix());
+            AZ_Trace("python", "Py_GetProgramFullPath=%ls \n", Py_GetProgramFullPath());
+
             RedirectOutput::Intialize(PyImport_ImportModule("azlmbr_redirect"), &PythonBindings::OnStdOut, &PythonBindings::OnStdError);
 
             // Add custom site packages after initializing the interpreter above.  Calling Py_SetPath before initialization

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

@@ -40,6 +40,8 @@ ly_add_target(
     FILES_CMAKE
         editorpythonbindings_editor_files.cmake
     INCLUDE_DIRECTORIES
+        PRIVATE
+            ${CMAKE_CURRENT_SOURCE_DIR}/Source/Platform/${PAL_PLATFORM_NAME}
         PRIVATE
             .
             Source

+ 4 - 0
Gems/EditorPythonBindings/Code/Source/EditorPythonBindingsModule.cpp

@@ -16,11 +16,14 @@
 #include <PythonMarshalComponent.h>
 #include <PythonLogSymbolsComponent.h>
 
+#include <InitializePython.h>
+
 namespace EditorPythonBindings
 {
     class EditorPythonBindingsModule
         : public AZ::Module
         , public AzToolsFramework::EmbeddedPython::PythonLoader
+        , private InitializePython
     {
     public:
         AZ_RTTI(EditorPythonBindingsModule, "{851B9E35-4FD5-49B1-8207-E40D4BBA36CC}", AZ::Module);
@@ -28,6 +31,7 @@ namespace EditorPythonBindings
 
         EditorPythonBindingsModule()
             : AZ::Module()
+            , InitializePython()
         {
             m_descriptors.insert(m_descriptors.end(), 
             {

+ 54 - 0
Gems/EditorPythonBindings/Code/Source/Platform/Linux/InitializePython.h

@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ */
+#pragma once
+
+#include <AzCore/Debug/Trace.h>
+#include <dlfcn.h>
+
+namespace EditorPythonBindings
+{
+    // s_libPythonLibraryFile must match the library name listed in (O3DE Engine Root)/python/runtime/.../python-config.cmake
+    // in the set(${MY}_LIBRARY_xxxx sections.
+    const char* s_libPythonLibraryFile = "libpython3.10.so.1.0"; 
+
+    class InitializePython
+    {
+    public:
+        InitializePython()
+        {
+            m_libPythonLibraryFile = InitializePython::LoadModule(s_libPythonLibraryFile);
+        }
+        virtual ~InitializePython()
+        {
+            InitializePython::UnloadModule(m_libPythonLibraryFile);
+        }
+
+    private:
+        static void* LoadModule(const char* moduleToLoad)
+        {
+            void* moduleHandle = dlopen(moduleToLoad, RTLD_NOW | RTLD_GLOBAL);
+            if (!moduleHandle)
+            {
+                [[maybe_unused]] const char* loadError = dlerror();
+                AZ_Error("EditorPythonBindings", false, "Unable to load python library %s for EditorPythonBindings: %s", moduleToLoad,
+                         loadError ? loadError : "Unknown Error");
+            }
+            return moduleHandle;
+        }
+
+        static void UnloadModule(void* moduleHandle)
+        {
+            if (moduleHandle)
+            {
+                dlclose(moduleHandle);
+            }
+        }
+
+        void* m_libPythonLibraryFile;
+    };
+} // namespace EditorPythonBindings

+ 18 - 0
Gems/EditorPythonBindings/Code/Source/Platform/Mac/InitializePython.h

@@ -0,0 +1,18 @@
+/*
+ * 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
+ *
+ */
+#pragma once
+
+namespace EditorPythonBindings
+{
+    class InitializePython
+    {
+    public:
+        InitializePython() = default;
+        virtual ~InitializePython() = default;
+    };
+} // namespace EditorPythonBindings

+ 18 - 0
Gems/EditorPythonBindings/Code/Source/Platform/Windows/InitializePython.h

@@ -0,0 +1,18 @@
+/*
+ * 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
+ *
+ */
+#pragma once
+
+namespace EditorPythonBindings
+{
+    class InitializePython
+    {
+    public:
+        InitializePython() = default;
+        virtual ~InitializePython() = default;
+    };
+} // namespace EditorPythonBindings

+ 8 - 6
Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp

@@ -573,12 +573,6 @@ namespace EditorPythonBindings
         AZStd::to_wstring(pyHomePath, pyBasePath);
         Py_SetPythonHome(pyHomePath.c_str());
 
-        // display basic Python information
-        AZ_TracePrintf("python", "Py_GetVersion=%s \n", Py_GetVersion());
-        AZ_TracePrintf("python", "Py_GetPath=%ls \n", Py_GetPath());
-        AZ_TracePrintf("python", "Py_GetExecPrefix=%ls \n", Py_GetExecPrefix());
-        AZ_TracePrintf("python", "Py_GetProgramFullPath=%ls \n", Py_GetProgramFullPath());
-
         PyImport_AppendInittab("azlmbr_redirect", RedirectOutput::PyInit_RedirectOutput);
         try
         {
@@ -586,10 +580,17 @@ namespace EditorPythonBindings
             Py_IsolatedFlag = 1; // -I - Also sets Py_NoUserSiteDirectory.  If removed PyNoUserSiteDirectory should be set.
             Py_IgnoreEnvironmentFlag = 1; // -E
             Py_InspectFlag = 1; // unhandled SystemExit will terminate the process unless Py_InspectFlag is set
+            Py_DontWriteBytecodeFlag = 1; // Do not generate precompiled bytecode
 
             const bool initializeSignalHandlers = true;
             pybind11::initialize_interpreter(initializeSignalHandlers);
 
+            // display basic Python information
+            AZ_Trace("python", "Py_GetVersion=%s \n", Py_GetVersion());
+            AZ_Trace("python", "Py_GetPath=%ls \n", Py_GetPath());
+            AZ_Trace("python", "Py_GetExecPrefix=%ls \n", Py_GetExecPrefix());
+            AZ_Trace("python", "Py_GetProgramFullPath=%ls \n", Py_GetProgramFullPath());
+
             // Add custom site packages after initializing the interpreter above.  Calling Py_SetPath before initialization
             // alters the behavior of the initializer to not compute default search paths. See https://docs.python.org/3/c-api/init.html#c.Py_SetPath
             if (pyPackageSites.size())
@@ -817,6 +818,7 @@ namespace EditorPythonBindings
             const int updatePath = 1;
             PySys_SetArgvEx(argc, argv, updatePath);
 
+            Py_DontWriteBytecodeFlag = 1;
             PyCompilerFlags flags;
             flags.cf_flags = 0;
             const int bAutoCloseFile = true;

+ 1 - 1
cmake/Platform/Common/Install_common.cmake

@@ -1171,7 +1171,7 @@ function(ly_setup_o3de_install)
 
     if("$ENV{O3DE_PACKAGE_TYPE}" STREQUAL "DEB")
         ly_install(FILES
-            ${LY_ROOT_FOLDER}/Code/Tools/ProjectManager/Resources/o3de.svg
+            ${LY_ROOT_FOLDER}/Code/Tools/ProjectManager/Resources/o3de_desktop.svg
             DESTINATION .
             COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}
         )

+ 19 - 13
cmake/Platform/Linux/Packaging/postinst.in

@@ -10,9 +10,10 @@
 set -o errexit # exit on the first failure encountered
 
 {
-    ln -s @CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/o3de /usr/local/bin/o3de
-    ln -s @CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/AssetProcessor /usr/local/bin/o3de.assetprocessor
-    ln -s @CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/Editor /usr/local/bin/o3de.editor
+    ln -s -f @CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/o3de /usr/local/bin/o3de
+    ln -s -f @CPACK_PACKAGING_INSTALL_PREFIX@/scripts/o3de.sh /usr/local/bin/o3de.sh
+    ln -s -f @CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/AssetProcessor /usr/local/bin/o3de.assetprocessor
+    ln -s -f @CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/Editor /usr/local/bin/o3de.editor
 
     # Generate the desktop icon
     DESKTOP_ICON_FILE=/usr/share/applications/o3de.desktop
@@ -24,20 +25,25 @@ Comment=O3DE Project Manager\n\
 Type=Application\n\
 Exec=@CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/o3de\n\
 Path=@CPACK_PACKAGING_INSTALL_PREFIX@/bin/Linux/profile/Default/\n\
-Icon=@CPACK_PACKAGING_INSTALL_PREFIX@/o3de.svg\n\
+Icon=@CPACK_PACKAGING_INSTALL_PREFIX@/o3de_desktop.svg\n\
 Terminal=false\n\
 StartupWMClass=O3DE.SNAP\n\
 StartupNotify=true\n\
 X-GNOME-Autostart-enabled=true\n\
 " > $DESKTOP_ICON_FILE
 
-    if [ "" != "$SUDO_USER" ]
-    then
-        pushd @CPACK_PACKAGING_INSTALL_PREFIX@
-        chown -R $SUDO_USER .
-        sudo -u $SUDO_USER python/get_python.sh
-        popd
-    fi
+    pushd @CPACK_PACKAGING_INSTALL_PREFIX@
 
-} 
-#&> /dev/null # hide output
+    # Clear out any previously generated egg-info linked folder (as a result of the installer build)
+    sudo rm -rf scripts/o3de/o3de.egg-info
+
+    # The following folders must be writeable to support the egg-info creation during the bootstrapping of 
+    # python.
+    sudo chmod a+w Tools/LyTestTools
+    sudo chmod a+w Tools/RemoteConsole/ly_remote_console
+    sudo chmod a+w Gems/Atom/RPI/Tools
+    sudo chmod a+w Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface
+    sudo chmod a+w scripts/o3de
+
+    popd
+} &> /dev/null # hide output

+ 1 - 0
cmake/Platform/Linux/Packaging/postrm.in

@@ -11,6 +11,7 @@ set -o errexit # exit on the first failure encountered
 
 {
     rm -f /usr/local/bin/o3de
+    rm -f /usr/local/bin/o3de.sh
     rm -f /usr/local/bin/o3de.assetprocessor
     rm -f /usr/local/bin/o3de.editor
     rm -f /usr/share/applications/o3de.desktop

+ 1 - 1
python/python.cmd

@@ -91,7 +91,7 @@ REM Execute the python call from the arguments within the python venv environmen
 
 call %PYTHON_VENV_ACTIVATE%
 
-call "%PYTHON_VENV_PYTHON%" %PYTHON_ARGS%
+call "%PYTHON_VENV_PYTHON%" -B %PYTHON_ARGS%
 SET PYTHON_RESULT=%ERRORLEVEL%
 
 call %PYTHON_VENV_DEACTIVATE%

+ 2 - 2
python/python.sh

@@ -115,11 +115,11 @@ then
 fi
 
 # Activate the venv environment
-source $PYTHON_VENV_ACTIVATE
+source "$PYTHON_VENV_ACTIVATE"
 
 # Make sure that python shared library that is loaded by the python linked in the venv folder
 # is the one that is loaded by injecting the shared lib path before invoking python. Otherwise,
 # the shared library may not be found or it could load it from a different location.
 PYTHON_LIB_PATH=$PYTHON_VENV/lib
-PYTHONNOUSERSITE=1 LD_LIBRARY_PATH="$PYTHON_LIB_PATH:$LD_LIBRARY_PATH" PYTHONPATH= "$PYTHON_VENV_PYTHON" "$@"
+PYTHONNOUSERSITE=1 LD_LIBRARY_PATH="$PYTHON_LIB_PATH:$LD_LIBRARY_PATH" PYTHONPATH= "$PYTHON_VENV_PYTHON" -B "$@"
 exit $?

+ 7 - 2
scripts/o3de/o3de/manifest.py

@@ -453,6 +453,7 @@ def get_enabled_gems(cmake_file: pathlib.Path) -> set:
     return gem_target_set
 
 
+FALLBACK_ENGINE_PROJECT_PATHS_WARNINGS = set()
 
 def get_project_enabled_gems(project_path: pathlib.Path, include_dependencies:bool = True) -> dict or None:
     """
@@ -487,8 +488,12 @@ def get_project_enabled_gems(project_path: pathlib.Path, include_dependencies:bo
                             f'"{project_path}" which is required to resolve gem dependencies.')
             return result
 
-        logger.warning('Failed to determine the correct engine for the project at '
-                        f'"{project_path}", falling back to this engine at {engine_path}.')
+        # Warn about falling back to a default engine once per project
+        global FALLBACK_ENGINE_PROJECT_PATHS_WARNINGS
+        if project_path not in FALLBACK_ENGINE_PROJECT_PATHS_WARNINGS:
+            FALLBACK_ENGINE_PROJECT_PATHS_WARNINGS.add(project_path)
+            logger.warning('Failed to determine the correct engine for the project at '
+                           f'"{project_path}", falling back to this engine at {engine_path}.')
     
     engine_json_data = get_engine_json_data(engine_path=engine_path)
     if not engine_json_data: