Date: 2022-08-02T03:13:29+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;

     13:   /* get the path for the Python interpreter executable */
     14:   PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,len);
     15:   PetscOptionsGetString(NULL,NULL,"-python",pythonexe,len,&flag);
     16:   if (!flag || pythonexe[0]==0) {
     17:     PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,len);
     18:   }
     19:   return 0;
     20: }

     22: /*
     23:     Python does not appear to have a universal way to indicate the location of Python dynamic library so try several possibilities
     24: */
     25: static PetscErrorCode PetscPythonFindLibraryName(const char pythonexe[],const char attempt[],char pythonlib[],size_t pl,PetscBool *found)
     26: {
     27:   char           command[2*PETSC_MAX_PATH_LEN];
     28:   FILE           *fp = NULL;
     29:   char           *eol;

     31:   /* call Python to find out the name of the Python dynamic library */
     32:   PetscStrncpy(command,pythonexe,sizeof(command));
     33:   PetscStrlcat(command," ",sizeof(command));
     34:   PetscStrlcat(command,attempt,sizeof(command));
     35: #if defined(PETSC_HAVE_POPEN)
     36:   PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fp);
     38:   PetscPClose(PETSC_COMM_SELF,fp);
     39: #else
     40:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Python: Aborted due to missing popen()");
     41: #endif
     42:   /* remove newlines */
     43:   PetscStrchr(pythonlib,'\n',&eol);
     44:   if (eol) eol[0] = 0;
     45:   PetscTestFile(pythonlib,'r',found);
     46:   return 0;
     47: }

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

     57:   PetscBool      found = PETSC_FALSE;

     59: #if defined(PETSC_PYTHON_LIB)
     60:   PetscStrncpy(pythonlib,PETSC_PYTHON_LIB,pl);
     61:   return 0;
     62: #endif

     64:   PetscPythonFindLibraryName(pythonexe,cmdline1,pythonlib,pl,&found);
     65:   if (!found) {
     66:     PetscPythonFindLibraryName(pythonexe,cmdline2,pythonlib,pl,&found);
     67:   }
     68:   if (!found) {
     69:     PetscPythonFindLibraryName(pythonexe,cmdline3,pythonlib,pl,&found);
     70:   }
     71:   if (!found) {
     72:     PetscPythonFindLibraryName(pythonexe,cmdline4,pythonlib,pl,&found);
     73:   }
     74:   if (!found) {
     75:     PetscPythonFindLibraryName(pythonexe,cmdline5,pythonlib,pl,&found);
     76:   }
     77:   PetscInfo(NULL,"Python library  %s found %d\n",pythonlib,found);
     78:   return 0;
     79: }

     81: /* ---------------------------------------------------------------- */

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

     85: static PyObject* Py_None = NULL;

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

     89: static int       (*Py_IsInitialized)(void);
     90: static void      (*Py_InitializeEx)(int);
     91: static void      (*Py_Finalize)(void);

     93: static void      (*PySys_SetArgv)(int,void*);
     94: static PyObject* (*PySys_GetObject)(const char*);
     95: static PyObject* (*PyObject_CallMethod)(PyObject*,const char*, const char*, ...);
     96: static PyObject* (*PyImport_ImportModule)(const char*);

     98: static void      (*Py_IncRef)(PyObject*);
     99: static void      (*Py_DecRef)(PyObject*);

    101: static void      (*PyErr_Clear)(void);
    102: static PyObject* (*PyErr_Occurred)(void);
    103: static void      (*PyErr_Fetch)(PyObject**,PyObject**,PyObject**);
    104: static void      (*PyErr_NormalizeException)(PyObject**,PyObject**, PyObject**);
    105: static void      (*PyErr_Display)(PyObject*,PyObject*,PyObject*);
    106: static void      (*PyErr_Restore)(PyObject*,PyObject*,PyObject*);

    108: #define PetscDLPyLibOpen(libname) \
    109:   PetscDLLibraryAppend(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,libname)
    110: #define PetscDLPyLibSym(symbol, value) \
    111:   PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,symbol,(void**)value)
    112: #define PetscDLPyLibClose(comm) \
    113:   do { } while (0)

    115: static PetscErrorCode PetscPythonLoadLibrary(const char pythonlib[])
    116: {
    117:   /* open the Python dynamic library */
    118:   PetscDLPyLibOpen(pythonlib);
    119:   PetscInfo(NULL,"Python: loaded dynamic library %s\n", pythonlib);
    120:   /* look required symbols from the Python C-API */
    121:   PetscDLPyLibSym("_Py_NoneStruct"        , &Py_None);
    122:   PetscDLPyLibSym("Py_GetVersion"         , &Py_GetVersion);
    123:   PetscDLPyLibSym("Py_IsInitialized"      , &Py_IsInitialized);
    124:   PetscDLPyLibSym("Py_InitializeEx"       , &Py_InitializeEx);
    125:   PetscDLPyLibSym("Py_Finalize"           , &Py_Finalize);
    126:   PetscDLPyLibSym("PySys_GetObject"       , &PySys_GetObject);
    127:   PetscDLPyLibSym("PySys_SetArgv"         , &PySys_SetArgv);
    128:   PetscDLPyLibSym("PyObject_CallMethod"   , &PyObject_CallMethod);
    129:   PetscDLPyLibSym("PyImport_ImportModule" , &PyImport_ImportModule);
    130:   PetscDLPyLibSym("Py_IncRef"             , &Py_IncRef);
    131:   PetscDLPyLibSym("Py_DecRef"             , &Py_DecRef);
    132:   PetscDLPyLibSym("PyErr_Clear"           , &PyErr_Clear);
    133:   PetscDLPyLibSym("PyErr_Occurred"        , &PyErr_Occurred);
    134:   PetscDLPyLibSym("PyErr_Fetch"             , &PyErr_Fetch);
    135:   PetscDLPyLibSym("PyErr_NormalizeException", &PyErr_NormalizeException);
    136:   PetscDLPyLibSym("PyErr_Display",            &PyErr_Display);
    137:   PetscDLPyLibSym("PyErr_Restore",            &PyErr_Restore);
    138:   /* XXX TODO: check that ALL symbols were there !!! */
    144:   PetscInfo(NULL,"Python: all required symbols loaded from Python dynamic library %s\n",pythonlib);
    145:   return 0;
    146: }

    148: /* ---------------------------------------------------------------- */

    150: static char      PetscPythonExe[PETSC_MAX_PATH_LEN] = { 0 };
    151: static char      PetscPythonLib[PETSC_MAX_PATH_LEN] = { 0 };
    152: static PetscBool PetscBeganPython = PETSC_FALSE;

    154: /*@C
    155:   PetscPythonFinalize - Finalize Python.

    157:   Level: intermediate

    159: @*/
    160: PetscErrorCode  PetscPythonFinalize(void)
    161: {
    162:   if (PetscBeganPython) { if (Py_IsInitialized()) Py_Finalize(); }
    163:   PetscBeganPython = PETSC_FALSE;
    164:   return 0;
    165: }

    167: /*@C
    168:   PetscPythonInitialize - Initialize Python and import petsc4py.

    170:    Input Parameter:
    171: +  pyexe - path to the Python interpreter executable, or NULL.
    172: -  pylib - full path to the Python dynamic library, or NULL.

    174:   Level: intermediate

    176: @*/
    177: PetscErrorCode  PetscPythonInitialize(const char pyexe[],const char pylib[])
    178: {
    179:   PyObject       *module = NULL;

    181:   if (PetscBeganPython) return 0;
    182:   /* Python executable */
    183:   if (pyexe && pyexe[0] != 0) {
    184:     PetscStrncpy(PetscPythonExe,pyexe,sizeof(PetscPythonExe));
    185:   } else {
    186:     PetscPythonFindExecutable(PetscPythonExe,sizeof(PetscPythonExe));
    187:   }
    188:   /* Python dynamic library */
    189:   if (pylib && pylib[0] != 0) {
    190:     PetscStrncpy(PetscPythonLib,pylib,sizeof(PetscPythonLib));
    191:   } else {
    192:     PetscPythonFindLibrary(PetscPythonExe,PetscPythonLib,sizeof(PetscPythonLib));
    193:   }
    194:   /* dynamically load Python library */
    195:   PetscPythonLoadLibrary(PetscPythonLib);
    196:   /* initialize Python */
    197:   PetscBeganPython = PETSC_FALSE;
    198:   if (!Py_IsInitialized()) {
    199:     static PetscBool registered = PETSC_FALSE;
    200:     const char       *py_version;
    201:     PyObject         *sys_path;
    202:     char             path[PETSC_MAX_PATH_LEN] = { 0 };

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

    242:     Py_DecRef(module); module = NULL;
    243:   } else {
    244:     PetscPythonPrintError();
    245:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: could not import module 'petsc4py.PETSc', perhaps your PYTHONPATH does not contain it");
    246:   }
    247:   return 0;
    248: }

    250: /*@C
    251:   PetscPythonPrintError - Print Python errors.

    253:   Level: developer

    255: @*/
    256: PetscErrorCode  PetscPythonPrintError(void)
    257: {
    258:   PyObject *exc=NULL, *val=NULL, *tb=NULL;

    260:   if (!PetscBeganPython) return 0;
    261:   if (!PyErr_Occurred()) return 0;
    262:   PyErr_Fetch(&exc,&val,&tb);
    263:   PyErr_NormalizeException(&exc,&val,&tb);
    264:   PyErr_Display(exc ? exc : Py_None, val ? val : Py_None, tb  ? tb  : Py_None);
    265:   PyErr_Restore(exc,val,tb);
    266:   return 0;
    267: }

    269: /* ---------------------------------------------------------------- */

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

    274: /*@C
    275:   PetscPythonMonitorSet - Set Python monitor

    277:   Level: developer

    279: @*/
    280: PetscErrorCode PetscPythonMonitorSet(PetscObject obj, const char url[])
    281: {
    284:   if (!PetscPythonMonitorSet_C) {
    285:     PetscPythonInitialize(NULL,NULL);
    287:   }
    288:   PetscPythonMonitorSet_C(obj,url);
    289:   return 0;
    290: }

    292: /* ---------------------------------------------------------------- */