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: {
 21:   while (libs) {
 22:     PetscErrorPrintf("  %s\n",libs->libname);
 23:     libs = libs->next;
 24:   }
 25:   return(0);
 26: }

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

 32:      Collective

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

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

 43:    Level: developer

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

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

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

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

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

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

 91:     /* and finally retrieve the file */
 92:     PetscFileRetrieve(comm,par2,lname,llen,found);
 93:   }

 95:   PetscFree(buf);
 96:   return(0);
 97: }

 99: /*@C
100:    PetscDLLibraryOpen - Opens a PETSc dynamic link library

102:      Collective

104:    Input Parameters:
105: +   comm - processors that are opening the library
106: -   path - name of the library, can be relative or absolute

108:    Output Parameter:
109: .   entry - a PETSc dynamic link library entry

111:    Level: developer

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

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

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

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


137:   *entry = NULL;

139:   /* retrieve the library */
140:   PetscInfo1(NULL,"Retrieving %s\n",path);
141:   PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
142:   if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",path);
143:   /* Eventually ./configure should determine if the system needs an executable dynamic library */
144: #define PETSC_USE_NONEXECUTABLE_SO
145: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
146:   PetscTestFile(par2,'x',&foundlibrary);
147:   if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",path,par2);
148: #endif

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

163:   /* open the dynamic library */
164:   PetscInfo1(NULL,"Opening dynamic library %s\n",libname);
165:   PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);

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

186:   PetscNew(entry);
187:   (*entry)->next   = NULL;
188:   (*entry)->handle = handle;
189:   PetscStrcpy((*entry)->libname,libname);
190:   return(0);
191: }

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

196:    Collective

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

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

207:    Level: developer

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

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

215: @*/
216: PetscErrorCode  PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
217: {
218:   char           libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
219:   PetscDLLibrary nlist,prev,list = NULL;


228:   if (outlist) list = *outlist;
229:   *value = NULL;

231:   PetscStrchr(insymbol,'(',&s);
232:   if (s) {
233:     /* make copy of symbol so we can edit it in place */
234:     PetscStrallocpy(insymbol,&symbol);
235:     /* If symbol contains () then replace with a NULL, to support functionname() */
236:     PetscStrchr(symbol,'(',&s);
237:     s[0] = 0;
238:   } else symbol = (char*)insymbol;

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

267: done:;
268:     PetscDLSym(nlist->handle,symbol,value);
269:     if (*value) {
270:       PetscInfo2(NULL,"Loading function %s from dynamic library %s\n",insymbol,path);
271:     }

273:     /*
274:          Function name does not include library so search path
275:          -----------------------------------------------------
276:     */
277:   } else {
278:     while (list) {
279:       PetscDLSym(list->handle,symbol,value);
280:       if (*value) {
281:         PetscInfo2(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);
282:         break;
283:       }
284:       list = list->next;
285:     }
286:     if (!*value) {
287:       PetscDLSym(NULL,symbol,value);
288:       if (*value) {
289:         PetscInfo1(NULL,"Loading symbol %s from object code\n",symbol);
290:       }
291:     }
292:   }

294:   if (symbol != insymbol) {
295:     PetscFree(symbol);
296:   }
297:   return(0);
298: }

300: /*@C
301:      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
302:                 of the search path.

304:      Collective

306:      Input Parameters:
307: +     comm - MPI communicator
308: -     path - name of the library

310:      Output Parameter:
311: .     outlist - list of libraries

313:      Level: developer

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

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

321: .seealso: PetscDLLibraryOpen()
322: @*/
323: PetscErrorCode  PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
324: {
325:   PetscDLLibrary list,prev;
327:   size_t         len;
328:   PetscBool      match,dir;
329:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
330:   char           *libname,suffix[16],*s;
331:   PetscToken     token;


336:   /* is path a directory? */
337:   PetscTestDirectory(path,'r',&dir);
338:   if (dir) {
339:     PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);
340:     PetscStrncpy(program,path,sizeof(program));
341:     PetscStrlen(program,&len);
342:     if (program[len-1] == '/') {
343:       PetscStrlcat(program,"*.",sizeof(program));
344:     } else {
345:       PetscStrlcat(program,"/*.",sizeof(program));
346:     }
347:     PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));

349:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
350:     if (!dir) return(0);
351:   } else {
352:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
353:   }
354:   PetscStrncpy(suffix,".",sizeof(suffix));
355:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));

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

387: /*@C
388:      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
389:                  the search path.

391:      Collective

393:      Input Parameters:
394: +     comm - MPI communicator
395: -     path - name of the library

397:      Output Parameter:
398: .     outlist - list of libraries

400:      Level: developer

402:      Notes:
403:     If library is already in path will remove old reference.

405: @*/
406: PetscErrorCode  PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
407: {
408:   PetscDLLibrary list,prev;
410:   size_t         len;
411:   PetscBool      match,dir;
412:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
413:   char           *libname,suffix[16],*s;
414:   PetscToken     token;


419:   /* is path a directory? */
420:   PetscTestDirectory(path,'r',&dir);
421:   if (dir) {
422:     PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);
423:     PetscStrncpy(program,path,sizeof(program));
424:     PetscStrlen(program,&len);
425:     if (program[len-1] == '/') {
426:       PetscStrlcat(program,"*.",sizeof(program));
427:     } else {
428:       PetscStrlcat(program,"/*.",sizeof(program));
429:     }
430:     PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));

432:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
433:     if (!dir) return(0);
434:   } else {
435:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
436:   }

438:   PetscStrncpy(suffix,".",sizeof(suffix));
439:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));

441:   PetscTokenCreate(found,'\n',&token);
442:   PetscTokenFind(token,&libname);
443:   while (libname) {
444:     /* remove suffix from libname */
445:     PetscStrstr(libname,suffix,&s);
446:     if (s) s[0] = 0;
447:     /* see if library was already open and move it to the front */
448:     prev  = NULL;
449:     list  = *outlist;
450:     match = PETSC_FALSE;
451:     while (list) {
452:       PetscStrcmp(list->libname,libname,&match);
453:       if (match) {
454:         PetscInfo1(NULL,"Moving %s to begin of dynamic library search path\n",libname);
455:         if (prev) prev->next = list->next;
456:         if (prev) list->next = *outlist;
457:         *outlist = list;
458:         break;
459:       }
460:       prev = list;
461:       list = list->next;
462:     }
463:     /* restore suffix from libname */
464:     if (s) s[0] = '.';
465:     if (!match) {
466:       /* open the library and add to front of list */
467:       PetscDLLibraryOpen(comm,libname,&list);
468:       PetscInfo1(NULL,"Prepending %s to dynamic library search path\n",libname);
469:       list->next = *outlist;
470:       *outlist   = list;
471:     }
472:     PetscTokenFind(token,&libname);
473:   }
474:   PetscTokenDestroy(&token);
475:   return(0);
476: }

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

481:     Collective on PetscDLLibrary

483:     Input Parameter:
484: .     head - library list

486:      Level: developer

488: @*/
489: PetscErrorCode  PetscDLLibraryClose(PetscDLLibrary list)
490: {
491:   PetscBool      done = PETSC_FALSE;
492:   PetscDLLibrary prev,tail;

496:   if (!list) return(0);
497:   /* traverse the list in reverse order */
498:   while (!done) {
499:     if (!list->next) done = PETSC_TRUE;
500:     prev = tail = list;
501:     while (tail->next) {
502:       prev = tail;
503:       tail = tail->next;
504:     }
505:     prev->next = NULL;
506:     /* close the dynamic library and free the space in entry data-structure*/
507:     PetscInfo1(NULL,"Closing dynamic library %s\n",tail->libname);
508:     PetscDLClose(&tail->handle);
509:     PetscFree(tail);
510:   }
511:   return(0);
512: }