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