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