xref: /petsc/src/sys/dll/dlimpl.c (revision ce94432eddcd14845bc7e8083b7f8ea723b9bf7d)
1 
2 /*
3    Low-level routines for managing dynamic link libraries (DLLs).
4 */
5 
6 #include <petsc-private/petscimpl.h>
7 
8 /* XXX Should be done better !!!*/
9 #if !defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
10 #undef PETSC_HAVE_WINDOWS_H
11 #undef PETSC_HAVE_DLFCN_H
12 #endif
13 
14 #if defined(PETSC_HAVE_WINDOWS_H)
15 #include <windows.h>
16 #elif defined(PETSC_HAVE_DLFCN_H)
17 #include <dlfcn.h>
18 #endif
19 
20 #if defined(PETSC_HAVE_WINDOWS_H)
21 typedef HMODULE dlhandle_t;
22 typedef FARPROC dlsymbol_t;
23 #elif defined(PETSC_HAVE_DLFCN_H)
24 typedef void* dlhandle_t;
25 typedef void* dlsymbol_t;
26 #else
27 typedef void* dlhandle_t;
28 typedef void* dlsymbol_t;
29 #endif
30 
31 #undef __FUNCT__
32 #define __FUNCT__ "PetscDLOpen"
33 /*@C
34    PetscDLOpen - opens dynamic library
35 
36    Not Collective
37 
38    Input Parameters:
39 +    name - name of library
40 -    mode - options on how to open library
41 
42    Output Parameter:
43 .    handle
44 
45    Level: developer
46 
47 @*/
48 PetscErrorCode  PetscDLOpen(const char name[],PetscDLMode mode,PetscDLHandle *handle)
49 {
50   PETSC_UNUSED int dlflags1,dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
51   dlhandle_t       dlhandle;
52 
53   PetscFunctionBegin;
54   PetscValidCharPointer(name,1);
55   PetscValidPointer(handle,3);
56 
57   dlflags1 = 0;
58   dlflags2 = 0;
59   dlhandle = (dlhandle_t) 0;
60   *handle  = (PetscDLHandle) 0;
61 
62   /*
63      --- LoadLibrary ---
64   */
65 #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
66   dlhandle = LoadLibrary(name);
67   if (!dlhandle) {
68 #if defined(PETSC_HAVE_GETLASTERROR)
69     PetscErrorCode ierr;
70     DWORD          erc;
71     char           *buff = NULL;
72     erc = GetLastError();
73     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
74                   NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
75     ierr = PetscError(PETSC_COMM_SELF,__LINE__,__FUNCT__,__FILE__,__SDIR__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT,
76                       "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,buff);
77     LocalFree(buff);
78     PetscFunctionReturn(ierr);
79 #else
80     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,"unavailable");
81 #endif
82   }
83 
84   /*
85      --- dlopen ---
86   */
87 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
88   /*
89       Mode indicates symbols required by symbol loaded with dlsym()
90      are only loaded when required (not all together) also indicates
91      symbols required can be contained in other libraries also opened
92      with dlopen()
93   */
94 #if defined(PETSC_HAVE_RTLD_LAZY)
95   dlflags1 = RTLD_LAZY;
96 #endif
97 #if defined(PETSC_HAVE_RTLD_NOW)
98   if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
99 #endif
100 #if defined(PETSC_HAVE_RTLD_GLOBAL)
101   dlflags2 = RTLD_GLOBAL;
102 #endif
103 #if defined(PETSC_HAVE_RTLD_LOCAL)
104   if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
105 #endif
106 #if defined(PETSC_HAVE_DLERROR)
107   dlerror(); /* clear any previous error */
108 #endif
109   dlhandle = dlopen(name,dlflags1|dlflags2);
110   if (!dlhandle) {
111 #if defined(PETSC_HAVE_DLERROR)
112     const char *errmsg = dlerror();
113 #else
114     const char *errmsg = "unavailable";
115 #endif
116     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s\n",name,errmsg);
117   }
118 
119   /*
120      --- unimplemented ---
121   */
122 #else
123   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
124 #endif
125 
126   *handle = (PetscDLHandle) dlhandle;
127   PetscFunctionReturn(0);
128 }
129 
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "PetscDLClose"
133 /*@C
134    PetscDLClose -  closes a dynamic library
135 
136    Not Collective
137 
138   Input Parameter:
139 .   handle - the handle for the library obtained with PetscDLOpen()
140 
141   Level: developer
142 @*/
143 PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
144 {
145 
146   PetscFunctionBegin;
147   PetscValidPointer(handle,1);
148 
149   /*
150      --- FreeLibrary ---
151   */
152 #if defined(PETSC_HAVE_WINDOWS_H)
153 #if defined(PETSC_HAVE_FREELIBRARY)
154   if (FreeLibrary((dlhandle_t)*handle) == 0) {
155 #if defined(PETSC_HAVE_GETLASTERROR)
156     char  *buff = NULL;
157     DWORD erc   = GetLastError();
158     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
159     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
160     LocalFree(buff);
161 #else
162     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","unavailable");
163 #endif
164   }
165 #endif /* !PETSC_HAVE_FREELIBRARY */
166 
167   /*
168      --- dclose ---
169   */
170 #elif defined(PETSC_HAVE_DLFCN_H)
171 #if defined(PETSC_HAVE_DLCLOSE)
172 #if defined(PETSC_HAVE_DLERROR)
173   dlerror(); /* clear any previous error */
174 #endif
175   if (dlclose((dlhandle_t)*handle) < 0) {
176 #if defined(PETSC_HAVE_DLERROR)
177     const char *errmsg = dlerror();
178 #else
179     const char *errmsg = "unavailable";
180 #endif
181     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", errmsg);
182   }
183 #endif /* !PETSC_HAVE_DLCLOSE */
184 
185   /*
186      --- unimplemented ---
187   */
188 #else
189   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
190 #endif
191 
192   *handle = NULL;
193   PetscFunctionReturn(0);
194 }
195 
196 #undef __FUNCT__
197 #define __FUNCT__ "PetscDLSym"
198 /*@C
199    PetscDLSym - finds a symbol in a dynamic library
200 
201    Not Collective
202 
203    Input Parameters:
204 +   handle - obtained with PetscDLOpen() or NULL
205 -   symbol - name of symbol
206 
207    Output Parameter:
208 .   value - pointer to the function, NULL if not found
209 
210    Level: developer
211 
212   Notes:
213    If handle is NULL, the symbol is looked for in the main executable's dynamic symbol table.
214    In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
215    systems this requires platform-specific linker flags.
216 
217 @*/
218 PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
219 {
220   PETSC_UNUSED dlhandle_t dlhandle;
221   dlsymbol_t              dlsymbol;
222 
223   PetscValidCharPointer(symbol,2);
224   PetscValidPointer(value,3);
225 
226   dlhandle = (dlhandle_t) 0;
227   dlsymbol = (dlsymbol_t) 0;
228   *value   = (void*) 0;
229 
230   /*
231      --- GetProcAddress ---
232   */
233 #if defined(PETSC_HAVE_WINDOWS_H)
234 #if defined(PETSC_HAVE_GETPROCADDRESS)
235   if (handle) dlhandle = (dlhandle_t) handle;
236   else dlhandle = (dlhandle_t) GetCurrentProcess();
237   dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol);
238 #if defined(PETSC_HAVE_SETLASTERROR)
239   SetLastError((DWORD)0); /* clear any previous error */
240 #endif
241 #endif /* !PETSC_HAVE_GETPROCADDRESS */
242 
243   /*
244      --- dlsym ---
245   */
246 #elif defined(PETSC_HAVE_DLFCN_H)
247 #if defined(PETSC_HAVE_DLSYM)
248   if (handle) dlhandle = (dlhandle_t) handle;
249   else {
250 
251 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
252     /* Attempt to retrieve the main executable's dlhandle. */
253     { int dlflags1 = 0, dlflags2 = 0;
254 #if defined(PETSC_HAVE_RTLD_LAZY)
255       dlflags1 = RTLD_LAZY;
256 #endif
257       if (!dlflags1) {
258 #if defined(PETSC_HAVE_RTLD_NOW)
259         dlflags1 = RTLD_NOW;
260 #endif
261       }
262 #if defined(PETSC_HAVE_RTLD_LOCAL)
263       dlflags2 = RTLD_LOCAL;
264 #endif
265       if (!dlflags2) {
266 #if defined(PETSC_HAVE_RTLD_GLOBAL)
267         dlflags2 = RTLD_GLOBAL;
268 #endif
269       }
270 #if defined(PETSC_HAVE_DLERROR)
271       if (!(PETSC_RUNNING_ON_VALGRIND)) {
272         dlerror(); /* clear any previous error; valgrind does not like this */
273       }
274 #endif
275       /* Attempt to open the main executable as a dynamic library. */
276 #if defined(PETSC_HAVE_RTDL_DEFAULT)
277       dlhandle = RTLD_DEFAULT;
278 #else
279       dlhandle = dlopen(0, dlflags1|dlflags2);
280 #if defined(PETSC_HAVE_DLERROR)
281       { const char *e = (const char*) dlerror();
282         if (e) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library:\n  Error message from dlopen(): '%s'\n", e);
283       }
284 #endif
285 #endif
286     }
287 #endif
288 #endif /* PETSC_HAVE_DLOPEN && PETSC_USE_DYNAMIC_LIBRARIES */
289   }
290 #if defined(PETSC_HAVE_DLERROR)
291   dlerror(); /* clear any previous error */
292 #endif
293   dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol);
294   /*
295      --- unimplemented ---
296   */
297 #else
298   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
299 #endif
300 
301   *value = *((void**)&dlsymbol);
302 
303 #if defined(PETSC_SERIALIZE_FUNCTIONS)
304   if (*value) {
305     PetscErrorCode ierr;
306     ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr);
307   }
308 #endif
309   return(0);
310 }
311