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