Actual source code: dl.c

  2: /*
  3:       Routines for opening dynamic link libraries (DLLs), keeping a searchable
  4:    path of DLLs, obtaining remote DLLs via a URL and opening them locally.
  5: */

 7:  #include petsc.h
 8:  #include petscsys.h
  9: #include "petscfix.h"

 11: #if defined (PETSC_USE_DYNAMIC_LIBRARIES)

 13: #if defined(PETSC_HAVE_PWD_H)
 14: #include <pwd.h>
 15: #endif
 16: #include <ctype.h>
 17: #include <sys/types.h>
 18: #include <sys/stat.h>
 19: #if defined(PETSC_HAVE_UNISTD_H)
 20: #include <unistd.h>
 21: #endif
 22: #if defined(PETSC_HAVE_STDLIB_H)
 23: #include <stdlib.h>
 24: #endif
 25: #if defined(PETSC_HAVE_SYS_UTSNAME_H)
 26: #include <sys/utsname.h>
 27: #endif
 28: #if defined(PETSC_HAVE_WINDOWS_H)
 29: #include <windows.h>
 30: #endif
 31: #include <fcntl.h>
 32: #include <time.h>  
 33: #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
 34: #include <sys/systeminfo.h>
 35: #endif

 37: #endif

 39: #include "petscfix.h"


 42: /*
 43:    Contains the list of registered CCA components
 44: */
 45: PetscFList CCAList = 0;


 48: /* ------------------------------------------------------------------------------*/
 49: /*
 50:       Code to maintain a list of opened dynamic libraries and load symbols
 51: */
 52: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
 53: #if defined(PETSC_HAVE_DLFCN_H)
 54: #include <dlfcn.h>
 55: #endif
 56: struct _PetscDLLibraryList {
 57:   PetscDLLibraryList next;
 58:   void          *handle;
 59:   char          libname[PETSC_MAX_PATH_LEN];
 60: };

 63: EXTERN PetscErrorCode Petsc_DelTag(MPI_Comm,int,void*,void*);

 68: PetscErrorCode PetscDLLibraryPrintPath(void)
 69: {
 70:   PetscDLLibraryList libs;

 73:   libs = DLLibrariesLoaded;
 74:   while (libs) {
 75:     PetscErrorPrintf("  %s\n",libs->libname);
 76:     libs = libs->next;
 77:   }
 78:   return(0);
 79: }

 83: /*@C
 84:    PetscDLLibraryGetInfo - Gets the text information from a PETSc
 85:        dynamic library

 87:      Not Collective

 89:    Input Parameters:
 90: .   handle - library handle returned by PetscDLLibraryOpen()

 92:    Level: developer

 94: @*/
 95: PetscErrorCode PetscDLLibraryGetInfo(void *handle,const char type[],const char *mess[])
 96: {
 97:   PetscErrorCode ierr,(*sfunc)(const char *,const char*,const char *[]);

100: #if defined(PETSC_HAVE_DLSYM)
101:   sfunc   = (PetscErrorCode (*)(const char *,const char*,const char *[])) dlsym(handle,"PetscDLLibraryInfo");
102: #elif defined(PETSC_HAVE_GETPROCADDRESS)
103:   sfunc   = (PetscErrorCode (*)(const char *,const char*,const char *[])) GetProcAddress((HMODULE)handle,"PetscDLLibraryInfo");
104: #endif
105:   if (!sfunc) {
106:     *mess = "No library information in the file\n";
107:   } else {
108:     (*sfunc)(0,type,mess);
109:   }
110:   return(0);
111: }

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

119:      Collective on MPI_Comm

121:    Input Parameters:
122: +   comm - processors that are opening the library
123: -   libname - name of the library, can be relative or absolute

125:    Output Parameter:
126: .   handle - library handle 

128:    Level: developer

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

133:    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${BOPT}, or ${any environmental variable}
134:    occuring in directoryname and filename will be replaced with appropriate values.
135: @*/
136: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,int llen,PetscTruth *found)
137: {
138:   char       *par2,buff[10],*en,*gz;
140:   size_t     len1,len2,len;
141:   PetscTruth tflg,flg;


145:   /* 
146:      make copy of library name and replace $PETSC_ARCH and $BOPT and 
147:      so we can add to the end of it to look for something like .so.1.0 etc.
148:   */
149:   PetscStrlen(libname,&len);
150:   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);
151:   PetscMalloc(len*sizeof(char),&par2);
152:   PetscStrreplace(comm,libname,par2,len);

154:   /* 
155:      Remove any file: header
156:   */
157:   PetscStrncmp(par2,"file:",5,&tflg);
158:   if (tflg) {
159:     PetscStrcpy(par2,par2+5);
160:   }

162:   /* strip out .a from it if user put it in by mistake */
163:   PetscStrlen(par2,&len);
164:   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;

166:   /* remove .gz if it ends library name */
167:   PetscStrstr(par2,".gz",&gz);
168:   if (gz) {
169:     PetscStrlen(gz,&len);
170:     if (len == 3) {
171:       *gz = 0;
172:     }
173:   }

175:   /* see if library name does already not have suffix attached */
176:   PetscStrcpy(buff,".");
177:   PetscStrcat(buff,PETSC_SLSUFFIX);
178:   PetscStrstr(par2,buff,&en);
179:   if (en) {
180:     PetscStrlen(en,&len1);
181:     PetscStrlen(PETSC_SLSUFFIX,&len2);
182:     flg = (PetscTruth) (len1 != 1 + len2);
183:   } else {
184:     flg = PETSC_TRUE;
185:   }
186:   if (flg) {
187:     PetscStrcat(par2,".");
188:     PetscStrcat(par2,PETSC_SLSUFFIX);
189:   }

191:   /* put the .gz back on if it was there */
192:   if (gz) {
193:     PetscStrcat(par2,".gz");
194:   }

196:   PetscFileRetrieve(comm,par2,lname,llen,found);
197:   PetscFree(par2);
198:   return(0);
199: }


204: /*@C
205:    PetscDLLibraryOpen - Opens a dynamic link library

207:      Collective on MPI_Comm

209:    Input Parameters:
210: +   comm - processors that are opening the library
211: -   libname - name of the library, can be relative or absolute

213:    Output Parameter:
214: .   handle - library handle 

216:    Level: developer

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

221:    ${PETSC_ARCH} and ${BOPT} occuring in directoryname and filename 
222:    will be replaced with appropriate values.
223: @*/
224: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char libname[],void **handle)
225: {
227:   char       *par2;
228:   PetscTruth foundlibrary;
229:   PetscErrorCode (*func)(const char*);


233:   PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&par2);
234:   PetscDLLibraryRetrieve(comm,libname,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
235:   if (!foundlibrary) {
236:     SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",libname);
237:   }

239: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
240:   PetscTestFile(par2,'x',&foundlibrary);
241:   if (!foundlibrary) {
242:     SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",libname,par2);
243:   }
244: #endif

246:   /*
247:       Mode indicates symbols required by symbol loaded with dlsym() 
248:      are only loaded when required (not all together) also indicates
249:      symbols required can be contained in other libraries also opened
250:      with dlopen()
251:   */
252:   PetscLogInfo(0,"PetscDLLibraryOpen:Opening %s\n",libname);
253: #if defined(PETSC_HAVE_DLOPEN)
254: #if defined(PETSC_HAVE_RTLD_GLOBAL)
255:   *handle = dlopen(par2,RTLD_LAZY  |  RTLD_GLOBAL);
256: #else
257:   *handle = dlopen(par2,RTLD_LAZY);
258: #endif
259: #elif defined(PETSC_HAVE_LOADLIBRARY)
260:   *handle = LoadLibrary(par2);
261: #endif
262:   if (!*handle) {
263: #if defined(PETSC_HAVE_DLERROR)
264:     SETERRQ3(PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  %s\n  Error message from dlopen() %s\n",libname,par2,dlerror());
265: #elif defined(PETSC_HAVE_GETLASTERROR)
266:     {
267:       DWORD erc;
268:       char *buff;
269:       erc   = GetLastError();
270:       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
271:                     NULL,
272:                     erc,
273:                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
274:                     (LPSTR)&buff,
275:                     0,
276:                     NULL);
277:       PetscError(__LINE__,__FUNCT__,__FILE__,__SDIR__,PETSC_ERR_FILE_OPEN,1,
278:                         "Unable to open dynamic library:\n  %s\n  %s\n  Error message from LoadLibrary() %s\n",
279:                         libname,par2,buff);
280:       LocalFree(buff);
281:       return(ierr);
282:     }
283: #endif
284:   }
285:   /* run the function PetscFListAddDynamic() if it is in the library */
286: #if defined(PETSC_HAVE_DLSYM)
287:   func  = (PetscErrorCode (*)(const char *)) dlsym(*handle,"PetscDLLibraryRegister");
288: #elif defined(PETSC_HAVE_GETPROCADDRESS)
289:   func  = (PetscErrorCode (*)(const char *)) GetProcAddress((HMODULE)*handle,"PetscDLLibraryRegister");
290: #endif
291:   if (func) {
292:     (*func)(libname);
293:     PetscLogInfo(0,"PetscDLLibraryOpen:Loading registered routines from %s\n",libname);
294:   }
295:   if (PetscLogPrintInfo) {
296:     PetscErrorCode (*sfunc)(const char *,const char*,char **);
297:     char *mess;

299: #if defined(PETSC_HAVE_DLSYM)
300:     sfunc   = (PetscErrorCode (*)(const char *,const char*,char **)) dlsym(*handle,"PetscDLLibraryInfo");
301: #elif defined(PETSC_HAVE_GETPROCADDRESS)
302:     sfunc   = (PetscErrorCode (*)(const char *,const char*,char **)) GetProcAddress((HMODULE)*handle,"PetscDLLibraryInfo");
303: #endif
304:     if (sfunc) {
305:       (*sfunc)(libname,"Contents",&mess);
306:       if (mess) {
307:         PetscLogInfo(0,"Contents:\n %s",mess);
308:       }
309:       (*sfunc)(libname,"Authors",&mess);
310:       if (mess) {
311:         PetscLogInfo(0,"Authors:\n %s",mess);
312:       }
313:       (*sfunc)(libname,"Version",&mess);
314:       if (mess) {
315:         PetscLogInfo(0,"Version:\n %s\n",mess);
316:       }
317:     }
318:   }

320:   PetscFree(par2);
321:   return(0);
322: }

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

329:    Collective on MPI_Comm

331:    Input Parameter:
332: +  path     - optional complete library name
333: -  insymbol - name of symbol

335:    Output Parameter:
336: .  value 

338:    Level: developer

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

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

345: @*/
346: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibraryList *inlist,const char path[],const char insymbol[],void **value)
347: {
348:   char               *par1,*symbol;
350:   size_t             len;
351:   PetscDLLibraryList nlist,prev,list;

354:   if (inlist) list = *inlist; else list = PETSC_NULL;
355:   *value = 0;

357:   /* make copy of symbol so we can edit it in place */
358:   PetscStrlen(insymbol,&len);
359:   PetscMalloc((len+1)*sizeof(char),&symbol);
360:   PetscStrcpy(symbol,insymbol);

362:   /* 
363:       If symbol contains () then replace with a NULL, to support functionname() 
364:   */
365:   PetscStrchr(symbol,'(',&par1);
366:   if (par1) *par1 = 0;


369:   /*
370:        Function name does include library 
371:        -------------------------------------
372:   */
373:   if (path && path[0] != '\0') {
374:     void *handle;
375: 
376:     /*   
377:         Look if library is already opened and in path
378:     */
379:     nlist = list;
380:     prev  = 0;
381:     while (nlist) {
382:       PetscTruth match;

384:       PetscStrcmp(nlist->libname,path,&match);
385:       if (match) {
386:         handle = nlist->handle;
387:         goto done;
388:       }
389:       prev  = nlist;
390:       nlist = nlist->next;
391:     }
392:     PetscDLLibraryOpen(comm,path,&handle);

394:     PetscNew(struct _PetscDLLibraryList,&nlist);
395:     nlist->next   = 0;
396:     nlist->handle = handle;
397:     PetscStrcpy(nlist->libname,path);

399:     if (prev) {
400:       prev->next = nlist;
401:     } else {
402:       if (inlist) *inlist = nlist;
403:       else {PetscDLLibraryClose(nlist);}
404:     }
405:     PetscLogInfo(0,"PetscDLLibraryAppend:Appending %s to dynamic library search path\n",path);

407:     done:;
408: #if defined(PETSC_HAVE_DLSYM)
409:     *value   = dlsym(handle,symbol);
410: #elif defined(PETSC_HAVE_GETPROCADDRESS)
411:     *value   = GetProcAddress((HMODULE)handle,symbol);
412: #endif
413:     if (!*value) {
414:       SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
415:     }
416:     PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from dynamic library %s\n",insymbol,path);

418:   /*
419:        Function name does not include library so search path
420:        -----------------------------------------------------
421:   */
422:   } else {
423:     while (list) {
424: #if defined(PETSC_HAVE_DLSYM)
425:       *value =  dlsym(list->handle,symbol);
426: #elif defined(PETSC_HAVE_GETPROCADDRESS)
427:       *value   = GetProcAddress((HMODULE)list->handle,symbol);
428: #endif
429:       if (*value) {
430:         PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from dynamic library %s\n",symbol,list->libname);
431:         break;
432:       }
433:       list = list->next;
434:     }
435:     if (!*value) {
436: #if defined(PETSC_HAVE_DLSYM)
437:       *value =  dlsym(0,symbol);
438: #elif defined(PETSC_HAVE_GETPROCADDRESS)
439:       *value = GetProcAddress(GetCurrentProcess(),symbol);
440: #endif
441:       if (*value) {
442:         PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from object code\n",symbol);
443:       }
444:     }
445:   }

447:   PetscFree(symbol);
448:   return(0);
449: }

453: /*@C
454:      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
455:                 of the search path.

457:      Collective on MPI_Comm

459:      Input Parameters:
460: +     comm - MPI communicator
461: -     libname - name of the library

463:      Output Parameter:
464: .     outlist - list of libraries

466:      Level: developer

468:      Notes: if library is already in path will not add it.
469: @*/
470: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibraryList *outlist,const char libname[])
471: {
472:   PetscDLLibraryList list,prev;
473:   void*              handle;
475:   size_t             len;
476:   PetscTruth         match,dir;
477:   char               program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
478:   PetscToken         *token;


482:   /* is libname a directory? */
483:   PetscTestDirectory(libname,'r',&dir);
484:   if (dir) {
485:     PetscLogInfo(0,"Checking directory %s for dynamic libraries\n",libname);
486:     PetscStrcpy(program,libname);
487:     PetscStrlen(program,&len);
488:     if (program[len-1] == '/') {
489:       PetscStrcat(program,"*.");
490:     } else {
491:       PetscStrcat(program,"/*.");
492:     }
493:     PetscStrcat(program,PETSC_SLSUFFIX);

495:     PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
496:     if (!dir) return(0);
497:     found = buf;
498:   } else {
499:     found = (char*)libname;
500:   }
501:   PetscStrcpy(suffix,".");
502:   PetscStrcat(suffix,PETSC_SLSUFFIX);

504:   PetscTokenCreate(found,'\n',&token);
505:   PetscTokenFind(token,&libname1);
506:   PetscStrstr(libname1,suffix,&s);
507:   if (s) s[0] = 0;
508:   while (libname1) {

510:     /* see if library was already open then we are done */
511:     list  = prev = *outlist;
512:     match = PETSC_FALSE;
513:     while (list) {

515:       PetscStrcmp(list->libname,libname1,&match);
516:       if (match) break;
517:       prev = list;
518:       list = list->next;
519:     }
520:     if (!match) {

522:       PetscDLLibraryOpen(comm,libname1,&handle);

524:       PetscNew(struct _PetscDLLibraryList,&list);
525:       list->next   = 0;
526:       list->handle = handle;
527:       PetscStrcpy(list->libname,libname1);

529:       if (!*outlist) {
530:         *outlist   = list;
531:       } else {
532:         prev->next = list;
533:       }
534:       PetscLogInfo(0,"PetscDLLibraryAppend:Appending %s to dynamic library search path\n",libname1);
535:     }
536:     PetscTokenFind(token,&libname1);
537:     if (libname1) {
538:       PetscStrstr(libname1,suffix,&s);
539:       if (s) s[0] = 0;
540:     }
541:   }
542:   PetscTokenDestroy(token);
543:   return(0);
544: }

548: /*@C
549:      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
550:                  the search path.

552:      Collective on MPI_Comm

554:      Input Parameters:
555: +     comm - MPI communicator
556: -     libname - name of the library

558:      Output Parameter:
559: .     outlist - list of libraries

561:      Level: developer

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

565: @*/
566: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibraryList *outlist,const char libname[])
567: {
568:   PetscDLLibraryList list,prev;
569:   void*              handle;
571:   size_t             len;
572:   PetscTruth         match,dir;
573:   char               program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
574:   PetscToken         *token;

577: 
578:   /* is libname a directory? */
579:   PetscTestDirectory(libname,'r',&dir);
580:   if (dir) {
581:     PetscLogInfo(0,"Checking directory %s for dynamic libraries\n",libname);
582:     PetscStrcpy(program,libname);
583:     PetscStrlen(program,&len);
584:     if (program[len-1] == '/') {
585:       PetscStrcat(program,"*.");
586:     } else {
587:       PetscStrcat(program,"/*.");
588:     }
589:     PetscStrcat(program,PETSC_SLSUFFIX);

591:     PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
592:     if (!dir) return(0);
593:     found = buf;
594:   } else {
595:     found = (char*)libname;
596:   }

598:   PetscStrcpy(suffix,".");
599:   PetscStrcat(suffix,PETSC_SLSUFFIX);

601:   PetscTokenCreate(found,'\n',&token);
602:   PetscTokenFind(token,&libname1);
603:   PetscStrstr(libname1,suffix,&s);
604:   if (s) s[0] = 0;
605:   while (libname1) {
606:     /* see if library was already open and move it to the front */
607:     list  = *outlist;
608:     prev  = 0;
609:     match = PETSC_FALSE;
610:     while (list) {

612:       PetscStrcmp(list->libname,libname1,&match);
613:       if (match) {
614:         if (prev) prev->next = list->next;
615:         list->next = *outlist;
616:         *outlist   = list;
617:         break;
618:       }
619:       prev = list;
620:       list = list->next;
621:     }
622:     if (!match) {
623:       /* open the library and add to front of list */
624:       PetscDLLibraryOpen(comm,libname1,&handle);
625: 
626:       PetscLogInfo(0,"PetscDLLibraryPrepend:Prepending %s to dynamic library search path\n",libname1);

628:       PetscNew(struct _PetscDLLibraryList,&list);
629:       list->handle = handle;
630:       list->next   = *outlist;
631:       PetscStrcpy(list->libname,libname1);
632:       *outlist     = list;
633:     }
634:     PetscTokenFind(token,&libname1);
635:     if (libname1) {
636:       PetscStrstr(libname1,suffix,&s);
637:       if (s) s[0] = 0;
638:     }
639:   }
640:   PetscTokenDestroy(token);
641:   return(0);
642: }

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

649:     Collective on PetscDLLibrary

651:     Input Parameter:
652: .     next - library list

654:      Level: developer

656: @*/
657: PetscErrorCode PetscDLLibraryClose(PetscDLLibraryList next)
658: {
659:   PetscDLLibraryList prev;


664:   while (next) {
665:     prev = next;
666:     next = next->next;
667:     /* free the space in the prev data-structure */
668:     PetscFree(prev);
669:   }
670:   return(0);
671: }

675: /*@C
676:      PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
677:                 of the search path.

679:      Collective on MPI_Comm

681:      Input Parameters:
682: +     comm - MPI communicator
683: -     libname - name of directory to check

685:      Output Parameter:
686: .     outlist - list of libraries

688:      Level: developer

690:      Notes: if library is already in path will not add it.
691: @*/
692: PetscErrorCode PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibraryList *outlist,const char dirname[])
693: {
695:   size_t             l;
696:   PetscTruth         dir;
697:   char               program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
698:   char               *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
699:   FILE               *fp;
700:   PetscToken         *token1,*token2;


704:   /* is dirname a directory? */
705:   PetscTestDirectory(dirname,'r',&dir);
706:   if (!dir) return(0);

708:   PetscLogInfo(0,"Checking directory %s for CCA components\n",dirname);
709:   PetscStrcpy(program,dirname);
710:   PetscStrcat(program,"/*.cca");

712:   PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
713:   if (!dir) return(0);

715:   PetscStrcpy(suffix,".");
716:   PetscStrcat(suffix,PETSC_SLSUFFIX);
717:   PetscTokenCreate(buf,'\n',&token1);
718:   PetscTokenFind(token1,&libname1);
719:   while (libname1) {
720:     fp    = fopen(libname1,"r"); if (!fp) continue;
721:     while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
722:       if (found[0] == '!') continue;
723:       PetscStrstr(found,suffix,&f2);
724:       if (f2) { /* found library name */
725:         if (found[0] == '/') {
726:           lib = found;
727:         } else {
728:           PetscStrcpy(libname,dirname);
729:           PetscStrlen(libname,&l);
730:           if (libname[l-1] != '/') {PetscStrcat(libname,"/");}
731:           PetscStrcat(libname,found);
732:           lib  = libname;
733:         }
734:         PetscDLLibraryAppend(comm,outlist,lib);
735:       } else {
736:         PetscLogInfo(0,"CCA Component function and name: %s from %s\n",found,libname1);
737:         PetscTokenCreate(found,' ',&token2);
738:         PetscTokenFind(token2,&func);
739:         PetscTokenFind(token2,&funcname);
740:         PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);
741:         PetscTokenDestroy(token2);
742:       }
743:     }
744:     fclose(fp);
745:     PetscTokenFind(token1,&libname1);
746:   }
747:   PetscTokenDestroy(token1);
748:   return(0);
749: }


752: #endif