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