Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Python interface
5 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2017-2019, Even Rouault, <even dot rouault at spatialys dot
9 : *com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_conv.h"
15 : #include "cpl_error.h"
16 : #include "cpl_string.h"
17 : #include "cpl_spawn.h"
18 : #include "gdalpython.h"
19 :
20 : #include <algorithm>
21 : #include <mutex>
22 : #include <set>
23 : #include <vector>
24 :
25 : using namespace GDALPy;
26 :
27 : typedef struct PyThreadState_t PyThreadState;
28 :
29 : static PyThreadState *(*PyEval_SaveThread)(void) = nullptr;
30 : static void (*PyEval_RestoreThread)(PyThreadState *) = nullptr;
31 : static void (*Py_Finalize)(void) = nullptr;
32 : static void (*Py_InitializeEx)(int) = nullptr;
33 : static void (*PyEval_InitThreads)(void) = nullptr;
34 : static PyObject *(*Py_CompileStringExFlags)(const char *, const char *, int,
35 : void *, int) = nullptr;
36 :
37 : static std::mutex gMutexGDALPython;
38 : static bool gbHasInitializedPython = false;
39 : static PyThreadState *gphThreadState = nullptr;
40 :
41 : // Emulate Py_CompileString with Py_CompileStringExFlags
42 : // Probably just a temporary measure for a bug of Python 3.8.0 on Windows
43 : // https://bugs.python.org/issue37633
44 0 : static PyObject *GDAL_Py_CompileString(const char *str, const char *filename,
45 : int start)
46 : {
47 0 : return Py_CompileStringExFlags(str, filename, start, nullptr, -1);
48 : }
49 :
50 : namespace GDALPy
51 : {
52 : int (*Py_IsInitialized)(void) = nullptr;
53 : PyGILState_STATE (*PyGILState_Ensure)(void) = nullptr;
54 : void (*PyGILState_Release)(PyGILState_STATE) = nullptr;
55 : void (*Py_SetProgramName)(const wchar_t *) = nullptr;
56 : void (*Py_SetPythonHome)(const wchar_t *) = nullptr;
57 : PyObject *(*PyObject_Type)(PyObject *) = nullptr;
58 : int (*PyObject_IsInstance)(PyObject *, PyObject *) = nullptr;
59 : PyObject *(*PyTuple_New)(size_t) = nullptr;
60 : PyObject *(*PyBool_FromLong)(long) = nullptr;
61 : PyObject *(*PyLong_FromLong)(long) = nullptr;
62 : long (*PyLong_AsLong)(PyObject *) = nullptr;
63 : PyObject *(*PyLong_FromLongLong)(GIntBig) = nullptr;
64 : GIntBig (*PyLong_AsLongLong)(PyObject *) = nullptr;
65 : PyObject *(*PyFloat_FromDouble)(double) = nullptr;
66 : double (*PyFloat_AsDouble)(PyObject *) = nullptr;
67 : PyObject *(*PyObject_Call)(PyObject *, PyObject *, PyObject *) = nullptr;
68 : PyObject *(*PyObject_GetIter)(PyObject *) = nullptr;
69 : PyObject *(*PyIter_Next)(PyObject *) = nullptr;
70 : void (*Py_IncRef)(PyObject *) = nullptr;
71 : void (*Py_DecRef)(PyObject *) = nullptr;
72 : PyObject *(*PyErr_Occurred)(void) = nullptr;
73 : void (*PyErr_Print)(void) = nullptr;
74 :
75 : PyObject *(*Py_CompileString)(const char *, const char *, int) = nullptr;
76 : PyObject *(*PyImport_ExecCodeModule)(const char *, PyObject *) = nullptr;
77 : int (*PyObject_HasAttrString)(PyObject *, const char *) = nullptr;
78 : PyObject *(*PyObject_GetAttrString)(PyObject *, const char *) = nullptr;
79 : int (*PyObject_SetAttrString)(PyObject *, const char *, PyObject *) = nullptr;
80 : int (*PyTuple_SetItem)(PyObject *, size_t, PyObject *) = nullptr;
81 : void (*PyObject_Print)(PyObject *, FILE *, int) = nullptr;
82 : Py_ssize_t (*PyBytes_Size)(PyObject *) = nullptr;
83 : const char *(*PyBytes_AsString)(PyObject *) = nullptr;
84 : int *(*PyBytes_AsStringAndSize)(PyObject *, char **, size_t *) = nullptr;
85 : PyObject *(*PyBytes_FromObject)(PyObject *) = nullptr;
86 : PyObject *(*PyBytes_FromStringAndSize)(const void *, size_t) = nullptr;
87 : PyObject *(*PyUnicode_FromString)(const char *) = nullptr;
88 : PyObject *(*PyUnicode_AsUTF8String)(PyObject *) = nullptr;
89 : PyObject *(*PyImport_ImportModule)(const char *) = nullptr;
90 : int (*PyCallable_Check)(PyObject *) = nullptr;
91 : PyObject *(*PyDict_New)(void) = nullptr;
92 : int (*PyDict_SetItemString)(PyObject *p, const char *key,
93 : PyObject *val) = nullptr;
94 : int (*PyDict_Next)(PyObject *p, size_t *, PyObject **, PyObject **) = nullptr;
95 : PyObject *(*PyDict_GetItemString)(PyObject *p, const char *key) = nullptr;
96 : PyObject *(*PyList_New)(Py_ssize_t) = nullptr;
97 : int (*PyList_SetItem)(PyObject *, Py_ssize_t, PyObject *) = nullptr;
98 : int (*PyArg_ParseTuple)(PyObject *, const char *, ...) = nullptr;
99 :
100 : int (*PySequence_Check)(PyObject *o) = nullptr;
101 : Py_ssize_t (*PySequence_Size)(PyObject *o) = nullptr;
102 : PyObject *(*PySequence_GetItem)(PyObject *o, Py_ssize_t i) = nullptr;
103 :
104 : void (*PyErr_Fetch)(PyObject **poPyType, PyObject **poPyValue,
105 : PyObject **poPyTraceback) = nullptr;
106 : void (*PyErr_Clear)(void) = nullptr;
107 : const char *(*Py_GetVersion)(void) = nullptr;
108 :
109 : int (*PyBuffer_FillInfo)(Py_buffer *view, PyObject *obj, void *buf, size_t len,
110 : int readonly, int infoflags) = nullptr;
111 : PyObject *(*PyMemoryView_FromBuffer)(Py_buffer *view) = nullptr;
112 :
113 : PyObject *(*PyModule_Create2)(struct PyModuleDef *, int) = nullptr;
114 : } // namespace GDALPy
115 :
116 : /* MinGW32 might define HAVE_DLFCN_H, so skip the unix implementation */
117 : #if defined(HAVE_DLFCN_H) && !defined(_WIN32)
118 :
119 : #include <dlfcn.h>
120 :
121 : typedef void *LibraryHandle;
122 :
123 : #define LOAD_NOCHECK_WITH_NAME(libHandle, x, name) \
124 : do \
125 : { \
126 : void *ptr = dlsym(libHandle, name); \
127 : memcpy(&x, &ptr, sizeof(void *)); \
128 : } while (0)
129 :
130 : #elif defined(_WIN32)
131 :
132 : #include <windows.h>
133 : #include <psapi.h>
134 :
135 : typedef HMODULE LibraryHandle;
136 :
137 : #define LOAD_NOCHECK_WITH_NAME(libHandle, x, name) \
138 : do \
139 : { \
140 : FARPROC ptr = GetProcAddress(libHandle, name); \
141 : memcpy(&x, &ptr, sizeof(void *)); \
142 : } while (0)
143 :
144 : #endif
145 :
146 : #define STRINGIFY(x) #x
147 :
148 : #define LOAD_NOCHECK(libHandle, x) \
149 : LOAD_NOCHECK_WITH_NAME(libHandle, x, STRINGIFY(x))
150 : #define LOAD_WITH_NAME(libHandle, x, name) \
151 : do \
152 : { \
153 : LOAD_NOCHECK_WITH_NAME(libHandle, x, name); \
154 : if (!x) \
155 : { \
156 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s", name); \
157 : return false; \
158 : } \
159 : } while (0)
160 : #define LOAD(libHandle, x) LOAD_WITH_NAME(libHandle, x, STRINGIFY(x))
161 :
162 : /************************************************************************/
163 : /* LoadPythonAPI() */
164 : /************************************************************************/
165 :
166 : /** Load the subset of the Python C API that we need */
167 58 : static bool LoadPythonAPI()
168 : {
169 : static int nInit = -1;
170 58 : if (nInit >= 0)
171 51 : return nInit == TRUE;
172 7 : nInit = FALSE;
173 :
174 : #ifdef LOAD_NOCHECK_WITH_NAME
175 : static LibraryHandle libHandle = nullptr;
176 7 : const char *pszPythonSO = CPLGetConfigOption("PYTHONSO", nullptr);
177 : #if defined(HAVE_DLFCN_H) && !defined(_WIN32)
178 :
179 : // First try in the current process in case the python symbols would
180 : // be already loaded
181 7 : libHandle = dlopen(nullptr, RTLD_LAZY);
182 14 : if (libHandle != nullptr &&
183 7 : dlsym(libHandle, "Py_SetProgramName") != nullptr)
184 : {
185 2 : CPLDebug("GDAL", "Current process has python symbols loaded");
186 : }
187 : else
188 : {
189 5 : if (libHandle)
190 5 : dlclose(libHandle);
191 5 : libHandle = nullptr;
192 : }
193 :
194 : // Then try the user provided shared object name
195 7 : if (libHandle == nullptr && pszPythonSO != nullptr)
196 : {
197 : // coverity[tainted_string]
198 2 : libHandle = dlopen(pszPythonSO, RTLD_NOW | RTLD_GLOBAL);
199 2 : if (libHandle == nullptr)
200 : {
201 1 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load %s",
202 : pszPythonSO);
203 1 : return false;
204 : }
205 1 : if (dlsym(libHandle, "Py_SetProgramName") == nullptr)
206 : {
207 1 : CPLError(CE_Failure, CPLE_AppDefined,
208 : "Cannot find Py_SetProgramName symbol in %s", pszPythonSO);
209 1 : return false;
210 : }
211 : }
212 :
213 : // Then try the PYTHONSO_DEFAULT if defined at compile time
214 : #ifdef PYTHONSO_DEFAULT
215 : if (libHandle == nullptr)
216 : {
217 : libHandle = dlopen(PYTHONSO_DEFAULT, RTLD_NOW | RTLD_GLOBAL);
218 : if (!libHandle)
219 : {
220 : CPLDebug("GDAL", "%s found", PYTHONSO_DEFAULT);
221 : }
222 : }
223 : #endif
224 :
225 : #if defined(__MACH__) && defined(__APPLE__)
226 : #define SO_EXT "dylib"
227 : #else
228 : #define IS_SO_EXT
229 : #define SO_EXT "so"
230 : #endif
231 :
232 3 : const auto tryDlopen = [](CPLString osPythonSO)
233 : {
234 3 : CPLDebug("GDAL", "Trying %s", osPythonSO.c_str());
235 3 : auto l_libHandle = dlopen(osPythonSO.c_str(), RTLD_NOW | RTLD_GLOBAL);
236 : #ifdef IS_SO_EXT
237 3 : if (l_libHandle == nullptr)
238 : {
239 0 : osPythonSO += ".1.0";
240 0 : CPLDebug("GDAL", "Trying %s", osPythonSO.c_str());
241 0 : l_libHandle = dlopen(osPythonSO.c_str(), RTLD_NOW | RTLD_GLOBAL);
242 : }
243 : #endif
244 3 : return l_libHandle;
245 : };
246 :
247 : // Then try to find the libpython that corresponds to the python binary
248 : // in the PATH
249 5 : if (libHandle == nullptr)
250 : {
251 6 : CPLString osVersion;
252 3 : char *pszPath = getenv("PATH");
253 3 : if (pszPath != nullptr
254 : #ifdef DEBUG
255 : // For testing purposes
256 3 : && CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_PYTHON_PATH", "YES"))
257 : #endif
258 : )
259 : {
260 : const CPLStringList aosPathParts(
261 6 : CSLTokenizeString2(pszPath, ":", 0));
262 3 : for (int iTry = 0; iTry < 2; ++iTry)
263 : {
264 21 : for (const char *pszPathPart : aosPathParts)
265 : {
266 : struct stat sStat;
267 : std::string osPythonBinary(
268 21 : CPLFormFilenameSafe(pszPathPart, "python", nullptr));
269 21 : if (iTry == 0)
270 21 : osPythonBinary += "3";
271 21 : if (lstat(osPythonBinary.c_str(), &sStat) != 0)
272 18 : continue;
273 :
274 3 : CPLDebug("GDAL", "Found %s", osPythonBinary.c_str());
275 :
276 6 : if (S_ISLNK(sStat.st_mode)
277 : #ifdef DEBUG
278 : // For testing purposes
279 3 : && CPLTestBool(CPLGetConfigOption(
280 : "GDAL_ENABLE_PYTHON_SYMLINK", "YES"))
281 : #endif
282 : )
283 : {
284 6 : std::set<std::string> oSetAlreadyTriedLinks;
285 : while (true)
286 : {
287 3 : oSetAlreadyTriedLinks.insert(osPythonBinary);
288 :
289 : // If this is a symlink, hopefully the resolved
290 : // name will be like "python3.6"
291 3 : const int nBufSize = 2048;
292 3 : std::vector<char> oFilename(nBufSize);
293 3 : char *szPointerFilename = &oFilename[0];
294 : int nBytes = static_cast<int>(
295 3 : readlink(osPythonBinary.c_str(),
296 3 : szPointerFilename, nBufSize));
297 3 : if (nBytes != -1)
298 : {
299 3 : szPointerFilename[std::min(nBytes,
300 3 : nBufSize - 1)] = 0;
301 : CPLString osFilename(
302 3 : CPLGetFilename(szPointerFilename));
303 3 : CPLDebug("GDAL", "Which is an alias to: %s",
304 : szPointerFilename);
305 :
306 3 : if (STARTS_WITH(osFilename, "python"))
307 : {
308 3 : std::string osResolvedFullLink;
309 : // If the filename is again a symlink,
310 : // resolve it
311 3 : if (CPLIsFilenameRelative(osFilename))
312 : {
313 : osResolvedFullLink =
314 9 : CPLFormFilenameSafe(
315 6 : CPLGetPathSafe(
316 : osPythonBinary.c_str())
317 : .c_str(),
318 3 : osFilename, nullptr);
319 : }
320 : else
321 : {
322 0 : osResolvedFullLink = osFilename;
323 : }
324 0 : if (oSetAlreadyTriedLinks.find(
325 3 : osResolvedFullLink) ==
326 6 : oSetAlreadyTriedLinks.end() &&
327 3 : lstat(osResolvedFullLink.c_str(),
328 6 : &sStat) == 0 &&
329 3 : S_ISLNK(sStat.st_mode))
330 : {
331 : osPythonBinary =
332 0 : std::move(osResolvedFullLink);
333 0 : continue;
334 : }
335 :
336 : osVersion =
337 3 : osFilename.substr(strlen("python"));
338 3 : CPLDebug(
339 : "GDAL",
340 : "Python version from binary name: %s",
341 : osVersion.c_str());
342 : }
343 : }
344 : else
345 : {
346 0 : CPLDebug("GDAL", "realink(%s) failed",
347 : osPythonBinary.c_str());
348 : }
349 3 : break;
350 0 : }
351 : }
352 :
353 : // Otherwise, expensive way: start the binary and ask
354 : // it for its version...
355 3 : if (osVersion.empty())
356 : {
357 0 : const char *pszPrintVersion =
358 : "import sys; print(str(sys.version_info[0]) +"
359 : "'.' + str(sys.version_info[1]))";
360 0 : const char *const apszArgv[] = {osPythonBinary.c_str(),
361 : "-c", pszPrintVersion,
362 0 : nullptr};
363 : const CPLString osTmpFilename(
364 0 : VSIMemGenerateHiddenFilename("out.txt"));
365 0 : VSILFILE *fout = VSIFOpenL(osTmpFilename, "wb+");
366 0 : if (CPLSpawn(apszArgv, nullptr, fout, FALSE) == 0)
367 : {
368 : char *pszStr =
369 0 : reinterpret_cast<char *>(VSIGetMemFileBuffer(
370 : osTmpFilename, nullptr, FALSE));
371 0 : osVersion = pszStr;
372 0 : if (!osVersion.empty() && osVersion.back() == '\n')
373 : {
374 0 : osVersion.resize(osVersion.size() - 1);
375 : }
376 0 : CPLDebug("GDAL", "Python version from binary: %s",
377 : osVersion.c_str());
378 : }
379 0 : VSIFCloseL(fout);
380 0 : VSIUnlink(osTmpFilename);
381 : }
382 3 : break;
383 : }
384 3 : if (!osVersion.empty())
385 3 : break;
386 : }
387 : }
388 :
389 3 : if (!osVersion.empty())
390 : {
391 3 : libHandle = tryDlopen("libpython" + osVersion + "." SO_EXT);
392 3 : if (libHandle != nullptr)
393 : {
394 3 : CPLDebug("GDAL", "... success");
395 : }
396 0 : else if (osVersion[0] == '3')
397 : {
398 0 : libHandle = tryDlopen("libpython" + osVersion + "m." SO_EXT);
399 0 : if (libHandle != nullptr)
400 : {
401 0 : CPLDebug("GDAL", "... success");
402 : }
403 : }
404 : }
405 : }
406 :
407 : // Otherwise probe a few known objects.
408 : // Note: update doc/source/drivers/raster/vrt.rst if change
409 5 : if (libHandle == nullptr)
410 : {
411 0 : const char *const apszPythonSO[] = {
412 : "libpython3.8." SO_EXT, "libpython3.9." SO_EXT,
413 : "libpython3.10." SO_EXT, "libpython3.11." SO_EXT,
414 : "libpython3.12." SO_EXT, "libpython3.13." SO_EXT,
415 : "libpython3.7m." SO_EXT, "libpython3.6m." SO_EXT,
416 : "libpython3.5m." SO_EXT, "libpython3.4m." SO_EXT,
417 : "libpython3.3." SO_EXT, "libpython3.2." SO_EXT};
418 0 : for (size_t i = 0;
419 0 : libHandle == nullptr && i < CPL_ARRAYSIZE(apszPythonSO); ++i)
420 : {
421 0 : libHandle = tryDlopen(apszPythonSO[i]);
422 0 : if (libHandle != nullptr)
423 0 : CPLDebug("GDAL", "... success");
424 : }
425 : }
426 :
427 : #elif defined(_WIN32)
428 : CPLString osPythonBinaryUsed;
429 :
430 : // First try in the current process in case the python symbols would
431 : // be already loaded
432 : HANDLE hProcess = GetCurrentProcess();
433 : std::vector<HMODULE> ahModules;
434 :
435 : // 100 is not large enough when GDAL is loaded from QGIS for example
436 : ahModules.resize(1000);
437 : for (int i = 0; i < 2; i++)
438 : {
439 : DWORD nSizeNeeded = 0;
440 : const DWORD nSizeIn =
441 : static_cast<DWORD>(ahModules.size() * sizeof(HMODULE));
442 : EnumProcessModules(hProcess, &ahModules[0], nSizeIn, &nSizeNeeded);
443 : ahModules.resize(static_cast<size_t>(nSizeNeeded) / sizeof(HMODULE));
444 : if (nSizeNeeded <= nSizeIn)
445 : {
446 : break;
447 : }
448 : }
449 :
450 : for (size_t i = 0; i < ahModules.size(); i++)
451 : {
452 : if (GetProcAddress(ahModules[i], "Py_SetProgramName"))
453 : {
454 : libHandle = ahModules[i];
455 : CPLDebug("GDAL", "Current process has python symbols loaded");
456 : break;
457 : }
458 : }
459 :
460 : // Then try the user provided shared object name
461 : if (libHandle == nullptr && pszPythonSO != nullptr)
462 : {
463 : UINT uOldErrorMode;
464 : /* Avoid error boxes to pop up (#5211, #5525) */
465 : uOldErrorMode =
466 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
467 :
468 : #if (defined(_WIN32) && _MSC_VER >= 1310) || __MSVCRT_VERSION__ >= 0x0601
469 : if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
470 : {
471 : wchar_t *pwszFilename =
472 : CPLRecodeToWChar(pszPythonSO, CPL_ENC_UTF8, CPL_ENC_UCS2);
473 : libHandle = LoadLibraryW(pwszFilename);
474 : CPLFree(pwszFilename);
475 : }
476 : else
477 : #endif
478 : {
479 : libHandle = LoadLibrary(pszPythonSO);
480 : }
481 :
482 : SetErrorMode(uOldErrorMode);
483 :
484 : if (libHandle == nullptr)
485 : {
486 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load %s",
487 : pszPythonSO);
488 : return false;
489 : }
490 : if (GetProcAddress(libHandle, "Py_SetProgramName") == nullptr)
491 : {
492 : CPLError(CE_Failure, CPLE_AppDefined,
493 : "Cannot find Py_SetProgramName symbol in %s", pszPythonSO);
494 : return false;
495 : }
496 : }
497 :
498 : // Then try the PYTHONSO_DEFAULT if defined at compile time
499 : #ifdef PYTHONSO_DEFAULT
500 : if (libHandle == nullptr)
501 : {
502 : UINT uOldErrorMode;
503 : uOldErrorMode =
504 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
505 :
506 : libHandle = LoadLibrary(PYTHONSO_DEFAULT);
507 : SetErrorMode(uOldErrorMode);
508 : if (!libHandle)
509 : {
510 : CPLDebug("GDAL", "%s found", PYTHONSO_DEFAULT);
511 : }
512 : }
513 : #endif
514 :
515 : // Then try to find the pythonXY.dll that corresponds to the python binary
516 : // in the PATH
517 : if (libHandle == nullptr)
518 : {
519 : std::string osDLLName;
520 : char *pszPath = getenv("PATH");
521 : if (pszPath != nullptr
522 : #ifdef DEBUG
523 : // For testing purposes
524 : && CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_PYTHON_PATH", "YES"))
525 : #endif
526 : )
527 : {
528 : const CPLStringList aosPathParts(
529 : CSLTokenizeString2(pszPath, ";", 0));
530 : for (int iTry = 0; iTry < 2; ++iTry)
531 : {
532 : for (const char *pszPathPart : aosPathParts)
533 : {
534 : VSIStatBufL sStat;
535 : std::string osPythonBinary(CPLFormFilenameSafe(
536 : pszPathPart, "python.exe", nullptr));
537 : if (iTry == 1)
538 : osPythonBinary += "3";
539 : if (VSIStatL(osPythonBinary.c_str(), &sStat) != 0)
540 : continue;
541 :
542 : CPLDebug("GDAL", "Found %s", osPythonBinary.c_str());
543 :
544 : {
545 : // Test when dll is in the same directory as the exe
546 : const CPLStringList aosFiles(VSIReadDir(pszPathPart));
547 : for (const char *pszFilename : aosFiles)
548 : {
549 : if ((STARTS_WITH_CI(pszFilename, "python") ||
550 : // mingw64 uses libpython3.X.dll naming
551 : STARTS_WITH_CI(pszFilename, "libpython3.")) &&
552 : // do not load minimum API dll
553 : !EQUAL(pszFilename, "python3.dll") &&
554 : EQUAL(CPLGetExtensionSafe(pszFilename).c_str(),
555 : "dll"))
556 : {
557 : osDLLName = CPLFormFilenameSafe(
558 : pszPathPart, pszFilename, nullptr);
559 : osPythonBinaryUsed = osPythonBinary;
560 : break;
561 : }
562 : }
563 : }
564 :
565 : // In python3.2, the dll is in the DLLs subdirectory
566 : if (osDLLName.empty())
567 : {
568 : const std::string osDLLsDir(
569 : CPLFormFilenameSafe(pszPathPart, "DLLs", nullptr));
570 : const CPLStringList aosFiles(
571 : VSIReadDir(osDLLsDir.c_str()));
572 : for (const char *pszFilename : aosFiles)
573 : {
574 : if (STARTS_WITH_CI(pszFilename, "python") &&
575 : EQUAL(CPLGetExtensionSafe(pszFilename).c_str(),
576 : "dll"))
577 : {
578 : osDLLName = CPLFormFilenameSafe(
579 : osDLLsDir.c_str(), pszFilename, nullptr);
580 : break;
581 : }
582 : }
583 : }
584 :
585 : break;
586 : }
587 : if (!osDLLName.empty())
588 : break;
589 : }
590 : }
591 :
592 : if (!osDLLName.empty())
593 : {
594 : // CPLDebug("GDAL", "Trying %s", osDLLName.c_str());
595 : UINT uOldErrorMode;
596 : uOldErrorMode =
597 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
598 : libHandle = LoadLibrary(osDLLName.c_str());
599 : SetErrorMode(uOldErrorMode);
600 : if (libHandle != nullptr)
601 : {
602 : CPLDebug("GDAL", "%s loaded", osDLLName.c_str());
603 : }
604 : }
605 : }
606 :
607 : // Otherwise probe a few known objects
608 : // Note: update doc/source/drivers/raster/vrt.rst if change
609 : if (libHandle == nullptr)
610 : {
611 : const char *const apszPythonSO[] = {
612 : "python38.dll", "python39.dll", "python310.dll", "python311.dll",
613 : "python312.dll", "python313.dll", "python37.dll", "python36.dll",
614 : "python35.dll", "python34.dll", "python33.dll", "python32.dll"};
615 : UINT uOldErrorMode;
616 : uOldErrorMode =
617 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
618 :
619 : for (size_t i = 0;
620 : libHandle == nullptr && i < CPL_ARRAYSIZE(apszPythonSO); ++i)
621 : {
622 : CPLDebug("GDAL", "Trying %s", apszPythonSO[i]);
623 : libHandle = LoadLibrary(apszPythonSO[i]);
624 : if (libHandle != nullptr)
625 : CPLDebug("GDAL", "... success");
626 : }
627 : SetErrorMode(uOldErrorMode);
628 : }
629 : #endif
630 5 : if (!libHandle)
631 : {
632 0 : CPLError(
633 : CE_Failure, CPLE_AppDefined,
634 : "Cannot find python/libpython. You can set the PYTHONSO "
635 : "configuration option to point to the a python .so/.dll/.dylib");
636 0 : return false;
637 : }
638 :
639 5 : LOAD(libHandle, Py_GetVersion);
640 10 : CPLString osPythonVersion(Py_GetVersion());
641 5 : osPythonVersion.replaceAll("\r\n", ' ');
642 5 : osPythonVersion.replaceAll('\n', ' ');
643 5 : CPLDebug("GDAL", "Python version used: %s", osPythonVersion.c_str());
644 :
645 5 : LOAD(libHandle, Py_SetProgramName);
646 5 : LOAD(libHandle, Py_SetPythonHome);
647 :
648 : #ifdef _WIN32
649 : if (!osPythonBinaryUsed.empty() && getenv("PYTHONHOME") == nullptr)
650 : {
651 : std::string osPythonHome =
652 : CPLGetDirnameSafe(osPythonBinaryUsed.c_str());
653 : VSIStatBufL sStat;
654 : bool bOK = false;
655 : // Test Windows Conda layout
656 : std::string osDirEncodings =
657 : CPLFormFilenameSafe(osPythonHome.c_str(), "lib/encodings", nullptr);
658 : if (VSIStatL(osDirEncodings.c_str(), &sStat) == 0)
659 : {
660 : bOK = true;
661 : }
662 : else
663 : {
664 : // Test mingw64 layout
665 : const CPLStringList aosVersionTokens(
666 : CSLTokenizeString2(osPythonVersion.c_str(), ".", 0));
667 : if (aosVersionTokens.size() >= 3)
668 : {
669 : osPythonHome = CPLGetDirnameSafe(osPythonHome.c_str());
670 : osDirEncodings = CPLFormFilenameSafe(
671 : osPythonHome.c_str(),
672 : CPLSPrintf("lib/python%s.%s/encodings", aosVersionTokens[0],
673 : aosVersionTokens[1]),
674 : nullptr);
675 : if (VSIStatL(osDirEncodings.c_str(), &sStat) == 0)
676 : {
677 : bOK = true;
678 : }
679 : }
680 : }
681 : if (bOK)
682 : {
683 : static wchar_t wszPythonHome[4096];
684 : wchar_t *pwszPythonHome = CPLRecodeToWChar(
685 : osPythonHome.c_str(), CPL_ENC_UTF8, CPL_ENC_UCS2);
686 : const size_t nLength = wcslen(pwszPythonHome) + 1;
687 : if (nLength <= sizeof(wszPythonHome))
688 : {
689 : CPLDebug("GDAL", "Call Py_SetPythonHome(%s)",
690 : osPythonHome.c_str());
691 : memcpy(wszPythonHome, pwszPythonHome,
692 : nLength * sizeof(wchar_t));
693 : // The string must reside in static storage
694 : Py_SetPythonHome(wszPythonHome);
695 : }
696 : CPLFree(pwszPythonHome);
697 : }
698 : }
699 : #endif
700 :
701 5 : LOAD(libHandle, PyBuffer_FillInfo);
702 5 : LOAD(libHandle, PyMemoryView_FromBuffer);
703 5 : LOAD(libHandle, PyObject_Type);
704 5 : LOAD(libHandle, PyObject_IsInstance);
705 5 : LOAD(libHandle, PyTuple_New);
706 5 : LOAD(libHandle, PyBool_FromLong);
707 5 : LOAD(libHandle, PyLong_FromLong);
708 5 : LOAD(libHandle, PyLong_AsLong);
709 5 : LOAD(libHandle, PyLong_FromLongLong);
710 5 : LOAD(libHandle, PyLong_AsLongLong);
711 5 : LOAD(libHandle, PyBytes_Size);
712 5 : LOAD(libHandle, PyBytes_AsString);
713 5 : LOAD(libHandle, PyBytes_AsStringAndSize);
714 5 : LOAD(libHandle, PyBytes_FromObject);
715 5 : LOAD(libHandle, PyBytes_FromStringAndSize);
716 :
717 5 : LOAD(libHandle, PyModule_Create2);
718 :
719 5 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_FromString,
720 : "PyUnicode_FromString");
721 5 : if (PyUnicode_FromString == nullptr)
722 : {
723 0 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_FromString,
724 : "PyUnicodeUCS2_FromString");
725 : }
726 5 : if (PyUnicode_FromString == nullptr)
727 : {
728 0 : LOAD_WITH_NAME(libHandle, PyUnicode_FromString,
729 : "PyUnicodeUCS4_FromString");
730 : }
731 5 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
732 : "PyUnicode_AsUTF8String");
733 5 : if (PyUnicode_AsUTF8String == nullptr)
734 : {
735 0 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
736 : "PyUnicodeUCS2_AsUTF8String");
737 : }
738 5 : if (PyUnicode_AsUTF8String == nullptr)
739 : {
740 0 : LOAD_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
741 : "PyUnicodeUCS4_AsUTF8String");
742 : }
743 :
744 5 : LOAD(libHandle, PyFloat_FromDouble);
745 5 : LOAD(libHandle, PyFloat_AsDouble);
746 5 : LOAD(libHandle, PyObject_Call);
747 5 : LOAD(libHandle, PyObject_GetIter);
748 5 : LOAD(libHandle, PyIter_Next);
749 5 : LOAD(libHandle, Py_IncRef);
750 5 : LOAD(libHandle, Py_DecRef);
751 5 : LOAD(libHandle, PyErr_Occurred);
752 5 : LOAD(libHandle, PyErr_Print);
753 5 : LOAD(libHandle, Py_IsInitialized);
754 5 : LOAD(libHandle, Py_InitializeEx);
755 5 : LOAD(libHandle, PyEval_InitThreads);
756 5 : LOAD(libHandle, PyEval_SaveThread);
757 5 : LOAD(libHandle, PyEval_RestoreThread);
758 5 : LOAD(libHandle, Py_Finalize);
759 5 : LOAD_NOCHECK(libHandle, Py_CompileString);
760 5 : if (Py_CompileString == nullptr)
761 : {
762 : // Probably just a temporary measure for a bug of Python 3.8.0 on
763 : // Windows https://bugs.python.org/issue37633
764 0 : LOAD(libHandle, Py_CompileStringExFlags);
765 0 : Py_CompileString = GDAL_Py_CompileString;
766 : }
767 5 : LOAD(libHandle, PyImport_ExecCodeModule);
768 5 : LOAD(libHandle, PyObject_HasAttrString);
769 5 : LOAD(libHandle, PyObject_GetAttrString);
770 5 : LOAD(libHandle, PyObject_SetAttrString);
771 5 : LOAD(libHandle, PyTuple_SetItem);
772 5 : LOAD(libHandle, PyObject_Print);
773 5 : LOAD(libHandle, PyImport_ImportModule);
774 5 : LOAD(libHandle, PyCallable_Check);
775 5 : LOAD(libHandle, PyDict_New);
776 5 : LOAD(libHandle, PyDict_SetItemString);
777 5 : LOAD(libHandle, PyDict_Next);
778 5 : LOAD(libHandle, PyDict_GetItemString);
779 5 : LOAD(libHandle, PyList_New);
780 5 : LOAD(libHandle, PyList_SetItem);
781 5 : LOAD(libHandle, PySequence_Check);
782 5 : LOAD(libHandle, PySequence_Size);
783 5 : LOAD(libHandle, PySequence_GetItem);
784 5 : LOAD(libHandle, PyArg_ParseTuple);
785 5 : LOAD(libHandle, PyGILState_Ensure);
786 5 : LOAD(libHandle, PyGILState_Release);
787 5 : LOAD(libHandle, PyErr_Fetch);
788 5 : LOAD(libHandle, PyErr_Clear);
789 :
790 : #else // LOAD_NOCHECK_WITH_NAME
791 : CPLError(CE_Failure, CPLE_AppDefined,
792 : "This platform doesn't support dynamic loading of "
793 : "libraries");
794 : return false;
795 : #endif // LOAD_NOCHECK_WITH_NAME
796 :
797 5 : nInit = true;
798 5 : return true;
799 : }
800 :
801 : //! @cond Doxygen_Suppress
802 :
803 : /************************************************************************/
804 : /* GDALPythonInitialize() */
805 : /************************************************************************/
806 :
807 : /** Call this to initialize the Python environment.
808 : */
809 58 : bool GDALPythonInitialize()
810 : {
811 116 : std::lock_guard<std::mutex> guard(gMutexGDALPython);
812 :
813 58 : if (!LoadPythonAPI())
814 2 : return false;
815 :
816 56 : int bIsInitialized = Py_IsInitialized();
817 56 : if (!bIsInitialized)
818 : {
819 3 : gbHasInitializedPython = true;
820 3 : CPLDebug("GDAL", "Before Py_Initialize()");
821 3 : Py_InitializeEx(0);
822 3 : CPLDebug("GDAL", "Py_Initialize()");
823 3 : PyEval_InitThreads();
824 3 : gphThreadState = PyEval_SaveThread();
825 : }
826 :
827 56 : return true;
828 : }
829 :
830 : /************************************************************************/
831 : /* GDALPythonFinalize() */
832 : /************************************************************************/
833 :
834 : /** To be called by GDALDestroy() */
835 427 : void GDALPythonFinalize()
836 : {
837 427 : if (gbHasInitializedPython)
838 : {
839 3 : CPLDebug("GDAL", "Py_Finalize() = %p", Py_Finalize);
840 3 : PyEval_RestoreThread(gphThreadState);
841 3 : Py_Finalize();
842 3 : gbHasInitializedPython = false;
843 3 : gphThreadState = nullptr;
844 : }
845 427 : }
846 :
847 : namespace GDALPy
848 : {
849 :
850 : /************************************************************************/
851 : /* GIL_Holder() */
852 : /************************************************************************/
853 :
854 575 : GIL_Holder::GIL_Holder(bool bExclusiveLock) : m_bExclusiveLock(bExclusiveLock)
855 : {
856 575 : if (bExclusiveLock)
857 : {
858 0 : gMutexGDALPython.lock();
859 : }
860 575 : m_eState = PyGILState_Ensure();
861 575 : }
862 :
863 : /************************************************************************/
864 : /* ~GIL_Holder() */
865 : /************************************************************************/
866 :
867 1150 : GIL_Holder::~GIL_Holder()
868 : {
869 575 : PyGILState_Release(m_eState);
870 575 : if (m_bExclusiveLock)
871 : {
872 0 : gMutexGDALPython.unlock();
873 : }
874 : else
875 : {
876 : }
877 575 : }
878 :
879 : /************************************************************************/
880 : /* GetString() */
881 : /************************************************************************/
882 :
883 1588 : CPLString GetString(PyObject *obj, bool bEmitError)
884 : {
885 1588 : PyObject *unicode = PyUnicode_AsUTF8String(obj);
886 1588 : if (PyErr_Occurred())
887 : {
888 0 : if (bEmitError)
889 : {
890 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
891 0 : GetPyExceptionString().c_str());
892 : }
893 0 : return CPLString();
894 : }
895 :
896 1588 : const char *pszRet = PyBytes_AsString(unicode);
897 3176 : CPLString osRet = pszRet ? pszRet : "";
898 1588 : Py_DecRef(unicode);
899 1588 : return osRet;
900 : }
901 :
902 : /************************************************************************/
903 : /* GetPyExceptionString() */
904 : /************************************************************************/
905 :
906 8 : CPLString GetPyExceptionString()
907 : {
908 8 : PyObject *poPyType = nullptr;
909 8 : PyObject *poPyValue = nullptr;
910 8 : PyObject *poPyTraceback = nullptr;
911 :
912 8 : PyErr_Fetch(&poPyType, &poPyValue, &poPyTraceback);
913 8 : if (poPyType)
914 8 : Py_IncRef(poPyType);
915 8 : if (poPyValue)
916 8 : Py_IncRef(poPyValue);
917 8 : if (poPyTraceback)
918 4 : Py_IncRef(poPyTraceback);
919 :
920 : // This is a mess. traceback.format_exception/format_exception_only
921 : // sometimes throw exceptions themselves !
922 : CPLString osPythonCode(
923 : "import traceback\n"
924 : "\n"
925 : "def GDALFormatException2(etype, value):\n"
926 : " try:\n"
927 : " return ''.join(traceback.format_exception_only(etype, value))\n"
928 : " except:\n"
929 : " return (str(etype) + ', ' + str(value))\n"
930 : "\n"
931 : "def GDALFormatException3(etype, value, tb):\n"
932 : //" print(etype, value, tb)\n"
933 : " try:\n"
934 : " return ''.join(traceback.format_exception(etype, value, tb))\n"
935 : " except:\n"
936 16 : " return (str(etype) + ', ' + str(value))\n");
937 :
938 8 : CPLString osRet("An exception occurred in exception formatting code...");
939 :
940 : static int nCounter = 0;
941 16 : CPLString osModuleName(CPLSPrintf("gdal_exception_%d", nCounter));
942 : PyObject *poCompiledString =
943 8 : Py_CompileString(osPythonCode, osModuleName, Py_file_input);
944 8 : if (poCompiledString == nullptr || PyErr_Occurred())
945 : {
946 0 : PyErr_Print();
947 : }
948 : else
949 : {
950 : PyObject *poModule =
951 8 : PyImport_ExecCodeModule(osModuleName, poCompiledString);
952 8 : CPLAssert(poModule);
953 :
954 8 : Py_DecRef(poCompiledString);
955 :
956 : PyObject *poPyGDALFormatException2 =
957 8 : PyObject_GetAttrString(poModule, "GDALFormatException2");
958 8 : CPLAssert(poPyGDALFormatException2);
959 :
960 : PyObject *poPyGDALFormatException3 =
961 8 : PyObject_GetAttrString(poModule, "GDALFormatException3");
962 8 : CPLAssert(poPyGDALFormatException3);
963 :
964 8 : Py_DecRef(poModule);
965 :
966 8 : PyObject *pyArgs = PyTuple_New(poPyTraceback ? 3 : 2);
967 8 : PyTuple_SetItem(pyArgs, 0, poPyType);
968 8 : PyTuple_SetItem(pyArgs, 1, poPyValue);
969 8 : if (poPyTraceback)
970 4 : PyTuple_SetItem(pyArgs, 2, poPyTraceback);
971 8 : PyObject *poPyRet = PyObject_Call(
972 8 : poPyTraceback ? poPyGDALFormatException3 : poPyGDALFormatException2,
973 : pyArgs, nullptr);
974 8 : Py_DecRef(pyArgs);
975 :
976 8 : if (PyErr_Occurred())
977 : {
978 0 : osRet = "An exception occurred in exception formatting code...";
979 0 : PyErr_Print();
980 : }
981 : else
982 : {
983 8 : osRet = GetString(poPyRet, false);
984 8 : Py_DecRef(poPyRet);
985 : }
986 :
987 8 : Py_DecRef(poPyGDALFormatException2);
988 8 : Py_DecRef(poPyGDALFormatException3);
989 : }
990 :
991 8 : if (poPyType)
992 8 : Py_DecRef(poPyType);
993 8 : if (poPyValue)
994 8 : Py_DecRef(poPyValue);
995 8 : if (poPyTraceback)
996 4 : Py_DecRef(poPyTraceback);
997 :
998 16 : return osRet;
999 : }
1000 :
1001 : /************************************************************************/
1002 : /* ErrOccurredEmitCPLError() */
1003 : /************************************************************************/
1004 :
1005 2273 : bool ErrOccurredEmitCPLError()
1006 : {
1007 2273 : if (PyErr_Occurred())
1008 : {
1009 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
1010 6 : GetPyExceptionString().c_str());
1011 3 : return true;
1012 : }
1013 2270 : return false;
1014 : }
1015 :
1016 : } // namespace GDALPy
1017 :
1018 : //! @endcond
|