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 }