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