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