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