Actual source code: dl.c

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

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

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

 31:      Collective

 33:    Input Parameters:
 34: +   comm - processors that are opening the library
 35: -   libname - name of the library, can be relative or absolute

 37:    Output Parameters:
 38: +   name - actual name of file on local filesystem if found
 39: .   llen - length of the name buffer
 40: -   found - true if the file exists

 42:    Level: developer

 44:    Notes:
 45:    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]

 47:    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
 48:    occurring in directoryname and filename will be replaced with appropriate values.
 49: @*/
 50: PetscErrorCode  PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool  *found)
 51: {
 52:   char           *buf,*par2,suffix[16],*gz,*so;
 53:   size_t         len;

 55:   /*
 56:      make copy of library name and replace $PETSC_ARCH etc
 57:      so we can add to the end of it to look for something like .so.1.0 etc.
 58:   */
 59:   PetscStrlen(libname,&len);
 60:   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);
 61:   PetscMalloc1(len,&buf);
 62:   par2 = buf;
 63:   PetscStrreplace(comm,libname,par2,len);

 65:   /* temporarily remove .gz if it ends library name */
 66:   PetscStrrstr(par2,".gz",&gz);
 67:   if (gz) {
 68:     PetscStrlen(gz,&len);
 69:     if (len != 3) gz  = NULL; /* do not end (exactly) with .gz */
 70:     else          *gz = 0;    /* ends with .gz, so remove it   */
 71:   }
 72:   /* strip out .a from it if user put it in by mistake */
 73:   PetscStrlen(par2,&len);
 74:   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;

 76:   PetscFileRetrieve(comm,par2,lname,llen,found);
 77:   if (!(*found)) {
 78:     /* see if library name does already not have suffix attached */
 79:     PetscStrncpy(suffix,".",sizeof(suffix));
 80:     PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
 81:     PetscStrrstr(par2,suffix,&so);
 82:     /* and attach the suffix if it is not there */
 83:     if (!so) PetscStrcat(par2,suffix);

 85:     /* restore the .gz suffix if it was there */
 86:     if (gz) PetscStrcat(par2,".gz");

 88:     /* and finally retrieve the file */
 89:     PetscFileRetrieve(comm,par2,lname,llen,found);
 90:   }

 92:   PetscFree(buf);
 93:   return 0;
 94: }

 96: /*@C
 97:    PetscDLLibraryOpen - Opens a PETSc dynamic link library

 99:      Collective

101:    Input Parameters:
102: +   comm - processors that are opening the library
103: -   path - name of the library, can be relative or absolute

105:    Output Parameter:
106: .   entry - a PETSc dynamic link library entry

108:    Level: developer

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

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

116:    ${PETSC_ARCH} occurring in directoryname and filename
117:    will be replaced with the appropriate value.

119: .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
120: @*/
121: PetscErrorCode  PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
122: {
123:   PetscBool      foundlibrary,match;
124:   char           libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
125:   char           *basename,registername[128];
126:   PetscDLHandle  handle;
127:   PetscErrorCode (*func)(void) = NULL;


132:   *entry = NULL;

134:   /* retrieve the library */
135:   PetscInfo(NULL,"Retrieving %s\n",path);
136:   PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
138:   /* Eventually ./configure should determine if the system needs an executable dynamic library */
139: #define PETSC_USE_NONEXECUTABLE_SO
140: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
141:   PetscTestFile(par2,'x',&foundlibrary);
143: #endif

145:   /* copy path and setup shared library suffix  */
146:   PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
147:   PetscStrncpy(suffix,".",sizeof(suffix));
148:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
149:   /* remove wrong suffixes from libname */
150:   PetscStrrstr(libname,".gz",&s);
151:   if (s && s[3] == 0) s[0] = 0;
152:   PetscStrrstr(libname,".a",&s);
153:   if (s && s[2] == 0) s[0] = 0;
154:   /* remove shared suffix from libname */
155:   PetscStrrstr(libname,suffix,&s);
156:   if (s) s[0] = 0;

158:   /* open the dynamic library */
159:   PetscInfo(NULL,"Opening dynamic library %s\n",libname);
160:   PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);

162:   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
163:   PetscStrrchr(libname,'/',&basename); /* XXX Windows ??? */
164:   if (!basename) basename = libname;
165:   PetscStrncmp(basename,"lib",3,&match);
166:   if (match) basename = basename + 3;
167:   else {
168:     PetscInfo(NULL,"Dynamic library %s does not have lib prefix\n",libname);
169:   }
170:   for (s=basename; *s; s++) if (*s == '-') *s = '_';
171:   PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername));
172:   PetscStrlcat(registername,basename,sizeof(registername));
173:   PetscDLSym(handle,registername,(void**)&func);
174:   if (func) {
175:     PetscInfo(NULL,"Loading registered routines from %s\n",libname);
176:     (*func)();
177:   } else {
178:     PetscInfo(NULL,"Dynamic library %s does not have symbol %s\n",libname,registername);
179:   }

181:   PetscNew(entry);
182:   (*entry)->next   = NULL;
183:   (*entry)->handle = handle;
184:   PetscStrcpy((*entry)->libname,libname);
185:   return 0;
186: }

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

191:    Collective

193:    Input Parameters:
194: +  comm - communicator that will open the library
195: .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
196: .  path     - optional complete library name (if provided checks here before checking outlist)
197: -  insymbol - name of symbol

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

202:    Level: developer

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

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

210: @*/
211: PetscErrorCode  PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
212: {
213:   char           libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
214:   PetscDLLibrary nlist,prev,list = NULL;


221:   if (outlist) list = *outlist;
222:   *value = NULL;

224:   PetscStrchr(insymbol,'(',&s);
225:   if (s) {
226:     /* make copy of symbol so we can edit it in place */
227:     PetscStrallocpy(insymbol,&symbol);
228:     /* If symbol contains () then replace with a NULL, to support functionname() */
229:     PetscStrchr(symbol,'(',&s);
230:     s[0] = 0;
231:   } else symbol = (char*)insymbol;

233:   /*
234:        Function name does include library
235:        -------------------------------------
236:   */
237:   if (path && path[0] != '\0') {
238:     /* copy path and remove suffix from libname */
239:     PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);
240:     PetscStrncpy(suffix,".",sizeof(suffix));
241:     PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));
242:     PetscStrrstr(libname,suffix,&s);
243:     if (s) s[0] = 0;
244:     /* Look if library is already opened and in path */
245:     prev  = NULL;
246:     nlist = list;
247:     while (nlist) {
248:       PetscBool match;
249:       PetscStrcmp(nlist->libname,libname,&match);
250:       if (match) goto done;
251:       prev  = nlist;
252:       nlist = nlist->next;
253:     }
254:     /* open the library and append it to path */
255:     PetscDLLibraryOpen(comm,path,&nlist);
256:     PetscInfo(NULL,"Appending %s to dynamic library search path\n",path);
257:     if (prev) prev->next = nlist;
258:     else {if (outlist) *outlist   = nlist;}

260: done:;
261:     PetscDLSym(nlist->handle,symbol,value);
262:     if (*value) {
263:       PetscInfo(NULL,"Loading function %s from dynamic library %s\n",insymbol,path);
264:     }

266:     /*
267:          Function name does not include library so search path
268:          -----------------------------------------------------
269:     */
270:   } else {
271:     while (list) {
272:       PetscDLSym(list->handle,symbol,value);
273:       if (*value) {
274:         PetscInfo(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
275:         break;
276:       }
277:       list = list->next;
278:     }
279:     if (!*value) {
280:       PetscDLSym(NULL,symbol,value);
281:       if (*value) {
282:         PetscInfo(NULL,"Loading symbol %s from object code\n",symbol);
283:       }
284:     }
285:   }

287:   if (symbol != insymbol) {
288:     PetscFree(symbol);
289:   }
290:   return 0;
291: }

293: /*@C
294:      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
295:                 of the search path.

297:      Collective

299:      Input Parameters:
300: +     comm - MPI communicator
301: -     path - name of the library

303:      Output Parameter:
304: .     outlist - list of libraries

306:      Level: developer

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

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

314: .seealso: PetscDLLibraryOpen()
315: @*/
316: PetscErrorCode  PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
317: {
318:   PetscDLLibrary list,prev;
319:   size_t         len;
320:   PetscBool      match,dir;
321:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
322:   char           *libname,suffix[16],*s;
323:   PetscToken     token;


327:   /* is path a directory? */
328:   PetscTestDirectory(path,'r',&dir);
329:   if (dir) {
330:     PetscInfo(NULL,"Checking directory %s for dynamic libraries\n",path);
331:     PetscStrncpy(program,path,sizeof(program));
332:     PetscStrlen(program,&len);
333:     if (program[len-1] == '/') {
334:       PetscStrlcat(program,"*.",sizeof(program));
335:     } else {
336:       PetscStrlcat(program,"/*.",sizeof(program));
337:     }
338:     PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));

340:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
341:     if (!dir) return 0;
342:   } else {
343:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
344:   }
345:   PetscStrncpy(suffix,".",sizeof(suffix));
346:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));

348:   PetscTokenCreate(found,'\n',&token);
349:   PetscTokenFind(token,&libname);
350:   while (libname) {
351:     /* remove suffix from libname */
352:     PetscStrrstr(libname,suffix,&s);
353:     if (s) s[0] = 0;
354:     /* see if library was already open then we are done */
355:     list  = prev = *outlist;
356:     match = PETSC_FALSE;
357:     while (list) {
358:       PetscStrcmp(list->libname,libname,&match);
359:       if (match) break;
360:       prev = list;
361:       list = list->next;
362:     }
363:     /* restore suffix from libname */
364:     if (s) s[0] = '.';
365:     if (!match) {
366:       /* open the library and add to end of list */
367:       PetscDLLibraryOpen(comm,libname,&list);
368:       PetscInfo(NULL,"Appending %s to dynamic library search path\n",libname);
369:       if (!*outlist) *outlist   = list;
370:       else           prev->next = list;
371:     }
372:     PetscTokenFind(token,&libname);
373:   }
374:   PetscTokenDestroy(&token);
375:   return 0;
376: }

378: /*@C
379:      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
380:                  the search path.

382:      Collective

384:      Input Parameters:
385: +     comm - MPI communicator
386: -     path - name of the library

388:      Output Parameter:
389: .     outlist - list of libraries

391:      Level: developer

393:      Notes:
394:     If library is already in path will remove old reference.

396: @*/
397: PetscErrorCode  PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
398: {
399:   PetscDLLibrary list,prev;
400:   size_t         len;
401:   PetscBool      match,dir;
402:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
403:   char           *libname,suffix[16],*s;
404:   PetscToken     token;


408:   /* is path a directory? */
409:   PetscTestDirectory(path,'r',&dir);
410:   if (dir) {
411:     PetscInfo(NULL,"Checking directory %s for dynamic libraries\n",path);
412:     PetscStrncpy(program,path,sizeof(program));
413:     PetscStrlen(program,&len);
414:     if (program[len-1] == '/') {
415:       PetscStrlcat(program,"*.",sizeof(program));
416:     } else {
417:       PetscStrlcat(program,"/*.",sizeof(program));
418:     }
419:     PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));

421:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
422:     if (!dir) return 0;
423:   } else {
424:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
425:   }

427:   PetscStrncpy(suffix,".",sizeof(suffix));
428:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));

430:   PetscTokenCreate(found,'\n',&token);
431:   PetscTokenFind(token,&libname);
432:   while (libname) {
433:     /* remove suffix from libname */
434:     PetscStrstr(libname,suffix,&s);
435:     if (s) s[0] = 0;
436:     /* see if library was already open and move it to the front */
437:     prev  = NULL;
438:     list  = *outlist;
439:     match = PETSC_FALSE;
440:     while (list) {
441:       PetscStrcmp(list->libname,libname,&match);
442:       if (match) {
443:         PetscInfo(NULL,"Moving %s to begin of dynamic library search path\n",libname);
444:         if (prev) prev->next = list->next;
445:         if (prev) list->next = *outlist;
446:         *outlist = list;
447:         break;
448:       }
449:       prev = list;
450:       list = list->next;
451:     }
452:     /* restore suffix from libname */
453:     if (s) s[0] = '.';
454:     if (!match) {
455:       /* open the library and add to front of list */
456:       PetscDLLibraryOpen(comm,libname,&list);
457:       PetscInfo(NULL,"Prepending %s to dynamic library search path\n",libname);
458:       list->next = *outlist;
459:       *outlist   = list;
460:     }
461:     PetscTokenFind(token,&libname);
462:   }
463:   PetscTokenDestroy(&token);
464:   return 0;
465: }

467: /*@C
468:      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.

470:     Collective on PetscDLLibrary

472:     Input Parameter:
473: .     head - library list

475:      Level: developer

477: @*/
478: PetscErrorCode  PetscDLLibraryClose(PetscDLLibrary list)
479: {
480:   PetscBool      done = PETSC_FALSE;
481:   PetscDLLibrary prev,tail;

483:   if (!list) return 0;
484:   /* traverse the list in reverse order */
485:   while (!done) {
486:     if (!list->next) done = PETSC_TRUE;
487:     prev = tail = list;
488:     while (tail->next) {
489:       prev = tail;
490:       tail = tail->next;
491:     }
492:     prev->next = NULL;
493:     /* close the dynamic library and free the space in entry data-structure*/
494:     PetscInfo(NULL,"Closing dynamic library %s\n",tail->libname);
495:     PetscDLClose(&tail->handle);
496:     PetscFree(tail);
497:   }
498:   return 0;
499: }