Actual source code: dl.c
petsc-3.9.4 2018-09-11
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: PetscStrncpy(suffix,".",sizeof(suffix));
83: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
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;
144: *entry = NULL;
146: /* retrieve the library */
147: PetscInfo1(0,"Retrieving %s\n",path);
148: PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
149: if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",path);
150: /* Eventually ./configure should determine if the system needs an executable dynamic library */
151: #define PETSC_USE_NONEXECUTABLE_SO
152: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
153: PetscTestFile(par2,'x',&foundlibrary);
154: if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",path,par2);
155: #endif
157: /* copy path and setup shared library suffix */
158: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
159: PetscStrncpy(suffix,".",sizeof(suffix));
160: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
161: /* remove wrong suffixes from libname */
162: PetscStrrstr(libname,".gz",&s);
163: if (s && s[3] == 0) s[0] = 0;
164: PetscStrrstr(libname,".a",&s);
165: if (s && s[2] == 0) s[0] = 0;
166: /* remove shared suffix from libname */
167: PetscStrrstr(libname,suffix,&s);
168: if (s) s[0] = 0;
170: /* open the dynamic library */
171: PetscInfo1(0,"Opening dynamic library %s\n",libname);
172: PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);
174: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
175: PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
176: if (!basename) basename = libname;
177: PetscStrncmp(basename,"lib",3,&match);
178: if (match) basename = basename + 3;
179: else {
180: PetscInfo1(0,"Dynamic library %s does not have lib prefix\n",libname);
181: }
182: for (s=basename; *s; s++) if (*s == '-') *s = '_';
183: PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername));
184: PetscStrlcat(registername,basename,sizeof(registername));
185: PetscDLSym(handle,registername,(void**)&func);
186: if (func) {
187: PetscInfo1(0,"Loading registered routines from %s\n",libname);
188: (*func)();
189: } else {
190: PetscInfo2(0,"Dynamic library %s does not have symbol %s\n",libname,registername);
191: }
193: PetscNew(entry);
194: (*entry)->next = 0;
195: (*entry)->handle = handle;
196: PetscStrcpy((*entry)->libname,libname);
197: return(0);
198: }
200: #undef PETSC_FUNCTION_NAME
201: #if defined(__cplusplus)
202: # define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_CXX
203: #else
204: # define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_C
205: #endif
207: /*@C
208: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
210: Collective on MPI_Comm
212: Input Parameter:
213: + comm - communicator that will open the library
214: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
215: . path - optional complete library name (if provided checks here before checking outlist)
216: - insymbol - name of symbol
218: Output Parameter:
219: . value - if symbol not found then this value is set to NULL
221: Level: developer
223: Notes: Symbol can be of the form
224: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
226: Will attempt to (retrieve and) open the library if it is not yet been opened.
228: @*/
229: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
230: {
231: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
232: PetscDLLibrary nlist,prev,list = NULL;
241: if (outlist) list = *outlist;
242: *value = 0;
245: PetscStrchr(insymbol,'(',&s);
246: if (s) {
247: /* make copy of symbol so we can edit it in place */
248: PetscStrallocpy(insymbol,&symbol);
249: /* If symbol contains () then replace with a NULL, to support functionname() */
250: PetscStrchr(symbol,'(',&s);
251: s[0] = 0;
252: } else symbol = (char*)insymbol;
254: /*
255: Function name does include library
256: -------------------------------------
257: */
258: if (path && path[0] != '\0') {
259: /* copy path and remove suffix from libname */
260: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
261: PetscStrncpy(suffix,".",sizeof(suffix));
262: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
263: PetscStrrstr(libname,suffix,&s);
264: if (s) s[0] = 0;
265: /* Look if library is already opened and in path */
266: prev = 0;
267: nlist = list;
268: while (nlist) {
269: PetscBool match;
270: PetscStrcmp(nlist->libname,libname,&match);
271: if (match) goto done;
272: prev = nlist;
273: nlist = nlist->next;
274: }
275: /* open the library and append it to path */
276: PetscDLLibraryOpen(comm,path,&nlist);
277: PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
278: if (prev) prev->next = nlist;
279: else {if (outlist) *outlist = nlist;}
281: done:;
282: PetscDLSym(nlist->handle,symbol,value);
283: if (*value) {
284: PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
285: }
287: /*
288: Function name does not include library so search path
289: -----------------------------------------------------
290: */
291: } else {
292: while (list) {
293: PetscDLSym(list->handle,symbol,value);
294: if (*value) {
295: PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
296: break;
297: }
298: list = list->next;
299: }
300: if (!*value) {
301: PetscDLSym(NULL,symbol,value);
302: if (*value) {
303: PetscInfo1(0,"Loading symbol %s from object code\n",symbol);
304: }
305: }
306: }
308: if (symbol != insymbol) {
309: PetscFree(symbol);
310: }
311: return(0);
312: }
314: /*@C
315: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
316: of the search path.
318: Collective on MPI_Comm
320: Input Parameters:
321: + comm - MPI communicator
322: - path - name of the library
324: Output Parameter:
325: . outlist - list of libraries
327: Level: developer
329: Notes: if library is already in path will not add it.
331: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
332: when the library is opened.
334: .seealso: PetscDLLibraryOpen()
335: @*/
336: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
337: {
338: PetscDLLibrary list,prev;
340: size_t len;
341: PetscBool match,dir;
342: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
343: char *libname,suffix[16],*s;
344: PetscToken token;
349: /* is path a directory? */
350: PetscTestDirectory(path,'r',&dir);
351: if (dir) {
352: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
353: PetscStrncpy(program,path,sizeof(program));
354: PetscStrlen(program,&len);
355: if (program[len-1] == '/') {
356: PetscStrlcat(program,"*.",sizeof(program));
357: } else {
358: PetscStrlcat(program,"/*.",sizeof(program));
359: }
360: PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));
362: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
363: if (!dir) return(0);
364: } else {
365: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
366: }
367: PetscStrncpy(suffix,".",sizeof(suffix));
368: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
370: PetscTokenCreate(found,'\n',&token);
371: PetscTokenFind(token,&libname);
372: while (libname) {
373: /* remove suffix from libname */
374: PetscStrrstr(libname,suffix,&s);
375: if (s) s[0] = 0;
376: /* see if library was already open then we are done */
377: list = prev = *outlist;
378: match = PETSC_FALSE;
379: while (list) {
380: PetscStrcmp(list->libname,libname,&match);
381: if (match) break;
382: prev = list;
383: list = list->next;
384: }
385: /* restore suffix from libname */
386: if (s) s[0] = '.';
387: if (!match) {
388: /* open the library and add to end of list */
389: PetscDLLibraryOpen(comm,libname,&list);
390: PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
391: if (!*outlist) *outlist = list;
392: else prev->next = list;
393: }
394: PetscTokenFind(token,&libname);
395: }
396: PetscTokenDestroy(&token);
397: return(0);
398: }
400: /*@C
401: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
402: the search path.
404: Collective on MPI_Comm
406: Input Parameters:
407: + comm - MPI communicator
408: - path - name of the library
410: Output Parameter:
411: . outlist - list of libraries
413: Level: developer
415: Notes: If library is already in path will remove old reference.
417: @*/
418: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
419: {
420: PetscDLLibrary list,prev;
422: size_t len;
423: PetscBool match,dir;
424: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
425: char *libname,suffix[16],*s;
426: PetscToken token;
431: /* is path a directory? */
432: PetscTestDirectory(path,'r',&dir);
433: if (dir) {
434: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
435: PetscStrncpy(program,path,sizeof(program));
436: PetscStrlen(program,&len);
437: if (program[len-1] == '/') {
438: PetscStrlcat(program,"*.",sizeof(program));
439: } else {
440: PetscStrlcat(program,"/*.",sizeof(program));
441: }
442: PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));
444: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
445: if (!dir) return(0);
446: } else {
447: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
448: }
450: PetscStrncpy(suffix,".",sizeof(suffix));
451: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
453: PetscTokenCreate(found,'\n',&token);
454: PetscTokenFind(token,&libname);
455: while (libname) {
456: /* remove suffix from libname */
457: PetscStrstr(libname,suffix,&s);
458: if (s) s[0] = 0;
459: /* see if library was already open and move it to the front */
460: prev = 0;
461: list = *outlist;
462: match = PETSC_FALSE;
463: while (list) {
464: PetscStrcmp(list->libname,libname,&match);
465: if (match) {
466: PetscInfo1(0,"Moving %s to begin of dynamic library search path\n",libname);
467: if (prev) prev->next = list->next;
468: if (prev) list->next = *outlist;
469: *outlist = list;
470: break;
471: }
472: prev = list;
473: list = list->next;
474: }
475: /* restore suffix from libname */
476: if (s) s[0] = '.';
477: if (!match) {
478: /* open the library and add to front of list */
479: PetscDLLibraryOpen(comm,libname,&list);
480: PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname);
481: list->next = *outlist;
482: *outlist = list;
483: }
484: PetscTokenFind(token,&libname);
485: }
486: PetscTokenDestroy(&token);
487: return(0);
488: }
490: /*@C
491: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
493: Collective on PetscDLLibrary
495: Input Parameter:
496: . head - library list
498: Level: developer
500: @*/
501: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
502: {
503: PetscBool done = PETSC_FALSE;
504: PetscDLLibrary prev,tail;
508: if (!list) return(0);
509: /* traverse the list in reverse order */
510: while (!done) {
511: if (!list->next) done = PETSC_TRUE;
512: prev = tail = list;
513: while (tail->next) {
514: prev = tail;
515: tail = tail->next;
516: }
517: prev->next = 0;
518: /* close the dynamic library and free the space in entry data-structure*/
519: PetscInfo1(0,"Closing dynamic library %s\n",tail->libname);
520: PetscDLClose(&tail->handle);
521: PetscFree(tail);
522: }
523: return(0);
524: }