Actual source code: dl.c
1: /*$Id: dl.c,v 1.71 2001/04/10 19:34:28 bsmith Exp $*/
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 petsc.h
8: #include petscsys.h
9: #include "petscfix.h"
10: #if defined(PETSC_HAVE_PWD_H)
11: #include <pwd.h>
12: #endif
13: #include <ctype.h>
14: #include <sys/types.h>
15: #include <sys/stat.h>
16: #if defined(PETSC_HAVE_UNISTD_H)
17: #include <unistd.h>
18: #endif
19: #if defined(PETSC_HAVE_STDLIB_H)
20: #include <stdlib.h>
21: #endif
22: #if !defined(PARCH_win32)
23: #include <sys/utsname.h>
24: #endif
25: #if defined(PARCH_win32)
26: #include <windows.h>
27: #include <io.h>
28: #include <direct.h>
29: #endif
30: #if defined (PARCH_win32_gnu)
31: #include <windows.h>
32: #endif
33: #include <fcntl.h>
34: #include <time.h>
35: #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
36: #include <sys/systeminfo.h>
37: #endif
38: #include "petscfix.h"
40: #ifndef MAXPATHLEN
41: #define MAXPATHLEN 1024
42: #endif
44: /* ------------------------------------------------------------------------------*/
45: /*
46: Code to maintain a list of opened dynamic libraries and load symbols
47: */
48: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
49: #include <dlfcn.h>
51: struct _PetscDLLibraryList {
52: PetscDLLibraryList next;
53: void *handle;
54: char libname[1024];
55: };
57: EXTERN_C_BEGIN
58: extern int Petsc_DelTag(MPI_Comm,int,void*,void*);
59: EXTERN_C_END
61: int PetscDLLibraryPrintPath(void)
62: {
63: PetscDLLibraryList libs;
66: PetscErrorPrintf("Unable to find function. Search path:n");
67: libs = DLLibrariesLoaded;
68: while (libs) {
69: PetscErrorPrintf(" %sn",libs->libname);
70: libs = libs->next;
71: }
72: return(0);
73: }
75: /*@C
76: PetscDLLibraryGetInfo - Gets the text information from a PETSc
77: dynamic library
79: Not Collective
81: Input Parameters:
82: . handle - library handle returned by PetscDLLibraryOpen()
84: Level: developer
86: @*/
87: int PetscDLLibraryGetInfo(void *handle,char *type,char **mess)
88: {
89: int ierr,(*sfunc)(const char *,const char*,char **);
92: sfunc = (int (*)(const char *,const char*,char **)) dlsym(handle,"PetscDLLibraryInfo");
93: if (!sfunc) {
94: *mess = "No library information in the filen";
95: } else {
96: (*sfunc)(0,type,mess);
97: }
98: return(0);
99: }
101: /*@C
102: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
103: (if it is remote), indicates if it exits and its local name.
105: Collective on MPI_Comm
107: Input Parameters:
108: + comm - processors that are opening the library
109: - libname - name of the library, can be relative or absolute
111: Output Parameter:
112: . handle - library handle
114: Level: developer
116: Notes:
117: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
119: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${BOPT}, or ${any environmental variable}
120: occuring in directoryname and filename will be replaced with appropriate values.
121: @*/
122: int PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,int llen,PetscTruth *found)
123: {
124: char *par2,buff[10],*en,*gz;
125: int ierr,len1,len2,len;
126: PetscTruth tflg,flg;
130: /*
131: make copy of library name and replace $PETSC_ARCH and $BOPT and
132: so we can add to the end of it to look for something like .so.1.0 etc.
133: */
134: PetscStrlen(libname,&len);
135: len = PetscMax(4*len,1024);
136: PetscMalloc(len*sizeof(char),&par2);
137: PetscStrreplace(comm,libname,par2,len);
139: /*
140: Remove any file: header
141: */
142: PetscStrncmp(par2,"file:",5,&tflg);
143: if (tflg) {
144: PetscStrcpy(par2,par2+5);
145: }
147: /* strip out .a from it if user put it in by mistake */
148: ierr = PetscStrlen(par2,&len);
149: if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
151: /* remove .gz if it ends library name */
152: PetscStrstr(par2,".gz",&gz);
153: if (gz) {
154: PetscStrlen(gz,&len);
155: if (len == 3) {
156: *gz = 0;
157: }
158: }
160: /* see if library name does already not have suffix attached */
161: PetscStrcpy(buff,".");
162: PetscStrcat(buff,PETSC_SLSUFFIX);
163: PetscStrstr(par2,buff,&en);
164: if (en) {
165: PetscStrlen(en,&len1);
166: PetscStrlen(PETSC_SLSUFFIX,&len2);
167: flg = (PetscTruth) (len1 != 1 + len2);
168: } else {
169: flg = PETSC_TRUE;
170: }
171: if (flg) {
172: PetscStrcat(par2,".");
173: PetscStrcat(par2,PETSC_SLSUFFIX);
174: }
176: /* put the .gz back on if it was there */
177: if (gz) {
178: PetscStrcat(par2,".gz");
179: }
181: PetscFileRetrieve(comm,par2,lname,llen,found);
182: PetscFree(par2);
183: return(0);
184: }
186: /*@C
187: PetscDLLibraryOpen - Opens a dynamic link library
189: Collective on MPI_Comm
191: Input Parameters:
192: + comm - processors that are opening the library
193: - libname - name of the library, can be relative or absolute
195: Output Parameter:
196: . handle - library handle
198: Level: developer
200: Notes:
201: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
203: ${PETSC_ARCH} and ${BOPT} occuring in directoryname and filename
204: will be replaced with appropriate values.
205: @*/
206: int PetscDLLibraryOpen(MPI_Comm comm,const char libname[],void **handle)
207: {
208: char *par2,ierr;
209: PetscTruth foundlibrary;
210: int (*func)(const char*);
214: PetscMalloc(1024*sizeof(char),&par2);
215: PetscDLLibraryRetrieve(comm,libname,par2,1024,&foundlibrary);
216: if (!foundlibrary) {
217: SETERRQ1(1,"Unable to locate dynamic library:n %sn",libname);
218: }
220: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
221: ierr = PetscTestFile(par2,'x',&foundlibrary);
222: if (!foundlibrary) {
223: SETERRQ2(1,"Dynamic library is not executable:n %sn %sn",libname,par2);
224: }
225: #endif
227: /*
228: Mode indicates symbols required by symbol loaded with dlsym()
229: are only loaded when required (not all together) also indicates
230: symbols required can be contained in other libraries also opened
231: with dlopen()
232: */
233: PetscLogInfo(0,"PetscDLLibraryOpen:Opening %sn",libname);
234: #if defined(PETSC_HAVE_RTLD_GLOBAL)
235: *handle = dlopen(par2,RTLD_LAZY | RTLD_GLOBAL);
236: #else
237: *handle = dlopen(par2,RTLD_LAZY);
238: #endif
240: if (!*handle) {
241: SETERRQ3(1,"Unable to open dynamic library:n %sn %sn Error message from dlopen() %sn",
242: libname,par2,dlerror());
243: }
245: /* run the function PetscFListAddDynamic() if it is in the library */
246: func = (int (*)(const char *)) dlsym(*handle,"PetscDLLibraryRegister");
247: if (func) {
248: (*func)(libname);
249: PetscLogInfo(0,"PetscDLLibraryOpen:Loading registered routines from %sn",libname);
250: }
251: if (PetscLogPrintInfo) {
252: int (*sfunc)(const char *,const char*,char **);
253: char *mess;
255: sfunc = (int (*)(const char *,const char*,char **)) dlsym(*handle,"PetscDLLibraryInfo");
256: if (sfunc) {
257: (*sfunc)(libname,"Contents",&mess);
258: if (mess) {
259: PetscLogInfo(0,"Contents:n %s",mess);
260: }
261: (*sfunc)(libname,"Authors",&mess);
262: if (mess) {
263: PetscLogInfo(0,"Authors:n %s",mess);
264: }
265: (*sfunc)(libname,"Version",&mess);
266: if (mess) {
267: PetscLogInfo(0,"Version:n %sn",mess);
268: }
269: }
270: }
272: PetscFree(par2);
273: return(0);
274: }
276: /*@C
277: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
279: Collective on MPI_Comm
281: Input Parameter:
282: + path - optional complete library name
283: - insymbol - name of symbol
285: Output Parameter:
286: . value
288: Level: developer
290: Notes: Symbol can be of the form
291: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
293: Will attempt to (retrieve and) open the library if it is not yet been opened.
295: @*/
296: int PetscDLLibrarySym(MPI_Comm comm,PetscDLLibraryList *inlist,const char path[],const char insymbol[],void **value)
297: {
298: char *par1,*symbol;
299: int ierr,len;
300: PetscDLLibraryList nlist,prev,list;
303: if (inlist) list = *inlist; else list = PETSC_NULL;
304: *value = 0;
306: /* make copy of symbol so we can edit it in place */
307: PetscStrlen(insymbol,&len);
308: PetscMalloc((len+1)*sizeof(char),&symbol);
309: PetscStrcpy(symbol,insymbol);
311: /*
312: If symbol contains () then replace with a NULL, to support functionname()
313: */
314: PetscStrchr(symbol,'(',&par1);
315: if (par1) *par1 = 0;
318: /*
319: Function name does include library
320: -------------------------------------
321: */
322: if (path && path[0] != '0') {
323: void *handle;
324:
325: /*
326: Look if library is already opened and in path
327: */
328: nlist = list;
329: prev = 0;
330: while (nlist) {
331: PetscTruth match;
333: PetscStrcmp(nlist->libname,path,&match);
334: if (match) {
335: handle = nlist->handle;
336: goto done;
337: }
338: prev = nlist;
339: nlist = nlist->next;
340: }
341: PetscDLLibraryOpen(comm,path,&handle);
343: ierr = PetscNew(struct _PetscDLLibraryList,&nlist);
344: nlist->next = 0;
345: nlist->handle = handle;
346: PetscStrcpy(nlist->libname,path);
348: if (prev) {
349: prev->next = nlist;
350: } else {
351: if (inlist) *inlist = nlist;
352: else {PetscDLLibraryClose(nlist);}
353: }
354: PetscLogInfo(0,"PetscDLLibraryAppend:Appending %s to dynamic library search pathn",symbol);
356: done:;
357: *value = dlsym(handle,symbol);
358: if (!*value) {
359: SETERRQ2(1,"Unable to locate function %s in dynamic library %s",insymbol,path);
360: }
361: PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from dynamic library %sn",insymbol,path);
363: /*
364: Function name does not include library so search path
365: -----------------------------------------------------
366: */
367: } else {
368: while (list) {
369: *value = dlsym(list->handle,symbol);
370: if (*value) {
371: PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from dynamic library %sn",symbol,list->libname);
372: break;
373: }
374: list = list->next;
375: }
376: if (!*value) {
377: *value = dlsym(0,symbol);
378: if (*value) {
379: PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from object coden",symbol);
380: }
381: }
382: }
384: PetscFree(symbol);
385: return(0);
386: }
388: /*@C
389: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
390: of the search path.
392: Collective on MPI_Comm
394: Input Parameters:
395: + comm - MPI communicator
396: - libname - name of the library
398: Output Parameter:
399: . outlist - list of libraries
401: Level: developer
403: Notes: if library is already in path will not add it.
404: @*/
405: int PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibraryList *outlist,const char libname[])
406: {
407: PetscDLLibraryList list,prev;
408: void* handle;
409: int ierr;
413: /* see if library was already open then we are done */
414: list = prev = *outlist;
415: while (list) {
416: PetscTruth match;
418: PetscStrcmp(list->libname,libname,&match);
419: if (match) {
420: return(0);
421: }
422: prev = list;
423: list = list->next;
424: }
426: PetscDLLibraryOpen(comm,libname,&handle);
428: ierr = PetscNew(struct _PetscDLLibraryList,&list);
429: list->next = 0;
430: list->handle = handle;
431: PetscStrcpy(list->libname,libname);
433: if (!*outlist) {
434: *outlist = list;
435: } else {
436: prev->next = list;
437: }
438: PetscLogInfo(0,"PetscDLLibraryAppend:Appending %s to dynamic library search pathn",libname);
439: return(0);
440: }
442: /*@C
443: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
444: the search path.
446: Collective on MPI_Comm
448: Input Parameters:
449: + comm - MPI communicator
450: - libname - name of the library
452: Output Parameter:
453: . outlist - list of libraries
455: Level: developer
457: Notes: If library is already in path will remove old reference.
459: @*/
460: int PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibraryList *outlist,const char libname[])
461: {
462: PetscDLLibraryList list,prev;
463: void* handle;
464: int ierr;
467:
468: /* see if library was already open and move it to the front */
469: list = *outlist;
470: prev = 0;
471: while (list) {
472: PetscTruth match;
474: PetscStrcmp(list->libname,libname,&match);
475: if (match) {
476: if (prev) prev->next = list->next;
477: list->next = *outlist;
478: *outlist = list;
479: return(0);
480: }
481: prev = list;
482: list = list->next;
483: }
485: /* open the library and add to front of list */
486: PetscDLLibraryOpen(comm,libname,&handle);
488: PetscLogInfo(0,"PetscDLLibraryPrepend:Prepending %s to dynamic library search pathn",libname);
490: ierr = PetscNew(struct _PetscDLLibraryList,&list);
491: list->handle = handle;
492: list->next = *outlist;
493: PetscStrcpy(list->libname,libname);
494: *outlist = list;
496: return(0);
497: }
499: /*@C
500: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
502: Collective on PetscDLLibrary
504: Input Parameter:
505: . next - library list
507: Level: developer
509: @*/
510: int PetscDLLibraryClose(PetscDLLibraryList next)
511: {
512: PetscDLLibraryList prev;
513: int ierr;
517: while (next) {
518: prev = next;
519: next = next->next;
520: /* free the space in the prev data-structure */
521: PetscFree(prev);
522: }
523: return(0);
524: }
526: #endif