xref: /petsc/src/sys/dll/dl.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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 
189371c9d4SSatish Balay PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs) {
19e5c89e4eSSatish Balay   PetscFunctionBegin;
20e5c89e4eSSatish Balay   while (libs) {
21e5c89e4eSSatish Balay     PetscErrorPrintf("  %s\n", libs->libname);
22e5c89e4eSSatish Balay     libs = libs->next;
23e5c89e4eSSatish Balay   }
24e5c89e4eSSatish Balay   PetscFunctionReturn(0);
25e5c89e4eSSatish Balay }
26e5c89e4eSSatish Balay 
27e5c89e4eSSatish Balay /*@C
28e5c89e4eSSatish Balay    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
29e5c89e4eSSatish Balay      (if it is remote), indicates if it exits and its local name.
30e5c89e4eSSatish Balay 
31d083f849SBarry Smith      Collective
32e5c89e4eSSatish Balay 
33e5c89e4eSSatish Balay    Input Parameters:
34e5c89e4eSSatish Balay +   comm - processors that are opening the library
35e5c89e4eSSatish Balay -   libname - name of the library, can be relative or absolute
36e5c89e4eSSatish Balay 
37d8d19677SJose E. Roman    Output Parameters:
382d53ad75SBarry Smith +   name - actual name of file on local filesystem if found
392d53ad75SBarry Smith .   llen - length of the name buffer
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.
49e5c89e4eSSatish Balay @*/
509371c9d4SSatish Balay PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm, const char libname[], char *lname, size_t llen, PetscBool *found) {
51d46cf212SLisandro Dalcin   char  *buf, *par2, suffix[16], *gz, *so;
52d46cf212SLisandro Dalcin   size_t len;
53e5c89e4eSSatish Balay 
54e5c89e4eSSatish Balay   PetscFunctionBegin;
55e5c89e4eSSatish Balay   /*
56a523d312SBarry Smith      make copy of library name and replace $PETSC_ARCH etc
57e5c89e4eSSatish Balay      so we can add to the end of it to look for something like .so.1.0 etc.
58e5c89e4eSSatish Balay   */
599566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(libname, &len));
602f613bf5SBarry Smith   len = PetscMax(4 * len, PETSC_MAX_PATH_LEN);
619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(len, &buf));
62d46cf212SLisandro Dalcin   par2 = buf;
639566063dSJacob Faibussowitsch   PetscCall(PetscStrreplace(comm, libname, par2, len));
64e5c89e4eSSatish Balay 
65d46cf212SLisandro Dalcin   /* temporarily remove .gz if it ends library name */
669566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(par2, ".gz", &gz));
67e5c89e4eSSatish Balay   if (gz) {
689566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(gz, &len));
6902c9f0b5SLisandro Dalcin     if (len != 3) gz = NULL; /* do not end (exactly) with .gz */
70d46cf212SLisandro Dalcin     else *gz = 0;            /* ends with .gz, so remove it   */
71e5c89e4eSSatish Balay   }
723fa76a5bSLisandro Dalcin   /* strip out .a from it if user put it in by mistake */
739566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(par2, &len));
743fa76a5bSLisandro Dalcin   if (par2[len - 1] == 'a' && par2[len - 2] == '.') par2[len - 2] = 0;
753fa76a5bSLisandro Dalcin 
769566063dSJacob Faibussowitsch   PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
778ce0dc28SMatthew G Knepley   if (!(*found)) {
78e5c89e4eSSatish Balay     /* see if library name does already not have suffix attached */
799566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
809566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
819566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(par2, suffix, &so));
82d46cf212SLisandro Dalcin     /* and attach the suffix if it is not there */
839566063dSJacob Faibussowitsch     if (!so) PetscCall(PetscStrcat(par2, suffix));
84e5c89e4eSSatish Balay 
85d46cf212SLisandro Dalcin     /* restore the .gz suffix if it was there */
869566063dSJacob Faibussowitsch     if (gz) PetscCall(PetscStrcat(par2, ".gz"));
87d46cf212SLisandro Dalcin 
88d46cf212SLisandro Dalcin     /* and finally retrieve the file */
899566063dSJacob Faibussowitsch     PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
902d53ad75SBarry Smith   }
91d46cf212SLisandro Dalcin 
929566063dSJacob Faibussowitsch   PetscCall(PetscFree(buf));
93e5c89e4eSSatish Balay   PetscFunctionReturn(0);
94e5c89e4eSSatish Balay }
95e5c89e4eSSatish Balay 
96e5c89e4eSSatish Balay /*@C
97ebd79076SLisandro Dalcin    PetscDLLibraryOpen - Opens a PETSc dynamic link library
98e5c89e4eSSatish Balay 
99d083f849SBarry Smith      Collective
100e5c89e4eSSatish Balay 
101e5c89e4eSSatish Balay    Input Parameters:
102e5c89e4eSSatish Balay +   comm - processors that are opening the library
1030f31fb7fSLisandro Dalcin -   path - name of the library, can be relative or absolute
104e5c89e4eSSatish Balay 
105e5c89e4eSSatish Balay    Output Parameter:
1060f31fb7fSLisandro Dalcin .   entry - a PETSc dynamic link library entry
107e5c89e4eSSatish Balay 
108e5c89e4eSSatish Balay    Level: developer
109e5c89e4eSSatish Balay 
110e5c89e4eSSatish Balay    Notes:
111bb84e0fdSBarry Smith    [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
112bb84e0fdSBarry Smith 
113bb84e0fdSBarry Smith    If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
114bb84e0fdSBarry Smith    when the library is opened.
115e5c89e4eSSatish Balay 
116a5b23f4aSJose E. Roman    ${PETSC_ARCH} occurring in directoryname and filename
117e5c89e4eSSatish Balay    will be replaced with the appropriate value.
118bb84e0fdSBarry Smith 
119db781477SPatrick Sanan .seealso: `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`
120e5c89e4eSSatish Balay @*/
1219371c9d4SSatish Balay PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm, const char path[], PetscDLLibrary *entry) {
122ace3abfcSBarry Smith   PetscBool     foundlibrary, match;
123b3bb0f5eSLisandro Dalcin   char          libname[PETSC_MAX_PATH_LEN], par2[PETSC_MAX_PATH_LEN], suffix[16], *s;
124b3bb0f5eSLisandro Dalcin   char         *basename, registername[128];
1255673baf8SLisandro Dalcin   PetscDLHandle handle;
126607a6623SBarry Smith   PetscErrorCode (*func)(void) = NULL;
127e5c89e4eSSatish Balay 
128e5c89e4eSSatish Balay   PetscFunctionBegin;
12982a51d08SSatish Balay   PetscValidCharPointer(path, 2);
1305673baf8SLisandro Dalcin   PetscValidPointer(entry, 3);
131ebd79076SLisandro Dalcin 
1320298fd71SBarry Smith   *entry = NULL;
133e5c89e4eSSatish Balay 
134b3bb0f5eSLisandro Dalcin   /* retrieve the library */
1359566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Retrieving %s\n", path));
1369566063dSJacob Faibussowitsch   PetscCall(PetscDLLibraryRetrieve(comm, path, par2, PETSC_MAX_PATH_LEN, &foundlibrary));
13728b400f6SJacob Faibussowitsch   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate dynamic library:\n  %s", path);
138e2e64c6bSBarry Smith   /* Eventually ./configure should determine if the system needs an executable dynamic library */
139e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
140e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
1419566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(par2, 'x', &foundlibrary));
14228b400f6SJacob Faibussowitsch   PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Dynamic library is not executable:\n  %s\n  %s", path, par2);
143e5c89e4eSSatish Balay #endif
144e5c89e4eSSatish Balay 
1453fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
1469566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN));
1479566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
1489566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
1493fa76a5bSLisandro Dalcin   /* remove wrong suffixes from libname */
1509566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, ".gz", &s));
1513fa76a5bSLisandro Dalcin   if (s && s[3] == 0) s[0] = 0;
1529566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, ".a", &s));
1533fa76a5bSLisandro Dalcin   if (s && s[2] == 0) s[0] = 0;
1543fa76a5bSLisandro Dalcin   /* remove shared suffix from libname */
1559566063dSJacob Faibussowitsch   PetscCall(PetscStrrstr(libname, suffix, &s));
156b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
157b3bb0f5eSLisandro Dalcin 
1585673baf8SLisandro Dalcin   /* open the dynamic library */
1599566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Opening dynamic library %s\n", libname));
1609566063dSJacob Faibussowitsch   PetscCall(PetscDLOpen(par2, PETSC_DL_DECIDE, &handle));
161b3bb0f5eSLisandro Dalcin 
162b3bb0f5eSLisandro Dalcin   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
1639566063dSJacob Faibussowitsch   PetscCall(PetscStrrchr(libname, '/', &basename)); /* XXX Windows ??? */
164b3bb0f5eSLisandro Dalcin   if (!basename) basename = libname;
1659566063dSJacob Faibussowitsch   PetscCall(PetscStrncmp(basename, "lib", 3, &match));
166a297a907SKarl Rupp   if (match) basename = basename + 3;
167*48a46eb9SPierre Jolivet   else PetscCall(PetscInfo(NULL, "Dynamic library %s does not have lib prefix\n", libname));
1689371c9d4SSatish Balay   for (s = basename; *s; s++)
1699371c9d4SSatish Balay     if (*s == '-') *s = '_';
1709566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(registername, "PetscDLLibraryRegister_", sizeof(registername)));
1719566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(registername, basename, sizeof(registername)));
1729566063dSJacob Faibussowitsch   PetscCall(PetscDLSym(handle, registername, (void **)&func));
173b3bb0f5eSLisandro Dalcin   if (func) {
1749566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Loading registered routines from %s\n", libname));
1759566063dSJacob Faibussowitsch     PetscCall((*func)());
176b3bb0f5eSLisandro Dalcin   } else {
1779566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Dynamic library %s does not have symbol %s\n", libname, registername));
178b3bb0f5eSLisandro Dalcin   }
1795673baf8SLisandro Dalcin 
1809566063dSJacob Faibussowitsch   PetscCall(PetscNew(entry));
18102c9f0b5SLisandro Dalcin   (*entry)->next   = NULL;
182b3bb0f5eSLisandro Dalcin   (*entry)->handle = handle;
1839566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy((*entry)->libname, libname));
184e5c89e4eSSatish Balay   PetscFunctionReturn(0);
185e5c89e4eSSatish Balay }
186e5c89e4eSSatish Balay 
187e5c89e4eSSatish Balay /*@C
188e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
189e5c89e4eSSatish Balay 
190d083f849SBarry Smith    Collective
191e5c89e4eSSatish Balay 
192d8d19677SJose E. Roman    Input Parameters:
193e5bd5246SBarry Smith +  comm - communicator that will open the library
1940298fd71SBarry Smith .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
19530a1dd1fSBarry Smith .  path     - optional complete library name (if provided checks here before checking outlist)
196e5c89e4eSSatish Balay -  insymbol - name of symbol
197e5c89e4eSSatish Balay 
198e5c89e4eSSatish Balay    Output Parameter:
1990298fd71SBarry Smith .  value - if symbol not found then this value is set to NULL
200e5c89e4eSSatish Balay 
201e5c89e4eSSatish Balay    Level: developer
202e5c89e4eSSatish Balay 
20395452b02SPatrick Sanan    Notes:
20495452b02SPatrick Sanan     Symbol can be of the form
205e5c89e4eSSatish Balay         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
206e5c89e4eSSatish Balay 
207e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
208e5c89e4eSSatish Balay 
209e5c89e4eSSatish Balay @*/
2109371c9d4SSatish Balay PetscErrorCode PetscDLLibrarySym(MPI_Comm comm, PetscDLLibrary *outlist, const char path[], const char insymbol[], void **value) {
211b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN], suffix[16], *symbol, *s;
2120298fd71SBarry Smith   PetscDLLibrary nlist, prev, list = NULL;
213e5c89e4eSSatish Balay 
214e5c89e4eSSatish Balay   PetscFunctionBegin;
215340b11eeSBarry Smith   if (outlist) PetscValidPointer(outlist, 2);
2165673baf8SLisandro Dalcin   if (path) PetscValidCharPointer(path, 3);
2175673baf8SLisandro Dalcin   PetscValidCharPointer(insymbol, 4);
2185673baf8SLisandro Dalcin   PetscValidPointer(value, 5);
2195673baf8SLisandro Dalcin 
220340b11eeSBarry Smith   if (outlist) list = *outlist;
22102c9f0b5SLisandro Dalcin   *value = NULL;
222e5c89e4eSSatish Balay 
2239566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(insymbol, '(', &s));
2242d53ad75SBarry Smith   if (s) {
225e5c89e4eSSatish Balay     /* make copy of symbol so we can edit it in place */
2269566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(insymbol, &symbol));
227b3bb0f5eSLisandro Dalcin     /* If symbol contains () then replace with a NULL, to support functionname() */
2289566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(symbol, '(', &s));
2292d53ad75SBarry Smith     s[0] = 0;
230a297a907SKarl Rupp   } else symbol = (char *)insymbol;
231e5c89e4eSSatish Balay 
232e5c89e4eSSatish Balay   /*
233e5c89e4eSSatish Balay        Function name does include library
234e5c89e4eSSatish Balay        -------------------------------------
235e5c89e4eSSatish Balay   */
236e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
237b3bb0f5eSLisandro Dalcin     /* copy path and remove suffix from libname */
2389566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN));
2399566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
2409566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
2419566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(libname, suffix, &s));
242b3bb0f5eSLisandro Dalcin     if (s) s[0] = 0;
2435673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
24402c9f0b5SLisandro Dalcin     prev  = NULL;
245b3bb0f5eSLisandro Dalcin     nlist = list;
246e5c89e4eSSatish Balay     while (nlist) {
247ace3abfcSBarry Smith       PetscBool match;
2489566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(nlist->libname, libname, &match));
2495673baf8SLisandro Dalcin       if (match) goto done;
250e5c89e4eSSatish Balay       prev  = nlist;
251e5c89e4eSSatish Balay       nlist = nlist->next;
252e5c89e4eSSatish Balay     }
253b3bb0f5eSLisandro Dalcin     /* open the library and append it to path */
2549566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryOpen(comm, path, &nlist));
2559566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", path));
256a297a907SKarl Rupp     if (prev) prev->next = nlist;
2579371c9d4SSatish Balay     else {
2589371c9d4SSatish Balay       if (outlist) *outlist = nlist;
2599371c9d4SSatish Balay     }
260e5c89e4eSSatish Balay 
261e5c89e4eSSatish Balay   done:;
2629566063dSJacob Faibussowitsch     PetscCall(PetscDLSym(nlist->handle, symbol, value));
263*48a46eb9SPierre Jolivet     if (*value) PetscCall(PetscInfo(NULL, "Loading function %s from dynamic library %s\n", insymbol, path));
264e5c89e4eSSatish Balay 
265e5c89e4eSSatish Balay     /*
266e5c89e4eSSatish Balay          Function name does not include library so search path
267e5c89e4eSSatish Balay          -----------------------------------------------------
268e5c89e4eSSatish Balay     */
269e5c89e4eSSatish Balay   } else {
270e5c89e4eSSatish Balay     while (list) {
2719566063dSJacob Faibussowitsch       PetscCall(PetscDLSym(list->handle, symbol, value));
272e5c89e4eSSatish Balay       if (*value) {
2739566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Loading symbol %s from dynamic library %s\n", symbol, list->libname));
274e5c89e4eSSatish Balay         break;
275e5c89e4eSSatish Balay       }
276e5c89e4eSSatish Balay       list = list->next;
277e5c89e4eSSatish Balay     }
278e5c89e4eSSatish Balay     if (!*value) {
2799566063dSJacob Faibussowitsch       PetscCall(PetscDLSym(NULL, symbol, value));
280*48a46eb9SPierre Jolivet       if (*value) PetscCall(PetscInfo(NULL, "Loading symbol %s from object code\n", symbol));
281e5c89e4eSSatish Balay     }
282e5c89e4eSSatish Balay   }
283e5c89e4eSSatish Balay 
284*48a46eb9SPierre Jolivet   if (symbol != insymbol) PetscCall(PetscFree(symbol));
285e5c89e4eSSatish Balay   PetscFunctionReturn(0);
286e5c89e4eSSatish Balay }
287e5c89e4eSSatish Balay 
288e5c89e4eSSatish Balay /*@C
289e5c89e4eSSatish Balay      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
290e5c89e4eSSatish Balay                 of the search path.
291e5c89e4eSSatish Balay 
292d083f849SBarry Smith      Collective
293e5c89e4eSSatish Balay 
294e5c89e4eSSatish Balay      Input Parameters:
295e5c89e4eSSatish Balay +     comm - MPI communicator
2960f31fb7fSLisandro Dalcin -     path - name of the library
297e5c89e4eSSatish Balay 
298e5c89e4eSSatish Balay      Output Parameter:
299e5c89e4eSSatish Balay .     outlist - list of libraries
300e5c89e4eSSatish Balay 
301e5c89e4eSSatish Balay      Level: developer
302e5c89e4eSSatish Balay 
30395452b02SPatrick Sanan      Notes:
30495452b02SPatrick Sanan     if library is already in path will not add it.
305bb84e0fdSBarry Smith 
306bb84e0fdSBarry Smith   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
307bb84e0fdSBarry Smith       when the library is opened.
308bb84e0fdSBarry Smith 
309db781477SPatrick Sanan .seealso: `PetscDLLibraryOpen()`
310e5c89e4eSSatish Balay @*/
3119371c9d4SSatish Balay PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[]) {
312e5bd5246SBarry Smith   PetscDLLibrary list, prev;
313e5c89e4eSSatish Balay   size_t         len;
314ace3abfcSBarry Smith   PetscBool      match, dir;
315b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
316b3bb0f5eSLisandro Dalcin   char          *libname, suffix[16], *s;
3179c9d3cfdSBarry Smith   PetscToken     token;
318e5c89e4eSSatish Balay 
319e5c89e4eSSatish Balay   PetscFunctionBegin;
320b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist, 2);
321e5c89e4eSSatish Balay 
322b3bb0f5eSLisandro Dalcin   /* is path a directory? */
3239566063dSJacob Faibussowitsch   PetscCall(PetscTestDirectory(path, 'r', &dir));
324e5c89e4eSSatish Balay   if (dir) {
3259566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
3269566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(program, path, sizeof(program)));
3279566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(program, &len));
328e5c89e4eSSatish Balay     if (program[len - 1] == '/') {
3299566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
330e5c89e4eSSatish Balay     } else {
3319566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
332e5c89e4eSSatish Balay     }
3339566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
334e5c89e4eSSatish Balay 
3359566063dSJacob Faibussowitsch     PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
336e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
337e5c89e4eSSatish Balay   } else {
3389566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
339e5c89e4eSSatish Balay   }
3409566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
3419566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
342e5c89e4eSSatish Balay 
3439566063dSJacob Faibussowitsch   PetscCall(PetscTokenCreate(found, '\n', &token));
3449566063dSJacob Faibussowitsch   PetscCall(PetscTokenFind(token, &libname));
345b3bb0f5eSLisandro Dalcin   while (libname) {
346b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
3479566063dSJacob Faibussowitsch     PetscCall(PetscStrrstr(libname, suffix, &s));
348e5c89e4eSSatish Balay     if (s) s[0] = 0;
349e5c89e4eSSatish Balay     /* see if library was already open then we are done */
350e5c89e4eSSatish Balay     list = prev = *outlist;
351e5c89e4eSSatish Balay     match       = PETSC_FALSE;
352e5c89e4eSSatish Balay     while (list) {
3539566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(list->libname, libname, &match));
354e5c89e4eSSatish Balay       if (match) break;
355e5c89e4eSSatish Balay       prev = list;
356e5c89e4eSSatish Balay       list = list->next;
357e5c89e4eSSatish Balay     }
358b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
359b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
360e5c89e4eSSatish Balay     if (!match) {
3615673baf8SLisandro Dalcin       /* open the library and add to end of list */
3629566063dSJacob Faibussowitsch       PetscCall(PetscDLLibraryOpen(comm, libname, &list));
3639566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", libname));
364a297a907SKarl Rupp       if (!*outlist) *outlist = list;
365a297a907SKarl Rupp       else prev->next = list;
366e5c89e4eSSatish Balay     }
3679566063dSJacob Faibussowitsch     PetscCall(PetscTokenFind(token, &libname));
368e5c89e4eSSatish Balay   }
3699566063dSJacob Faibussowitsch   PetscCall(PetscTokenDestroy(&token));
370e5c89e4eSSatish Balay   PetscFunctionReturn(0);
371e5c89e4eSSatish Balay }
372e5c89e4eSSatish Balay 
373e5c89e4eSSatish Balay /*@C
374e5c89e4eSSatish Balay      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
375e5c89e4eSSatish Balay                  the search path.
376e5c89e4eSSatish Balay 
377d083f849SBarry Smith      Collective
378e5c89e4eSSatish Balay 
379e5c89e4eSSatish Balay      Input Parameters:
380e5c89e4eSSatish Balay +     comm - MPI communicator
3810f31fb7fSLisandro Dalcin -     path - name of the library
382e5c89e4eSSatish Balay 
383e5c89e4eSSatish Balay      Output Parameter:
384e5c89e4eSSatish Balay .     outlist - list of libraries
385e5c89e4eSSatish Balay 
386e5c89e4eSSatish Balay      Level: developer
387e5c89e4eSSatish Balay 
38895452b02SPatrick Sanan      Notes:
38995452b02SPatrick Sanan     If library is already in path will remove old reference.
390e5c89e4eSSatish Balay 
391e5c89e4eSSatish Balay @*/
3929371c9d4SSatish Balay PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[]) {
393e5bd5246SBarry Smith   PetscDLLibrary list, prev;
394e5c89e4eSSatish Balay   size_t         len;
395ace3abfcSBarry Smith   PetscBool      match, dir;
396b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
397b3bb0f5eSLisandro Dalcin   char          *libname, suffix[16], *s;
3985b096c79SMatthew Knepley   PetscToken     token;
399e5c89e4eSSatish Balay 
400e5c89e4eSSatish Balay   PetscFunctionBegin;
401b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist, 2);
402e5c89e4eSSatish Balay 
403b3bb0f5eSLisandro Dalcin   /* is path a directory? */
4049566063dSJacob Faibussowitsch   PetscCall(PetscTestDirectory(path, 'r', &dir));
405e5c89e4eSSatish Balay   if (dir) {
4069566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
4079566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(program, path, sizeof(program)));
4089566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(program, &len));
409e5c89e4eSSatish Balay     if (program[len - 1] == '/') {
4109566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
411e5c89e4eSSatish Balay     } else {
4129566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
413e5c89e4eSSatish Balay     }
4149566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
415e5c89e4eSSatish Balay 
4169566063dSJacob Faibussowitsch     PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
417e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
418e5c89e4eSSatish Balay   } else {
4199566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
420e5c89e4eSSatish Balay   }
421e5c89e4eSSatish Balay 
4229566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
4239566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
424e5c89e4eSSatish Balay 
4259566063dSJacob Faibussowitsch   PetscCall(PetscTokenCreate(found, '\n', &token));
4269566063dSJacob Faibussowitsch   PetscCall(PetscTokenFind(token, &libname));
427b3bb0f5eSLisandro Dalcin   while (libname) {
428b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
4299566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(libname, suffix, &s));
430e5c89e4eSSatish Balay     if (s) s[0] = 0;
431e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
43202c9f0b5SLisandro Dalcin     prev  = NULL;
433b3bb0f5eSLisandro Dalcin     list  = *outlist;
434e5c89e4eSSatish Balay     match = PETSC_FALSE;
435e5c89e4eSSatish Balay     while (list) {
4369566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(list->libname, libname, &match));
437e5c89e4eSSatish Balay       if (match) {
4389566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Moving %s to begin of dynamic library search path\n", libname));
439e5c89e4eSSatish Balay         if (prev) prev->next = list->next;
440b3bb0f5eSLisandro Dalcin         if (prev) list->next = *outlist;
441e5c89e4eSSatish Balay         *outlist = list;
442e5c89e4eSSatish Balay         break;
443e5c89e4eSSatish Balay       }
444e5c89e4eSSatish Balay       prev = list;
445e5c89e4eSSatish Balay       list = list->next;
446e5c89e4eSSatish Balay     }
447b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
448b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
449e5c89e4eSSatish Balay     if (!match) {
4505673baf8SLisandro Dalcin       /* open the library and add to front of list */
4519566063dSJacob Faibussowitsch       PetscCall(PetscDLLibraryOpen(comm, libname, &list));
4529566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Prepending %s to dynamic library search path\n", libname));
453ebd79076SLisandro Dalcin       list->next = *outlist;
454e5c89e4eSSatish Balay       *outlist   = list;
455e5c89e4eSSatish Balay     }
4569566063dSJacob Faibussowitsch     PetscCall(PetscTokenFind(token, &libname));
457e5c89e4eSSatish Balay   }
4589566063dSJacob Faibussowitsch   PetscCall(PetscTokenDestroy(&token));
459e5c89e4eSSatish Balay   PetscFunctionReturn(0);
460e5c89e4eSSatish Balay }
461e5c89e4eSSatish Balay 
462e5c89e4eSSatish Balay /*@C
463e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
464e5c89e4eSSatish Balay 
465e5c89e4eSSatish Balay     Collective on PetscDLLibrary
466e5c89e4eSSatish Balay 
467e5c89e4eSSatish Balay     Input Parameter:
4683fa76a5bSLisandro Dalcin .     head - library list
469e5c89e4eSSatish Balay 
470e5c89e4eSSatish Balay      Level: developer
471e5c89e4eSSatish Balay 
472e5c89e4eSSatish Balay @*/
4739371c9d4SSatish Balay PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list) {
474ace3abfcSBarry Smith   PetscBool      done = PETSC_FALSE;
4750f31fb7fSLisandro Dalcin   PetscDLLibrary prev, tail;
476e5c89e4eSSatish Balay 
477e5c89e4eSSatish Balay   PetscFunctionBegin;
4780f31fb7fSLisandro Dalcin   if (!list) PetscFunctionReturn(0);
4793fa76a5bSLisandro Dalcin   /* traverse the list in reverse order */
4803fa76a5bSLisandro Dalcin   while (!done) {
4810f31fb7fSLisandro Dalcin     if (!list->next) done = PETSC_TRUE;
4820f31fb7fSLisandro Dalcin     prev = tail = list;
4833fa76a5bSLisandro Dalcin     while (tail->next) {
4843fa76a5bSLisandro Dalcin       prev = tail;
4853fa76a5bSLisandro Dalcin       tail = tail->next;
486e5c89e4eSSatish Balay     }
48702c9f0b5SLisandro Dalcin     prev->next = NULL;
4883fa76a5bSLisandro Dalcin     /* close the dynamic library and free the space in entry data-structure*/
4899566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Closing dynamic library %s\n", tail->libname));
4909566063dSJacob Faibussowitsch     PetscCall(PetscDLClose(&tail->handle));
4919566063dSJacob Faibussowitsch     PetscCall(PetscFree(tail));
492a297a907SKarl Rupp   }
493e5c89e4eSSatish Balay   PetscFunctionReturn(0);
494e5c89e4eSSatish Balay }
495