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 CHKERRQ(PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,len)); 16 CHKERRQ(PetscOptionsGetString(NULL,NULL,"-python",pythonexe,len,&flag)); 17 if (!flag || pythonexe[0]==0) { 18 CHKERRQ(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 CHKERRQ(PetscStrncpy(command,pythonexe,sizeof(command))); 35 CHKERRQ(PetscStrlcat(command," ",sizeof(command))); 36 CHKERRQ(PetscStrlcat(command,attempt,sizeof(command))); 37 #if defined(PETSC_HAVE_POPEN) 38 CHKERRQ(PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fp)); 39 PetscCheckFalse(!fgets(pythonlib,pl,fp),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: bad output from executable: %s\nRunning: %s",pythonexe,command); 40 CHKERRQ(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 CHKERRQ(PetscStrchr(pythonlib,'\n',&eol)); 46 if (eol) eol[0] = 0; 47 CHKERRQ(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; import sys;print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),\"libpython\"+sys.version[:3]+\".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 CHKERRQ(PetscStrncpy(pythonlib,PETSC_PYTHON_LIB,pl)); 64 PetscFunctionReturn(0); 65 #endif 66 67 CHKERRQ(PetscPythonFindLibraryName(pythonexe,cmdline1,pythonlib,pl,&found)); 68 if (!found) { 69 CHKERRQ(PetscPythonFindLibraryName(pythonexe,cmdline2,pythonlib,pl,&found)); 70 } 71 if (!found) { 72 CHKERRQ(PetscPythonFindLibraryName(pythonexe,cmdline3,pythonlib,pl,&found)); 73 } 74 if (!found) { 75 CHKERRQ(PetscPythonFindLibraryName(pythonexe,cmdline4,pythonlib,pl,&found)); 76 } 77 if (!found) { 78 CHKERRQ(PetscPythonFindLibraryName(pythonexe,cmdline5,pythonlib,pl,&found)); 79 } 80 CHKERRQ(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 CHKERRQ(PetscDLPyLibOpen(pythonlib)); 123 CHKERRQ(PetscInfo(NULL,"Python: loaded dynamic library %s\n", pythonlib)); 124 /* look required symbols from the Python C-API */ 125 CHKERRQ(PetscDLPyLibSym("_Py_NoneStruct" , &Py_None)); 126 CHKERRQ(PetscDLPyLibSym("Py_GetVersion" , &Py_GetVersion)); 127 CHKERRQ(PetscDLPyLibSym("Py_IsInitialized" , &Py_IsInitialized)); 128 CHKERRQ(PetscDLPyLibSym("Py_InitializeEx" , &Py_InitializeEx)); 129 CHKERRQ(PetscDLPyLibSym("Py_Finalize" , &Py_Finalize)); 130 CHKERRQ(PetscDLPyLibSym("PySys_GetObject" , &PySys_GetObject)); 131 CHKERRQ(PetscDLPyLibSym("PySys_SetArgv" , &PySys_SetArgv)); 132 CHKERRQ(PetscDLPyLibSym("PyObject_CallMethod" , &PyObject_CallMethod)); 133 CHKERRQ(PetscDLPyLibSym("PyImport_ImportModule" , &PyImport_ImportModule)); 134 CHKERRQ(PetscDLPyLibSym("Py_IncRef" , &Py_IncRef)); 135 CHKERRQ(PetscDLPyLibSym("Py_DecRef" , &Py_DecRef)); 136 CHKERRQ(PetscDLPyLibSym("PyErr_Clear" , &PyErr_Clear)); 137 CHKERRQ(PetscDLPyLibSym("PyErr_Occurred" , &PyErr_Occurred)); 138 CHKERRQ(PetscDLPyLibSym("PyErr_Fetch" , &PyErr_Fetch)); 139 CHKERRQ(PetscDLPyLibSym("PyErr_NormalizeException", &PyErr_NormalizeException)); 140 CHKERRQ(PetscDLPyLibSym("PyErr_Display", &PyErr_Display)); 141 CHKERRQ(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 CHKERRQ(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 Parameter: 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 CHKERRQ(PetscStrncpy(PetscPythonExe,pyexe,sizeof(PetscPythonExe))); 191 } else { 192 CHKERRQ(PetscPythonFindExecutable(PetscPythonExe,sizeof(PetscPythonExe))); 193 } 194 /* Python dynamic library */ 195 if (pylib && pylib[0] != 0) { 196 CHKERRQ(PetscStrncpy(PetscPythonLib,pylib,sizeof(PetscPythonLib))); 197 } else { 198 CHKERRQ(PetscPythonFindLibrary(PetscPythonExe,PetscPythonLib,sizeof(PetscPythonLib))); 199 } 200 /* dynamically load Python library */ 201 CHKERRQ(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 */ 211 Py_InitializeEx(0); /* 0: do not install signal handlers */ 212 /* build 'sys.argv' list */ 213 py_version = Py_GetVersion(); 214 if (py_version[0] == '2') { 215 int argc = 0; char *argv[1] = {NULL}; 216 PySys_SetArgv(argc,argv); 217 } 218 if (py_version[0] == '3') { 219 int argc = 0; wchar_t *argv[1] = {NULL}; 220 PySys_SetArgv(argc,argv); 221 } 222 /* add PETSC_LIB_DIR in front of 'sys.path' */ 223 sys_path = PySys_GetObject("path"); 224 if (sys_path) { 225 CHKERRQ(PetscStrreplace(PETSC_COMM_SELF,"${PETSC_LIB_DIR}",path,sizeof(path))); 226 Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,(char*)path)); 227 #if defined(PETSC_PETSC4PY_INSTALL_PATH) 228 { 229 char *rpath; 230 CHKERRQ(PetscStrallocpy(PETSC_PETSC4PY_INSTALL_PATH,&rpath)); 231 Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,rpath)); 232 CHKERRQ(PetscFree(rpath)); 233 } 234 #endif 235 } 236 /* register finalizer */ 237 if (!registered) { 238 CHKERRQ(PetscRegisterFinalize(PetscPythonFinalize)); 239 registered = PETSC_TRUE; 240 } 241 PetscBeganPython = PETSC_TRUE; 242 } 243 /* import 'petsc4py.PETSc' module */ 244 module = PyImport_ImportModule("petsc4py.PETSc"); 245 if (module) { 246 CHKERRQ(PetscInfo(NULL,"Python: successfully imported module 'petsc4py.PETSc'\n")); 247 248 Py_DecRef(module); module = NULL; 249 } else { 250 PetscPythonPrintError(); 251 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: could not import module 'petsc4py.PETSc', perhaps your PYTHONPATH does not contain it"); 252 } 253 PetscFunctionReturn(0); 254 } 255 256 /*@C 257 PetscPythonPrintError - Print Python errors. 258 259 Level: developer 260 261 @*/ 262 PetscErrorCode PetscPythonPrintError(void) 263 { 264 PyObject *exc=NULL, *val=NULL, *tb=NULL; 265 266 PetscFunctionBegin; 267 if (!PetscBeganPython) PetscFunctionReturn(0); 268 if (!PyErr_Occurred()) PetscFunctionReturn(0); 269 PyErr_Fetch(&exc,&val,&tb); 270 PyErr_NormalizeException(&exc,&val,&tb); 271 PyErr_Display(exc ? exc : Py_None, val ? val : Py_None, tb ? tb : Py_None); 272 PyErr_Restore(exc,val,tb); 273 PetscFunctionReturn(0); 274 } 275 276 /* ---------------------------------------------------------------- */ 277 278 PETSC_EXTERN PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]); 279 PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]) = NULL; 280 281 /*@C 282 PetscPythonMonitorSet - Set Python monitor 283 284 Level: developer 285 286 @*/ 287 PetscErrorCode PetscPythonMonitorSet(PetscObject obj, const char url[]) 288 { 289 PetscFunctionBegin; 290 PetscValidHeader(obj,1); 291 PetscValidCharPointer(url,2); 292 if (!PetscPythonMonitorSet_C) { 293 CHKERRQ(PetscPythonInitialize(NULL,NULL)); 294 PetscCheck(PetscPythonMonitorSet_C,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't initialize Python support for monitors"); 295 } 296 CHKERRQ(PetscPythonMonitorSet_C(obj,url)); 297 PetscFunctionReturn(0); 298 } 299 300 /* ---------------------------------------------------------------- */ 301