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