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