xref: /petsc/src/sys/dll/dl.c (revision ce0a2cd1da0658c2b28aad1be2e2c8e41567bece)
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 etc
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) SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s\n",libname);
202 
203   /* Eventually config/configure.py should determine if the system needs an executable dynamic library */
204 #define PETSC_USE_NONEXECUTABLE_SO
205 #if !defined(PETSC_USE_NONEXECUTABLE_SO)
206   ierr  = PetscTestFile(par2,'x',&foundlibrary);CHKERRQ(ierr);
207   if (!foundlibrary) SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s\n",libname,par2);
208 #endif
209 
210   /*
211       Mode indicates symbols required by symbol loaded with dlsym()
212      are only loaded when required (not all together) also indicates
213      symbols required can be contained in other libraries also opened
214      with dlopen()
215   */
216   ierr = PetscInfo1(0,"Opening %s\n",libname);CHKERRQ(ierr);
217 #if defined(PETSC_HAVE_LOADLIBRARY)
218   *handle = LoadLibrary(par2);
219 #elif defined(PETSC_HAVE_RTLD_GLOBAL)
220   *handle = dlopen(par2,RTLD_LAZY | RTLD_GLOBAL);
221 #else
222   *handle = dlopen(par2,RTLD_LAZY);
223 #endif
224 
225   if (!*handle) {
226 #if defined(PETSC_HAVE_DLERROR)
227     SETERRQ3(PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  %s\n  Error message from dlopen() %s\n",libname,par2,dlerror());
228 #elif defined(PETSC_HAVE_GETLASTERROR)
229     {
230       DWORD erc;
231       char  *buff;
232       erc   = GetLastError();
233       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
234                     NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
235       ierr = PetscError(__LINE__,__FUNCT__,__FILE__,__SDIR__,PETSC_ERR_FILE_OPEN,1,
236                         "Unable to open dynamic library:\n  %s\n  %s\n  Error message from LoadLibrary() %s\n",libname,par2,buff);
237       LocalFree(buff);
238       return(ierr);
239     }
240 #endif
241   }
242 
243   /* build name of symbol to look for based on libname */
244   ierr = PetscStrcpy(registername,"PetscDLLibraryRegister_");CHKERRQ(ierr);
245   /* look for libXXXXX.YYY and extract out the XXXXXX */
246   ierr = PetscStrrstr(libname,"lib",&ptr);CHKERRQ(ierr);
247   if (!ptr) SETERRQ1(PETSC_ERR_ARG_WRONG,"Dynamic library name must have lib prefix:%s",libname);
248   ierr = PetscStrchr(ptr+3,'.',&ptrp);CHKERRQ(ierr);
249   if (ptrp) {
250     len = ptrp - ptr - 3;
251   } else {
252     ierr = PetscStrlen(ptr+3,&len);CHKERRQ(ierr);
253   }
254   ierr = PetscStrncat(registername,ptr+3,len);CHKERRQ(ierr);
255 
256 #if defined(PETSC_HAVE_GETPROCADDRESS)
257   func = (PetscErrorCode (*)(const char *)) GetProcAddress((HMODULE)*handle,registername);
258 #else
259   func = (PetscErrorCode (*)(const char *)) dlsym(*handle,registername);
260 #endif
261   if (func) {
262     ierr = (*func)(libname);CHKERRQ(ierr);
263     ierr = PetscInfo1(0,"Loading registered routines from %s\n",libname);CHKERRQ(ierr);
264   } else {
265     SETERRQ2(PETSC_ERR_FILE_UNEXPECTED,"Able to locate dynamic library %s, but cannot load symbol  %s\n",libname,registername);
266   }
267   ierr = PetscFree(par2);CHKERRQ(ierr);
268   PetscFunctionReturn(0);
269 }
270 
271 #undef __FUNCT__
272 #define __FUNCT__ "PetscDLLibrarySym"
273 /*@C
274    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
275 
276    Collective on MPI_Comm
277 
278    Input Parameter:
279 +  comm - communicator that will open the library
280 .  inlist - list of already open libraries that may contain symbol (checks here before path)
281 .  path     - optional complete library name
282 -  insymbol - name of symbol
283 
284    Output Parameter:
285 .  value
286 
287    Level: developer
288 
289    Notes: Symbol can be of the form
290         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
291 
292         Will attempt to (retrieve and) open the library if it is not yet been opened.
293 
294 @*/
295 PetscErrorCode PETSC_DLLEXPORT PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *inlist,const char path[],const char insymbol[],void **value)
296 {
297   char           *par1,*symbol;
298   PetscErrorCode ierr;
299   size_t         len;
300   PetscDLLibrary nlist,prev,list;
301 
302   PetscFunctionBegin;
303   if (inlist) list = *inlist; else list = PETSC_NULL;
304   *value = 0;
305 
306   /* make copy of symbol so we can edit it in place */
307   ierr = PetscStrlen(insymbol,&len);CHKERRQ(ierr);
308   ierr = PetscMalloc((len+1)*sizeof(char),&symbol);CHKERRQ(ierr);
309   ierr = PetscStrcpy(symbol,insymbol);CHKERRQ(ierr);
310 
311   /*
312       If symbol contains () then replace with a NULL, to support functionname()
313   */
314   ierr = PetscStrchr(symbol,'(',&par1);CHKERRQ(ierr);
315   if (par1) *par1 = 0;
316 
317 
318   /*
319        Function name does include library
320        -------------------------------------
321   */
322   if (path && path[0] != '\0') {
323     void *handle;
324 
325     /*
326         Look if library is already opened and in path
327     */
328     nlist = list;
329     prev  = 0;
330     while (nlist) {
331       PetscTruth match;
332 
333       ierr = PetscStrcmp(nlist->libname,path,&match);CHKERRQ(ierr);
334       if (match) {
335         handle = nlist->handle;
336         goto done;
337       }
338       prev  = nlist;
339       nlist = nlist->next;
340     }
341     ierr = PetscDLLibraryOpen(comm,path,&handle);CHKERRQ(ierr);
342 
343     ierr          = PetscNew(struct _n_PetscDLLibrary,&nlist);CHKERRQ(ierr);
344     nlist->next   = 0;
345     nlist->handle = handle;
346     ierr = PetscStrcpy(nlist->libname,path);CHKERRQ(ierr);
347 
348     if (prev) {
349       prev->next = nlist;
350     } else {
351       if (inlist) *inlist = nlist;
352       else {ierr = PetscDLLibraryClose(nlist);CHKERRQ(ierr);}
353     }
354     ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",path);CHKERRQ(ierr);
355 
356     done:;
357 #if defined(PETSC_HAVE_GETPROCADDRESS)
358     *value   = GetProcAddress((HMODULE)handle,symbol);
359 #else
360     *value   = dlsym(handle,symbol);
361 #endif
362     if (!*value) {
363       SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
364     }
365     ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);CHKERRQ(ierr);
366 
367   /*
368        Function name does not include library so search path
369        -----------------------------------------------------
370   */
371   } else {
372     while (list) {
373 #if defined(PETSC_HAVE_GETPROCADDRESS)
374       *value = GetProcAddress((HMODULE)list->handle,symbol);
375 #else
376       *value =  dlsym(list->handle,symbol);
377 #endif
378       if (*value) {
379         ierr = PetscInfo2(0,"Loading function %s from dynamic library %s\n",symbol,list->libname);CHKERRQ(ierr);
380         break;
381       }
382       list = list->next;
383     }
384     if (!*value) {
385 #if defined(PETSC_HAVE_GETPROCADDRESS)
386       *value = GetProcAddress(GetCurrentProcess(),symbol);
387 #else
388       *value = dlsym(0,symbol);
389 #endif
390       if (*value) {
391         ierr = PetscInfo1(0,"Loading function %s from object code\n",symbol);CHKERRQ(ierr);
392       }
393     }
394   }
395 
396   ierr = PetscFree(symbol);CHKERRQ(ierr);
397   PetscFunctionReturn(0);
398 }
399 
400 #undef __FUNCT__
401 #define __FUNCT__ "PetscDLLibraryAppend"
402 /*@C
403      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
404                 of the search path.
405 
406      Collective on MPI_Comm
407 
408      Input Parameters:
409 +     comm - MPI communicator
410 -     libname - name of the library
411 
412      Output Parameter:
413 .     outlist - list of libraries
414 
415      Level: developer
416 
417      Notes: if library is already in path will not add it.
418 @*/
419 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
420 {
421   PetscDLLibrary list,prev;
422   void*          handle;
423   PetscErrorCode ierr;
424   size_t         len;
425   PetscTruth     match,dir;
426   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
427   PetscToken     token;
428 
429   PetscFunctionBegin;
430 
431   /* is libname a directory? */
432   ierr = PetscTestDirectory(libname,'r',&dir);CHKERRQ(ierr);
433   if (dir) {
434     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);CHKERRQ(ierr);
435     ierr  = PetscStrcpy(program,libname);CHKERRQ(ierr);
436     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
437     if (program[len-1] == '/') {
438       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
439     } else {
440       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
441     }
442     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
443 
444     ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
445     if (!dir) PetscFunctionReturn(0);
446     found = buf;
447   } else {
448     found = (char*)libname;
449   }
450   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
451   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
452 
453   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
454   ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
455   ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
456   if (s) s[0] = 0;
457   while (libname1) {
458 
459     /* see if library was already open then we are done */
460     list  = prev = *outlist;
461     match = PETSC_FALSE;
462     while (list) {
463 
464       ierr = PetscStrcmp(list->libname,libname1,&match);CHKERRQ(ierr);
465       if (match) break;
466       prev = list;
467       list = list->next;
468     }
469     if (!match) {
470 
471       ierr = PetscDLLibraryOpen(comm,libname1,&handle);CHKERRQ(ierr);
472 
473       ierr         = PetscNew(struct _n_PetscDLLibrary,&list);CHKERRQ(ierr);
474       list->next   = 0;
475       list->handle = handle;
476       ierr = PetscStrcpy(list->libname,libname1);CHKERRQ(ierr);
477 
478       if (!*outlist) {
479 	*outlist   = list;
480       } else {
481 	prev->next = list;
482       }
483       ierr = PetscInfo1(0,"Appending %s to dynamic library search path\n",libname1);CHKERRQ(ierr);
484     }
485     ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
486     if (libname1) {
487       ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
488       if (s) s[0] = 0;
489     }
490   }
491   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
492   PetscFunctionReturn(0);
493 }
494 
495 #undef __FUNCT__
496 #define __FUNCT__ "PetscDLLibraryPrepend"
497 /*@C
498      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
499                  the search path.
500 
501      Collective on MPI_Comm
502 
503      Input Parameters:
504 +     comm - MPI communicator
505 -     libname - name of the library
506 
507      Output Parameter:
508 .     outlist - list of libraries
509 
510      Level: developer
511 
512      Notes: If library is already in path will remove old reference.
513 
514 @*/
515 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
516 {
517   PetscDLLibrary list,prev;
518   void*          handle;
519   PetscErrorCode ierr;
520   size_t         len;
521   PetscTruth     match,dir;
522   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
523   PetscToken     token;
524 
525   PetscFunctionBegin;
526 
527   /* is libname a directory? */
528   ierr = PetscTestDirectory(libname,'r',&dir);CHKERRQ(ierr);
529   if (dir) {
530     ierr = PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);CHKERRQ(ierr);
531     ierr  = PetscStrcpy(program,libname);CHKERRQ(ierr);
532     ierr  = PetscStrlen(program,&len);CHKERRQ(ierr);
533     if (program[len-1] == '/') {
534       ierr  = PetscStrcat(program,"*.");CHKERRQ(ierr);
535     } else {
536       ierr  = PetscStrcat(program,"/*.");CHKERRQ(ierr);
537     }
538     ierr  = PetscStrcat(program,PETSC_SLSUFFIX);CHKERRQ(ierr);
539 
540     ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
541     if (!dir) PetscFunctionReturn(0);
542     found = buf;
543   } else {
544     found = (char*)libname;
545   }
546 
547   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
548   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
549 
550   ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr);
551   ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
552   ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
553   if (s) s[0] = 0;
554   while (libname1) {
555     /* see if library was already open and move it to the front */
556     list  = *outlist;
557     prev  = 0;
558     match = PETSC_FALSE;
559     while (list) {
560 
561       ierr = PetscStrcmp(list->libname,libname1,&match);CHKERRQ(ierr);
562       if (match) {
563 	if (prev) prev->next = list->next;
564 	list->next = *outlist;
565 	*outlist   = list;
566 	break;
567       }
568       prev = list;
569       list = list->next;
570     }
571     if (!match) {
572       /* open the library and add to front of list */
573       ierr = PetscDLLibraryOpen(comm,libname1,&handle);CHKERRQ(ierr);
574 
575       ierr = PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname1);CHKERRQ(ierr);
576 
577       ierr         = PetscNew(struct _n_PetscDLLibrary,&list);CHKERRQ(ierr);
578       list->handle = handle;
579       list->next   = *outlist;
580       ierr = PetscStrcpy(list->libname,libname1);CHKERRQ(ierr);
581       *outlist     = list;
582     }
583     ierr = PetscTokenFind(token,&libname1);CHKERRQ(ierr);
584     if (libname1) {
585       ierr = PetscStrstr(libname1,suffix,&s);CHKERRQ(ierr);
586       if (s) s[0] = 0;
587     }
588   }
589   ierr = PetscTokenDestroy(token);CHKERRQ(ierr);
590   PetscFunctionReturn(0);
591 }
592 
593 #undef __FUNCT__
594 #define __FUNCT__ "PetscDLLibraryClose"
595 /*@C
596      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
597 
598     Collective on PetscDLLibrary
599 
600     Input Parameter:
601 .     next - library list
602 
603      Level: developer
604 
605 @*/
606 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryClose(PetscDLLibrary next)
607 {
608   PetscDLLibrary prev;
609   PetscErrorCode ierr;
610 
611   PetscFunctionBegin;
612   while (next) {
613     prev = next;
614     next = next->next;
615     /* free the space in the prev data-structure */
616     ierr = PetscFree(prev);CHKERRQ(ierr);
617   }
618   PetscFunctionReturn(0);
619 }
620 
621 #undef __FUNCT__
622 #define __FUNCT__ "PetscDLLibraryCCAAppend"
623 /*@C
624      PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
625                 of the search path.
626 
627      Collective on MPI_Comm
628 
629      Input Parameters:
630 +     comm - MPI communicator
631 -     libname - name of directory to check
632 
633      Output Parameter:
634 .     outlist - list of libraries
635 
636      Level: developer
637 
638      Notes: if library is already in path will not add it.
639 @*/
640 PetscErrorCode PETSC_DLLEXPORT PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char dirname[])
641 {
642   PetscErrorCode ierr;
643   size_t         l;
644   PetscTruth     dir;
645   char           program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
646   char           *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
647   FILE           *fp;
648   PetscToken     token1, token2;
649   int            err;
650 
651   PetscFunctionBegin;
652   /* is dirname a directory? */
653   ierr = PetscTestDirectory(dirname,'r',&dir);CHKERRQ(ierr);
654   if (!dir) PetscFunctionReturn(0);
655 
656   ierr = PetscInfo1(0,"Checking directory %s for CCA components\n",dirname);CHKERRQ(ierr);
657   ierr  = PetscStrcpy(program,dirname);CHKERRQ(ierr);
658   ierr  = PetscStrcat(program,"/*.cca");CHKERRQ(ierr);
659 
660   ierr = PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr);
661   if (!dir) PetscFunctionReturn(0);
662 
663   ierr = PetscStrcpy(suffix,".");CHKERRQ(ierr);
664   ierr = PetscStrcat(suffix,PETSC_SLSUFFIX);CHKERRQ(ierr);
665   ierr = PetscTokenCreate(buf,'\n',&token1);CHKERRQ(ierr);
666   ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
667   while (libname1) {
668     fp    = fopen(libname1,"r"); if (!fp) continue;
669     while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
670       if (found[0] == '!') continue;
671       ierr = PetscStrstr(found,suffix,&f2);CHKERRQ(ierr);
672       if (f2) { /* found library name */
673         if (found[0] == '/') {
674           lib = found;
675         } else {
676           ierr = PetscStrcpy(libname,dirname);CHKERRQ(ierr);
677           ierr = PetscStrlen(libname,&l);CHKERRQ(ierr);
678           if (libname[l-1] != '/') {ierr = PetscStrcat(libname,"/");CHKERRQ(ierr);}
679           ierr = PetscStrcat(libname,found);CHKERRQ(ierr);
680           lib  = libname;
681         }
682         ierr = PetscDLLibraryAppend(comm,outlist,lib);CHKERRQ(ierr);
683       } else {
684         ierr = PetscInfo2(0,"CCA Component function and name: %s from %s\n",found,libname1);CHKERRQ(ierr);
685         ierr = PetscTokenCreate(found,' ',&token2);CHKERRQ(ierr);
686         ierr = PetscTokenFind(token2,&func);CHKERRQ(ierr);
687         ierr = PetscTokenFind(token2,&funcname);CHKERRQ(ierr);
688         ierr = PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);CHKERRQ(ierr);
689         ierr = PetscTokenDestroy(token2);CHKERRQ(ierr);
690       }
691     }
692     err = fclose(fp);
693     if (err) SETERRQ(PETSC_ERR_SYS,"fclose() failed on file");
694     ierr = PetscTokenFind(token1,&libname1);CHKERRQ(ierr);
695   }
696   ierr = PetscTokenDestroy(token1);CHKERRQ(ierr);
697   PetscFunctionReturn(0);
698 }
699 
700 
701 #endif
702 
703 
704