Actual source code: dl.c

petsc-3.4.5 2014-06-29
  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 <petsc-private/petscimpl.h>

  8: /* ------------------------------------------------------------------------------*/
  9: /*
 10:       Code to maintain a list of opened dynamic libraries and load symbols
 11: */
 12: struct _n_PetscDLLibrary {
 13:   PetscDLLibrary next;
 14:   PetscDLHandle  handle;
 15:   char           libname[PETSC_MAX_PATH_LEN];
 16: };

 20: PetscErrorCode  PetscDLLibraryPrintPath(PetscDLLibrary libs)
 21: {
 23:   while (libs) {
 24:     PetscErrorPrintf("  %s\n",libs->libname);
 25:     libs = libs->next;
 26:   }
 27:   return(0);
 28: }

 32: /*@C
 33:    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
 34:      (if it is remote), indicates if it exits and its local name.

 36:      Collective on MPI_Comm

 38:    Input Parameters:
 39: +   comm - processors that are opening the library
 40: -   libname - name of the library, can be relative or absolute

 42:    Output Parameter:
 43: +   name - actual name of file on local filesystem if found
 44: .   llen - length of the name buffer
 45: -   found - true if the file exists

 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,PetscBool  *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;

 83:   PetscFileRetrieve(comm,par2,lname,llen,found);
 84:   if (!(*found)) {
 85:     /* see if library name does already not have suffix attached */
 86:     PetscStrcpy(suffix,".");
 87:     PetscStrcat(suffix,PETSC_SLSUFFIX);
 88:     PetscStrrstr(par2,suffix,&so);
 89:     /* and attach the suffix if it is not there */
 90:     if (!so) { PetscStrcat(par2,suffix); }

 92:     /* restore the .gz suffix if it was there */
 93:     if (gz) { PetscStrcat(par2,".gz"); }

 95:     /* and finally retrieve the file */
 96:     PetscFileRetrieve(comm,par2,lname,llen,found);
 97:   }

 99:   PetscFree(buf);
100:   return(0);
101: }


106: /*@C
107:    PetscDLLibraryOpen - Opens a PETSc dynamic link library

109:      Collective on MPI_Comm

111:    Input Parameters:
112: +   comm - processors that are opening the library
113: -   path - name of the library, can be relative or absolute

115:    Output Parameter:
116: .   entry - a PETSc dynamic link library entry

118:    Level: developer

120:    Notes:
121:    [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]

123:    If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
124:    when the library is opened.

126:    ${PETSC_ARCH} occuring in directoryname and filename
127:    will be replaced with the appropriate value.

129: .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
130: @*/
131: PetscErrorCode  PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
132: {
134:   PetscBool      foundlibrary,match;
135:   char           libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
136:   char           *basename,registername[128];
137:   PetscDLHandle  handle;
138:   PetscErrorCode (*func)(void) = NULL;
139:   size_t         len;


145:   *entry = NULL;

147:   /* retrieve the library */
148:   PetscInfo1(0,"Retrieving %s\n",path);
149:   PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
150:   if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",path);
151:   /* Eventually ./configure should determine if the system needs an executable dynamic library */
152: #define PETSC_USE_NONEXECUTABLE_SO
153: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
154:   PetscTestFile(par2,'x',&foundlibrary);
155:   if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",path,par2);
156: #endif

158:   /* copy path and setup shared library suffix  */
159:   PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
160:   PetscStrcpy(suffix,".");
161:   PetscStrcat(suffix,PETSC_SLSUFFIX);
162:   /* remove wrong suffixes from libname */
163:   PetscStrrstr(libname,".gz",&s);
164:   if (s && s[3] == 0) s[0] = 0;
165:   PetscStrrstr(libname,".a",&s);
166:   if (s && s[2] == 0) s[0] = 0;
167:   /* remove shared suffix from libname */
168:   PetscStrrstr(libname,suffix,&s);
169:   if (s) s[0] = 0;

171:   /* open the dynamic library */
172:   PetscInfo1(0,"Opening dynamic library %s\n",libname);
173:   PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);

175:   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
176:   PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
177:   if (!basename) basename = libname;
178:   PetscStrncmp(basename,"lib",3,&match);
179:   if (match) basename = basename + 3;
180:   else {
181:     PetscInfo1(0,"Dynamic library %s does not have lib prefix\n",libname);
182:   }
183:   for (s=basename; *s; s++) if (*s == '-') *s = '_';
184:   PetscStrlen(basename,&len);
185:   PetscStrcpy(registername,"PetscDLLibraryRegister_");
186:   PetscStrncat(registername,basename,len);
187:   PetscDLSym(handle,registername,(void**)&func);
188:   if (func) {
189:     PetscInfo1(0,"Loading registered routines from %s\n",libname);
190:     (*func)();
191:   } else {
192:     PetscInfo2(0,"Dynamic library %s does not have symbol %s\n",libname,registername);
193:   }

195:   PetscNew(struct _n_PetscDLLibrary,entry);
196:   (*entry)->next   = 0;
197:   (*entry)->handle = handle;
198:   PetscStrcpy((*entry)->libname,libname);
199:   return(0);
200: }

204: /*@C
205:    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.

207:    Collective on MPI_Comm

209:    Input Parameter:
210: +  comm - communicator that will open the library
211: .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
212: .  path     - optional complete library name (if provided checks here before checking outlist)
213: -  insymbol - name of symbol

215:    Output Parameter:
216: .  value - if symbol not found then this value is set to NULL

218:    Level: developer

220:    Notes: Symbol can be of the form
221:         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional

223:         Will attempt to (retrieve and) open the library if it is not yet been opened.

225: @*/
226: PetscErrorCode  PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
227: {
228:   char           libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
229:   PetscDLLibrary nlist,prev,list = NULL;


238:   if (outlist) list = *outlist;
239:   *value = 0;


242:   PetscStrchr(insymbol,'(',&s);
243:   if (s) {
244:     /* make copy of symbol so we can edit it in place */
245:     PetscStrallocpy(insymbol,&symbol);
246:     /* If symbol contains () then replace with a NULL, to support functionname() */
247:     PetscStrchr(symbol,'(',&s);
248:     s[0] = 0;
249:   } else symbol = (char*)insymbol;

251:   /*
252:        Function name does include library
253:        -------------------------------------
254:   */
255:   if (path && path[0] != '\0') {
256:     /* copy path and remove suffix from libname */
257:     PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
258:     PetscStrcpy(suffix,".");
259:     PetscStrcat(suffix,PETSC_SLSUFFIX);
260:     PetscStrrstr(libname,suffix,&s);
261:     if (s) s[0] = 0;
262:     /* Look if library is already opened and in path */
263:     prev  = 0;
264:     nlist = list;
265:     while (nlist) {
266:       PetscBool match;
267:       PetscStrcmp(nlist->libname,libname,&match);
268:       if (match) goto done;
269:       prev  = nlist;
270:       nlist = nlist->next;
271:     }
272:     /* open the library and append it to path */
273:     PetscDLLibraryOpen(comm,path,&nlist);
274:     PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
275:     if (prev) prev->next = nlist;
276:     else      *outlist   = nlist;

278: done:;
279:     PetscDLSym(nlist->handle,symbol,value);
280:     if (*value) {
281:       PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
282:     }

284:     /*
285:          Function name does not include library so search path
286:          -----------------------------------------------------
287:     */
288:   } else {
289:     while (list) {
290:       PetscDLSym(list->handle,symbol,value);
291:       if (*value) {
292:         PetscInfo2(0,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
293:         break;
294:       }
295:       list = list->next;
296:     }
297:     if (!*value) {
298:       PetscDLSym(NULL,symbol,value);
299:       if (*value) {
300:         PetscInfo1(0,"Loading symbol %s from object code\n",symbol);
301:       }
302:     }
303:   }

305:   if (symbol != insymbol) {
306:     PetscFree(symbol);
307:   }
308:   return(0);
309: }

313: /*@C
314:      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
315:                 of the search path.

317:      Collective on MPI_Comm

319:      Input Parameters:
320: +     comm - MPI communicator
321: -     path - name of the library

323:      Output Parameter:
324: .     outlist - list of libraries

326:      Level: developer

328:      Notes: if library is already in path will not add it.

330:   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
331:       when the library is opened.

333: .seealso: PetscDLLibraryOpen()
334: @*/
335: PetscErrorCode  PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
336: {
337:   PetscDLLibrary list,prev;
339:   size_t         len;
340:   PetscBool      match,dir;
341:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
342:   char           *libname,suffix[16],*s;
343:   PetscToken     token;


348:   /* is path a directory? */
349:   PetscTestDirectory(path,'r',&dir);
350:   if (dir) {
351:     PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
352:     PetscStrcpy(program,path);
353:     PetscStrlen(program,&len);
354:     if (program[len-1] == '/') {
355:       PetscStrcat(program,"*.");
356:     } else {
357:       PetscStrcat(program,"/*.");
358:     }
359:     PetscStrcat(program,PETSC_SLSUFFIX);

361:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
362:     if (!dir) return(0);
363:   } else {
364:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
365:   }
366:   PetscStrcpy(suffix,".");
367:   PetscStrcat(suffix,PETSC_SLSUFFIX);

369:   PetscTokenCreate(found,'\n',&token);
370:   PetscTokenFind(token,&libname);
371:   while (libname) {
372:     /* remove suffix from libname */
373:     PetscStrrstr(libname,suffix,&s);
374:     if (s) s[0] = 0;
375:     /* see if library was already open then we are done */
376:     list  = prev = *outlist;
377:     match = PETSC_FALSE;
378:     while (list) {
379:       PetscStrcmp(list->libname,libname,&match);
380:       if (match) break;
381:       prev = list;
382:       list = list->next;
383:     }
384:     /* restore suffix from libname */
385:     if (s) s[0] = '.';
386:     if (!match) {
387:       /* open the library and add to end of list */
388:       PetscDLLibraryOpen(comm,libname,&list);
389:       PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
390:       if (!*outlist) *outlist   = list;
391:       else           prev->next = list;
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:   PetscBool      match,dir;
425:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
426:   char           *libname,suffix[16],*s;
427:   PetscToken     token;


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