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