1 /* ----------------------------------------------------------------------------- 2 * wrapperloader.swg 3 * 4 * Support code for dynamically linking the C wrapper library from the D 5 * wrapper module. 6 * 7 * The loading code was adapted from the Derelict project and is used with 8 * permission from Michael Parker, the original author. 9 * ----------------------------------------------------------------------------- */ 10 11 %pragma(d) wrapperloadercode = %{ 12 private { 13 version(linux) { 14 version = Nix; 15 } else version(darwin) { 16 version = Nix; 17 } else version(OSX) { 18 version = Nix; 19 } else version(FreeBSD) { 20 version = Nix; 21 version = freebsd; 22 } else version(freebsd) { 23 version = Nix; 24 } else version(Unix) { 25 version = Nix; 26 } else version(Posix) { 27 version = Nix; 28 } 29 30 version(Tango) { 31 static import tango.stdc.string; 32 static import tango.stdc.stringz; 33 34 version (PhobosCompatibility) { 35 } else { 36 alias char[] string; 37 alias wchar[] wstring; 38 alias dchar[] dstring; 39 } 40 } else { 41 version(D_Version2) { 42 static import std.conv; 43 } 44 static import std.string; 45 static import std.c.string; 46 } 47 48 version(D_Version2) { 49 mixin("alias const(char)* CCPTR;"); 50 } else { 51 alias char* CCPTR; 52 } 53 54 CCPTR swigToCString(string str) { 55 version(Tango) { 56 return tango.stdc.stringz.toStringz(str); 57 } else { 58 return std.string.toStringz(str); 59 } 60 } 61 62 string swigToDString(CCPTR cstr) { 63 version(Tango) { 64 return tango.stdc.stringz.fromStringz(cstr); 65 } else { 66 version(D_Version2) { 67 mixin("return std.conv.to!string(cstr);"); 68 } else { 69 return std.c.string.toString(cstr); 70 } 71 } 72 } 73 } 74 75 class SwigSwigSharedLibLoadException : Exception { 76 this(in string[] libNames, in string[] reasons) { 77 string msg = "Failed to load one or more shared libraries:"; 78 foreach(i, n; libNames) { 79 msg ~= "\n\t" ~ n ~ " - "; 80 if(i < reasons.length) 81 msg ~= reasons[i]; 82 else 83 msg ~= "Unknown"; 84 } 85 super(msg); 86 } 87 } 88 89 class SwigSymbolLoadException : Exception { 90 this(string SwigSharedLibName, string symbolName) { 91 super("Failed to load symbol " ~ symbolName ~ " from shared library " ~ SwigSharedLibName); 92 _symbolName = symbolName; 93 } 94 95 string symbolName() { 96 return _symbolName; 97 } 98 99 private: 100 string _symbolName; 101 } 102 103 private { 104 version(Nix) { 105 version(freebsd) { 106 // the dl* functions are in libc on FreeBSD 107 } 108 else { 109 pragma(lib, "dl"); 110 } 111 112 version(Tango) { 113 import tango.sys.Common; 114 } else version(linux) { 115 import std.c.linux.linux; 116 } else { 117 extern(C) { 118 const RTLD_NOW = 2; 119 120 void *dlopen(CCPTR file, int mode); 121 int dlclose(void* handle); 122 void *dlsym(void* handle, CCPTR name); 123 CCPTR dlerror(); 124 } 125 } 126 127 alias void* SwigSharedLibHandle; 128 129 SwigSharedLibHandle swigLoadSharedLib(string libName) { 130 return dlopen(swigToCString(libName), RTLD_NOW); 131 } 132 133 void swigUnloadSharedLib(SwigSharedLibHandle hlib) { 134 dlclose(hlib); 135 } 136 137 void* swigGetSymbol(SwigSharedLibHandle hlib, string symbolName) { 138 return dlsym(hlib, swigToCString(symbolName)); 139 } 140 141 string swigGetErrorStr() { 142 CCPTR err = dlerror(); 143 if (err is null) { 144 return "Unknown Error"; 145 } 146 return swigToDString(err); 147 } 148 } else version(Windows) { 149 alias ushort WORD; 150 alias uint DWORD; 151 alias CCPTR LPCSTR; 152 alias void* HMODULE; 153 alias void* HLOCAL; 154 alias int function() FARPROC; 155 struct VA_LIST {} 156 157 extern (Windows) { 158 HMODULE LoadLibraryA(LPCSTR); 159 FARPROC GetProcAddress(HMODULE, LPCSTR); 160 void FreeLibrary(HMODULE); 161 DWORD GetLastError(); 162 DWORD FormatMessageA(DWORD, in void*, DWORD, DWORD, LPCSTR, DWORD, VA_LIST*); 163 HLOCAL LocalFree(HLOCAL); 164 } 165 166 DWORD MAKELANGID(WORD p, WORD s) { 167 return (((cast(WORD)s) << 10) | cast(WORD)p); 168 } 169 170 enum { 171 LANG_NEUTRAL = 0, 172 SUBLANG_DEFAULT = 1, 173 FORMAT_MESSAGE_ALLOCATE_BUFFER = 256, 174 FORMAT_MESSAGE_IGNORE_INSERTS = 512, 175 FORMAT_MESSAGE_FROM_SYSTEM = 4096 176 } 177 178 alias HMODULE SwigSharedLibHandle; 179 180 SwigSharedLibHandle swigLoadSharedLib(string libName) { 181 return LoadLibraryA(swigToCString(libName)); 182 } 183 184 void swigUnloadSharedLib(SwigSharedLibHandle hlib) { 185 FreeLibrary(hlib); 186 } 187 188 void* swigGetSymbol(SwigSharedLibHandle hlib, string symbolName) { 189 return GetProcAddress(hlib, swigToCString(symbolName)); 190 } 191 192 string swigGetErrorStr() { 193 DWORD errcode = GetLastError(); 194 195 LPCSTR msgBuf; 196 DWORD i = FormatMessageA( 197 FORMAT_MESSAGE_ALLOCATE_BUFFER | 198 FORMAT_MESSAGE_FROM_SYSTEM | 199 FORMAT_MESSAGE_IGNORE_INSERTS, 200 null, 201 errcode, 202 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 203 cast(LPCSTR)&msgBuf, 204 0, 205 null); 206 207 string text = swigToDString(msgBuf); 208 LocalFree(cast(HLOCAL)msgBuf); 209 210 if (i >= 2) { 211 i -= 2; 212 } 213 return text[0 .. i]; 214 } 215 } else { 216 static assert(0, "Operating system not supported by the wrapper loading code."); 217 } 218 219 final class SwigSharedLib { 220 void load(string[] names) { 221 if (_hlib !is null) return; 222 223 string[] failedLibs; 224 string[] reasons; 225 226 foreach(n; names) { 227 _hlib = swigLoadSharedLib(n); 228 if (_hlib is null) { 229 failedLibs ~= n; 230 reasons ~= swigGetErrorStr(); 231 continue; 232 } 233 _name = n; 234 break; 235 } 236 237 if (_hlib is null) { 238 throw new SwigSwigSharedLibLoadException(failedLibs, reasons); 239 } 240 } 241 242 void* loadSymbol(string symbolName, bool doThrow = true) { 243 void* sym = swigGetSymbol(_hlib, symbolName); 244 if(doThrow && (sym is null)) { 245 throw new SwigSymbolLoadException(_name, symbolName); 246 } 247 return sym; 248 } 249 250 void unload() { 251 if(_hlib !is null) { 252 swigUnloadSharedLib(_hlib); 253 _hlib = null; 254 } 255 } 256 257 private: 258 string _name; 259 SwigSharedLibHandle _hlib; 260 } 261 } 262 263 static this() { 264 string[] possibleFileNames; 265 version (Posix) { 266 version (OSX) { 267 possibleFileNames ~= ["lib$wraplibrary.dylib", "lib$wraplibrary.bundle"]; 268 } 269 possibleFileNames ~= ["lib$wraplibrary.so"]; 270 } else version (Windows) { 271 possibleFileNames ~= ["$wraplibrary.dll", "lib$wraplibrary.so"]; 272 } else { 273 static assert(false, "Operating system not supported by the wrapper loading code."); 274 } 275 276 auto library = new SwigSharedLib; 277 library.load(possibleFileNames); 278 279 string bindCode(string functionPointer, string symbol) { 280 return functionPointer ~ " = cast(typeof(" ~ functionPointer ~ 281 "))library.loadSymbol(`" ~ symbol ~ "`);"; 282 } 283 284 //#if !defined(SWIG_D_NO_EXCEPTION_HELPER) 285 mixin(bindCode("swigRegisterExceptionCallbacks$module", "SWIGRegisterExceptionCallbacks_$module")); 286 //#endif // SWIG_D_NO_EXCEPTION_HELPER 287 //#if !defined(SWIG_D_NO_STRING_HELPER) 288 mixin(bindCode("swigRegisterStringCallback$module", "SWIGRegisterStringCallback_$module")); 289 //#endif // SWIG_D_NO_STRING_HELPER 290 $wrapperloaderbindcode 291 } 292 293 //#if !defined(SWIG_D_NO_EXCEPTION_HELPER) 294 extern(C) void function( 295 SwigExceptionCallback exceptionCallback, 296 SwigExceptionCallback illegalArgumentCallback, 297 SwigExceptionCallback illegalElementCallback, 298 SwigExceptionCallback ioCallback, 299 SwigExceptionCallback noSuchElementCallback) swigRegisterExceptionCallbacks$module; 300 //#endif // SWIG_D_NO_EXCEPTION_HELPER 301 302 //#if !defined(SWIG_D_NO_STRING_HELPER) 303 extern(C) void function(SwigStringCallback callback) swigRegisterStringCallback$module; 304 //#endif // SWIG_D_NO_STRING_HELPER 305 %} 306 307 %pragma(d) wrapperloaderbindcommand = %{ 308 mixin(bindCode("$function", "$symbol"));%} 309