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

Revision 292, 9.4 kB (checked in by aldacron, 7 months ago)

[DerelictUtil?]
* added a pragma for DSSS to link in libdl automatically on Linux/Mac.

Line 
1 /*
2  * Copyright (c) 2004-2007 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
53 version (Nix)
54 {
55     // for people using DSSS, tell it to link the executable with libdl
56     version(build)
57     {
58         pragma(link, "dl");
59     }
60 }
61
62
63 private alias void* SharedLibHandle;
64
65 //==============================================================================
66 class SharedLib
67 {
68 public:
69     char[] name()
70     {
71         return _name;
72     }
73
74 private:
75     SharedLibHandle _handle;
76     char[] _name;
77
78     this(SharedLibHandle handle, char[] name)
79     {
80         _handle = handle;
81         _name = name;
82     }
83 }
84 //==============================================================================
85 SharedLib Derelict_LoadSharedLib(char[] libName)
86 in
87 {
88     assert(libName !is null);
89 }
90 body
91 {
92     return Platform_LoadSharedLib(libName);
93 }
94
95 //==============================================================================
96 SharedLib Derelict_LoadSharedLib(char[][] libNames)
97 in
98 {
99     assert(libNames !is null);
100 }
101 body
102 {
103     SharedLibLoadException exception = null;
104     SharedLib lib = null;
105
106     foreach(char[] libName; libNames)
107     {
108         try
109         {
110             lib = Derelict_LoadSharedLib(libName);
111             if(lib !is null) break;
112         }
113         catch(SharedLibLoadException slle)
114         {
115             exception = slle;
116         }
117     }
118     if(lib is null)
119         throw exception;
120
121     return lib;
122 }
123
124 //==============================================================================
125 void Derelict_UnloadSharedLib(SharedLib lib)
126 {
127     if(lib !is null && lib._handle !is null)
128         Platform_UnloadSharedLib(lib);
129 }
130 //==============================================================================
131 void* Derelict_GetProc(SharedLib lib, char[] procName)
132 in
133 {
134     assert(lib !is null);
135     assert(procName !is null);
136 }
137 body
138 {
139     if(lib._handle is null)
140         throw new InvalidSharedLibHandleException(lib._name);
141     return Platform_GetProc(lib, procName);
142 }
143 //==============================================================================
144 version(Windows)
145 {
146     private import derelict.util.wintypes;
147
148     SharedLib Platform_LoadSharedLib(char[] libName)
149     {
150         HMODULE hlib = LoadLibraryA(toCString(libName));
151         if(null is hlib)
152             throw new SharedLibLoadException(libName);
153
154         return new SharedLib(hlib, libName);
155     }
156
157     void Platform_UnloadSharedLib(SharedLib lib)
158     {
159         FreeLibrary(cast(HMODULE)lib._handle);
160         lib._handle = null;
161     }
162
163     void* Platform_GetProc(SharedLib lib, char[] procName)
164     {
165         void* proc = GetProcAddress(cast(HMODULE)lib._handle, toCString(procName));
166         if(null is proc)
167             Derelict_HandleMissingProc(lib._name, procName);
168
169         return proc;
170     }
171
172 }
173 else version(Nix)
174 {
175     version(Tango)
176     {
177         private import tango.sys.Common;
178     }
179     else version(linux)
180     {
181         private import std.c.linux.linux;
182     }
183     else
184     {
185         extern(C)
186         {
187             /* From <dlfcn.h>
188             *  See http://www.opengroup.org/onlinepubs/007908799/xsh/dlsym.html
189             */
190
191             const int RTLD_NOW = 2;
192
193             void *dlopen(char* file, int mode);
194             int dlclose(void* handle);
195             void *dlsym(void* handle, char* name);
196             char* dlerror();
197         }
198     }
199
200     SharedLib Platform_LoadSharedLib(char[] libName)
201     {
202         void* hlib = dlopen(toCString(libName), RTLD_NOW);
203         if(null is hlib)
204             throw new SharedLibLoadException("Failed to load shared library " ~ libName);
205
206         return new SharedLib(hlib, libName);
207     }
208
209     void Platform_UnloadSharedLib(SharedLib lib)
210     {
211         dlclose(lib._handle);
212         lib._handle = null;
213     }
214
215     void* Platform_GetProc(SharedLib lib, char[] procName)
216     {
217         void* proc = dlsym(lib._handle, toCString(procName));
218         if(null is proc)
219             Derelict_HandleMissingProc(lib._name, procName);
220
221         return proc;
222     }
223 }
224 else
225 {
226     static assert(0);
227 }
228
229 //==============================================================================
230
231 struct GenericLoader {
232     void setup(char[] winLibs, char[] linLibs, char[] macLibs, void function(SharedLib) userLoad, char[] versionStr = "") {
233         assert (userLoad !is null);
234         this.winLibs = winLibs;
235         this.linLibs = linLibs;
236         this.macLibs = macLibs;
237         this.userLoad = userLoad;
238         this.versionStr = versionStr;
239     }
240
241     void load(char[] libNameString = null)
242     {
243         if (myLib !is null) {
244             return;
245         }
246
247         // make sure the lib will be unloaded at progam termination
248         registeredLoaders ~= this;
249
250
251         if (libNameString is null) {
252             version (Windows) {
253                 libNameString = winLibs;
254             }
255             else version (linux) {
256                 libNameString = linLibs;
257             }
258             else version(darwin) {
259                 libNameString = macLibs;
260             }
261
262             if(libNameString is null || libNameString == "")
263             {
264                 throw new DerelictException("Invalid library name");
265             }
266         }
267
268         char[][] libNames = libNameString.splitStr(",");
269         foreach (inout char[] l; libNames) {
270             l = l.stripWhiteSpace();
271         }
272
273         load(libNames);
274     }
275
276     void load(char[][] libNames)
277     {
278         myLib = Derelict_LoadSharedLib(libNames);
279
280         if(userLoad is null)
281         {
282             // this should never, ever, happen
283             throw new DerelictException("Something is horribly wrong -- internal load function not configured");
284         }
285         userLoad(myLib);
286     }
287
288     char[] versionString()
289     {
290         return versionStr;
291     }
292
293     void unload()
294     {
295         if (myLib !is null) {
296             Derelict_UnloadSharedLib(myLib);
297             myLib = null;
298         }
299     }
300
301     bool loaded()
302     {
303         return (myLib !is null);
304     }
305
306     char[] libName()
307     {
308         return loaded ? myLib.name : null;
309     }
310
311     static ~this()
312     {
313         foreach (x; registeredLoaders) {
314             x.unload();
315         }
316     }
317
318     private {
319         static GenericLoader*[] registeredLoaders;
320
321         SharedLib myLib;
322         char[] winLibs;
323         char[] linLibs;
324         char[] macLibs;
325         char[] versionStr = "";
326
327         void function(SharedLib) userLoad;
328     }
329 }
330
331 //==============================================================================
332
333 struct GenericDependentLoader {
334     void setup(GenericLoader* dependence, void function(SharedLib) userLoad) {
335         assert (dependence !is null);
336         assert (userLoad !is null);
337
338         this.dependence = dependence;
339         this.userLoad = userLoad;
340     }
341
342     void load()
343     {
344         assert (dependence.loaded);
345         userLoad(dependence.myLib);
346     }
347
348     char[] versionString()
349     {
350         return dependence.versionString;
351     }
352
353     void unload()
354     {
355     }
356
357     bool loaded()
358     {
359         return dependence.loaded;
360     }
361
362     char[] libName()
363     {
364         return dependence.libName;
365     }
366
367     private {
368         GenericLoader*              dependence;
369         void function(SharedLib)    userLoad;
370     }
371 }
372
373 //==============================================================================
374
375 package struct Binder(T) {
376     void opCall(char[] n, SharedLib lib) {
377         *fptr = Derelict_GetProc(lib, n);
378     }
379
380
381     private {
382         void** fptr;
383     }
384 }
385
386
387 template bindFunc(T) {
388     Binder!(T) bindFunc(inout T a) {
389         Binder!(T) res;
390         res.fptr = cast(void**)&a;
391         return res;
392     }
393 }
Note: See TracBrowser for help on using the browser.