xref: /petsc/src/sys/dll/dl.c (revision 5673baf80db13bf90ebf3b7d404b13be20b2a2b2)
1e5c89e4eSSatish Balay #define PETSC_DLL
2e5c89e4eSSatish Balay /*
3e5c89e4eSSatish Balay       Routines for opening dynamic link libraries (DLLs), keeping a searchable
4e5c89e4eSSatish Balay    path of DLLs, obtaining remote DLLs via a URL and opening them locally.
5e5c89e4eSSatish Balay */
6e5c89e4eSSatish Balay 
7e5c89e4eSSatish Balay #include "petsc.h"
8e5c89e4eSSatish Balay #include "petscsys.h"
9e5c89e4eSSatish Balay #include "petscfix.h"
10e5c89e4eSSatish Balay 
11e5c89e4eSSatish Balay #if defined(PETSC_HAVE_PWD_H)
12e5c89e4eSSatish Balay #include <pwd.h>
13e5c89e4eSSatish Balay #endif
14e5c89e4eSSatish Balay #include <ctype.h>
15e5c89e4eSSatish Balay #include <sys/types.h>
16e5c89e4eSSatish Balay #include <sys/stat.h>
17e5c89e4eSSatish Balay #if defined(PETSC_HAVE_UNISTD_H)
18e5c89e4eSSatish Balay #include <unistd.h>
19e5c89e4eSSatish Balay #endif
20e5c89e4eSSatish Balay #if defined(PETSC_HAVE_STDLIB_H)
21e5c89e4eSSatish Balay #include <stdlib.h>
22e5c89e4eSSatish Balay #endif
23e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SYS_UTSNAME_H)
24e5c89e4eSSatish Balay #include <sys/utsname.h>
25e5c89e4eSSatish Balay #endif
26e5c89e4eSSatish Balay #include <fcntl.h>
27e5c89e4eSSatish Balay #include <time.h>
28e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
29e5c89e4eSSatish Balay #include <sys/systeminfo.h>
30e5c89e4eSSatish Balay #endif
31e5c89e4eSSatish Balay 
32e5c89e4eSSatish Balay /*
33e5c89e4eSSatish Balay    Contains the list of registered CCA components
34e5c89e4eSSatish Balay */
35e5c89e4eSSatish Balay PetscFList CCAList = 0;
36e5c89e4eSSatish Balay 
37e5c89e4eSSatish Balay 
38e5c89e4eSSatish Balay /* ------------------------------------------------------------------------------*/
39e5c89e4eSSatish Balay /*
40e5c89e4eSSatish Balay       Code to maintain a list of opened dynamic libraries and load symbols
41e5c89e4eSSatish Balay */
42e5bd5246SBarry Smith struct _n_PetscDLLibrary {
43e5bd5246SBarry Smith   PetscDLLibrary next;
44ebd79076SLisandro Dalcin   PetscDLHandle  handle;
45e5c89e4eSSatish Balay   char           libname[PETSC_MAX_PATH_LEN];
46e5c89e4eSSatish Balay };
47e5c89e4eSSatish Balay 
48e5c89e4eSSatish Balay #undef __FUNCT__
49e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryPrintPath"
50*5673baf8SLisandro Dalcin PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryPrintPath(PetscDLLibrary libs)
51e5c89e4eSSatish Balay {
52e5c89e4eSSatish Balay   PetscFunctionBegin;
53e5c89e4eSSatish Balay   while (libs) {
54e5c89e4eSSatish Balay     PetscErrorPrintf("  %s\n",libs->libname);
55e5c89e4eSSatish Balay     libs = libs->next;
56e5c89e4eSSatish Balay   }
57e5c89e4eSSatish Balay   PetscFunctionReturn(0);
58e5c89e4eSSatish Balay }
59e5c89e4eSSatish Balay 
60e5c89e4eSSatish Balay #undef __FUNCT__
61e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryRetrieve"
62e5c89e4eSSatish Balay /*@C
63e5c89e4eSSatish Balay    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
64e5c89e4eSSatish Balay      (if it is remote), indicates if it exits and its local name.
65e5c89e4eSSatish Balay 
66e5c89e4eSSatish Balay      Collective on MPI_Comm
67e5c89e4eSSatish Balay 
68e5c89e4eSSatish Balay    Input Parameters:
69e5c89e4eSSatish Balay +   comm - processors that are opening the library
70e5c89e4eSSatish Balay -   libname - name of the library, can be relative or absolute
71e5c89e4eSSatish Balay 
72e5c89e4eSSatish Balay    Output Parameter:
73e5c89e4eSSatish Balay .   handle - library handle
74e5c89e4eSSatish Balay 
75e5c89e4eSSatish Balay    Level: developer
76e5c89e4eSSatish Balay 
77e5c89e4eSSatish Balay    Notes:
78e5c89e4eSSatish Balay    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
79e5c89e4eSSatish Balay 
80e5c89e4eSSatish Balay    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
81e5c89e4eSSatish Balay    occuring in directoryname and filename will be replaced with appropriate values.
82e5c89e4eSSatish Balay @*/
83300a7f5bSBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscTruth *found)
84e5c89e4eSSatish Balay {
85e5c89e4eSSatish Balay   char           *par2,buff[10],*en,*gz;
86e5c89e4eSSatish Balay   PetscErrorCode ierr;
87e5c89e4eSSatish Balay   size_t         len1,len2,len;
88e5c89e4eSSatish Balay   PetscTruth     tflg,flg;
89e5c89e4eSSatish Balay 
90e5c89e4eSSatish Balay   PetscFunctionBegin;
91e5c89e4eSSatish Balay   /*
92a523d312SBarry Smith      make copy of library name and replace $PETSC_ARCH etc
93e5c89e4eSSatish Balay      so we can add to the end of it to look for something like .so.1.0 etc.
94e5c89e4eSSatish Balay   */
95e5c89e4eSSatish Balay   ierr = PetscStrlen(libname,&len);CHKERRQ(ierr);
96e5c89e4eSSatish Balay   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
97e5c89e4eSSatish Balay   ierr = PetscMalloc(len*sizeof(char),&par2);CHKERRQ(ierr);
98e5c89e4eSSatish Balay   ierr = PetscStrreplace(comm,libname,par2,len);CHKERRQ(ierr);
99e5c89e4eSSatish Balay 
100e5c89e4eSSatish Balay   /*
101e5c89e4eSSatish Balay      Remove any file: header
102e5c89e4eSSatish Balay   */
103e5c89e4eSSatish Balay   ierr = PetscStrncmp(par2,"file:",5,&tflg);CHKERRQ(ierr);
104e5c89e4eSSatish Balay   if (tflg) {
105e5c89e4eSSatish Balay     ierr = PetscStrcpy(par2,par2+5);CHKERRQ(ierr);
106e5c89e4eSSatish Balay   }
107e5c89e4eSSatish Balay 
108e5c89e4eSSatish Balay   /* strip out .a from it if user put it in by mistake */
109e5c89e4eSSatish Balay   ierr    = PetscStrlen(par2,&len);CHKERRQ(ierr);
110e5c89e4eSSatish Balay   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay   /* remove .gz if it ends library name */
113e5c89e4eSSatish Balay   ierr = PetscStrstr(par2,".gz",&gz);CHKERRQ(ierr);
114e5c89e4eSSatish Balay   if (gz) {
115e5c89e4eSSatish Balay     ierr = PetscStrlen(gz,&len);CHKERRQ(ierr);
116e5c89e4eSSatish Balay     if (len == 3) {
117e5c89e4eSSatish Balay       *gz = 0;
118e5c89e4eSSatish Balay     }
119e5c89e4eSSatish Balay   }
120e5c89e4eSSatish Balay 
121e5c89e4eSSatish Balay   /* see if library name does already not have suffix attached */
122e5c89e4eSSatish Balay   ierr = PetscStrcpy(buff,".");CHKERRQ(ierr);
123e5c89e4eSSatish Balay   ierr = PetscStrcat(buff,PETSC_SLSUFFIX);CHKERRQ(ierr);
124e5c89e4eSSatish Balay   ierr = PetscStrstr(par2,buff,&en);CHKERRQ(ierr);
125e5c89e4eSSatish Balay   if (en) {
126e5c89e4eSSatish Balay     ierr = PetscStrlen(en,&len1);CHKERRQ(ierr);
127e5c89e4eSSatish Balay     ierr = PetscStrlen(PETSC_SLSUFFIX,&len2);CHKERRQ(ierr);
128e5c89e4eSSatish Balay     flg = (PetscTruth) (len1 != 1 + len2);
129e5c89e4eSSatish Balay   } else {
130e5c89e4eSSatish Balay     flg = PETSC_TRUE;
131e5c89e4eSSatish Balay   }
132e5c89e4eSSatish Balay   if (flg) {
133e5c89e4eSSatish Balay     ierr = PetscStrcat(par2,".");CHKERRQ(ierr);
134e5c89e4eSSatish Balay     ierr = PetscStrcat(par2,PETSC_SLSUFFIX);CHKERRQ(ierr);
135e5c89e4eSSatish Balay   }
136e5c89e4eSSatish Balay 
137e5c89e4eSSatish Balay   /* put the .gz back on if it was there */
138e5c89e4eSSatish Balay   if (gz) {
139e5c89e4eSSatish Balay     ierr = PetscStrcat(par2,".gz");CHKERRQ(ierr);
140e5c89e4eSSatish Balay   }
141e5c89e4eSSatish Balay 
142e5c89e4eSSatish Balay   ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr);
143e5c89e4eSSatish Balay   ierr = PetscFree(par2);CHKERRQ(ierr);
144e5c89e4eSSatish Balay   PetscFunctionReturn(0);
145e5c89e4eSSatish Balay }
146e5c89e4eSSatish Balay 
147e5c89e4eSSatish Balay 
148e5c89e4eSSatish Balay #undef __FUNCT__
149e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryOpen"
150e5c89e4eSSatish Balay /*@C
151ebd79076SLisandro Dalcin    PetscDLLibraryOpen - Opens a PETSc dynamic link library
152e5c89e4eSSatish Balay 
153e5c89e4eSSatish Balay      Collective on MPI_Comm
154e5c89e4eSSatish Balay 
155e5c89e4eSSatish Balay    Input Parameters:
156e5c89e4eSSatish Balay +   comm - processors that are opening the library
157e5c89e4eSSatish Balay -   libname - name of the library, can be relative or absolute
158e5c89e4eSSatish Balay 
159e5c89e4eSSatish Balay    Output Parameter:
160e5c89e4eSSatish Balay .   handle - library handle
161e5c89e4eSSatish Balay 
162e5c89e4eSSatish Balay    Level: developer
163e5c89e4eSSatish Balay 
164e5c89e4eSSatish Balay    Notes:
165e5c89e4eSSatish Balay    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
166e5c89e4eSSatish Balay 
167e5c89e4eSSatish Balay    ${PETSC_ARCH} occuring in directoryname and filename
168e5c89e4eSSatish Balay    will be replaced with the appropriate value.
169e5c89e4eSSatish Balay @*/
170*5673baf8SLisandro Dalcin PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryOpen(MPI_Comm comm,const char libname[],PetscDLLibrary *entry)
171e5c89e4eSSatish Balay {
172e5c89e4eSSatish Balay   PetscErrorCode ierr;
173e5c89e4eSSatish Balay   char           *par2,registername[128],*ptr,*ptrp;
174e5c89e4eSSatish Balay   PetscTruth     foundlibrary;
175*5673baf8SLisandro Dalcin   PetscDLHandle  handle;
176e5c89e4eSSatish Balay   PetscErrorCode (*func)(const char*) = NULL;
177e5c89e4eSSatish Balay   size_t         len;
178e5c89e4eSSatish Balay 
179e5c89e4eSSatish Balay   PetscFunctionBegin;
180*5673baf8SLisandro Dalcin   PetscValidCharPointer(libname,2);
181*5673baf8SLisandro Dalcin   PetscValidPointer(entry,3);
182ebd79076SLisandro Dalcin 
183*5673baf8SLisandro Dalcin   *entry = PETSC_NULL;
184e5c89e4eSSatish Balay   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&par2);CHKERRQ(ierr);
185e5c89e4eSSatish Balay   ierr = PetscDLLibraryRetrieve(comm,libname,par2,PETSC_MAX_PATH_LEN,&foundlibrary);CHKERRQ(ierr);
186a523d312SBarry Smith   if (!foundlibrary) SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",libname);
187e5c89e4eSSatish Balay 
188e5c89e4eSSatish Balay   /* Eventually config/configure.py should determine if the system needs an executable dynamic library */
189e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
190e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
191e5c89e4eSSatish Balay   ierr  = PetscTestFile(par2,'x',&foundlibrary);CHKERRQ(ierr);
192a523d312SBarry Smith   if (!foundlibrary) SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",libname,par2);
193e5c89e4eSSatish Balay #endif
194e5c89e4eSSatish Balay 
195e5c89e4eSSatish Balay   /* look for libXXXXX.YYY and extract out the XXXXXX */
196e5c89e4eSSatish Balay   ierr = PetscStrrstr(libname,"lib",&ptr);CHKERRQ(ierr);
197e5c89e4eSSatish Balay   if (!ptr) SETERRQ1(PETSC_ERR_ARG_WRONG,"Dynamic library name must have lib prefix:%s",libname);
198e5c89e4eSSatish Balay   ierr = PetscStrchr(ptr+3,'.',&ptrp);CHKERRQ(ierr);
199e5c89e4eSSatish Balay   if (ptrp) {
20019bdad02SBarry Smith     len = ptrp - ptr - 3;
201e5c89e4eSSatish Balay   } else {
202e5c89e4eSSatish Balay     ierr = PetscStrlen(ptr+3,&len);CHKERRQ(ierr);
203e5c89e4eSSatish Balay   }
204*5673baf8SLisandro Dalcin   /* open the dynamic library */
205*5673baf8SLisandro Dalcin   ierr = PetscInfo1(0,"Opening %s\n",libname);CHKERRQ(ierr);
206*5673baf8SLisandro Dalcin   ierr = PetscDLOpen(par2,PETSC_DL_GLOBAL,&handle);CHKERRQ(ierr);
207*5673baf8SLisandro Dalcin   ierr = PetscFree(par2);CHKERRQ(ierr);
208*5673baf8SLisandro Dalcin   /* build name of symbol to look for based on libname */
209*5673baf8SLisandro Dalcin   ierr = PetscStrcpy(registername,"PetscDLLibraryRegister_");CHKERRQ(ierr);
210e5c89e4eSSatish Balay   ierr = PetscStrncat(registername,ptr+3,len);CHKERRQ(ierr);
211*5673baf8SLisandro Dalcin   ierr = PetscDLSym(handle,registername,(void**)&func);CHKERRQ(ierr);
212*5673baf8SLisandro Dalcin   if (!func) {
213e5c89e4eSSatish Balay     SETERRQ2(PETSC_ERR_FILE_UNEXPECTED,"Able to locate dynamic library %s, but cannot load symbol %s\n",libname,registername);
214e5c89e4eSSatish Balay   }
215*5673baf8SLisandro Dalcin   ierr = PetscInfo1(0,"Loading registered routines from %s\n",libname);CHKERRQ(ierr);
216*5673baf8SLisandro Dalcin   ierr = (*func)(libname);CHKERRQ(ierr);
217*5673baf8SLisandro Dalcin 
218*5673baf8SLisandro Dalcin   ierr = PetscNew(struct _n_PetscDLLibrary,entry);CHKERRQ(ierr);
219*5673baf8SLisandro Dalcin   ierr = PetscStrcpy((*entry)->libname,libname);CHKERRQ(ierr);
220*5673baf8SLisandro Dalcin   (*entry)->handle = handle;
221*5673baf8SLisandro Dalcin   (*entry)->next   = 0;
222*5673baf8SLisandro Dalcin 
223e5c89e4eSSatish Balay   PetscFunctionReturn(0);
224e5c89e4eSSatish Balay }
225e5c89e4eSSatish Balay 
226e5c89e4eSSatish Balay #undef __FUNCT__
227e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibrarySym"
228e5c89e4eSSatish Balay /*@C
229e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
230e5c89e4eSSatish Balay 
231e5c89e4eSSatish Balay    Collective on MPI_Comm
232e5c89e4eSSatish Balay 
233e5c89e4eSSatish Balay    Input Parameter:
234e5bd5246SBarry Smith +  comm - communicator that will open the library
235e5bd5246SBarry Smith .  inlist - list of already open libraries that may contain symbol (checks here before path)
236e5bd5246SBarry Smith .  path     - optional complete library name
237e5c89e4eSSatish Balay -  insymbol - name of symbol
238e5c89e4eSSatish Balay 
239e5c89e4eSSatish Balay    Output Parameter:
240e5c89e4eSSatish Balay .  value
241e5c89e4eSSatish Balay 
242e5c89e4eSSatish Balay    Level: developer
243e5c89e4eSSatish Balay 
244e5c89e4eSSatish Balay    Notes: Symbol can be of the form
245e5c89e4eSSatish Balay         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
246e5c89e4eSSatish Balay 
247e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
248e5c89e4eSSatish Balay 
249e5c89e4eSSatish Balay @*/
250e5bd5246SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *inlist,const char path[],const char insymbol[],void **value)
251e5c89e4eSSatish Balay {
252e5c89e4eSSatish Balay   char           *par1,*symbol;
253e5c89e4eSSatish Balay   PetscErrorCode ierr;
254e5c89e4eSSatish Balay   size_t         len;
255e5bd5246SBarry Smith   PetscDLLibrary nlist,prev,list;
256e5c89e4eSSatish Balay 
257e5c89e4eSSatish Balay   PetscFunctionBegin;
258*5673baf8SLisandro Dalcin   PetscValidPointer(inlist,2);
259*5673baf8SLisandro Dalcin   if (path) PetscValidCharPointer(path,3);
260*5673baf8SLisandro Dalcin   PetscValidCharPointer(insymbol,4);
261*5673baf8SLisandro Dalcin   PetscValidPointer(value,5);
262*5673baf8SLisandro Dalcin 
263*5673baf8SLisandro Dalcin   list   = *inlist;
264e5c89e4eSSatish Balay   *value = 0;
265e5c89e4eSSatish Balay 
266e5c89e4eSSatish Balay   /* make copy of symbol so we can edit it in place */
267e5c89e4eSSatish Balay   ierr = PetscStrlen(insymbol,&len);CHKERRQ(ierr);
268e5c89e4eSSatish Balay   ierr = PetscMalloc((len+1)*sizeof(char),&symbol);CHKERRQ(ierr);
269e5c89e4eSSatish Balay   ierr = PetscStrcpy(symbol,insymbol);CHKERRQ(ierr);
270e5c89e4eSSatish Balay 
271e5c89e4eSSatish Balay   /*
272e5c89e4eSSatish Balay       If symbol contains () then replace with a NULL, to support functionname()
273e5c89e4eSSatish Balay   */
274e5c89e4eSSatish Balay   ierr = PetscStrchr(symbol,'(',&par1);CHKERRQ(ierr);
275e5c89e4eSSatish Balay   if (par1) *par1 = 0;
276e5c89e4eSSatish Balay 
277e5c89e4eSSatish Balay 
278e5c89e4eSSatish Balay   /*
279e5c89e4eSSatish Balay        Function name does include library
280e5c89e4eSSatish Balay        -------------------------------------
281e5c89e4eSSatish Balay   */
282e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
283*5673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
284e5c89e4eSSatish Balay     nlist = list;
285e5c89e4eSSatish Balay     prev  = 0;
286e5c89e4eSSatish Balay     while (nlist) {
287e5c89e4eSSatish Balay       PetscTruth match;
288e5c89e4eSSatish Balay       ierr = PetscStrcmp(nlist->libname,path,&match);CHKERRQ(ierr);
289*5673baf8SLisandro Dalcin       if (match) goto done;
290e5c89e4eSSatish Balay       prev  = nlist;
291e5c89e4eSSatish Balay       nlist = nlist->next;
292e5c89e4eSSatish Balay     }
293e5c89e4eSSatish Balay 
294*5673baf8SLisandro Dalcin     ierr = PetscDLLibraryOpen(comm,path,&nlist);CHKERRQ(ierr);
295ae15b995SBarry Smith     ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",path);CHKERRQ(ierr);
296*5673baf8SLisandro Dalcin     if (prev) { prev->next = nlist; }
297*5673baf8SLisandro Dalcin     else      { *inlist    = nlist; }
298e5c89e4eSSatish Balay 
299e5c89e4eSSatish Balay   done:;
300*5673baf8SLisandro Dalcin     ierr = PetscDLSym(nlist->handle,symbol,value);CHKERRQ(ierr);
301e5c89e4eSSatish Balay     if (!*value) {
302e5c89e4eSSatish Balay       SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
303e5c89e4eSSatish Balay     }
304ae15b995SBarry Smith     ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);CHKERRQ(ierr);
305e5c89e4eSSatish Balay 
306e5c89e4eSSatish Balay   /*
307e5c89e4eSSatish Balay        Function name does not include library so search path
308e5c89e4eSSatish Balay        -----------------------------------------------------
309e5c89e4eSSatish Balay   */
310e5c89e4eSSatish Balay   } else {
311e5c89e4eSSatish Balay     while (list) {
312ebd79076SLisandro Dalcin       ierr = PetscDLSym(list->handle,symbol,value);CHKERRQ(ierr);
313e5c89e4eSSatish Balay       if (*value) {
314ae15b995SBarry Smith         ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",symbol,list->libname);CHKERRQ(ierr);
315e5c89e4eSSatish Balay         break;
316e5c89e4eSSatish Balay       }
317e5c89e4eSSatish Balay       list = list->next;
318e5c89e4eSSatish Balay     }
319e5c89e4eSSatish Balay     if (!*value) {
320ebd79076SLisandro Dalcin       ierr = PetscDLSym(PETSC_NULL,symbol,value);CHKERRQ(ierr);
321e5c89e4eSSatish Balay       if (*value) {
322ae15b995SBarry Smith         ierr = PetscInfo1(0,"Loading function %s from object code\n",symbol);CHKERRQ(ierr);
323e5c89e4eSSatish Balay       }
324e5c89e4eSSatish Balay     }
325e5c89e4eSSatish Balay   }
326e5c89e4eSSatish Balay 
327e5c89e4eSSatish Balay   ierr = PetscFree(symbol);CHKERRQ(ierr);
328e5c89e4eSSatish Balay   PetscFunctionReturn(0);
329e5c89e4eSSatish Balay }
330e5c89e4eSSatish Balay 
331e5c89e4eSSatish Balay #undef __FUNCT__
332e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryAppend"
333e5c89e4eSSatish Balay /*@C
334e5c89e4eSSatish Balay      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
335e5c89e4eSSatish Balay                 of the search path.
336e5c89e4eSSatish Balay 
337e5c89e4eSSatish Balay      Collective on MPI_Comm
338e5c89e4eSSatish Balay 
339e5c89e4eSSatish Balay      Input Parameters:
340e5c89e4eSSatish Balay +     comm - MPI communicator
341e5c89e4eSSatish Balay -     libname - name of the library
342e5c89e4eSSatish Balay 
343e5c89e4eSSatish Balay      Output Parameter:
344e5c89e4eSSatish Balay .     outlist - list of libraries
345e5c89e4eSSatish Balay 
346e5c89e4eSSatish Balay      Level: developer
347e5c89e4eSSatish Balay 
348e5c89e4eSSatish Balay      Notes: if library is already in path will not add it.
349e5c89e4eSSatish Balay @*/
350e5bd5246SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
351e5c89e4eSSatish Balay {
352e5bd5246SBarry Smith   PetscDLLibrary list,prev;
353e5c89e4eSSatish Balay   PetscErrorCode ierr;
354e5c89e4eSSatish Balay   size_t         len;
355e5c89e4eSSatish Balay   PetscTruth     match,dir;
356e5c89e4eSSatish Balay   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
3579c9d3cfdSBarry Smith   PetscToken     token;
358e5c89e4eSSatish Balay 
359e5c89e4eSSatish Balay   PetscFunctionBegin;
360e5c89e4eSSatish Balay 
361e5c89e4eSSatish Balay   /* is libname a directory? */
362e5c89e4eSSatish Balay   ierr = PetscTestDirectory(libname,'r',&dir);CHKERRQ(ierr);
363e5c89e4eSSatish Balay   if (dir) {
364ae15b995SBarry Smith     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);CHKERRQ(ierr);
365e5c89e4eSSatish Balay     ierr  = PetscStrcpy(program,libname);CHKERRQ(ierr);
366e5c89e4eSSatish Balay     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
367e5c89e4eSSatish Balay     if (program[len-1] == '/') {
368e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
369e5c89e4eSSatish Balay     } else {
370e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
371e5c89e4eSSatish Balay     }
372e5c89e4eSSatish Balay     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
373e5c89e4eSSatish Balay 
374e5c89e4eSSatish Balay     ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
375e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
376e5c89e4eSSatish Balay     found = buf;
377e5c89e4eSSatish Balay   } else {
378e5c89e4eSSatish Balay     found = (char*)libname;
379e5c89e4eSSatish Balay   }
380e5c89e4eSSatish Balay   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
381e5c89e4eSSatish Balay   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
382e5c89e4eSSatish Balay 
383e5c89e4eSSatish Balay   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
384e5c89e4eSSatish Balay   ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
385e5c89e4eSSatish Balay   ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
386e5c89e4eSSatish Balay   if (s) s[0] = 0;
387e5c89e4eSSatish Balay   while (libname1) {
388e5c89e4eSSatish Balay     /* see if library was already open then we are done */
389e5c89e4eSSatish Balay     list  = prev = *outlist;
390e5c89e4eSSatish Balay     match = PETSC_FALSE;
391e5c89e4eSSatish Balay     while (list) {
392e5c89e4eSSatish Balay       ierr = PetscStrcmp(list->libname,libname1,&match);CHKERRQ(ierr);
393e5c89e4eSSatish Balay       if (match) break;
394e5c89e4eSSatish Balay       prev = list;
395e5c89e4eSSatish Balay       list = list->next;
396e5c89e4eSSatish Balay     }
397e5c89e4eSSatish Balay     if (!match) {
398*5673baf8SLisandro Dalcin       /* open the library and add to end of list */
399*5673baf8SLisandro Dalcin        ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",libname1);CHKERRQ(ierr);
400*5673baf8SLisandro Dalcin       ierr = PetscDLLibraryOpen(comm,libname1,&list);CHKERRQ(ierr);
401e5c89e4eSSatish Balay       if (!*outlist) {
402e5c89e4eSSatish Balay 	*outlist   = list;
403e5c89e4eSSatish Balay       } else {
404e5c89e4eSSatish Balay 	prev->next = list;
405e5c89e4eSSatish Balay       }
406e5c89e4eSSatish Balay     }
407e5c89e4eSSatish Balay     ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
408e5c89e4eSSatish Balay     if (libname1) {
409e5c89e4eSSatish Balay       ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
410e5c89e4eSSatish Balay       if (s) s[0] = 0;
411e5c89e4eSSatish Balay     }
412e5c89e4eSSatish Balay   }
413e5c89e4eSSatish Balay   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
414e5c89e4eSSatish Balay   PetscFunctionReturn(0);
415e5c89e4eSSatish Balay }
416e5c89e4eSSatish Balay 
417e5c89e4eSSatish Balay #undef __FUNCT__
418e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryPrepend"
419e5c89e4eSSatish Balay /*@C
420e5c89e4eSSatish Balay      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
421e5c89e4eSSatish Balay                  the search path.
422e5c89e4eSSatish Balay 
423e5c89e4eSSatish Balay      Collective on MPI_Comm
424e5c89e4eSSatish Balay 
425e5c89e4eSSatish Balay      Input Parameters:
426e5c89e4eSSatish Balay +     comm - MPI communicator
427e5c89e4eSSatish Balay -     libname - name of the library
428e5c89e4eSSatish Balay 
429e5c89e4eSSatish Balay      Output Parameter:
430e5c89e4eSSatish Balay .     outlist - list of libraries
431e5c89e4eSSatish Balay 
432e5c89e4eSSatish Balay      Level: developer
433e5c89e4eSSatish Balay 
434e5c89e4eSSatish Balay      Notes: If library is already in path will remove old reference.
435e5c89e4eSSatish Balay 
436e5c89e4eSSatish Balay @*/
437e5bd5246SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
438e5c89e4eSSatish Balay {
439e5bd5246SBarry Smith   PetscDLLibrary list,prev;
440e5c89e4eSSatish Balay   PetscErrorCode ierr;
441e5c89e4eSSatish Balay   size_t         len;
442e5c89e4eSSatish Balay   PetscTruth     match,dir;
443e5c89e4eSSatish Balay   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
4445b096c79SMatthew Knepley   PetscToken     token;
445e5c89e4eSSatish Balay 
446e5c89e4eSSatish Balay   PetscFunctionBegin;
447e5c89e4eSSatish Balay 
448e5c89e4eSSatish Balay   /* is libname a directory? */
449e5c89e4eSSatish Balay   ierr = PetscTestDirectory(libname,'r',&dir);CHKERRQ(ierr);
450e5c89e4eSSatish Balay   if (dir) {
451ae15b995SBarry Smith     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);CHKERRQ(ierr);
452e5c89e4eSSatish Balay     ierr  = PetscStrcpy(program,libname);CHKERRQ(ierr);
453e5c89e4eSSatish Balay     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
454e5c89e4eSSatish Balay     if (program[len-1] == '/') {
455e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
456e5c89e4eSSatish Balay     } else {
457e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
458e5c89e4eSSatish Balay     }
459e5c89e4eSSatish Balay     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
460e5c89e4eSSatish Balay 
461e5c89e4eSSatish Balay     ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
462e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
463e5c89e4eSSatish Balay     found = buf;
464e5c89e4eSSatish Balay   } else {
465e5c89e4eSSatish Balay     found = (char*)libname;
466e5c89e4eSSatish Balay   }
467e5c89e4eSSatish Balay 
468e5c89e4eSSatish Balay   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
469e5c89e4eSSatish Balay   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
470e5c89e4eSSatish Balay 
471e5c89e4eSSatish Balay   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
472e5c89e4eSSatish Balay   ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
473e5c89e4eSSatish Balay   ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
474e5c89e4eSSatish Balay   if (s) s[0] = 0;
475e5c89e4eSSatish Balay   while (libname1) {
476e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
477e5c89e4eSSatish Balay     list  = *outlist;
478e5c89e4eSSatish Balay     prev  = 0;
479e5c89e4eSSatish Balay     match = PETSC_FALSE;
480e5c89e4eSSatish Balay     while (list) {
481e5c89e4eSSatish Balay       ierr = PetscStrcmp(list->libname,libname1,&match);CHKERRQ(ierr);
482e5c89e4eSSatish Balay       if (match) {
483e5c89e4eSSatish Balay 	if (prev) prev->next = list->next;
484e5c89e4eSSatish Balay 	list->next = *outlist;
485e5c89e4eSSatish Balay 	*outlist   = list;
486e5c89e4eSSatish Balay 	break;
487e5c89e4eSSatish Balay       }
488e5c89e4eSSatish Balay       prev = list;
489e5c89e4eSSatish Balay       list = list->next;
490e5c89e4eSSatish Balay     }
491e5c89e4eSSatish Balay     if (!match) {
492ebd79076SLisandro Dalcin       ierr = PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname1);CHKERRQ(ierr);
493*5673baf8SLisandro Dalcin       /* open the library and add to front of list */
494*5673baf8SLisandro Dalcin       ierr = PetscDLLibraryOpen(comm,libname1,&list);CHKERRQ(ierr);
495ebd79076SLisandro Dalcin       list->next = *outlist;
496e5c89e4eSSatish Balay       *outlist   = list;
497e5c89e4eSSatish Balay     }
498e5c89e4eSSatish Balay     ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
499e5c89e4eSSatish Balay     if (libname1) {
500e5c89e4eSSatish Balay       ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
501e5c89e4eSSatish Balay       if (s) s[0] = 0;
502e5c89e4eSSatish Balay     }
503e5c89e4eSSatish Balay   }
504e5c89e4eSSatish Balay   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
505e5c89e4eSSatish Balay   PetscFunctionReturn(0);
506e5c89e4eSSatish Balay }
507e5c89e4eSSatish Balay 
508e5c89e4eSSatish Balay #undef __FUNCT__
509e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryClose"
510e5c89e4eSSatish Balay /*@C
511e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
512e5c89e4eSSatish Balay 
513e5c89e4eSSatish Balay     Collective on PetscDLLibrary
514e5c89e4eSSatish Balay 
515e5c89e4eSSatish Balay     Input Parameter:
516e5c89e4eSSatish Balay .     next - library list
517e5c89e4eSSatish Balay 
518e5c89e4eSSatish Balay      Level: developer
519e5c89e4eSSatish Balay 
520e5c89e4eSSatish Balay @*/
521e5bd5246SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryClose(PetscDLLibrary next)
522e5c89e4eSSatish Balay {
523e5bd5246SBarry Smith   PetscDLLibrary prev;
524e5c89e4eSSatish Balay   PetscErrorCode ierr;
525e5c89e4eSSatish Balay 
526e5c89e4eSSatish Balay   PetscFunctionBegin;
527e5c89e4eSSatish Balay   while (next) {
528e5c89e4eSSatish Balay     prev = next;
529e5c89e4eSSatish Balay     next = next->next;
530ebd79076SLisandro Dalcin     /* close the dynamic library */
531ebd79076SLisandro Dalcin     ierr = PetscDLClose(&prev->handle);CHKERRQ(ierr);
532e5c89e4eSSatish Balay     /* free the space in the prev data-structure */
533e5c89e4eSSatish Balay     ierr = PetscFree(prev);CHKERRQ(ierr);
534e5c89e4eSSatish Balay   }
535e5c89e4eSSatish Balay   PetscFunctionReturn(0);
536e5c89e4eSSatish Balay }
537e5c89e4eSSatish Balay 
538e5c89e4eSSatish Balay #undef __FUNCT__
539e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryCCAAppend"
540e5c89e4eSSatish Balay /*@C
541e5c89e4eSSatish Balay      PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
542e5c89e4eSSatish Balay                 of the search path.
543e5c89e4eSSatish Balay 
544e5c89e4eSSatish Balay      Collective on MPI_Comm
545e5c89e4eSSatish Balay 
546e5c89e4eSSatish Balay      Input Parameters:
547e5c89e4eSSatish Balay +     comm - MPI communicator
548e5c89e4eSSatish Balay -     libname - name of directory to check
549e5c89e4eSSatish Balay 
550e5c89e4eSSatish Balay      Output Parameter:
551e5c89e4eSSatish Balay .     outlist - list of libraries
552e5c89e4eSSatish Balay 
553e5c89e4eSSatish Balay      Level: developer
554e5c89e4eSSatish Balay 
555e5c89e4eSSatish Balay      Notes: if library is already in path will not add it.
556e5c89e4eSSatish Balay @*/
557e5bd5246SBarry Smith PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char dirname[])
558e5c89e4eSSatish Balay {
559e5c89e4eSSatish Balay   PetscErrorCode ierr;
560e5c89e4eSSatish Balay   size_t         l;
561e5c89e4eSSatish Balay   PetscTruth     dir;
562e5c89e4eSSatish Balay   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
563e5c89e4eSSatish Balay   char           *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
564e5c89e4eSSatish Balay   FILE           *fp;
5655b096c79SMatthew Knepley   PetscToken     token1, token2;
566ed9cf6e9SBarry Smith   int            err;
567e5c89e4eSSatish Balay 
568e5c89e4eSSatish Balay   PetscFunctionBegin;
569e5c89e4eSSatish Balay   /* is dirname a directory? */
570e5c89e4eSSatish Balay   ierr = PetscTestDirectory(dirname,'r',&dir);CHKERRQ(ierr);
571e5c89e4eSSatish Balay   if (!dir) PetscFunctionReturn(0);
572e5c89e4eSSatish Balay 
573ae15b995SBarry Smith   ierr = PetscInfo1(0,"Checking directory %s for CCA components\n",dirname);CHKERRQ(ierr);
574e5c89e4eSSatish Balay   ierr  = PetscStrcpy(program,dirname);CHKERRQ(ierr);
575e5c89e4eSSatish Balay   ierr  = PetscStrcat(program,"/*.cca");CHKERRQ(ierr);
576e5c89e4eSSatish Balay 
577e5c89e4eSSatish Balay   ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
578e5c89e4eSSatish Balay   if (!dir) PetscFunctionReturn(0);
579e5c89e4eSSatish Balay 
580e5c89e4eSSatish Balay   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
581e5c89e4eSSatish Balay   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
582e5c89e4eSSatish Balay   ierr = PetscTokenCreate(buf,'\n',&token1);CHKERRQ(ierr);
583e5c89e4eSSatish Balay   ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
584e5c89e4eSSatish Balay   while (libname1) {
585e5c89e4eSSatish Balay     fp    = fopen(libname1,"r"); if (!fp) continue;
586e5c89e4eSSatish Balay     while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
587e5c89e4eSSatish Balay       if (found[0] == '!') continue;
588e5c89e4eSSatish Balay       ierr = PetscStrstr(found,suffix,&f2);CHKERRQ(ierr);
589e5c89e4eSSatish Balay       if (f2) { /* found library name */
590e5c89e4eSSatish Balay         if (found[0] == '/') {
591e5c89e4eSSatish Balay           lib = found;
592e5c89e4eSSatish Balay         } else {
593e5c89e4eSSatish Balay           ierr = PetscStrcpy(libname,dirname);CHKERRQ(ierr);
594e5c89e4eSSatish Balay           ierr = PetscStrlen(libname,&l);CHKERRQ(ierr);
595e5c89e4eSSatish Balay           if (libname[l-1] != '/') {ierr = PetscStrcat(libname,"/");CHKERRQ(ierr);}
596e5c89e4eSSatish Balay           ierr = PetscStrcat(libname,found);CHKERRQ(ierr);
597e5c89e4eSSatish Balay           lib  = libname;
598e5c89e4eSSatish Balay         }
599e5c89e4eSSatish Balay         ierr = PetscDLLibraryAppend(comm,outlist,lib);CHKERRQ(ierr);
600e5c89e4eSSatish Balay       } else {
601ae15b995SBarry Smith         ierr = PetscInfo2(0,"CCA Component function and name: %s from %s\n",found,libname1);CHKERRQ(ierr);
602e5c89e4eSSatish Balay         ierr = PetscTokenCreate(found,' ',&token2);CHKERRQ(ierr);
603e5c89e4eSSatish Balay         ierr = PetscTokenFind(token2,&func);CHKERRQ(ierr);
604e5c89e4eSSatish Balay         ierr = PetscTokenFind(token2,&funcname);CHKERRQ(ierr);
605e5c89e4eSSatish Balay         ierr = PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);CHKERRQ(ierr);
606e5c89e4eSSatish Balay         ierr = PetscTokenDestroy(token2);CHKERRQ(ierr);
607e5c89e4eSSatish Balay       }
608e5c89e4eSSatish Balay     }
609ed9cf6e9SBarry Smith     err = fclose(fp);
610ed9cf6e9SBarry Smith     if (err) SETERRQ(PETSC_ERR_SYS,"fclose() failed on file");
611e5c89e4eSSatish Balay     ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
612e5c89e4eSSatish Balay   }
613e5c89e4eSSatish Balay   ierr = PetscTokenDestroy(token1);CHKERRQ(ierr);
614e5c89e4eSSatish Balay   PetscFunctionReturn(0);
615e5c89e4eSSatish Balay }
616