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