7
7
*/
8
8
9
9
#include < AzToolsFramework/API/PythonLoader.h>
10
- #include < AzToolsFramework_Traits_Platform.h>
11
10
#include < AzCore/Component/ComponentApplicationBus.h>
12
11
#include < AzCore/IO/FileIO.h>
13
12
#include < AzCore/IO/GenericStreams.h>
14
13
#include < AzCore/IO/Path/Path.h>
14
+ #include < AzCore/IO/SystemFile.h>
15
15
#include < AzCore/Math/Sha1.h>
16
16
#include < AzCore/std/containers/vector.h>
17
17
#include < AzCore/std/string/string.h>
18
18
#include < AzCore/std/string/string_view.h>
19
19
#include < AzCore/std/string/conversions.h>
20
20
#include < AzCore/std/string/tokenize.h>
21
+ #include < AzCore/Serialization/Json/JsonUtils.h>
21
22
#include < AzCore/Settings/ConfigParser.h>
22
23
#include < AzCore/Utils/Utils.h>
23
24
#include < AzFramework/IO/LocalFileIO.h>
@@ -26,82 +27,56 @@ namespace AzToolsFramework::EmbeddedPython
26
27
{
27
28
PythonLoader::PythonLoader ()
28
29
{
29
- #if AZ_TRAIT_PYTHON_LOADER_ENABLE_EXPLICIT_LOADING
30
- // PYTHON_SHARED_LIBRARY_PATH must be defined in the build scripts and referencing the path to the python shared library
31
- #if !defined(PYTHON_SHARED_LIBRARY_PATH)
32
- #error "PYTHON_SHARED_LIBRARY_PATH is not defined"
33
- #endif
34
-
35
- // Construct the path to the shared python library within the venv folder
36
- AZ::IO::FixedMaxPath engineRoot = AZ::IO::FixedMaxPath (AZ::Utils::GetEnginePath ());
37
- AZ::IO::FixedMaxPath thirdPartyRoot = PythonLoader::GetDefault3rdPartyPath (false );
38
- AZ::IO::FixedMaxPath pythonVenvPath = PythonLoader::GetPythonVenvPath (thirdPartyRoot, engineRoot);
39
-
40
- AZ::IO::PathView libPythonName = AZ::IO::PathView (PYTHON_SHARED_LIBRARY_PATH).Filename ();
41
- AZ::IO::FixedMaxPath pythonVenvLibPath = pythonVenvPath / " lib" / libPythonName;
42
-
43
- m_embeddedLibPythonModuleHandle = AZ::DynamicModuleHandle::Create (pythonVenvLibPath.StringAsPosix ().c_str (), false );
44
- bool loadResult = m_embeddedLibPythonModuleHandle->Load (false , true );
45
- AZ_Error (" PythonLoader" , loadResult, " Failed to load %s.\n " , libPythonName.StringAsPosix ().c_str ());
46
- #endif // AZ_TRAIT_PYTHON_LOADER_ENABLE_EXPLICIT_LOADING
47
- }
48
-
49
- PythonLoader::~PythonLoader ()
50
- {
51
- #if AZ_TRAIT_PYTHON_LOADER_ENABLE_EXPLICIT_LOADING
52
- AZ_Assert (m_embeddedLibPythonModuleHandle, " DynamicModuleHandle for python was not created" );
53
- m_embeddedLibPythonModuleHandle->Unload ();
54
- #endif // AZ_TRAIT_PYTHON_LOADER_ENABLE_EXPLICIT_LOADING
55
- }
30
+ #if defined(IMPLICIT_LOAD_PYTHON_SHARED_LIBRARY)
56
31
57
- AZ::IO::FixedMaxPath PythonLoader::GetDefault3rdPartyPath (bool createOnDemand)
58
- {
59
- AZ::IO::FixedMaxPath thirdPartyEnvPathPath;
60
-
61
- // The highest priority for the 3rd party path is the environment variable 'LY_3RDPARTY_PATH'
62
- static constexpr const char * env3rdPartyKey = " LY_3RDPARTY_PATH" ;
63
- char env3rdPartyPath[AZ::IO::MaxPathLength] = { ' \0 ' };
64
- auto envOutcome = AZ::Utils::GetEnv (AZStd::span (env3rdPartyPath), env3rdPartyKey);
65
- if (envOutcome && (strlen (env3rdPartyPath) > 0 ))
66
- {
67
- // If so, then use the path that is set as the third party path
68
- thirdPartyEnvPathPath = AZ::IO::FixedMaxPath (env3rdPartyPath).LexicallyNormal ();
69
- }
70
- // The next priority is to read the 3rd party directory from the manifest file
71
- else if (auto manifest3rdPartyResult = AZ::Utils::Get3rdPartyDirectory (); manifest3rdPartyResult.IsSuccess ())
32
+ // Determine if this is an sdk-engine build. For SDK engines, we want to prevent implicit python module loading.
33
+ [[maybe_unused]] bool isSdkEngine{ false };
34
+ auto engineSettingsPath = AZ::IO::FixedMaxPath{ AZ::Utils::GetEnginePath () } / " engine.json" ;
35
+ if (AZ::IO::SystemFile::Exists (engineSettingsPath.c_str ()))
72
36
{
73
- thirdPartyEnvPathPath = manifest3rdPartyResult.GetValue ();
37
+ auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile (engineSettingsPath.c_str ());
38
+ if (loadOutcome.IsSuccess ())
39
+ {
40
+ auto & doc = loadOutcome.GetValue ();
41
+ rapidjson::Value::MemberIterator sdkEngineFieldIter = doc.FindMember (" sdk_engine" );
42
+ if (sdkEngineFieldIter != doc.MemberEnd ())
43
+ {
44
+ isSdkEngine = sdkEngineFieldIter->value .GetBool ();
45
+ }
46
+ }
74
47
}
75
- // Fallback to the default 3rd Party path based on the location of the manifest folder
76
- else
48
+ if (!isSdkEngine)
77
49
{
78
- auto manifestPath = AZ::Utils::GetO3deManifestDirectory ();
79
- thirdPartyEnvPathPath = AZ::IO::FixedMaxPath (manifestPath) / " 3rdParty" ;
50
+ m_embeddedLibPythonModuleHandle = AZ::DynamicModuleHandle::Create (IMPLICIT_LOAD_PYTHON_SHARED_LIBRARY, false );
51
+ bool loadResult = m_embeddedLibPythonModuleHandle->Load (false , true );
52
+ AZ_Error (" PythonLoader" , loadResult, " Failed to load " IMPLICIT_LOAD_PYTHON_SHARED_LIBRARY " \n " );
80
53
}
54
+ #endif // IMPLICIT_LOAD_PYTHON_SHARED_LIBRARY
55
+ }
81
56
82
- if ((!AZ::IO::SystemFile::IsDirectory (thirdPartyEnvPathPath.c_str ())) && createOnDemand)
57
+ PythonLoader::~PythonLoader ()
58
+ {
59
+ #if defined(IMPLICIT_LOAD_PYTHON_SHARED_LIBRARY)
60
+ if (m_embeddedLibPythonModuleHandle)
83
61
{
84
- auto createPathResult = AZ::IO::SystemFile::CreateDir (thirdPartyEnvPathPath.c_str ());
85
- AZ_Assert (createPathResult, " Unable to create missing 3rd Party Folder '%s'" , thirdPartyEnvPathPath.c_str ())
62
+ m_embeddedLibPythonModuleHandle->Unload ();
86
63
}
87
- return thirdPartyEnvPathPath;
64
+ # endif // IMPLICIT_LOAD_PYTHON_SHARED_LIBRARY
88
65
}
89
66
90
- AZ::IO::FixedMaxPath PythonLoader::GetPythonHomePath (AZ::IO::PathView engineRoot)
67
+ AZ::IO::FixedMaxPath PythonLoader::GetPythonHomePath (AZ::IO::PathView engineRoot, const char * overridePythonBaseVenvPath /* = nullptr */ )
91
68
{
92
- AZ::IO::FixedMaxPath thirdPartyFolder = GetDefault3rdPartyPath (true );
93
-
94
69
// The python HOME path relative to the executable depends on the host platform the package is created for
95
70
#if AZ_TRAIT_PYTHON_LOADER_PYTHON_HOME_BIN_SUBPATH
96
- AZ::IO::FixedMaxPath pythonHomePath = PythonLoader::GetPythonExecutablePath (thirdPartyFolder, engineRoot ).ParentPath ();
71
+ AZ::IO::FixedMaxPath pythonHomePath = PythonLoader::GetPythonExecutablePath (engineRoot, overridePythonBaseVenvPath ).ParentPath ();
97
72
#else
98
- AZ::IO::FixedMaxPath pythonHomePath = PythonLoader::GetPythonExecutablePath (thirdPartyFolder, engineRoot );
73
+ AZ::IO::FixedMaxPath pythonHomePath = PythonLoader::GetPythonExecutablePath (engineRoot, overridePythonBaseVenvPath );
99
74
#endif // AZ_TRAIT_PYTHON_LOADER_PYTHON_HOME_BIN_SUBPATH
100
75
101
76
return pythonHomePath;
102
77
}
103
78
104
- AZ::IO::FixedMaxPath PythonLoader::GetPythonVenvPath (AZ::IO::PathView thirdPartyRoot, AZ::IO::PathView engineRoot )
79
+ AZ::IO::FixedMaxPath PythonLoader::GetPythonVenvPath (AZ::IO::PathView engineRoot, const char * overridePythonBaseVenvPath /* = nullptr */ )
105
80
{
106
81
// Perform the same hash calculation as cmake/CalculateEnginePathId.cmake
107
82
// ///
@@ -118,16 +93,18 @@ namespace AzToolsFramework::EmbeddedPython
118
93
hasher.GetDigest (digest);
119
94
120
95
// Construct the path to where the python venv based on the engine path should be located
121
- AZ::IO::FixedMaxPath libPath = thirdPartyRoot;
96
+ AZ::IO::FixedMaxPath libPath = (overridePythonBaseVenvPath != nullptr ) ? AZ::IO::FixedMaxPath (overridePythonBaseVenvPath) :
97
+ AZ::Utils::GetO3dePythonVenvRoot ();
98
+
122
99
// The ID is based on the first 32 bits of the digest, and formatted to at least 8-character wide hexadecimal representation
123
- libPath /= AZ::IO::FixedMaxPathString::format (" venv/ %08x" , digest[0 ]);
100
+ libPath /= AZ::IO::FixedMaxPathString::format (" %08x" , digest[0 ]);
124
101
libPath = libPath.LexicallyNormal ();
125
102
return libPath;
126
103
}
127
104
128
- AZ::IO::FixedMaxPath PythonLoader::GetPythonExecutablePath (AZ::IO::PathView thirdPartyRoot, AZ::IO::PathView engineRoot )
105
+ AZ::IO::FixedMaxPath PythonLoader::GetPythonExecutablePath (AZ::IO::PathView engineRoot, const char * overridePythonBaseVenvPath /* = nullptr */ )
129
106
{
130
- AZ::IO::FixedMaxPath pythonVenvConfig = PythonLoader::GetPythonVenvPath (thirdPartyRoot, engineRoot ) / " pyvenv.cfg" ;
107
+ AZ::IO::FixedMaxPath pythonVenvConfig = PythonLoader::GetPythonVenvPath (engineRoot, overridePythonBaseVenvPath ) / " pyvenv.cfg" ;
131
108
AZ::IO::SystemFileStream systemFileStream;
132
109
if (!systemFileStream.Open (pythonVenvConfig.c_str (), AZ::IO::OpenMode::ModeRead))
133
110
{
@@ -151,11 +128,11 @@ namespace AzToolsFramework::EmbeddedPython
151
128
return AZ::IO::FixedMaxPath (pythonHome);
152
129
}
153
130
154
- void PythonLoader::ReadPythonEggLinkPaths (AZ::IO::PathView thirdPartyRoot, AZ::IO::PathView engineRoot, EggLinkPathVisitor resultPathCallback)
131
+ void PythonLoader::ReadPythonEggLinkPaths (AZ::IO::PathView engineRoot, EggLinkPathVisitor resultPathCallback, const char * overridePythonBaseVenvPath /* = nullptr */ )
155
132
{
156
133
// Get the python venv path
157
134
AZ::IO::FixedMaxPath pythonVenvSitePackages =
158
- AZ::IO::FixedMaxPath (PythonLoader::GetPythonVenvPath (thirdPartyRoot, engineRoot )) / O3DE_PYTHON_SITE_PACKAGE_SUBPATH;
135
+ AZ::IO::FixedMaxPath (PythonLoader::GetPythonVenvPath (engineRoot, overridePythonBaseVenvPath )) / O3DE_PYTHON_SITE_PACKAGE_SUBPATH;
159
136
160
137
// Always add the site-packages folder from the virtual environment into the path list
161
138
resultPathCallback (pythonVenvSitePackages.LexicallyNormal ());
0 commit comments