xref: /petsc/src/sys/dll/dl.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
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) {
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 
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 {
53d46cf212SLisandro Dalcin   char  *buf, *par2, suffix[16], *gz, *so;
54d46cf212SLisandro Dalcin   size_t len;
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));
622f613bf5SBarry Smith   len = PetscMax(4 * len, PETSC_MAX_PATH_LEN);
639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(len, &buf));
64d46cf212SLisandro Dalcin   par2 = buf;
659566063dSJacob Faibussowitsch   PetscCall(PetscStrreplace(comm, libname, par2, len));
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)) {
80e5c89e4eSSatish Balay     /* see if library name does already not have suffix attached */
819566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
829566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
839566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(par2, suffix, &so));
84d46cf212SLisandro Dalcin     /* and attach the suffix if it is not there */
859566063dSJacob Faibussowitsch     if (!so) PetscCall(PetscStrcat(par2, suffix));
86e5c89e4eSSatish Balay 
87d46cf212SLisandro Dalcin     /* restore the .gz suffix if it was there */
889566063dSJacob Faibussowitsch     if (gz) PetscCall(PetscStrcat(par2, ".gz"));
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));
95e5c89e4eSSatish Balay   PetscFunctionReturn(0);
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;
126b3bb0f5eSLisandro Dalcin   char          libname[PETSC_MAX_PATH_LEN], par2[PETSC_MAX_PATH_LEN], suffix[16], *s;
127b3bb0f5eSLisandro Dalcin   char         *basename, registername[128];
1285673baf8SLisandro Dalcin   PetscDLHandle handle;
129607a6623SBarry Smith   PetscErrorCode (*func)(void) = NULL;
130e5c89e4eSSatish Balay 
131e5c89e4eSSatish Balay   PetscFunctionBegin;
13282a51d08SSatish Balay   PetscValidCharPointer(path, 2);
1335673baf8SLisandro Dalcin   PetscValidPointer(entry, 3);
134ebd79076SLisandro Dalcin 
1350298fd71SBarry Smith   *entry = NULL;
136e5c89e4eSSatish Balay 
137b3bb0f5eSLisandro Dalcin   /* retrieve the library */
1389566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Retrieving %s\n", path));
1399566063dSJacob Faibussowitsch   PetscCall(PetscDLLibraryRetrieve(comm, path, par2, PETSC_MAX_PATH_LEN, &foundlibrary));
14028b400f6SJacob Faibussowitsch   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate dynamic library:\n  %s", path);
141e2e64c6bSBarry Smith   /* Eventually ./configure should determine if the system needs an executable dynamic library */
142e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
143e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
1449566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(par2, 'x', &foundlibrary));
14528b400f6SJacob Faibussowitsch   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Dynamic library is not executable:\n  %s\n  %s", path, par2);
146e5c89e4eSSatish Balay #endif
147e5c89e4eSSatish Balay 
1483fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
1499566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN));
1509566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
1519566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
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;
1869566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy((*entry)->libname, libname));
187e5c89e4eSSatish Balay   PetscFunctionReturn(0);
188e5c89e4eSSatish Balay }
189e5c89e4eSSatish Balay 
190e5c89e4eSSatish Balay /*@C
191e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
192e5c89e4eSSatish Balay 
193d083f849SBarry Smith    Collective
194e5c89e4eSSatish Balay 
195d8d19677SJose E. Roman    Input Parameters:
196e5bd5246SBarry Smith +  comm - communicator that will open the library
1970298fd71SBarry Smith .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
19830a1dd1fSBarry Smith .  path     - optional complete library name (if provided checks here before checking outlist)
199e5c89e4eSSatish Balay -  insymbol - name of symbol
200e5c89e4eSSatish Balay 
201e5c89e4eSSatish Balay    Output Parameter:
2020298fd71SBarry 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 
210e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
211e5c89e4eSSatish Balay 
212e5c89e4eSSatish Balay @*/
213d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDLLibrarySym(MPI_Comm comm, PetscDLLibrary *outlist, const char path[], const char insymbol[], void **value)
214d71ae5a4SJacob Faibussowitsch {
215b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN], suffix[16], *symbol, *s;
2160298fd71SBarry Smith   PetscDLLibrary nlist, prev, list = NULL;
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));
289e5c89e4eSSatish Balay   PetscFunctionReturn(0);
290e5c89e4eSSatish Balay }
291e5c89e4eSSatish Balay 
292e5c89e4eSSatish Balay /*@C
293e5c89e4eSSatish Balay      PetscDLLibraryAppend - Appends another dynamic link library to the seach 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];
321b3bb0f5eSLisandro Dalcin   char          *libname, suffix[16], *s;
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));
341e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
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));
375e5c89e4eSSatish Balay   PetscFunctionReturn(0);
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];
403b3bb0f5eSLisandro Dalcin   char          *libname, suffix[16], *s;
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));
423e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
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));
465e5c89e4eSSatish Balay   PetscFunctionReturn(0);
466e5c89e4eSSatish Balay }
467e5c89e4eSSatish Balay 
468e5c89e4eSSatish Balay /*@C
469e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
470e5c89e4eSSatish Balay 
471*c3339decSBarry 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;
4850f31fb7fSLisandro Dalcin   if (!list) PetscFunctionReturn(0);
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   }
500e5c89e4eSSatish Balay   PetscFunctionReturn(0);
501e5c89e4eSSatish Balay }
502