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