xref: /petsc/src/sys/dll/dl.c (revision c6a7a37075f8bf8d34d92c4910d42445b7a3482d)
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 
18d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs)
19d71ae5a4SJacob Faibussowitsch {
20e5c89e4eSSatish Balay   PetscFunctionBegin;
21e5c89e4eSSatish Balay   while (libs) {
223ba16761SJacob Faibussowitsch     PetscCall(PetscErrorPrintf("  %s\n", libs->libname));
23e5c89e4eSSatish Balay     libs = libs->next;
24e5c89e4eSSatish Balay   }
253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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 
38d8d19677SJose 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 @*/
51d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm, const char libname[], char *lname, size_t llen, PetscBool *found)
52d71ae5a4SJacob Faibussowitsch {
53*c6a7a370SJeremy L Thompson   char  *buf, *par2, *gz = NULL, *so = NULL;
54*c6a7a370SJeremy L Thompson   size_t len, blen;
55e5c89e4eSSatish Balay 
56e5c89e4eSSatish Balay   PetscFunctionBegin;
57e5c89e4eSSatish Balay   /*
58a523d312SBarry Smith      make copy of library name and replace $PETSC_ARCH etc
59e5c89e4eSSatish Balay      so we can add to the end of it to look for something like .so.1.0 etc.
60e5c89e4eSSatish Balay   */
619566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(libname, &len));
62*c6a7a370SJeremy L Thompson   blen = PetscMax(4 * len, PETSC_MAX_PATH_LEN);
63*c6a7a370SJeremy L Thompson   PetscCall(PetscMalloc1(blen, &buf));
64d46cf212SLisandro Dalcin   par2 = buf;
65*c6a7a370SJeremy L Thompson   PetscCall(PetscStrreplace(comm, libname, par2, blen));
66e5c89e4eSSatish Balay 
67d46cf212SLisandro Dalcin   /* temporarily remove .gz if it ends library name */
689566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(par2, ".gz", &gz));
69e5c89e4eSSatish Balay   if (gz) {
709566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(gz, &len));
7102c9f0b5SLisandro Dalcin     if (len != 3) gz = NULL; /* do not end (exactly) with .gz */
72d46cf212SLisandro Dalcin     else *gz = 0;            /* ends with .gz, so remove it   */
73e5c89e4eSSatish Balay   }
743fa76a5bSLisandro Dalcin   /* strip out .a from it if user put it in by mistake */
759566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(par2, &len));
763fa76a5bSLisandro Dalcin   if (par2[len - 1] == 'a' && par2[len - 2] == '.') par2[len - 2] = 0;
773fa76a5bSLisandro Dalcin 
789566063dSJacob Faibussowitsch   PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
798ce0dc28SMatthew G Knepley   if (!(*found)) {
80*c6a7a370SJeremy L Thompson     const char suffix[] = "." PETSC_SLSUFFIX;
81*c6a7a370SJeremy L Thompson 
82e5c89e4eSSatish Balay     /* see if library name does already not have suffix attached */
839566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(par2, suffix, &so));
84d46cf212SLisandro Dalcin     /* and attach the suffix if it is not there */
85*c6a7a370SJeremy L Thompson     if (!so) PetscCall(PetscStrlcat(par2, suffix, blen));
86e5c89e4eSSatish Balay 
87d46cf212SLisandro Dalcin     /* restore the .gz suffix if it was there */
88*c6a7a370SJeremy L Thompson     if (gz) PetscCall(PetscStrlcat(par2, ".gz", blen));
89d46cf212SLisandro Dalcin 
90d46cf212SLisandro Dalcin     /* and finally retrieve the file */
919566063dSJacob Faibussowitsch     PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
922d53ad75SBarry Smith   }
93d46cf212SLisandro Dalcin 
949566063dSJacob Faibussowitsch   PetscCall(PetscFree(buf));
953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96e5c89e4eSSatish Balay }
97e5c89e4eSSatish Balay 
98e5c89e4eSSatish Balay /*@C
99ebd79076SLisandro Dalcin    PetscDLLibraryOpen - Opens a PETSc dynamic link library
100e5c89e4eSSatish Balay 
101d083f849SBarry Smith      Collective
102e5c89e4eSSatish Balay 
103e5c89e4eSSatish Balay    Input Parameters:
104e5c89e4eSSatish Balay +   comm - processors that are opening the library
1050f31fb7fSLisandro Dalcin -   path - name of the library, can be relative or absolute
106e5c89e4eSSatish Balay 
107e5c89e4eSSatish Balay    Output Parameter:
1080f31fb7fSLisandro Dalcin .   entry - a PETSc dynamic link library entry
109e5c89e4eSSatish Balay 
110e5c89e4eSSatish Balay    Level: developer
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay    Notes:
113bb84e0fdSBarry Smith    [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
114bb84e0fdSBarry Smith 
115bb84e0fdSBarry Smith    If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
116bb84e0fdSBarry Smith    when the library is opened.
117e5c89e4eSSatish Balay 
118a5b23f4aSJose E. Roman    ${PETSC_ARCH} occurring in directoryname and filename
119e5c89e4eSSatish Balay    will be replaced with the appropriate value.
120bb84e0fdSBarry Smith 
121db781477SPatrick Sanan .seealso: `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`
122e5c89e4eSSatish Balay @*/
123d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm, const char path[], PetscDLLibrary *entry)
124d71ae5a4SJacob Faibussowitsch {
125ace3abfcSBarry Smith   PetscBool     foundlibrary, match;
126*c6a7a370SJeremy L Thompson   const char    suffix[] = "." PETSC_SLSUFFIX;
127*c6a7a370SJeremy L Thompson   char          libname[PETSC_MAX_PATH_LEN], par2[PETSC_MAX_PATH_LEN], *s;
128b3bb0f5eSLisandro Dalcin   char         *basename, registername[128];
1295673baf8SLisandro Dalcin   PetscDLHandle handle;
130607a6623SBarry Smith   PetscErrorCode (*func)(void) = NULL;
131e5c89e4eSSatish Balay 
132e5c89e4eSSatish Balay   PetscFunctionBegin;
13382a51d08SSatish Balay   PetscValidCharPointer(path, 2);
1345673baf8SLisandro Dalcin   PetscValidPointer(entry, 3);
135ebd79076SLisandro Dalcin 
1360298fd71SBarry Smith   *entry = NULL;
137e5c89e4eSSatish Balay 
138b3bb0f5eSLisandro Dalcin   /* retrieve the library */
1399566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Retrieving %s\n", path));
1409566063dSJacob Faibussowitsch   PetscCall(PetscDLLibraryRetrieve(comm, path, par2, PETSC_MAX_PATH_LEN, &foundlibrary));
14128b400f6SJacob Faibussowitsch   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate dynamic library:\n  %s", path);
142e2e64c6bSBarry Smith   /* Eventually ./configure should determine if the system needs an executable dynamic library */
143e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
144e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
1459566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(par2, 'x', &foundlibrary));
14628b400f6SJacob Faibussowitsch   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Dynamic library is not executable:\n  %s\n  %s", path, par2);
147e5c89e4eSSatish Balay #endif
148e5c89e4eSSatish Balay 
1493fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
150*c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(libname, path, sizeof(libname)));
1513fa76a5bSLisandro Dalcin   /* remove wrong suffixes from libname */
1529566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, ".gz", &s));
1533fa76a5bSLisandro Dalcin   if (s && s[3] == 0) s[0] = 0;
1549566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, ".a", &s));
1553fa76a5bSLisandro Dalcin   if (s && s[2] == 0) s[0] = 0;
1563fa76a5bSLisandro Dalcin   /* remove shared suffix from libname */
1579566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, suffix, &s));
158b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
159b3bb0f5eSLisandro Dalcin 
1605673baf8SLisandro Dalcin   /* open the dynamic library */
1619566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Opening dynamic library %s\n", libname));
1629566063dSJacob Faibussowitsch   PetscCall(PetscDLOpen(par2, PETSC_DL_DECIDE, &handle));
163b3bb0f5eSLisandro Dalcin 
164b3bb0f5eSLisandro Dalcin   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
1659566063dSJacob Faibussowitsch   PetscCall(PetscStrrchr(libname, '/', &basename)); /* XXX Windows ??? */
166b3bb0f5eSLisandro Dalcin   if (!basename) basename = libname;
1679566063dSJacob Faibussowitsch   PetscCall(PetscStrncmp(basename, "lib", 3, &match));
168a297a907SKarl Rupp   if (match) basename = basename + 3;
16948a46eb9SPierre Jolivet   else PetscCall(PetscInfo(NULL, "Dynamic library %s does not have lib prefix\n", libname));
1709371c9d4SSatish Balay   for (s = basename; *s; s++)
1719371c9d4SSatish Balay     if (*s == '-') *s = '_';
1729566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(registername, "PetscDLLibraryRegister_", sizeof(registername)));
1739566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(registername, basename, sizeof(registername)));
1749566063dSJacob Faibussowitsch   PetscCall(PetscDLSym(handle, registername, (void **)&func));
175b3bb0f5eSLisandro Dalcin   if (func) {
1769566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Loading registered routines from %s\n", libname));
1779566063dSJacob Faibussowitsch     PetscCall((*func)());
178b3bb0f5eSLisandro Dalcin   } else {
1799566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Dynamic library %s does not have symbol %s\n", libname, registername));
180b3bb0f5eSLisandro Dalcin   }
1815673baf8SLisandro Dalcin 
1829566063dSJacob Faibussowitsch   PetscCall(PetscNew(entry));
18302c9f0b5SLisandro Dalcin   (*entry)->next   = NULL;
184b3bb0f5eSLisandro Dalcin   (*entry)->handle = handle;
185*c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy((*entry)->libname, libname, sizeof((*entry)->libname)));
1863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
187e5c89e4eSSatish Balay }
188e5c89e4eSSatish Balay 
189e5c89e4eSSatish Balay /*@C
190e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
191e5c89e4eSSatish Balay 
192d083f849SBarry Smith    Collective
193e5c89e4eSSatish Balay 
194d8d19677SJose E. Roman    Input Parameters:
195e5bd5246SBarry Smith +  comm - communicator that will open the library
1960298fd71SBarry Smith .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
19730a1dd1fSBarry Smith .  path     - optional complete library name (if provided checks here before checking outlist)
198e5c89e4eSSatish Balay -  insymbol - name of symbol
199e5c89e4eSSatish Balay 
200e5c89e4eSSatish Balay    Output Parameter:
2010298fd71SBarry Smith .  value - if symbol not found then this value is set to NULL
202e5c89e4eSSatish Balay 
203e5c89e4eSSatish Balay    Level: developer
204e5c89e4eSSatish Balay 
20595452b02SPatrick Sanan    Notes:
20695452b02SPatrick Sanan     Symbol can be of the form
207e5c89e4eSSatish Balay         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
208e5c89e4eSSatish Balay 
209e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
210e5c89e4eSSatish Balay 
211e5c89e4eSSatish Balay @*/
212d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibrarySym(MPI_Comm comm, PetscDLLibrary *outlist, const char path[], const char insymbol[], void **value)
213d71ae5a4SJacob Faibussowitsch {
214bbcf679cSJacob Faibussowitsch   char           libname[PETSC_MAX_PATH_LEN], suffix[16];
2157864358aSSatish Balay   char          *symbol = NULL, *s = NULL;
216bbcf679cSJacob Faibussowitsch   PetscDLLibrary list = NULL, nlist, prev;
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay   PetscFunctionBegin;
219340b11eeSBarry Smith   if (outlist) PetscValidPointer(outlist, 2);
2205673baf8SLisandro Dalcin   if (path) PetscValidCharPointer(path, 3);
2215673baf8SLisandro Dalcin   PetscValidCharPointer(insymbol, 4);
2225673baf8SLisandro Dalcin   PetscValidPointer(value, 5);
2235673baf8SLisandro Dalcin 
224340b11eeSBarry Smith   if (outlist) list = *outlist;
22502c9f0b5SLisandro Dalcin   *value = NULL;
226e5c89e4eSSatish Balay 
2279566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(insymbol, '(', &s));
2282d53ad75SBarry Smith   if (s) {
229e5c89e4eSSatish Balay     /* make copy of symbol so we can edit it in place */
2309566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(insymbol, &symbol));
231b3bb0f5eSLisandro Dalcin     /* If symbol contains () then replace with a NULL, to support functionname() */
2329566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(symbol, '(', &s));
2332d53ad75SBarry Smith     s[0] = 0;
234a297a907SKarl Rupp   } else symbol = (char *)insymbol;
235e5c89e4eSSatish Balay 
236e5c89e4eSSatish Balay   /*
237e5c89e4eSSatish Balay        Function name does include library
238e5c89e4eSSatish Balay        -------------------------------------
239e5c89e4eSSatish Balay   */
240e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
241b3bb0f5eSLisandro Dalcin     /* copy path and remove suffix from libname */
2429566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN));
2439566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
2449566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
2459566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(libname, suffix, &s));
246b3bb0f5eSLisandro Dalcin     if (s) s[0] = 0;
2475673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
24802c9f0b5SLisandro Dalcin     prev  = NULL;
249b3bb0f5eSLisandro Dalcin     nlist = list;
250e5c89e4eSSatish Balay     while (nlist) {
251ace3abfcSBarry Smith       PetscBool match;
2529566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(nlist->libname, libname, &match));
2535673baf8SLisandro Dalcin       if (match) goto done;
254e5c89e4eSSatish Balay       prev  = nlist;
255e5c89e4eSSatish Balay       nlist = nlist->next;
256e5c89e4eSSatish Balay     }
257b3bb0f5eSLisandro Dalcin     /* open the library and append it to path */
2589566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryOpen(comm, path, &nlist));
2599566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", path));
260a297a907SKarl Rupp     if (prev) prev->next = nlist;
2619371c9d4SSatish Balay     else {
2629371c9d4SSatish Balay       if (outlist) *outlist = nlist;
2639371c9d4SSatish Balay     }
264e5c89e4eSSatish Balay 
265e5c89e4eSSatish Balay   done:;
2669566063dSJacob Faibussowitsch     PetscCall(PetscDLSym(nlist->handle, symbol, value));
26748a46eb9SPierre Jolivet     if (*value) PetscCall(PetscInfo(NULL, "Loading function %s from dynamic library %s\n", insymbol, path));
268e5c89e4eSSatish Balay 
269e5c89e4eSSatish Balay     /*
270e5c89e4eSSatish Balay          Function name does not include library so search path
271e5c89e4eSSatish Balay          -----------------------------------------------------
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
293da81f932SPierre Jolivet      PetscDLLibraryAppend - Appends another dynamic link library to the search list, to the end
294e5c89e4eSSatish Balay                 of the search path.
295e5c89e4eSSatish Balay 
296d083f849SBarry Smith      Collective
297e5c89e4eSSatish Balay 
298e5c89e4eSSatish Balay      Input Parameters:
299e5c89e4eSSatish Balay +     comm - MPI communicator
3000f31fb7fSLisandro Dalcin -     path - name of the library
301e5c89e4eSSatish Balay 
302e5c89e4eSSatish Balay      Output Parameter:
303e5c89e4eSSatish Balay .     outlist - list of libraries
304e5c89e4eSSatish Balay 
305e5c89e4eSSatish Balay      Level: developer
306e5c89e4eSSatish Balay 
307811af0c4SBarry Smith      Note:
30895452b02SPatrick Sanan     if library is already in path will not add it.
309bb84e0fdSBarry Smith 
310bb84e0fdSBarry Smith   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
311bb84e0fdSBarry Smith       when the library is opened.
312bb84e0fdSBarry Smith 
313db781477SPatrick Sanan .seealso: `PetscDLLibraryOpen()`
314e5c89e4eSSatish Balay @*/
315d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
316d71ae5a4SJacob Faibussowitsch {
317e5bd5246SBarry Smith   PetscDLLibrary list, prev;
318e5c89e4eSSatish Balay   size_t         len;
319ace3abfcSBarry Smith   PetscBool      match, dir;
320b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
321bbcf679cSJacob Faibussowitsch   char          *libname, suffix[16], *s = NULL;
3229c9d3cfdSBarry Smith   PetscToken     token;
323e5c89e4eSSatish Balay 
324e5c89e4eSSatish Balay   PetscFunctionBegin;
325b3bb0f5eSLisandro Dalcin   PetscValidPointer(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
379e5c89e4eSSatish Balay      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
380e5c89e4eSSatish Balay                  the search path.
381e5c89e4eSSatish Balay 
382d083f849SBarry Smith      Collective
383e5c89e4eSSatish Balay 
384e5c89e4eSSatish Balay      Input Parameters:
385e5c89e4eSSatish Balay +     comm - MPI communicator
3860f31fb7fSLisandro Dalcin -     path - name of the library
387e5c89e4eSSatish Balay 
388e5c89e4eSSatish Balay      Output Parameter:
389e5c89e4eSSatish Balay .     outlist - list of libraries
390e5c89e4eSSatish Balay 
391e5c89e4eSSatish Balay      Level: developer
392e5c89e4eSSatish Balay 
393811af0c4SBarry Smith      Note:
39495452b02SPatrick Sanan     If library is already in path will remove old reference.
395e5c89e4eSSatish Balay 
396e5c89e4eSSatish Balay @*/
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];
403bbcf679cSJacob Faibussowitsch   char          *libname, suffix[16], *s = NULL;
4045b096c79SMatthew Knepley   PetscToken     token;
405e5c89e4eSSatish Balay 
406e5c89e4eSSatish Balay   PetscFunctionBegin;
407b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist, 2);
408e5c89e4eSSatish Balay 
409b3bb0f5eSLisandro Dalcin   /* is path a directory? */
4109566063dSJacob Faibussowitsch   PetscCall(PetscTestDirectory(path, 'r', &dir));
411e5c89e4eSSatish Balay   if (dir) {
4129566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
4139566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(program, path, sizeof(program)));
4149566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(program, &len));
415e5c89e4eSSatish Balay     if (program[len - 1] == '/') {
4169566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
417e5c89e4eSSatish Balay     } else {
4189566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
419e5c89e4eSSatish Balay     }
4209566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
421e5c89e4eSSatish Balay 
4229566063dSJacob Faibussowitsch     PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
4233ba16761SJacob Faibussowitsch     if (!dir) PetscFunctionReturn(PETSC_SUCCESS);
424e5c89e4eSSatish Balay   } else {
4259566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
426e5c89e4eSSatish Balay   }
427e5c89e4eSSatish Balay 
4289566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
4299566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
430e5c89e4eSSatish Balay 
4319566063dSJacob Faibussowitsch   PetscCall(PetscTokenCreate(found, '\n', &token));
4329566063dSJacob Faibussowitsch   PetscCall(PetscTokenFind(token, &libname));
433b3bb0f5eSLisandro Dalcin   while (libname) {
434b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
4359566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(libname, suffix, &s));
436e5c89e4eSSatish Balay     if (s) s[0] = 0;
437e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
43802c9f0b5SLisandro Dalcin     prev  = NULL;
439b3bb0f5eSLisandro Dalcin     list  = *outlist;
440e5c89e4eSSatish Balay     match = PETSC_FALSE;
441e5c89e4eSSatish Balay     while (list) {
4429566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(list->libname, libname, &match));
443e5c89e4eSSatish Balay       if (match) {
4449566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Moving %s to begin of dynamic library search path\n", libname));
445e5c89e4eSSatish Balay         if (prev) prev->next = list->next;
446b3bb0f5eSLisandro Dalcin         if (prev) list->next = *outlist;
447e5c89e4eSSatish Balay         *outlist = list;
448e5c89e4eSSatish Balay         break;
449e5c89e4eSSatish Balay       }
450e5c89e4eSSatish Balay       prev = list;
451e5c89e4eSSatish Balay       list = list->next;
452e5c89e4eSSatish Balay     }
453b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
454b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
455e5c89e4eSSatish Balay     if (!match) {
4565673baf8SLisandro Dalcin       /* open the library and add to front of list */
4579566063dSJacob Faibussowitsch       PetscCall(PetscDLLibraryOpen(comm, libname, &list));
4589566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Prepending %s to dynamic library search path\n", libname));
459ebd79076SLisandro Dalcin       list->next = *outlist;
460e5c89e4eSSatish Balay       *outlist   = list;
461e5c89e4eSSatish Balay     }
4629566063dSJacob Faibussowitsch     PetscCall(PetscTokenFind(token, &libname));
463e5c89e4eSSatish Balay   }
4649566063dSJacob Faibussowitsch   PetscCall(PetscTokenDestroy(&token));
4653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
466e5c89e4eSSatish Balay }
467e5c89e4eSSatish Balay 
468e5c89e4eSSatish Balay /*@C
469e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
470e5c89e4eSSatish Balay 
471c3339decSBarry Smith     Collective
472e5c89e4eSSatish Balay 
473e5c89e4eSSatish Balay     Input Parameter:
4743fa76a5bSLisandro Dalcin .     head - library list
475e5c89e4eSSatish Balay 
476e5c89e4eSSatish Balay      Level: developer
477e5c89e4eSSatish Balay 
478e5c89e4eSSatish Balay @*/
479d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
480d71ae5a4SJacob Faibussowitsch {
481ace3abfcSBarry Smith   PetscBool      done = PETSC_FALSE;
4820f31fb7fSLisandro Dalcin   PetscDLLibrary prev, tail;
483e5c89e4eSSatish Balay 
484e5c89e4eSSatish Balay   PetscFunctionBegin;
4853ba16761SJacob Faibussowitsch   if (!list) PetscFunctionReturn(PETSC_SUCCESS);
4863fa76a5bSLisandro Dalcin   /* traverse the list in reverse order */
4873fa76a5bSLisandro Dalcin   while (!done) {
4880f31fb7fSLisandro Dalcin     if (!list->next) done = PETSC_TRUE;
4890f31fb7fSLisandro Dalcin     prev = tail = list;
4903fa76a5bSLisandro Dalcin     while (tail->next) {
4913fa76a5bSLisandro Dalcin       prev = tail;
4923fa76a5bSLisandro Dalcin       tail = tail->next;
493e5c89e4eSSatish Balay     }
49402c9f0b5SLisandro Dalcin     prev->next = NULL;
4953fa76a5bSLisandro Dalcin     /* close the dynamic library and free the space in entry data-structure*/
4969566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Closing dynamic library %s\n", tail->libname));
4979566063dSJacob Faibussowitsch     PetscCall(PetscDLClose(&tail->handle));
4989566063dSJacob Faibussowitsch     PetscCall(PetscFree(tail));
499a297a907SKarl Rupp   }
5003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
501e5c89e4eSSatish Balay }
502