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 {
168: PetscInfo(NULL,"Dynamic library %s does not have lib prefix\n",libname);
169: }
170: for (s=basename; *s; s++) if (*s == '-') *s = '_';
171: PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername));
172: PetscStrlcat(registername,basename,sizeof(registername));
173: PetscDLSym(handle,registername,(void**)&func);
174: if (func) {
175: PetscInfo(NULL,"Loading registered routines from %s\n",libname);
176: (*func)();
177: } else {
178: PetscInfo(NULL,"Dynamic library %s does not have symbol %s\n",libname,registername);
179: }
181: PetscNew(entry);
182: (*entry)->next = NULL;
183: (*entry)->handle = handle;
184: PetscStrcpy((*entry)->libname,libname);
185: return 0;
186: }
188: /*@C
189: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
191: Collective
193: Input Parameters:
194: + comm - communicator that will open the library
195: . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
196: . path - optional complete library name (if provided checks here before checking outlist)
197: - insymbol - name of symbol
199: Output Parameter:
200: . value - if symbol not found then this value is set to NULL
202: Level: developer
204: Notes:
205: Symbol can be of the form
206: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
208: Will attempt to (retrieve and) open the library if it is not yet been opened.
210: @*/
211: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
212: {
213: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
214: PetscDLLibrary nlist,prev,list = NULL;
221: if (outlist) list = *outlist;
222: *value = NULL;
224: PetscStrchr(insymbol,'(',&s);
225: if (s) {
226: /* make copy of symbol so we can edit it in place */
227: PetscStrallocpy(insymbol,&symbol);
228: /* If symbol contains () then replace with a NULL, to support functionname() */
229: PetscStrchr(symbol,'(',&s);
230: s[0] = 0;
231: } else symbol = (char*)insymbol;
233: /*
234: Function name does include library
235: -------------------------------------
236: */
237: if (path && path[0] != '\0') {
238: /* copy path and remove suffix from libname */
239: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
240: PetscStrncpy(suffix,".",sizeof(suffix));
241: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
242: PetscStrrstr(libname,suffix,&s);
243: if (s) s[0] = 0;
244: /* Look if library is already opened and in path */
245: prev = NULL;
246: nlist = list;
247: while (nlist) {
248: PetscBool match;
249: PetscStrcmp(nlist->libname,libname,&match);
250: if (match) goto done;
251: prev = nlist;
252: nlist = nlist->next;
253: }
254: /* open the library and append it to path */
255: PetscDLLibraryOpen(comm,path,&nlist);
256: PetscInfo(NULL,"Appending %s to dynamic library search path\n",path);
257: if (prev) prev->next = nlist;
258: else {if (outlist) *outlist = nlist;}
260: done:;
261: PetscDLSym(nlist->handle,symbol,value);
262: if (*value) {
263: PetscInfo(NULL,"Loading function %s from dynamic library %s\n",insymbol,path);
264: }
266: /*
267: Function name does not include library so search path
268: -----------------------------------------------------
269: */
270: } else {
271: while (list) {
272: PetscDLSym(list->handle,symbol,value);
273: if (*value) {
274: PetscInfo(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
275: break;
276: }
277: list = list->next;
278: }
279: if (!*value) {
280: PetscDLSym(NULL,symbol,value);
281: if (*value) {
282: PetscInfo(NULL,"Loading symbol %s from object code\n",symbol);
283: }
284: }
285: }
287: if (symbol != insymbol) {
288: PetscFree(symbol);
289: }
290: return 0;
291: }
293: /*@C
294: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
295: of the search path.
297: Collective
299: Input Parameters:
300: + comm - MPI communicator
301: - path - name of the library
303: Output Parameter:
304: . outlist - list of libraries
306: Level: developer
308: Notes:
309: if library is already in path will not add it.
311: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
312: when the library is opened.
314: .seealso: PetscDLLibraryOpen()
315: @*/
316: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
317: {
318: PetscDLLibrary list,prev;
319: size_t len;
320: PetscBool match,dir;
321: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
322: char *libname,suffix[16],*s;
323: PetscToken token;
327: /* is path a directory? */
328: PetscTestDirectory(path,'r',&dir);
329: if (dir) {
330: PetscInfo(NULL,"Checking directory %s for dynamic libraries\n",path);
331: PetscStrncpy(program,path,sizeof(program));
332: PetscStrlen(program,&len);
333: if (program[len-1] == '/') {
334: PetscStrlcat(program,"*.",sizeof(program));
335: } else {
336: PetscStrlcat(program,"/*.",sizeof(program));
337: }
338: PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));
340: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
341: if (!dir) return 0;
342: } else {
343: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
344: }
345: PetscStrncpy(suffix,".",sizeof(suffix));
346: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
348: PetscTokenCreate(found,'\n',&token);
349: PetscTokenFind(token,&libname);
350: while (libname) {
351: /* remove suffix from libname */
352: PetscStrrstr(libname,suffix,&s);
353: if (s) s[0] = 0;
354: /* see if library was already open then we are done */
355: list = prev = *outlist;
356: match = PETSC_FALSE;
357: while (list) {
358: PetscStrcmp(list->libname,libname,&match);
359: if (match) break;
360: prev = list;
361: list = list->next;
362: }
363: /* restore suffix from libname */
364: if (s) s[0] = '.';
365: if (!match) {
366: /* open the library and add to end of list */
367: PetscDLLibraryOpen(comm,libname,&list);
368: PetscInfo(NULL,"Appending %s to dynamic library search path\n",libname);
369: if (!*outlist) *outlist = list;
370: else prev->next = list;
371: }
372: PetscTokenFind(token,&libname);
373: }
374: PetscTokenDestroy(&token);
375: return 0;
376: }
378: /*@C
379: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
380: the search path.
382: Collective
384: Input Parameters:
385: + comm - MPI communicator
386: - path - name of the library
388: Output Parameter:
389: . outlist - list of libraries
391: Level: developer
393: Notes:
394: If library is already in path will remove old reference.
396: @*/
397: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
398: {
399: PetscDLLibrary list,prev;
400: size_t len;
401: PetscBool match,dir;
402: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
403: char *libname,suffix[16],*s;
404: PetscToken token;
408: /* is path a directory? */
409: PetscTestDirectory(path,'r',&dir);
410: if (dir) {
411: PetscInfo(NULL,"Checking directory %s for dynamic libraries\n",path);
412: PetscStrncpy(program,path,sizeof(program));
413: PetscStrlen(program,&len);
414: if (program[len-1] == '/') {
415: PetscStrlcat(program,"*.",sizeof(program));
416: } else {
417: PetscStrlcat(program,"/*.",sizeof(program));
418: }
419: PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));
421: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
422: if (!dir) return 0;
423: } else {
424: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
425: }
427: PetscStrncpy(suffix,".",sizeof(suffix));
428: PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
430: PetscTokenCreate(found,'\n',&token);
431: PetscTokenFind(token,&libname);
432: while (libname) {
433: /* remove suffix from libname */
434: PetscStrstr(libname,suffix,&s);
435: if (s) s[0] = 0;
436: /* see if library was already open and move it to the front */
437: prev = NULL;
438: list = *outlist;
439: match = PETSC_FALSE;
440: while (list) {
441: PetscStrcmp(list->libname,libname,&match);
442: if (match) {
443: PetscInfo(NULL,"Moving %s to begin of dynamic library search path\n",libname);
444: if (prev) prev->next = list->next;
445: if (prev) list->next = *outlist;
446: *outlist = list;
447: break;
448: }
449: prev = list;
450: list = list->next;
451: }
452: /* restore suffix from libname */
453: if (s) s[0] = '.';
454: if (!match) {
455: /* open the library and add to front of list */
456: PetscDLLibraryOpen(comm,libname,&list);
457: PetscInfo(NULL,"Prepending %s to dynamic library search path\n",libname);
458: list->next = *outlist;
459: *outlist = list;
460: }
461: PetscTokenFind(token,&libname);
462: }
463: PetscTokenDestroy(&token);
464: return 0;
465: }
467: /*@C
468: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
470: Collective on PetscDLLibrary
472: Input Parameter:
473: . head - library list
475: Level: developer
477: @*/
478: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
479: {
480: PetscBool done = PETSC_FALSE;
481: PetscDLLibrary prev,tail;
483: if (!list) return 0;
484: /* traverse the list in reverse order */
485: while (!done) {
486: if (!list->next) done = PETSC_TRUE;
487: prev = tail = list;
488: while (tail->next) {
489: prev = tail;
490: tail = tail->next;
491: }
492: prev->next = NULL;
493: /* close the dynamic library and free the space in entry data-structure*/
494: PetscInfo(NULL,"Closing dynamic library %s\n",tail->libname);
495: PetscDLClose(&tail->handle);
496: PetscFree(tail);
497: }
498: return 0;
499: }