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: while (libs) {
21: PetscErrorPrintf(" %s\n", libs->libname);
22: libs = libs->next;
23: }
24: return 0;
25: }
27: /*@C
28: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
29: (if it is remote), indicates if it exits and its local name.
31: Collective
33: Input Parameters:
34: + comm - processors that are opening the library
35: - libname - name of the library, can be relative or absolute
37: Output Parameters:
38: + name - actual name of file on local filesystem if found
39: . llen - length of the name buffer
40: - found - true if the file exists
42: Level: developer
44: Notes:
45: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
47: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
48: occurring in directoryname and filename will be replaced with appropriate values.
49: @*/
50: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm, const char libname[], char *lname, size_t llen, PetscBool *found)
51: {
52: char *buf, *par2, suffix[16], *gz, *so;
53: size_t len;
55: /*
56: make copy of library name and replace $PETSC_ARCH etc
57: so we can add to the end of it to look for something like .so.1.0 etc.
58: */
59: PetscStrlen(libname, &len);
60: len = PetscMax(4 * len, PETSC_MAX_PATH_LEN);
61: PetscMalloc1(len, &buf);
62: par2 = buf;
63: PetscStrreplace(comm, libname, par2, len);
65: /* temporarily remove .gz if it ends library name */
66: PetscStrrstr(par2, ".gz", &gz);
67: if (gz) {
68: PetscStrlen(gz, &len);
69: if (len != 3) gz = NULL; /* do not end (exactly) with .gz */
70: else *gz = 0; /* ends with .gz, so remove it */
71: }
72: /* strip out .a from it if user put it in by mistake */
73: PetscStrlen(par2, &len);
74: if (par2[len - 1] == 'a' && par2[len - 2] == '.') par2[len - 2] = 0;
76: PetscFileRetrieve(comm, par2, lname, llen, found);
77: if (!(*found)) {
78: /* see if library name does already not have suffix attached */
79: PetscStrncpy(suffix, ".", sizeof(suffix));
80: PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));
81: PetscStrrstr(par2, suffix, &so);
82: /* and attach the suffix if it is not there */
83: if (!so) PetscStrcat(par2, suffix);
85: /* restore the .gz suffix if it was there */
86: if (gz) PetscStrcat(par2, ".gz");
88: /* and finally retrieve the file */
89: PetscFileRetrieve(comm, par2, lname, llen, found);
90: }
92: PetscFree(buf);
93: return 0;
94: }
96: /*@C
97: PetscDLLibraryOpen - Opens a PETSc dynamic link library
99: Collective
101: Input Parameters:
102: + comm - processors that are opening the library
103: - path - name of the library, can be relative or absolute
105: Output Parameter:
106: . entry - a PETSc dynamic link library entry
108: Level: developer
110: Notes:
111: [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
113: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
114: when the library is opened.
116: ${PETSC_ARCH} occurring in directoryname and filename
117: will be replaced with the appropriate value.
119: .seealso: `PetscLoadDynamicLibrary()`, `PetscDLLibraryAppend()`
120: @*/
121: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm, const char path[], PetscDLLibrary *entry)
122: {
123: PetscBool foundlibrary, match;
124: char libname[PETSC_MAX_PATH_LEN], par2[PETSC_MAX_PATH_LEN], suffix[16], *s;
125: char *basename, registername[128];
126: PetscDLHandle handle;
127: PetscErrorCode (*func)(void) = NULL;
132: *entry = NULL;
134: /* retrieve the library */
135: PetscInfo(NULL, "Retrieving %s\n", path);
136: PetscDLLibraryRetrieve(comm, path, par2, PETSC_MAX_PATH_LEN, &foundlibrary);
138: /* Eventually ./configure should determine if the system needs an executable dynamic library */
139: #define PETSC_USE_NONEXECUTABLE_SO
140: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
141: PetscTestFile(par2, 'x', &foundlibrary);
143: #endif
145: /* copy path and setup shared library suffix */
146: PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN);
147: PetscStrncpy(suffix, ".", sizeof(suffix));
148: PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));
149: /* remove wrong suffixes from libname */
150: PetscStrrstr(libname, ".gz", &s);
151: if (s && s[3] == 0) s[0] = 0;
152: PetscStrrstr(libname, ".a", &s);
153: if (s && s[2] == 0) s[0] = 0;
154: /* remove shared suffix from libname */
155: PetscStrrstr(libname, suffix, &s);
156: if (s) s[0] = 0;
158: /* open the dynamic library */
159: PetscInfo(NULL, "Opening dynamic library %s\n", libname);
160: PetscDLOpen(par2, PETSC_DL_DECIDE, &handle);
162: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
163: PetscStrrchr(libname, '/', &basename); /* XXX Windows ??? */
164: if (!basename) basename = libname;
165: PetscStrncmp(basename, "lib", 3, &match);
166: if (match) basename = basename + 3;
167: else PetscInfo(NULL, "Dynamic library %s does not have lib prefix\n", libname);
168: for (s = basename; *s; s++)
169: if (*s == '-') *s = '_';
170: PetscStrncpy(registername, "PetscDLLibraryRegister_", sizeof(registername));
171: PetscStrlcat(registername, basename, sizeof(registername));
172: PetscDLSym(handle, registername, (void **)&func);
173: if (func) {
174: PetscInfo(NULL, "Loading registered routines from %s\n", libname);
175: (*func)();
176: } else {
177: PetscInfo(NULL, "Dynamic library %s does not have symbol %s\n", libname, registername);
178: }
180: PetscNew(entry);
181: (*entry)->next = NULL;
182: (*entry)->handle = handle;
183: PetscStrcpy((*entry)->libname, libname);
184: return 0;
185: }
187: /*@C
188: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
190: Collective
192: Input Parameters:
193: + comm - communicator that will open the library
194: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
195: . path - optional complete library name (if provided checks here before checking outlist)
196: - insymbol - name of symbol
198: Output Parameter:
199: . value - if symbol not found then this value is set to NULL
201: Level: developer
203: Notes:
204: Symbol can be of the form
205: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
207: Will attempt to (retrieve and) open the library if it is not yet been opened.
209: @*/
210: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm, PetscDLLibrary *outlist, const char path[], const char insymbol[], void **value)
211: {
212: char libname[PETSC_MAX_PATH_LEN], suffix[16], *symbol, *s;
213: PetscDLLibrary nlist, prev, list = NULL;
220: if (outlist) list = *outlist;
221: *value = NULL;
223: PetscStrchr(insymbol, '(', &s);
224: if (s) {
225: /* make copy of symbol so we can edit it in place */
226: PetscStrallocpy(insymbol, &symbol);
227: /* If symbol contains () then replace with a NULL, to support functionname() */
228: PetscStrchr(symbol, '(', &s);
229: s[0] = 0;
230: } else symbol = (char *)insymbol;
232: /*
233: Function name does include library
234: -------------------------------------
235: */
236: if (path && path[0] != '\0') {
237: /* copy path and remove suffix from libname */
238: PetscStrncpy(libname, path, PETSC_MAX_PATH_LEN);
239: PetscStrncpy(suffix, ".", sizeof(suffix));
240: PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));
241: PetscStrrstr(libname, suffix, &s);
242: if (s) s[0] = 0;
243: /* Look if library is already opened and in path */
244: prev = NULL;
245: nlist = list;
246: while (nlist) {
247: PetscBool match;
248: PetscStrcmp(nlist->libname, libname, &match);
249: if (match) goto done;
250: prev = nlist;
251: nlist = nlist->next;
252: }
253: /* open the library and append it to path */
254: PetscDLLibraryOpen(comm, path, &nlist);
255: PetscInfo(NULL, "Appending %s to dynamic library search path\n", path);
256: if (prev) prev->next = nlist;
257: else {
258: if (outlist) *outlist = nlist;
259: }
261: done:;
262: PetscDLSym(nlist->handle, symbol, value);
263: if (*value) PetscInfo(NULL, "Loading function %s from dynamic library %s\n", insymbol, path);
265: /*
266: Function name does not include library so search path
267: -----------------------------------------------------
268: */
269: } else {
270: while (list) {
271: PetscDLSym(list->handle, symbol, value);
272: if (*value) {
273: PetscInfo(NULL, "Loading symbol %s from dynamic library %s\n", symbol, list->libname);
274: break;
275: }
276: list = list->next;
277: }
278: if (!*value) {
279: PetscDLSym(NULL, symbol, value);
280: if (*value) PetscInfo(NULL, "Loading symbol %s from object code\n", symbol);
281: }
282: }
284: if (symbol != insymbol) PetscFree(symbol);
285: return 0;
286: }
288: /*@C
289: PetscDLLibraryAppend - Appends another dynamic link library to the search list, to the end
290: of the search path.
292: Collective
294: Input Parameters:
295: + comm - MPI communicator
296: - path - name of the library
298: Output Parameter:
299: . outlist - list of libraries
301: Level: developer
303: Note:
304: if library is already in path will not add it.
306: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
307: when the library is opened.
309: .seealso: `PetscDLLibraryOpen()`
310: @*/
311: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
312: {
313: PetscDLLibrary list, prev;
314: size_t len;
315: PetscBool match, dir;
316: char program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
317: char *libname, suffix[16], *s;
318: PetscToken token;
322: /* is path a directory? */
323: PetscTestDirectory(path, 'r', &dir);
324: if (dir) {
325: PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path);
326: PetscStrncpy(program, path, sizeof(program));
327: PetscStrlen(program, &len);
328: if (program[len - 1] == '/') {
329: PetscStrlcat(program, "*.", sizeof(program));
330: } else {
331: PetscStrlcat(program, "/*.", sizeof(program));
332: }
333: PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program));
335: PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir);
336: if (!dir) return 0;
337: } else {
338: PetscStrncpy(found, path, PETSC_MAX_PATH_LEN);
339: }
340: PetscStrncpy(suffix, ".", sizeof(suffix));
341: PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));
343: PetscTokenCreate(found, '\n', &token);
344: PetscTokenFind(token, &libname);
345: while (libname) {
346: /* remove suffix from libname */
347: PetscStrrstr(libname, suffix, &s);
348: if (s) s[0] = 0;
349: /* see if library was already open then we are done */
350: list = prev = *outlist;
351: match = PETSC_FALSE;
352: while (list) {
353: PetscStrcmp(list->libname, libname, &match);
354: if (match) break;
355: prev = list;
356: list = list->next;
357: }
358: /* restore suffix from libname */
359: if (s) s[0] = '.';
360: if (!match) {
361: /* open the library and add to end of list */
362: PetscDLLibraryOpen(comm, libname, &list);
363: PetscInfo(NULL, "Appending %s to dynamic library search path\n", libname);
364: if (!*outlist) *outlist = list;
365: else prev->next = list;
366: }
367: PetscTokenFind(token, &libname);
368: }
369: PetscTokenDestroy(&token);
370: return 0;
371: }
373: /*@C
374: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
375: the search path.
377: Collective
379: Input Parameters:
380: + comm - MPI communicator
381: - path - name of the library
383: Output Parameter:
384: . outlist - list of libraries
386: Level: developer
388: Note:
389: If library is already in path will remove old reference.
391: @*/
392: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm, PetscDLLibrary *outlist, const char path[])
393: {
394: PetscDLLibrary list, prev;
395: size_t len;
396: PetscBool match, dir;
397: char program[PETSC_MAX_PATH_LEN], found[8 * PETSC_MAX_PATH_LEN];
398: char *libname, suffix[16], *s;
399: PetscToken token;
403: /* is path a directory? */
404: PetscTestDirectory(path, 'r', &dir);
405: if (dir) {
406: PetscInfo(NULL, "Checking directory %s for dynamic libraries\n", path);
407: PetscStrncpy(program, path, sizeof(program));
408: PetscStrlen(program, &len);
409: if (program[len - 1] == '/') {
410: PetscStrlcat(program, "*.", sizeof(program));
411: } else {
412: PetscStrlcat(program, "/*.", sizeof(program));
413: }
414: PetscStrlcat(program, PETSC_SLSUFFIX, sizeof(program));
416: PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir);
417: if (!dir) return 0;
418: } else {
419: PetscStrncpy(found, path, PETSC_MAX_PATH_LEN);
420: }
422: PetscStrncpy(suffix, ".", sizeof(suffix));
423: PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));
425: PetscTokenCreate(found, '\n', &token);
426: PetscTokenFind(token, &libname);
427: while (libname) {
428: /* remove suffix from libname */
429: PetscStrstr(libname, suffix, &s);
430: if (s) s[0] = 0;
431: /* see if library was already open and move it to the front */
432: prev = NULL;
433: list = *outlist;
434: match = PETSC_FALSE;
435: while (list) {
436: PetscStrcmp(list->libname, libname, &match);
437: if (match) {
438: PetscInfo(NULL, "Moving %s to begin of dynamic library search path\n", libname);
439: if (prev) prev->next = list->next;
440: if (prev) list->next = *outlist;
441: *outlist = list;
442: break;
443: }
444: prev = list;
445: list = list->next;
446: }
447: /* restore suffix from libname */
448: if (s) s[0] = '.';
449: if (!match) {
450: /* open the library and add to front of list */
451: PetscDLLibraryOpen(comm, libname, &list);
452: PetscInfo(NULL, "Prepending %s to dynamic library search path\n", libname);
453: list->next = *outlist;
454: *outlist = list;
455: }
456: PetscTokenFind(token, &libname);
457: }
458: PetscTokenDestroy(&token);
459: return 0;
460: }
462: /*@C
463: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
465: Collective
467: Input Parameter:
468: . head - library list
470: Level: developer
472: @*/
473: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
474: {
475: PetscBool done = PETSC_FALSE;
476: PetscDLLibrary prev, tail;
478: if (!list) return 0;
479: /* traverse the list in reverse order */
480: while (!done) {
481: if (!list->next) done = PETSC_TRUE;
482: prev = tail = list;
483: while (tail->next) {
484: prev = tail;
485: tail = tail->next;
486: }
487: prev->next = NULL;
488: /* close the dynamic library and free the space in entry data-structure*/
489: PetscInfo(NULL, "Closing dynamic library %s\n", tail->libname);
490: PetscDLClose(&tail->handle);
491: PetscFree(tail);
492: }
493: return 0;
494: }