xref: /petsc/src/sys/dll/dl.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
1e5c89e4eSSatish Balay /*
2e5c89e4eSSatish Balay       Routines for opening dynamic link libraries (DLLs), keeping a searchable
3e5c89e4eSSatish Balay    path of DLLs, obtaining remote DLLs via a URL and opening them locally.
4e5c89e4eSSatish Balay */
5e5c89e4eSSatish Balay 
6af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
7e5c89e4eSSatish Balay 
8e5c89e4eSSatish Balay /* ------------------------------------------------------------------------------*/
9e5c89e4eSSatish Balay /*
10e5c89e4eSSatish Balay       Code to maintain a list of opened dynamic libraries and load symbols
11e5c89e4eSSatish Balay */
12e5bd5246SBarry Smith struct _n_PetscDLLibrary {
13e5bd5246SBarry Smith   PetscDLLibrary next;
14ebd79076SLisandro Dalcin   PetscDLHandle  handle;
15e5c89e4eSSatish Balay   char           libname[PETSC_MAX_PATH_LEN];
16e5c89e4eSSatish Balay };
17e5c89e4eSSatish Balay 
187087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryPrintPath(PetscDLLibrary libs)
19e5c89e4eSSatish Balay {
20e5c89e4eSSatish Balay   PetscFunctionBegin;
21e5c89e4eSSatish Balay   while (libs) {
22e5c89e4eSSatish Balay     PetscErrorPrintf("  %s\n",libs->libname);
23e5c89e4eSSatish Balay     libs = libs->next;
24e5c89e4eSSatish Balay   }
25e5c89e4eSSatish Balay   PetscFunctionReturn(0);
26e5c89e4eSSatish Balay }
27e5c89e4eSSatish Balay 
28e5c89e4eSSatish Balay /*@C
29e5c89e4eSSatish Balay    PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
30e5c89e4eSSatish Balay      (if it is remote), indicates if it exits and its local name.
31e5c89e4eSSatish Balay 
32d083f849SBarry Smith      Collective
33e5c89e4eSSatish Balay 
34e5c89e4eSSatish Balay    Input Parameters:
35e5c89e4eSSatish Balay +   comm - processors that are opening the library
36e5c89e4eSSatish Balay -   libname - name of the library, can be relative or absolute
37e5c89e4eSSatish Balay 
38d8d19677SJose E. Roman    Output Parameters:
392d53ad75SBarry Smith +   name - actual name of file on local filesystem if found
402d53ad75SBarry Smith .   llen - length of the name buffer
412d53ad75SBarry Smith -   found - true if the file exists
42e5c89e4eSSatish Balay 
43e5c89e4eSSatish Balay    Level: developer
44e5c89e4eSSatish Balay 
45e5c89e4eSSatish Balay    Notes:
46e5c89e4eSSatish Balay    [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
47e5c89e4eSSatish Balay 
48e5c89e4eSSatish Balay    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
49a5b23f4aSJose E. Roman    occurring in directoryname and filename will be replaced with appropriate values.
50e5c89e4eSSatish Balay @*/
517087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool  *found)
52e5c89e4eSSatish Balay {
53d46cf212SLisandro Dalcin   char           *buf,*par2,suffix[16],*gz,*so;
54d46cf212SLisandro Dalcin   size_t         len;
55e5c89e4eSSatish Balay 
56e5c89e4eSSatish Balay   PetscFunctionBegin;
57e5c89e4eSSatish Balay   /*
58a523d312SBarry Smith      make copy of library name and replace $PETSC_ARCH etc
59e5c89e4eSSatish Balay      so we can add to the end of it to look for something like .so.1.0 etc.
60e5c89e4eSSatish Balay   */
61*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlen(libname,&len));
622f613bf5SBarry Smith   len  = PetscMax(4*len,PETSC_MAX_PATH_LEN);
63*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(len,&buf));
64d46cf212SLisandro Dalcin   par2 = buf;
65*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrreplace(comm,libname,par2,len));
66e5c89e4eSSatish Balay 
67d46cf212SLisandro Dalcin   /* temporarily remove .gz if it ends library name */
68*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrrstr(par2,".gz",&gz));
69e5c89e4eSSatish Balay   if (gz) {
70*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlen(gz,&len));
7102c9f0b5SLisandro Dalcin     if (len != 3) gz  = NULL; /* do not end (exactly) with .gz */
72d46cf212SLisandro Dalcin     else          *gz = 0;    /* ends with .gz, so remove it   */
73e5c89e4eSSatish Balay   }
743fa76a5bSLisandro Dalcin   /* strip out .a from it if user put it in by mistake */
75*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlen(par2,&len));
763fa76a5bSLisandro Dalcin   if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
773fa76a5bSLisandro Dalcin 
78*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFileRetrieve(comm,par2,lname,llen,found));
798ce0dc28SMatthew G Knepley   if (!(*found)) {
80e5c89e4eSSatish Balay     /* see if library name does already not have suffix attached */
81*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(suffix,".",sizeof(suffix)));
82*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix)));
83*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrrstr(par2,suffix,&so));
84d46cf212SLisandro Dalcin     /* and attach the suffix if it is not there */
85*5f80ce2aSJacob Faibussowitsch     if (!so) CHKERRQ(PetscStrcat(par2,suffix));
86e5c89e4eSSatish Balay 
87d46cf212SLisandro Dalcin     /* restore the .gz suffix if it was there */
88*5f80ce2aSJacob Faibussowitsch     if (gz) CHKERRQ(PetscStrcat(par2,".gz"));
89d46cf212SLisandro Dalcin 
90d46cf212SLisandro Dalcin     /* and finally retrieve the file */
91*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFileRetrieve(comm,par2,lname,llen,found));
922d53ad75SBarry Smith   }
93d46cf212SLisandro Dalcin 
94*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(buf));
95e5c89e4eSSatish Balay   PetscFunctionReturn(0);
96e5c89e4eSSatish Balay }
97e5c89e4eSSatish Balay 
98e5c89e4eSSatish Balay /*@C
99ebd79076SLisandro Dalcin    PetscDLLibraryOpen - Opens a PETSc dynamic link library
100e5c89e4eSSatish Balay 
101d083f849SBarry Smith      Collective
102e5c89e4eSSatish Balay 
103e5c89e4eSSatish Balay    Input Parameters:
104e5c89e4eSSatish Balay +   comm - processors that are opening the library
1050f31fb7fSLisandro Dalcin -   path - name of the library, can be relative or absolute
106e5c89e4eSSatish Balay 
107e5c89e4eSSatish Balay    Output Parameter:
1080f31fb7fSLisandro Dalcin .   entry - a PETSc dynamic link library entry
109e5c89e4eSSatish Balay 
110e5c89e4eSSatish Balay    Level: developer
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay    Notes:
113bb84e0fdSBarry Smith    [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0]
114bb84e0fdSBarry Smith 
115bb84e0fdSBarry Smith    If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
116bb84e0fdSBarry Smith    when the library is opened.
117e5c89e4eSSatish Balay 
118a5b23f4aSJose E. Roman    ${PETSC_ARCH} occurring in directoryname and filename
119e5c89e4eSSatish Balay    will be replaced with the appropriate value.
120bb84e0fdSBarry Smith 
121bb84e0fdSBarry Smith .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend()
122e5c89e4eSSatish Balay @*/
1237087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry)
124e5c89e4eSSatish Balay {
125ace3abfcSBarry Smith   PetscBool      foundlibrary,match;
126b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s;
127b3bb0f5eSLisandro Dalcin   char           *basename,registername[128];
1285673baf8SLisandro Dalcin   PetscDLHandle  handle;
129607a6623SBarry Smith   PetscErrorCode (*func)(void) = NULL;
130e5c89e4eSSatish Balay 
131e5c89e4eSSatish Balay   PetscFunctionBegin;
13282a51d08SSatish Balay   PetscValidCharPointer(path,2);
1335673baf8SLisandro Dalcin   PetscValidPointer(entry,3);
134ebd79076SLisandro Dalcin 
1350298fd71SBarry Smith   *entry = NULL;
136e5c89e4eSSatish Balay 
137b3bb0f5eSLisandro Dalcin   /* retrieve the library */
138*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscInfo(NULL,"Retrieving %s\n",path));
139*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary));
1402c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!foundlibrary,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n  %s",path);
141e2e64c6bSBarry Smith   /* Eventually ./configure should determine if the system needs an executable dynamic library */
142e5c89e4eSSatish Balay #define PETSC_USE_NONEXECUTABLE_SO
143e5c89e4eSSatish Balay #if !defined(PETSC_USE_NONEXECUTABLE_SO)
144*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTestFile(par2,'x',&foundlibrary));
1452c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!foundlibrary,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n  %s\n  %s",path,par2);
146e5c89e4eSSatish Balay #endif
147e5c89e4eSSatish Balay 
1483fa76a5bSLisandro Dalcin   /* copy path and setup shared library suffix  */
149*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN));
150*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrncpy(suffix,".",sizeof(suffix)));
151*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix)));
1523fa76a5bSLisandro Dalcin   /* remove wrong suffixes from libname */
153*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrrstr(libname,".gz",&s));
1543fa76a5bSLisandro Dalcin   if (s && s[3] == 0) s[0] = 0;
155*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrrstr(libname,".a",&s));
1563fa76a5bSLisandro Dalcin   if (s && s[2] == 0) s[0] = 0;
1573fa76a5bSLisandro Dalcin   /* remove shared suffix from libname */
158*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrrstr(libname,suffix,&s));
159b3bb0f5eSLisandro Dalcin   if (s) s[0] = 0;
160b3bb0f5eSLisandro Dalcin 
1615673baf8SLisandro Dalcin   /* open the dynamic library */
162*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscInfo(NULL,"Opening dynamic library %s\n",libname));
163*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDLOpen(par2,PETSC_DL_DECIDE,&handle));
164b3bb0f5eSLisandro Dalcin 
165b3bb0f5eSLisandro Dalcin   /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */
166*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrrchr(libname,'/',&basename)); /* XXX Windows ??? */
167b3bb0f5eSLisandro Dalcin   if (!basename) basename = libname;
168*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrncmp(basename,"lib",3,&match));
169a297a907SKarl Rupp   if (match) basename = basename + 3;
170a297a907SKarl Rupp   else {
171*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Dynamic library %s does not have lib prefix\n",libname));
172e5c89e4eSSatish Balay   }
173cf4b33a9SJed Brown   for (s=basename; *s; s++) if (*s == '-') *s = '_';
174*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername)));
175*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlcat(registername,basename,sizeof(registername)));
176*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDLSym(handle,registername,(void**)&func));
177b3bb0f5eSLisandro Dalcin   if (func) {
178*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Loading registered routines from %s\n",libname));
179*5f80ce2aSJacob Faibussowitsch     CHKERRQ((*func)());
180b3bb0f5eSLisandro Dalcin   } else {
181*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Dynamic library %s does not have symbol %s\n",libname,registername));
182b3bb0f5eSLisandro Dalcin   }
1835673baf8SLisandro Dalcin 
184*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNew(entry));
18502c9f0b5SLisandro Dalcin   (*entry)->next   = NULL;
186b3bb0f5eSLisandro Dalcin   (*entry)->handle = handle;
187*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcpy((*entry)->libname,libname));
188e5c89e4eSSatish Balay   PetscFunctionReturn(0);
189e5c89e4eSSatish Balay }
190e5c89e4eSSatish Balay 
191e5c89e4eSSatish Balay /*@C
192e5c89e4eSSatish Balay    PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
193e5c89e4eSSatish Balay 
194d083f849SBarry Smith    Collective
195e5c89e4eSSatish Balay 
196d8d19677SJose E. Roman    Input Parameters:
197e5bd5246SBarry Smith +  comm - communicator that will open the library
1980298fd71SBarry Smith .  outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function)
19930a1dd1fSBarry Smith .  path     - optional complete library name (if provided checks here before checking outlist)
200e5c89e4eSSatish Balay -  insymbol - name of symbol
201e5c89e4eSSatish Balay 
202e5c89e4eSSatish Balay    Output Parameter:
2030298fd71SBarry Smith .  value - if symbol not found then this value is set to NULL
204e5c89e4eSSatish Balay 
205e5c89e4eSSatish Balay    Level: developer
206e5c89e4eSSatish Balay 
20795452b02SPatrick Sanan    Notes:
20895452b02SPatrick Sanan     Symbol can be of the form
209e5c89e4eSSatish Balay         [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
210e5c89e4eSSatish Balay 
211e5c89e4eSSatish Balay         Will attempt to (retrieve and) open the library if it is not yet been opened.
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay @*/
2147087cfbeSBarry Smith PetscErrorCode  PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value)
215e5c89e4eSSatish Balay {
216b3bb0f5eSLisandro Dalcin   char           libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s;
2170298fd71SBarry Smith   PetscDLLibrary nlist,prev,list = NULL;
218e5c89e4eSSatish Balay 
219e5c89e4eSSatish Balay   PetscFunctionBegin;
220340b11eeSBarry Smith   if (outlist) PetscValidPointer(outlist,2);
2215673baf8SLisandro Dalcin   if (path) PetscValidCharPointer(path,3);
2225673baf8SLisandro Dalcin   PetscValidCharPointer(insymbol,4);
2235673baf8SLisandro Dalcin   PetscValidPointer(value,5);
2245673baf8SLisandro Dalcin 
225340b11eeSBarry Smith   if (outlist) list = *outlist;
22602c9f0b5SLisandro Dalcin   *value = NULL;
227e5c89e4eSSatish Balay 
228*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrchr(insymbol,'(',&s));
2292d53ad75SBarry Smith   if (s) {
230e5c89e4eSSatish Balay     /* make copy of symbol so we can edit it in place */
231*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrallocpy(insymbol,&symbol));
232b3bb0f5eSLisandro Dalcin     /* If symbol contains () then replace with a NULL, to support functionname() */
233*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrchr(symbol,'(',&s));
2342d53ad75SBarry Smith     s[0] = 0;
235a297a907SKarl Rupp   } else symbol = (char*)insymbol;
236e5c89e4eSSatish Balay 
237e5c89e4eSSatish Balay   /*
238e5c89e4eSSatish Balay        Function name does include library
239e5c89e4eSSatish Balay        -------------------------------------
240e5c89e4eSSatish Balay   */
241e5c89e4eSSatish Balay   if (path && path[0] != '\0') {
242b3bb0f5eSLisandro Dalcin     /* copy path and remove suffix from libname */
243*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN));
244*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(suffix,".",sizeof(suffix)));
245*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix)));
246*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrrstr(libname,suffix,&s));
247b3bb0f5eSLisandro Dalcin     if (s) s[0] = 0;
2485673baf8SLisandro Dalcin     /* Look if library is already opened and in path */
24902c9f0b5SLisandro Dalcin     prev  = NULL;
250b3bb0f5eSLisandro Dalcin     nlist = list;
251e5c89e4eSSatish Balay     while (nlist) {
252ace3abfcSBarry Smith       PetscBool match;
253*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(nlist->libname,libname,&match));
2545673baf8SLisandro Dalcin       if (match) goto done;
255e5c89e4eSSatish Balay       prev  = nlist;
256e5c89e4eSSatish Balay       nlist = nlist->next;
257e5c89e4eSSatish Balay     }
258b3bb0f5eSLisandro Dalcin     /* open the library and append it to path */
259*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDLLibraryOpen(comm,path,&nlist));
260*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Appending %s to dynamic library search path\n",path));
261a297a907SKarl Rupp     if (prev) prev->next = nlist;
262ca43db0aSBarry Smith     else {if (outlist) *outlist   = nlist;}
263e5c89e4eSSatish Balay 
264e5c89e4eSSatish Balay done:;
265*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDLSym(nlist->handle,symbol,value));
26630a1dd1fSBarry Smith     if (*value) {
267*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(NULL,"Loading function %s from dynamic library %s\n",insymbol,path));
26830a1dd1fSBarry Smith     }
269e5c89e4eSSatish Balay 
270e5c89e4eSSatish Balay     /*
271e5c89e4eSSatish Balay          Function name does not include library so search path
272e5c89e4eSSatish Balay          -----------------------------------------------------
273e5c89e4eSSatish Balay     */
274e5c89e4eSSatish Balay   } else {
275e5c89e4eSSatish Balay     while (list) {
276*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDLSym(list->handle,symbol,value));
277e5c89e4eSSatish Balay       if (*value) {
278*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscInfo(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname));
279e5c89e4eSSatish Balay         break;
280e5c89e4eSSatish Balay       }
281e5c89e4eSSatish Balay       list = list->next;
282e5c89e4eSSatish Balay     }
283e5c89e4eSSatish Balay     if (!*value) {
284*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDLSym(NULL,symbol,value));
285e5c89e4eSSatish Balay       if (*value) {
286*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscInfo(NULL,"Loading symbol %s from object code\n",symbol));
287e5c89e4eSSatish Balay       }
288e5c89e4eSSatish Balay     }
289e5c89e4eSSatish Balay   }
290e5c89e4eSSatish Balay 
2912d53ad75SBarry Smith   if (symbol != insymbol) {
292*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(symbol));
2932d53ad75SBarry Smith   }
294e5c89e4eSSatish Balay   PetscFunctionReturn(0);
295e5c89e4eSSatish Balay }
296e5c89e4eSSatish Balay 
297e5c89e4eSSatish Balay /*@C
298e5c89e4eSSatish Balay      PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
299e5c89e4eSSatish Balay                 of the search path.
300e5c89e4eSSatish Balay 
301d083f849SBarry Smith      Collective
302e5c89e4eSSatish Balay 
303e5c89e4eSSatish Balay      Input Parameters:
304e5c89e4eSSatish Balay +     comm - MPI communicator
3050f31fb7fSLisandro Dalcin -     path - name of the library
306e5c89e4eSSatish Balay 
307e5c89e4eSSatish Balay      Output Parameter:
308e5c89e4eSSatish Balay .     outlist - list of libraries
309e5c89e4eSSatish Balay 
310e5c89e4eSSatish Balay      Level: developer
311e5c89e4eSSatish Balay 
31295452b02SPatrick Sanan      Notes:
31395452b02SPatrick Sanan     if library is already in path will not add it.
314bb84e0fdSBarry Smith 
315bb84e0fdSBarry Smith   If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run
316bb84e0fdSBarry Smith       when the library is opened.
317bb84e0fdSBarry Smith 
318bb84e0fdSBarry Smith .seealso: PetscDLLibraryOpen()
319e5c89e4eSSatish Balay @*/
3207087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
321e5c89e4eSSatish Balay {
322e5bd5246SBarry Smith   PetscDLLibrary list,prev;
323e5c89e4eSSatish Balay   size_t         len;
324ace3abfcSBarry Smith   PetscBool      match,dir;
325b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
326b3bb0f5eSLisandro Dalcin   char           *libname,suffix[16],*s;
3279c9d3cfdSBarry Smith   PetscToken     token;
328e5c89e4eSSatish Balay 
329e5c89e4eSSatish Balay   PetscFunctionBegin;
330b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist,2);
331e5c89e4eSSatish Balay 
332b3bb0f5eSLisandro Dalcin   /* is path a directory? */
333*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTestDirectory(path,'r',&dir));
334e5c89e4eSSatish Balay   if (dir) {
335*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Checking directory %s for dynamic libraries\n",path));
336*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(program,path,sizeof(program)));
337*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlen(program,&len));
338e5c89e4eSSatish Balay     if (program[len-1] == '/') {
339*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrlcat(program,"*.",sizeof(program)));
340e5c89e4eSSatish Balay     } else {
341*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrlcat(program,"/*.",sizeof(program)));
342e5c89e4eSSatish Balay     }
343*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program)));
344e5c89e4eSSatish Balay 
345*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir));
346e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
347e5c89e4eSSatish Balay   } else {
348*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(found,path,PETSC_MAX_PATH_LEN));
349e5c89e4eSSatish Balay   }
350*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrncpy(suffix,".",sizeof(suffix)));
351*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix)));
352e5c89e4eSSatish Balay 
353*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTokenCreate(found,'\n',&token));
354*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTokenFind(token,&libname));
355b3bb0f5eSLisandro Dalcin   while (libname) {
356b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
357*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrrstr(libname,suffix,&s));
358e5c89e4eSSatish Balay     if (s) s[0] = 0;
359e5c89e4eSSatish Balay     /* see if library was already open then we are done */
360e5c89e4eSSatish Balay     list  = prev = *outlist;
361e5c89e4eSSatish Balay     match = PETSC_FALSE;
362e5c89e4eSSatish Balay     while (list) {
363*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(list->libname,libname,&match));
364e5c89e4eSSatish Balay       if (match) break;
365e5c89e4eSSatish Balay       prev = list;
366e5c89e4eSSatish Balay       list = list->next;
367e5c89e4eSSatish Balay     }
368b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
369b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
370e5c89e4eSSatish Balay     if (!match) {
3715673baf8SLisandro Dalcin       /* open the library and add to end of list */
372*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDLLibraryOpen(comm,libname,&list));
373*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(NULL,"Appending %s to dynamic library search path\n",libname));
374a297a907SKarl Rupp       if (!*outlist) *outlist   = list;
375a297a907SKarl Rupp       else           prev->next = list;
376e5c89e4eSSatish Balay     }
377*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscTokenFind(token,&libname));
378e5c89e4eSSatish Balay   }
379*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTokenDestroy(&token));
380e5c89e4eSSatish Balay   PetscFunctionReturn(0);
381e5c89e4eSSatish Balay }
382e5c89e4eSSatish Balay 
383e5c89e4eSSatish Balay /*@C
384e5c89e4eSSatish Balay      PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
385e5c89e4eSSatish Balay                  the search path.
386e5c89e4eSSatish Balay 
387d083f849SBarry Smith      Collective
388e5c89e4eSSatish Balay 
389e5c89e4eSSatish Balay      Input Parameters:
390e5c89e4eSSatish Balay +     comm - MPI communicator
3910f31fb7fSLisandro Dalcin -     path - name of the library
392e5c89e4eSSatish Balay 
393e5c89e4eSSatish Balay      Output Parameter:
394e5c89e4eSSatish Balay .     outlist - list of libraries
395e5c89e4eSSatish Balay 
396e5c89e4eSSatish Balay      Level: developer
397e5c89e4eSSatish Balay 
39895452b02SPatrick Sanan      Notes:
39995452b02SPatrick Sanan     If library is already in path will remove old reference.
400e5c89e4eSSatish Balay 
401e5c89e4eSSatish Balay @*/
4027087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[])
403e5c89e4eSSatish Balay {
404e5bd5246SBarry Smith   PetscDLLibrary list,prev;
405e5c89e4eSSatish Balay   size_t         len;
406ace3abfcSBarry Smith   PetscBool      match,dir;
407b3bb0f5eSLisandro Dalcin   char           program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN];
408b3bb0f5eSLisandro Dalcin   char           *libname,suffix[16],*s;
4095b096c79SMatthew Knepley   PetscToken     token;
410e5c89e4eSSatish Balay 
411e5c89e4eSSatish Balay   PetscFunctionBegin;
412b3bb0f5eSLisandro Dalcin   PetscValidPointer(outlist,2);
413e5c89e4eSSatish Balay 
414b3bb0f5eSLisandro Dalcin   /* is path a directory? */
415*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTestDirectory(path,'r',&dir));
416e5c89e4eSSatish Balay   if (dir) {
417*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Checking directory %s for dynamic libraries\n",path));
418*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(program,path,sizeof(program)));
419*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlen(program,&len));
420e5c89e4eSSatish Balay     if (program[len-1] == '/') {
421*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrlcat(program,"*.",sizeof(program)));
422e5c89e4eSSatish Balay     } else {
423*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrlcat(program,"/*.",sizeof(program)));
424e5c89e4eSSatish Balay     }
425*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program)));
426e5c89e4eSSatish Balay 
427*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir));
428e5c89e4eSSatish Balay     if (!dir) PetscFunctionReturn(0);
429e5c89e4eSSatish Balay   } else {
430*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(found,path,PETSC_MAX_PATH_LEN));
431e5c89e4eSSatish Balay   }
432e5c89e4eSSatish Balay 
433*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrncpy(suffix,".",sizeof(suffix)));
434*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix)));
435e5c89e4eSSatish Balay 
436*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTokenCreate(found,'\n',&token));
437*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTokenFind(token,&libname));
438b3bb0f5eSLisandro Dalcin   while (libname) {
439b3bb0f5eSLisandro Dalcin     /* remove suffix from libname */
440*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrstr(libname,suffix,&s));
441e5c89e4eSSatish Balay     if (s) s[0] = 0;
442e5c89e4eSSatish Balay     /* see if library was already open and move it to the front */
44302c9f0b5SLisandro Dalcin     prev  = NULL;
444b3bb0f5eSLisandro Dalcin     list  = *outlist;
445e5c89e4eSSatish Balay     match = PETSC_FALSE;
446e5c89e4eSSatish Balay     while (list) {
447*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(list->libname,libname,&match));
448e5c89e4eSSatish Balay       if (match) {
449*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscInfo(NULL,"Moving %s to begin of dynamic library search path\n",libname));
450e5c89e4eSSatish Balay         if (prev) prev->next = list->next;
451b3bb0f5eSLisandro Dalcin         if (prev) list->next = *outlist;
452e5c89e4eSSatish Balay         *outlist = list;
453e5c89e4eSSatish Balay         break;
454e5c89e4eSSatish Balay       }
455e5c89e4eSSatish Balay       prev = list;
456e5c89e4eSSatish Balay       list = list->next;
457e5c89e4eSSatish Balay     }
458b3bb0f5eSLisandro Dalcin     /* restore suffix from libname */
459b3bb0f5eSLisandro Dalcin     if (s) s[0] = '.';
460e5c89e4eSSatish Balay     if (!match) {
4615673baf8SLisandro Dalcin       /* open the library and add to front of list */
462*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDLLibraryOpen(comm,libname,&list));
463*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(NULL,"Prepending %s to dynamic library search path\n",libname));
464ebd79076SLisandro Dalcin       list->next = *outlist;
465e5c89e4eSSatish Balay       *outlist   = list;
466e5c89e4eSSatish Balay     }
467*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscTokenFind(token,&libname));
468e5c89e4eSSatish Balay   }
469*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTokenDestroy(&token));
470e5c89e4eSSatish Balay   PetscFunctionReturn(0);
471e5c89e4eSSatish Balay }
472e5c89e4eSSatish Balay 
473e5c89e4eSSatish Balay /*@C
474e5c89e4eSSatish Balay      PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
475e5c89e4eSSatish Balay 
476e5c89e4eSSatish Balay     Collective on PetscDLLibrary
477e5c89e4eSSatish Balay 
478e5c89e4eSSatish Balay     Input Parameter:
4793fa76a5bSLisandro Dalcin .     head - library list
480e5c89e4eSSatish Balay 
481e5c89e4eSSatish Balay      Level: developer
482e5c89e4eSSatish Balay 
483e5c89e4eSSatish Balay @*/
4847087cfbeSBarry Smith PetscErrorCode  PetscDLLibraryClose(PetscDLLibrary list)
485e5c89e4eSSatish Balay {
486ace3abfcSBarry Smith   PetscBool      done = PETSC_FALSE;
4870f31fb7fSLisandro Dalcin   PetscDLLibrary prev,tail;
488e5c89e4eSSatish Balay 
489e5c89e4eSSatish Balay   PetscFunctionBegin;
4900f31fb7fSLisandro Dalcin   if (!list) PetscFunctionReturn(0);
4913fa76a5bSLisandro Dalcin   /* traverse the list in reverse order */
4923fa76a5bSLisandro Dalcin   while (!done) {
4930f31fb7fSLisandro Dalcin     if (!list->next) done = PETSC_TRUE;
4940f31fb7fSLisandro Dalcin     prev = tail = list;
4953fa76a5bSLisandro Dalcin     while (tail->next) {
4963fa76a5bSLisandro Dalcin       prev = tail;
4973fa76a5bSLisandro Dalcin       tail = tail->next;
498e5c89e4eSSatish Balay     }
49902c9f0b5SLisandro Dalcin     prev->next = NULL;
5003fa76a5bSLisandro Dalcin     /* close the dynamic library and free the space in entry data-structure*/
501*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(NULL,"Closing dynamic library %s\n",tail->libname));
502*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDLClose(&tail->handle));
503*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(tail));
504a297a907SKarl Rupp   }
505e5c89e4eSSatish Balay   PetscFunctionReturn(0);
506e5c89e4eSSatish Balay }
507