root/trunk/DerelictUtil/derelict/util/loader.d

Revision 394, 10.3 kB (checked in by doob, 2 years ago)

Missed a version statement for freebsd in loader. Removed the pragma link to libc

Line 
1 /*
2  * Copyright (c) 2004-2009 Derelict Developers
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the names 'Derelict', 'DerelictUtil', nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 module derelict.util.loader;
33
34 private
35 {
36     import derelict.util.exception;
37     import derelict.util.wrapper;
38 }
39
40 version(linux)
41 {
42     version = Nix;
43 }
44 version(darwin)
45 {
46     version = Nix;
47 }
48 else version(Unix)
49 {
50     version = Nix;
51 }
52 else version (FreeBSD)
53 {
54     version = Nix;
55     version = freebsd;
56 }
57 else version (freebsd)
58 {
59     version = Nix;
60 }
61
62 version (Nix)
63 {
64     // for people using DSSS, tell it to link the executable with libdl
65     version(build)
66     {
67         version (freebsd)
68         {
69             // the dl* functions are in libc on freebsd which the compiler links automatically
70         }
71            
72         else
73             pragma(link, "dl");
74     }
75 }
76
77
78 private alias void* SharedLibHandle;
79
80 //==============================================================================
81 class SharedLib
82 {
83 public:
84     char[] name()
85     {
86         return _name;
87     }
88
89 private:
90     SharedLibHandle _handle;
91     char[] _name;
92
93     this(SharedLibHandle handle, char[] name)
94     {
95         _handle = handle;
96         _name = name;
97     }
98 }
99 //==============================================================================
100 SharedLib Derelict_LoadSharedLib(char[] libName)
101 in
102 {
103     assert(libName !is null);
104 }
105 body
106 {
107     SharedLibHandle handle = Platform_LoadSharedLib(libName);
108     if(handle is null)
109         throw new SharedLibLoadException("Failed to load shared lib " ~ libName ~ ": " ~ GetErrorStr());
110     return new SharedLib(handle, libName);
111 }
112
113 //==============================================================================
114 SharedLib Derelict_LoadSharedLib(char[][] libNames)
115 in
116 {
117     assert(libNames !is null);
118 }
119 body
120 {
121     char[][] failedLibs;
122     char[][] reasons;
123
124     foreach(char[] libName; libNames)
125     {
126         SharedLibHandle handle = Platform_LoadSharedLib(libName);
127         if(handle !is null)
128         {
129             return new SharedLib(handle, libName);
130         }
131         else
132         {
133             failedLibs ~= libName;
134             reasons ~= GetErrorStr();
135         }
136
137     }
138     SharedLibLoadException.throwNew(failedLibs, reasons);
139     return null; // to shut the compiler up
140 }
141
142 //==============================================================================
143 void Derelict_UnloadSharedLib(SharedLib lib)
144 {
145     if(lib !is null && lib._handle !is null)
146         Platform_UnloadSharedLib(lib);
147 }
148 //==============================================================================
149 void* Derelict_GetProc(SharedLib lib, char[] procName)
150 in
151 {
152     assert(lib !is null);
153     assert(procName !is null);
154 }
155 body
156 {
157     if(lib._handle is null)
158         throw new InvalidSharedLibHandleException(lib._name);
159     return Platform_GetProc(lib, procName);
160 }
161 //==============================================================================
162 version(Windows)
163 {
164     private import derelict.util.wintypes;
165
166     SharedLibHandle Platform_LoadSharedLib(char[] libName)
167     {
168         return LoadLibraryA(toCString(libName));
169     }
170
171     void Platform_UnloadSharedLib(SharedLib lib)
172     {
173         FreeLibrary(cast(HMODULE)lib._handle);
174         lib._handle = null;
175     }
176
177     void* Platform_GetProc(SharedLib lib, char[] procName)
178     {
179         void* proc = GetProcAddress(cast(HMODULE)lib._handle, toCString(procName));
180         if(null is proc)
181             Derelict_HandleMissingProc(lib._name, procName);
182
183         return proc;
184     }
185
186     private char[] GetErrorStr()
187     {
188         // adapted from Tango
189
190         DWORD errcode = GetLastError();
191
192         LPCSTR msgBuf;
193         DWORD i = FormatMessageA(
194             FORMAT_MESSAGE_ALLOCATE_BUFFER |
195             FORMAT_MESSAGE_FROM_SYSTEM |
196             FORMAT_MESSAGE_IGNORE_INSERTS,
197             null,
198             errcode,
199             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
200             cast(LPCSTR)&msgBuf,
201             0,
202             null);
203
204         char[] text = toDString(msgBuf);
205         LocalFree(cast(HLOCAL)msgBuf);
206
207         if(i >= 2)
208             i -= 2;
209         return text[0 .. i];
210     }
211
212 }
213 else version(Nix)
214 {
215
216     extern(C)
217     {
218         enum
219         {
220             RTLD_NOW = 0x2,
221             RTLD_NOLOAD = 0x10,
222         }
223
224         void *dlopen(char* file, int mode);
225         int dlclose(void* handle);
226         void *dlsym(void* handle, char* name);
227         char* dlerror();
228     }
229
230
231     SharedLibHandle Platform_LoadSharedLib(char[] libName)
232     {
233         return dlopen(toCString(libName), RTLD_NOW);
234     }
235
236     void Platform_UnloadSharedLib(SharedLib lib)
237     {
238         dlclose(lib._handle);
239         lib._handle = null;
240     }
241
242     void* Platform_GetProc(SharedLib lib, char[] procName)
243     {
244         void* proc = dlsym(lib._handle, toCString(procName));
245         if(null is proc)
246             Derelict_HandleMissingProc(lib._name, procName);
247
248         return proc;
249     }
250
251     private char[] GetErrorStr()
252     {
253         char* err = dlerror();
254         if(err is null)
255             return "Uknown Error";
256
257         return toDString(err).dup;
258     }
259 }
260 else
261 {
262     static assert(0);
263 }
264
265 //==============================================================================
266
267 struct GenericLoader {
268     void setup(char[] winLibs, char[] nixLibs, char[] macLibs, void function(SharedLib) userLoad, char[] versionStr = "") {
269         assert (userLoad !is null);
270         this.winLibs = winLibs;
271         this.nixLibs = nixLibs;
272         this.macLibs = macLibs;
273         this.userLoad = userLoad;
274         this.versionStr = versionStr;
275     }
276
277     void load(char[] libNameString = null)
278     {
279         if (myLib !is null) {
280             return;
281         }
282
283         // make sure the lib will be unloaded at progam termination
284         registeredLoaders ~= this;
285
286
287         if (libNameString is null) {
288             version (Windows) {
289                 libNameString = winLibs;
290             }
291             else version (freebsd) {
292                 libNameString = nixLibs;
293             }
294             else version (linux) {
295                 libNameString = nixLibs;
296             }
297             else version(darwin) {
298                 libNameString = macLibs;
299             }
300
301             if(libNameString is null || libNameString == "")
302             {
303                 throw new DerelictException("Invalid library name");
304             }
305         }
306
307         char[][] libNames = libNameString.splitStr(",");
308         foreach (inout char[] l; libNames) {
309             l = l.stripWhiteSpace();
310         }
311
312         load(libNames);
313     }
314
315     void load(char[][] libNames)
316     {
317         myLib = Derelict_LoadSharedLib(libNames);
318
319         if(userLoad is null)
320         {
321             // this should never, ever, happen
322             throw new DerelictException("Something is horribly wrong -- internal load function not configured");
323         }
324         userLoad(myLib);
325     }
326
327     char[] versionString()
328     {
329         return versionStr;
330     }
331
332     void unload()
333     {
334         if (myLib !is null) {
335             Derelict_UnloadSharedLib(myLib);
336             myLib = null;
337         }
338     }
339
340     bool loaded()
341     {
342         return (myLib !is null);
343     }
344
345     char[] libName()
346     {
347         return loaded ? myLib.name : null;
348     }
349
350     static ~this()
351     {
352         foreach (x; registeredLoaders) {
353             x.unload();
354         }
355     }
356
357     private {
358         static GenericLoader*[] registeredLoaders;
359
360         SharedLib myLib;
361         char[] winLibs;
362         char[] nixLibs;
363         char[] macLibs;
364         char[] versionStr = "";
365
366         void function(SharedLib) userLoad;
367     }
368 }
369
370 //==============================================================================
371
372 struct GenericDependentLoader {
373     void setup(GenericLoader* dependence, void function(SharedLib) userLoad) {
374         assert (dependence !is null);
375         assert (userLoad !is null);
376
377         this.dependence = dependence;
378         this.userLoad = userLoad;
379     }
380
381     void load()
382     {
383         assert (dependence.loaded);
384         userLoad(dependence.myLib);
385     }
386
387     char[] versionString()
388     {
389         return dependence.versionString;
390     }
391
392     void unload()
393     {
394     }
395
396     bool loaded()
397     {
398         return dependence.loaded;
399     }
400
401     char[] libName()
402     {
403         return dependence.libName;
404     }
405
406     private {
407         GenericLoader*              dependence;
408         void function(SharedLib)    userLoad;
409     }
410 }
411
412 //==============================================================================
413
414 package struct Binder(T) {
415     void opCall(char[] n, SharedLib lib) {
416         *fptr = Derelict_GetProc(lib, n);
417     }
418
419
420     private {
421         void** fptr;
422     }
423 }
424
425
426 template bindFunc(T) {
427     Binder!(T) bindFunc(inout T a) {
428         Binder!(T) res;
429         res.fptr = cast(void**)&a;
430         return res;
431     }
432 }
Note: See TracBrowser for help on using the browser.