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 mixin((is(ReturnType!__self_function__ == void) ? "" : "return ") ~ 78 apiFunctionPointerName!(__traits(identifier, __self_function__)) ~ 79 "(" ~ commaSeparated!([ParameterIdentifierTuple!__self_function__]) ~ ");"); 80 }; 81 82 enum LoadApiSymbolsVerbose 83 { 84 none, 85 message, 86 assertion 87 } 88 89 mixin template SSLL_INIT() 90 { 91 alias apiFuncs = funcsByUDA!(__traits(parent, loadApiSymbols), ApiUDA); 92 93 void loadApiSymbols(LoadApiSymbolsVerbose verbose=LoadApiSymbolsVerbose.none) 94 { 95 version (Posix) 96 { 97 import core.sys.posix.dlfcn : dlsym; 98 alias getSymbol = dlsym; 99 } 100 version (Windows) 101 { 102 import core.sys.windows.windows : GetProcAddress; 103 alias getSymbol = GetProcAddress; 104 } 105 106 foreach (f; apiFuncs) 107 { 108 enum libname = getUDAs!(f, ApiUDA)[$-1].libname; 109 enum fname = __traits(identifier, f) ~ '\0'; 110 enum pname = apiFunctionPointerName!(fname[0..$-1]); 111 mixin(pname ~ " = cast(typeof(" ~ pname ~ "))getSymbol(" 112 ~ libname ~ ", fname.ptr);"); 113 if (mixin(pname ~ " is null")) 114 { 115 with (LoadApiSymbolsVerbose) final switch (verbose) 116 { 117 case none: break; 118 case message: 119 import core.stdc.stdio : printf; 120 printf("can't find '%s' function\n", fname.ptr); 121 break; 122 case assertion: assert(0, fname[0..$-1]); 123 } 124 } 125 } 126 } 127 128 mixin funcPointers!apiFuncs; 129 } 130 131 template apiFunctionPointerName(string f) 132 { enum apiFunctionPointerName = "__" ~ f ~"_fnc_ptr"; } 133 134 template funcsByUDA(alias symbol, uda) 135 { 136 template impl(lst...) 137 { 138 static if (lst.length == 1) 139 { 140 static if (is(typeof(__traits(getMember, symbol, lst[0])) == function)) 141 { 142 alias ff = AliasSeq!(__traits(getMember, symbol, lst[0]))[0]; 143 static if (hasUDA!(ff, uda)) alias impl = AliasSeq!(ff); 144 else alias impl = AliasSeq!(); 145 } 146 else alias impl = AliasSeq!(); 147 } 148 else alias impl = AliasSeq!(impl!(lst[0..$/2]), impl!(lst[$/2..$])); 149 } 150 151 alias funcsByUDA = impl!(__traits(allMembers, symbol)); 152 } 153 154 mixin template funcPointers(funcs...) 155 { 156 static if (funcs.length == 0) {} 157 else static if (funcs.length == 1) 158 { 159 alias __this = funcs[0]; 160 mixin(`private __gshared extern(C) @nogc nothrow ReturnType!__this function(Parameters!__this) ` ~ 161 apiFunctionPointerName!(__traits(identifier, __this)) ~ `;`); 162 } 163 else 164 { 165 mixin funcPointers!(funcs[0..$/2]); 166 mixin funcPointers!(funcs[$/2..$]); 167 } 168 }