1 2 module ws.sys.library; 3 4 import 5 std.string, 6 std.conv, 7 std.traits, 8 ws.log; 9 10 version(Windows) import derelict.util.wintypes; 11 version(Posix) import core.sys.posix.dlfcn; 12 13 14 string embedFunc(string n, string t)(){ 15 return t ~ ' ' ~ n ~ ";\n"; 16 } 17 18 string embedFunc(string n, T)(){ 19 return fullyQualifiedName!T ~ ' ' ~ n ~ ";\n"; 20 } 21 22 string getFunc()(){ 23 return ""; 24 } 25 26 string getFunc(string n, T, More...)(){ 27 return embedFunc!(n, T)() ~ getFunc!More(); 28 //return t ~ ' ' ~ n ~ ";\n" ~ getFunc!More(); 29 } 30 31 string getFunc(string n, string t, More...)(){ 32 return embedFunc!(n, t)() ~ getFunc!More(); 33 } 34 35 string loadFunc(string f)(){ 36 return f ~ " = cast(typeof(" ~ f ~ "))l.get(\"" ~ f ~ "\");"; 37 } 38 39 40 bool compiles(string c)(){ 41 mixin("return __traits(compiles, " ~ c ~ ");"); 42 } 43 44 45 Library fillLibrary(alias Fillable)(string path){ 46 auto library = new Library(path); 47 foreach(member; __traits(allMembers, Fillable)){ 48 mixin("enum compiles = __traits(compiles, Fillable."~member~" !is null);"); 49 static if(compiles){ 50 mixin("enum isFP = isFunctionPointer!(Fillable." ~ member ~ ");"); 51 static if(isFP){ 52 mixin("assert(!hasUnsharedAliasing!(typeof(Fillable." ~ member ~ ")));"); 53 mixin("Fillable." ~ member ~ " = cast(typeof(Fillable." ~ member ~ "))library.get(member);"); 54 mixin("assert(Fillable." ~ member ~ " != null);"); 55 } 56 } 57 } 58 return library; 59 } 60 61 62 mixin template library(string refname, string name, Args...){ 63 64 mixin(" 65 struct " ~ refname ~ " { 66 import ws.log; 67 __gshared Library lib; 68 shared static this(){ 69 try 70 lib = load(); 71 catch(Exception e){ 72 ws.log.Log.error(e.toString()); 73 throw e; 74 } 75 } 76 static Library load(){ 77 Library l = new Library(\"" ~ name ~ "\"); 78 loadFuncs!Args(l); 79 return l; 80 } 81 } 82 "); 83 84 void loadFuncs(string f, More...)(Library l){ 85 mixin(loadFunc!(f)()); 86 static if(More.length >= 2) 87 loadFuncs!(More[1..$])(l); 88 } 89 90 // put last due to possible override 91 mixin(getFunc!Args()); 92 93 } 94 95 class Library { 96 97 void* get(string s){ 98 void* p = null; 99 version(Windows) 100 p = GetProcAddress(lib, s.toStringz()); 101 version(Posix) 102 p = dlsym(lib, s.toStringz); 103 if(!p) 104 throw new Exception("Failed to load symbol \"" ~ s ~ "\": " ~ getError()); 105 return p; 106 } 107 108 109 T call(T, string name, Args...)(Args args){ 110 alias T function(Args) FT; 111 static FT func; 112 if(!func) 113 func = cast(FT)get(name); 114 return func(args); 115 } 116 117 118 this(string s, string vers = ""){ 119 version(Windows) 120 lib = LoadLibraryA(s.toStringz()); 121 version(Posix) 122 lib = dlopen(("lib" ~ s ~ ".so" ~ vers).toStringz(), RTLD_NOW); 123 if(!lib) 124 throw new Exception("Failed to load library \"" ~ s ~ "\": " ~ getError()); 125 } 126 127 128 ~this(){ 129 version(Windows) 130 FreeLibrary(lib); 131 version(Posix) 132 dlclose(lib); 133 } 134 135 version(Windows) private HMODULE lib; 136 version(Posix) private void* lib; 137 138 private string getError(){ 139 version(Windows){ 140 DWORD errcode = GetLastError(); 141 LPCSTR msgBuf; 142 DWORD i = FormatMessageA( 143 FORMAT_MESSAGE_ALLOCATE_BUFFER | 144 FORMAT_MESSAGE_FROM_SYSTEM | 145 FORMAT_MESSAGE_IGNORE_INSERTS, 146 null, 147 errcode, 148 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 149 cast(LPCSTR)&msgBuf, 150 0, 151 null); 152 string text = to!string(msgBuf); 153 LocalFree(cast(HLOCAL)msgBuf); 154 if(i >= 2) 155 i -= 2; 156 return text[0 .. i] ~ " (%s)".format(errcode); 157 }version(Posix){ 158 auto err = dlerror(); 159 if(!err) 160 return "Unknown Error"; 161 return to!string(err); 162 } 163 } 164 } 165 166 167 class AutoLibrary { 168 169 protected { 170 Library lib; 171 string prefix; 172 173 } 174 175 this(string name, string prefix){ 176 this.prefix = prefix; 177 lib = new Library(name); 178 } 179 180 181 182 } 183