1 module gfx.bindings.core;
2 
3 // Dynamic bindings facility
4 
5 /// A handle to a shared library
6 alias SharedLib = void*;
7 /// A handle to a shared library symbol
8 alias SharedSym = void*;
9 
10 /// Opens a shared library.
11 /// Return null in case of failure.
12 SharedLib openSharedLib(string name);
13 
14 /// Load a symbol from a shared library.
15 /// Return null in case of failure.
16 SharedSym loadSharedSym(SharedLib lib, string name);
17 
18 /// Close a shared library
19 void closeSharedLib(SharedLib lib);
20 
21 
22 /// Generic Dynamic lib symbol loader.
23 /// Symbols loaded with such loader must be cast to the appropriate function type.
24 alias SymbolLoader = SharedSym delegate (in string name);
25 
26 
27 version(Posix)
28 {
29     import std.string : toStringz;
30     import core.sys.posix.dlfcn;
31 
32     SharedLib openSharedLib(string name)
33     {
34         return dlopen(toStringz(name), RTLD_LAZY);
35     }
36 
37     SharedSym loadSharedSym(SharedLib lib, string name)
38     {
39         return dlsym(lib, toStringz(name));
40     }
41 
42     void closeSharedLib(SharedLib lib)
43     {
44         dlclose(lib);
45     }
46 }
47 version(Windows)
48 {
49     import std.string : toStringz;
50     import core.sys.windows.winbase;
51 
52     SharedLib openSharedLib(string name)
53     {
54         return LoadLibraryA(toStringz(name));
55     }
56 
57     SharedSym loadSharedSym(SharedLib lib, string name)
58     {
59         return GetProcAddress(lib, toStringz(name));
60     }
61 
62     void closeSharedLib(SharedLib lib)
63     {
64         FreeLibrary(lib);
65     }
66 }
67 
68 /// Utility that open a shared library and load symbols from it.
69 class SharedLibLoader
70 {
71     import std.typecons : Flag, Yes, No;
72     private SharedLib _lib;
73     private string _libName;
74 
75     /// Load the shared libraries and call bindSymbols if succesful.
76     void load (string[] libNames)
77     {
78         foreach (ln; libNames)
79         {
80             _lib = openSharedLib(ln);
81             if (_lib)
82             {
83                 _libName = ln;
84                 break;
85             }
86         }
87         if (!_lib)
88         {
89             import std.conv : to;
90             throw new Exception(
91                 "Cannot load one of shared libs " ~ libNames.to!string
92             );
93         }
94         bindSymbols();
95     }
96 
97     /// Direct handle access
98     public @property SharedLib handle()
99     {
100         return _lib;
101     }
102 
103     /// Returns whether the shared library is open.
104     public @property bool loaded() const
105     {
106         return _lib !is null;
107     }
108 
109     /// Returns the name of the shared library that was open.
110     /// Empty string if not loaded.
111     public @property string libName() const
112     {
113         return _libName;
114     }
115 
116     /// Bind a symbol, using the function pointer symbol name.
117     void bind(alias f)(Flag!"optional" optional = No.optional)
118     {
119         immutable name = f.stringof;
120         if (f !is null)
121         {
122             throw new Exception("Tentative to bind already bound symbol "~ name);
123         }
124         auto sym = loadSharedSym(_lib, name);
125         if (!sym && !optional)
126         {
127             throw new Exception("Cannot load symbol "~name~" from "~_libName~".");
128         }
129         f = cast(typeof(f)) sym;
130     }
131 
132     /// Subclasses can override this to bind all the necessary symbols.
133     /// Default implementation does nothing.
134     void bindSymbols()
135     {}
136 }