xref: /petsc/src/sys/dll/dl.c (revision 6d8694c4fbab79f9439f1ad13c0386ba7ee1ca4b)
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       Code to maintain a list of opened dynamic libraries and load symbols
10e5c89e4eSSatish Balay */
11e5bd5246SBarry Smith struct _n_PetscDLLibrary {
12e5bd5246SBarry Smith   PetscDLLibrary next;
13ebd79076SLisandro Dalcin   PetscDLHandle  handle;
14e5c89e4eSSatish Balay   char           libname[PETSC_MAX_PATH_LEN];
15e5c89e4eSSatish Balay };
16e5c89e4eSSatish Balay 
PetscDLLibraryPrintPath(PetscDLLibrary libs)17d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs)
18d71ae5a4SJacob Faibussowitsch {
19e5c89e4eSSatish Balay   PetscFunctionBegin;
20e5c89e4eSSatish Balay   while (libs) {
213ba16761SJacob Faibussowitsch     PetscCall(PetscErrorPrintf("  %s\n", libs->libname));
22e5c89e4eSSatish Balay     libs = libs->next;
23e5c89e4eSSatish Balay   }
243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25e5c89e4eSSatish Balay }
26e5c89e4eSSatish Balay 
27e5c89e4eSSatish Balay /*@C
28e5c89e4eSSatish Balay   PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
2921532e8aSBarry Smith   (if it is remote), then indicates if it exits and its local name.
30e5c89e4eSSatish Balay 
31d083f849SBarry Smith   Collective
32e5c89e4eSSatish Balay 
33e5c89e4eSSatish Balay   Input Parameters:
3421532e8aSBarry Smith + comm    - MPI processes that will be opening the library
3521532e8aSBarry Smith . libname - name of the library, can be a relative or absolute path and be a URL
3621532e8aSBarry Smith - llen    - length of the `name` buffer
37e5c89e4eSSatish Balay 
38d8d19677SJose E. Roman   Output Parameters:
39aec76313SJacob Faibussowitsch + lname - actual name of the file on local filesystem if `found`
402d53ad75SBarry Smith - found - true if the file exists
41e5c89e4eSSatish Balay 
42e5c89e4eSSatish Balay   Level: developer
43e5c89e4eSSatish Balay 
44e5c89e4eSSatish Balay   Notes:
45e5c89e4eSSatish Balay   [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
46e5c89e4eSSatish Balay 
47e5c89e4eSSatish Balay    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
48a5b23f4aSJose E. Roman   occurring in directoryname and filename will be replaced with appropriate values.
4921532e8aSBarry Smith 
5021532e8aSBarry Smith .seealso: `PetscFileRetrieve()`
51e5c89e4eSSatish Balay @*/
PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char lname[],size_t llen,PetscBool * found)52cc4c1da9SBarry Smith PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm, const char libname[], char lname[], size_t llen, PetscBool *found)
53d71ae5a4SJacob Faibussowitsch {
54c6a7a370SJeremy L Thompson   char  *buf, *par2, *gz = NULL, *so = NULL;
55c6a7a370SJeremy L Thompson   size_t len, blen;
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   */
629566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(libname, &len));
63c6a7a370SJeremy L Thompson   blen = PetscMax(4 * len, PETSC_MAX_PATH_LEN);
64c6a7a370SJeremy L Thompson   PetscCall(PetscMalloc1(blen, &buf));
65d46cf212SLisandro Dalcin   par2 = buf;
66c6a7a370SJeremy L Thompson   PetscCall(PetscStrreplace(comm, libname, par2, blen));
67e5c89e4eSSatish Balay 
68d46cf212SLisandro Dalcin   /* temporarily remove .gz if it ends library name */
699566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(par2, ".gz", &gz));
70e5c89e4eSSatish Balay   if (gz) {
719566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(gz, &len));
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 */
769566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(par2, &len));
773fa76a5bSLisandro Dalcin   if (par2[len - 1] == 'a' && par2[len - 2] == '.') par2[len - 2] = 0;
783fa76a5bSLisandro Dalcin 
799566063dSJacob Faibussowitsch   PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
804ad8454bSPierre Jolivet   if (!*found) {
81c6a7a370SJeremy L Thompson     const char suffix[] = "." PETSC_SLSUFFIX;
82c6a7a370SJeremy L Thompson 
83e5c89e4eSSatish Balay     /* see if library name does already not have suffix attached */
849566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(par2, suffix, &so));
85d46cf212SLisandro Dalcin     /* and attach the suffix if it is not there */
86c6a7a370SJeremy L Thompson     if (!so) PetscCall(PetscStrlcat(par2, suffix, blen));
87e5c89e4eSSatish Balay 
88d46cf212SLisandro Dalcin     /* restore the .gz suffix if it was there */
89c6a7a370SJeremy L Thompson     if (gz) PetscCall(PetscStrlcat(par2, ".gz", blen));
90d46cf212SLisandro Dalcin 
91d46cf212SLisandro Dalcin     /* and finally retrieve the file */
929566063dSJacob Faibussowitsch     PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
932d53ad75SBarry Smith   }
94d46cf212SLisandro Dalcin 
959566063dSJacob Faibussowitsch   PetscCall(PetscFree(buf));
963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
97e5c89e4eSSatish Balay }
98e5c89e4eSSatish Balay 
99e5c89e4eSSatish Balay /*@C
100ebd79076SLisandro Dalcin   PetscDLLibraryOpen - Opens a PETSc dynamic link library
101e5c89e4eSSatish Balay 
102cc4c1da9SBarry Smith   Collective, No Fortran Support
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay   Input Parameters:
10521532e8aSBarry Smith + comm - MPI processes that are opening the library
10621532e8aSBarry Smith - path - name of the library, can be a relative or absolute path
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 
11621532e8aSBarry 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 
12221532e8aSBarry Smith .seealso: `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`, `PetscDLLibraryRetrieve()`, `PetscDLLibrarySym()`, `PetscDLLibraryClose()`
123e5c89e4eSSatish Balay @*/
PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary * entry)124d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm, const char path[], PetscDLLibrary *entry)
125d71ae5a4SJacob Faibussowitsch {
126ace3abfcSBarry Smith   PetscBool     foundlibrary, match;
127c6a7a370SJeremy L Thompson   const char    suffix[] = "." PETSC_SLSUFFIX;
128c6a7a370SJeremy L Thompson   char          libname[PETSC_MAX_PATH_LEN], par2[PETSC_MAX_PATH_LEN], *s;
129b3bb0f5eSLisandro Dalcin   char         *basename, registername[128];
1305673baf8SLisandro Dalcin   PetscDLHandle handle;
131607a6623SBarry Smith   PetscErrorCode (*func)(void) = NULL;
132e5c89e4eSSatish Balay 
133e5c89e4eSSatish Balay   PetscFunctionBegin;
1344f572ea9SToby Isaac   PetscAssertPointer(path, 2);
1354f572ea9SToby Isaac   PetscAssertPointer(entry, 3);
136ebd79076SLisandro Dalcin 
1370298fd71SBarry Smith   *entry = NULL;
138e5c89e4eSSatish Balay 
139b3bb0f5eSLisandro Dalcin   /* retrieve the library */
1409566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Retrieving %s\n", path));
1419566063dSJacob Faibussowitsch   PetscCall(PetscDLLibraryRetrieve(comm, path, par2, PETSC_MAX_PATH_LEN, &foundlibrary));
14200045ab3SPierre Jolivet   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate dynamic library: %s", 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)
1469566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(par2, 'x', &foundlibrary));
14700045ab3SPierre Jolivet   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Dynamic library is not executable: %s %s", path, par2);
148e5c89e4eSSatish Balay #endif
149e5c89e4eSSatish Balay 
1503fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
151c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(libname, path, sizeof(libname)));
1523fa76a5bSLisandro Dalcin   /* remove wrong suffixes from libname */
1539566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, ".gz", &s));
1543fa76a5bSLisandro Dalcin   if (s && s[3] == 0) s[0] = 0;
1559566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, ".a", &s));
1563fa76a5bSLisandro Dalcin   if (s && s[2] == 0) s[0] = 0;
1573fa76a5bSLisandro Dalcin   /* remove shared suffix from libname */
1589566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, suffix, &s));
159b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
160b3bb0f5eSLisandro Dalcin 
1615673baf8SLisandro Dalcin   /* open the dynamic library */
1629566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Opening dynamic library %s\n", libname));
1639566063dSJacob Faibussowitsch   PetscCall(PetscDLOpen(par2, PETSC_DL_DECIDE, &handle));
164b3bb0f5eSLisandro Dalcin 
165b3bb0f5eSLisandro Dalcin   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
1669566063dSJacob Faibussowitsch   PetscCall(PetscStrrchr(libname, '/', &basename)); /* XXX Windows ??? */
167b3bb0f5eSLisandro Dalcin   if (!basename) basename = libname;
1689566063dSJacob Faibussowitsch   PetscCall(PetscStrncmp(basename, "lib", 3, &match));
169a297a907SKarl Rupp   if (match) basename = basename + 3;
17048a46eb9SPierre Jolivet   else PetscCall(PetscInfo(NULL, "Dynamic library %s does not have lib prefix\n", libname));
1719371c9d4SSatish Balay   for (s = basename; *s; s++)
1729371c9d4SSatish Balay     if (*s == '-') *s = '_';
1739566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(registername, "PetscDLLibraryRegister_", sizeof(registername)));
1749566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(registername, basename, sizeof(registername)));
1759566063dSJacob Faibussowitsch   PetscCall(PetscDLSym(handle, registername, (void **)&func));
176b3bb0f5eSLisandro Dalcin   if (func) {
1779566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Loading registered routines from %s\n", libname));
1789566063dSJacob Faibussowitsch     PetscCall((*func)());
179b3bb0f5eSLisandro Dalcin   } else {
1809566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Dynamic library %s does not have symbol %s\n", libname, registername));
181b3bb0f5eSLisandro Dalcin   }
1825673baf8SLisandro Dalcin 
1839566063dSJacob Faibussowitsch   PetscCall(PetscNew(entry));
18402c9f0b5SLisandro Dalcin   (*entry)->next   = NULL;
185b3bb0f5eSLisandro Dalcin   (*entry)->handle = handle;
186c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy((*entry)->libname, libname, sizeof((*entry)->libname)));
1873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
188e5c89e4eSSatish Balay }
189e5c89e4eSSatish Balay 
190e5c89e4eSSatish Balay /*@C
19121532e8aSBarry Smith   PetscDLLibrarySym - Load a symbol from a list of dynamic link libraries.
192e5c89e4eSSatish Balay 
193cc4c1da9SBarry Smith   Collective, No Fortran Support
194e5c89e4eSSatish Balay 
195d8d19677SJose E. Roman   Input Parameters:
19621532e8aSBarry Smith + comm     - the MPI communicator that will load the symbol
19721532e8aSBarry Smith . outlist  - list of already open libraries that may contain symbol (can be `NULL` and only the executable is searched for the function)
19821532e8aSBarry Smith . path     - optional complete library name (if provided it checks here before checking `outlist`)
199e5c89e4eSSatish Balay - insymbol - name of symbol
200e5c89e4eSSatish Balay 
201e5c89e4eSSatish Balay   Output Parameter:
20221532e8aSBarry Smith . value - if symbol not found then this value is set to `NULL`
203e5c89e4eSSatish Balay 
204e5c89e4eSSatish Balay   Level: developer
205e5c89e4eSSatish Balay 
20695452b02SPatrick Sanan   Notes:
20795452b02SPatrick Sanan   Symbol can be of the form
208e5c89e4eSSatish Balay   [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
209e5c89e4eSSatish Balay 
21021532e8aSBarry Smith   It will attempt to (retrieve and) open the library if it is not yet been opened.
211e5c89e4eSSatish Balay 
21221532e8aSBarry Smith .seealso: `PetscDLLibrary`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`, `PetscDLLibraryRetrieve()`, `PetscDLLibraryOpen()`, `PetscDLLibraryClose()`
213e5c89e4eSSatish Balay @*/
PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary * outlist,const char path[],const char insymbol[],void ** value)214*ce78bad3SBarry Smith PetscErrorCode PetscDLLibrarySym(MPI_Comm comm, PetscDLLibrary *outlist, const char path[], const char insymbol[], void **value) PeNS
215d71ae5a4SJacob Faibussowitsch {
216bbcf679cSJacob Faibussowitsch   char           libname[PETSC_MAX_PATH_LEN], suffix[16];
2177864358aSSatish Balay   char          *symbol = NULL, *s = NULL;
218bbcf679cSJacob Faibussowitsch   PetscDLLibrary list = NULL, nlist, prev;
219e5c89e4eSSatish Balay 
220e5c89e4eSSatish Balay   PetscFunctionBegin;
2214f572ea9SToby Isaac   if (outlist) PetscAssertPointer(outlist, 2);
2224f572ea9SToby Isaac   if (path) PetscAssertPointer(path, 3);
2234f572ea9SToby Isaac   PetscAssertPointer(insymbol, 4);
2244f572ea9SToby Isaac   PetscAssertPointer(value, 5);
2255673baf8SLisandro Dalcin 
226340b11eeSBarry Smith   if (outlist) list = *outlist;
22702c9f0b5SLisandro Dalcin   *value = NULL;
228e5c89e4eSSatish Balay 
2299566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(insymbol, '(', &s));
2302d53ad75SBarry Smith   if (s) {
231e5c89e4eSSatish Balay     /* make copy of symbol so we can edit it in place */
2329566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(insymbol, &symbol));
233b3bb0f5eSLisandro Dalcin     /* If symbol contains () then replace with a NULL, to support functionname() */
2349566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(symbol, '(', &s));
2352d53ad75SBarry Smith     s[0] = 0;
236a297a907SKarl Rupp   } else symbol = (char *)insymbol;
237e5c89e4eSSatish Balay 
238e5c89e4eSSatish Balay   /*
239e5c89e4eSSatish Balay        Function name does include library
240e5c89e4eSSatish Balay   */
241e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
242b3bb0f5eSLisandro Dalcin     /* copy path and remove suffix from libname */
2439566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN));
2449566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
2459566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
2469566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(libname, suffix, &s));
247b3bb0f5eSLisandro Dalcin     if (s) s[0] = 0;
2485673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
24902c9f0b5SLisandro Dalcin     prev  = NULL;
250b3bb0f5eSLisandro Dalcin     nlist = list;
251e5c89e4eSSatish Balay     while (nlist) {
252ace3abfcSBarry Smith       PetscBool match;
2539566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(nlist->libname, libname, &match));
2545673baf8SLisandro Dalcin       if (match) goto done;
255e5c89e4eSSatish Balay       prev  = nlist;
256e5c89e4eSSatish Balay       nlist = nlist->next;
257e5c89e4eSSatish Balay     }
258b3bb0f5eSLisandro Dalcin     /* open the library and append it to path */
2599566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryOpen(comm, path, &nlist));
2609566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", path));
261a297a907SKarl Rupp     if (prev) prev->next = nlist;
2629371c9d4SSatish Balay     else {
2639371c9d4SSatish Balay       if (outlist) *outlist = nlist;
2649371c9d4SSatish Balay     }
265e5c89e4eSSatish Balay 
266e5c89e4eSSatish Balay   done:;
2679566063dSJacob Faibussowitsch     PetscCall(PetscDLSym(nlist->handle, symbol, value));
26848a46eb9SPierre Jolivet     if (*value) PetscCall(PetscInfo(NULL, "Loading function %s from dynamic library %s\n", insymbol, path));
269e5c89e4eSSatish Balay 
270e5c89e4eSSatish Balay     /*
271e5c89e4eSSatish Balay          Function name does not include library so search path
272e5c89e4eSSatish Balay     */
273e5c89e4eSSatish Balay   } else {
274e5c89e4eSSatish Balay     while (list) {
2759566063dSJacob Faibussowitsch       PetscCall(PetscDLSym(list->handle, symbol, value));
276e5c89e4eSSatish Balay       if (*value) {
2779566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Loading symbol %s from dynamic library %s\n", symbol, list->libname));
278e5c89e4eSSatish Balay         break;
279e5c89e4eSSatish Balay       }
280e5c89e4eSSatish Balay       list = list->next;
281e5c89e4eSSatish Balay     }
282e5c89e4eSSatish Balay     if (!*value) {
2839566063dSJacob Faibussowitsch       PetscCall(PetscDLSym(NULL, symbol, value));
28448a46eb9SPierre Jolivet       if (*value) PetscCall(PetscInfo(NULL, "Loading symbol %s from object code\n", symbol));
285e5c89e4eSSatish Balay     }
286e5c89e4eSSatish Balay   }
287e5c89e4eSSatish Balay 
28848a46eb9SPierre Jolivet   if (symbol != insymbol) PetscCall(PetscFree(symbol));
2893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
290e5c89e4eSSatish Balay }
291e5c89e4eSSatish Balay 
292e5c89e4eSSatish Balay /*@C
29321532e8aSBarry Smith   PetscDLLibraryAppend - Appends another dynamic link library to the end  of the search list
294e5c89e4eSSatish Balay 
295cc4c1da9SBarry Smith   Collective, No Fortran Support
296e5c89e4eSSatish Balay 
297e5c89e4eSSatish Balay   Input Parameters:
298e5c89e4eSSatish Balay + comm - MPI communicator
2990f31fb7fSLisandro Dalcin - path - name of the library
300e5c89e4eSSatish Balay 
301e5c89e4eSSatish Balay   Output Parameter:
302e5c89e4eSSatish Balay . outlist - list of libraries
303e5c89e4eSSatish Balay 
304e5c89e4eSSatish Balay   Level: developer
305e5c89e4eSSatish Balay 
306811af0c4SBarry Smith   Note:
30795452b02SPatrick Sanan   if library is already in path will not add it.
308bb84e0fdSBarry Smith 
309bb84e0fdSBarry Smith   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
310bb84e0fdSBarry Smith   when the library is opened.
311bb84e0fdSBarry Smith 
312aec76313SJacob Faibussowitsch .seealso: `PetscDLLibrary`, `PetscDLLibraryOpen()`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryRetrieve()`, `PetscDLLibraryPrepend()`
313e5c89e4eSSatish Balay @*/
PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary * outlist,const char path[])314d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
315d71ae5a4SJacob Faibussowitsch {
316e5bd5246SBarry Smith   PetscDLLibrary list, prev;
317e5c89e4eSSatish Balay   size_t         len;
318ace3abfcSBarry Smith   PetscBool      match, dir;
319b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
320*ce78bad3SBarry Smith   const char    *libname;
321*ce78bad3SBarry Smith   char           suffix[16], *s = NULL;
3229c9d3cfdSBarry Smith   PetscToken     token;
323e5c89e4eSSatish Balay 
324e5c89e4eSSatish Balay   PetscFunctionBegin;
3254f572ea9SToby Isaac   PetscAssertPointer(outlist, 2);
326e5c89e4eSSatish Balay 
327b3bb0f5eSLisandro Dalcin   /* is path a directory? */
3289566063dSJacob Faibussowitsch   PetscCall(PetscTestDirectory(path, 'r', &dir));
329e5c89e4eSSatish Balay   if (dir) {
3309566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
3319566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(program, path, sizeof(program)));
3329566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(program, &len));
333e5c89e4eSSatish Balay     if (program[len - 1] == '/') {
3349566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
335e5c89e4eSSatish Balay     } else {
3369566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
337e5c89e4eSSatish Balay     }
3389566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
339e5c89e4eSSatish Balay 
3409566063dSJacob Faibussowitsch     PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
3413ba16761SJacob Faibussowitsch     if (!dir) PetscFunctionReturn(PETSC_SUCCESS);
342e5c89e4eSSatish Balay   } else {
3439566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
344e5c89e4eSSatish Balay   }
3459566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
3469566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
347e5c89e4eSSatish Balay 
3489566063dSJacob Faibussowitsch   PetscCall(PetscTokenCreate(found, '\n', &token));
3499566063dSJacob Faibussowitsch   PetscCall(PetscTokenFind(token, &libname));
350b3bb0f5eSLisandro Dalcin   while (libname) {
351b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
3529566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(libname, suffix, &s));
353e5c89e4eSSatish Balay     if (s) s[0] = 0;
354e5c89e4eSSatish Balay     /* see if library was already open then we are done */
355e5c89e4eSSatish Balay     list = prev = *outlist;
356e5c89e4eSSatish Balay     match       = PETSC_FALSE;
357e5c89e4eSSatish Balay     while (list) {
3589566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(list->libname, libname, &match));
359e5c89e4eSSatish Balay       if (match) break;
360e5c89e4eSSatish Balay       prev = list;
361e5c89e4eSSatish Balay       list = list->next;
362e5c89e4eSSatish Balay     }
363b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
364b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
365e5c89e4eSSatish Balay     if (!match) {
3665673baf8SLisandro Dalcin       /* open the library and add to end of list */
3679566063dSJacob Faibussowitsch       PetscCall(PetscDLLibraryOpen(comm, libname, &list));
3689566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", libname));
369a297a907SKarl Rupp       if (!*outlist) *outlist = list;
370a297a907SKarl Rupp       else prev->next = list;
371e5c89e4eSSatish Balay     }
3729566063dSJacob Faibussowitsch     PetscCall(PetscTokenFind(token, &libname));
373e5c89e4eSSatish Balay   }
3749566063dSJacob Faibussowitsch   PetscCall(PetscTokenDestroy(&token));
3753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
376e5c89e4eSSatish Balay }
377e5c89e4eSSatish Balay 
378e5c89e4eSSatish Balay /*@C
37921532e8aSBarry Smith   PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of the search list
380e5c89e4eSSatish Balay 
381cc4c1da9SBarry Smith   Collective, No Fortran Support
382e5c89e4eSSatish Balay 
383e5c89e4eSSatish Balay   Input Parameters:
384e5c89e4eSSatish Balay + comm - MPI communicator
3850f31fb7fSLisandro Dalcin - path - name of the library
386e5c89e4eSSatish Balay 
387e5c89e4eSSatish Balay   Output Parameter:
388e5c89e4eSSatish Balay . outlist - list of libraries
389e5c89e4eSSatish Balay 
390e5c89e4eSSatish Balay   Level: developer
391e5c89e4eSSatish Balay 
392811af0c4SBarry Smith   Note:
39321532e8aSBarry Smith   If library is already in the list it will remove the old reference.
394e5c89e4eSSatish Balay 
395aec76313SJacob Faibussowitsch .seealso: `PetscDLLibrary`, `PetscDLLibraryOpen()`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryRetrieve()`, `PetscDLLibraryAppend()`
396e5c89e4eSSatish Balay @*/
PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary * outlist,const char path[])397d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
398d71ae5a4SJacob Faibussowitsch {
399e5bd5246SBarry Smith   PetscDLLibrary list, prev;
400e5c89e4eSSatish Balay   size_t         len;
401ace3abfcSBarry Smith   PetscBool      match, dir;
402b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
403*ce78bad3SBarry Smith   const char    *libname;
404*ce78bad3SBarry Smith   char           suffix[16], *s = NULL;
4055b096c79SMatthew Knepley   PetscToken     token;
406e5c89e4eSSatish Balay 
407e5c89e4eSSatish Balay   PetscFunctionBegin;
4084f572ea9SToby Isaac   PetscAssertPointer(outlist, 2);
409e5c89e4eSSatish Balay 
410b3bb0f5eSLisandro Dalcin   /* is path a directory? */
4119566063dSJacob Faibussowitsch   PetscCall(PetscTestDirectory(path, 'r', &dir));
412e5c89e4eSSatish Balay   if (dir) {
4139566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
4149566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(program, path, sizeof(program)));
4159566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(program, &len));
416e5c89e4eSSatish Balay     if (program[len - 1] == '/') {
4179566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
418e5c89e4eSSatish Balay     } else {
4199566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
420e5c89e4eSSatish Balay     }
4219566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
422e5c89e4eSSatish Balay 
4239566063dSJacob Faibussowitsch     PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
4243ba16761SJacob Faibussowitsch     if (!dir) PetscFunctionReturn(PETSC_SUCCESS);
425e5c89e4eSSatish Balay   } else {
4269566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
427e5c89e4eSSatish Balay   }
428e5c89e4eSSatish Balay 
4299566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
4309566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
431e5c89e4eSSatish Balay 
4329566063dSJacob Faibussowitsch   PetscCall(PetscTokenCreate(found, '\n', &token));
4339566063dSJacob Faibussowitsch   PetscCall(PetscTokenFind(token, &libname));
434b3bb0f5eSLisandro Dalcin   while (libname) {
435b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
4369566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(libname, suffix, &s));
437e5c89e4eSSatish Balay     if (s) s[0] = 0;
438e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
43902c9f0b5SLisandro Dalcin     prev  = NULL;
440b3bb0f5eSLisandro Dalcin     list  = *outlist;
441e5c89e4eSSatish Balay     match = PETSC_FALSE;
442e5c89e4eSSatish Balay     while (list) {
4439566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(list->libname, libname, &match));
444e5c89e4eSSatish Balay       if (match) {
4459566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Moving %s to begin of dynamic library search path\n", libname));
446e5c89e4eSSatish Balay         if (prev) prev->next = list->next;
447b3bb0f5eSLisandro Dalcin         if (prev) list->next = *outlist;
448e5c89e4eSSatish Balay         *outlist = list;
449e5c89e4eSSatish Balay         break;
450e5c89e4eSSatish Balay       }
451e5c89e4eSSatish Balay       prev = list;
452e5c89e4eSSatish Balay       list = list->next;
453e5c89e4eSSatish Balay     }
454b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
455b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
456e5c89e4eSSatish Balay     if (!match) {
4575673baf8SLisandro Dalcin       /* open the library and add to front of list */
4589566063dSJacob Faibussowitsch       PetscCall(PetscDLLibraryOpen(comm, libname, &list));
4599566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Prepending %s to dynamic library search path\n", libname));
460ebd79076SLisandro Dalcin       list->next = *outlist;
461e5c89e4eSSatish Balay       *outlist   = list;
462e5c89e4eSSatish Balay     }
4639566063dSJacob Faibussowitsch     PetscCall(PetscTokenFind(token, &libname));
464e5c89e4eSSatish Balay   }
4659566063dSJacob Faibussowitsch   PetscCall(PetscTokenDestroy(&token));
4663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
467e5c89e4eSSatish Balay }
468e5c89e4eSSatish Balay 
469e5c89e4eSSatish Balay /*@C
470e5c89e4eSSatish Balay   PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
471e5c89e4eSSatish Balay 
472cc4c1da9SBarry Smith   Collective, No Fortran Support
473e5c89e4eSSatish Balay 
474e5c89e4eSSatish Balay   Input Parameter:
475aec76313SJacob Faibussowitsch . list - library list
476e5c89e4eSSatish Balay 
477e5c89e4eSSatish Balay   Level: developer
478e5c89e4eSSatish Balay 
479aec76313SJacob Faibussowitsch .seealso: `PetscDLLibrary`, `PetscDLLibraryOpen()`, `PetscLoadDynamicLibrary()`, `PetscDLLibraryRetrieve()`, `PetscDLLibraryAppend()`,
48021532e8aSBarry Smith           `PetscDLLibraryPrepend()`
481e5c89e4eSSatish Balay @*/
PetscDLLibraryClose(PetscDLLibrary list)482d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
483d71ae5a4SJacob Faibussowitsch {
484ace3abfcSBarry Smith   PetscBool      done = PETSC_FALSE;
4850f31fb7fSLisandro Dalcin   PetscDLLibrary prev, tail;
486e5c89e4eSSatish Balay 
487e5c89e4eSSatish Balay   PetscFunctionBegin;
4883ba16761SJacob Faibussowitsch   if (!list) PetscFunctionReturn(PETSC_SUCCESS);
4893fa76a5bSLisandro Dalcin   /* traverse the list in reverse order */
4903fa76a5bSLisandro Dalcin   while (!done) {
4910f31fb7fSLisandro Dalcin     if (!list->next) done = PETSC_TRUE;
4920f31fb7fSLisandro Dalcin     prev = tail = list;
4933fa76a5bSLisandro Dalcin     while (tail->next) {
4943fa76a5bSLisandro Dalcin       prev = tail;
4953fa76a5bSLisandro Dalcin       tail = tail->next;
496e5c89e4eSSatish Balay     }
49702c9f0b5SLisandro Dalcin     prev->next = NULL;
4983fa76a5bSLisandro Dalcin     /* close the dynamic library and free the space in entry data-structure*/
4999566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Closing dynamic library %s\n", tail->libname));
5009566063dSJacob Faibussowitsch     PetscCall(PetscDLClose(&tail->handle));
5019566063dSJacob Faibussowitsch     PetscCall(PetscFree(tail));
502a297a907SKarl Rupp   }
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
504e5c89e4eSSatish Balay }
505