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