xref: /petsc/src/sys/dll/dl.c (revision d8d19677bbccf95218448bee62e6b87f4513e133)
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 
6af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
7e5c89e4eSSatish Balay 
8e5c89e4eSSatish Balay /* ------------------------------------------------------------------------------*/
9e5c89e4eSSatish Balay /*
10e5c89e4eSSatish Balay       Code to maintain a list of opened dynamic libraries and load symbols
11e5c89e4eSSatish Balay */
12e5bd5246SBarry Smith struct _n_PetscDLLibrary {
13e5bd5246SBarry Smith   PetscDLLibrary next;
14ebd79076SLisandro Dalcin   PetscDLHandle  handle;
15e5c89e4eSSatish Balay   char           libname[PETSC_MAX_PATH_LEN];
16e5c89e4eSSatish Balay };
17e5c89e4eSSatish Balay 
187087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryPrintPath(PetscDLLibrary libs)
19e5c89e4eSSatish Balay {
20e5c89e4eSSatish Balay   PetscFunctionBegin;
21e5c89e4eSSatish Balay   while (libs) {
22e5c89e4eSSatish Balay     PetscErrorPrintf("  %s\n",libs->libname);
23e5c89e4eSSatish Balay     libs = libs->next;
24e5c89e4eSSatish Balay   }
25e5c89e4eSSatish Balay   PetscFunctionReturn(0);
26e5c89e4eSSatish Balay }
27e5c89e4eSSatish Balay 
28e5c89e4eSSatish Balay /*@C
29e5c89e4eSSatish Balay    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
30e5c89e4eSSatish Balay      (if it is remote), indicates if it exits and its local name.
31e5c89e4eSSatish Balay 
32d083f849SBarry Smith      Collective
33e5c89e4eSSatish Balay 
34e5c89e4eSSatish Balay    Input Parameters:
35e5c89e4eSSatish Balay +   comm - processors that are opening the library
36e5c89e4eSSatish Balay -   libname - name of the library, can be relative or absolute
37e5c89e4eSSatish Balay 
38*d8d19677SJose E. Roman    Output Parameters:
392d53ad75SBarry Smith +   name - actual name of file on local filesystem if found
402d53ad75SBarry Smith .   llen - length of the name buffer
412d53ad75SBarry Smith -   found - true if the file exists
42e5c89e4eSSatish Balay 
43e5c89e4eSSatish Balay    Level: developer
44e5c89e4eSSatish Balay 
45e5c89e4eSSatish Balay    Notes:
46e5c89e4eSSatish Balay    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
47e5c89e4eSSatish Balay 
48e5c89e4eSSatish Balay    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
49a5b23f4aSJose E. Roman    occurring in directoryname and filename will be replaced with appropriate values.
50e5c89e4eSSatish Balay @*/
517087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool  *found)
52e5c89e4eSSatish Balay {
53d46cf212SLisandro Dalcin   char           *buf,*par2,suffix[16],*gz,*so;
54d46cf212SLisandro Dalcin   size_t         len;
55e5c89e4eSSatish Balay   PetscErrorCode ierr;
56e5c89e4eSSatish Balay 
57e5c89e4eSSatish Balay   PetscFunctionBegin;
58e5c89e4eSSatish Balay   /*
59a523d312SBarry Smith      make copy of library name and replace $PETSC_ARCH etc
60e5c89e4eSSatish Balay      so we can add to the end of it to look for something like .so.1.0 etc.
61e5c89e4eSSatish Balay   */
62e5c89e4eSSatish Balay   ierr = PetscStrlen(libname,&len);CHKERRQ(ierr);
63e5c89e4eSSatish Balay   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
64785e854fSJed Brown   ierr = PetscMalloc1(len,&buf);CHKERRQ(ierr);
65d46cf212SLisandro Dalcin   par2 = buf;
66e5c89e4eSSatish Balay   ierr = PetscStrreplace(comm,libname,par2,len);CHKERRQ(ierr);
67e5c89e4eSSatish Balay 
68d46cf212SLisandro Dalcin   /* temporarily remove .gz if it ends library name */
69d46cf212SLisandro Dalcin   ierr = PetscStrrstr(par2,".gz",&gz);CHKERRQ(ierr);
70e5c89e4eSSatish Balay   if (gz) {
71e5c89e4eSSatish Balay     ierr = PetscStrlen(gz,&len);CHKERRQ(ierr);
7202c9f0b5SLisandro Dalcin     if (len != 3) gz  = NULL; /* do not end (exactly) with .gz */
73d46cf212SLisandro Dalcin     else          *gz = 0;    /* ends with .gz, so remove it   */
74e5c89e4eSSatish Balay   }
753fa76a5bSLisandro Dalcin   /* strip out .a from it if user put it in by mistake */
763fa76a5bSLisandro Dalcin   ierr = PetscStrlen(par2,&len);CHKERRQ(ierr);
773fa76a5bSLisandro Dalcin   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
783fa76a5bSLisandro Dalcin 
792d53ad75SBarry Smith   ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr);
808ce0dc28SMatthew G Knepley   if (!(*found)) {
81e5c89e4eSSatish Balay     /* see if library name does already not have suffix attached */
82a126751eSBarry Smith     ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr);
83a126751eSBarry Smith     ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr);
84b3bb0f5eSLisandro Dalcin     ierr = PetscStrrstr(par2,suffix,&so);CHKERRQ(ierr);
85d46cf212SLisandro Dalcin     /* and attach the suffix if it is not there */
86d46cf212SLisandro Dalcin     if (!so) { ierr = PetscStrcat(par2,suffix);CHKERRQ(ierr); }
87e5c89e4eSSatish Balay 
88d46cf212SLisandro Dalcin     /* restore the .gz suffix if it was there */
89d46cf212SLisandro Dalcin     if (gz) { ierr = PetscStrcat(par2,".gz");CHKERRQ(ierr); }
90d46cf212SLisandro Dalcin 
91d46cf212SLisandro Dalcin     /* and finally retrieve the file */
92e5c89e4eSSatish Balay     ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr);
932d53ad75SBarry Smith   }
94d46cf212SLisandro Dalcin 
95d46cf212SLisandro Dalcin   ierr = PetscFree(buf);CHKERRQ(ierr);
96e5c89e4eSSatish Balay   PetscFunctionReturn(0);
97e5c89e4eSSatish Balay }
98e5c89e4eSSatish Balay 
99e5c89e4eSSatish Balay /*@C
100ebd79076SLisandro Dalcin    PetscDLLibraryOpen - Opens a PETSc dynamic link library
101e5c89e4eSSatish Balay 
102d083f849SBarry Smith      Collective
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay    Input Parameters:
105e5c89e4eSSatish Balay +   comm - processors that are opening the library
1060f31fb7fSLisandro Dalcin -   path - name of the library, can be relative or absolute
107e5c89e4eSSatish Balay 
108e5c89e4eSSatish Balay    Output Parameter:
1090f31fb7fSLisandro Dalcin .   entry - a PETSc dynamic link library entry
110e5c89e4eSSatish Balay 
111e5c89e4eSSatish Balay    Level: developer
112e5c89e4eSSatish Balay 
113e5c89e4eSSatish Balay    Notes:
114bb84e0fdSBarry Smith    [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
115bb84e0fdSBarry Smith 
116bb84e0fdSBarry Smith    If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
117bb84e0fdSBarry Smith    when the library is opened.
118e5c89e4eSSatish Balay 
119a5b23f4aSJose E. Roman    ${PETSC_ARCH} occurring in directoryname and filename
120e5c89e4eSSatish Balay    will be replaced with the appropriate value.
121bb84e0fdSBarry Smith 
122bb84e0fdSBarry Smith .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
123e5c89e4eSSatish Balay @*/
1247087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
125e5c89e4eSSatish Balay {
126e5c89e4eSSatish Balay   PetscErrorCode ierr;
127ace3abfcSBarry Smith   PetscBool      foundlibrary,match;
128b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
129b3bb0f5eSLisandro Dalcin   char           *basename,registername[128];
1305673baf8SLisandro Dalcin   PetscDLHandle  handle;
131607a6623SBarry Smith   PetscErrorCode (*func)(void) = NULL;
132e5c89e4eSSatish Balay 
133e5c89e4eSSatish Balay   PetscFunctionBegin;
13482a51d08SSatish Balay   PetscValidCharPointer(path,2);
1355673baf8SLisandro Dalcin   PetscValidPointer(entry,3);
136ebd79076SLisandro Dalcin 
1370298fd71SBarry Smith   *entry = NULL;
138e5c89e4eSSatish Balay 
139b3bb0f5eSLisandro Dalcin   /* retrieve the library */
14002c9f0b5SLisandro Dalcin   ierr = PetscInfo1(NULL,"Retrieving %s\n",path);CHKERRQ(ierr);
141b3bb0f5eSLisandro Dalcin   ierr = PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);CHKERRQ(ierr);
142e32f2f54SBarry Smith   if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",path);
143e2e64c6bSBarry Smith   /* Eventually ./configure should determine if the system needs an executable dynamic library */
144e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
145e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
146e5c89e4eSSatish Balay   ierr = PetscTestFile(par2,'x',&foundlibrary);CHKERRQ(ierr);
147e32f2f54SBarry Smith   if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",path,par2);
148e5c89e4eSSatish Balay #endif
149e5c89e4eSSatish Balay 
1503fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
151b3bb0f5eSLisandro Dalcin   ierr = PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
152a126751eSBarry Smith   ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr);
153a126751eSBarry Smith   ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr);
1543fa76a5bSLisandro Dalcin   /* remove wrong suffixes from libname */
1553fa76a5bSLisandro Dalcin   ierr = PetscStrrstr(libname,".gz",&s);CHKERRQ(ierr);
1563fa76a5bSLisandro Dalcin   if (s && s[3] == 0) s[0] = 0;
1573fa76a5bSLisandro Dalcin   ierr = PetscStrrstr(libname,".a",&s);CHKERRQ(ierr);
1583fa76a5bSLisandro Dalcin   if (s && s[2] == 0) s[0] = 0;
1593fa76a5bSLisandro Dalcin   /* remove shared suffix from libname */
160b3bb0f5eSLisandro Dalcin   ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr);
161b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
162b3bb0f5eSLisandro Dalcin 
1635673baf8SLisandro Dalcin   /* open the dynamic library */
16402c9f0b5SLisandro Dalcin   ierr = PetscInfo1(NULL,"Opening dynamic library %s\n",libname);CHKERRQ(ierr);
165b3bb0f5eSLisandro Dalcin   ierr = PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);CHKERRQ(ierr);
166b3bb0f5eSLisandro Dalcin 
167b3bb0f5eSLisandro Dalcin   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
168b3bb0f5eSLisandro Dalcin   ierr = PetscStrrchr(libname,'/',&basename);CHKERRQ(ierr); /* XXX Windows ??? */
169b3bb0f5eSLisandro Dalcin   if (!basename) basename = libname;
170b3bb0f5eSLisandro Dalcin   ierr = PetscStrncmp(basename,"lib",3,&match);CHKERRQ(ierr);
171a297a907SKarl Rupp   if (match) basename = basename + 3;
172a297a907SKarl Rupp   else {
17302c9f0b5SLisandro Dalcin     ierr = PetscInfo1(NULL,"Dynamic library %s does not have lib prefix\n",libname);CHKERRQ(ierr);
174e5c89e4eSSatish Balay   }
175cf4b33a9SJed Brown   for (s=basename; *s; s++) if (*s == '-') *s = '_';
176153a8027SBarry Smith   ierr = PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername));CHKERRQ(ierr);
177a126751eSBarry Smith   ierr = PetscStrlcat(registername,basename,sizeof(registername));CHKERRQ(ierr);
178b3bb0f5eSLisandro Dalcin   ierr = PetscDLSym(handle,registername,(void**)&func);CHKERRQ(ierr);
179b3bb0f5eSLisandro Dalcin   if (func) {
18002c9f0b5SLisandro Dalcin     ierr = PetscInfo1(NULL,"Loading registered routines from %s\n",libname);CHKERRQ(ierr);
181607a6623SBarry Smith     ierr = (*func)();CHKERRQ(ierr);
182b3bb0f5eSLisandro Dalcin   } else {
18302c9f0b5SLisandro Dalcin     ierr = PetscInfo2(NULL,"Dynamic library %s does not have symbol %s\n",libname,registername);CHKERRQ(ierr);
184b3bb0f5eSLisandro Dalcin   }
1855673baf8SLisandro Dalcin 
186b00a9115SJed Brown   ierr = PetscNew(entry);CHKERRQ(ierr);
18702c9f0b5SLisandro Dalcin   (*entry)->next   = NULL;
188b3bb0f5eSLisandro Dalcin   (*entry)->handle = handle;
189b3bb0f5eSLisandro Dalcin   ierr = PetscStrcpy((*entry)->libname,libname);CHKERRQ(ierr);
190e5c89e4eSSatish Balay   PetscFunctionReturn(0);
191e5c89e4eSSatish Balay }
192e5c89e4eSSatish Balay 
193e5c89e4eSSatish Balay /*@C
194e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
195e5c89e4eSSatish Balay 
196d083f849SBarry Smith    Collective
197e5c89e4eSSatish Balay 
198*d8d19677SJose E. Roman    Input Parameters:
199e5bd5246SBarry Smith +  comm - communicator that will open the library
2000298fd71SBarry Smith .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
20130a1dd1fSBarry Smith .  path     - optional complete library name (if provided checks here before checking outlist)
202e5c89e4eSSatish Balay -  insymbol - name of symbol
203e5c89e4eSSatish Balay 
204e5c89e4eSSatish Balay    Output Parameter:
2050298fd71SBarry Smith .  value - if symbol not found then this value is set to NULL
206e5c89e4eSSatish Balay 
207e5c89e4eSSatish Balay    Level: developer
208e5c89e4eSSatish Balay 
20995452b02SPatrick Sanan    Notes:
21095452b02SPatrick Sanan     Symbol can be of the form
211e5c89e4eSSatish Balay         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
214e5c89e4eSSatish Balay 
215e5c89e4eSSatish Balay @*/
2167087cfbeSBarry Smith PetscErrorCode  PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
217e5c89e4eSSatish Balay {
218b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
2190298fd71SBarry Smith   PetscDLLibrary nlist,prev,list = NULL;
220b3bb0f5eSLisandro Dalcin   PetscErrorCode ierr;
221e5c89e4eSSatish Balay 
222e5c89e4eSSatish Balay   PetscFunctionBegin;
223340b11eeSBarry Smith   if (outlist) PetscValidPointer(outlist,2);
2245673baf8SLisandro Dalcin   if (path) PetscValidCharPointer(path,3);
2255673baf8SLisandro Dalcin   PetscValidCharPointer(insymbol,4);
2265673baf8SLisandro Dalcin   PetscValidPointer(value,5);
2275673baf8SLisandro Dalcin 
228340b11eeSBarry Smith   if (outlist) list = *outlist;
22902c9f0b5SLisandro Dalcin   *value = NULL;
230e5c89e4eSSatish Balay 
2312d53ad75SBarry Smith   ierr = PetscStrchr(insymbol,'(',&s);CHKERRQ(ierr);
2322d53ad75SBarry Smith   if (s) {
233e5c89e4eSSatish Balay     /* make copy of symbol so we can edit it in place */
2342d53ad75SBarry Smith     ierr = PetscStrallocpy(insymbol,&symbol);CHKERRQ(ierr);
235b3bb0f5eSLisandro Dalcin     /* If symbol contains () then replace with a NULL, to support functionname() */
236b3bb0f5eSLisandro Dalcin     ierr = PetscStrchr(symbol,'(',&s);CHKERRQ(ierr);
2372d53ad75SBarry Smith     s[0] = 0;
238a297a907SKarl Rupp   } else symbol = (char*)insymbol;
239e5c89e4eSSatish Balay 
240e5c89e4eSSatish Balay   /*
241e5c89e4eSSatish Balay        Function name does include library
242e5c89e4eSSatish Balay        -------------------------------------
243e5c89e4eSSatish Balay   */
244e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
245b3bb0f5eSLisandro Dalcin     /* copy path and remove suffix from libname */
246b3bb0f5eSLisandro Dalcin     ierr = PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
247a126751eSBarry Smith     ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr);
248a126751eSBarry Smith     ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr);
249b3bb0f5eSLisandro Dalcin     ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr);
250b3bb0f5eSLisandro Dalcin     if (s) s[0] = 0;
2515673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
25202c9f0b5SLisandro Dalcin     prev  = NULL;
253b3bb0f5eSLisandro Dalcin     nlist = list;
254e5c89e4eSSatish Balay     while (nlist) {
255ace3abfcSBarry Smith       PetscBool match;
256b3bb0f5eSLisandro Dalcin       ierr = PetscStrcmp(nlist->libname,libname,&match);CHKERRQ(ierr);
2575673baf8SLisandro Dalcin       if (match) goto done;
258e5c89e4eSSatish Balay       prev  = nlist;
259e5c89e4eSSatish Balay       nlist = nlist->next;
260e5c89e4eSSatish Balay     }
261b3bb0f5eSLisandro Dalcin     /* open the library and append it to path */
2625673baf8SLisandro Dalcin     ierr = PetscDLLibraryOpen(comm,path,&nlist);CHKERRQ(ierr);
26302c9f0b5SLisandro Dalcin     ierr = PetscInfo1(NULL,"Appending %s to dynamic library search path\n",path);CHKERRQ(ierr);
264a297a907SKarl Rupp     if (prev) prev->next = nlist;
265ca43db0aSBarry Smith     else {if (outlist) *outlist   = nlist;}
266e5c89e4eSSatish Balay 
267e5c89e4eSSatish Balay done:;
2685673baf8SLisandro Dalcin     ierr = PetscDLSym(nlist->handle,symbol,value);CHKERRQ(ierr);
26930a1dd1fSBarry Smith     if (*value) {
27002c9f0b5SLisandro Dalcin       ierr = PetscInfo2(NULL,"Loading function %s from dynamic library %s\n",insymbol,path);CHKERRQ(ierr);
27130a1dd1fSBarry Smith     }
272e5c89e4eSSatish Balay 
273e5c89e4eSSatish Balay     /*
274e5c89e4eSSatish Balay          Function name does not include library so search path
275e5c89e4eSSatish Balay          -----------------------------------------------------
276e5c89e4eSSatish Balay     */
277e5c89e4eSSatish Balay   } else {
278e5c89e4eSSatish Balay     while (list) {
279ebd79076SLisandro Dalcin       ierr = PetscDLSym(list->handle,symbol,value);CHKERRQ(ierr);
280e5c89e4eSSatish Balay       if (*value) {
28102c9f0b5SLisandro Dalcin         ierr = PetscInfo2(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);CHKERRQ(ierr);
282e5c89e4eSSatish Balay         break;
283e5c89e4eSSatish Balay       }
284e5c89e4eSSatish Balay       list = list->next;
285e5c89e4eSSatish Balay     }
286e5c89e4eSSatish Balay     if (!*value) {
2870298fd71SBarry Smith       ierr = PetscDLSym(NULL,symbol,value);CHKERRQ(ierr);
288e5c89e4eSSatish Balay       if (*value) {
28902c9f0b5SLisandro Dalcin         ierr = PetscInfo1(NULL,"Loading symbol %s from object code\n",symbol);CHKERRQ(ierr);
290e5c89e4eSSatish Balay       }
291e5c89e4eSSatish Balay     }
292e5c89e4eSSatish Balay   }
293e5c89e4eSSatish Balay 
2942d53ad75SBarry Smith   if (symbol != insymbol) {
295e5c89e4eSSatish Balay     ierr = PetscFree(symbol);CHKERRQ(ierr);
2962d53ad75SBarry Smith   }
297e5c89e4eSSatish Balay   PetscFunctionReturn(0);
298e5c89e4eSSatish Balay }
299e5c89e4eSSatish Balay 
300e5c89e4eSSatish Balay /*@C
301e5c89e4eSSatish Balay      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
302e5c89e4eSSatish Balay                 of the search path.
303e5c89e4eSSatish Balay 
304d083f849SBarry Smith      Collective
305e5c89e4eSSatish Balay 
306e5c89e4eSSatish Balay      Input Parameters:
307e5c89e4eSSatish Balay +     comm - MPI communicator
3080f31fb7fSLisandro Dalcin -     path - name of the library
309e5c89e4eSSatish Balay 
310e5c89e4eSSatish Balay      Output Parameter:
311e5c89e4eSSatish Balay .     outlist - list of libraries
312e5c89e4eSSatish Balay 
313e5c89e4eSSatish Balay      Level: developer
314e5c89e4eSSatish Balay 
31595452b02SPatrick Sanan      Notes:
31695452b02SPatrick Sanan     if library is already in path will not add it.
317bb84e0fdSBarry Smith 
318bb84e0fdSBarry Smith   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
319bb84e0fdSBarry Smith       when the library is opened.
320bb84e0fdSBarry Smith 
321bb84e0fdSBarry Smith .seealso: PetscDLLibraryOpen()
322e5c89e4eSSatish Balay @*/
3237087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
324e5c89e4eSSatish Balay {
325e5bd5246SBarry Smith   PetscDLLibrary list,prev;
326e5c89e4eSSatish Balay   PetscErrorCode ierr;
327e5c89e4eSSatish Balay   size_t         len;
328ace3abfcSBarry Smith   PetscBool      match,dir;
329b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
330b3bb0f5eSLisandro Dalcin   char           *libname,suffix[16],*s;
3319c9d3cfdSBarry Smith   PetscToken     token;
332e5c89e4eSSatish Balay 
333e5c89e4eSSatish Balay   PetscFunctionBegin;
334b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist,2);
335e5c89e4eSSatish Balay 
336b3bb0f5eSLisandro Dalcin   /* is path a directory? */
337b3bb0f5eSLisandro Dalcin   ierr = PetscTestDirectory(path,'r',&dir);CHKERRQ(ierr);
338e5c89e4eSSatish Balay   if (dir) {
33902c9f0b5SLisandro Dalcin     ierr = PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);CHKERRQ(ierr);
340a126751eSBarry Smith     ierr = PetscStrncpy(program,path,sizeof(program));CHKERRQ(ierr);
341e5c89e4eSSatish Balay     ierr = PetscStrlen(program,&len);CHKERRQ(ierr);
342e5c89e4eSSatish Balay     if (program[len-1] == '/') {
343a126751eSBarry Smith       ierr = PetscStrlcat(program,"*.",sizeof(program));CHKERRQ(ierr);
344e5c89e4eSSatish Balay     } else {
345a126751eSBarry Smith       ierr = PetscStrlcat(program,"/*.",sizeof(program));CHKERRQ(ierr);
346e5c89e4eSSatish Balay     }
347a126751eSBarry Smith     ierr = PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));CHKERRQ(ierr);
348e5c89e4eSSatish Balay 
349b3bb0f5eSLisandro Dalcin     ierr = PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
350e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
351e5c89e4eSSatish Balay   } else {
352b3bb0f5eSLisandro Dalcin     ierr = PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
353e5c89e4eSSatish Balay   }
354a126751eSBarry Smith   ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr);
355a126751eSBarry Smith   ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr);
356e5c89e4eSSatish Balay 
357e5c89e4eSSatish Balay   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
358b3bb0f5eSLisandro Dalcin   ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
359b3bb0f5eSLisandro Dalcin   while (libname) {
360b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
361b3bb0f5eSLisandro Dalcin     ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr);
362e5c89e4eSSatish Balay     if (s) s[0] = 0;
363e5c89e4eSSatish Balay     /* see if library was already open then we are done */
364e5c89e4eSSatish Balay     list  = prev = *outlist;
365e5c89e4eSSatish Balay     match = PETSC_FALSE;
366e5c89e4eSSatish Balay     while (list) {
367b3bb0f5eSLisandro Dalcin       ierr = PetscStrcmp(list->libname,libname,&match);CHKERRQ(ierr);
368e5c89e4eSSatish Balay       if (match) break;
369e5c89e4eSSatish Balay       prev = list;
370e5c89e4eSSatish Balay       list = list->next;
371e5c89e4eSSatish Balay     }
372b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
373b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
374e5c89e4eSSatish Balay     if (!match) {
3755673baf8SLisandro Dalcin       /* open the library and add to end of list */
376b3bb0f5eSLisandro Dalcin       ierr = PetscDLLibraryOpen(comm,libname,&list);CHKERRQ(ierr);
37702c9f0b5SLisandro Dalcin       ierr = PetscInfo1(NULL,"Appending %s to dynamic library search path\n",libname);CHKERRQ(ierr);
378a297a907SKarl Rupp       if (!*outlist) *outlist   = list;
379a297a907SKarl Rupp       else           prev->next = list;
380e5c89e4eSSatish Balay     }
381b3bb0f5eSLisandro Dalcin     ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
382e5c89e4eSSatish Balay   }
3838c74ee41SBarry Smith   ierr = PetscTokenDestroy(&token);CHKERRQ(ierr);
384e5c89e4eSSatish Balay   PetscFunctionReturn(0);
385e5c89e4eSSatish Balay }
386e5c89e4eSSatish Balay 
387e5c89e4eSSatish Balay /*@C
388e5c89e4eSSatish Balay      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
389e5c89e4eSSatish Balay                  the search path.
390e5c89e4eSSatish Balay 
391d083f849SBarry Smith      Collective
392e5c89e4eSSatish Balay 
393e5c89e4eSSatish Balay      Input Parameters:
394e5c89e4eSSatish Balay +     comm - MPI communicator
3950f31fb7fSLisandro Dalcin -     path - name of the library
396e5c89e4eSSatish Balay 
397e5c89e4eSSatish Balay      Output Parameter:
398e5c89e4eSSatish Balay .     outlist - list of libraries
399e5c89e4eSSatish Balay 
400e5c89e4eSSatish Balay      Level: developer
401e5c89e4eSSatish Balay 
40295452b02SPatrick Sanan      Notes:
40395452b02SPatrick Sanan     If library is already in path will remove old reference.
404e5c89e4eSSatish Balay 
405e5c89e4eSSatish Balay @*/
4067087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
407e5c89e4eSSatish Balay {
408e5bd5246SBarry Smith   PetscDLLibrary list,prev;
409e5c89e4eSSatish Balay   PetscErrorCode ierr;
410e5c89e4eSSatish Balay   size_t         len;
411ace3abfcSBarry Smith   PetscBool      match,dir;
412b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
413b3bb0f5eSLisandro Dalcin   char           *libname,suffix[16],*s;
4145b096c79SMatthew Knepley   PetscToken     token;
415e5c89e4eSSatish Balay 
416e5c89e4eSSatish Balay   PetscFunctionBegin;
417b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist,2);
418e5c89e4eSSatish Balay 
419b3bb0f5eSLisandro Dalcin   /* is path a directory? */
420b3bb0f5eSLisandro Dalcin   ierr = PetscTestDirectory(path,'r',&dir);CHKERRQ(ierr);
421e5c89e4eSSatish Balay   if (dir) {
42202c9f0b5SLisandro Dalcin     ierr = PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);CHKERRQ(ierr);
423a126751eSBarry Smith     ierr = PetscStrncpy(program,path,sizeof(program));CHKERRQ(ierr);
424e5c89e4eSSatish Balay     ierr = PetscStrlen(program,&len);CHKERRQ(ierr);
425e5c89e4eSSatish Balay     if (program[len-1] == '/') {
426a126751eSBarry Smith       ierr = PetscStrlcat(program,"*.",sizeof(program));CHKERRQ(ierr);
427e5c89e4eSSatish Balay     } else {
428a126751eSBarry Smith       ierr = PetscStrlcat(program,"/*.",sizeof(program));CHKERRQ(ierr);
429e5c89e4eSSatish Balay     }
430a126751eSBarry Smith     ierr = PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));CHKERRQ(ierr);
431e5c89e4eSSatish Balay 
432b3bb0f5eSLisandro Dalcin     ierr = PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
433e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
434e5c89e4eSSatish Balay   } else {
435b3bb0f5eSLisandro Dalcin     ierr = PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
436e5c89e4eSSatish Balay   }
437e5c89e4eSSatish Balay 
438a126751eSBarry Smith   ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr);
439a126751eSBarry Smith   ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr);
440e5c89e4eSSatish Balay 
441e5c89e4eSSatish Balay   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
442b3bb0f5eSLisandro Dalcin   ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
443b3bb0f5eSLisandro Dalcin   while (libname) {
444b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
445b3bb0f5eSLisandro Dalcin     ierr = PetscStrstr(libname,suffix,&s);CHKERRQ(ierr);
446e5c89e4eSSatish Balay     if (s) s[0] = 0;
447e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
44802c9f0b5SLisandro Dalcin     prev  = NULL;
449b3bb0f5eSLisandro Dalcin     list  = *outlist;
450e5c89e4eSSatish Balay     match = PETSC_FALSE;
451e5c89e4eSSatish Balay     while (list) {
452b3bb0f5eSLisandro Dalcin       ierr = PetscStrcmp(list->libname,libname,&match);CHKERRQ(ierr);
453e5c89e4eSSatish Balay       if (match) {
45402c9f0b5SLisandro Dalcin         ierr = PetscInfo1(NULL,"Moving %s to begin of dynamic library search path\n",libname);CHKERRQ(ierr);
455e5c89e4eSSatish Balay         if (prev) prev->next = list->next;
456b3bb0f5eSLisandro Dalcin         if (prev) list->next = *outlist;
457e5c89e4eSSatish Balay         *outlist = list;
458e5c89e4eSSatish Balay         break;
459e5c89e4eSSatish Balay       }
460e5c89e4eSSatish Balay       prev = list;
461e5c89e4eSSatish Balay       list = list->next;
462e5c89e4eSSatish Balay     }
463b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
464b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
465e5c89e4eSSatish Balay     if (!match) {
4665673baf8SLisandro Dalcin       /* open the library and add to front of list */
467b3bb0f5eSLisandro Dalcin       ierr       = PetscDLLibraryOpen(comm,libname,&list);CHKERRQ(ierr);
46802c9f0b5SLisandro Dalcin       ierr       = PetscInfo1(NULL,"Prepending %s to dynamic library search path\n",libname);CHKERRQ(ierr);
469ebd79076SLisandro Dalcin       list->next = *outlist;
470e5c89e4eSSatish Balay       *outlist   = list;
471e5c89e4eSSatish Balay     }
472b3bb0f5eSLisandro Dalcin     ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr);
473e5c89e4eSSatish Balay   }
4748c74ee41SBarry Smith   ierr = PetscTokenDestroy(&token);CHKERRQ(ierr);
475e5c89e4eSSatish Balay   PetscFunctionReturn(0);
476e5c89e4eSSatish Balay }
477e5c89e4eSSatish Balay 
478e5c89e4eSSatish Balay /*@C
479e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
480e5c89e4eSSatish Balay 
481e5c89e4eSSatish Balay     Collective on PetscDLLibrary
482e5c89e4eSSatish Balay 
483e5c89e4eSSatish Balay     Input Parameter:
4843fa76a5bSLisandro Dalcin .     head - library list
485e5c89e4eSSatish Balay 
486e5c89e4eSSatish Balay      Level: developer
487e5c89e4eSSatish Balay 
488e5c89e4eSSatish Balay @*/
4897087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryClose(PetscDLLibrary list)
490e5c89e4eSSatish Balay {
491ace3abfcSBarry Smith   PetscBool      done = PETSC_FALSE;
4920f31fb7fSLisandro Dalcin   PetscDLLibrary prev,tail;
493e5c89e4eSSatish Balay   PetscErrorCode ierr;
494e5c89e4eSSatish Balay 
495e5c89e4eSSatish Balay   PetscFunctionBegin;
4960f31fb7fSLisandro Dalcin   if (!list) PetscFunctionReturn(0);
4973fa76a5bSLisandro Dalcin   /* traverse the list in reverse order */
4983fa76a5bSLisandro Dalcin   while (!done) {
4990f31fb7fSLisandro Dalcin     if (!list->next) done = PETSC_TRUE;
5000f31fb7fSLisandro Dalcin     prev = tail = list;
5013fa76a5bSLisandro Dalcin     while (tail->next) {
5023fa76a5bSLisandro Dalcin       prev = tail;
5033fa76a5bSLisandro Dalcin       tail = tail->next;
504e5c89e4eSSatish Balay     }
50502c9f0b5SLisandro Dalcin     prev->next = NULL;
5063fa76a5bSLisandro Dalcin     /* close the dynamic library and free the space in entry data-structure*/
50702c9f0b5SLisandro Dalcin     ierr = PetscInfo1(NULL,"Closing dynamic library %s\n",tail->libname);CHKERRQ(ierr);
5083fa76a5bSLisandro Dalcin     ierr = PetscDLClose(&tail->handle);CHKERRQ(ierr);
5093fa76a5bSLisandro Dalcin     ierr = PetscFree(tail);CHKERRQ(ierr);
510a297a907SKarl Rupp   }
511e5c89e4eSSatish Balay   PetscFunctionReturn(0);
512e5c89e4eSSatish Balay }
513e5c89e4eSSatish Balay 
514