Actual source code: pythonsys.c

petsc-3.14.6 2021-03-30
Report Typos and Errors
  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: /* ---------------------------------------------------------------- */