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: }