1 /**
2 Loading and unloading shared libraries.
3
4 Copyright: Derelict Contributors 2005-2015.
5 Copyright: Guillaume Piolat 2015-2016.
6 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 */
8 module dplug.core.sharedlib;
9
10 import dplug.core.nogc;
11 import dplug.core.vec;
12
13 //version = debugSharedLibs;
14
15 version(debugSharedLibs)
16 {
17 import core.stdc.stdio;
18 }
19
20 alias void* SharedLibHandle;
21
22 /// Shared library ressource
23 struct SharedLib
24 {
25 nothrow:
26 @nogc:
27
28 void load(string name)
29 {
30 version(debugSharedLibs)
31 {
32 auto lib = CString(name);
33 printf("loading dynlib '%s'\n", lib.storage);
34 }
35
36 if(isLoaded)
37 return;
38 _name = name;
39 _hlib = LoadSharedLib(name);
40 if(_hlib is null)
41 assert(false, "Couldn't open the shared library.");
42 }
43
44 @disable this(this);
45
46 bool hasSymbol(string symbolName)
47 {
48 assert(isLoaded());
49 void* sym = GetSymbol(_hlib, symbolName);
50 return sym != null;
51 }
52
53 void* loadSymbol(string symbolName)
54 {
55 assert(isLoaded());
56
57 version(debugSharedLibs)
58 {
59 auto sb = CString(symbolName);
60 printf(" loading symbol '%s'\n", sb.storage);
61 }
62
63 void* sym = GetSymbol(_hlib, symbolName);
64 if(!sym)
65 assert(false, "Couldn't get symbol.");
66 return sym;
67 }
68
69 void unload()
70 {
71 if(isLoaded())
72 {
73 UnloadSharedLib(_hlib);
74 _hlib = null;
75
76 version(debugSharedLibs)
77 {
78 auto lib = CString(_name);
79 printf("unloaded dynlib '%s'\n", lib.storage);
80 }
81 }
82 }
83
84 /// Returns true if the shared library is currently loaded, false otherwise.
85 bool isLoaded()
86 {
87 return (_hlib !is null);
88 }
89
90 /// Return the internal shared library handle, this is used to move ownership of such objects.
91 /// Ownership of the underlying shared library is lost.initializeWithHandle
92 SharedLibHandle disown()
93 {
94 SharedLibHandle result = _hlib;
95 _hlib = null;
96 return result;
97 }
98
99 /// Recreate a SharedLib using a `disown()` stored handle. This is used instead of postblit.
100 void initializeWithHandle(SharedLibHandle handle)
101 {
102 assert(_hlib is null);
103 _hlib = handle;
104 _name = null;
105 }
106
107 private:
108 string _name;
109 SharedLibHandle _hlib;
110 }
111
112 /// Loader. In debug mode, this fills functions pointers with null.
113 abstract class SharedLibLoader
114 {
115 nothrow:
116 @nogc:
117
118 this(string libName)
119 {
120 _libName = libName;
121 version(debugSharedLibs)
122 {
123 _funcPointers = makeAlignedBuffer!(void**)();
124 }
125 }
126
127 /// Binds a function pointer to a symbol in this loader's shared library.
128 final void bindFunc(void** ptr, string funcName)
129 {
130 void* func = _lib.loadSymbol(funcName);
131 version(debugSharedLibs)
132 {
133 _funcPointers.pushBack(ptr);
134 }
135 *ptr = func;
136 }
137
138 final void load()
139 {
140 _lib.load(_libName);
141 loadSymbols();
142 }
143
144 // Unload the library, and sets all functions pointer to null.
145 final void unload()
146 {
147 _lib.unload();
148
149 version(debugSharedLibs)
150 {
151 // Sets all registered functions pointers to null
152 // so that they can't be reused
153 foreach(ptr; _funcPointers[])
154 *ptr = null;
155
156 _funcPointers.clearContents();
157 }
158 }
159
160 protected:
161
162 /// Implemented by subclasses to load all symbols with `bindFunc`.
163 abstract void loadSymbols();
164
165 private:
166 string _libName;
167 SharedLib _lib;
168 version(debugSharedLibs)
169 Vec!(void**) _funcPointers;
170 }
171
172
173 private:
174
175
176
177 version(Posix)
178 {
179 import core.sys.posix.dlfcn;
180
181 private {
182
183 SharedLibHandle LoadSharedLib(string libName) nothrow @nogc
184 {
185 return dlopen(CString(libName), RTLD_NOW);
186 }
187
188 void UnloadSharedLib(SharedLibHandle hlib) nothrow @nogc
189 {
190 dlclose(hlib);
191 }
192
193 void* GetSymbol(SharedLibHandle hlib, string symbolName) nothrow @nogc
194 {
195 return dlsym(hlib, CString(symbolName));
196 }
197 }
198 }
199 else version(Windows)
200 {
201 import core.sys.windows.winbase;
202
203 private {
204 nothrow @nogc
205 SharedLibHandle LoadSharedLib(string libName)
206 {
207 return LoadLibraryA(CString(libName));
208 }
209
210 nothrow @nogc
211 void UnloadSharedLib(SharedLibHandle hlib)
212 {
213 FreeLibrary(hlib);
214 }
215
216 nothrow @nogc
217 void* GetSymbol(SharedLibHandle hlib, string symbolName)
218 {
219 return GetProcAddress(hlib, CString(symbolName));
220 }
221 }
222 } else {
223 static assert(0, "Derelict does not support this platform.");
224 }