xref: /petsc/src/sys/dll/dlimpl.c (revision 5c6c1daec53e1d9ab0bec9db5309fd8fc7645b8d)
1 
2 /*
3    Low-level routines for managing dynamic link libraries (DLLs).
4 */
5 
6 #include <petscsys.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 -    flags - options on how to open library
41 
42    Output Parameter:
43 .    handle
44 
45    Level: developer
46 
47 @*/
48 PetscErrorCode  PetscDLOpen(const char name[],int flags,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 (flags & PETSC_DL_NOW)
99     dlflags1 = RTLD_NOW;
100 #endif
101 #if defined(PETSC_HAVE_RTLD_GLOBAL)
102   dlflags2 = RTLD_GLOBAL;
103 #endif
104 #if defined(PETSC_HAVE_RTLD_LOCAL)
105   if (flags & PETSC_DL_LOCAL)
106     dlflags2 = RTLD_LOCAL;
107 #endif
108 #if defined(PETSC_HAVE_DLERROR)
109   dlerror(); /* clear any previous error */
110 #endif
111   dlhandle = dlopen(name,dlflags1|dlflags2);
112   if (!dlhandle) {
113 #if defined(PETSC_HAVE_DLERROR)
114     const char *errmsg = dlerror();
115 #else
116     const char *errmsg = "unavailable";
117 #endif
118     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s\n",name,errmsg);
119   }
120 
121   /*
122      --- unimplemented ---
123   */
124 #else
125   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
126 #endif
127 
128   *handle = (PetscDLHandle) dlhandle;
129 
130   PetscFunctionReturn(0);
131 }
132 
133 
134 #undef __FUNCT__
135 #define __FUNCT__ "PetscDLClose"
136 /*@C
137    PetscDLClose -  closes a dynamic library
138 
139    Not Collective
140 
141   Input Parameter:
142 .   handle - the handle for the library obtained with PetscDLOpen()
143 
144   Level: developer
145 @*/
146 PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
147 {
148 
149   PetscFunctionBegin;
150   PetscValidPointer(handle,1);
151 
152   /*
153      --- FreeLibrary ---
154   */
155 #if defined(PETSC_HAVE_WINDOWS_H)
156 #if defined(PETSC_HAVE_FREELIBRARY)
157   if (FreeLibrary((dlhandle_t)*handle) == 0) {
158 #if defined(PETSC_HAVE_GETLASTERROR)
159     char  *buff = NULL;
160     DWORD erc   = GetLastError();
161     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
162 		  NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
163     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
164     LocalFree(buff);
165 #else
166     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","unavailable");
167 #endif
168   }
169 #endif /* !PETSC_HAVE_FREELIBRARY */
170 
171   /*
172      --- dclose ---
173   */
174 #elif defined(PETSC_HAVE_DLFCN_H)
175 #if defined(PETSC_HAVE_DLCLOSE)
176 #if defined(PETSC_HAVE_DLERROR)
177   dlerror(); /* clear any previous error */
178 #endif
179   if (dlclose((dlhandle_t)*handle) < 0) {
180 #if defined(PETSC_HAVE_DLERROR)
181     const char *errmsg = dlerror();
182 #else
183     const char *errmsg = "unavailable";
184 #endif
185     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", errmsg);
186   }
187 #endif /* !PETSC_HAVE_DLCLOSE */
188 
189   /*
190      --- unimplemented ---
191   */
192 #else
193   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
194 #endif
195 
196   *handle = PETSC_NULL;
197 
198   PetscFunctionReturn(0);
199 }
200 
201 #undef __FUNCT__
202 #define __FUNCT__ "PetscDLSym"
203 /*@C
204    PetscDLSym - finds a symbol in a dynamic library
205 
206    Not Collective
207 
208    Input Parameters:
209 +   handle - obtained with PetscDLOpen() or PETSC_NULL
210 -   symbol - name of symbol
211 
212    Output Parameter:
213 .   value - pointer to the function
214 
215    Level: developer
216 
217   Notes:
218    If handle is PETSC_NULL, the symbol is looked for in the main executable's dynamic symbol table.
219    In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
220    systems this requires platform-specific linker flags.
221 
222 @*/
223 PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
224 {
225   PETSC_UNUSED dlhandle_t dlhandle;
226   dlsymbol_t              dlsymbol;
227 
228   PetscValidCharPointer(symbol,2);
229   PetscValidPointer(value,3);
230 
231   dlhandle = (dlhandle_t) 0;
232   dlsymbol = (dlsymbol_t) 0;
233 
234   *value   = (void *) 0;
235 
236   /*
237      --- GetProcAddress ---
238   */
239 #if defined(PETSC_HAVE_WINDOWS_H)
240 #if defined(PETSC_HAVE_GETPROCADDRESS)
241   if (handle)
242     dlhandle = (dlhandle_t) handle;
243   else
244     dlhandle = (dlhandle_t) GetCurrentProcess();
245   dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol);
246 #if defined(PETSC_HAVE_SETLASTERROR)
247   SetLastError((DWORD)0); /* clear any previous error */
248 #endif
249 #endif /* !PETSC_HAVE_GETPROCADDRESS */
250 
251   /*
252      --- dlsym ---
253   */
254 #elif defined(PETSC_HAVE_DLFCN_H)
255 #if defined(PETSC_HAVE_DLSYM)
256   if (handle) {
257     dlhandle = (dlhandle_t) handle;
258   } else {
259 
260 
261 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
262     /* Attempt to retrieve the main executable's dlhandle. */
263     { int dlflags1 = 0, dlflags2 = 0;
264 #if defined(PETSC_HAVE_RTLD_LAZY)
265       dlflags1 = RTLD_LAZY;
266 #endif
267       if (!dlflags1) {
268 #if defined(PETSC_HAVE_RTLD_NOW)
269         dlflags1 = RTLD_NOW;
270 #endif
271       }
272 #if defined(PETSC_HAVE_RTLD_LOCAL)
273       dlflags2 = RTLD_LOCAL;
274 #endif
275       if (!dlflags2) {
276 #if defined(PETSC_HAVE_RTLD_GLOBAL)
277         dlflags2 = RTLD_GLOBAL;
278 #endif
279       }
280 #if defined(PETSC_HAVE_DLERROR)
281       if (!(PETSC_RUNNING_ON_VALGRIND)) {
282         dlerror(); /* clear any previous error; valgrind does not like this */
283       }
284 #endif
285       /* Attempt to open the main executable as a dynamic library. */
286 #if defined(PETSC_HAVE_RTDL_DEFAULT)
287       dlhandle = RTLD_DEFAULT;
288 #else
289       dlhandle = dlopen(0, dlflags1|dlflags2);
290 #if defined(PETSC_HAVE_DLERROR)
291       { const char *e = (const char*) dlerror();
292         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);
293       }
294 #endif
295 #endif
296     }
297 #endif
298 #endif /* PETSC_HAVE_DLOPEN && PETSC_USE_DYNAMIC_LIBRARIES */
299   }
300 #if defined(PETSC_HAVE_DLERROR)
301   dlerror(); /* clear any previous error */
302 #endif
303   dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol);
304   /*
305      --- unimplemented ---
306   */
307 #else
308   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
309 #endif
310 
311   *value = *((void**)&dlsymbol);
312 
313 #if defined(PETSC_SERIALIZE_FUNCTIONS)
314   if (*value) {
315     PetscErrorCode ierr;
316     ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr);
317   }
318 #endif
319   return(0);
320 }
321