xref: /petsc/src/sys/dll/dl.c (revision 340b11ee7902fa255abacfbb65399a1af48d609e)
1e5c89e4eSSatish Balay /*
2e5c89e4eSSatish Balay       Routines for opening dynamic link libraries (DLLs), keeping a searchable
3e5c89e4eSSatish Balay    path of DLLs, obtaining remote DLLs via a URL and opening them locally.
4e5c89e4eSSatish Balay */
5e5c89e4eSSatish Balay 
6c6db04a5SJed Brown #include <petscsys.h>
7c6db04a5SJed Brown #include <../src/sys/dll/dlimpl.h>
8e5c89e4eSSatish Balay 
9e5c89e4eSSatish Balay /* ------------------------------------------------------------------------------*/
10e5c89e4eSSatish Balay /*
11e5c89e4eSSatish Balay       Code to maintain a list of opened dynamic libraries and load symbols
12e5c89e4eSSatish Balay */
13e5bd5246SBarry Smith struct _n_PetscDLLibrary {
14e5bd5246SBarry Smith   PetscDLLibrary next;
15ebd79076SLisandro Dalcin   PetscDLHandle  handle;
16e5c89e4eSSatish Balay   char           libname[PETSC_MAX_PATH_LEN];
17e5c89e4eSSatish Balay };
18e5c89e4eSSatish Balay 
19e5c89e4eSSatish Balay #undef __FUNCT__
20e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryPrintPath"
217087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryPrintPath(PetscDLLibrary libs)
22e5c89e4eSSatish Balay {
23e5c89e4eSSatish Balay   PetscFunctionBegin;
24e5c89e4eSSatish Balay   while (libs) {
25e5c89e4eSSatish Balay     PetscErrorPrintf("  %s\n",libs->libname);
26e5c89e4eSSatish Balay     libs = libs->next;
27e5c89e4eSSatish Balay   }
28e5c89e4eSSatish Balay   PetscFunctionReturn(0);
29e5c89e4eSSatish Balay }
30e5c89e4eSSatish Balay 
31e5c89e4eSSatish Balay #undef __FUNCT__
32e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryRetrieve"
33e5c89e4eSSatish Balay /*@C
34e5c89e4eSSatish Balay    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
35e5c89e4eSSatish Balay      (if it is remote), indicates if it exits and its local name.
36e5c89e4eSSatish Balay 
37e5c89e4eSSatish Balay      Collective on MPI_Comm
38e5c89e4eSSatish Balay 
39e5c89e4eSSatish Balay    Input Parameters:
40e5c89e4eSSatish Balay +   comm - processors that are opening the library
41e5c89e4eSSatish Balay -   libname - name of the library, can be relative or absolute
42e5c89e4eSSatish Balay 
43e5c89e4eSSatish Balay    Output Parameter:
44e5c89e4eSSatish Balay .   handle - library handle
45e5c89e4eSSatish Balay 
46e5c89e4eSSatish Balay    Level: developer
47e5c89e4eSSatish Balay 
48e5c89e4eSSatish Balay    Notes:
49e5c89e4eSSatish Balay    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
50e5c89e4eSSatish Balay 
51e5c89e4eSSatish Balay    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
52e5c89e4eSSatish Balay    occuring in directoryname and filename will be replaced with appropriate values.
53e5c89e4eSSatish Balay @*/
547087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool  *found)
55e5c89e4eSSatish Balay {
56d46cf212SLisandro Dalcin   char           *buf,*par2,suffix[16],*gz,*so;
57d46cf212SLisandro Dalcin   size_t         len;
58e5c89e4eSSatish Balay   PetscErrorCode ierr;
59e5c89e4eSSatish Balay 
60e5c89e4eSSatish Balay   PetscFunctionBegin;
61e5c89e4eSSatish Balay   /*
62a523d312SBarry Smith      make copy of library name and replace $PETSC_ARCH etc
63e5c89e4eSSatish Balay      so we can add to the end of it to look for something like .so.1.0 etc.
64e5c89e4eSSatish Balay   */
65e5c89e4eSSatish Balay   ierr = PetscStrlen(libname,&len);CHKERRQ(ierr);
66e5c89e4eSSatish Balay   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
67d46cf212SLisandro Dalcin   ierr = PetscMalloc(len*sizeof(char),&buf);CHKERRQ(ierr);
68d46cf212SLisandro Dalcin   par2 = buf;
69e5c89e4eSSatish Balay   ierr = PetscStrreplace(comm,libname,par2,len);CHKERRQ(ierr);
70e5c89e4eSSatish Balay 
71d46cf212SLisandro Dalcin   /* temporarily remove .gz if it ends library name */
72d46cf212SLisandro Dalcin   ierr = PetscStrrstr(par2,".gz",&gz);CHKERRQ(ierr);
73e5c89e4eSSatish Balay   if (gz) {
74e5c89e4eSSatish Balay     ierr = PetscStrlen(gz,&len);CHKERRQ(ierr);
75d46cf212SLisandro Dalcin     if (len != 3) gz  = 0; /* do not end (exactly) with .gz */
76d46cf212SLisandro Dalcin     else          *gz = 0; /* ends with .gz, so remove it   */
77e5c89e4eSSatish Balay   }
783fa76a5bSLisandro Dalcin   /* strip out .a from it if user put it in by mistake */
793fa76a5bSLisandro Dalcin   ierr = PetscStrlen(par2,&len);CHKERRQ(ierr);
803fa76a5bSLisandro Dalcin   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
813fa76a5bSLisandro Dalcin 
82e5c89e4eSSatish Balay 
83e5c89e4eSSatish Balay   /* see if library name does already not have suffix attached */
84b3bb0f5eSLisandro Dalcin   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
85b3bb0f5eSLisandro Dalcin   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
86b3bb0f5eSLisandro Dalcin   ierr = PetscStrrstr(par2,suffix,&so);CHKERRQ(ierr);
87d46cf212SLisandro Dalcin   /* and attach the suffix if it is not there */
88d46cf212SLisandro Dalcin   if (!so) { ierr = PetscStrcat(par2,suffix);CHKERRQ(ierr); }
89e5c89e4eSSatish Balay 
90d46cf212SLisandro Dalcin   /* restore the .gz suffix if it was there */
91d46cf212SLisandro Dalcin   if (gz) { ierr = PetscStrcat(par2,".gz");CHKERRQ(ierr); }
92d46cf212SLisandro Dalcin 
93d46cf212SLisandro Dalcin   /* and finally retrieve the file */
94e5c89e4eSSatish Balay   ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr);
95d46cf212SLisandro Dalcin 
96d46cf212SLisandro Dalcin   ierr = PetscFree(buf);CHKERRQ(ierr);
97e5c89e4eSSatish Balay   PetscFunctionReturn(0);
98e5c89e4eSSatish Balay }
99e5c89e4eSSatish Balay 
100e5c89e4eSSatish Balay 
101e5c89e4eSSatish Balay #undef __FUNCT__
102e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryOpen"
103e5c89e4eSSatish Balay /*@C
104ebd79076SLisandro Dalcin    PetscDLLibraryOpen - Opens a PETSc dynamic link library
105e5c89e4eSSatish Balay 
106e5c89e4eSSatish Balay      Collective on MPI_Comm
107e5c89e4eSSatish Balay 
108e5c89e4eSSatish Balay    Input Parameters:
109e5c89e4eSSatish Balay +   comm - processors that are opening the library
1100f31fb7fSLisandro Dalcin -   path - name of the library, can be relative or absolute
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay    Output Parameter:
1130f31fb7fSLisandro Dalcin .   entry - a PETSc dynamic link library entry
114e5c89e4eSSatish Balay 
115e5c89e4eSSatish Balay    Level: developer
116e5c89e4eSSatish Balay 
117e5c89e4eSSatish Balay    Notes:
118bb84e0fdSBarry Smith    [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
119bb84e0fdSBarry Smith 
120bb84e0fdSBarry Smith    If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
121bb84e0fdSBarry Smith    when the library is opened.
122e5c89e4eSSatish Balay 
123e5c89e4eSSatish Balay    ${PETSC_ARCH} occuring in directoryname and filename
124e5c89e4eSSatish Balay    will be replaced with the appropriate value.
125bb84e0fdSBarry Smith 
126bb84e0fdSBarry Smith .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
127e5c89e4eSSatish Balay @*/
1287087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
129e5c89e4eSSatish Balay {
130e5c89e4eSSatish Balay   PetscErrorCode ierr;
131ace3abfcSBarry Smith   PetscBool      foundlibrary,match;
132b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
133b3bb0f5eSLisandro Dalcin   char           *basename,registername[128];
1345673baf8SLisandro Dalcin   PetscDLHandle  handle;
135e5c89e4eSSatish Balay   PetscErrorCode (*func)(const char*) = NULL;
136e5c89e4eSSatish Balay   size_t         len;
137e5c89e4eSSatish Balay 
138e5c89e4eSSatish Balay   PetscFunctionBegin;
13982a51d08SSatish Balay   PetscValidCharPointer(path,2);
1405673baf8SLisandro Dalcin   PetscValidPointer(entry,3);
141ebd79076SLisandro Dalcin 
1425673baf8SLisandro Dalcin   *entry = PETSC_NULL;
143e5c89e4eSSatish Balay 
144b3bb0f5eSLisandro Dalcin   /* retrieve the library */
145b3bb0f5eSLisandro Dalcin   ierr = PetscInfo1(0,"Retrieving %s\n",path);CHKERRQ(ierr);
146b3bb0f5eSLisandro Dalcin   ierr = PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);CHKERRQ(ierr);
147e32f2f54SBarry Smith   if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",path);
148e2e64c6bSBarry Smith   /* Eventually ./configure should determine if the system needs an executable dynamic library */
149e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
150e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
151e5c89e4eSSatish Balay   ierr  = PetscTestFile(par2,'x',&foundlibrary);CHKERRQ(ierr);
152e32f2f54SBarry Smith   if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",path,par2);
153e5c89e4eSSatish Balay #endif
154e5c89e4eSSatish Balay 
1553fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
156b3bb0f5eSLisandro Dalcin   ierr = PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
157b3bb0f5eSLisandro Dalcin   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
158b3bb0f5eSLisandro Dalcin   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
1593fa76a5bSLisandro Dalcin   /* remove wrong suffixes from libname */
1603fa76a5bSLisandro Dalcin   ierr = PetscStrrstr(libname,".gz",&s);CHKERRQ(ierr);
1613fa76a5bSLisandro Dalcin   if (s && s[3] == 0) s[0] = 0;
1623fa76a5bSLisandro Dalcin   ierr = PetscStrrstr(libname,".a",&s);CHKERRQ(ierr);
1633fa76a5bSLisandro Dalcin   if (s && s[2] == 0) s[0] = 0;
1643fa76a5bSLisandro Dalcin   /* remove shared suffix from libname */
165b3bb0f5eSLisandro Dalcin   ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr);
166b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
167b3bb0f5eSLisandro Dalcin 
1685673baf8SLisandro Dalcin   /* open the dynamic library */
169b3bb0f5eSLisandro Dalcin   ierr = PetscInfo1(0,"Opening dynamic library %s\n",libname);CHKERRQ(ierr);
170b3bb0f5eSLisandro Dalcin   ierr = PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);CHKERRQ(ierr);
171b3bb0f5eSLisandro Dalcin 
172b3bb0f5eSLisandro Dalcin   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
173b3bb0f5eSLisandro Dalcin   ierr = PetscStrrchr(libname,'/',&basename);CHKERRQ(ierr); /* XXX Windows ??? */
174b3bb0f5eSLisandro Dalcin   if (!basename) basename = libname;
175b3bb0f5eSLisandro Dalcin   ierr = PetscStrncmp(basename,"lib",3,&match);CHKERRQ(ierr);
176b3bb0f5eSLisandro Dalcin   if (match) {
177b3bb0f5eSLisandro Dalcin     basename = basename + 3;
178b3bb0f5eSLisandro Dalcin   } else {
179bb84e0fdSBarry Smith     ierr = PetscInfo1(0,"Dynamic library %s does not have lib prefix\n",libname);CHKERRQ(ierr);
180e5c89e4eSSatish Balay   }
181b3bb0f5eSLisandro Dalcin   ierr = PetscStrlen(basename,&len);CHKERRQ(ierr);
182b3bb0f5eSLisandro Dalcin   ierr = PetscStrcpy(registername,"PetscDLLibraryRegister_");CHKERRQ(ierr);
183b3bb0f5eSLisandro Dalcin   ierr = PetscStrncat(registername,basename,len);CHKERRQ(ierr);
184b3bb0f5eSLisandro Dalcin   ierr = PetscDLSym(handle,registername,(void**)&func);CHKERRQ(ierr);
185b3bb0f5eSLisandro Dalcin   if (func) {
1865673baf8SLisandro Dalcin     ierr = PetscInfo1(0,"Loading registered routines from %s\n",libname);CHKERRQ(ierr);
1875673baf8SLisandro Dalcin     ierr = (*func)(libname);CHKERRQ(ierr);
188b3bb0f5eSLisandro Dalcin   } else {
189bb84e0fdSBarry Smith     ierr = PetscInfo2(0,"Dynamic library %s does not have symbol %s\n",libname,registername);CHKERRQ(ierr);
190b3bb0f5eSLisandro Dalcin   }
1915673baf8SLisandro Dalcin 
1925673baf8SLisandro Dalcin   ierr = PetscNew(struct _n_PetscDLLibrary,entry);CHKERRQ(ierr);
1935673baf8SLisandro Dalcin   (*entry)->next   = 0;
194b3bb0f5eSLisandro Dalcin   (*entry)->handle = handle;
195b3bb0f5eSLisandro Dalcin   ierr = PetscStrcpy((*entry)->libname,libname);CHKERRQ(ierr);
1965673baf8SLisandro Dalcin 
197e5c89e4eSSatish Balay   PetscFunctionReturn(0);
198e5c89e4eSSatish Balay }
199e5c89e4eSSatish Balay 
200e5c89e4eSSatish Balay #undef __FUNCT__
201e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibrarySym"
202e5c89e4eSSatish Balay /*@C
203e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
204e5c89e4eSSatish Balay 
205e5c89e4eSSatish Balay    Collective on MPI_Comm
206e5c89e4eSSatish Balay 
207e5c89e4eSSatish Balay    Input Parameter:
208e5bd5246SBarry Smith +  comm - communicator that will open the library
209*340b11eeSBarry Smith .  outlist - list of already open libraries that may contain symbol (can be PETSC_NULL and only the executable is searched for the function)
21030a1dd1fSBarry Smith .  path     - optional complete library name (if provided checks here before checking outlist)
211e5c89e4eSSatish Balay -  insymbol - name of symbol
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay    Output Parameter:
21430a1dd1fSBarry Smith .  value - if symbol not found then this value is set to PETSC_NULL
215e5c89e4eSSatish Balay 
216e5c89e4eSSatish Balay    Level: developer
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay    Notes: Symbol can be of the form
219e5c89e4eSSatish Balay         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
220e5c89e4eSSatish Balay 
221e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
222e5c89e4eSSatish Balay 
223e5c89e4eSSatish Balay @*/
2247087cfbeSBarry Smith PetscErrorCode  PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
225e5c89e4eSSatish Balay {
226b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
227e5c89e4eSSatish Balay   size_t         len;
228*340b11eeSBarry Smith   PetscDLLibrary nlist,prev,list = PETSC_NULL;
229b3bb0f5eSLisandro Dalcin   PetscErrorCode ierr;
230e5c89e4eSSatish Balay 
231e5c89e4eSSatish Balay   PetscFunctionBegin;
232*340b11eeSBarry Smith   if (outlist) PetscValidPointer(outlist,2);
2335673baf8SLisandro Dalcin   if (path) PetscValidCharPointer(path,3);
2345673baf8SLisandro Dalcin   PetscValidCharPointer(insymbol,4);
2355673baf8SLisandro Dalcin   PetscValidPointer(value,5);
2365673baf8SLisandro Dalcin 
237*340b11eeSBarry Smith   if (outlist) list   = *outlist;
238e5c89e4eSSatish Balay   *value = 0;
239e5c89e4eSSatish Balay 
240e5c89e4eSSatish Balay   /* make copy of symbol so we can edit it in place */
241e5c89e4eSSatish Balay   ierr = PetscStrlen(insymbol,&len);CHKERRQ(ierr);
242e5c89e4eSSatish Balay   ierr = PetscMalloc((len+1)*sizeof(char),&symbol);CHKERRQ(ierr);
243e5c89e4eSSatish Balay   ierr = PetscStrcpy(symbol,insymbol);CHKERRQ(ierr);
244b3bb0f5eSLisandro Dalcin   /* If symbol contains () then replace with a NULL, to support functionname() */
245b3bb0f5eSLisandro Dalcin   ierr = PetscStrchr(symbol,'(',&s);CHKERRQ(ierr);
246b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
247e5c89e4eSSatish Balay 
248e5c89e4eSSatish Balay   /*
249e5c89e4eSSatish Balay        Function name does include library
250e5c89e4eSSatish Balay        -------------------------------------
251e5c89e4eSSatish Balay   */
252e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
253b3bb0f5eSLisandro Dalcin     /* copy path and remove suffix from libname */
254b3bb0f5eSLisandro Dalcin     ierr = PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
255b3bb0f5eSLisandro Dalcin     ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
256b3bb0f5eSLisandro Dalcin     ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
257b3bb0f5eSLisandro Dalcin     ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr);
258b3bb0f5eSLisandro Dalcin     if (s) s[0] = 0;
2595673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
260e5c89e4eSSatish Balay     prev  = 0;
261b3bb0f5eSLisandro Dalcin     nlist = list;
262e5c89e4eSSatish Balay     while (nlist) {
263ace3abfcSBarry Smith       PetscBool  match;
264b3bb0f5eSLisandro Dalcin       ierr = PetscStrcmp(nlist->libname,libname,&match);CHKERRQ(ierr);
2655673baf8SLisandro Dalcin       if (match) goto done;
266e5c89e4eSSatish Balay       prev  = nlist;
267e5c89e4eSSatish Balay       nlist = nlist->next;
268e5c89e4eSSatish Balay     }
269b3bb0f5eSLisandro Dalcin     /* open the library and append it to path */
2705673baf8SLisandro Dalcin     ierr = PetscDLLibraryOpen(comm,path,&nlist);CHKERRQ(ierr);
271ae15b995SBarry Smith     ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",path);CHKERRQ(ierr);
2725673baf8SLisandro Dalcin     if (prev) { prev->next = nlist; }
273b3bb0f5eSLisandro Dalcin     else      { *outlist   = nlist; }
274e5c89e4eSSatish Balay 
275e5c89e4eSSatish Balay   done:;
2765673baf8SLisandro Dalcin     ierr = PetscDLSym(nlist->handle,symbol,value);CHKERRQ(ierr);
27730a1dd1fSBarry Smith     if (*value) {
278ae15b995SBarry Smith       ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);CHKERRQ(ierr);
27930a1dd1fSBarry Smith     }
280e5c89e4eSSatish Balay 
281e5c89e4eSSatish Balay   /*
282e5c89e4eSSatish Balay        Function name does not include library so search path
283e5c89e4eSSatish Balay        -----------------------------------------------------
284e5c89e4eSSatish Balay   */
285e5c89e4eSSatish Balay   } else {
286e5c89e4eSSatish Balay     while (list) {
287ebd79076SLisandro Dalcin       ierr = PetscDLSym(list->handle,symbol,value);CHKERRQ(ierr);
288e5c89e4eSSatish Balay       if (*value) {
289b3bb0f5eSLisandro Dalcin         ierr = PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);CHKERRQ(ierr);
290e5c89e4eSSatish Balay         break;
291e5c89e4eSSatish Balay       }
292e5c89e4eSSatish Balay       list = list->next;
293e5c89e4eSSatish Balay     }
294e5c89e4eSSatish Balay     if (!*value) {
295ebd79076SLisandro Dalcin       ierr = PetscDLSym(PETSC_NULL,symbol,value);CHKERRQ(ierr);
296e5c89e4eSSatish Balay       if (*value) {
297b3bb0f5eSLisandro Dalcin         ierr = PetscInfo1(0,"Loading symbol %s from object code\n",symbol);CHKERRQ(ierr);
298e5c89e4eSSatish Balay       }
299e5c89e4eSSatish Balay     }
300e5c89e4eSSatish Balay   }
301e5c89e4eSSatish Balay 
302e5c89e4eSSatish Balay   ierr = PetscFree(symbol);CHKERRQ(ierr);
303e5c89e4eSSatish Balay   PetscFunctionReturn(0);
304e5c89e4eSSatish Balay }
305e5c89e4eSSatish Balay 
306e5c89e4eSSatish Balay #undef __FUNCT__
307e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryAppend"
308e5c89e4eSSatish Balay /*@C
309e5c89e4eSSatish Balay      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
310e5c89e4eSSatish Balay                 of the search path.
311e5c89e4eSSatish Balay 
312e5c89e4eSSatish Balay      Collective on MPI_Comm
313e5c89e4eSSatish Balay 
314e5c89e4eSSatish Balay      Input Parameters:
315e5c89e4eSSatish Balay +     comm - MPI communicator
3160f31fb7fSLisandro Dalcin -     path - name of the library
317e5c89e4eSSatish Balay 
318e5c89e4eSSatish Balay      Output Parameter:
319e5c89e4eSSatish Balay .     outlist - list of libraries
320e5c89e4eSSatish Balay 
321e5c89e4eSSatish Balay      Level: developer
322e5c89e4eSSatish Balay 
323e5c89e4eSSatish Balay      Notes: if library is already in path will not add it.
324bb84e0fdSBarry Smith 
325bb84e0fdSBarry Smith   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
326bb84e0fdSBarry Smith       when the library is opened.
327bb84e0fdSBarry Smith 
328bb84e0fdSBarry Smith .seealso: PetscDLLibraryOpen()
329e5c89e4eSSatish Balay @*/
3307087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
331e5c89e4eSSatish Balay {
332e5bd5246SBarry Smith   PetscDLLibrary list,prev;
333e5c89e4eSSatish Balay   PetscErrorCode ierr;
334e5c89e4eSSatish Balay   size_t         len;
335ace3abfcSBarry Smith   PetscBool      match,dir;
336b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
337b3bb0f5eSLisandro Dalcin   char           *libname,suffix[16],*s;
3389c9d3cfdSBarry Smith   PetscToken     token;
339e5c89e4eSSatish Balay 
340e5c89e4eSSatish Balay   PetscFunctionBegin;
341b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist,2);
342e5c89e4eSSatish Balay 
343b3bb0f5eSLisandro Dalcin   /* is path a directory? */
344b3bb0f5eSLisandro Dalcin   ierr = PetscTestDirectory(path,'r',&dir);CHKERRQ(ierr);
345e5c89e4eSSatish Balay   if (dir) {
346b3bb0f5eSLisandro Dalcin     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);CHKERRQ(ierr);
347b3bb0f5eSLisandro Dalcin     ierr  = PetscStrcpy(program,path);CHKERRQ(ierr);
348e5c89e4eSSatish Balay     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
349e5c89e4eSSatish Balay     if (program[len-1] == '/') {
350e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
351e5c89e4eSSatish Balay     } else {
352e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
353e5c89e4eSSatish Balay     }
354e5c89e4eSSatish Balay     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
355e5c89e4eSSatish Balay 
356b3bb0f5eSLisandro Dalcin     ierr = PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
357e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
358e5c89e4eSSatish Balay   } else {
359b3bb0f5eSLisandro Dalcin     ierr = PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
360e5c89e4eSSatish Balay   }
361e5c89e4eSSatish Balay   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
362e5c89e4eSSatish Balay   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
363e5c89e4eSSatish Balay 
364e5c89e4eSSatish Balay   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
365b3bb0f5eSLisandro Dalcin   ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
366b3bb0f5eSLisandro Dalcin   while (libname) {
367b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
368b3bb0f5eSLisandro Dalcin     ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr);
369e5c89e4eSSatish Balay     if (s) s[0] = 0;
370e5c89e4eSSatish Balay     /* see if library was already open then we are done */
371e5c89e4eSSatish Balay     list  = prev = *outlist;
372e5c89e4eSSatish Balay     match = PETSC_FALSE;
373e5c89e4eSSatish Balay     while (list) {
374b3bb0f5eSLisandro Dalcin       ierr = PetscStrcmp(list->libname,libname,&match);CHKERRQ(ierr);
375e5c89e4eSSatish Balay       if (match) break;
376e5c89e4eSSatish Balay       prev = list;
377e5c89e4eSSatish Balay       list = list->next;
378e5c89e4eSSatish Balay     }
379b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
380b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
381e5c89e4eSSatish Balay     if (!match) {
3825673baf8SLisandro Dalcin       /* open the library and add to end of list */
383b3bb0f5eSLisandro Dalcin       ierr = PetscDLLibraryOpen(comm,libname,&list);CHKERRQ(ierr);
384b3bb0f5eSLisandro Dalcin       ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);CHKERRQ(ierr);
385e5c89e4eSSatish Balay       if (!*outlist) {
386e5c89e4eSSatish Balay 	*outlist   = list;
387e5c89e4eSSatish Balay       } else {
388e5c89e4eSSatish Balay 	prev->next = list;
389e5c89e4eSSatish Balay       }
390e5c89e4eSSatish Balay     }
391b3bb0f5eSLisandro Dalcin     ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
392e5c89e4eSSatish Balay   }
393e5c89e4eSSatish Balay   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
394e5c89e4eSSatish Balay   PetscFunctionReturn(0);
395e5c89e4eSSatish Balay }
396e5c89e4eSSatish Balay 
397e5c89e4eSSatish Balay #undef __FUNCT__
398e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryPrepend"
399e5c89e4eSSatish Balay /*@C
400e5c89e4eSSatish Balay      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
401e5c89e4eSSatish Balay                  the search path.
402e5c89e4eSSatish Balay 
403e5c89e4eSSatish Balay      Collective on MPI_Comm
404e5c89e4eSSatish Balay 
405e5c89e4eSSatish Balay      Input Parameters:
406e5c89e4eSSatish Balay +     comm - MPI communicator
4070f31fb7fSLisandro Dalcin -     path - name of the library
408e5c89e4eSSatish Balay 
409e5c89e4eSSatish Balay      Output Parameter:
410e5c89e4eSSatish Balay .     outlist - list of libraries
411e5c89e4eSSatish Balay 
412e5c89e4eSSatish Balay      Level: developer
413e5c89e4eSSatish Balay 
414e5c89e4eSSatish Balay      Notes: If library is already in path will remove old reference.
415e5c89e4eSSatish Balay 
416e5c89e4eSSatish Balay @*/
4177087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
418e5c89e4eSSatish Balay {
419e5bd5246SBarry Smith   PetscDLLibrary list,prev;
420e5c89e4eSSatish Balay   PetscErrorCode ierr;
421e5c89e4eSSatish Balay   size_t         len;
422ace3abfcSBarry Smith   PetscBool      match,dir;
423b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
424b3bb0f5eSLisandro Dalcin   char           *libname,suffix[16],*s;
4255b096c79SMatthew Knepley   PetscToken     token;
426e5c89e4eSSatish Balay 
427e5c89e4eSSatish Balay   PetscFunctionBegin;
428b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist,2);
429e5c89e4eSSatish Balay 
430b3bb0f5eSLisandro Dalcin   /* is path a directory? */
431b3bb0f5eSLisandro Dalcin   ierr = PetscTestDirectory(path,'r',&dir);CHKERRQ(ierr);
432e5c89e4eSSatish Balay   if (dir) {
433b3bb0f5eSLisandro Dalcin     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);CHKERRQ(ierr);
434b3bb0f5eSLisandro Dalcin     ierr  = PetscStrcpy(program,path);CHKERRQ(ierr);
435e5c89e4eSSatish Balay     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
436e5c89e4eSSatish Balay     if (program[len-1] == '/') {
437e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
438e5c89e4eSSatish Balay     } else {
439e5c89e4eSSatish Balay       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
440e5c89e4eSSatish Balay     }
441e5c89e4eSSatish Balay     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
442e5c89e4eSSatish Balay 
443b3bb0f5eSLisandro Dalcin     ierr = PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
444e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
445e5c89e4eSSatish Balay   } else {
446b3bb0f5eSLisandro Dalcin     ierr = PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
447e5c89e4eSSatish Balay   }
448e5c89e4eSSatish Balay 
449e5c89e4eSSatish Balay   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
450e5c89e4eSSatish Balay   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
451e5c89e4eSSatish Balay 
452e5c89e4eSSatish Balay   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
453b3bb0f5eSLisandro Dalcin   ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
454b3bb0f5eSLisandro Dalcin   while (libname) {
455b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
456b3bb0f5eSLisandro Dalcin     ierr = PetscStrstr(libname,suffix,&s);CHKERRQ(ierr);
457e5c89e4eSSatish Balay     if (s) s[0] = 0;
458e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
459e5c89e4eSSatish Balay     prev  = 0;
460b3bb0f5eSLisandro Dalcin     list  = *outlist;
461e5c89e4eSSatish Balay     match = PETSC_FALSE;
462e5c89e4eSSatish Balay     while (list) {
463b3bb0f5eSLisandro Dalcin       ierr = PetscStrcmp(list->libname,libname,&match);CHKERRQ(ierr);
464e5c89e4eSSatish Balay       if (match) {
465b3bb0f5eSLisandro Dalcin 	ierr = PetscInfo1(0,"Moving %s to begin of dynamic library search path\n",libname);CHKERRQ(ierr);
466e5c89e4eSSatish Balay 	if (prev) prev->next = list->next;
467b3bb0f5eSLisandro Dalcin 	if (prev) list->next = *outlist;
468e5c89e4eSSatish Balay 	*outlist = list;
469e5c89e4eSSatish Balay 	break;
470e5c89e4eSSatish Balay       }
471e5c89e4eSSatish Balay       prev = list;
472e5c89e4eSSatish Balay       list = list->next;
473e5c89e4eSSatish Balay     }
474b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
475b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
476e5c89e4eSSatish Balay     if (!match) {
4775673baf8SLisandro Dalcin       /* open the library and add to front of list */
478b3bb0f5eSLisandro Dalcin       ierr = PetscDLLibraryOpen(comm,libname,&list);CHKERRQ(ierr);
479b3bb0f5eSLisandro Dalcin       ierr = PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname);CHKERRQ(ierr);
480ebd79076SLisandro Dalcin       list->next = *outlist;
481e5c89e4eSSatish Balay       *outlist   = list;
482e5c89e4eSSatish Balay     }
483b3bb0f5eSLisandro Dalcin     ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
484e5c89e4eSSatish Balay   }
485e5c89e4eSSatish Balay   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
486e5c89e4eSSatish Balay   PetscFunctionReturn(0);
487e5c89e4eSSatish Balay }
488e5c89e4eSSatish Balay 
489e5c89e4eSSatish Balay #undef __FUNCT__
490e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryClose"
491e5c89e4eSSatish Balay /*@C
492e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
493e5c89e4eSSatish Balay 
494e5c89e4eSSatish Balay     Collective on PetscDLLibrary
495e5c89e4eSSatish Balay 
496e5c89e4eSSatish Balay     Input Parameter:
4973fa76a5bSLisandro Dalcin .     head - library list
498e5c89e4eSSatish Balay 
499e5c89e4eSSatish Balay      Level: developer
500e5c89e4eSSatish Balay 
501e5c89e4eSSatish Balay @*/
5027087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryClose(PetscDLLibrary list)
503e5c89e4eSSatish Balay {
504ace3abfcSBarry Smith   PetscBool      done = PETSC_FALSE;
5050f31fb7fSLisandro Dalcin   PetscDLLibrary prev,tail;
506e5c89e4eSSatish Balay   PetscErrorCode ierr;
507e5c89e4eSSatish Balay 
508e5c89e4eSSatish Balay   PetscFunctionBegin;
5090f31fb7fSLisandro Dalcin   if (!list) PetscFunctionReturn(0);
5103fa76a5bSLisandro Dalcin   /* traverse the list in reverse order */
5113fa76a5bSLisandro Dalcin   while (!done) {
5120f31fb7fSLisandro Dalcin     if (!list->next) done = PETSC_TRUE;
5130f31fb7fSLisandro Dalcin     prev = tail = list;
5143fa76a5bSLisandro Dalcin     while (tail->next) {
5153fa76a5bSLisandro Dalcin       prev = tail;
5163fa76a5bSLisandro Dalcin       tail = tail->next;
517e5c89e4eSSatish Balay     }
5183fa76a5bSLisandro Dalcin     prev->next = 0;
5193fa76a5bSLisandro Dalcin     /* close the dynamic library and free the space in entry data-structure*/
5203fa76a5bSLisandro Dalcin     ierr = PetscInfo1(0,"Closing dynamic library %s\n",tail->libname);CHKERRQ(ierr);
5213fa76a5bSLisandro Dalcin     ierr = PetscDLClose(&tail->handle);CHKERRQ(ierr);
5223fa76a5bSLisandro Dalcin     ierr = PetscFree(tail);CHKERRQ(ierr);
5233fa76a5bSLisandro Dalcin   };
524e5c89e4eSSatish Balay   PetscFunctionReturn(0);
525e5c89e4eSSatish Balay }
526e5c89e4eSSatish Balay 
5273fa76a5bSLisandro Dalcin /* ------------------------------------------------------------------------------*/
5283fa76a5bSLisandro Dalcin 
5293fa76a5bSLisandro Dalcin /*
5303fa76a5bSLisandro Dalcin    Contains the list of registered CCA components
5313fa76a5bSLisandro Dalcin */
5323fa76a5bSLisandro Dalcin PetscFList CCAList = 0;
5333fa76a5bSLisandro Dalcin 
534e5c89e4eSSatish Balay #undef __FUNCT__
535e5c89e4eSSatish Balay #define __FUNCT__ "PetscDLLibraryCCAAppend"
536e5c89e4eSSatish Balay /*@C
537e5c89e4eSSatish Balay      PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
538e5c89e4eSSatish Balay                 of the search path.
539e5c89e4eSSatish Balay 
540e5c89e4eSSatish Balay      Collective on MPI_Comm
541e5c89e4eSSatish Balay 
542e5c89e4eSSatish Balay      Input Parameters:
543e5c89e4eSSatish Balay +     comm - MPI communicator
5440f31fb7fSLisandro Dalcin -     dirname - name of directory to check
545e5c89e4eSSatish Balay 
546e5c89e4eSSatish Balay      Output Parameter:
547e5c89e4eSSatish Balay .     outlist - list of libraries
548e5c89e4eSSatish Balay 
549e5c89e4eSSatish Balay      Level: developer
550e5c89e4eSSatish Balay 
551e5c89e4eSSatish Balay      Notes: if library is already in path will not add it.
552e5c89e4eSSatish Balay @*/
5537087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char dirname[])
554e5c89e4eSSatish Balay {
555e5c89e4eSSatish Balay   PetscErrorCode ierr;
556e5c89e4eSSatish Balay   size_t         l;
557ace3abfcSBarry Smith   PetscBool      dir;
558e5c89e4eSSatish Balay   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
559e5c89e4eSSatish Balay   char           *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
560e5c89e4eSSatish Balay   FILE           *fp;
5615b096c79SMatthew Knepley   PetscToken     token1, token2;
562ed9cf6e9SBarry Smith   int            err;
563e5c89e4eSSatish Balay 
564e5c89e4eSSatish Balay   PetscFunctionBegin;
565e5c89e4eSSatish Balay   /* is dirname a directory? */
566e5c89e4eSSatish Balay   ierr = PetscTestDirectory(dirname,'r',&dir);CHKERRQ(ierr);
567e5c89e4eSSatish Balay   if (!dir) PetscFunctionReturn(0);
568e5c89e4eSSatish Balay 
569ae15b995SBarry Smith   ierr = PetscInfo1(0,"Checking directory %s for CCA components\n",dirname);CHKERRQ(ierr);
570e5c89e4eSSatish Balay   ierr  = PetscStrcpy(program,dirname);CHKERRQ(ierr);
571e5c89e4eSSatish Balay   ierr  = PetscStrcat(program,"/*.cca");CHKERRQ(ierr);
572e5c89e4eSSatish Balay 
573e5c89e4eSSatish Balay   ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
574e5c89e4eSSatish Balay   if (!dir) PetscFunctionReturn(0);
575e5c89e4eSSatish Balay 
576e5c89e4eSSatish Balay   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
577e5c89e4eSSatish Balay   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
578e5c89e4eSSatish Balay   ierr = PetscTokenCreate(buf,'\n',&token1);CHKERRQ(ierr);
579e5c89e4eSSatish Balay   ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
580e5c89e4eSSatish Balay   while (libname1) {
581e5c89e4eSSatish Balay     fp    = fopen(libname1,"r"); if (!fp) continue;
582e5c89e4eSSatish Balay     while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
583e5c89e4eSSatish Balay       if (found[0] == '!') continue;
584e5c89e4eSSatish Balay       ierr = PetscStrstr(found,suffix,&f2);CHKERRQ(ierr);
585e5c89e4eSSatish Balay       if (f2) { /* found library name */
586e5c89e4eSSatish Balay         if (found[0] == '/') {
587e5c89e4eSSatish Balay           lib = found;
588e5c89e4eSSatish Balay         } else {
589e5c89e4eSSatish Balay           ierr = PetscStrcpy(libname,dirname);CHKERRQ(ierr);
590e5c89e4eSSatish Balay           ierr = PetscStrlen(libname,&l);CHKERRQ(ierr);
591e5c89e4eSSatish Balay           if (libname[l-1] != '/') {ierr = PetscStrcat(libname,"/");CHKERRQ(ierr);}
592e5c89e4eSSatish Balay           ierr = PetscStrcat(libname,found);CHKERRQ(ierr);
593e5c89e4eSSatish Balay           lib  = libname;
594e5c89e4eSSatish Balay         }
595e5c89e4eSSatish Balay         ierr = PetscDLLibraryAppend(comm,outlist,lib);CHKERRQ(ierr);
596e5c89e4eSSatish Balay       } else {
597ae15b995SBarry Smith         ierr = PetscInfo2(0,"CCA Component function and name: %s from %s\n",found,libname1);CHKERRQ(ierr);
598e5c89e4eSSatish Balay         ierr = PetscTokenCreate(found,' ',&token2);CHKERRQ(ierr);
599e5c89e4eSSatish Balay         ierr = PetscTokenFind(token2,&func);CHKERRQ(ierr);
600e5c89e4eSSatish Balay         ierr = PetscTokenFind(token2,&funcname);CHKERRQ(ierr);
601e5c89e4eSSatish Balay         ierr = PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);CHKERRQ(ierr);
602e5c89e4eSSatish Balay         ierr = PetscTokenDestroy(token2);CHKERRQ(ierr);
603e5c89e4eSSatish Balay       }
604e5c89e4eSSatish Balay     }
605ed9cf6e9SBarry Smith     err = fclose(fp);
606e32f2f54SBarry Smith     if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
607e5c89e4eSSatish Balay     ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
608e5c89e4eSSatish Balay   }
609e5c89e4eSSatish Balay   ierr = PetscTokenDestroy(token1);CHKERRQ(ierr);
610e5c89e4eSSatish Balay   PetscFunctionReturn(0);
611e5c89e4eSSatish Balay }
612