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 PetscInfo(NULL, "Dynamic library %s does not have lib prefix\n", libname);
168:   for (s = basename; *s; s++)
169:     if (*s == '-') *s = '_';
170:   PetscStrncpy(registername, "PetscDLLibraryRegister_", sizeof(registername));
171:   PetscStrlcat(registername, basename, sizeof(registername));
172:   PetscDLSym(handle, registername, (void **)&func);
173:   if (func) {
174:     PetscInfo(NULL, "Loading registered routines from %s\n", libname);
175:     (*func)();
176:   } else {
177:     PetscInfo(NULL, "Dynamic library %s does not have symbol %s\n", libname, registername);
178:   }

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

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

190:    Collective

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

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

201:    Level: developer

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

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

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


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

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

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

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

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

284:   if (symbol != insymbol) PetscFree(symbol);
285:   return 0;
286: }

288: /*@C
289:      PetscDLLibraryAppend - Appends another dynamic link library to the search list, to the end
290:                 of the search path.

292:      Collective

294:      Input Parameters:
295: +     comm - MPI communicator
296: -     path - name of the library

298:      Output Parameter:
299: .     outlist - list of libraries

301:      Level: developer

303:      Note:
304:     if library is already in path will not add it.

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

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


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

335:     PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir);
336:     if (!dir) return 0;
337:   } else {
338:     PetscStrncpy(found, path, PETSC_MAX_PATH_LEN);
339:   }
340:   PetscStrncpy(suffix, ".", sizeof(suffix));
341:   PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));

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

373: /*@C
374:      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
375:                  the search path.

377:      Collective

379:      Input Parameters:
380: +     comm - MPI communicator
381: -     path - name of the library

383:      Output Parameter:
384: .     outlist - list of libraries

386:      Level: developer

388:      Note:
389:     If library is already in path will remove old reference.

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


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

416:     PetscLs(comm, program, found, 8 * PETSC_MAX_PATH_LEN, &dir);
417:     if (!dir) return 0;
418:   } else {
419:     PetscStrncpy(found, path, PETSC_MAX_PATH_LEN);
420:   }

422:   PetscStrncpy(suffix, ".", sizeof(suffix));
423:   PetscStrlcat(suffix, PETSC_SLSUFFIX, sizeof(suffix));

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

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

465:     Collective

467:     Input Parameter:
468: .     head - library list

470:      Level: developer

472: @*/
473: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list)
474: {
475:   PetscBool      done = PETSC_FALSE;
476:   PetscDLLibrary prev, tail;

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