Date: 2022-03-31T04:46:05+00:00

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