1 /*
2 
3 Boost Software License - Version 1.0 - August 17th, 2003
4 
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 
27 */
28 module derelict.util.sharedlib;
29 
30 private
31 {
32     import derelict.util.exception;
33     import derelict.util.compat;
34 }
35 
36 version(linux)
37 {
38     version = Nix;
39 }
40 else version(darwin)
41 {
42     version = Nix;
43 }
44 else version(OSX)
45 {
46     version = Nix;
47 }
48 else version(FreeBSD)
49 {
50     version = Nix;
51     version = freebsd;
52 }
53 else version(freebsd)
54 {
55     version = Nix;
56 }
57 else version(Unix)
58 {
59     version = Nix;
60 }
61 else version(Posix)
62 {
63     version = Nix;
64 }
65 
66 version(Nix)
67 {
68     // for people using DSSS, tell it to link the executable with libdl
69     version(build)
70     {
71         version(freebsd)
72         {
73             // the dl* functions are in libc on FreeBSD
74         }
75         else pragma(link, "dl");
76     }
77 
78     version(Tango)
79     {
80         private import tango.sys.Common;
81     }
82     else version(linux)
83     {
84         private import std.c.linux.linux;
85     }
86     else
87     {
88         extern(C)
89         {
90             /* From <dlfcn.h>
91             *  See http://www.opengroup.org/onlinepubs/007908799/xsh/dlsym.html
92             */
93 
94             const int RTLD_NOW = 2;
95 
96             void *dlopen(CCPTR file, int mode);
97             int dlclose(void* handle);
98             void *dlsym(void* handle, CCPTR name);
99             CCPTR dlerror();
100         }
101     }
102 
103     alias void* SharedLibHandle;
104 
105     private SharedLibHandle LoadSharedLib(string libName)
106     {
107         return dlopen(toCString(libName), RTLD_NOW);
108     }
109 
110     private void UnloadSharedLib(SharedLibHandle hlib)
111     {
112         dlclose(hlib);
113     }
114 
115     private void* GetSymbol(SharedLibHandle hlib, string symbolName)
116     {
117         return dlsym(hlib, toCString(symbolName));
118     }
119 
120     private string GetErrorStr()
121     {
122         CCPTR err = dlerror();
123         if(err is null)
124             return "Uknown Error";
125 
126         return toDString(err);
127     }
128 
129 }
130 else version(Windows)
131 {
132     private import derelict.util.wintypes;
133     alias HMODULE SharedLibHandle;
134 
135     private SharedLibHandle LoadSharedLib(string libName)
136     {
137         return LoadLibraryA(toCString(libName));
138     }
139 
140     private void UnloadSharedLib(SharedLibHandle hlib)
141     {
142         FreeLibrary(hlib);
143     }
144 
145     private void* GetSymbol(SharedLibHandle hlib, string symbolName)
146     {
147         return GetProcAddress(hlib, toCString(symbolName));
148     }
149 
150     private string GetErrorStr()
151     {
152         // adapted from Tango
153 
154         DWORD errcode = GetLastError();
155 
156         LPCSTR msgBuf;
157         DWORD i = FormatMessageA(
158             FORMAT_MESSAGE_ALLOCATE_BUFFER |
159             FORMAT_MESSAGE_FROM_SYSTEM |
160             FORMAT_MESSAGE_IGNORE_INSERTS,
161             null,
162             errcode,
163             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
164             cast(LPCSTR)&msgBuf,
165             0,
166             null);
167 
168         string text = toDString(msgBuf);
169         LocalFree(cast(HLOCAL)msgBuf);
170 
171         if(i >= 2)
172             i -= 2;
173         return text[0 .. i];
174     }
175 }
176 else
177 {
178     static assert(0, "Derelict does not support this platform.");
179 }
180 
181 final class SharedLib
182 {
183 public:
184     this()
185     {
186     }
187 
188     string name()
189     {
190         return _name;
191     }
192 
193     bool isLoaded()
194     {
195         return (_hlib !is null);
196     }
197 
198     void load(string[] names)
199     {
200         if(isLoaded)
201             return;
202 
203         string[] failedLibs;
204         string[] reasons;
205 
206         foreach(n; names)
207         {
208             _hlib = LoadSharedLib(n);
209             if(_hlib !is null)
210             {
211                 _name = n;
212                 break;
213             }
214 
215             failedLibs ~= n;
216             reasons ~= GetErrorStr();
217         }
218 
219         if(!isLoaded)
220         {
221             SharedLibLoadException.throwNew(failedLibs, reasons);
222         }
223     }
224 
225     void* loadSymbol(string symbolName, bool doThrow = true)
226     {
227         void* sym = GetSymbol(_hlib, symbolName);
228         if(doThrow && (sym is null))
229             Derelict_HandleMissingSymbol(name, symbolName);
230 
231         return sym;
232     }
233 
234     void unload()
235     {
236         if(isLoaded)
237         {
238             UnloadSharedLib(_hlib);
239             _hlib = null;
240         }
241     }
242 
243 private:
244     string _name;
245     SharedLibHandle _hlib;
246 }