xref: /petsc/src/sys/dll/dl.c (revision 5673baf80db13bf90ebf3b7d404b13be20b2a2b2)
1 #define PETSC_DLL
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 */
6 
7 #include "petsc.h"
8 #include "petscsys.h"
9 #include "petscfix.h"
10 
11 #if defined(PETSC_HAVE_PWD_H)
12 #include <pwd.h>
13 #endif
14 #include <ctype.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #if defined(PETSC_HAVE_UNISTD_H)
18 #include <unistd.h>
19 #endif
20 #if defined(PETSC_HAVE_STDLIB_H)
21 #include <stdlib.h>
22 #endif
23 #if defined(PETSC_HAVE_SYS_UTSNAME_H)
24 #include <sys/utsname.h>
25 #endif
26 #include <fcntl.h>
27 #include <time.h>
28 #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
29 #include <sys/systeminfo.h>
30 #endif
31 
32 /*
33    Contains the list of registered CCA components
34 */
35 PetscFList CCAList = 0;
36 
37 
38 /* ------------------------------------------------------------------------------*/
39 /*
40       Code to maintain a list of opened dynamic libraries and load symbols
41 */
42 struct _n_PetscDLLibrary {
43   PetscDLLibrary next;
44   PetscDLHandle  handle;
45   char           libname[PETSC_MAX_PATH_LEN];
46 };
47 
48 #undef __FUNCT__
49 #define __FUNCT__ "PetscDLLibraryPrintPath"
50 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryPrintPath(PetscDLLibrary libs)
51 {
52   PetscFunctionBegin;
53   while (libs) {
54     PetscErrorPrintf("  %s\n",libs->libname);
55     libs = libs->next;
56   }
57   PetscFunctionReturn(0);
58 }
59 
60 #undef __FUNCT__
61 #define __FUNCT__ "PetscDLLibraryRetrieve"
62 /*@C
63    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
64      (if it is remote), indicates if it exits and its local name.
65 
66      Collective on MPI_Comm
67 
68    Input Parameters:
69 +   comm - processors that are opening the library
70 -   libname - name of the library, can be relative or absolute
71 
72    Output Parameter:
73 .   handle - library handle
74 
75    Level: developer
76 
77    Notes:
78    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
79 
80    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
81    occuring in directoryname and filename will be replaced with appropriate values.
82 @*/
83 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscTruth *found)
84 {
85   char           *par2,buff[10],*en,*gz;
86   PetscErrorCode ierr;
87   size_t         len1,len2,len;
88   PetscTruth     tflg,flg;
89 
90   PetscFunctionBegin;
91   /*
92      make copy of library name and replace $PETSC_ARCH etc
93      so we can add to the end of it to look for something like .so.1.0 etc.
94   */
95   ierr = PetscStrlen(libname,&len);CHKERRQ(ierr);
96   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
97   ierr = PetscMalloc(len*sizeof(char),&par2);CHKERRQ(ierr);
98   ierr = PetscStrreplace(comm,libname,par2,len);CHKERRQ(ierr);
99 
100   /*
101      Remove any file: header
102   */
103   ierr = PetscStrncmp(par2,"file:",5,&tflg);CHKERRQ(ierr);
104   if (tflg) {
105     ierr = PetscStrcpy(par2,par2+5);CHKERRQ(ierr);
106   }
107 
108   /* strip out .a from it if user put it in by mistake */
109   ierr    = PetscStrlen(par2,&len);CHKERRQ(ierr);
110   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
111 
112   /* remove .gz if it ends library name */
113   ierr = PetscStrstr(par2,".gz",&gz);CHKERRQ(ierr);
114   if (gz) {
115     ierr = PetscStrlen(gz,&len);CHKERRQ(ierr);
116     if (len == 3) {
117       *gz = 0;
118     }
119   }
120 
121   /* see if library name does already not have suffix attached */
122   ierr = PetscStrcpy(buff,".");CHKERRQ(ierr);
123   ierr = PetscStrcat(buff,PETSC_SLSUFFIX);CHKERRQ(ierr);
124   ierr = PetscStrstr(par2,buff,&en);CHKERRQ(ierr);
125   if (en) {
126     ierr = PetscStrlen(en,&len1);CHKERRQ(ierr);
127     ierr = PetscStrlen(PETSC_SLSUFFIX,&len2);CHKERRQ(ierr);
128     flg = (PetscTruth) (len1 != 1 + len2);
129   } else {
130     flg = PETSC_TRUE;
131   }
132   if (flg) {
133     ierr = PetscStrcat(par2,".");CHKERRQ(ierr);
134     ierr = PetscStrcat(par2,PETSC_SLSUFFIX);CHKERRQ(ierr);
135   }
136 
137   /* put the .gz back on if it was there */
138   if (gz) {
139     ierr = PetscStrcat(par2,".gz");CHKERRQ(ierr);
140   }
141 
142   ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr);
143   ierr = PetscFree(par2);CHKERRQ(ierr);
144   PetscFunctionReturn(0);
145 }
146 
147 
148 #undef __FUNCT__
149 #define __FUNCT__ "PetscDLLibraryOpen"
150 /*@C
151    PetscDLLibraryOpen - Opens a PETSc dynamic link library
152 
153      Collective on MPI_Comm
154 
155    Input Parameters:
156 +   comm - processors that are opening the library
157 -   libname - name of the library, can be relative or absolute
158 
159    Output Parameter:
160 .   handle - library handle
161 
162    Level: developer
163 
164    Notes:
165    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
166 
167    ${PETSC_ARCH} occuring in directoryname and filename
168    will be replaced with the appropriate value.
169 @*/
170 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryOpen(MPI_Comm comm,const char libname[],PetscDLLibrary *entry)
171 {
172   PetscErrorCode ierr;
173   char           *par2,registername[128],*ptr,*ptrp;
174   PetscTruth     foundlibrary;
175   PetscDLHandle  handle;
176   PetscErrorCode (*func)(const char*) = NULL;
177   size_t         len;
178 
179   PetscFunctionBegin;
180   PetscValidCharPointer(libname,2);
181   PetscValidPointer(entry,3);
182 
183   *entry = PETSC_NULL;
184   ierr = PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&par2);CHKERRQ(ierr);
185   ierr = PetscDLLibraryRetrieve(comm,libname,par2,PETSC_MAX_PATH_LEN,&foundlibrary);CHKERRQ(ierr);
186   if (!foundlibrary) SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",libname);
187 
188   /* Eventually config/configure.py should determine if the system needs an executable dynamic library */
189 #define PETSC_USE_NONEXECUTABLE_SO
190 #if !defined(PETSC_USE_NONEXECUTABLE_SO)
191   ierr  = PetscTestFile(par2,'x',&foundlibrary);CHKERRQ(ierr);
192   if (!foundlibrary) SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",libname,par2);
193 #endif
194 
195   /* look for libXXXXX.YYY and extract out the XXXXXX */
196   ierr = PetscStrrstr(libname,"lib",&ptr);CHKERRQ(ierr);
197   if (!ptr) SETERRQ1(PETSC_ERR_ARG_WRONG,"Dynamic library name must have lib prefix:%s",libname);
198   ierr = PetscStrchr(ptr+3,'.',&ptrp);CHKERRQ(ierr);
199   if (ptrp) {
200     len = ptrp - ptr - 3;
201   } else {
202     ierr = PetscStrlen(ptr+3,&len);CHKERRQ(ierr);
203   }
204   /* open the dynamic library */
205   ierr = PetscInfo1(0,"Opening %s\n",libname);CHKERRQ(ierr);
206   ierr = PetscDLOpen(par2,PETSC_DL_GLOBAL,&handle);CHKERRQ(ierr);
207   ierr = PetscFree(par2);CHKERRQ(ierr);
208   /* build name of symbol to look for based on libname */
209   ierr = PetscStrcpy(registername,"PetscDLLibraryRegister_");CHKERRQ(ierr);
210   ierr = PetscStrncat(registername,ptr+3,len);CHKERRQ(ierr);
211   ierr = PetscDLSym(handle,registername,(void**)&func);CHKERRQ(ierr);
212   if (!func) {
213     SETERRQ2(PETSC_ERR_FILE_UNEXPECTED,"Able to locate dynamic library %s, but cannot load symbol %s\n",libname,registername);
214   }
215   ierr = PetscInfo1(0,"Loading registered routines from %s\n",libname);CHKERRQ(ierr);
216   ierr = (*func)(libname);CHKERRQ(ierr);
217 
218   ierr = PetscNew(struct _n_PetscDLLibrary,entry);CHKERRQ(ierr);
219   ierr = PetscStrcpy((*entry)->libname,libname);CHKERRQ(ierr);
220   (*entry)->handle = handle;
221   (*entry)->next   = 0;
222 
223   PetscFunctionReturn(0);
224 }
225 
226 #undef __FUNCT__
227 #define __FUNCT__ "PetscDLLibrarySym"
228 /*@C
229    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
230 
231    Collective on MPI_Comm
232 
233    Input Parameter:
234 +  comm - communicator that will open the library
235 .  inlist - list of already open libraries that may contain symbol (checks here before path)
236 .  path     - optional complete library name
237 -  insymbol - name of symbol
238 
239    Output Parameter:
240 .  value
241 
242    Level: developer
243 
244    Notes: Symbol can be of the form
245         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
246 
247         Will attempt to (retrieve and) open the library if it is not yet been opened.
248 
249 @*/
250 PetscErrorCode PETSC_DLLEXPORT PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *inlist,const char path[],const char insymbol[],void **value)
251 {
252   char           *par1,*symbol;
253   PetscErrorCode ierr;
254   size_t         len;
255   PetscDLLibrary nlist,prev,list;
256 
257   PetscFunctionBegin;
258   PetscValidPointer(inlist,2);
259   if (path) PetscValidCharPointer(path,3);
260   PetscValidCharPointer(insymbol,4);
261   PetscValidPointer(value,5);
262 
263   list   = *inlist;
264   *value = 0;
265 
266   /* make copy of symbol so we can edit it in place */
267   ierr = PetscStrlen(insymbol,&len);CHKERRQ(ierr);
268   ierr = PetscMalloc((len+1)*sizeof(char),&symbol);CHKERRQ(ierr);
269   ierr = PetscStrcpy(symbol,insymbol);CHKERRQ(ierr);
270 
271   /*
272       If symbol contains () then replace with a NULL, to support functionname()
273   */
274   ierr = PetscStrchr(symbol,'(',&par1);CHKERRQ(ierr);
275   if (par1) *par1 = 0;
276 
277 
278   /*
279        Function name does include library
280        -------------------------------------
281   */
282   if (path && path[0] != '\0') {
283     /* Look if library is already opened and in path */
284     nlist = list;
285     prev  = 0;
286     while (nlist) {
287       PetscTruth match;
288       ierr = PetscStrcmp(nlist->libname,path,&match);CHKERRQ(ierr);
289       if (match) goto done;
290       prev  = nlist;
291       nlist = nlist->next;
292     }
293 
294     ierr = PetscDLLibraryOpen(comm,path,&nlist);CHKERRQ(ierr);
295     ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",path);CHKERRQ(ierr);
296     if (prev) { prev->next = nlist; }
297     else      { *inlist    = nlist; }
298 
299   done:;
300     ierr = PetscDLSym(nlist->handle,symbol,value);CHKERRQ(ierr);
301     if (!*value) {
302       SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
303     }
304     ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);CHKERRQ(ierr);
305 
306   /*
307        Function name does not include library so search path
308        -----------------------------------------------------
309   */
310   } else {
311     while (list) {
312       ierr = PetscDLSym(list->handle,symbol,value);CHKERRQ(ierr);
313       if (*value) {
314         ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",symbol,list->libname);CHKERRQ(ierr);
315         break;
316       }
317       list = list->next;
318     }
319     if (!*value) {
320       ierr = PetscDLSym(PETSC_NULL,symbol,value);CHKERRQ(ierr);
321       if (*value) {
322         ierr = PetscInfo1(0,"Loading function %s from object code\n",symbol);CHKERRQ(ierr);
323       }
324     }
325   }
326 
327   ierr = PetscFree(symbol);CHKERRQ(ierr);
328   PetscFunctionReturn(0);
329 }
330 
331 #undef __FUNCT__
332 #define __FUNCT__ "PetscDLLibraryAppend"
333 /*@C
334      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
335                 of the search path.
336 
337      Collective on MPI_Comm
338 
339      Input Parameters:
340 +     comm - MPI communicator
341 -     libname - name of the library
342 
343      Output Parameter:
344 .     outlist - list of libraries
345 
346      Level: developer
347 
348      Notes: if library is already in path will not add it.
349 @*/
350 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
351 {
352   PetscDLLibrary list,prev;
353   PetscErrorCode ierr;
354   size_t         len;
355   PetscTruth     match,dir;
356   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
357   PetscToken     token;
358 
359   PetscFunctionBegin;
360 
361   /* is libname a directory? */
362   ierr = PetscTestDirectory(libname,'r',&dir);CHKERRQ(ierr);
363   if (dir) {
364     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);CHKERRQ(ierr);
365     ierr  = PetscStrcpy(program,libname);CHKERRQ(ierr);
366     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
367     if (program[len-1] == '/') {
368       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
369     } else {
370       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
371     }
372     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
373 
374     ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
375     if (!dir) PetscFunctionReturn(0);
376     found = buf;
377   } else {
378     found = (char*)libname;
379   }
380   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
381   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
382 
383   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
384   ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
385   ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
386   if (s) s[0] = 0;
387   while (libname1) {
388     /* see if library was already open then we are done */
389     list  = prev = *outlist;
390     match = PETSC_FALSE;
391     while (list) {
392       ierr = PetscStrcmp(list->libname,libname1,&match);CHKERRQ(ierr);
393       if (match) break;
394       prev = list;
395       list = list->next;
396     }
397     if (!match) {
398       /* open the library and add to end of list */
399        ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",libname1);CHKERRQ(ierr);
400       ierr = PetscDLLibraryOpen(comm,libname1,&list);CHKERRQ(ierr);
401       if (!*outlist) {
402 	*outlist   = list;
403       } else {
404 	prev->next = list;
405       }
406     }
407     ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
408     if (libname1) {
409       ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
410       if (s) s[0] = 0;
411     }
412   }
413   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
414   PetscFunctionReturn(0);
415 }
416 
417 #undef __FUNCT__
418 #define __FUNCT__ "PetscDLLibraryPrepend"
419 /*@C
420      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
421                  the search path.
422 
423      Collective on MPI_Comm
424 
425      Input Parameters:
426 +     comm - MPI communicator
427 -     libname - name of the library
428 
429      Output Parameter:
430 .     outlist - list of libraries
431 
432      Level: developer
433 
434      Notes: If library is already in path will remove old reference.
435 
436 @*/
437 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
438 {
439   PetscDLLibrary list,prev;
440   PetscErrorCode ierr;
441   size_t         len;
442   PetscTruth     match,dir;
443   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
444   PetscToken     token;
445 
446   PetscFunctionBegin;
447 
448   /* is libname a directory? */
449   ierr = PetscTestDirectory(libname,'r',&dir);CHKERRQ(ierr);
450   if (dir) {
451     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);CHKERRQ(ierr);
452     ierr  = PetscStrcpy(program,libname);CHKERRQ(ierr);
453     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
454     if (program[len-1] == '/') {
455       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
456     } else {
457       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
458     }
459     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
460 
461     ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
462     if (!dir) PetscFunctionReturn(0);
463     found = buf;
464   } else {
465     found = (char*)libname;
466   }
467 
468   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
469   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
470 
471   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
472   ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
473   ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
474   if (s) s[0] = 0;
475   while (libname1) {
476     /* see if library was already open and move it to the front */
477     list  = *outlist;
478     prev  = 0;
479     match = PETSC_FALSE;
480     while (list) {
481       ierr = PetscStrcmp(list->libname,libname1,&match);CHKERRQ(ierr);
482       if (match) {
483 	if (prev) prev->next = list->next;
484 	list->next = *outlist;
485 	*outlist   = list;
486 	break;
487       }
488       prev = list;
489       list = list->next;
490     }
491     if (!match) {
492       ierr = PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname1);CHKERRQ(ierr);
493       /* open the library and add to front of list */
494       ierr = PetscDLLibraryOpen(comm,libname1,&list);CHKERRQ(ierr);
495       list->next = *outlist;
496       *outlist   = list;
497     }
498     ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
499     if (libname1) {
500       ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
501       if (s) s[0] = 0;
502     }
503   }
504   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
505   PetscFunctionReturn(0);
506 }
507 
508 #undef __FUNCT__
509 #define __FUNCT__ "PetscDLLibraryClose"
510 /*@C
511      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
512 
513     Collective on PetscDLLibrary
514 
515     Input Parameter:
516 .     next - library list
517 
518      Level: developer
519 
520 @*/
521 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryClose(PetscDLLibrary next)
522 {
523   PetscDLLibrary prev;
524   PetscErrorCode ierr;
525 
526   PetscFunctionBegin;
527   while (next) {
528     prev = next;
529     next = next->next;
530     /* close the dynamic library */
531     ierr = PetscDLClose(&prev->handle);CHKERRQ(ierr);
532     /* free the space in the prev data-structure */
533     ierr = PetscFree(prev);CHKERRQ(ierr);
534   }
535   PetscFunctionReturn(0);
536 }
537 
538 #undef __FUNCT__
539 #define __FUNCT__ "PetscDLLibraryCCAAppend"
540 /*@C
541      PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
542                 of the search path.
543 
544      Collective on MPI_Comm
545 
546      Input Parameters:
547 +     comm - MPI communicator
548 -     libname - name of directory to check
549 
550      Output Parameter:
551 .     outlist - list of libraries
552 
553      Level: developer
554 
555      Notes: if library is already in path will not add it.
556 @*/
557 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char dirname[])
558 {
559   PetscErrorCode ierr;
560   size_t         l;
561   PetscTruth     dir;
562   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
563   char           *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
564   FILE           *fp;
565   PetscToken     token1, token2;
566   int            err;
567 
568   PetscFunctionBegin;
569   /* is dirname a directory? */
570   ierr = PetscTestDirectory(dirname,'r',&dir);CHKERRQ(ierr);
571   if (!dir) PetscFunctionReturn(0);
572 
573   ierr = PetscInfo1(0,"Checking directory %s for CCA components\n",dirname);CHKERRQ(ierr);
574   ierr  = PetscStrcpy(program,dirname);CHKERRQ(ierr);
575   ierr  = PetscStrcat(program,"/*.cca");CHKERRQ(ierr);
576 
577   ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
578   if (!dir) PetscFunctionReturn(0);
579 
580   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
581   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
582   ierr = PetscTokenCreate(buf,'\n',&token1);CHKERRQ(ierr);
583   ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
584   while (libname1) {
585     fp    = fopen(libname1,"r"); if (!fp) continue;
586     while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
587       if (found[0] == '!') continue;
588       ierr = PetscStrstr(found,suffix,&f2);CHKERRQ(ierr);
589       if (f2) { /* found library name */
590         if (found[0] == '/') {
591           lib = found;
592         } else {
593           ierr = PetscStrcpy(libname,dirname);CHKERRQ(ierr);
594           ierr = PetscStrlen(libname,&l);CHKERRQ(ierr);
595           if (libname[l-1] != '/') {ierr = PetscStrcat(libname,"/");CHKERRQ(ierr);}
596           ierr = PetscStrcat(libname,found);CHKERRQ(ierr);
597           lib  = libname;
598         }
599         ierr = PetscDLLibraryAppend(comm,outlist,lib);CHKERRQ(ierr);
600       } else {
601         ierr = PetscInfo2(0,"CCA Component function and name: %s from %s\n",found,libname1);CHKERRQ(ierr);
602         ierr = PetscTokenCreate(found,' ',&token2);CHKERRQ(ierr);
603         ierr = PetscTokenFind(token2,&func);CHKERRQ(ierr);
604         ierr = PetscTokenFind(token2,&funcname);CHKERRQ(ierr);
605         ierr = PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);CHKERRQ(ierr);
606         ierr = PetscTokenDestroy(token2);CHKERRQ(ierr);
607       }
608     }
609     err = fclose(fp);
610     if (err) SETERRQ(PETSC_ERR_SYS,"fclose() failed on file");
611     ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
612   }
613   ierr = PetscTokenDestroy(token1);CHKERRQ(ierr);
614   PetscFunctionReturn(0);
615 }
616