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