Actual source code: dl.c
petsc-3.8.4 2018-03-24
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: {
21: while (libs) {
22: PetscErrorPrintf(" %s\n",libs->libname);
23: libs = libs->next;
24: }
25: return(0);
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 on MPI_Comm
34: Input Parameters:
35: + comm - processors that are opening the library
36: - libname - name of the library, can be relative or absolute
38: Output Parameter:
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: occuring 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,suffix[16],*gz,*so;
54: size_t len;
58: /*
59: make copy of library name and replace $PETSC_ARCH etc
60: so we can add to the end of it to look for something like .so.1.0 etc.
61: */
62: PetscStrlen(libname,&len);
63: len = PetscMax(4*len,PETSC_MAX_PATH_LEN);
64: PetscMalloc1(len,&buf);
65: par2 = buf;
66: PetscStrreplace(comm,libname,par2,len);
68: /* temporarily remove .gz if it ends library name */
69: PetscStrrstr(par2,".gz",&gz);
70: if (gz) {
71: PetscStrlen(gz,&len);
72: if (len != 3) gz = 0; /* do not end (exactly) with .gz */
73: else *gz = 0; /* ends with .gz, so remove it */
74: }
75: /* strip out .a from it if user put it in by mistake */
76: PetscStrlen(par2,&len);
77: if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
79: PetscFileRetrieve(comm,par2,lname,llen,found);
80: if (!(*found)) {
81: /* see if library name does already not have suffix attached */
82: PetscStrcpy(suffix,".");
83: PetscStrcat(suffix,PETSC_SLSUFFIX);
84: PetscStrrstr(par2,suffix,&so);
85: /* and attach the suffix if it is not there */
86: if (!so) { PetscStrcat(par2,suffix); }
88: /* restore the .gz suffix if it was there */
89: if (gz) { PetscStrcat(par2,".gz"); }
91: /* and finally retrieve the file */
92: PetscFileRetrieve(comm,par2,lname,llen,found);
93: }
95: PetscFree(buf);
96: return(0);
97: }
99: /*
100: Some compilers when used with -std=c89 don't produce a usable PETSC_FUNCTION_NAME. Since this name is needed in PetscMallocDump()
101: to avoid reporting the memory allocations in the function as not freed we hardwire the value here.
102: */
103: #undef PETSC_FUNCTION_NAME
104: #define PETSC_FUNCTION_NAME "PetscDLLibraryOpen"
106: /*@C
107: PetscDLLibraryOpen - Opens a PETSc dynamic link library
109: Collective on MPI_Comm
111: Input Parameters:
112: + comm - processors that are opening the library
113: - path - name of the library, can be relative or absolute
115: Output Parameter:
116: . entry - a PETSc dynamic link library entry
118: Level: developer
120: Notes:
121: [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
123: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
124: when the library is opened.
126: ${PETSC_ARCH} occuring in directoryname and filename
127: will be replaced with the appropriate value.
129: .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
130: @*/
131: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
132: {
134: PetscBool foundlibrary,match;
135: char libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
136: char *basename,registername[128];
137: PetscDLHandle handle;
138: PetscErrorCode (*func)(void) = NULL;
139: size_t len;
145: *entry = NULL;
147: /* retrieve the library */
148: PetscInfo1(0,"Retrieving %s\n",path);
149: PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
150: if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",path);
151: /* Eventually ./configure should determine if the system needs an executable dynamic library */
152: #define PETSC_USE_NONEXECUTABLE_SO
153: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
154: PetscTestFile(par2,'x',&foundlibrary);
155: if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",path,par2);
156: #endif
158: /* copy path and setup shared library suffix */
159: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
160: PetscStrcpy(suffix,".");
161: PetscStrcat(suffix,PETSC_SLSUFFIX);
162: /* remove wrong suffixes from libname */
163: PetscStrrstr(libname,".gz",&s);
164: if (s && s[3] == 0) s[0] = 0;
165: PetscStrrstr(libname,".a",&s);
166: if (s && s[2] == 0) s[0] = 0;
167: /* remove shared suffix from libname */
168: PetscStrrstr(libname,suffix,&s);
169: if (s) s[0] = 0;
171: /* open the dynamic library */
172: PetscInfo1(0,"Opening dynamic library %s\n",libname);
173: PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);
175: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
176: PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
177: if (!basename) basename = libname;
178: PetscStrncmp(basename,"lib",3,&match);
179: if (match) basename = basename + 3;
180: else {
181: PetscInfo1(0,"Dynamic library %s does not have lib prefix\n",libname);
182: }
183: for (s=basename; *s; s++) if (*s == '-') *s = '_';
184: PetscStrlen(basename,&len);
185: PetscStrcpy(registername,"PetscDLLibraryRegister_");
186: PetscStrncat(registername,basename,len);
187: PetscDLSym(handle,registername,(void**)&func);
188: if (func) {
189: PetscInfo1(0,"Loading registered routines from %s\n",libname);
190: (*func)();
191: } else {
192: PetscInfo2(0,"Dynamic library %s does not have symbol %s\n",libname,registername);
193: }
195: PetscNew(entry);
196: (*entry)->next = 0;
197: (*entry)->handle = handle;
198: PetscStrcpy((*entry)->libname,libname);
199: return(0);
200: }
202: #undef PETSC_FUNCTION_NAME
203: #if defined(__cplusplus)
204: # define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_CXX
205: #else
206: # define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_C
207: #endif
209: /*@C
210: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
212: Collective on MPI_Comm
214: Input Parameter:
215: + comm - communicator that will open the library
216: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
217: . path - optional complete library name (if provided checks here before checking outlist)
218: - insymbol - name of symbol
220: Output Parameter:
221: . value - if symbol not found then this value is set to NULL
223: Level: developer
225: Notes: Symbol can be of the form
226: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
228: Will attempt to (retrieve and) open the library if it is not yet been opened.
230: @*/
231: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
232: {
233: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
234: PetscDLLibrary nlist,prev,list = NULL;
243: if (outlist) list = *outlist;
244: *value = 0;
247: PetscStrchr(insymbol,'(',&s);
248: if (s) {
249: /* make copy of symbol so we can edit it in place */
250: PetscStrallocpy(insymbol,&symbol);
251: /* If symbol contains () then replace with a NULL, to support functionname() */
252: PetscStrchr(symbol,'(',&s);
253: s[0] = 0;
254: } else symbol = (char*)insymbol;
256: /*
257: Function name does include library
258: -------------------------------------
259: */
260: if (path && path[0] != '\0') {
261: /* copy path and remove suffix from libname */
262: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
263: PetscStrcpy(suffix,".");
264: PetscStrcat(suffix,PETSC_SLSUFFIX);
265: PetscStrrstr(libname,suffix,&s);
266: if (s) s[0] = 0;
267: /* Look if library is already opened and in path */
268: prev = 0;
269: nlist = list;
270: while (nlist) {
271: PetscBool match;
272: PetscStrcmp(nlist->libname,libname,&match);
273: if (match) goto done;
274: prev = nlist;
275: nlist = nlist->next;
276: }
277: /* open the library and append it to path */
278: PetscDLLibraryOpen(comm,path,&nlist);
279: PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
280: if (prev) prev->next = nlist;
281: else {if (outlist) *outlist = nlist;}
283: done:;
284: PetscDLSym(nlist->handle,symbol,value);
285: if (*value) {
286: PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
287: }
289: /*
290: Function name does not include library so search path
291: -----------------------------------------------------
292: */
293: } else {
294: while (list) {
295: PetscDLSym(list->handle,symbol,value);
296: if (*value) {
297: PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
298: break;
299: }
300: list = list->next;
301: }
302: if (!*value) {
303: PetscDLSym(NULL,symbol,value);
304: if (*value) {
305: PetscInfo1(0,"Loading symbol %s from object code\n",symbol);
306: }
307: }
308: }
310: if (symbol != insymbol) {
311: PetscFree(symbol);
312: }
313: return(0);
314: }
316: /*@C
317: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
318: of the search path.
320: Collective on MPI_Comm
322: Input Parameters:
323: + comm - MPI communicator
324: - path - name of the library
326: Output Parameter:
327: . outlist - list of libraries
329: Level: developer
331: Notes: if library is already in path will not add it.
333: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
334: when the library is opened.
336: .seealso: PetscDLLibraryOpen()
337: @*/
338: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
339: {
340: PetscDLLibrary list,prev;
342: size_t len;
343: PetscBool match,dir;
344: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
345: char *libname,suffix[16],*s;
346: PetscToken token;
351: /* is path a directory? */
352: PetscTestDirectory(path,'r',&dir);
353: if (dir) {
354: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
355: PetscStrcpy(program,path);
356: PetscStrlen(program,&len);
357: if (program[len-1] == '/') {
358: PetscStrcat(program,"*.");
359: } else {
360: PetscStrcat(program,"/*.");
361: }
362: PetscStrcat(program,PETSC_SLSUFFIX);
364: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
365: if (!dir) return(0);
366: } else {
367: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
368: }
369: PetscStrcpy(suffix,".");
370: PetscStrcat(suffix,PETSC_SLSUFFIX);
372: PetscTokenCreate(found,'\n',&token);
373: PetscTokenFind(token,&libname);
374: while (libname) {
375: /* remove suffix from libname */
376: PetscStrrstr(libname,suffix,&s);
377: if (s) s[0] = 0;
378: /* see if library was already open then we are done */
379: list = prev = *outlist;
380: match = PETSC_FALSE;
381: while (list) {
382: PetscStrcmp(list->libname,libname,&match);
383: if (match) break;
384: prev = list;
385: list = list->next;
386: }
387: /* restore suffix from libname */
388: if (s) s[0] = '.';
389: if (!match) {
390: /* open the library and add to end of list */
391: PetscDLLibraryOpen(comm,libname,&list);
392: PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
393: if (!*outlist) *outlist = list;
394: else prev->next = list;
395: }
396: PetscTokenFind(token,&libname);
397: }
398: PetscTokenDestroy(&token);
399: return(0);
400: }
402: /*@C
403: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
404: the search path.
406: Collective on MPI_Comm
408: Input Parameters:
409: + comm - MPI communicator
410: - path - name of the library
412: Output Parameter:
413: . outlist - list of libraries
415: Level: developer
417: Notes: If library is already in path will remove old reference.
419: @*/
420: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
421: {
422: PetscDLLibrary list,prev;
424: size_t len;
425: PetscBool match,dir;
426: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
427: char *libname,suffix[16],*s;
428: PetscToken token;
433: /* is path a directory? */
434: PetscTestDirectory(path,'r',&dir);
435: if (dir) {
436: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
437: PetscStrcpy(program,path);
438: PetscStrlen(program,&len);
439: if (program[len-1] == '/') {
440: PetscStrcat(program,"*.");
441: } else {
442: PetscStrcat(program,"/*.");
443: }
444: PetscStrcat(program,PETSC_SLSUFFIX);
446: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
447: if (!dir) return(0);
448: } else {
449: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
450: }
452: PetscStrcpy(suffix,".");
453: PetscStrcat(suffix,PETSC_SLSUFFIX);
455: PetscTokenCreate(found,'\n',&token);
456: PetscTokenFind(token,&libname);
457: while (libname) {
458: /* remove suffix from libname */
459: PetscStrstr(libname,suffix,&s);
460: if (s) s[0] = 0;
461: /* see if library was already open and move it to the front */
462: prev = 0;
463: list = *outlist;
464: match = PETSC_FALSE;
465: while (list) {
466: PetscStrcmp(list->libname,libname,&match);
467: if (match) {
468: PetscInfo1(0,"Moving %s to begin of dynamic library search path\n",libname);
469: if (prev) prev->next = list->next;
470: if (prev) list->next = *outlist;
471: *outlist = list;
472: break;
473: }
474: prev = list;
475: list = list->next;
476: }
477: /* restore suffix from libname */
478: if (s) s[0] = '.';
479: if (!match) {
480: /* open the library and add to front of list */
481: PetscDLLibraryOpen(comm,libname,&list);
482: PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname);
483: list->next = *outlist;
484: *outlist = list;
485: }
486: PetscTokenFind(token,&libname);
487: }
488: PetscTokenDestroy(&token);
489: return(0);
490: }
492: /*@C
493: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
495: Collective on PetscDLLibrary
497: Input Parameter:
498: . head - library list
500: Level: developer
502: @*/
503: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
504: {
505: PetscBool done = PETSC_FALSE;
506: PetscDLLibrary prev,tail;
510: if (!list) return(0);
511: /* traverse the list in reverse order */
512: while (!done) {
513: if (!list->next) done = PETSC_TRUE;
514: prev = tail = list;
515: while (tail->next) {
516: prev = tail;
517: tail = tail->next;
518: }
519: prev->next = 0;
520: /* close the dynamic library and free the space in entry data-structure*/
521: PetscInfo1(0,"Closing dynamic library %s\n",tail->libname);
522: PetscDLClose(&tail->handle);
523: PetscFree(tail);
524: }
525: return(0);
526: }