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