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: {
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
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,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 = NULL; /* 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: /*@C
100: PetscDLLibraryOpen - Opens a PETSc dynamic link library
102: Collective
104: Input Parameters:
105: + comm - processors that are opening the library
106: - path - name of the library, can be relative or absolute
108: Output Parameter:
109: . entry - a PETSc dynamic link library entry
111: Level: developer
113: Notes:
114: [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
116: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
117: when the library is opened.
119: ${PETSC_ARCH} occurring in directoryname and filename
120: will be replaced with the appropriate value.
122: .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
123: @*/
124: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
125: {
127: PetscBool foundlibrary,match;
128: char libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
129: char *basename,registername[128];
130: PetscDLHandle handle;
131: PetscErrorCode (*func)(void) = NULL;
137: *entry = NULL;
139: /* retrieve the library */
140: PetscInfo1(NULL,"Retrieving %s\n",path);
141: PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
142: if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",path);
143: /* Eventually ./configure should determine if the system needs an executable dynamic library */
144: #define PETSC_USE_NONEXECUTABLE_SO
145: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
146: PetscTestFile(par2,'x',&foundlibrary);
147: if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",path,par2);
148: #endif
150: /* copy path and setup shared library suffix */
151: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
152: PetscStrncpy(suffix,".",sizeof(suffix));
153: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
154: /* remove wrong suffixes from libname */
155: PetscStrrstr(libname,".gz",&s);
156: if (s && s[3] == 0) s[0] = 0;
157: PetscStrrstr(libname,".a",&s);
158: if (s && s[2] == 0) s[0] = 0;
159: /* remove shared suffix from libname */
160: PetscStrrstr(libname,suffix,&s);
161: if (s) s[0] = 0;
163: /* open the dynamic library */
164: PetscInfo1(NULL,"Opening dynamic library %s\n",libname);
165: PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);
167: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
168: PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
169: if (!basename) basename = libname;
170: PetscStrncmp(basename,"lib",3,&match);
171: if (match) basename = basename + 3;
172: else {
173: PetscInfo1(NULL,"Dynamic library %s does not have lib prefix\n",libname);
174: }
175: for (s=basename; *s; s++) if (*s == '-') *s = '_';
176: PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername));
177: PetscStrlcat(registername,basename,sizeof(registername));
178: PetscDLSym(handle,registername,(void**)&func);
179: if (func) {
180: PetscInfo1(NULL,"Loading registered routines from %s\n",libname);
181: (*func)();
182: } else {
183: PetscInfo2(NULL,"Dynamic library %s does not have symbol %s\n",libname,registername);
184: }
186: PetscNew(entry);
187: (*entry)->next = NULL;
188: (*entry)->handle = handle;
189: PetscStrcpy((*entry)->libname,libname);
190: return(0);
191: }
193: /*@C
194: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
196: Collective
198: Input Parameters:
199: + comm - communicator that will open the library
200: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
201: . path - optional complete library name (if provided checks here before checking outlist)
202: - insymbol - name of symbol
204: Output Parameter:
205: . value - if symbol not found then this value is set to NULL
207: Level: developer
209: Notes:
210: Symbol can be of the form
211: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
213: Will attempt to (retrieve and) open the library if it is not yet been opened.
215: @*/
216: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
217: {
218: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
219: PetscDLLibrary nlist,prev,list = NULL;
228: if (outlist) list = *outlist;
229: *value = NULL;
231: PetscStrchr(insymbol,'(',&s);
232: if (s) {
233: /* make copy of symbol so we can edit it in place */
234: PetscStrallocpy(insymbol,&symbol);
235: /* If symbol contains () then replace with a NULL, to support functionname() */
236: PetscStrchr(symbol,'(',&s);
237: s[0] = 0;
238: } else symbol = (char*)insymbol;
240: /*
241: Function name does include library
242: -------------------------------------
243: */
244: if (path && path[0] != '\0') {
245: /* copy path and remove suffix from libname */
246: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
247: PetscStrncpy(suffix,".",sizeof(suffix));
248: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
249: PetscStrrstr(libname,suffix,&s);
250: if (s) s[0] = 0;
251: /* Look if library is already opened and in path */
252: prev = NULL;
253: nlist = list;
254: while (nlist) {
255: PetscBool match;
256: PetscStrcmp(nlist->libname,libname,&match);
257: if (match) goto done;
258: prev = nlist;
259: nlist = nlist->next;
260: }
261: /* open the library and append it to path */
262: PetscDLLibraryOpen(comm,path,&nlist);
263: PetscInfo1(NULL,"Appending %s to dynamic library search path\n",path);
264: if (prev) prev->next = nlist;
265: else {if (outlist) *outlist = nlist;}
267: done:;
268: PetscDLSym(nlist->handle,symbol,value);
269: if (*value) {
270: PetscInfo2(NULL,"Loading function %s from dynamic library %s\n",insymbol,path);
271: }
273: /*
274: Function name does not include library so search path
275: -----------------------------------------------------
276: */
277: } else {
278: while (list) {
279: PetscDLSym(list->handle,symbol,value);
280: if (*value) {
281: PetscInfo2(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
282: break;
283: }
284: list = list->next;
285: }
286: if (!*value) {
287: PetscDLSym(NULL,symbol,value);
288: if (*value) {
289: PetscInfo1(NULL,"Loading symbol %s from object code\n",symbol);
290: }
291: }
292: }
294: if (symbol != insymbol) {
295: PetscFree(symbol);
296: }
297: return(0);
298: }
300: /*@C
301: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
302: of the search path.
304: Collective
306: Input Parameters:
307: + comm - MPI communicator
308: - path - name of the library
310: Output Parameter:
311: . outlist - list of libraries
313: Level: developer
315: Notes:
316: if library is already in path will not add it.
318: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
319: when the library is opened.
321: .seealso: PetscDLLibraryOpen()
322: @*/
323: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
324: {
325: PetscDLLibrary list,prev;
327: size_t len;
328: PetscBool match,dir;
329: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
330: char *libname,suffix[16],*s;
331: PetscToken token;
336: /* is path a directory? */
337: PetscTestDirectory(path,'r',&dir);
338: if (dir) {
339: PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);
340: PetscStrncpy(program,path,sizeof(program));
341: PetscStrlen(program,&len);
342: if (program[len-1] == '/') {
343: PetscStrlcat(program,"*.",sizeof(program));
344: } else {
345: PetscStrlcat(program,"/*.",sizeof(program));
346: }
347: PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));
349: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
350: if (!dir) return(0);
351: } else {
352: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
353: }
354: PetscStrncpy(suffix,".",sizeof(suffix));
355: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
357: PetscTokenCreate(found,'\n',&token);
358: PetscTokenFind(token,&libname);
359: while (libname) {
360: /* remove suffix from libname */
361: PetscStrrstr(libname,suffix,&s);
362: if (s) s[0] = 0;
363: /* see if library was already open then we are done */
364: list = prev = *outlist;
365: match = PETSC_FALSE;
366: while (list) {
367: PetscStrcmp(list->libname,libname,&match);
368: if (match) break;
369: prev = list;
370: list = list->next;
371: }
372: /* restore suffix from libname */
373: if (s) s[0] = '.';
374: if (!match) {
375: /* open the library and add to end of list */
376: PetscDLLibraryOpen(comm,libname,&list);
377: PetscInfo1(NULL,"Appending %s to dynamic library search path\n",libname);
378: if (!*outlist) *outlist = list;
379: else prev->next = list;
380: }
381: PetscTokenFind(token,&libname);
382: }
383: PetscTokenDestroy(&token);
384: return(0);
385: }
387: /*@C
388: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
389: the search path.
391: Collective
393: Input Parameters:
394: + comm - MPI communicator
395: - path - name of the library
397: Output Parameter:
398: . outlist - list of libraries
400: Level: developer
402: Notes:
403: If library is already in path will remove old reference.
405: @*/
406: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
407: {
408: PetscDLLibrary list,prev;
410: size_t len;
411: PetscBool match,dir;
412: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
413: char *libname,suffix[16],*s;
414: PetscToken token;
419: /* is path a directory? */
420: PetscTestDirectory(path,'r',&dir);
421: if (dir) {
422: PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);
423: PetscStrncpy(program,path,sizeof(program));
424: PetscStrlen(program,&len);
425: if (program[len-1] == '/') {
426: PetscStrlcat(program,"*.",sizeof(program));
427: } else {
428: PetscStrlcat(program,"/*.",sizeof(program));
429: }
430: PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));
432: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
433: if (!dir) return(0);
434: } else {
435: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
436: }
438: PetscStrncpy(suffix,".",sizeof(suffix));
439: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
441: PetscTokenCreate(found,'\n',&token);
442: PetscTokenFind(token,&libname);
443: while (libname) {
444: /* remove suffix from libname */
445: PetscStrstr(libname,suffix,&s);
446: if (s) s[0] = 0;
447: /* see if library was already open and move it to the front */
448: prev = NULL;
449: list = *outlist;
450: match = PETSC_FALSE;
451: while (list) {
452: PetscStrcmp(list->libname,libname,&match);
453: if (match) {
454: PetscInfo1(NULL,"Moving %s to begin of dynamic library search path\n",libname);
455: if (prev) prev->next = list->next;
456: if (prev) list->next = *outlist;
457: *outlist = list;
458: break;
459: }
460: prev = list;
461: list = list->next;
462: }
463: /* restore suffix from libname */
464: if (s) s[0] = '.';
465: if (!match) {
466: /* open the library and add to front of list */
467: PetscDLLibraryOpen(comm,libname,&list);
468: PetscInfo1(NULL,"Prepending %s to dynamic library search path\n",libname);
469: list->next = *outlist;
470: *outlist = list;
471: }
472: PetscTokenFind(token,&libname);
473: }
474: PetscTokenDestroy(&token);
475: return(0);
476: }
478: /*@C
479: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
481: Collective on PetscDLLibrary
483: Input Parameter:
484: . head - library list
486: Level: developer
488: @*/
489: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
490: {
491: PetscBool done = PETSC_FALSE;
492: PetscDLLibrary prev,tail;
496: if (!list) return(0);
497: /* traverse the list in reverse order */
498: while (!done) {
499: if (!list->next) done = PETSC_TRUE;
500: prev = tail = list;
501: while (tail->next) {
502: prev = tail;
503: tail = tail->next;
504: }
505: prev->next = NULL;
506: /* close the dynamic library and free the space in entry data-structure*/
507: PetscInfo1(NULL,"Closing dynamic library %s\n",tail->libname);
508: PetscDLClose(&tail->handle);
509: PetscFree(tail);
510: }
511: return(0);
512: }