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