Actual source code: pythonsys.c
petsc-3.14.6 2021-03-30
1: #include <petsc/private/petscimpl.h>
3: /* ---------------------------------------------------------------- */
5: #if !defined(PETSC_PYTHON_EXE)
6: #define PETSC_PYTHON_EXE "python"
7: #endif
9: static PetscErrorCode PetscPythonFindExecutable(char pythonexe[],size_t len)
10: {
11: PetscBool flag;
15: /* get the path for the Python interpreter executable */
16: PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,len);
17: PetscOptionsGetString(NULL,NULL,"-python",pythonexe,len,&flag);
18: if (!flag || pythonexe[0]==0) {
19: PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,len);
20: }
21: return(0);
22: }
24: /*
25: Python does not appear to have a universal way to indicate the location of Python dynamic library so try several possibilities
26: */
27: static PetscErrorCode PetscPythonFindLibraryName(const char pythonexe[],const char attempt[],char pythonlib[],size_t pl,PetscBool *found)
28: {
29: char command[2*PETSC_MAX_PATH_LEN];
30: FILE *fp = NULL;
31: char *eol;
35: /* call Python to find out the name of the Python dynamic library */
36: PetscStrncpy(command,pythonexe,sizeof(command));
37: PetscStrlcat(command," ",sizeof(command));
38: PetscStrlcat(command,attempt,sizeof(command));
39: #if defined(PETSC_HAVE_POPEN)
40: PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fp);
41: if (!fgets(pythonlib,pl,fp)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: bad output from executable: %s",pythonexe);
42: PetscPClose(PETSC_COMM_SELF,fp);
43: #else
44: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: Aborted due to missing popen()");
45: #endif
46: /* remove newlines */
47: PetscStrchr(pythonlib,'\n',&eol);
48: if (eol) eol[0] = 0;
49: PetscTestFile(pythonlib,'r',found);
50: return(0);
51: }
54: static PetscErrorCode PetscPythonFindLibrary(const char pythonexe[],char pythonlib[],size_t pl)
55: {
56: const char cmdline1[] = "-c 'import os;from distutils import sysconfig; print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),sysconfig.get_config_var(\"LDLIBRARY\")))'";
57: const char cmdline2[] = "-c 'import os;from distutils import sysconfig; import sys;print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),\"libpython\"+sys.version[:3]+\".dylib\"))'";
58: const char cmdline3[] = "-c 'import os;from distutils import sysconfig; print(os.path.join(sysconfig.get_config_var(\"LIBPL\"),sysconfig.get_config_var(\"LDLIBRARY\")))'";
59: const char cmdline4[] = "-c 'from distutils import sysconfig; print(sysconfig.get_config_var(\"LIBPYTHON\"))'";
60: const char cmdline5[] = "-c 'import os;from distutils import sysconfig; import sys;print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),\"libpython\"+sys.version[:3]+\".so\"))'";
62: PetscBool found = PETSC_FALSE;
66: #if defined(PETSC_PYTHON_LIB)
67: PetscStrncpy(pythonlib,PETSC_PYTHON_LIB,pl);
68: return(0);
69: #endif
71: PetscPythonFindLibraryName(pythonexe,cmdline1,pythonlib,pl,&found);
72: if (!found) {
73: PetscPythonFindLibraryName(pythonexe,cmdline2,pythonlib,pl,&found);
74: }
75: if (!found) {
76: PetscPythonFindLibraryName(pythonexe,cmdline3,pythonlib,pl,&found);
77: }
78: if (!found) {
79: PetscPythonFindLibraryName(pythonexe,cmdline4,pythonlib,pl,&found);
80: }
81: if (!found) {
82: PetscPythonFindLibraryName(pythonexe,cmdline5,pythonlib,pl,&found);
83: }
84: PetscInfo2(NULL,"Python library %s found %d\n",pythonlib,found);
85: return(0);
86: }
88: /* ---------------------------------------------------------------- */
90: typedef struct _Py_object_t PyObject; /* fake definition */
92: static PyObject* Py_None = NULL;
94: static const char* (*Py_GetVersion)(void);
96: static int (*Py_IsInitialized)(void);
97: static void (*Py_InitializeEx)(int);
98: static void (*Py_Finalize)(void);
100: static void (*PySys_SetArgv)(int,void*);
101: static PyObject* (*PySys_GetObject)(const char*);
102: static PyObject* (*PyObject_CallMethod)(PyObject*,const char*, const char*, ...);
103: static PyObject* (*PyImport_ImportModule)(const char*);
105: static void (*Py_IncRef)(PyObject*);
106: static void (*Py_DecRef)(PyObject*);
108: static void (*PyErr_Clear)(void);
109: static PyObject* (*PyErr_Occurred)(void);
110: static void (*PyErr_Fetch)(PyObject**,PyObject**,PyObject**);
111: static void (*PyErr_NormalizeException)(PyObject**,PyObject**, PyObject**);
112: static void (*PyErr_Display)(PyObject*,PyObject*,PyObject*);
113: static void (*PyErr_Restore)(PyObject*,PyObject*,PyObject*);
116: #define PetscDLPyLibOpen(libname) \
117: PetscDLLibraryAppend(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,libname)
118: #define PetscDLPyLibSym(symbol, value) \
119: PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,symbol,(void**)value)
120: #define PetscDLPyLibClose(comm) \
121: do { } while (0)
123: static PetscErrorCode PetscPythonLoadLibrary(const char pythonlib[])
124: {
128: /* open the Python dynamic library */
129: PetscDLPyLibOpen(pythonlib);
130: PetscInfo1(NULL,"Python: loaded dynamic library %s\n", pythonlib);
131: /* look required symbols from the Python C-API */
132: PetscDLPyLibSym("_Py_NoneStruct" , &Py_None);
133: PetscDLPyLibSym("Py_GetVersion" , &Py_GetVersion);
134: PetscDLPyLibSym("Py_IsInitialized" , &Py_IsInitialized);
135: PetscDLPyLibSym("Py_InitializeEx" , &Py_InitializeEx);
136: PetscDLPyLibSym("Py_Finalize" , &Py_Finalize);
137: PetscDLPyLibSym("PySys_GetObject" , &PySys_GetObject);
138: PetscDLPyLibSym("PySys_SetArgv" , &PySys_SetArgv);
139: PetscDLPyLibSym("PyObject_CallMethod" , &PyObject_CallMethod);
140: PetscDLPyLibSym("PyImport_ImportModule" , &PyImport_ImportModule);
141: PetscDLPyLibSym("Py_IncRef" , &Py_IncRef);
142: PetscDLPyLibSym("Py_DecRef" , &Py_DecRef);
143: PetscDLPyLibSym("PyErr_Clear" , &PyErr_Clear);
144: PetscDLPyLibSym("PyErr_Occurred" , &PyErr_Occurred);
145: PetscDLPyLibSym("PyErr_Fetch" , &PyErr_Fetch);
146: PetscDLPyLibSym("PyErr_NormalizeException", &PyErr_NormalizeException);
147: PetscDLPyLibSym("PyErr_Display", &PyErr_Display);
148: PetscDLPyLibSym("PyErr_Restore", &PyErr_Restore);
149: /* XXX TODO: check that ALL symbols were there !!! */
150: if (!Py_None) SETERRQ1(PETSC_COMM_SELF,1,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
151: if (!Py_GetVersion) SETERRQ1(PETSC_COMM_SELF,1,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
152: if (!Py_IsInitialized) SETERRQ1(PETSC_COMM_SELF,1,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
153: if (!Py_InitializeEx) SETERRQ1(PETSC_COMM_SELF,1,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
154: if (!Py_Finalize) SETERRQ1(PETSC_COMM_SELF,1,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
155: PetscInfo1(NULL,"Python: all required symbols loaded from Python dynamic library %s\n",pythonlib);
156: return(0);
157: }
159: /* ---------------------------------------------------------------- */
161: static char PetscPythonExe[PETSC_MAX_PATH_LEN] = { 0 };
162: static char PetscPythonLib[PETSC_MAX_PATH_LEN] = { 0 };
163: static PetscBool PetscBeganPython = PETSC_FALSE;
165: /*@C
166: PetscPythonFinalize - Finalize Python.
168: Level: intermediate
170: @*/
171: PetscErrorCode PetscPythonFinalize(void)
172: {
174: if (PetscBeganPython) { if (Py_IsInitialized()) Py_Finalize(); }
175: PetscBeganPython = PETSC_FALSE;
176: return(0);
177: }
179: /*@C
180: PetscPythonInitialize - Initialize Python and import petsc4py.
182: Input Parameter:
183: + pyexe - path to the Python interpreter executable, or NULL.
184: - pylib - full path to the Python dynamic library, or NULL.
186: Level: intermediate
188: @*/
189: PetscErrorCode PetscPythonInitialize(const char pyexe[],const char pylib[])
190: {
191: PyObject *module = NULL;
195: if (PetscBeganPython) return(0);
196: /* Python executable */
197: if (pyexe && pyexe[0] != 0) {
198: PetscStrncpy(PetscPythonExe,pyexe,sizeof(PetscPythonExe));
199: } else {
200: PetscPythonFindExecutable(PetscPythonExe,sizeof(PetscPythonExe));
201: }
202: /* Python dynamic library */
203: if (pylib && pylib[0] != 0) {
204: PetscStrncpy(PetscPythonLib,pylib,sizeof(PetscPythonLib));
205: } else {
206: PetscPythonFindLibrary(PetscPythonExe,PetscPythonLib,sizeof(PetscPythonLib));
207: }
208: /* dynamically load Python library */
209: PetscPythonLoadLibrary(PetscPythonLib);
210: /* initialize Python */
211: PetscBeganPython = PETSC_FALSE;
212: if (!Py_IsInitialized()) {
213: static PetscBool registered = PETSC_FALSE;
214: const char *py_version;
215: PyObject *sys_path;
216: char path[PETSC_MAX_PATH_LEN] = { 0 };
218: /* initialize Python */
219: Py_InitializeEx(0); /* 0: do not install signal handlers */
220: /* build 'sys.argv' list */
221: py_version = Py_GetVersion();
222: if (py_version[0] == '2') {
223: int argc = 0; char *argv[1] = {NULL};
224: PySys_SetArgv(argc,argv);
225: }
226: if (py_version[0] == '3') {
227: int argc = 0; wchar_t *argv[1] = {NULL};
228: PySys_SetArgv(argc,argv);
229: }
230: /* add PETSC_LIB_DIR in front of 'sys.path' */
231: sys_path = PySys_GetObject("path");
232: if (sys_path) {
233: PetscStrreplace(PETSC_COMM_SELF,"${PETSC_LIB_DIR}",path,sizeof(path));
234: Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,(char*)path));
235: #if defined(PETSC_PETSC4PY_INSTALL_PATH)
236: {
237: char *rpath;
238: PetscStrallocpy(PETSC_PETSC4PY_INSTALL_PATH,&rpath);
239: Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,rpath));
240: PetscFree(rpath);
241: }
242: #endif
243: }
244: /* register finalizer */
245: if (!registered) {
246: PetscRegisterFinalize(PetscPythonFinalize);
247: registered = PETSC_TRUE;
248: }
249: PetscBeganPython = PETSC_TRUE;
250: }
251: /* import 'petsc4py.PETSc' module */
252: module = PyImport_ImportModule("petsc4py.PETSc");
253: if (module) {
254: PetscInfo(NULL,"Python: successfully imported module 'petsc4py.PETSc'\n");
256: Py_DecRef(module); module = NULL;
257: } else {
258: PetscPythonPrintError();
259: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: could not import module 'petsc4py.PETSc', perhaps your PYTHONPATH does not contain it\n");
260: }
261: return(0);
262: }
264: /*@C
265: PetscPythonPrintError - Print Python errors.
267: Level: developer
269: @*/
270: PetscErrorCode PetscPythonPrintError(void)
271: {
272: PyObject *exc=NULL, *val=NULL, *tb=NULL;
275: if (!PetscBeganPython) return(0);
276: if (!PyErr_Occurred()) return(0);
277: PyErr_Fetch(&exc,&val,&tb);
278: PyErr_NormalizeException(&exc,&val,&tb);
279: PyErr_Display(exc ? exc : Py_None, val ? val : Py_None, tb ? tb : Py_None);
280: PyErr_Restore(exc,val,tb);
281: return(0);
282: }
284: /* ---------------------------------------------------------------- */
286: PETSC_EXTERN PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]);
287: PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]) = NULL;
289: /*@C
290: PetscPythonMonitorSet - Set Python monitor
292: Level: developer
294: @*/
295: PetscErrorCode PetscPythonMonitorSet(PetscObject obj, const char url[])
296: {
302: if (!PetscPythonMonitorSet_C) {
303: PetscPythonInitialize(NULL,NULL);
304: if (!PetscPythonMonitorSet_C) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Couldn't initialize Python support for monitors");
305: }
306: PetscPythonMonitorSet_C(obj,url);
307: return(0);
308: }
310: /* ---------------------------------------------------------------- */