xref: /petsc/src/sys/python/pythonsys.c (revision c4aff0603fc492ff1b8f7cea5c0683e73afe702f)
1*c4aff060SBarry Smith #define PETSC_DLL
2*c4aff060SBarry Smith 
3*c4aff060SBarry Smith #include "petsc.h"       /*I "petsc.h" I*/
4*c4aff060SBarry Smith #include "petscsys.h"    /*I "petscsys.h" I*/
5*c4aff060SBarry Smith 
6*c4aff060SBarry Smith /* ---------------------------------------------------------------- */
7*c4aff060SBarry Smith 
8*c4aff060SBarry Smith #if !defined(PETSC_PYTHON_EXE)
9*c4aff060SBarry Smith #define PETSC_PYTHON_EXE "python"
10*c4aff060SBarry Smith #endif
11*c4aff060SBarry Smith 
12*c4aff060SBarry Smith #undef __FUNCT__
13*c4aff060SBarry Smith #define __FUNCT__ "PetscPythonFindExecutable"
14*c4aff060SBarry Smith static PetscErrorCode PetscPythonFindExecutable(char pythonexe[PETSC_MAX_PATH_LEN])
15*c4aff060SBarry Smith {
16*c4aff060SBarry Smith   PetscTruth     flag;
17*c4aff060SBarry Smith   PetscErrorCode ierr;
18*c4aff060SBarry Smith   PetscFunctionBegin;
19*c4aff060SBarry Smith   /* get the path for the Python interpreter executable */
20*c4aff060SBarry Smith   ierr = PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
21*c4aff060SBarry Smith   ierr = PetscOptionsGetString(PETSC_NULL,"-python",pythonexe,PETSC_MAX_PATH_LEN,&flag);CHKERRQ(ierr);
22*c4aff060SBarry Smith   if (!flag || pythonexe[0]==0) {
23*c4aff060SBarry Smith     ierr = PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
24*c4aff060SBarry Smith   }
25*c4aff060SBarry Smith   PetscFunctionReturn(0);
26*c4aff060SBarry Smith }
27*c4aff060SBarry Smith 
28*c4aff060SBarry Smith #undef __FUNCT__
29*c4aff060SBarry Smith #define __FUNCT__ "PetscPythonFindLibrary"
30*c4aff060SBarry Smith static PetscErrorCode PetscPythonFindLibrary(char pythonexe[PETSC_MAX_PATH_LEN],
31*c4aff060SBarry Smith 					     char pythonlib[PETSC_MAX_PATH_LEN])
32*c4aff060SBarry Smith {
33*c4aff060SBarry Smith   const char cmdline[] = "-c 'import sys; print(sys.exec_prefix); print(sys.version[:3])'";
34*c4aff060SBarry Smith   char command[PETSC_MAX_PATH_LEN+1+sizeof(cmdline)+1];
35*c4aff060SBarry Smith   char prefix[PETSC_MAX_PATH_LEN],version[8],sep[2]={PETSC_DIR_SEPARATOR, 0},*eol;
36*c4aff060SBarry Smith   FILE* fp = NULL;
37*c4aff060SBarry Smith   char path[PETSC_MAX_PATH_LEN+1];
38*c4aff060SBarry Smith   PetscTruth found = PETSC_FALSE;
39*c4aff060SBarry Smith   PetscErrorCode ierr;
40*c4aff060SBarry Smith   PetscFunctionBegin;
41*c4aff060SBarry Smith 
42*c4aff060SBarry Smith #if defined(PETSC_PYTHON_LIB)
43*c4aff060SBarry Smith   ierr = PetscStrcpy(pythonlib,PETSC_PYTHON_LIB);CHKERRQ(ierr);
44*c4aff060SBarry Smith   PetscFunctionReturn(0);
45*c4aff060SBarry Smith #endif
46*c4aff060SBarry Smith 
47*c4aff060SBarry Smith   /* call Python to find out the name of the Python dynamic library */
48*c4aff060SBarry Smith   ierr = PetscStrncpy(command,pythonexe,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
49*c4aff060SBarry Smith   ierr = PetscStrcat(command," ");CHKERRQ(ierr);
50*c4aff060SBarry Smith   ierr = PetscStrcat(command,cmdline);CHKERRQ(ierr);
51*c4aff060SBarry Smith #if defined(PETSC_HAVE_POPEN)
52*c4aff060SBarry Smith   ierr = PetscPOpen(PETSC_COMM_SELF,PETSC_NULL,command,"r",&fp);CHKERRQ(ierr);
53*c4aff060SBarry Smith   if (!fgets(prefix,sizeof(prefix),fp))
54*c4aff060SBarry Smith     { SETERRQ1(PETSC_ERR_PLIB,"Python: bad output from executable: %s",pythonexe); }
55*c4aff060SBarry Smith   if (!fgets(version,sizeof(version),fp))
56*c4aff060SBarry Smith     { SETERRQ1(PETSC_ERR_PLIB,"Python: bad output from executable: %s",pythonexe); }
57*c4aff060SBarry Smith   ierr = PetscPClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr);
58*c4aff060SBarry Smith #else
59*c4aff060SBarry Smith   SETERRQ(1,"Python: Aborted due to missing popen()");
60*c4aff060SBarry Smith #endif
61*c4aff060SBarry Smith   /* remove newlines */
62*c4aff060SBarry Smith   ierr = PetscStrchr(prefix,'\n',&eol);CHKERRQ(ierr);
63*c4aff060SBarry Smith   if (eol) eol[0] = 0;
64*c4aff060SBarry Smith   ierr = PetscStrchr(version,'\n',&eol);CHKERRQ(ierr);
65*c4aff060SBarry Smith   if (eol) eol[0] = 0;
66*c4aff060SBarry Smith 
67*c4aff060SBarry Smith   /* test for $prefix/lib64/libpythonX.X[.so]*/
68*c4aff060SBarry Smith   ierr = PetscStrcpy(pythonlib,prefix);CHKERRQ(ierr);
69*c4aff060SBarry Smith   ierr = PetscStrcat(pythonlib,sep);CHKERRQ(ierr);
70*c4aff060SBarry Smith   ierr = PetscStrcat(pythonlib,"lib64");CHKERRQ(ierr);
71*c4aff060SBarry Smith   ierr = PetscTestDirectory(pythonlib,'r',&found);CHKERRQ(ierr);
72*c4aff060SBarry Smith   if (found) {
73*c4aff060SBarry Smith     ierr = PetscStrcat(pythonlib,sep);CHKERRQ(ierr);
74*c4aff060SBarry Smith     ierr = PetscStrcat(pythonlib,"libpython");CHKERRQ(ierr);
75*c4aff060SBarry Smith     ierr = PetscStrcat(pythonlib,version);CHKERRQ(ierr);
76*c4aff060SBarry Smith     ierr = PetscDLLibraryRetrieve(PETSC_COMM_SELF,pythonlib,path,PETSC_MAX_PATH_LEN,&found);CHKERRQ(ierr);
77*c4aff060SBarry Smith     if (found) PetscFunctionReturn(0);
78*c4aff060SBarry Smith   }
79*c4aff060SBarry Smith 
80*c4aff060SBarry Smith   /* test for $prefix/lib/libpythonX.X[.so]*/
81*c4aff060SBarry Smith   ierr = PetscStrcpy(pythonlib,prefix);CHKERRQ(ierr);
82*c4aff060SBarry Smith   ierr = PetscStrcat(pythonlib,sep);CHKERRQ(ierr);
83*c4aff060SBarry Smith   ierr = PetscStrcat(pythonlib,"lib");CHKERRQ(ierr);
84*c4aff060SBarry Smith   ierr = PetscTestDirectory(pythonlib,'r',&found);CHKERRQ(ierr);
85*c4aff060SBarry Smith   if (found) {
86*c4aff060SBarry Smith     ierr = PetscStrcat(pythonlib,sep);CHKERRQ(ierr);
87*c4aff060SBarry Smith     ierr = PetscStrcat(pythonlib,"libpython");CHKERRQ(ierr);
88*c4aff060SBarry Smith     ierr = PetscStrcat(pythonlib,version);CHKERRQ(ierr);
89*c4aff060SBarry Smith     ierr = PetscDLLibraryRetrieve(PETSC_COMM_SELF,pythonlib,path,PETSC_MAX_PATH_LEN,&found);CHKERRQ(ierr);
90*c4aff060SBarry Smith     if (found) PetscFunctionReturn(0);
91*c4aff060SBarry Smith   }
92*c4aff060SBarry Smith 
93*c4aff060SBarry Smith   /* nothing good found */
94*c4aff060SBarry Smith   ierr = PetscMemzero(pythonlib,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
95*c4aff060SBarry Smith   ierr = PetscInfo(0,"Python dynamic library not found\n");CHKERRQ(ierr);
96*c4aff060SBarry Smith 
97*c4aff060SBarry Smith   PetscFunctionReturn(0);
98*c4aff060SBarry Smith }
99*c4aff060SBarry Smith 
100*c4aff060SBarry Smith /* ---------------------------------------------------------------- */
101*c4aff060SBarry Smith 
102*c4aff060SBarry Smith typedef struct _Py_object_t PyObject; /* fake definition */
103*c4aff060SBarry Smith 
104*c4aff060SBarry Smith static int   	 (*Py_IsInitialized)(void);
105*c4aff060SBarry Smith static void  	 (*Py_InitializeEx)(int);
106*c4aff060SBarry Smith static void  	 (*Py_Finalize)(void);
107*c4aff060SBarry Smith 
108*c4aff060SBarry Smith static void      (*PySys_SetArgv)(int, char **);
109*c4aff060SBarry Smith static PyObject* (*PyImport_ImportModule)(const char *);
110*c4aff060SBarry Smith 
111*c4aff060SBarry Smith static void      (*Py_IncRef)(PyObject *);
112*c4aff060SBarry Smith static void      (*Py_DecRef)(PyObject *);
113*c4aff060SBarry Smith 
114*c4aff060SBarry Smith static void      (*PyErr_Clear)(void);
115*c4aff060SBarry Smith static PyObject* (*PyErr_Occurred)(void);
116*c4aff060SBarry Smith 
117*c4aff060SBarry Smith 
118*c4aff060SBarry Smith #define PetscDLPyLibOpen(libname) \
119*c4aff060SBarry Smith   PetscDLLibraryAppend(PETSC_COMM_SELF,&DLLibrariesLoaded,libname)
120*c4aff060SBarry Smith #define PetscDLPyLibSym(symbol, value) \
121*c4aff060SBarry Smith   PetscDLLibrarySym(PETSC_COMM_SELF,&DLLibrariesLoaded,PETSC_NULL,symbol,(void**)value)
122*c4aff060SBarry Smith #define PetscDLPyLibClose(comm) \
123*c4aff060SBarry Smith   do { } while(0)
124*c4aff060SBarry Smith 
125*c4aff060SBarry Smith #undef __FUNCT__
126*c4aff060SBarry Smith #define __FUNCT__ "PetscPythonLoadLibrary"
127*c4aff060SBarry Smith static PetscErrorCode PetscPythonLoadLibrary(const char pythonlib[])
128*c4aff060SBarry Smith {
129*c4aff060SBarry Smith   PetscErrorCode ierr;
130*c4aff060SBarry Smith   PetscFunctionBegin;
131*c4aff060SBarry Smith 
132*c4aff060SBarry Smith   /* open the Python dynamic library */
133*c4aff060SBarry Smith   ierr = PetscDLPyLibOpen(pythonlib);CHKERRQ(ierr);
134*c4aff060SBarry Smith   ierr = PetscInfo1(0,"Python: loaded dynamic library %s\n", pythonlib); CHKERRQ(ierr);
135*c4aff060SBarry Smith   /* look required symbols from the Python C-API */
136*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("Py_IsInitialized"      , &Py_IsInitialized      );CHKERRQ(ierr);
137*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("Py_InitializeEx"       , &Py_InitializeEx       );CHKERRQ(ierr);
138*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("Py_Finalize"           , &Py_Finalize           );CHKERRQ(ierr);
139*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("PySys_SetArgv"         , &PySys_SetArgv         );CHKERRQ(ierr);
140*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("PyImport_ImportModule" , &PyImport_ImportModule );CHKERRQ(ierr);
141*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("Py_IncRef"             , &Py_IncRef             );CHKERRQ(ierr);
142*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("Py_DecRef"             , &Py_DecRef             );CHKERRQ(ierr);
143*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("PyErr_Clear"           , &PyErr_Clear           );CHKERRQ(ierr);
144*c4aff060SBarry Smith   ierr = PetscDLPyLibSym("PyErr_Occurred"        , &PyErr_Occurred        );CHKERRQ(ierr);
145*c4aff060SBarry Smith   /* XXX TODO: check that ALL symbols were there !!! */
146*c4aff060SBarry Smith   if (!Py_IsInitialized) {SETERRQ(1,"Python: failed to load symbols from dynamic library");}
147*c4aff060SBarry Smith   if (!Py_InitializeEx)  {SETERRQ(1,"Python: failed to load symbols from dynamic library");}
148*c4aff060SBarry Smith   if (!Py_Finalize)      {SETERRQ(1,"Python: failed to load symbols from dynamic library");}
149*c4aff060SBarry Smith   ierr = PetscInfo(0,"Python: all required symbols loaded from Python dynamic library\n"); CHKERRQ(ierr);
150*c4aff060SBarry Smith 
151*c4aff060SBarry Smith   PetscFunctionReturn(0);
152*c4aff060SBarry Smith }
153*c4aff060SBarry Smith 
154*c4aff060SBarry Smith /* ---------------------------------------------------------------- */
155*c4aff060SBarry Smith 
156*c4aff060SBarry Smith static char       PetscPythonExe[PETSC_MAX_PATH_LEN] = { 0 };
157*c4aff060SBarry Smith static char       PetscPythonLib[PETSC_MAX_PATH_LEN] = { 0 };
158*c4aff060SBarry Smith static PetscTruth PetscBeganPython = PETSC_FALSE;
159*c4aff060SBarry Smith 
160*c4aff060SBarry Smith #undef __FUNCT__
161*c4aff060SBarry Smith #define __FUNCT__ "PetscPythonFinalize"
162*c4aff060SBarry Smith /*@C
163*c4aff060SBarry Smith   PetscPythonFinalize - Finalize Python.
164*c4aff060SBarry Smith 
165*c4aff060SBarry Smith   Level: intermediate
166*c4aff060SBarry Smith 
167*c4aff060SBarry Smith .keywords: Python
168*c4aff060SBarry Smith @*/
169*c4aff060SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscPythonFinalize(void)
170*c4aff060SBarry Smith {
171*c4aff060SBarry Smith   PetscFunctionBegin;
172*c4aff060SBarry Smith   if (PetscBeganPython) { if (Py_IsInitialized()) Py_Finalize(); }
173*c4aff060SBarry Smith   PetscBeganPython = PETSC_FALSE;
174*c4aff060SBarry Smith   PetscFunctionReturn(0);
175*c4aff060SBarry Smith }
176*c4aff060SBarry Smith 
177*c4aff060SBarry Smith #undef __FUNCT__
178*c4aff060SBarry Smith #define __FUNCT__ "PetscPythonInitialize"
179*c4aff060SBarry Smith /*@C
180*c4aff060SBarry Smith   PetscPythonInitialize - Initialize Python and import petsc4py.
181*c4aff060SBarry Smith 
182*c4aff060SBarry Smith    Input Parameter:
183*c4aff060SBarry Smith +  pyexe - path to the Python interpreter executable, or PETSC_NULL.
184*c4aff060SBarry Smith -  pylib - full path to the Python dynamic library, or PETSC_NULL.
185*c4aff060SBarry Smith 
186*c4aff060SBarry Smith   Level: intermediate
187*c4aff060SBarry Smith 
188*c4aff060SBarry Smith .keywords: Python
189*c4aff060SBarry Smith 
190*c4aff060SBarry Smith @*/
191*c4aff060SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscPythonInitialize(const char pyexe[],const char pylib[])
192*c4aff060SBarry Smith {
193*c4aff060SBarry Smith   int               argc       = 0;
194*c4aff060SBarry Smith   char              **argv     = 0;
195*c4aff060SBarry Smith   PyObject          *module    = 0;
196*c4aff060SBarry Smith   static PetscTruth registered = PETSC_FALSE;
197*c4aff060SBarry Smith   PetscErrorCode    ierr;
198*c4aff060SBarry Smith   PetscFunctionBegin;
199*c4aff060SBarry Smith   if (PetscBeganPython) PetscFunctionReturn(0);
200*c4aff060SBarry Smith   /* Python executable */
201*c4aff060SBarry Smith   if (pyexe && pyexe[0] != 0) {
202*c4aff060SBarry Smith     ierr = PetscStrncpy(PetscPythonExe,pyexe,sizeof(PetscPythonExe));CHKERRQ(ierr);
203*c4aff060SBarry Smith   } else {
204*c4aff060SBarry Smith     ierr = PetscPythonFindExecutable(PetscPythonExe);CHKERRQ(ierr);
205*c4aff060SBarry Smith   }
206*c4aff060SBarry Smith   /* Python dynamic library */
207*c4aff060SBarry Smith   if (pylib && pylib[0] != 0) {
208*c4aff060SBarry Smith     ierr = PetscStrncpy(PetscPythonLib,pylib,sizeof(PetscPythonLib));CHKERRQ(ierr);
209*c4aff060SBarry Smith   } else {
210*c4aff060SBarry Smith     ierr = PetscPythonFindLibrary(PetscPythonExe,PetscPythonLib);CHKERRQ(ierr);
211*c4aff060SBarry Smith   }
212*c4aff060SBarry Smith   /* dynamically load Python library */
213*c4aff060SBarry Smith   ierr = PetscPythonLoadLibrary(PetscPythonLib);CHKERRQ(ierr);
214*c4aff060SBarry Smith   /* initialize Python */
215*c4aff060SBarry Smith   PetscBeganPython = PETSC_FALSE;
216*c4aff060SBarry Smith   if (!Py_IsInitialized()) {
217*c4aff060SBarry Smith     /* call below does not install signal handlers */
218*c4aff060SBarry Smith     Py_InitializeEx(0);
219*c4aff060SBarry Smith     /* call below required to build 'sys.argv' list */
220*c4aff060SBarry Smith     ierr = PetscGetArgs(&argc,&argv);CHKERRQ(ierr);
221*c4aff060SBarry Smith     if (argc && argv && argv[0]) PySys_SetArgv(argc,argv);
222*c4aff060SBarry Smith     /* register finalizer */
223*c4aff060SBarry Smith     if (!registered) {
224*c4aff060SBarry Smith       ierr = PetscRegisterFinalize(PetscPythonFinalize);CHKERRQ(ierr);
225*c4aff060SBarry Smith       registered = PETSC_TRUE;
226*c4aff060SBarry Smith     }
227*c4aff060SBarry Smith     PetscBeganPython = PETSC_TRUE;
228*c4aff060SBarry Smith   }
229*c4aff060SBarry Smith   /* import 'petsc4py.PETSc' module */
230*c4aff060SBarry Smith   module = PyImport_ImportModule("petsc4py.PETSc");
231*c4aff060SBarry Smith   if (module) {
232*c4aff060SBarry Smith     ierr = PetscInfo(0,"Python: successfully imported  module 'petsc4py.PETSc'\n"); CHKERRQ(ierr);
233*c4aff060SBarry Smith     Py_DecRef(module); module = 0;
234*c4aff060SBarry Smith   } else {
235*c4aff060SBarry Smith     SETERRQ(PETSC_ERR_PLIB,"Python: could not import module 'petsc4py.PETSc', perhaps your PYTHONPATH does not contain it\n");
236*c4aff060SBarry Smith   }
237*c4aff060SBarry Smith   PetscFunctionReturn(0);
238*c4aff060SBarry Smith }
239*c4aff060SBarry Smith 
240*c4aff060SBarry Smith /* ---------------------------------------------------------------- */
241