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.14." SO_EXT, "libpython3.7m." SO_EXT,
416 : "libpython3.6m." SO_EXT, "libpython3.5m." SO_EXT};
417 0 : for (size_t i = 0;
418 0 : libHandle == nullptr && i < CPL_ARRAYSIZE(apszPythonSO); ++i)
419 : {
420 0 : libHandle = tryDlopen(apszPythonSO[i]);
421 0 : if (libHandle != nullptr)
422 0 : CPLDebug("GDAL", "... success");
423 : }
424 : }
425 :
426 : #elif defined(_WIN32)
427 : CPLString osPythonBinaryUsed;
428 :
429 : // First try in the current process in case the python symbols would
430 : // be already loaded
431 : HANDLE hProcess = GetCurrentProcess();
432 : std::vector<HMODULE> ahModules;
433 :
434 : // 100 is not large enough when GDAL is loaded from QGIS for example
435 : ahModules.resize(1000);
436 : for (int i = 0; i < 2; i++)
437 : {
438 : DWORD nSizeNeeded = 0;
439 : const DWORD nSizeIn =
440 : static_cast<DWORD>(ahModules.size() * sizeof(HMODULE));
441 : EnumProcessModules(hProcess, &ahModules[0], nSizeIn, &nSizeNeeded);
442 : ahModules.resize(static_cast<size_t>(nSizeNeeded) / sizeof(HMODULE));
443 : if (nSizeNeeded <= nSizeIn)
444 : {
445 : break;
446 : }
447 : }
448 :
449 : for (size_t i = 0; i < ahModules.size(); i++)
450 : {
451 : if (GetProcAddress(ahModules[i], "Py_SetProgramName"))
452 : {
453 : libHandle = ahModules[i];
454 : CPLDebug("GDAL", "Current process has python symbols loaded");
455 : break;
456 : }
457 : }
458 :
459 : // Then try the user provided shared object name
460 : if (libHandle == nullptr && pszPythonSO != nullptr)
461 : {
462 : UINT uOldErrorMode;
463 : /* Avoid error boxes to pop up (#5211, #5525) */
464 : uOldErrorMode =
465 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
466 :
467 : #if (defined(_WIN32) && _MSC_VER >= 1310) || __MSVCRT_VERSION__ >= 0x0601
468 : if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
469 : {
470 : wchar_t *pwszFilename =
471 : CPLRecodeToWChar(pszPythonSO, CPL_ENC_UTF8, CPL_ENC_UCS2);
472 : libHandle = LoadLibraryW(pwszFilename);
473 : CPLFree(pwszFilename);
474 : }
475 : else
476 : #endif
477 : {
478 : libHandle = LoadLibrary(pszPythonSO);
479 : }
480 :
481 : SetErrorMode(uOldErrorMode);
482 :
483 : if (libHandle == nullptr)
484 : {
485 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load %s",
486 : pszPythonSO);
487 : return false;
488 : }
489 : if (GetProcAddress(libHandle, "Py_SetProgramName") == nullptr)
490 : {
491 : CPLError(CE_Failure, CPLE_AppDefined,
492 : "Cannot find Py_SetProgramName symbol in %s", pszPythonSO);
493 : return false;
494 : }
495 : }
496 :
497 : // Then try the PYTHONSO_DEFAULT if defined at compile time
498 : #ifdef PYTHONSO_DEFAULT
499 : if (libHandle == nullptr)
500 : {
501 : UINT uOldErrorMode;
502 : uOldErrorMode =
503 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
504 :
505 : libHandle = LoadLibrary(PYTHONSO_DEFAULT);
506 : SetErrorMode(uOldErrorMode);
507 : if (!libHandle)
508 : {
509 : CPLDebug("GDAL", "%s found", PYTHONSO_DEFAULT);
510 : }
511 : }
512 : #endif
513 :
514 : // Then try to find the pythonXY.dll that corresponds to the python binary
515 : // in the PATH
516 : if (libHandle == nullptr)
517 : {
518 : std::string osDLLName;
519 : char *pszPath = getenv("PATH");
520 : if (pszPath != nullptr
521 : #ifdef DEBUG
522 : // For testing purposes
523 : && CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_PYTHON_PATH", "YES"))
524 : #endif
525 : )
526 : {
527 : const CPLStringList aosPathParts(
528 : CSLTokenizeString2(pszPath, ";", 0));
529 : for (int iTry = 0; iTry < 2; ++iTry)
530 : {
531 : for (const char *pszPathPart : aosPathParts)
532 : {
533 : VSIStatBufL sStat;
534 : std::string osPythonBinary(CPLFormFilenameSafe(
535 : pszPathPart, "python.exe", nullptr));
536 : if (iTry == 1)
537 : osPythonBinary += "3";
538 : if (VSIStatL(osPythonBinary.c_str(), &sStat) != 0)
539 : continue;
540 :
541 : CPLDebug("GDAL", "Found %s", osPythonBinary.c_str());
542 :
543 : {
544 : // Test when dll is in the same directory as the exe
545 : const CPLStringList aosFiles(VSIReadDir(pszPathPart));
546 : for (const char *pszFilename : aosFiles)
547 : {
548 : if ((STARTS_WITH_CI(pszFilename, "python") ||
549 : // mingw64 uses libpython3.X.dll naming
550 : STARTS_WITH_CI(pszFilename, "libpython3.")) &&
551 : // do not load minimum API dll
552 : !EQUAL(pszFilename, "python3.dll") &&
553 : EQUAL(CPLGetExtensionSafe(pszFilename).c_str(),
554 : "dll"))
555 : {
556 : osDLLName = CPLFormFilenameSafe(
557 : pszPathPart, pszFilename, nullptr);
558 : osPythonBinaryUsed = osPythonBinary;
559 : break;
560 : }
561 : }
562 : }
563 :
564 : // In python3.2, the dll is in the DLLs subdirectory
565 : if (osDLLName.empty())
566 : {
567 : const std::string osDLLsDir(
568 : CPLFormFilenameSafe(pszPathPart, "DLLs", nullptr));
569 : const CPLStringList aosFiles(
570 : VSIReadDir(osDLLsDir.c_str()));
571 : for (const char *pszFilename : aosFiles)
572 : {
573 : if (STARTS_WITH_CI(pszFilename, "python") &&
574 : EQUAL(CPLGetExtensionSafe(pszFilename).c_str(),
575 : "dll"))
576 : {
577 : osDLLName = CPLFormFilenameSafe(
578 : osDLLsDir.c_str(), pszFilename, nullptr);
579 : break;
580 : }
581 : }
582 : }
583 :
584 : break;
585 : }
586 : if (!osDLLName.empty())
587 : break;
588 : }
589 : }
590 :
591 : if (!osDLLName.empty())
592 : {
593 : // CPLDebug("GDAL", "Trying %s", osDLLName.c_str());
594 : UINT uOldErrorMode;
595 : uOldErrorMode =
596 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
597 : libHandle = LoadLibrary(osDLLName.c_str());
598 : SetErrorMode(uOldErrorMode);
599 : if (libHandle != nullptr)
600 : {
601 : CPLDebug("GDAL", "%s loaded", osDLLName.c_str());
602 : }
603 : }
604 : }
605 :
606 : // Otherwise probe a few known objects
607 : // Note: update doc/source/drivers/raster/vrt.rst if change
608 : if (libHandle == nullptr)
609 : {
610 : const char *const apszPythonSO[] = {
611 : "python38.dll", "python39.dll", "python310.dll", "python311.dll",
612 : "python312.dll", "python313.dll", "python314.dll", "python37.dll",
613 : "python36.dll", "python35.dll"};
614 : UINT uOldErrorMode;
615 : uOldErrorMode =
616 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
617 :
618 : for (size_t i = 0;
619 : libHandle == nullptr && i < CPL_ARRAYSIZE(apszPythonSO); ++i)
620 : {
621 : CPLDebug("GDAL", "Trying %s", apszPythonSO[i]);
622 : libHandle = LoadLibrary(apszPythonSO[i]);
623 : if (libHandle != nullptr)
624 : CPLDebug("GDAL", "... success");
625 : }
626 : SetErrorMode(uOldErrorMode);
627 : }
628 : #endif
629 5 : if (!libHandle)
630 : {
631 0 : CPLError(
632 : CE_Failure, CPLE_AppDefined,
633 : "Cannot find python/libpython. You can set the PYTHONSO "
634 : "configuration option to point to the a python .so/.dll/.dylib");
635 0 : return false;
636 : }
637 :
638 5 : LOAD(libHandle, Py_GetVersion);
639 10 : CPLString osPythonVersion(Py_GetVersion());
640 5 : osPythonVersion.replaceAll("\r\n", ' ');
641 5 : osPythonVersion.replaceAll('\n', ' ');
642 5 : CPLDebug("GDAL", "Python version used: %s", osPythonVersion.c_str());
643 :
644 5 : LOAD(libHandle, Py_SetProgramName);
645 5 : LOAD(libHandle, Py_SetPythonHome);
646 :
647 : #ifdef _WIN32
648 : if (!osPythonBinaryUsed.empty() && getenv("PYTHONHOME") == nullptr)
649 : {
650 : std::string osPythonHome =
651 : CPLGetDirnameSafe(osPythonBinaryUsed.c_str());
652 : VSIStatBufL sStat;
653 : bool bOK = false;
654 : // Test Windows Conda layout
655 : std::string osDirEncodings =
656 : CPLFormFilenameSafe(osPythonHome.c_str(), "lib/encodings", nullptr);
657 : if (VSIStatL(osDirEncodings.c_str(), &sStat) == 0)
658 : {
659 : bOK = true;
660 : }
661 : else
662 : {
663 : // Test mingw64 layout
664 : const CPLStringList aosVersionTokens(
665 : CSLTokenizeString2(osPythonVersion.c_str(), ".", 0));
666 : if (aosVersionTokens.size() >= 3)
667 : {
668 : osPythonHome = CPLGetDirnameSafe(osPythonHome.c_str());
669 : osDirEncodings = CPLFormFilenameSafe(
670 : osPythonHome.c_str(),
671 : CPLSPrintf("lib/python%s.%s/encodings", aosVersionTokens[0],
672 : aosVersionTokens[1]),
673 : nullptr);
674 : if (VSIStatL(osDirEncodings.c_str(), &sStat) == 0)
675 : {
676 : bOK = true;
677 : }
678 : }
679 : }
680 : if (bOK)
681 : {
682 : static wchar_t wszPythonHome[4096];
683 : wchar_t *pwszPythonHome = CPLRecodeToWChar(
684 : osPythonHome.c_str(), CPL_ENC_UTF8, CPL_ENC_UCS2);
685 : const size_t nLength = wcslen(pwszPythonHome) + 1;
686 : if (nLength <= sizeof(wszPythonHome))
687 : {
688 : CPLDebug("GDAL", "Call Py_SetPythonHome(%s)",
689 : osPythonHome.c_str());
690 : memcpy(wszPythonHome, pwszPythonHome,
691 : nLength * sizeof(wchar_t));
692 : // The string must reside in static storage
693 : Py_SetPythonHome(wszPythonHome);
694 : }
695 : CPLFree(pwszPythonHome);
696 : }
697 : }
698 : #endif
699 :
700 5 : LOAD(libHandle, PyBuffer_FillInfo);
701 5 : LOAD(libHandle, PyMemoryView_FromBuffer);
702 5 : LOAD(libHandle, PyObject_Type);
703 5 : LOAD(libHandle, PyObject_IsInstance);
704 5 : LOAD(libHandle, PyTuple_New);
705 5 : LOAD(libHandle, PyBool_FromLong);
706 5 : LOAD(libHandle, PyLong_FromLong);
707 5 : LOAD(libHandle, PyLong_AsLong);
708 5 : LOAD(libHandle, PyLong_FromLongLong);
709 5 : LOAD(libHandle, PyLong_AsLongLong);
710 5 : LOAD(libHandle, PyBytes_Size);
711 5 : LOAD(libHandle, PyBytes_AsString);
712 5 : LOAD(libHandle, PyBytes_AsStringAndSize);
713 5 : LOAD(libHandle, PyBytes_FromObject);
714 5 : LOAD(libHandle, PyBytes_FromStringAndSize);
715 :
716 5 : LOAD(libHandle, PyModule_Create2);
717 :
718 5 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_FromString,
719 : "PyUnicode_FromString");
720 5 : if (PyUnicode_FromString == nullptr)
721 : {
722 0 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_FromString,
723 : "PyUnicodeUCS2_FromString");
724 : }
725 5 : if (PyUnicode_FromString == nullptr)
726 : {
727 0 : LOAD_WITH_NAME(libHandle, PyUnicode_FromString,
728 : "PyUnicodeUCS4_FromString");
729 : }
730 5 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
731 : "PyUnicode_AsUTF8String");
732 5 : if (PyUnicode_AsUTF8String == nullptr)
733 : {
734 0 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
735 : "PyUnicodeUCS2_AsUTF8String");
736 : }
737 5 : if (PyUnicode_AsUTF8String == nullptr)
738 : {
739 0 : LOAD_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
740 : "PyUnicodeUCS4_AsUTF8String");
741 : }
742 :
743 5 : LOAD(libHandle, PyFloat_FromDouble);
744 5 : LOAD(libHandle, PyFloat_AsDouble);
745 5 : LOAD(libHandle, PyObject_Call);
746 5 : LOAD(libHandle, PyObject_GetIter);
747 5 : LOAD(libHandle, PyIter_Next);
748 5 : LOAD(libHandle, Py_IncRef);
749 5 : LOAD(libHandle, Py_DecRef);
750 5 : LOAD(libHandle, PyErr_Occurred);
751 5 : LOAD(libHandle, PyErr_Print);
752 5 : LOAD(libHandle, Py_IsInitialized);
753 5 : LOAD(libHandle, Py_InitializeEx);
754 5 : LOAD(libHandle, PyEval_InitThreads);
755 5 : LOAD(libHandle, PyEval_SaveThread);
756 5 : LOAD(libHandle, PyEval_RestoreThread);
757 5 : LOAD(libHandle, Py_Finalize);
758 5 : LOAD_NOCHECK(libHandle, Py_CompileString);
759 5 : if (Py_CompileString == nullptr)
760 : {
761 : // Probably just a temporary measure for a bug of Python 3.8.0 on
762 : // Windows https://bugs.python.org/issue37633
763 0 : LOAD(libHandle, Py_CompileStringExFlags);
764 0 : Py_CompileString = GDAL_Py_CompileString;
765 : }
766 5 : LOAD(libHandle, PyImport_ExecCodeModule);
767 5 : LOAD(libHandle, PyObject_HasAttrString);
768 5 : LOAD(libHandle, PyObject_GetAttrString);
769 5 : LOAD(libHandle, PyObject_SetAttrString);
770 5 : LOAD(libHandle, PyTuple_SetItem);
771 5 : LOAD(libHandle, PyObject_Print);
772 5 : LOAD(libHandle, PyImport_ImportModule);
773 5 : LOAD(libHandle, PyCallable_Check);
774 5 : LOAD(libHandle, PyDict_New);
775 5 : LOAD(libHandle, PyDict_SetItemString);
776 5 : LOAD(libHandle, PyDict_Next);
777 5 : LOAD(libHandle, PyDict_GetItemString);
778 5 : LOAD(libHandle, PyList_New);
779 5 : LOAD(libHandle, PyList_SetItem);
780 5 : LOAD(libHandle, PySequence_Check);
781 5 : LOAD(libHandle, PySequence_Size);
782 5 : LOAD(libHandle, PySequence_GetItem);
783 5 : LOAD(libHandle, PyArg_ParseTuple);
784 5 : LOAD(libHandle, PyGILState_Ensure);
785 5 : LOAD(libHandle, PyGILState_Release);
786 5 : LOAD(libHandle, PyErr_Fetch);
787 5 : LOAD(libHandle, PyErr_Clear);
788 :
789 : #else // LOAD_NOCHECK_WITH_NAME
790 : CPLError(CE_Failure, CPLE_AppDefined,
791 : "This platform doesn't support dynamic loading of "
792 : "libraries");
793 : return false;
794 : #endif // LOAD_NOCHECK_WITH_NAME
795 :
796 5 : nInit = true;
797 5 : return true;
798 : }
799 :
800 : //! @cond Doxygen_Suppress
801 :
802 : /************************************************************************/
803 : /* GDALPythonInitialize() */
804 : /************************************************************************/
805 :
806 : /** Call this to initialize the Python environment.
807 : */
808 58 : bool GDALPythonInitialize()
809 : {
810 116 : std::lock_guard<std::mutex> guard(gMutexGDALPython);
811 :
812 58 : if (!LoadPythonAPI())
813 2 : return false;
814 :
815 56 : int bIsInitialized = Py_IsInitialized();
816 56 : if (!bIsInitialized)
817 : {
818 3 : gbHasInitializedPython = true;
819 3 : CPLDebug("GDAL", "Before Py_Initialize()");
820 3 : Py_InitializeEx(0);
821 3 : CPLDebug("GDAL", "Py_Initialize()");
822 3 : PyEval_InitThreads();
823 3 : gphThreadState = PyEval_SaveThread();
824 : }
825 :
826 56 : return true;
827 : }
828 :
829 : /************************************************************************/
830 : /* GDALPythonFinalize() */
831 : /************************************************************************/
832 :
833 : /** To be called by GDALDestroy() */
834 428 : void GDALPythonFinalize()
835 : {
836 428 : if (gbHasInitializedPython)
837 : {
838 3 : CPLDebug("GDAL", "Py_Finalize() = %p", Py_Finalize);
839 3 : PyEval_RestoreThread(gphThreadState);
840 3 : Py_Finalize();
841 3 : gbHasInitializedPython = false;
842 3 : gphThreadState = nullptr;
843 : }
844 428 : }
845 :
846 : namespace GDALPy
847 : {
848 :
849 : /************************************************************************/
850 : /* GIL_Holder() */
851 : /************************************************************************/
852 :
853 575 : GIL_Holder::GIL_Holder(bool bExclusiveLock) : m_bExclusiveLock(bExclusiveLock)
854 : {
855 575 : if (bExclusiveLock)
856 : {
857 0 : gMutexGDALPython.lock();
858 : }
859 575 : m_eState = PyGILState_Ensure();
860 575 : }
861 :
862 : /************************************************************************/
863 : /* ~GIL_Holder() */
864 : /************************************************************************/
865 :
866 1150 : GIL_Holder::~GIL_Holder()
867 : {
868 575 : PyGILState_Release(m_eState);
869 575 : if (m_bExclusiveLock)
870 : {
871 0 : gMutexGDALPython.unlock();
872 : }
873 : else
874 : {
875 : }
876 575 : }
877 :
878 : /************************************************************************/
879 : /* GetString() */
880 : /************************************************************************/
881 :
882 1588 : CPLString GetString(PyObject *obj, bool bEmitError)
883 : {
884 1588 : PyObject *unicode = PyUnicode_AsUTF8String(obj);
885 1588 : if (PyErr_Occurred())
886 : {
887 0 : if (bEmitError)
888 : {
889 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
890 0 : GetPyExceptionString().c_str());
891 : }
892 0 : return CPLString();
893 : }
894 :
895 1588 : const char *pszRet = PyBytes_AsString(unicode);
896 3176 : CPLString osRet = pszRet ? pszRet : "";
897 1588 : Py_DecRef(unicode);
898 1588 : return osRet;
899 : }
900 :
901 : /************************************************************************/
902 : /* GetPyExceptionString() */
903 : /************************************************************************/
904 :
905 8 : CPLString GetPyExceptionString()
906 : {
907 8 : PyObject *poPyType = nullptr;
908 8 : PyObject *poPyValue = nullptr;
909 8 : PyObject *poPyTraceback = nullptr;
910 :
911 8 : PyErr_Fetch(&poPyType, &poPyValue, &poPyTraceback);
912 8 : if (poPyType)
913 8 : Py_IncRef(poPyType);
914 8 : if (poPyValue)
915 8 : Py_IncRef(poPyValue);
916 8 : if (poPyTraceback)
917 4 : Py_IncRef(poPyTraceback);
918 :
919 : // This is a mess. traceback.format_exception/format_exception_only
920 : // sometimes throw exceptions themselves !
921 : CPLString osPythonCode(
922 : "import traceback\n"
923 : "\n"
924 : "def GDALFormatException2(etype, value):\n"
925 : " try:\n"
926 : " return ''.join(traceback.format_exception_only(etype, value))\n"
927 : " except:\n"
928 : " return (str(etype) + ', ' + str(value))\n"
929 : "\n"
930 : "def GDALFormatException3(etype, value, tb):\n"
931 : //" print(etype, value, tb)\n"
932 : " try:\n"
933 : " return ''.join(traceback.format_exception(etype, value, tb))\n"
934 : " except:\n"
935 16 : " return (str(etype) + ', ' + str(value))\n");
936 :
937 8 : CPLString osRet("An exception occurred in exception formatting code...");
938 :
939 : static int nCounter = 0;
940 16 : CPLString osModuleName(CPLSPrintf("gdal_exception_%d", nCounter));
941 : PyObject *poCompiledString =
942 8 : Py_CompileString(osPythonCode, osModuleName, Py_file_input);
943 8 : if (poCompiledString == nullptr || PyErr_Occurred())
944 : {
945 0 : PyErr_Print();
946 : }
947 : else
948 : {
949 : PyObject *poModule =
950 8 : PyImport_ExecCodeModule(osModuleName, poCompiledString);
951 8 : CPLAssert(poModule);
952 :
953 8 : Py_DecRef(poCompiledString);
954 :
955 : PyObject *poPyGDALFormatException2 =
956 8 : PyObject_GetAttrString(poModule, "GDALFormatException2");
957 8 : CPLAssert(poPyGDALFormatException2);
958 :
959 : PyObject *poPyGDALFormatException3 =
960 8 : PyObject_GetAttrString(poModule, "GDALFormatException3");
961 8 : CPLAssert(poPyGDALFormatException3);
962 :
963 8 : Py_DecRef(poModule);
964 :
965 8 : PyObject *pyArgs = PyTuple_New(poPyTraceback ? 3 : 2);
966 8 : PyTuple_SetItem(pyArgs, 0, poPyType);
967 8 : PyTuple_SetItem(pyArgs, 1, poPyValue);
968 8 : if (poPyTraceback)
969 4 : PyTuple_SetItem(pyArgs, 2, poPyTraceback);
970 8 : PyObject *poPyRet = PyObject_Call(
971 8 : poPyTraceback ? poPyGDALFormatException3 : poPyGDALFormatException2,
972 : pyArgs, nullptr);
973 8 : Py_DecRef(pyArgs);
974 :
975 8 : if (PyErr_Occurred())
976 : {
977 0 : osRet = "An exception occurred in exception formatting code...";
978 0 : PyErr_Print();
979 : }
980 : else
981 : {
982 8 : osRet = GetString(poPyRet, false);
983 8 : Py_DecRef(poPyRet);
984 : }
985 :
986 8 : Py_DecRef(poPyGDALFormatException2);
987 8 : Py_DecRef(poPyGDALFormatException3);
988 : }
989 :
990 8 : if (poPyType)
991 8 : Py_DecRef(poPyType);
992 8 : if (poPyValue)
993 8 : Py_DecRef(poPyValue);
994 8 : if (poPyTraceback)
995 4 : Py_DecRef(poPyTraceback);
996 :
997 16 : return osRet;
998 : }
999 :
1000 : /************************************************************************/
1001 : /* ErrOccurredEmitCPLError() */
1002 : /************************************************************************/
1003 :
1004 2273 : bool ErrOccurredEmitCPLError()
1005 : {
1006 2273 : if (PyErr_Occurred())
1007 : {
1008 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
1009 6 : GetPyExceptionString().c_str());
1010 3 : return true;
1011 : }
1012 2270 : return false;
1013 : }
1014 :
1015 : } // namespace GDALPy
1016 :
1017 : //! @endcond
|