Actual source code: dl.c
1: /*
2: Routines for opening dynamic link libraries (DLLs), keeping a searchable
3: path of DLLs, obtaining remote DLLs via a URL and opening them locally.
4: */
6: #include <petsc/private/petscimpl.h>
8: /* ------------------------------------------------------------------------------*/
9: /*
10: Code to maintain a list of opened dynamic libraries and load symbols
11: */
12: struct _n_PetscDLLibrary {
13: PetscDLLibrary next;
14: PetscDLHandle handle;
15: char libname[PETSC_MAX_PATH_LEN];
16: };
18: PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs)
19: {
20: PetscFunctionBegin;
21: while (libs) {
22: PetscCall(PetscErrorPrintf(" %s\n", libs->libname));
23: libs = libs->next;
24: }
25: PetscFunctionReturn(PETSC_SUCCESS);
26: }
28: /*@C
29: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
30: (if it is remote), indicates if it exits and its local name.
32: Collective
34: Input Parameters:
35: + comm - processors that are opening the library
36: - libname - name of the library, can be relative or absolute
38: Output Parameters:
39: + name - actual name of file on local filesystem if found
40: . llen - length of the name buffer
41: - found - true if the file exists
43: Level: developer
45: Notes:
46: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
48: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
49: occurring in directoryname and filename will be replaced with appropriate values.
50: @*/
51: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm, const char libname[], char *lname, size_t llen, PetscBool *found)
52: {
53: char *buf, *par2, *gz = NULL, *so = NULL;
54: size_t len, blen;
56: PetscFunctionBegin;
57: /*
58: make copy of library name and replace $PETSC_ARCH etc
59: so we can add to the end of it to look for something like .so.1.0 etc.
60: */
61: PetscCall(PetscStrlen(libname, &len));
62: blen = PetscMax(4 * len, PETSC_MAX_PATH_LEN);
63: PetscCall(PetscMalloc1(blen, &buf));
64: par2 = buf;
65: PetscCall(PetscStrreplace(comm, libname, par2, blen));
67: /* temporarily remove .gz if it ends library name */
68: PetscCall(PetscStrrstr(par2, ".gz", &gz));
69: if (gz) {
70: PetscCall(PetscStrlen(gz, &len));
71: if (len != 3) gz = NULL; /* do not end (exactly) with .gz */
72: else *gz = 0; /* ends with .gz, so remove it */
73: }
74: /* strip out .a from it if user put it in by mistake */
75: PetscCall(PetscStrlen(par2, &len));
76: if (par2[len - 1] == 'a' && par2[len - 2] == '.') par2[len - 2] = 0;
78: PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
79: if (!(*found)) {
80: const char suffix[] = "." PETSC_SLSUFFIX;
82: /* see if library name does already not have suffix attached */
83: PetscCall(PetscStrrstr(par2, suffix, &so));
84: /* and attach the suffix if it is not there */
85: if (!so) PetscCall(PetscStrlcat(par2, suffix, blen));
87: /* restore the .gz suffix if it was there */
88: if (gz) PetscCall(PetscStrlcat(par2, ".gz", blen));
90: /* and finally retrieve the file */
91: PetscCall(PetscFileRetrieve(comm, par2, lname, llen, found));
92: }
94: PetscCall(PetscFree(buf));
95: PetscFunctionReturn(PETSC_SUCCESS);
96: }
98: /*@C
99: PetscDLLibraryOpen - Opens a PETSc dynamic link library
101: Collective
103: Input Parameters:
104: + comm - processors that are opening the library
105: - path - name of the library, can be relative or absolute
107: Output Parameter:
108: . entry - a PETSc dynamic link library entry
110: Level: developer
112: Notes:
113: [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
115: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
116: when the library is opened.
118: ${PETSC_ARCH} occurring in directoryname and filename
119: will be replaced with the appropriate value.
121: .seealso: `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`
122: @*/
123: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm, const char path[], PetscDLLibrary *entry)
124: {
125: PetscBool foundlibrary, match;
126: const char suffix[] = "." PETSC_SLSUFFIX;
127: char libname[PETSC_MAX_PATH_LEN], par2[PETSC_MAX_PATH_LEN], *s;
128: char *basename, registername[128];
129: PetscDLHandle handle;
130: PetscErrorCode (*func)(void) = NULL;
132: PetscFunctionBegin;
136: *entry = NULL;
138: /* retrieve the library */
139: PetscCall(PetscInfo(NULL, "Retrieving %s\n", path));
140: PetscCall(PetscDLLibraryRetrieve(comm, path, par2, PETSC_MAX_PATH_LEN, &foundlibrary));
141: PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate dynamic library:\n %s", path);
142: /* Eventually ./configure should determine if the system needs an executable dynamic library */
143: #define PETSC_USE_NONEXECUTABLE_SO
144: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
145: PetscCall(PetscTestFile(par2, 'x', &foundlibrary));
146: PetscCheck(foundlibrary, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Dynamic library is not executable:\n %s\n %s", path, par2);
147: #endif
149: /* copy path and setup shared library suffix */
150: PetscCall(PetscStrncpy(libname, path, sizeof(libname)));
151: /* remove wrong suffixes from libname */
152: PetscCall(PetscStrrstr(libname, ".gz", &s));
153: if (s && s[3] == 0) s[0] = 0;
154: PetscCall(PetscStrrstr(libname, ".a", &s));
155: if (s && s[2] == 0) s[0] = 0;
156: /* remove shared suffix from libname */
157: PetscCall(PetscStrrstr(libname, suffix, &s));
158: if (s) s[0] = 0;
160: /* open the dynamic library */
161: PetscCall(PetscInfo(NULL, "Opening dynamic library %s\n", libname));
162: PetscCall(PetscDLOpen(par2, PETSC_DL_DECIDE, &handle));
164: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
165: PetscCall(PetscStrrchr(libname, '/', &basename)); /* XXX Windows ??? */
166: if (!basename) basename = libname;
167: PetscCall(PetscStrncmp(basename, "lib", 3, &match));
168: if (match) basename = basename + 3;
169: else PetscCall(PetscInfo(NULL, "Dynamic library %s does not have lib prefix\n", libname));
170: for (s = basename; *s; s++)
171: if (*s == '-') *s = '_';
172: PetscCall(PetscStrncpy(registername, "PetscDLLibraryRegister_", sizeof(registername)));
173: PetscCall(PetscStrlcat(registername, basename, sizeof(registername)));
174: PetscCall(PetscDLSym(handle, registername, (void **)&func));
175: if (func) {
176: PetscCall(PetscInfo(NULL, "Loading registered routines from %s\n", libname));
177: PetscCall((*func)());
178: } else {
179: PetscCall(PetscInfo(NULL, "Dynamic library %s does not have symbol %s\n", libname, registername));
180: }
182: PetscCall(PetscNew(entry));
183: (*entry)->next = NULL;
184: (*entry)->handle = handle;
185: PetscCall(PetscStrncpy((*entry)->libname, libname, sizeof((*entry)->libname)));
186: PetscFunctionReturn(PETSC_SUCCESS);
187: }
189: /*@C
190: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
192: Collective
194: Input Parameters:
195: + comm - communicator that will open the library
196: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
197: . path - optional complete library name (if provided checks here before checking outlist)
198: - insymbol - name of symbol
200: Output Parameter:
201: . value - if symbol not found then this value is set to NULL
203: Level: developer
205: Notes:
206: Symbol can be of the form
207: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
209: Will attempt to (retrieve and) open the library if it is not yet been opened.
211: @*/
212: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm, PetscDLLibrary *outlist, const char path[], const char insymbol[], void **value)
213: {
214: char libname[PETSC_MAX_PATH_LEN], suffix[16];
215: char *symbol = NULL, *s = NULL;
216: PetscDLLibrary list = NULL, nlist, prev;
218: PetscFunctionBegin;
224: if (outlist) list = *outlist;
225: *value = NULL;
227: PetscCall(PetscStrchr(insymbol, '(', &s));
228: if (s) {
229: /* make copy of symbol so we can edit it in place */
230: PetscCall(PetscStrallocpy(insymbol, &symbol));
231: /* If symbol contains () then replace with a NULL, to support functionname() */
232: PetscCall(PetscStrchr(symbol, '(', &s));
233: s[0] = 0;
234: } else symbol = (char *)insymbol;
236: /*
237: Function name does include library
238: -------------------------------------
239: */
240: if (path && path[0] != '\0') {
241: /* copy path and remove suffix from libname */
242: PetscCall(PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN));
243: PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
244: PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
245: PetscCall(PetscStrrstr(libname, suffix, &s));
246: if (s) s[0] = 0;
247: /* Look if library is already opened and in path */
248: prev = NULL;
249: nlist = list;
250: while (nlist) {
251: PetscBool match;
252: PetscCall(PetscStrcmp(nlist->libname, libname, &match));
253: if (match) goto done;
254: prev = nlist;
255: nlist = nlist->next;
256: }
257: /* open the library and append it to path */
258: PetscCall(PetscDLLibraryOpen(comm, path, &nlist));
259: PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", path));
260: if (prev) prev->next = nlist;
261: else {
262: if (outlist) *outlist = nlist;
263: }
265: done:;
266: PetscCall(PetscDLSym(nlist->handle, symbol, value));
267: if (*value) PetscCall(PetscInfo(NULL, "Loading function %s from dynamic library %s\n", insymbol, path));
269: /*
270: Function name does not include library so search path
271: -----------------------------------------------------
272: */
273: } else {
274: while (list) {
275: PetscCall(PetscDLSym(list->handle, symbol, value));
276: if (*value) {
277: PetscCall(PetscInfo(NULL, "Loading symbol %s from dynamic library %s\n", symbol, list->libname));
278: break;
279: }
280: list = list->next;
281: }
282: if (!*value) {
283: PetscCall(PetscDLSym(NULL, symbol, value));
284: if (*value) PetscCall(PetscInfo(NULL, "Loading symbol %s from object code\n", symbol));
285: }
286: }
288: if (symbol != insymbol) PetscCall(PetscFree(symbol));
289: PetscFunctionReturn(PETSC_SUCCESS);
290: }
292: /*@C
293: PetscDLLibraryAppend - Appends another dynamic link library to the search list, to the end
294: of the search path.
296: Collective
298: Input Parameters:
299: + comm - MPI communicator
300: - path - name of the library
302: Output Parameter:
303: . outlist - list of libraries
305: Level: developer
307: Note:
308: if library is already in path will not add it.
310: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
311: when the library is opened.
313: .seealso: `PetscDLLibraryOpen()`
314: @*/
315: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
316: {
317: PetscDLLibrary list, prev;
318: size_t len;
319: PetscBool match, dir;
320: char program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
321: char *libname, suffix[16], *s = NULL;
322: PetscToken token;
324: PetscFunctionBegin;
327: /* is path a directory? */
328: PetscCall(PetscTestDirectory(path, 'r', &dir));
329: if (dir) {
330: PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
331: PetscCall(PetscStrncpy(program, path, sizeof(program)));
332: PetscCall(PetscStrlen(program, &len));
333: if (program[len - 1] == '/') {
334: PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
335: } else {
336: PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
337: }
338: PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
340: PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
341: if (!dir) PetscFunctionReturn(PETSC_SUCCESS);
342: } else {
343: PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
344: }
345: PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
346: PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
348: PetscCall(PetscTokenCreate(found, '\n', &token));
349: PetscCall(PetscTokenFind(token, &libname));
350: while (libname) {
351: /* remove suffix from libname */
352: PetscCall(PetscStrrstr(libname, suffix, &s));
353: if (s) s[0] = 0;
354: /* see if library was already open then we are done */
355: list = prev = *outlist;
356: match = PETSC_FALSE;
357: while (list) {
358: PetscCall(PetscStrcmp(list->libname, libname, &match));
359: if (match) break;
360: prev = list;
361: list = list->next;
362: }
363: /* restore suffix from libname */
364: if (s) s[0] = '.';
365: if (!match) {
366: /* open the library and add to end of list */
367: PetscCall(PetscDLLibraryOpen(comm, libname, &list));
368: PetscCall(PetscInfo(NULL, "Appending %s to dynamic library search path\n", libname));
369: if (!*outlist) *outlist = list;
370: else prev->next = list;
371: }
372: PetscCall(PetscTokenFind(token, &libname));
373: }
374: PetscCall(PetscTokenDestroy(&token));
375: PetscFunctionReturn(PETSC_SUCCESS);
376: }
378: /*@C
379: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
380: the search path.
382: Collective
384: Input Parameters:
385: + comm - MPI communicator
386: - path - name of the library
388: Output Parameter:
389: . outlist - list of libraries
391: Level: developer
393: Note:
394: If library is already in path will remove old reference.
396: @*/
397: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
398: {
399: PetscDLLibrary list, prev;
400: size_t len;
401: PetscBool match, dir;
402: char program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
403: char *libname, suffix[16], *s = NULL;
404: PetscToken token;
406: PetscFunctionBegin;
409: /* is path a directory? */
410: PetscCall(PetscTestDirectory(path, 'r', &dir));
411: if (dir) {
412: PetscCall(PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path));
413: PetscCall(PetscStrncpy(program, path, sizeof(program)));
414: PetscCall(PetscStrlen(program, &len));
415: if (program[len - 1] == '/') {
416: PetscCall(PetscStrlcat(program, "*.", sizeof(program)));
417: } else {
418: PetscCall(PetscStrlcat(program, "/*.", sizeof(program)));
419: }
420: PetscCall(PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program)));
422: PetscCall(PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir));
423: if (!dir) PetscFunctionReturn(PETSC_SUCCESS);
424: } else {
425: PetscCall(PetscStrncpy(found, path, PETSC_MAX_PATH_LEN));
426: }
428: PetscCall(PetscStrncpy(suffix, ".", sizeof(suffix)));
429: PetscCall(PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix)));
431: PetscCall(PetscTokenCreate(found, '\n', &token));
432: PetscCall(PetscTokenFind(token, &libname));
433: while (libname) {
434: /* remove suffix from libname */
435: PetscCall(PetscStrstr(libname, suffix, &s));
436: if (s) s[0] = 0;
437: /* see if library was already open and move it to the front */
438: prev = NULL;
439: list = *outlist;
440: match = PETSC_FALSE;
441: while (list) {
442: PetscCall(PetscStrcmp(list->libname, libname, &match));
443: if (match) {
444: PetscCall(PetscInfo(NULL, "Moving %s to begin of dynamic library search path\n", libname));
445: if (prev) prev->next = list->next;
446: if (prev) list->next = *outlist;
447: *outlist = list;
448: break;
449: }
450: prev = list;
451: list = list->next;
452: }
453: /* restore suffix from libname */
454: if (s) s[0] = '.';
455: if (!match) {
456: /* open the library and add to front of list */
457: PetscCall(PetscDLLibraryOpen(comm, libname, &list));
458: PetscCall(PetscInfo(NULL, "Prepending %s to dynamic library search path\n", libname));
459: list->next = *outlist;
460: *outlist = list;
461: }
462: PetscCall(PetscTokenFind(token, &libname));
463: }
464: PetscCall(PetscTokenDestroy(&token));
465: PetscFunctionReturn(PETSC_SUCCESS);
466: }
468: /*@C
469: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
471: Collective
473: Input Parameter:
474: . head - library list
476: Level: developer
478: @*/
479: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
480: {
481: PetscBool done = PETSC_FALSE;
482: PetscDLLibrary prev, tail;
484: PetscFunctionBegin;
485: if (!list) PetscFunctionReturn(PETSC_SUCCESS);
486: /* traverse the list in reverse order */
487: while (!done) {
488: if (!list->next) done = PETSC_TRUE;
489: prev = tail = list;
490: while (tail->next) {
491: prev = tail;
492: tail = tail->next;
493: }
494: prev->next = NULL;
495: /* close the dynamic library and free the space in entry data-structure*/
496: PetscCall(PetscInfo(NULL, "Closing dynamic library %s\n", tail->libname));
497: PetscCall(PetscDLClose(&tail->handle));
498: PetscCall(PetscFree(tail));
499: }
500: PetscFunctionReturn(PETSC_SUCCESS);
501: }