Actual source code: dl.c
petsc-3.7.3 2016-08-01
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: };
20: PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs)
21: {
23: while (libs) {
24: PetscErrorPrintf(" %s\n",libs->libname);
25: libs = libs->next;
26: }
27: return(0);
28: }
32: /*@C
33: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
34: (if it is remote), indicates if it exits and its local name.
36: Collective on MPI_Comm
38: Input Parameters:
39: + comm - processors that are opening the library
40: - libname - name of the library, can be relative or absolute
42: Output Parameter:
43: + name - actual name of file on local filesystem if found
44: . llen - length of the name buffer
45: - found - true if the file exists
47: Level: developer
49: Notes:
50: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
52: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
53: occuring in directoryname and filename will be replaced with appropriate values.
54: @*/
55: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool *found)
56: {
57: char *buf,*par2,suffix[16],*gz,*so;
58: size_t len;
62: /*
63: make copy of library name and replace $PETSC_ARCH etc
64: so we can add to the end of it to look for something like .so.1.0 etc.
65: */
66: PetscStrlen(libname,&len);
67: len = PetscMax(4*len,PETSC_MAX_PATH_LEN);
68: PetscMalloc1(len,&buf);
69: par2 = buf;
70: PetscStrreplace(comm,libname,par2,len);
72: /* temporarily remove .gz if it ends library name */
73: PetscStrrstr(par2,".gz",&gz);
74: if (gz) {
75: PetscStrlen(gz,&len);
76: if (len != 3) gz = 0; /* do not end (exactly) with .gz */
77: else *gz = 0; /* ends with .gz, so remove it */
78: }
79: /* strip out .a from it if user put it in by mistake */
80: PetscStrlen(par2,&len);
81: if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
83: PetscFileRetrieve(comm,par2,lname,llen,found);
84: if (!(*found)) {
85: /* see if library name does already not have suffix attached */
86: PetscStrcpy(suffix,".");
87: PetscStrcat(suffix,PETSC_SLSUFFIX);
88: PetscStrrstr(par2,suffix,&so);
89: /* and attach the suffix if it is not there */
90: if (!so) { PetscStrcat(par2,suffix); }
92: /* restore the .gz suffix if it was there */
93: if (gz) { PetscStrcat(par2,".gz"); }
95: /* and finally retrieve the file */
96: PetscFileRetrieve(comm,par2,lname,llen,found);
97: }
99: PetscFree(buf);
100: return(0);
101: }
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: }
204: /*@C
205: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
207: Collective on MPI_Comm
209: Input Parameter:
210: + comm - communicator that will open the library
211: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
212: . path - optional complete library name (if provided checks here before checking outlist)
213: - insymbol - name of symbol
215: Output Parameter:
216: . value - if symbol not found then this value is set to NULL
218: Level: developer
220: Notes: Symbol can be of the form
221: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
223: Will attempt to (retrieve and) open the library if it is not yet been opened.
225: @*/
226: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
227: {
228: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
229: PetscDLLibrary nlist,prev,list = NULL;
238: if (outlist) list = *outlist;
239: *value = 0;
242: PetscStrchr(insymbol,'(',&s);
243: if (s) {
244: /* make copy of symbol so we can edit it in place */
245: PetscStrallocpy(insymbol,&symbol);
246: /* If symbol contains () then replace with a NULL, to support functionname() */
247: PetscStrchr(symbol,'(',&s);
248: s[0] = 0;
249: } else symbol = (char*)insymbol;
251: /*
252: Function name does include library
253: -------------------------------------
254: */
255: if (path && path[0] != '\0') {
256: /* copy path and remove suffix from libname */
257: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
258: PetscStrcpy(suffix,".");
259: PetscStrcat(suffix,PETSC_SLSUFFIX);
260: PetscStrrstr(libname,suffix,&s);
261: if (s) s[0] = 0;
262: /* Look if library is already opened and in path */
263: prev = 0;
264: nlist = list;
265: while (nlist) {
266: PetscBool match;
267: PetscStrcmp(nlist->libname,libname,&match);
268: if (match) goto done;
269: prev = nlist;
270: nlist = nlist->next;
271: }
272: /* open the library and append it to path */
273: PetscDLLibraryOpen(comm,path,&nlist);
274: PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
275: if (prev) prev->next = nlist;
276: else {if (outlist) *outlist = nlist;}
278: done:;
279: PetscDLSym(nlist->handle,symbol,value);
280: if (*value) {
281: PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
282: }
284: /*
285: Function name does not include library so search path
286: -----------------------------------------------------
287: */
288: } else {
289: while (list) {
290: PetscDLSym(list->handle,symbol,value);
291: if (*value) {
292: PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
293: break;
294: }
295: list = list->next;
296: }
297: if (!*value) {
298: PetscDLSym(NULL,symbol,value);
299: if (*value) {
300: PetscInfo1(0,"Loading symbol %s from object code\n",symbol);
301: }
302: }
303: }
305: if (symbol != insymbol) {
306: PetscFree(symbol);
307: }
308: return(0);
309: }
313: /*@C
314: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
315: of the search path.
317: Collective on MPI_Comm
319: Input Parameters:
320: + comm - MPI communicator
321: - path - name of the library
323: Output Parameter:
324: . outlist - list of libraries
326: Level: developer
328: Notes: if library is already in path will not add it.
330: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
331: when the library is opened.
333: .seealso: PetscDLLibraryOpen()
334: @*/
335: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
336: {
337: PetscDLLibrary list,prev;
339: size_t len;
340: PetscBool match,dir;
341: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
342: char *libname,suffix[16],*s;
343: PetscToken token;
348: /* is path a directory? */
349: PetscTestDirectory(path,'r',&dir);
350: if (dir) {
351: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
352: PetscStrcpy(program,path);
353: PetscStrlen(program,&len);
354: if (program[len-1] == '/') {
355: PetscStrcat(program,"*.");
356: } else {
357: PetscStrcat(program,"/*.");
358: }
359: PetscStrcat(program,PETSC_SLSUFFIX);
361: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
362: if (!dir) return(0);
363: } else {
364: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
365: }
366: PetscStrcpy(suffix,".");
367: PetscStrcat(suffix,PETSC_SLSUFFIX);
369: PetscTokenCreate(found,'\n',&token);
370: PetscTokenFind(token,&libname);
371: while (libname) {
372: /* remove suffix from libname */
373: PetscStrrstr(libname,suffix,&s);
374: if (s) s[0] = 0;
375: /* see if library was already open then we are done */
376: list = prev = *outlist;
377: match = PETSC_FALSE;
378: while (list) {
379: PetscStrcmp(list->libname,libname,&match);
380: if (match) break;
381: prev = list;
382: list = list->next;
383: }
384: /* restore suffix from libname */
385: if (s) s[0] = '.';
386: if (!match) {
387: /* open the library and add to end of list */
388: PetscDLLibraryOpen(comm,libname,&list);
389: PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
390: if (!*outlist) *outlist = list;
391: else prev->next = list;
392: }
393: PetscTokenFind(token,&libname);
394: }
395: PetscTokenDestroy(&token);
396: return(0);
397: }
401: /*@C
402: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
403: the search path.
405: Collective on MPI_Comm
407: Input Parameters:
408: + comm - MPI communicator
409: - path - name of the library
411: Output Parameter:
412: . outlist - list of libraries
414: Level: developer
416: Notes: If library is already in path will remove old reference.
418: @*/
419: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
420: {
421: PetscDLLibrary list,prev;
423: size_t len;
424: PetscBool match,dir;
425: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
426: char *libname,suffix[16],*s;
427: PetscToken token;
432: /* is path a directory? */
433: PetscTestDirectory(path,'r',&dir);
434: if (dir) {
435: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
436: PetscStrcpy(program,path);
437: PetscStrlen(program,&len);
438: if (program[len-1] == '/') {
439: PetscStrcat(program,"*.");
440: } else {
441: PetscStrcat(program,"/*.");
442: }
443: PetscStrcat(program,PETSC_SLSUFFIX);
445: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
446: if (!dir) return(0);
447: } else {
448: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
449: }
451: PetscStrcpy(suffix,".");
452: PetscStrcat(suffix,PETSC_SLSUFFIX);
454: PetscTokenCreate(found,'\n',&token);
455: PetscTokenFind(token,&libname);
456: while (libname) {
457: /* remove suffix from libname */
458: PetscStrstr(libname,suffix,&s);
459: if (s) s[0] = 0;
460: /* see if library was already open and move it to the front */
461: prev = 0;
462: list = *outlist;
463: match = PETSC_FALSE;
464: while (list) {
465: PetscStrcmp(list->libname,libname,&match);
466: if (match) {
467: PetscInfo1(0,"Moving %s to begin of dynamic library search path\n",libname);
468: if (prev) prev->next = list->next;
469: if (prev) list->next = *outlist;
470: *outlist = list;
471: break;
472: }
473: prev = list;
474: list = list->next;
475: }
476: /* restore suffix from libname */
477: if (s) s[0] = '.';
478: if (!match) {
479: /* open the library and add to front of list */
480: PetscDLLibraryOpen(comm,libname,&list);
481: PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname);
482: list->next = *outlist;
483: *outlist = list;
484: }
485: PetscTokenFind(token,&libname);
486: }
487: PetscTokenDestroy(&token);
488: return(0);
489: }
493: /*@C
494: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
496: Collective on PetscDLLibrary
498: Input Parameter:
499: . head - library list
501: Level: developer
503: @*/
504: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
505: {
506: PetscBool done = PETSC_FALSE;
507: PetscDLLibrary prev,tail;
511: if (!list) return(0);
512: /* traverse the list in reverse order */
513: while (!done) {
514: if (!list->next) done = PETSC_TRUE;
515: prev = tail = list;
516: while (tail->next) {
517: prev = tail;
518: tail = tail->next;
519: }
520: prev->next = 0;
521: /* close the dynamic library and free the space in entry data-structure*/
522: PetscInfo1(0,"Closing dynamic library %s\n",tail->libname);
523: PetscDLClose(&tail->handle);
524: PetscFree(tail);
525: }
526: return(0);
527: }