Actual source code: dl.c
1: #define PETSC_DLL
2: /*
3: Routines for opening dynamic link libraries (DLLs), keeping a searchable
4: path of DLLs, obtaining remote DLLs via a URL and opening them locally.
5: */
7: #include petscsys.h
8: #include ../src/sys/dll/dlimpl.h
10: /* ------------------------------------------------------------------------------*/
11: /*
12: Code to maintain a list of opened dynamic libraries and load symbols
13: */
14: struct _n_PetscDLLibrary {
15: PetscDLLibrary next;
16: PetscDLHandle handle;
17: char libname[PETSC_MAX_PATH_LEN];
18: };
22: PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs)
23: {
25: while (libs) {
26: PetscErrorPrintf(" %s\n",libs->libname);
27: libs = libs->next;
28: }
29: return(0);
30: }
34: /*@C
35: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
36: (if it is remote), indicates if it exits and its local name.
38: Collective on MPI_Comm
40: Input Parameters:
41: + comm - processors that are opening the library
42: - libname - name of the library, can be relative or absolute
44: Output Parameter:
45: . handle - library handle
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,PetscTruth *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: PetscMalloc(len*sizeof(char),&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;
84: /* see if library name does already not have suffix attached */
85: PetscStrcpy(suffix,".");
86: PetscStrcat(suffix,PETSC_SLSUFFIX);
87: PetscStrrstr(par2,suffix,&so);
88: /* and attach the suffix if it is not there */
89: if (!so) { PetscStrcat(par2,suffix); }
91: /* restore the .gz suffix if it was there */
92: if (gz) { PetscStrcat(par2,".gz"); }
94: /* and finally retrieve the file */
95: PetscFileRetrieve(comm,par2,lname,llen,found);
97: PetscFree(buf);
98: return(0);
99: }
104: /*@C
105: PetscDLLibraryOpen - Opens a PETSc dynamic link library
107: Collective on MPI_Comm
109: Input Parameters:
110: + comm - processors that are opening the library
111: - path - name of the library, can be relative or absolute
113: Output Parameter:
114: . entry - a PETSc dynamic link library entry
116: Level: developer
118: Notes:
119: [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
121: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
122: when the library is opened.
124: ${PETSC_ARCH} occuring in directoryname and filename
125: will be replaced with the appropriate value.
127: .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
128: @*/
129: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
130: {
132: PetscTruth foundlibrary,match;
133: char libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
134: char *basename,registername[128];
135: PetscDLHandle handle;
136: PetscErrorCode (*func)(const char*) = NULL;
137: size_t len;
143: *entry = PETSC_NULL;
144:
145: /* retrieve the library */
146: PetscInfo1(0,"Retrieving %s\n",path);
147: PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
148: if (!foundlibrary) SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",path);
149: /* Eventually config/configure.py should determine if the system needs an executable dynamic library */
150: #define PETSC_USE_NONEXECUTABLE_SO
151: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
152: PetscTestFile(par2,'x',&foundlibrary);
153: if (!foundlibrary) SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",path,par2);
154: #endif
156: /* copy path and setup shared library suffix */
157: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
158: PetscStrcpy(suffix,".");
159: PetscStrcat(suffix,PETSC_SLSUFFIX);
160: /* remove wrong suffixes from libname */
161: PetscStrrstr(libname,".gz",&s);
162: if (s && s[3] == 0) s[0] = 0;
163: PetscStrrstr(libname,".a",&s);
164: if (s && s[2] == 0) s[0] = 0;
165: /* remove shared suffix from libname */
166: PetscStrrstr(libname,suffix,&s);
167: if (s) s[0] = 0;
169: /* open the dynamic library */
170: PetscInfo1(0,"Opening dynamic library %s\n",libname);
171: PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);
173: /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
174: PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
175: if (!basename) basename = libname;
176: PetscStrncmp(basename,"lib",3,&match);
177: if (match) {
178: basename = basename + 3;
179: } else {
180: PetscInfo1(0,"Dynamic library %s does not have lib prefix\n",libname);
181: }
182: PetscStrlen(basename,&len);
183: PetscStrcpy(registername,"PetscDLLibraryRegister_");
184: PetscStrncat(registername,basename,len);
185: PetscDLSym(handle,registername,(void**)&func);
186: if (func) {
187: PetscInfo1(0,"Loading registered routines from %s\n",libname);
188: (*func)(libname);
189: } else {
190: PetscInfo2(0,"Dynamic library %s does not have symbol %s\n",libname,registername);
191: }
192:
193: PetscNew(struct _n_PetscDLLibrary,entry);
194: (*entry)->next = 0;
195: (*entry)->handle = handle;
196: PetscStrcpy((*entry)->libname,libname);
198: return(0);
199: }
203: /*@C
204: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
206: Collective on MPI_Comm
208: Input Parameter:
209: + comm - communicator that will open the library
210: . outlist - list of already open libraries that may contain symbol (checks here before path)
211: . path - optional complete library name
212: - insymbol - name of symbol
214: Output Parameter:
215: . value
217: Level: developer
219: Notes: Symbol can be of the form
220: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
222: Will attempt to (retrieve and) open the library if it is not yet been opened.
224: @*/
225: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
226: {
227: char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
228: size_t len;
229: PetscDLLibrary nlist,prev,list;
238: list = *outlist;
239: *value = 0;
241: /* make copy of symbol so we can edit it in place */
242: PetscStrlen(insymbol,&len);
243: PetscMalloc((len+1)*sizeof(char),&symbol);
244: PetscStrcpy(symbol,insymbol);
245: /* If symbol contains () then replace with a NULL, to support functionname() */
246: PetscStrchr(symbol,'(',&s);
247: if (s) s[0] = 0;
249: /*
250: Function name does include library
251: -------------------------------------
252: */
253: if (path && path[0] != '\0') {
254: /* copy path and remove suffix from libname */
255: PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
256: PetscStrcpy(suffix,".");
257: PetscStrcat(suffix,PETSC_SLSUFFIX);
258: PetscStrrstr(libname,suffix,&s);
259: if (s) s[0] = 0;
260: /* Look if library is already opened and in path */
261: prev = 0;
262: nlist = list;
263: while (nlist) {
264: PetscTruth match;
265: PetscStrcmp(nlist->libname,libname,&match);
266: if (match) goto done;
267: prev = nlist;
268: nlist = nlist->next;
269: }
270: /* open the library and append it to path */
271: PetscDLLibraryOpen(comm,path,&nlist);
272: PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
273: if (prev) { prev->next = nlist; }
274: else { *outlist = nlist; }
276: done:;
277: PetscDLSym(nlist->handle,symbol,value);
278: if (!*value) {
279: SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
280: }
281: PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
283: /*
284: Function name does not include library so search path
285: -----------------------------------------------------
286: */
287: } else {
288: while (list) {
289: PetscDLSym(list->handle,symbol,value);
290: if (*value) {
291: PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
292: break;
293: }
294: list = list->next;
295: }
296: if (!*value) {
297: PetscDLSym(PETSC_NULL,symbol,value);
298: if (*value) {
299: PetscInfo1(0,"Loading symbol %s from object code\n",symbol);
300: }
301: }
302: }
304: PetscFree(symbol);
305: return(0);
306: }
310: /*@C
311: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
312: of the search path.
314: Collective on MPI_Comm
316: Input Parameters:
317: + comm - MPI communicator
318: - path - name of the library
320: Output Parameter:
321: . outlist - list of libraries
323: Level: developer
325: Notes: if library is already in path will not add it.
327: If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
328: when the library is opened.
330: .seealso: PetscDLLibraryOpen()
331: @*/
332: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
333: {
334: PetscDLLibrary list,prev;
336: size_t len;
337: PetscTruth match,dir;
338: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
339: char *libname,suffix[16],*s;
340: PetscToken token;
344:
345: /* is path a directory? */
346: PetscTestDirectory(path,'r',&dir);
347: if (dir) {
348: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
349: PetscStrcpy(program,path);
350: PetscStrlen(program,&len);
351: if (program[len-1] == '/') {
352: PetscStrcat(program,"*.");
353: } else {
354: PetscStrcat(program,"/*.");
355: }
356: PetscStrcat(program,PETSC_SLSUFFIX);
358: PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
359: if (!dir) return(0);
360: } else {
361: PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
362: }
363: PetscStrcpy(suffix,".");
364: PetscStrcat(suffix,PETSC_SLSUFFIX);
366: PetscTokenCreate(found,'\n',&token);
367: PetscTokenFind(token,&libname);
368: while (libname) {
369: /* remove suffix from libname */
370: PetscStrrstr(libname,suffix,&s);
371: if (s) s[0] = 0;
372: /* see if library was already open then we are done */
373: list = prev = *outlist;
374: match = PETSC_FALSE;
375: while (list) {
376: PetscStrcmp(list->libname,libname,&match);
377: if (match) break;
378: prev = list;
379: list = list->next;
380: }
381: /* restore suffix from libname */
382: if (s) s[0] = '.';
383: if (!match) {
384: /* open the library and add to end of list */
385: PetscDLLibraryOpen(comm,libname,&list);
386: PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
387: if (!*outlist) {
388: *outlist = list;
389: } else {
390: prev->next = list;
391: }
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: PetscTruth match,dir;
425: char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
426: char *libname,suffix[16],*s;
427: PetscToken token;
431:
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: PetscTruth 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: }
529: /* ------------------------------------------------------------------------------*/
531: /*
532: Contains the list of registered CCA components
533: */
534: PetscFList CCAList = 0;
538: /*@C
539: PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
540: of the search path.
542: Collective on MPI_Comm
544: Input Parameters:
545: + comm - MPI communicator
546: - dirname - name of directory to check
548: Output Parameter:
549: . outlist - list of libraries
551: Level: developer
553: Notes: if library is already in path will not add it.
554: @*/
555: PetscErrorCode PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char dirname[])
556: {
558: size_t l;
559: PetscTruth dir;
560: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
561: char *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
562: FILE *fp;
563: PetscToken token1, token2;
564: int err;
567: /* is dirname a directory? */
568: PetscTestDirectory(dirname,'r',&dir);
569: if (!dir) return(0);
571: PetscInfo1(0,"Checking directory %s for CCA components\n",dirname);
572: PetscStrcpy(program,dirname);
573: PetscStrcat(program,"/*.cca");
575: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
576: if (!dir) return(0);
578: PetscStrcpy(suffix,".");
579: PetscStrcat(suffix,PETSC_SLSUFFIX);
580: PetscTokenCreate(buf,'\n',&token1);
581: PetscTokenFind(token1,&libname1);
582: while (libname1) {
583: fp = fopen(libname1,"r"); if (!fp) continue;
584: while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
585: if (found[0] == '!') continue;
586: PetscStrstr(found,suffix,&f2);
587: if (f2) { /* found library name */
588: if (found[0] == '/') {
589: lib = found;
590: } else {
591: PetscStrcpy(libname,dirname);
592: PetscStrlen(libname,&l);
593: if (libname[l-1] != '/') {PetscStrcat(libname,"/");}
594: PetscStrcat(libname,found);
595: lib = libname;
596: }
597: PetscDLLibraryAppend(comm,outlist,lib);
598: } else {
599: PetscInfo2(0,"CCA Component function and name: %s from %s\n",found,libname1);
600: PetscTokenCreate(found,' ',&token2);
601: PetscTokenFind(token2,&func);
602: PetscTokenFind(token2,&funcname);
603: PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);
604: PetscTokenDestroy(token2);
605: }
606: }
607: err = fclose(fp);
608: if (err) SETERRQ(PETSC_ERR_SYS,"fclose() failed on file");
609: PetscTokenFind(token1,&libname1);
610: }
611: PetscTokenDestroy(token1);
612: return(0);
613: }