Actual source code: dl.c
petsc-3.3-p7 2013-05-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 <petscsys.h>
7: #include <../src/sys/dll/dlimpl.h>
9: /* ------------------------------------------------------------------------------*/
10: /*
11: Code to maintain a list of opened dynamic libraries and load symbols
12: */
13: struct _n_PetscDLLibrary {
14: PetscDLLibrary next;
15: PetscDLHandle handle;
16: char libname[PETSC_MAX_PATH_LEN];
17: };
21: PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs)
22: {
24: while (libs) {
25: PetscErrorPrintf(" %s\n",libs->libname);
26: libs = libs->next;
27: }
28: return(0);
29: }
33: /*@C
34: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
35: (if it is remote), indicates if it exits and its local name.
37: Collective on MPI_Comm
39: Input Parameters:
40: + comm - processors that are opening the library
41: - libname - name of the library, can be relative or absolute
43: Output Parameter:
44: . handle - library handle
46: Level: developer
48: Notes:
49: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
51: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
52: occuring in directoryname and filename will be replaced with appropriate values.
53: @*/
54: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool *found)
55: {
56: char *buf,*par2,suffix[16],*gz,*so;
57: size_t len;
61: /*
62: make copy of library name and replace $PETSC_ARCH etc
63: so we can add to the end of it to look for something like .so.1.0 etc.
64: */
65: PetscStrlen(libname,&len);
66: len = PetscMax(4*len,PETSC_MAX_PATH_LEN);
67: PetscMalloc(len*sizeof(char),&buf);
68: par2 = buf;
69: PetscStrreplace(comm,libname,par2,len);
71: /* temporarily remove .gz if it ends library name */
72: PetscStrrstr(par2,".gz",&gz);
73: if (gz) {
74: PetscStrlen(gz,&len);
75: if (len != 3) gz = 0; /* do not end (exactly) with .gz */
76: else *gz = 0; /* ends with .gz, so remove it */
77: }
78: /* strip out .a from it if user put it in by mistake */
79: PetscStrlen(par2,&len);
80: if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
83: /* see if library name does already not have suffix attached */
84: PetscStrcpy(suffix,".");
85: PetscStrcat(suffix,PETSC_SLSUFFIX);
86: PetscStrrstr(par2,suffix,&so);
87: /* and attach the suffix if it is not there */
88: if (!so) { PetscStrcat(par2,suffix); }
90: /* restore the .gz suffix if it was there */
91: if (gz) { PetscStrcat(par2,".gz"); }
93: /* and finally retrieve the file */
94: PetscFileRetrieve(comm,par2,lname,llen,found);
96: PetscFree(buf);
97: return(0);
98: }
103: /*@C
104: PetscDLLibraryOpen - Opens a PETSc dynamic link library
106: Collective on MPI_Comm
108: Input Parameters:
109: + comm - processors that are opening the library
110: - path - name of the library, can be relative or absolute
112: Output Parameter:
113: . entry - a PETSc dynamic link library entry
115: Level: developer
117: Notes:
118: [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
120: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
121: when the library is opened.
123: ${PETSC_ARCH} occuring in directoryname and filename
124: will be replaced with the appropriate value.
126: .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
127: @*/
128: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
129: {
131: PetscBool foundlibrary,match;
132: char libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
133: char *basename,registername[128];
134: PetscDLHandle handle;
135: PetscErrorCode (*func)(const char*) = NULL;
136: size_t len;
142: *entry = PETSC_NULL;
143:
144: /* retrieve the library */
145: PetscInfo1(0,"Retrieving %s\n",path);
146: PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
147: if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",path);
148: /* Eventually ./configure should determine if the system needs an executable dynamic library */
149: #define PETSC_USE_NONEXECUTABLE_SO
150: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
151: PetscTestFile(par2,'x',&foundlibrary);
152: if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",path,par2);
153: #endif
155: /* copy path and setup shared library suffix */
156: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
157: PetscStrcpy(suffix,".");
158: PetscStrcat(suffix,PETSC_SLSUFFIX);
159: /* remove wrong suffixes from libname */
160: PetscStrrstr(libname,".gz",&s);
161: if (s && s[3] == 0) s[0] = 0;
162: PetscStrrstr(libname,".a",&s);
163: if (s && s[2] == 0) s[0] = 0;
164: /* remove shared suffix from libname */
165: PetscStrrstr(libname,suffix,&s);
166: if (s) s[0] = 0;
168: /* open the dynamic library */
169: PetscInfo1(0,"Opening dynamic library %s\n",libname);
170: PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);
172: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
173: PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
174: if (!basename) basename = libname;
175: PetscStrncmp(basename,"lib",3,&match);
176: if (match) {
177: basename = basename + 3;
178: } else {
179: PetscInfo1(0,"Dynamic library %s does not have lib prefix\n",libname);
180: }
181: PetscStrlen(basename,&len);
182: PetscStrcpy(registername,"PetscDLLibraryRegister_");
183: PetscStrncat(registername,basename,len);
184: PetscDLSym(handle,registername,(void**)&func);
185: if (func) {
186: PetscInfo1(0,"Loading registered routines from %s\n",libname);
187: (*func)(libname);
188: } else {
189: PetscInfo2(0,"Dynamic library %s does not have symbol %s\n",libname,registername);
190: }
191:
192: PetscNew(struct _n_PetscDLLibrary,entry);
193: (*entry)->next = 0;
194: (*entry)->handle = handle;
195: PetscStrcpy((*entry)->libname,libname);
197: return(0);
198: }
202: /*@C
203: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
205: Collective on MPI_Comm
207: Input Parameter:
208: + comm - communicator that will open the library
209: . outlist - list of already open libraries that may contain symbol (can be PETSC_NULL and only the executable is searched for the function)
210: . path - optional complete library name (if provided checks here before checking outlist)
211: - insymbol - name of symbol
213: Output Parameter:
214: . value - if symbol not found then this value is set to PETSC_NULL
216: Level: developer
218: Notes: Symbol can be of the form
219: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
221: Will attempt to (retrieve and) open the library if it is not yet been opened.
223: @*/
224: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
225: {
226: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
227: size_t len;
228: PetscDLLibrary nlist,prev,list = PETSC_NULL;
237: if (outlist) list = *outlist;
238: *value = 0;
240: /* make copy of symbol so we can edit it in place */
241: PetscStrlen(insymbol,&len);
242: PetscMalloc((len+1)*sizeof(char),&symbol);
243: PetscStrcpy(symbol,insymbol);
244: /* If symbol contains () then replace with a NULL, to support functionname() */
245: PetscStrchr(symbol,'(',&s);
246: if (s) s[0] = 0;
248: /*
249: Function name does include library
250: -------------------------------------
251: */
252: if (path && path[0] != '\0') {
253: /* copy path and remove suffix from libname */
254: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
255: PetscStrcpy(suffix,".");
256: PetscStrcat(suffix,PETSC_SLSUFFIX);
257: PetscStrrstr(libname,suffix,&s);
258: if (s) s[0] = 0;
259: /* Look if library is already opened and in path */
260: prev = 0;
261: nlist = list;
262: while (nlist) {
263: PetscBool match;
264: PetscStrcmp(nlist->libname,libname,&match);
265: if (match) goto done;
266: prev = nlist;
267: nlist = nlist->next;
268: }
269: /* open the library and append it to path */
270: PetscDLLibraryOpen(comm,path,&nlist);
271: PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
272: if (prev) { prev->next = nlist; }
273: else { *outlist = nlist; }
275: done:;
276: PetscDLSym(nlist->handle,symbol,value);
277: if (*value) {
278: PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
279: }
281: /*
282: Function name does not include library so search path
283: -----------------------------------------------------
284: */
285: } else {
286: while (list) {
287: PetscDLSym(list->handle,symbol,value);
288: if (*value) {
289: PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
290: break;
291: }
292: list = list->next;
293: }
294: if (!*value) {
295: PetscDLSym(PETSC_NULL,symbol,value);
296: if (*value) {
297: PetscInfo1(0,"Loading symbol %s from object code\n",symbol);
298: }
299: }
300: }
302: PetscFree(symbol);
303: return(0);
304: }
308: /*@C
309: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
310: of the search path.
312: Collective on MPI_Comm
314: Input Parameters:
315: + comm - MPI communicator
316: - path - name of the library
318: Output Parameter:
319: . outlist - list of libraries
321: Level: developer
323: Notes: if library is already in path will not add it.
325: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
326: when the library is opened.
328: .seealso: PetscDLLibraryOpen()
329: @*/
330: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
331: {
332: PetscDLLibrary list,prev;
334: size_t len;
335: PetscBool match,dir;
336: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
337: char *libname,suffix[16],*s;
338: PetscToken token;
342:
343: /* is path a directory? */
344: PetscTestDirectory(path,'r',&dir);
345: if (dir) {
346: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
347: PetscStrcpy(program,path);
348: PetscStrlen(program,&len);
349: if (program[len-1] == '/') {
350: PetscStrcat(program,"*.");
351: } else {
352: PetscStrcat(program,"/*.");
353: }
354: PetscStrcat(program,PETSC_SLSUFFIX);
356: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
357: if (!dir) return(0);
358: } else {
359: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
360: }
361: PetscStrcpy(suffix,".");
362: PetscStrcat(suffix,PETSC_SLSUFFIX);
364: PetscTokenCreate(found,'\n',&token);
365: PetscTokenFind(token,&libname);
366: while (libname) {
367: /* remove suffix from libname */
368: PetscStrrstr(libname,suffix,&s);
369: if (s) s[0] = 0;
370: /* see if library was already open then we are done */
371: list = prev = *outlist;
372: match = PETSC_FALSE;
373: while (list) {
374: PetscStrcmp(list->libname,libname,&match);
375: if (match) break;
376: prev = list;
377: list = list->next;
378: }
379: /* restore suffix from libname */
380: if (s) s[0] = '.';
381: if (!match) {
382: /* open the library and add to end of list */
383: PetscDLLibraryOpen(comm,libname,&list);
384: PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
385: if (!*outlist) {
386: *outlist = list;
387: } else {
388: prev->next = list;
389: }
390: }
391: PetscTokenFind(token,&libname);
392: }
393: PetscTokenDestroy(&token);
394: return(0);
395: }
399: /*@C
400: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
401: the search path.
403: Collective on MPI_Comm
405: Input Parameters:
406: + comm - MPI communicator
407: - path - name of the library
409: Output Parameter:
410: . outlist - list of libraries
412: Level: developer
414: Notes: If library is already in path will remove old reference.
416: @*/
417: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
418: {
419: PetscDLLibrary list,prev;
421: size_t len;
422: PetscBool match,dir;
423: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
424: char *libname,suffix[16],*s;
425: PetscToken token;
429:
430: /* is path a directory? */
431: PetscTestDirectory(path,'r',&dir);
432: if (dir) {
433: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
434: PetscStrcpy(program,path);
435: PetscStrlen(program,&len);
436: if (program[len-1] == '/') {
437: PetscStrcat(program,"*.");
438: } else {
439: PetscStrcat(program,"/*.");
440: }
441: PetscStrcat(program,PETSC_SLSUFFIX);
443: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
444: if (!dir) return(0);
445: } else {
446: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
447: }
449: PetscStrcpy(suffix,".");
450: PetscStrcat(suffix,PETSC_SLSUFFIX);
452: PetscTokenCreate(found,'\n',&token);
453: PetscTokenFind(token,&libname);
454: while (libname) {
455: /* remove suffix from libname */
456: PetscStrstr(libname,suffix,&s);
457: if (s) s[0] = 0;
458: /* see if library was already open and move it to the front */
459: prev = 0;
460: list = *outlist;
461: match = PETSC_FALSE;
462: while (list) {
463: PetscStrcmp(list->libname,libname,&match);
464: if (match) {
465: PetscInfo1(0,"Moving %s to begin of dynamic library search path\n",libname);
466: if (prev) prev->next = list->next;
467: if (prev) list->next = *outlist;
468: *outlist = list;
469: break;
470: }
471: prev = list;
472: list = list->next;
473: }
474: /* restore suffix from libname */
475: if (s) s[0] = '.';
476: if (!match) {
477: /* open the library and add to front of list */
478: PetscDLLibraryOpen(comm,libname,&list);
479: PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname);
480: list->next = *outlist;
481: *outlist = list;
482: }
483: PetscTokenFind(token,&libname);
484: }
485: PetscTokenDestroy(&token);
486: return(0);
487: }
491: /*@C
492: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
494: Collective on PetscDLLibrary
496: Input Parameter:
497: . head - library list
499: Level: developer
501: @*/
502: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
503: {
504: PetscBool done = PETSC_FALSE;
505: PetscDLLibrary prev,tail;
509: if (!list) return(0);
510: /* traverse the list in reverse order */
511: while (!done) {
512: if (!list->next) done = PETSC_TRUE;
513: prev = tail = list;
514: while (tail->next) {
515: prev = tail;
516: tail = tail->next;
517: }
518: prev->next = 0;
519: /* close the dynamic library and free the space in entry data-structure*/
520: PetscInfo1(0,"Closing dynamic library %s\n",tail->libname);
521: PetscDLClose(&tail->handle);
522: PetscFree(tail);
523: };
524: return(0);
525: }