Actual source code: dl.c

petsc-master 2018-07-20
Report Typos and Errors
  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 on MPI_Comm

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

 38:    Output Parameter:
 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:    occuring 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  = 0; /* 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:   /*
100:      Some compilers when used with -std=c89 don't produce a usable PETSC_FUNCTION_NAME. Since this name is needed in PetscMallocDump()
101:      to avoid reporting the memory allocations in the function as not freed we hardwire the value here.
102:   */
103: #undef    PETSC_FUNCTION_NAME
104: #define   PETSC_FUNCTION_NAME "PetscDLLibraryOpen"

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;


144:   *entry = NULL;

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

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

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

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

193:   PetscNew(entry);
194:   (*entry)->next   = 0;
195:   (*entry)->handle = handle;
196:   PetscStrcpy((*entry)->libname,libname);
197:   return(0);
198: }

200: #undef    PETSC_FUNCTION_NAME
201: #if defined(__cplusplus)
202: #  define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_CXX
203: #else
204: #  define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_C
205: #endif

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

210:    Collective on MPI_Comm

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

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

221:    Level: developer

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

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

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


242:   if (outlist) list = *outlist;
243:   *value = 0;


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

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

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

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

309:   if (symbol != insymbol) {
310:     PetscFree(symbol);
311:   }
312:   return(0);
313: }

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

319:      Collective on MPI_Comm

321:      Input Parameters:
322: +     comm - MPI communicator
323: -     path - name of the library

325:      Output Parameter:
326: .     outlist - list of libraries

328:      Level: developer

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

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

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


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

364:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
365:     if (!dir) return(0);
366:   } else {
367:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
368:   }
369:   PetscStrncpy(suffix,".",sizeof(suffix));
370:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));

372:   PetscTokenCreate(found,'\n',&token);
373:   PetscTokenFind(token,&libname);
374:   while (libname) {
375:     /* remove suffix from libname */
376:     PetscStrrstr(libname,suffix,&s);
377:     if (s) s[0] = 0;
378:     /* see if library was already open then we are done */
379:     list  = prev = *outlist;
380:     match = PETSC_FALSE;
381:     while (list) {
382:       PetscStrcmp(list->libname,libname,&match);
383:       if (match) break;
384:       prev = list;
385:       list = list->next;
386:     }
387:     /* restore suffix from libname */
388:     if (s) s[0] = '.';
389:     if (!match) {
390:       /* open the library and add to end of list */
391:       PetscDLLibraryOpen(comm,libname,&list);
392:       PetscInfo1(0,"Appending %s to dynamic library search path\n",libname);
393:       if (!*outlist) *outlist   = list;
394:       else           prev->next = list;
395:     }
396:     PetscTokenFind(token,&libname);
397:   }
398:   PetscTokenDestroy(&token);
399:   return(0);
400: }

402: /*@C
403:      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
404:                  the search path.

406:      Collective on MPI_Comm

408:      Input Parameters:
409: +     comm - MPI communicator
410: -     path - name of the library

412:      Output Parameter:
413: .     outlist - list of libraries

415:      Level: developer

417:      Notes:
418:     If library is already in path will remove old reference.

420: @*/
421: PetscErrorCode  PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
422: {
423:   PetscDLLibrary list,prev;
425:   size_t         len;
426:   PetscBool      match,dir;
427:   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
428:   char           *libname,suffix[16],*s;
429:   PetscToken     token;


434:   /* is path a directory? */
435:   PetscTestDirectory(path,'r',&dir);
436:   if (dir) {
437:     PetscInfo1(0,"Checking directory %s for dynamic libraries\n",path);
438:     PetscStrncpy(program,path,sizeof(program));
439:     PetscStrlen(program,&len);
440:     if (program[len-1] == '/') {
441:       PetscStrlcat(program,"*.",sizeof(program));
442:     } else {
443:       PetscStrlcat(program,"/*.",sizeof(program));
444:     }
445:     PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));

447:     PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);
448:     if (!dir) return(0);
449:   } else {
450:     PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);
451:   }

453:   PetscStrncpy(suffix,".",sizeof(suffix));
454:   PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));

456:   PetscTokenCreate(found,'\n',&token);
457:   PetscTokenFind(token,&libname);
458:   while (libname) {
459:     /* remove suffix from libname */
460:     PetscStrstr(libname,suffix,&s);
461:     if (s) s[0] = 0;
462:     /* see if library was already open and move it to the front */
463:     prev  = 0;
464:     list  = *outlist;
465:     match = PETSC_FALSE;
466:     while (list) {
467:       PetscStrcmp(list->libname,libname,&match);
468:       if (match) {
469:         PetscInfo1(0,"Moving %s to begin of dynamic library search path\n",libname);
470:         if (prev) prev->next = list->next;
471:         if (prev) list->next = *outlist;
472:         *outlist = list;
473:         break;
474:       }
475:       prev = list;
476:       list = list->next;
477:     }
478:     /* restore suffix from libname */
479:     if (s) s[0] = '.';
480:     if (!match) {
481:       /* open the library and add to front of list */
482:       PetscDLLibraryOpen(comm,libname,&list);
483:       PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname);
484:       list->next = *outlist;
485:       *outlist   = list;
486:     }
487:     PetscTokenFind(token,&libname);
488:   }
489:   PetscTokenDestroy(&token);
490:   return(0);
491: }

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