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