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