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 modulederelict.util.sharedlib;
29 30 importstd..string;
31 32 importderelict.util.exception,
33 derelict.util.system;
34 35 aliasvoid* SharedLibHandle;
36 37 staticif(Derelict_OS_Posix) {
38 importcore.sys.posix.dlfcn;
39 40 enumLDFlags41 {
42 rtldLocal = RTLD_LOCAL,
43 rtldLazy = RTLD_LAZY,
44 rtldNow = RTLD_NOW,
45 rtldGlobal = RTLD_GLOBAL,
46 }
47 48 voidderelictLDFlags(LDFlagsflags) { ldFlags = flags; }
49 50 private {
51 LDFlagsldFlags = LDFlags.rtldNow;
52 53 SharedLibHandleLoadSharedLib(stringlibName)
54 {
55 returndlopen(libName.toStringz(), ldFlags);
56 }
57 58 voidUnloadSharedLib(SharedLibHandlehlib)
59 {
60 dlclose(hlib);
61 }
62 63 void* GetSymbol(SharedLibHandlehlib, stringsymbolName)
64 {
65 returndlsym(hlib, symbolName.toStringz());
66 }
67 68 stringGetErrorStr()
69 {
70 importstd.conv : to;
71 72 autoerr = dlerror();
73 if(errisnull)
74 return"Uknown Error";
75 76 returnto!string(err);
77 }
78 }
79 } elsestaticif(Derelict_OS_Windows) {
80 importcore.sys.windows.windows;
81 82 private {
83 SharedLibHandleLoadSharedLib(stringlibName)
84 {
85 returnLoadLibraryA(libName.toStringz());
86 }
87 88 voidUnloadSharedLib(SharedLibHandlehlib)
89 {
90 FreeLibrary(hlib);
91 }
92 93 void* GetSymbol(SharedLibHandlehlib, stringsymbolName)
94 {
95 returnGetProcAddress(hlib, symbolName.toStringz());
96 }
97 98 stringGetErrorStr()
99 {
100 importstd.windows.syserror;
101 returnsysErrorString(GetLastError());
102 }
103 }
104 } else {
105 staticassert(0, "Derelict does not support this platform.");
106 }
107 108 /++
109 Low-level wrapper of the even lower-level operating-specific shared library
110 loading interface.
111 112 While this interface can be used directly in applications, it is recommended
113 to use the interface specified by derelict.util.loader.SharedLibLoader
114 to implement bindings. SharedLib is designed to be the base of a higher-level
115 loader, but can be used in a program if only a handful of functions need to
116 be loaded from a given shared library.
117 +/118 structSharedLib119 {
120 /++
121 Finds and loads a shared library, using names to find the library
122 on the file system.
123 124 If multiple library names are specified in names, a SharedLibLoadException
125 will only be thrown if all of the libraries fail to load. It will be the head
126 of an exceptin chain containing one instance of the exception for each library
127 that failed.
128 129 130 Params:
131 names = An array containing one or more shared library names,
132 with one name per index.
133 Throws: SharedLibLoadException if the shared library or one of its
134 dependencies cannot be found on the file system.
135 SymbolLoadException if an expected symbol is missing from the
136 library.
137 +/138 voidload(string[] names)
139 {
140 if(isLoaded)
141 return;
142 143 string[] failedLibs;
144 string[] reasons;
145 146 foreach(n; names) {
147 _hlib = LoadSharedLib(n);
148 if(_hlib !isnull) {
149 _name = n;
150 break;
151 }
152 153 failedLibs ~= n;
154 reasons ~= GetErrorStr();
155 }
156 157 if(!isLoaded) {
158 SharedLibLoadException.throwNew(failedLibs, reasons);
159 }
160 }
161 162 /++
163 Loads the symbol specified by symbolName from a shared library.
164 165 Params:
166 symbolName = The name of the symbol to load.
167 doThrow = If true, a SymbolLoadException will be thrown if the symbol
168 is missing. If false, no exception will be thrown and the
169 ptr parameter will be set to null.
170 Throws: SymbolLoadException if doThrow is true and a the symbol
171 specified by funcName is missing from the shared library.
172 +/173 void* loadSymbol(stringsymbolName, booldoThrow = true)
174 {
175 void* sym = GetSymbol(_hlib, symbolName);
176 if(doThrow && !sym) {
177 autoresult = ShouldThrow.Yes;
178 if(_onMissingSym !isnull)
179 result = _onMissingSym(symbolName);
180 if(result == ShouldThrow.Yes)
181 thrownewSymbolLoadException(_name, symbolName);
182 }
183 184 returnsym;
185 }
186 187 /++
188 Unloads the shared library from memory, invalidating all function pointers
189 which were assigned a symbol by one of the load methods.
190 +/191 voidunload()
192 {
193 if(isLoaded) {
194 UnloadSharedLib(_hlib);
195 _hlib = null;
196 }
197 }
198 199 200 /// Returns the name of the shared library.201 @property @nogcnothrow202 stringname() { return_name; }
203 204 /// Returns true if the shared library is currently loaded, false otherwise.205 @property @nogcnothrow206 boolisLoaded() { return (_hlib !isnull); }
207 208 /++
209 Sets the callback that will be called when an expected symbol is
210 missing from the shared library.
211 212 Params:
213 callback = A delegate that returns a value of type
214 derelict.util.exception.ShouldThrow and accepts
215 a string as the sole parameter.
216 +/217 @property @nogcnothrow218 voidmissingSymbolCallback(MissingSymbolCallbackDgcallback)
219 {
220 _onMissingSym = callback;
221 }
222 223 /++
224 Sets the callback that will be called when an expected symbol is
225 missing from the shared library.
226 227 Params:
228 callback = A pointer to a function that returns a value of type
229 derelict.util.exception.ShouldThrow and accepts
230 a string as the sole parameter.
231 +/232 @property @nogcnothrow233 voidmissingSymbolCallback(MissingSymbolCallbackFunccallback)
234 {
235 importstd.functional : toDelegate;
236 _onMissingSym = toDelegate(callback);
237 }
238 239 /++
240 Returns the currently active missing symbol callback.
241 242 This exists primarily as a means to save the current callback before
243 setting a new one. It's useful, for example, if the new callback needs
244 to delegate to the old one.
245 +/246 @property @nogcnothrow247 MissingSymbolCallbackmissingSymbolCallback() { return_onMissingSym; }
248 249 private:
250 string_name;
251 SharedLibHandle_hlib;
252 privateMissingSymbolCallbackDg_onMissingSym;
253 }