1 /// 2 module ssll; 3 4 import core.stdc.stdlib : free, malloc; 5 import core.stdc.string : memcpy; 6 7 public import std.meta : AliasSeq; 8 public import std.traits : hasUDA, getUDAs, 9 ReturnType, Parameters, ParameterIdentifierTuple; 10 11 version (Posix) 12 { 13 import core.sys.posix.dlfcn : dlopen, dlclose, RTLD_LAZY; 14 15 alias LibHandler = void*; /// 16 } 17 else version (Windows) 18 { 19 import core.sys.windows.winbase : LoadLibraryA, FreeLibrary; 20 import core.sys.windows.windef : HINSTANCE; 21 22 alias LibHandler = HINSTANCE; /// 23 } 24 else static assert(0, "unknown platform"); 25 26 @nogc nothrow extern(C): 27 28 struct ApiUDA { string libname; } 29 30 /// 31 auto api(string lname="lib") @property { return ApiUDA(lname); } 32 33 /// 34 LibHandler loadLibrary(string name) 35 { 36 const ln = name.length; 37 38 if (ln == 0) return null; 39 40 auto buf = cast(char*)malloc(ln+1); 41 if (buf is null) return null; 42 scope (exit) free(buf); 43 44 memcpy(buf, name.ptr, ln); 45 buf[ln] = '\0'; 46 47 version (Posix) return dlopen(buf, RTLD_LAZY); 48 version (Windows) return LoadLibraryA(buf); 49 } 50 51 /// 52 void unloadLibrary(ref LibHandler lib) 53 { 54 version (Posix) dlclose(&lib); 55 version (Windows) FreeLibrary(lib); 56 57 lib = null; 58 } 59 60 /// used in rtLib mixin 61 template commaSeparated(string[] arr) 62 { 63 template r(string[] a) 64 { 65 static if (a.length == 0) enum r = ""; 66 else static if (a.length == 1) enum r = a[0]; 67 else enum r = r!(a[0..$/2]) ~ ", " ~ r!(a[$/2..$]); 68 } 69 70 enum commaSeparated = r!arr; 71 } 72 73 /// 74 enum SSLL_CALL = q{ 75 enum __dimmy_symbol__; 76 alias __self_function__ = AliasSeq!(__traits(parent, __dimmy_symbol__))[0]; 77 enum __self_function_name__ = __traits(identifier, __self_function__); 78 enum __function_pointer_name__ = apiFunctionPointerName!(__self_function_name__); 79 version (ssllCheckLoadingSymbols) 80 if (mixin(__function_pointer_name__ ~ " is null")) 81 assert(0, `function '` ~ __self_function_name__ ~ `' not loaded, call '` 82 ~ __MODULE__ ~ `.loadApiSybols() before`); 83 mixin((is(ReturnType!__self_function__ == void) ? "" : "return ") ~ 84 apiFunctionPointerName!(__traits(identifier, __self_function__)) ~ 85 "(" ~ commaSeparated!([ParameterIdentifierTuple!__self_function__]) ~ ");"); 86 }; 87 88 enum LoadApiSymbolsVerbose 89 { 90 none, 91 message, 92 assertion 93 } 94 95 mixin template SSLL_INIT() 96 { 97 alias apiFuncs = funcsByUDA!(__traits(parent, loadApiSymbols), ApiUDA); 98 99 void loadApiSymbols(LoadApiSymbolsVerbose verbose=LoadApiSymbolsVerbose.none) 100 { 101 version (Posix) 102 { 103 import core.sys.posix.dlfcn : dlsym; 104 alias getSymbol = dlsym; 105 } 106 version (Windows) 107 { 108 import core.sys.windows.windows : GetProcAddress; 109 alias getSymbol = GetProcAddress; 110 } 111 112 foreach (f; apiFuncs) 113 { 114 enum libname = getUDAs!(f, ApiUDA)[$-1].libname; 115 enum fname = __traits(identifier, f) ~ '\0'; 116 enum pname = apiFunctionPointerName!(fname[0..$-1]); 117 mixin(pname ~ " = cast(typeof(" ~ pname ~ "))getSymbol(" 118 ~ libname ~ ", fname.ptr);"); 119 if (mixin(pname ~ " is null")) 120 { 121 with (LoadApiSymbolsVerbose) final switch (verbose) 122 { 123 case none: break; 124 case message: 125 import core.stdc.stdio : printf; 126 printf("can't find '%s' function\n", fname.ptr); 127 break; 128 case assertion: assert(0, fname[0..$-1]); 129 } 130 } 131 } 132 } 133 134 mixin funcPointers!apiFuncs; 135 } 136 137 template apiFunctionPointerName(string f) 138 { enum apiFunctionPointerName = "__" ~ f ~"_fnc_ptr"; } 139 140 template funcsByUDA(alias symbol, uda) 141 { 142 template impl(lst...) 143 { 144 static if (lst.length == 1) 145 { 146 static if (is(typeof(__traits(getMember, symbol, lst[0])) == function)) 147 { 148 alias ff = AliasSeq!(__traits(getMember, symbol, lst[0]))[0]; 149 static if (hasUDA!(ff, uda)) alias impl = AliasSeq!(ff); 150 else alias impl = AliasSeq!(); 151 } 152 else alias impl = AliasSeq!(); 153 } 154 else alias impl = AliasSeq!(impl!(lst[0..$/2]), impl!(lst[$/2..$])); 155 } 156 157 alias funcsByUDA = impl!(__traits(allMembers, symbol)); 158 } 159 160 mixin template funcPointers(funcs...) 161 { 162 static if (funcs.length == 0) {} 163 else static if (funcs.length == 1) 164 { 165 alias __this = funcs[0]; 166 mixin(`private __gshared extern(C) @nogc nothrow ReturnType!__this function(Parameters!__this) ` ~ 167 apiFunctionPointerName!(__traits(identifier, __this)) ~ `;`); 168 } 169 else 170 { 171 mixin funcPointers!(funcs[0..$/2]); 172 mixin funcPointers!(funcs[$/2..$]); 173 } 174 }