1 module dynamic; 2 3 enum SymbolSet { all, skipDeprecated } 4 5 mixin template dynamicBinding(alias mod, SymbolSet symbols = SymbolSet.all) 6 { 7 import core.runtime : Runtime; 8 import std.traits : ReturnType, ParameterTypeTuple, functionLinkage; 9 import std.format : format; 10 11 alias _prototypes = prototypes!(mod, symbols); 12 13 private static string mixins() 14 { 15 string ret; 16 foreach (i, proto; _prototypes) { 17 ret ~= q{ 18 extern(%2$s) alias P_%1$s = ReturnType!(_prototypes[%3$d]) function(ParameterTypeTuple!(_prototypes[%3$d])); 19 P_%1$s p_%1$s; 20 extern(%2$s) ReturnType!(_prototypes[%3$d]) %1$s(ParameterTypeTuple!(_prototypes[%3$d]) params) { 21 assert(p_%1$s !is null, "Function not loaded: %1$s"); 22 return p_%1$s(params); 23 } 24 }.format(__traits(identifier, proto), functionLinkage!proto, i); 25 } 26 return ret; 27 } 28 mixin(mixins()); 29 30 void loadBinding(scope string[] library_files) 31 { 32 import std.conv : to; 33 import std.format : format; 34 import std.utf : toUTF16z; 35 import std..string : toStringz; 36 version (Windows) import core.sys.windows.windows : LoadLibraryW; 37 else import core.sys.posix.dlfcn : dlopen, RTLD_LAZY; 38 39 foreach (f; library_files) { 40 version (Windows) void* lib = LoadLibraryW(f.toUTF16z); 41 else void* lib = dlopen(f.toStringz(), RTLD_LAZY); 42 if (!lib) continue; 43 44 foreach (proto; _prototypes) { 45 mixin(q{ 46 p_%1$s = cast(P_%1$s)loadProc(lib, proto.mangleof); 47 if (!p_%1$s) 48 throw new Exception( 49 format("Failed to load function '%%s' from %1$s", 50 proto.mangleof)); 51 }.format(__traits(identifier, proto))); 52 } 53 return; 54 } 55 56 throw new Exception(format("Failed to load any of the shared library candidates: %(%s, %)", library_files)); 57 } 58 } 59 60 /// private 61 template prototypes(alias mod, SymbolSet symbols) 62 { 63 import std.meta : AliasSeq, staticMap; 64 65 template Overloads(string name) { 66 static if (symbols == SymbolSet.skipDeprecated && isDeprecated!(mod, name)) 67 alias Overloads = AliasSeq!(); 68 else 69 alias Overloads = AliasSeq!(__traits(getOverloads, mod, name)); 70 } 71 alias functions = staticMap!(Overloads, AliasSeq!(__traits(allMembers, mod))); 72 73 /*template impl(size_t idx) { 74 static if (idx < members.length) { 75 alias impl = AliasSeq!(members[i], impl 76 } else alias impl = AliasSeq!(); 77 }*/ 78 alias prototypes = functions; 79 } 80 81 // crude workaround to gag deprecation warnings 82 private enum isDeprecated(alias parent, string symbol) = 83 is(typeof({ 84 static assert(__traits(isDeprecated, __traits(getMember, parent, symbol))); 85 })); 86 87 /// private 88 void* loadProc(void* lib, string name) 89 { 90 import std..string : toStringz; 91 92 version (Windows) { 93 import core.sys.windows.windows; 94 return GetProcAddress(lib, name.toStringz()); 95 } else { 96 import core.sys.posix.dlfcn : dlsym; 97 return dlsym(lib, name.toStringz()); 98 } 99 }