Date: 2022-03-04T17:37:18+00:00

Actual source code: pythonsys.c

      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)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: bad output from executable: %s\nRunning: %s",pythonexe,command);
     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: }

     53: static PetscErrorCode PetscPythonFindLibrary(const char pythonexe[],char pythonlib[],size_t pl)
     54: {
     55:   const char     cmdline1[] = "-c 'import os, sysconfig; print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),sysconfig.get_config_var(\"LDLIBRARY\")))'";
     56:   const char     cmdline2[] = "-c 'import os, sysconfig; import sys;print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),\"libpython\"+sys.version[:3]+\".dylib\"))'";
     57:   const char     cmdline3[] = "-c 'import os, sysconfig; print(os.path.join(sysconfig.get_config_var(\"LIBPL\"),sysconfig.get_config_var(\"LDLIBRARY\")))'";
     58:   const char     cmdline4[] = "-c 'import sysconfig; print(sysconfig.get_config_var(\"LIBPYTHON\"))'";
     59:   const char     cmdline5[] = "-c 'import os, sysconfig; import sys;print(os.path.join(sysconfig.get_config_var(\"LIBDIR\"),\"libpython\"+sys.version[:3]+\".so\"))'";

     61:   PetscBool      found = PETSC_FALSE;

     65: #if defined(PETSC_PYTHON_LIB)
     66:   PetscStrncpy(pythonlib,PETSC_PYTHON_LIB,pl);
     67:   return(0);
     68: #endif

     70:   PetscPythonFindLibraryName(pythonexe,cmdline1,pythonlib,pl,&found);
     71:   if (!found) {
     72:     PetscPythonFindLibraryName(pythonexe,cmdline2,pythonlib,pl,&found);
     73:   }
     74:   if (!found) {
     75:     PetscPythonFindLibraryName(pythonexe,cmdline3,pythonlib,pl,&found);
     76:   }
     77:   if (!found) {
     78:     PetscPythonFindLibraryName(pythonexe,cmdline4,pythonlib,pl,&found);
     79:   }
     80:   if (!found) {
     81:     PetscPythonFindLibraryName(pythonexe,cmdline5,pythonlib,pl,&found);
     82:   }
     83:   PetscInfo2(NULL,"Python library  %s found %d\n",pythonlib,found);
     84:   return(0);
     85: }

     87: /* ---------------------------------------------------------------- */

     89: typedef struct _Py_object_t PyObject; /* fake definition */

     91: static PyObject* Py_None = NULL;

     93: static const char* (*Py_GetVersion)(void);

     95: static int       (*Py_IsInitialized)(void);
     96: static void      (*Py_InitializeEx)(int);
     97: static void      (*Py_Finalize)(void);

     99: static void      (*PySys_SetArgv)(int,void*);
    100: static PyObject* (*PySys_GetObject)(const char*);
    101: static PyObject* (*PyObject_CallMethod)(PyObject*,const char*, const char*, ...);
    102: static PyObject* (*PyImport_ImportModule)(const char*);

    104: static void      (*Py_IncRef)(PyObject*);
    105: static void      (*Py_DecRef)(PyObject*);

    107: static void      (*PyErr_Clear)(void);
    108: static PyObject* (*PyErr_Occurred)(void);
    109: static void      (*PyErr_Fetch)(PyObject**,PyObject**,PyObject**);
    110: static void      (*PyErr_NormalizeException)(PyObject**,PyObject**, PyObject**);
    111: static void      (*PyErr_Display)(PyObject*,PyObject*,PyObject*);
    112: static void      (*PyErr_Restore)(PyObject*,PyObject*,PyObject*);

    114: #define PetscDLPyLibOpen(libname) \
    115:   PetscDLLibraryAppend(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,libname)
    116: #define PetscDLPyLibSym(symbol, value) \
    117:   PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,symbol,(void**)value)
    118: #define PetscDLPyLibClose(comm) \
    119:   do { } while (0)

    121: static PetscErrorCode PetscPythonLoadLibrary(const char pythonlib[])
    122: {

    126:   /* open the Python dynamic library */
    127:   PetscDLPyLibOpen(pythonlib);
    128:   PetscInfo1(NULL,"Python: loaded dynamic library %s\n", pythonlib);
    129:   /* look required symbols from the Python C-API */
    130:   PetscDLPyLibSym("_Py_NoneStruct"        , &Py_None);
    131:   PetscDLPyLibSym("Py_GetVersion"         , &Py_GetVersion);
    132:   PetscDLPyLibSym("Py_IsInitialized"      , &Py_IsInitialized);
    133:   PetscDLPyLibSym("Py_InitializeEx"       , &Py_InitializeEx);
    134:   PetscDLPyLibSym("Py_Finalize"           , &Py_Finalize);
    135:   PetscDLPyLibSym("PySys_GetObject"       , &PySys_GetObject);
    136:   PetscDLPyLibSym("PySys_SetArgv"         , &PySys_SetArgv);
    137:   PetscDLPyLibSym("PyObject_CallMethod"   , &PyObject_CallMethod);
    138:   PetscDLPyLibSym("PyImport_ImportModule" , &PyImport_ImportModule);
    139:   PetscDLPyLibSym("Py_IncRef"             , &Py_IncRef);
    140:   PetscDLPyLibSym("Py_DecRef"             , &Py_DecRef);
    141:   PetscDLPyLibSym("PyErr_Clear"           , &PyErr_Clear);
    142:   PetscDLPyLibSym("PyErr_Occurred"        , &PyErr_Occurred);
    143:   PetscDLPyLibSym("PyErr_Fetch"             , &PyErr_Fetch);
    144:   PetscDLPyLibSym("PyErr_NormalizeException", &PyErr_NormalizeException);
    145:   PetscDLPyLibSym("PyErr_Display",            &PyErr_Display);
    146:   PetscDLPyLibSym("PyErr_Restore",            &PyErr_Restore);
    147:   /* XXX TODO: check that ALL symbols were there !!! */
    148:   if (!Py_None)          SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
    149:   if (!Py_GetVersion)    SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
    150:   if (!Py_IsInitialized) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
    151:   if (!Py_InitializeEx)  SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
    152:   if (!Py_Finalize)      SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: failed to load symbols from Python dynamic library %s",pythonlib);
    153:   PetscInfo1(NULL,"Python: all required symbols loaded from Python dynamic library %s\n",pythonlib);
    154:   return(0);
    155: }

    157: /* ---------------------------------------------------------------- */

    159: static char      PetscPythonExe[PETSC_MAX_PATH_LEN] = { 0 };
    160: static char      PetscPythonLib[PETSC_MAX_PATH_LEN] = { 0 };
    161: static PetscBool PetscBeganPython = PETSC_FALSE;

    163: /*@C
    164:   PetscPythonFinalize - Finalize Python.

    166:   Level: intermediate

    168: @*/
    169: PetscErrorCode  PetscPythonFinalize(void)
    170: {
    172:   if (PetscBeganPython) { if (Py_IsInitialized()) Py_Finalize(); }
    173:   PetscBeganPython = PETSC_FALSE;
    174:   return(0);
    175: }

    177: /*@C
    178:   PetscPythonInitialize - Initialize Python and import petsc4py.

    180:    Input Parameter:
    181: +  pyexe - path to the Python interpreter executable, or NULL.
    182: -  pylib - full path to the Python dynamic library, or NULL.

    184:   Level: intermediate

    186: @*/
    187: PetscErrorCode  PetscPythonInitialize(const char pyexe[],const char pylib[])
    188: {
    189:   PyObject       *module = NULL;

    193:   if (PetscBeganPython) return(0);
    194:   /* Python executable */
    195:   if (pyexe && pyexe[0] != 0) {
    196:     PetscStrncpy(PetscPythonExe,pyexe,sizeof(PetscPythonExe));
    197:   } else {
    198:     PetscPythonFindExecutable(PetscPythonExe,sizeof(PetscPythonExe));
    199:   }
    200:   /* Python dynamic library */
    201:   if (pylib && pylib[0] != 0) {
    202:     PetscStrncpy(PetscPythonLib,pylib,sizeof(PetscPythonLib));
    203:   } else {
    204:     PetscPythonFindLibrary(PetscPythonExe,PetscPythonLib,sizeof(PetscPythonLib));
    205:   }
    206:   /* dynamically load Python library */
    207:   PetscPythonLoadLibrary(PetscPythonLib);
    208:   /* initialize Python */
    209:   PetscBeganPython = PETSC_FALSE;
    210:   if (!Py_IsInitialized()) {
    211:     static PetscBool registered = PETSC_FALSE;
    212:     const char       *py_version;
    213:     PyObject         *sys_path;
    214:     char             path[PETSC_MAX_PATH_LEN] = { 0 };

    216:     /* initialize Python */
    217:     Py_InitializeEx(0); /* 0: do not install signal handlers */
    218:     /*  build 'sys.argv' list */
    219:     py_version = Py_GetVersion();
    220:     if (py_version[0] == '2') {
    221:       int argc = 0; char *argv[1] = {NULL};
    222:       PySys_SetArgv(argc,argv);
    223:     }
    224:     if (py_version[0] == '3') {
    225:       int argc = 0; wchar_t *argv[1] = {NULL};
    226:       PySys_SetArgv(argc,argv);
    227:     }
    228:     /* add PETSC_LIB_DIR in front of 'sys.path' */
    229:     sys_path = PySys_GetObject("path");
    230:     if (sys_path) {
    231:       PetscStrreplace(PETSC_COMM_SELF,"${PETSC_LIB_DIR}",path,sizeof(path));
    232:       Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,(char*)path));
    233: #if defined(PETSC_PETSC4PY_INSTALL_PATH)
    234:       {
    235:         char *rpath;
    236:         PetscStrallocpy(PETSC_PETSC4PY_INSTALL_PATH,&rpath);
    237:         Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,rpath));
    238:         PetscFree(rpath);
    239:       }
    240: #endif
    241:     }
    242:     /* register finalizer */
    243:     if (!registered) {
    244:       PetscRegisterFinalize(PetscPythonFinalize);
    245:       registered = PETSC_TRUE;
    246:     }
    247:     PetscBeganPython = PETSC_TRUE;
    248:   }
    249:   /* import 'petsc4py.PETSc' module */
    250:   module = PyImport_ImportModule("petsc4py.PETSc");
    251:   if (module) {
    252:     PetscInfo(NULL,"Python: successfully imported  module 'petsc4py.PETSc'\n");

    254:     Py_DecRef(module); module = NULL;
    255:   } else {
    256:     PetscPythonPrintError();
    257:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: could not import module 'petsc4py.PETSc', perhaps your PYTHONPATH does not contain it\n");
    258:   }
    259:   return(0);
    260: }

    262: /*@C
    263:   PetscPythonPrintError - Print Python errors.

    265:   Level: developer

    267: @*/
    268: PetscErrorCode  PetscPythonPrintError(void)
    269: {
    270:   PyObject *exc=NULL, *val=NULL, *tb=NULL;

    273:   if (!PetscBeganPython) return(0);
    274:   if (!PyErr_Occurred()) return(0);
    275:   PyErr_Fetch(&exc,&val,&tb);
    276:   PyErr_NormalizeException(&exc,&val,&tb);
    277:   PyErr_Display(exc ? exc : Py_None, val ? val : Py_None, tb  ? tb  : Py_None);
    278:   PyErr_Restore(exc,val,tb);
    279:   return(0);
    280: }

    282: /* ---------------------------------------------------------------- */

    284: PETSC_EXTERN PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]);
    285: PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]) = NULL;

    287: /*@C
    288:   PetscPythonMonitorSet - Set Python monitor

    290:   Level: developer

    292: @*/
    293: PetscErrorCode PetscPythonMonitorSet(PetscObject obj, const char url[])
    294: {

    300:   if (!PetscPythonMonitorSet_C) {
    301:     PetscPythonInitialize(NULL,NULL);
    302:     if (!PetscPythonMonitorSet_C) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't initialize Python support for monitors");
    303:   }
    304:   PetscPythonMonitorSet_C(obj,url);
    305:   return(0);
    306: }

    308: /* ---------------------------------------------------------------- */