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