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 /// Shared library ressource
21 struct SharedLib
22 {
23 nothrow:
24 @nogc:
25 
26     void load(string name)
27     {
28         version(debugSharedLibs)
29         {
30             auto lib = CString(name);
31             printf("loading dynlib '%s'\n", lib.storage);
32         }
33 
34         if(isLoaded)
35             return;
36         _name = name;
37         _hlib = LoadSharedLib(name);
38         if(_hlib is null)
39             assert(false, "Couldn't open the shared library.");
40     }
41 
42     @disable this(this);
43 
44     bool hasSymbol(string symbolName)
45     {
46         assert(isLoaded());
47         void* sym = GetSymbol(_hlib, symbolName);
48         return sym != null;
49     }
50 
51     void* loadSymbol(string symbolName)
52     {
53         assert(isLoaded());
54 
55         version(debugSharedLibs)
56         {
57             auto sb = CString(symbolName);
58             printf("  loading symbol '%s'\n", sb.storage);
59         }
60 
61         void* sym = GetSymbol(_hlib, symbolName);
62         if(!sym)
63             assert(false, "Couldn't get symbol.");
64         return sym;
65     }
66 
67     void unload()
68     {
69         if(isLoaded())
70         {
71             UnloadSharedLib(_hlib);
72             _hlib = null;
73 
74             version(debugSharedLibs)
75             {
76                 auto lib = CString(_name);
77                 printf("unloaded dynlib '%s'\n", lib.storage);
78             }
79         }
80     }
81 
82     /// Returns true if the shared library is currently loaded, false otherwise.
83     bool isLoaded()
84     {
85         return (_hlib !is null);
86     }
87 
88 private:
89     string _name;
90     SharedLibHandle _hlib;
91 }
92 
93 /// Loader. In debug mode, this fills functions pointers with null.
94 abstract class SharedLibLoader
95 {
96 nothrow:
97 @nogc:
98 
99     this(string libName)
100     {
101         _libName = libName;
102         version(debugSharedLibs)
103         {
104             _funcPointers = makeAlignedBuffer!(void**)();
105         }
106     }
107 
108     /// Binds a function pointer to a symbol in this loader's shared library.
109     final void bindFunc(void** ptr, string funcName)
110     {
111         void* func = _lib.loadSymbol(funcName);
112         version(debugSharedLibs)
113         {
114             _funcPointers.pushBack(ptr);
115         }
116         *ptr = func;
117     }
118 
119     final void load()
120     {
121         _lib.load(_libName);
122         loadSymbols();
123     }
124 
125     // Unload the library, and sets all functions pointer to null.
126     final void unload()
127     {
128         _lib.unload();
129 
130         version(debugSharedLibs)
131         {
132             // Sets all registered functions pointers to null
133             // so that they can't be reused
134             foreach(ptr; _funcPointers[])
135                 *ptr = null;
136 
137             _funcPointers.clearContents();
138         }
139     }
140 
141 protected:
142 
143     /// Implemented by subclasses to load all symbols with `bindFunc`.
144     abstract void loadSymbols();
145 
146 private:
147     string _libName;
148     SharedLib _lib;
149     version(debugSharedLibs)
150         Vec!(void**) _funcPointers;
151 }
152 
153 
154 private:
155 
156 alias void* SharedLibHandle;
157 
158 version(Posix)
159 {
160     import core.sys.posix.dlfcn;
161 
162     private {
163 
164         SharedLibHandle LoadSharedLib(string libName) nothrow @nogc
165         {
166             return dlopen(CString(libName), RTLD_NOW);
167         }
168 
169         void UnloadSharedLib(SharedLibHandle hlib) nothrow @nogc
170         {
171             dlclose(hlib);
172         }
173 
174         void* GetSymbol(SharedLibHandle hlib, string symbolName) nothrow @nogc
175         {
176             return dlsym(hlib, CString(symbolName));
177         }
178     }
179 }
180 else version(Windows)
181 {
182     import core.sys.windows.windows;
183 
184     private {
185         nothrow @nogc
186         SharedLibHandle LoadSharedLib(string libName)
187         {
188             return LoadLibraryA(CString(libName));
189         }
190 
191         nothrow @nogc
192         void UnloadSharedLib(SharedLibHandle hlib)
193         {
194             FreeLibrary(hlib);
195         }
196 
197         nothrow @nogc
198         void* GetSymbol(SharedLibHandle hlib, string symbolName)
199         {
200             return GetProcAddress(hlib, CString(symbolName));
201         }
202     }
203 } else {
204     static assert(0, "Derelict does not support this platform.");
205 }