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 : #if defined(LOAD_NOCHECK_WITH_NAME) && defined(HAVE_DLFCN_H) && !defined(_WIN32)
167 : static LibraryHandle libHandleStatic = nullptr;
168 : #endif
169 :
170 : /** Load the subset of the Python C API that we need */
171 53 : static bool LoadPythonAPI()
172 : {
173 : static bool bInit = false;
174 53 : if (bInit)
175 46 : return true;
176 :
177 : #ifdef LOAD_NOCHECK_WITH_NAME
178 : // The static here is just to avoid Coverity warning about resource leak.
179 7 : LibraryHandle libHandle = nullptr;
180 :
181 7 : const char *pszPythonSO = CPLGetConfigOption("PYTHONSO", nullptr);
182 : #if defined(HAVE_DLFCN_H) && !defined(_WIN32)
183 :
184 : // First try in the current process in case the python symbols would
185 : // be already loaded
186 : (void)libHandle;
187 7 : libHandle = dlopen(nullptr, RTLD_LAZY);
188 7 : libHandleStatic = libHandle;
189 14 : if (libHandle != nullptr &&
190 7 : dlsym(libHandle, "Py_SetProgramName") != nullptr)
191 : {
192 2 : CPLDebug("GDAL", "Current process has python symbols loaded");
193 : }
194 : else
195 : {
196 5 : libHandle = nullptr;
197 : }
198 :
199 : // Then try the user provided shared object name
200 7 : if (libHandle == nullptr && pszPythonSO != nullptr)
201 : {
202 : // coverity[tainted_string]
203 2 : libHandle = dlopen(pszPythonSO, RTLD_NOW | RTLD_GLOBAL);
204 2 : if (libHandle == nullptr)
205 : {
206 1 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load %s",
207 : pszPythonSO);
208 1 : return false;
209 : }
210 1 : if (dlsym(libHandle, "Py_SetProgramName") == nullptr)
211 : {
212 1 : CPLError(CE_Failure, CPLE_AppDefined,
213 : "Cannot find Py_SetProgramName symbol in %s", pszPythonSO);
214 1 : return false;
215 : }
216 : }
217 :
218 : // Then try the PYTHONSO_DEFAULT if defined at compile time
219 : #ifdef PYTHONSO_DEFAULT
220 : if (libHandle == nullptr)
221 : {
222 : libHandle = dlopen(PYTHONSO_DEFAULT, RTLD_NOW | RTLD_GLOBAL);
223 : if (!libHandle)
224 : {
225 : CPLDebug("GDAL", "%s found", PYTHONSO_DEFAULT);
226 : }
227 : }
228 : #endif
229 :
230 : #if defined(__MACH__) && defined(__APPLE__)
231 : #define SO_EXT "dylib"
232 : #else
233 : #define IS_SO_EXT
234 : #define SO_EXT "so"
235 : #endif
236 :
237 3 : const auto tryDlopen = [](CPLString osPythonSO)
238 : {
239 3 : CPLDebug("GDAL", "Trying %s", osPythonSO.c_str());
240 3 : auto l_libHandle = dlopen(osPythonSO.c_str(), RTLD_NOW | RTLD_GLOBAL);
241 : #ifdef IS_SO_EXT
242 3 : if (l_libHandle == nullptr)
243 : {
244 0 : osPythonSO += ".1.0";
245 0 : CPLDebug("GDAL", "Trying %s", osPythonSO.c_str());
246 0 : l_libHandle = dlopen(osPythonSO.c_str(), RTLD_NOW | RTLD_GLOBAL);
247 : }
248 : #endif
249 3 : return l_libHandle;
250 : };
251 :
252 : // Then try to find the libpython that corresponds to the python binary
253 : // in the PATH
254 5 : if (libHandle == nullptr)
255 : {
256 6 : CPLString osVersion;
257 3 : char *pszPath = getenv("PATH");
258 3 : if (pszPath != nullptr
259 : #ifdef DEBUG
260 : // For testing purposes
261 3 : && CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_PYTHON_PATH", "YES"))
262 : #endif
263 : )
264 : {
265 : const CPLStringList aosPathParts(
266 6 : CSLTokenizeString2(pszPath, ":", 0));
267 3 : for (int iTry = 0; iTry < 2; ++iTry)
268 : {
269 21 : for (const char *pszPathPart : aosPathParts)
270 : {
271 : struct stat sStat;
272 : CPLString osPythonBinary(
273 21 : CPLFormFilename(pszPathPart, "python", nullptr));
274 21 : if (iTry == 0)
275 21 : osPythonBinary += "3";
276 21 : if (lstat(osPythonBinary, &sStat) != 0)
277 18 : continue;
278 :
279 3 : CPLDebug("GDAL", "Found %s", osPythonBinary.c_str());
280 :
281 6 : if (S_ISLNK(sStat.st_mode)
282 : #ifdef DEBUG
283 : // For testing purposes
284 3 : && CPLTestBool(CPLGetConfigOption(
285 : "GDAL_ENABLE_PYTHON_SYMLINK", "YES"))
286 : #endif
287 : )
288 : {
289 6 : std::set<std::string> oSetAlreadyTriedLinks;
290 : while (true)
291 : {
292 3 : oSetAlreadyTriedLinks.insert(osPythonBinary);
293 :
294 : // If this is a symlink, hopefully the resolved
295 : // name will be like "python3.6"
296 3 : const int nBufSize = 2048;
297 3 : std::vector<char> oFilename(nBufSize);
298 3 : char *szPointerFilename = &oFilename[0];
299 3 : int nBytes = static_cast<int>(readlink(
300 3 : osPythonBinary, szPointerFilename, nBufSize));
301 3 : if (nBytes != -1)
302 : {
303 3 : szPointerFilename[std::min(nBytes,
304 3 : nBufSize - 1)] = 0;
305 : CPLString osFilename(
306 3 : CPLGetFilename(szPointerFilename));
307 3 : CPLDebug("GDAL", "Which is an alias to: %s",
308 : szPointerFilename);
309 :
310 3 : if (STARTS_WITH(osFilename, "python"))
311 : {
312 3 : CPLString osResolvedFullLink;
313 : // If the filename is again a symlink,
314 : // resolve it
315 3 : if (CPLIsFilenameRelative(osFilename))
316 : {
317 : osResolvedFullLink = CPLFormFilename(
318 : CPLGetPath(osPythonBinary),
319 3 : osFilename, nullptr);
320 : }
321 : else
322 : {
323 0 : osResolvedFullLink = osFilename;
324 : }
325 0 : if (oSetAlreadyTriedLinks.find(
326 3 : osResolvedFullLink) ==
327 6 : oSetAlreadyTriedLinks.end() &&
328 3 : lstat(osResolvedFullLink, &sStat) ==
329 6 : 0 &&
330 3 : S_ISLNK(sStat.st_mode))
331 : {
332 : osPythonBinary =
333 0 : std::move(osResolvedFullLink);
334 0 : continue;
335 : }
336 :
337 : osVersion =
338 3 : osFilename.substr(strlen("python"));
339 3 : CPLDebug(
340 : "GDAL",
341 : "Python version from binary name: %s",
342 : osVersion.c_str());
343 : }
344 : }
345 : else
346 : {
347 0 : CPLDebug("GDAL", "realink(%s) failed",
348 : osPythonBinary.c_str());
349 : }
350 3 : break;
351 0 : }
352 : }
353 :
354 : // Otherwise, expensive way: start the binary and ask
355 : // it for its version...
356 3 : if (osVersion.empty())
357 : {
358 0 : const char *pszPrintVersion =
359 : "import sys; print(str(sys.version_info[0]) +"
360 : "'.' + str(sys.version_info[1]))";
361 0 : const char *const apszArgv[] = {osPythonBinary.c_str(),
362 : "-c", pszPrintVersion,
363 0 : nullptr};
364 : const CPLString osTmpFilename(
365 0 : VSIMemGenerateHiddenFilename("out.txt"));
366 0 : VSILFILE *fout = VSIFOpenL(osTmpFilename, "wb+");
367 0 : if (CPLSpawn(apszArgv, nullptr, fout, FALSE) == 0)
368 : {
369 : char *pszStr =
370 0 : reinterpret_cast<char *>(VSIGetMemFileBuffer(
371 : osTmpFilename, nullptr, FALSE));
372 0 : osVersion = pszStr;
373 0 : if (!osVersion.empty() && osVersion.back() == '\n')
374 : {
375 0 : osVersion.resize(osVersion.size() - 1);
376 : }
377 0 : CPLDebug("GDAL", "Python version from binary: %s",
378 : osVersion.c_str());
379 : }
380 0 : VSIFCloseL(fout);
381 0 : VSIUnlink(osTmpFilename);
382 : }
383 3 : break;
384 : }
385 3 : if (!osVersion.empty())
386 3 : break;
387 : }
388 : }
389 :
390 3 : if (!osVersion.empty())
391 : {
392 3 : libHandle = tryDlopen("libpython" + osVersion + "." SO_EXT);
393 3 : if (libHandle != nullptr)
394 : {
395 3 : CPLDebug("GDAL", "... success");
396 : }
397 0 : else if (osVersion[0] == '3')
398 : {
399 0 : libHandle = tryDlopen("libpython" + osVersion + "m." SO_EXT);
400 0 : if (libHandle != nullptr)
401 : {
402 0 : CPLDebug("GDAL", "... success");
403 : }
404 : }
405 : }
406 : }
407 :
408 : // Otherwise probe a few known objects.
409 : // Note: update doc/source/drivers/raster/vrt.rst if change
410 5 : if (libHandle == nullptr)
411 : {
412 0 : const char *const apszPythonSO[] = {
413 : "libpython3.8." SO_EXT, "libpython3.9." SO_EXT,
414 : "libpython3.10." SO_EXT, "libpython3.11." SO_EXT,
415 : "libpython3.12." SO_EXT, "libpython3.13." SO_EXT,
416 : "libpython3.7m." SO_EXT, "libpython3.6m." SO_EXT,
417 : "libpython3.5m." SO_EXT, "libpython3.4m." SO_EXT,
418 : "libpython3.3." SO_EXT, "libpython3.2." 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 : CPLString 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 : CPLString osPythonBinary(
537 : CPLFormFilename(pszPathPart, "python.exe", nullptr));
538 : if (iTry == 1)
539 : osPythonBinary += "3";
540 : if (VSIStatL(osPythonBinary, &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(CPLGetExtension(pszFilename), "dll"))
556 : {
557 : osDLLName = CPLFormFilename(
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 CPLString osDLLsDir(
569 : CPLFormFilename(pszPathPart, "DLLs", nullptr));
570 : const CPLStringList aosFiles(VSIReadDir(osDLLsDir));
571 : for (const char *pszFilename : aosFiles)
572 : {
573 : if (STARTS_WITH_CI(pszFilename, "python") &&
574 : EQUAL(CPLGetExtension(pszFilename), "dll"))
575 : {
576 : osDLLName = CPLFormFilename(
577 : osDLLsDir, pszFilename, nullptr);
578 : break;
579 : }
580 : }
581 : }
582 :
583 : break;
584 : }
585 : if (!osDLLName.empty())
586 : break;
587 : }
588 : }
589 :
590 : if (!osDLLName.empty())
591 : {
592 : // CPLDebug("GDAL", "Trying %s", osDLLName.c_str());
593 : UINT uOldErrorMode;
594 : uOldErrorMode =
595 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
596 : libHandle = LoadLibrary(osDLLName);
597 : SetErrorMode(uOldErrorMode);
598 : if (libHandle != nullptr)
599 : {
600 : CPLDebug("GDAL", "%s loaded", osDLLName.c_str());
601 : }
602 : }
603 : }
604 :
605 : // Otherwise probe a few known objects
606 : // Note: update doc/source/drivers/raster/vrt.rst if change
607 : if (libHandle == nullptr)
608 : {
609 : const char *const apszPythonSO[] = {
610 : "python38.dll", "python39.dll", "python310.dll", "python311.dll",
611 : "python312.dll", "python313.dll", "python37.dll", "python36.dll",
612 : "python35.dll", "python34.dll", "python33.dll", "python32.dll"};
613 : UINT uOldErrorMode;
614 : uOldErrorMode =
615 : SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
616 :
617 : for (size_t i = 0;
618 : libHandle == nullptr && i < CPL_ARRAYSIZE(apszPythonSO); ++i)
619 : {
620 : CPLDebug("GDAL", "Trying %s", apszPythonSO[i]);
621 : libHandle = LoadLibrary(apszPythonSO[i]);
622 : if (libHandle != nullptr)
623 : CPLDebug("GDAL", "... success");
624 : }
625 : SetErrorMode(uOldErrorMode);
626 : }
627 : #endif
628 5 : if (!libHandle)
629 : {
630 0 : CPLError(
631 : CE_Failure, CPLE_AppDefined,
632 : "Cannot find python/libpython. You can set the PYTHONSO "
633 : "configuration option to point to the a python .so/.dll/.dylib");
634 0 : return false;
635 : }
636 :
637 5 : LOAD(libHandle, Py_GetVersion);
638 10 : CPLString osPythonVersion(Py_GetVersion());
639 5 : osPythonVersion.replaceAll("\r\n", ' ');
640 5 : osPythonVersion.replaceAll('\n', ' ');
641 5 : CPLDebug("GDAL", "Python version used: %s", osPythonVersion.c_str());
642 :
643 5 : LOAD(libHandle, Py_SetProgramName);
644 5 : LOAD(libHandle, Py_SetPythonHome);
645 :
646 : #ifdef _WIN32
647 : if (!osPythonBinaryUsed.empty() && getenv("PYTHONHOME") == nullptr)
648 : {
649 : const char *pszPythonHome = CPLGetDirname(osPythonBinaryUsed.c_str());
650 : VSIStatBufL sStat;
651 : bool bOK = false;
652 : // Test Windows Conda layout
653 : const char *pszDirEncodings =
654 : CPLFormFilename(pszPythonHome, "lib/encodings", nullptr);
655 : if (VSIStatL(pszDirEncodings, &sStat) == 0)
656 : {
657 : bOK = true;
658 : }
659 : else
660 : {
661 : // Test mingw64 layout
662 : const CPLStringList aosVersionTokens(
663 : CSLTokenizeString2(osPythonVersion.c_str(), ".", 0));
664 : if (aosVersionTokens.size() >= 3)
665 : {
666 : pszPythonHome = CPLGetDirname(pszPythonHome);
667 : pszDirEncodings = CPLFormFilename(
668 : pszPythonHome,
669 : CPLSPrintf("lib/python%s.%s/encodings", aosVersionTokens[0],
670 : aosVersionTokens[1]),
671 : nullptr);
672 : if (VSIStatL(pszDirEncodings, &sStat) == 0)
673 : {
674 : bOK = true;
675 : }
676 : }
677 : }
678 : if (bOK)
679 : {
680 : static wchar_t wszPythonHome[4096];
681 : wchar_t *pwszPythonHome =
682 : CPLRecodeToWChar(pszPythonHome, CPL_ENC_UTF8, CPL_ENC_UCS2);
683 : const size_t nLength = wcslen(pwszPythonHome) + 1;
684 : if (nLength <= sizeof(wszPythonHome))
685 : {
686 : CPLDebug("GDAL", "Call Py_SetPythonHome(%s)", pszPythonHome);
687 : memcpy(wszPythonHome, pwszPythonHome,
688 : nLength * sizeof(wchar_t));
689 : // The string must reside in static storage
690 : Py_SetPythonHome(wszPythonHome);
691 : }
692 : CPLFree(pwszPythonHome);
693 : }
694 : }
695 : #endif
696 :
697 5 : LOAD(libHandle, PyBuffer_FillInfo);
698 5 : LOAD(libHandle, PyMemoryView_FromBuffer);
699 5 : LOAD(libHandle, PyObject_Type);
700 5 : LOAD(libHandle, PyObject_IsInstance);
701 5 : LOAD(libHandle, PyTuple_New);
702 5 : LOAD(libHandle, PyBool_FromLong);
703 5 : LOAD(libHandle, PyLong_FromLong);
704 5 : LOAD(libHandle, PyLong_AsLong);
705 5 : LOAD(libHandle, PyLong_FromLongLong);
706 5 : LOAD(libHandle, PyLong_AsLongLong);
707 5 : LOAD(libHandle, PyBytes_Size);
708 5 : LOAD(libHandle, PyBytes_AsString);
709 5 : LOAD(libHandle, PyBytes_AsStringAndSize);
710 5 : LOAD(libHandle, PyBytes_FromObject);
711 5 : LOAD(libHandle, PyBytes_FromStringAndSize);
712 :
713 5 : LOAD(libHandle, PyModule_Create2);
714 :
715 5 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_FromString,
716 : "PyUnicode_FromString");
717 5 : if (PyUnicode_FromString == nullptr)
718 : {
719 0 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_FromString,
720 : "PyUnicodeUCS2_FromString");
721 : }
722 5 : if (PyUnicode_FromString == nullptr)
723 : {
724 0 : LOAD_WITH_NAME(libHandle, PyUnicode_FromString,
725 : "PyUnicodeUCS4_FromString");
726 : }
727 5 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
728 : "PyUnicode_AsUTF8String");
729 5 : if (PyUnicode_AsUTF8String == nullptr)
730 : {
731 0 : LOAD_NOCHECK_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
732 : "PyUnicodeUCS2_AsUTF8String");
733 : }
734 5 : if (PyUnicode_AsUTF8String == nullptr)
735 : {
736 0 : LOAD_WITH_NAME(libHandle, PyUnicode_AsUTF8String,
737 : "PyUnicodeUCS4_AsUTF8String");
738 : }
739 :
740 5 : LOAD(libHandle, PyFloat_FromDouble);
741 5 : LOAD(libHandle, PyFloat_AsDouble);
742 5 : LOAD(libHandle, PyObject_Call);
743 5 : LOAD(libHandle, PyObject_GetIter);
744 5 : LOAD(libHandle, PyIter_Next);
745 5 : LOAD(libHandle, Py_IncRef);
746 5 : LOAD(libHandle, Py_DecRef);
747 5 : LOAD(libHandle, PyErr_Occurred);
748 5 : LOAD(libHandle, PyErr_Print);
749 5 : LOAD(libHandle, Py_IsInitialized);
750 5 : LOAD(libHandle, Py_InitializeEx);
751 5 : LOAD(libHandle, PyEval_InitThreads);
752 5 : LOAD(libHandle, PyEval_SaveThread);
753 5 : LOAD(libHandle, PyEval_RestoreThread);
754 5 : LOAD(libHandle, Py_Finalize);
755 5 : LOAD_NOCHECK(libHandle, Py_CompileString);
756 5 : if (Py_CompileString == nullptr)
757 : {
758 : // Probably just a temporary measure for a bug of Python 3.8.0 on
759 : // Windows https://bugs.python.org/issue37633
760 0 : LOAD(libHandle, Py_CompileStringExFlags);
761 0 : Py_CompileString = GDAL_Py_CompileString;
762 : }
763 5 : LOAD(libHandle, PyImport_ExecCodeModule);
764 5 : LOAD(libHandle, PyObject_HasAttrString);
765 5 : LOAD(libHandle, PyObject_GetAttrString);
766 5 : LOAD(libHandle, PyObject_SetAttrString);
767 5 : LOAD(libHandle, PyTuple_SetItem);
768 5 : LOAD(libHandle, PyObject_Print);
769 5 : LOAD(libHandle, PyImport_ImportModule);
770 5 : LOAD(libHandle, PyCallable_Check);
771 5 : LOAD(libHandle, PyDict_New);
772 5 : LOAD(libHandle, PyDict_SetItemString);
773 5 : LOAD(libHandle, PyDict_Next);
774 5 : LOAD(libHandle, PyDict_GetItemString);
775 5 : LOAD(libHandle, PyList_New);
776 5 : LOAD(libHandle, PyList_SetItem);
777 5 : LOAD(libHandle, PySequence_Check);
778 5 : LOAD(libHandle, PySequence_Size);
779 5 : LOAD(libHandle, PySequence_GetItem);
780 5 : LOAD(libHandle, PyArg_ParseTuple);
781 5 : LOAD(libHandle, PyGILState_Ensure);
782 5 : LOAD(libHandle, PyGILState_Release);
783 5 : LOAD(libHandle, PyErr_Fetch);
784 5 : LOAD(libHandle, PyErr_Clear);
785 :
786 : #else // LOAD_NOCHECK_WITH_NAME
787 : CPLError(CE_Failure, CPLE_AppDefined,
788 : "This platform doesn't support dynamic loading of "
789 : "libraries") return false;
790 : #endif // LOAD_NOCHECK_WITH_NAME
791 :
792 5 : bInit = true;
793 5 : return bInit;
794 : }
795 :
796 : //! @cond Doxygen_Suppress
797 :
798 : /************************************************************************/
799 : /* GDALPythonInitialize() */
800 : /************************************************************************/
801 :
802 : /** Call this to initialize the Python environment.
803 : */
804 53 : bool GDALPythonInitialize()
805 : {
806 106 : std::lock_guard<std::mutex> guard(gMutexGDALPython);
807 :
808 53 : if (!LoadPythonAPI())
809 2 : return false;
810 :
811 51 : int bIsInitialized = Py_IsInitialized();
812 51 : if (!bIsInitialized)
813 : {
814 3 : gbHasInitializedPython = true;
815 3 : CPLDebug("GDAL", "Before Py_Initialize()");
816 3 : Py_InitializeEx(0);
817 3 : CPLDebug("GDAL", "Py_Initialize()");
818 3 : PyEval_InitThreads();
819 3 : gphThreadState = PyEval_SaveThread();
820 : }
821 :
822 51 : return true;
823 : }
824 :
825 : /************************************************************************/
826 : /* GDALPythonFinalize() */
827 : /************************************************************************/
828 :
829 : /** To be called by GDALDestroy() */
830 437 : void GDALPythonFinalize()
831 : {
832 437 : if (gbHasInitializedPython)
833 : {
834 3 : CPLDebug("GDAL", "Py_Finalize() = %p", Py_Finalize);
835 3 : PyEval_RestoreThread(gphThreadState);
836 3 : Py_Finalize();
837 3 : gbHasInitializedPython = false;
838 3 : gphThreadState = nullptr;
839 : }
840 437 : }
841 :
842 : namespace GDALPy
843 : {
844 :
845 : /************************************************************************/
846 : /* GIL_Holder() */
847 : /************************************************************************/
848 :
849 571 : GIL_Holder::GIL_Holder(bool bExclusiveLock) : m_bExclusiveLock(bExclusiveLock)
850 : {
851 571 : if (bExclusiveLock)
852 : {
853 0 : gMutexGDALPython.lock();
854 : }
855 571 : m_eState = PyGILState_Ensure();
856 571 : }
857 :
858 : /************************************************************************/
859 : /* ~GIL_Holder() */
860 : /************************************************************************/
861 :
862 1142 : GIL_Holder::~GIL_Holder()
863 : {
864 571 : PyGILState_Release(m_eState);
865 571 : if (m_bExclusiveLock)
866 : {
867 0 : gMutexGDALPython.unlock();
868 : }
869 : else
870 : {
871 : }
872 571 : }
873 :
874 : /************************************************************************/
875 : /* GetString() */
876 : /************************************************************************/
877 :
878 1588 : CPLString GetString(PyObject *obj, bool bEmitError)
879 : {
880 1588 : PyObject *unicode = PyUnicode_AsUTF8String(obj);
881 1588 : if (PyErr_Occurred())
882 : {
883 0 : if (bEmitError)
884 : {
885 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
886 0 : GetPyExceptionString().c_str());
887 : }
888 0 : return CPLString();
889 : }
890 :
891 1588 : const char *pszRet = PyBytes_AsString(unicode);
892 3176 : CPLString osRet = pszRet ? pszRet : "";
893 1588 : Py_DecRef(unicode);
894 1588 : return osRet;
895 : }
896 :
897 : /************************************************************************/
898 : /* GetPyExceptionString() */
899 : /************************************************************************/
900 :
901 8 : CPLString GetPyExceptionString()
902 : {
903 8 : PyObject *poPyType = nullptr;
904 8 : PyObject *poPyValue = nullptr;
905 8 : PyObject *poPyTraceback = nullptr;
906 :
907 8 : PyErr_Fetch(&poPyType, &poPyValue, &poPyTraceback);
908 8 : if (poPyType)
909 8 : Py_IncRef(poPyType);
910 8 : if (poPyValue)
911 8 : Py_IncRef(poPyValue);
912 8 : if (poPyTraceback)
913 4 : Py_IncRef(poPyTraceback);
914 :
915 : // This is a mess. traceback.format_exception/format_exception_only
916 : // sometimes throw exceptions themselves !
917 : CPLString osPythonCode(
918 : "import traceback\n"
919 : "\n"
920 : "def GDALFormatException2(etype, value):\n"
921 : " try:\n"
922 : " return ''.join(traceback.format_exception_only(etype, value))\n"
923 : " except:\n"
924 : " return (str(etype) + ', ' + str(value))\n"
925 : "\n"
926 : "def GDALFormatException3(etype, value, tb):\n"
927 : //" print(etype, value, tb)\n"
928 : " try:\n"
929 : " return ''.join(traceback.format_exception(etype, value, tb))\n"
930 : " except:\n"
931 16 : " return (str(etype) + ', ' + str(value))\n");
932 :
933 8 : CPLString osRet("An exception occurred in exception formatting code...");
934 :
935 : static int nCounter = 0;
936 16 : CPLString osModuleName(CPLSPrintf("gdal_exception_%d", nCounter));
937 : PyObject *poCompiledString =
938 8 : Py_CompileString(osPythonCode, osModuleName, Py_file_input);
939 8 : if (poCompiledString == nullptr || PyErr_Occurred())
940 : {
941 0 : PyErr_Print();
942 : }
943 : else
944 : {
945 : PyObject *poModule =
946 8 : PyImport_ExecCodeModule(osModuleName, poCompiledString);
947 8 : CPLAssert(poModule);
948 :
949 8 : Py_DecRef(poCompiledString);
950 :
951 : PyObject *poPyGDALFormatException2 =
952 8 : PyObject_GetAttrString(poModule, "GDALFormatException2");
953 8 : CPLAssert(poPyGDALFormatException2);
954 :
955 : PyObject *poPyGDALFormatException3 =
956 8 : PyObject_GetAttrString(poModule, "GDALFormatException3");
957 8 : CPLAssert(poPyGDALFormatException3);
958 :
959 8 : Py_DecRef(poModule);
960 :
961 8 : PyObject *pyArgs = PyTuple_New(poPyTraceback ? 3 : 2);
962 8 : PyTuple_SetItem(pyArgs, 0, poPyType);
963 8 : PyTuple_SetItem(pyArgs, 1, poPyValue);
964 8 : if (poPyTraceback)
965 4 : PyTuple_SetItem(pyArgs, 2, poPyTraceback);
966 8 : PyObject *poPyRet = PyObject_Call(
967 8 : poPyTraceback ? poPyGDALFormatException3 : poPyGDALFormatException2,
968 : pyArgs, nullptr);
969 8 : Py_DecRef(pyArgs);
970 :
971 8 : if (PyErr_Occurred())
972 : {
973 0 : osRet = "An exception occurred in exception formatting code...";
974 0 : PyErr_Print();
975 : }
976 : else
977 : {
978 8 : osRet = GetString(poPyRet, false);
979 8 : Py_DecRef(poPyRet);
980 : }
981 :
982 8 : Py_DecRef(poPyGDALFormatException2);
983 8 : Py_DecRef(poPyGDALFormatException3);
984 : }
985 :
986 8 : if (poPyType)
987 8 : Py_DecRef(poPyType);
988 8 : if (poPyValue)
989 8 : Py_DecRef(poPyValue);
990 8 : if (poPyTraceback)
991 4 : Py_DecRef(poPyTraceback);
992 :
993 16 : return osRet;
994 : }
995 :
996 : /************************************************************************/
997 : /* ErrOccurredEmitCPLError() */
998 : /************************************************************************/
999 :
1000 2268 : bool ErrOccurredEmitCPLError()
1001 : {
1002 2268 : if (PyErr_Occurred())
1003 : {
1004 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
1005 6 : GetPyExceptionString().c_str());
1006 3 : return true;
1007 : }
1008 2265 : return false;
1009 : }
1010 :
1011 : } // namespace GDALPy
1012 :
1013 : //! @endcond
|