/* ----------------------------------------------------------------------------- * wrapperloader.swg * * Support code for dynamically linking the C wrapper library from the D * wrapper module. * * The loading code was adapted from the Derelict project and is used with * permission from Michael Parker, the original author. * ----------------------------------------------------------------------------- */ %pragma(d) wrapperloadercode = %{ private { version(linux) { version = Nix; } else version(darwin) { version = Nix; } else version(OSX) { version = Nix; } else version(FreeBSD) { version = Nix; version = freebsd; } else version(freebsd) { version = Nix; } else version(Unix) { version = Nix; } else version(Posix) { version = Nix; } version(Tango) { static import tango.stdc.string; static import tango.stdc.stringz; version (PhobosCompatibility) { } else { alias char[] string; alias wchar[] wstring; alias dchar[] dstring; } } else { version(D_Version2) { static import std.conv; } else { static import std.c.string; } static import std.string; } version(D_Version2) { mixin("alias const(char)* CCPTR;"); } else { alias char* CCPTR; } CCPTR swigToCString(string str) { version(Tango) { return tango.stdc.stringz.toStringz(str); } else { return std.string.toStringz(str); } } string swigToDString(CCPTR cstr) { version(Tango) { return tango.stdc.stringz.fromStringz(cstr); } else { version(D_Version2) { mixin("return std.conv.to!string(cstr);"); } else { return std.c.string.toString(cstr); } } } } class SwigSwigSharedLibLoadException : Exception { this(in string[] libNames, in string[] reasons) { string msg = "Failed to load one or more shared libraries:"; foreach(i, n; libNames) { msg ~= "\n\t" ~ n ~ " - "; if(i < reasons.length) msg ~= reasons[i]; else msg ~= "Unknown"; } super(msg); } } class SwigSymbolLoadException : Exception { this(string SwigSharedLibName, string symbolName) { super("Failed to load symbol " ~ symbolName ~ " from shared library " ~ SwigSharedLibName); _symbolName = symbolName; } string symbolName() { return _symbolName; } private: string _symbolName; } private { version(Nix) { version(freebsd) { // the dl* functions are in libc on FreeBSD } else { pragma(lib, "dl"); } version(Tango) { import tango.sys.Common; } else version(linux) { import core.sys.posix.dlfcn; } else { extern(C) { const RTLD_NOW = 2; void *dlopen(CCPTR file, int mode); int dlclose(void* handle); void *dlsym(void* handle, CCPTR name); CCPTR dlerror(); } } alias void* SwigSharedLibHandle; SwigSharedLibHandle swigLoadSharedLib(string libName) { return dlopen(swigToCString(libName), RTLD_NOW); } void swigUnloadSharedLib(SwigSharedLibHandle hlib) { dlclose(hlib); } void* swigGetSymbol(SwigSharedLibHandle hlib, string symbolName) { return dlsym(hlib, swigToCString(symbolName)); } string swigGetErrorStr() { CCPTR err = dlerror(); if (err is null) { return "Unknown Error"; } return swigToDString(err); } } else version(Windows) { alias ushort WORD; alias uint DWORD; alias CCPTR LPCSTR; alias void* HMODULE; alias void* HLOCAL; alias int function() FARPROC; struct VA_LIST {} extern (Windows) { HMODULE LoadLibraryA(LPCSTR); FARPROC GetProcAddress(HMODULE, LPCSTR); void FreeLibrary(HMODULE); DWORD GetLastError(); DWORD FormatMessageA(DWORD, in void*, DWORD, DWORD, LPCSTR, DWORD, VA_LIST*); HLOCAL LocalFree(HLOCAL); } DWORD MAKELANGID(WORD p, WORD s) { return (((cast(WORD)s) << 10) | cast(WORD)p); } enum { LANG_NEUTRAL = 0, SUBLANG_DEFAULT = 1, FORMAT_MESSAGE_ALLOCATE_BUFFER = 256, FORMAT_MESSAGE_IGNORE_INSERTS = 512, FORMAT_MESSAGE_FROM_SYSTEM = 4096 } alias HMODULE SwigSharedLibHandle; SwigSharedLibHandle swigLoadSharedLib(string libName) { return LoadLibraryA(swigToCString(libName)); } void swigUnloadSharedLib(SwigSharedLibHandle hlib) { FreeLibrary(hlib); } void* swigGetSymbol(SwigSharedLibHandle hlib, string symbolName) { return GetProcAddress(hlib, swigToCString(symbolName)); } string swigGetErrorStr() { DWORD errcode = GetLastError(); LPCSTR msgBuf; DWORD i = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), cast(LPCSTR)&msgBuf, 0, null); string text = swigToDString(msgBuf); LocalFree(cast(HLOCAL)msgBuf); if (i >= 2) { i -= 2; } return text[0 .. i]; } } else { static assert(0, "Operating system not supported by the wrapper loading code."); } final class SwigSharedLib { void load(string[] names) { if (_hlib !is null) return; string[] failedLibs; string[] reasons; foreach(n; names) { _hlib = swigLoadSharedLib(n); if (_hlib is null) { failedLibs ~= n; reasons ~= swigGetErrorStr(); continue; } _name = n; break; } if (_hlib is null) { throw new SwigSwigSharedLibLoadException(failedLibs, reasons); } } void* loadSymbol(string symbolName, bool doThrow = true) { void* sym = swigGetSymbol(_hlib, symbolName); if(doThrow && (sym is null)) { throw new SwigSymbolLoadException(_name, symbolName); } return sym; } void unload() { if(_hlib !is null) { swigUnloadSharedLib(_hlib); _hlib = null; } } private: string _name; SwigSharedLibHandle _hlib; } } static this() { string[] possibleFileNames; version (Posix) { version (OSX) { possibleFileNames ~= ["lib$wraplibrary.dylib", "lib$wraplibrary.bundle"]; } possibleFileNames ~= ["lib$wraplibrary.so"]; } else version (Windows) { possibleFileNames ~= ["$wraplibrary.dll", "lib$wraplibrary.so"]; } else { static assert(false, "Operating system not supported by the wrapper loading code."); } auto library = new SwigSharedLib; library.load(possibleFileNames); string bindCode(string functionPointer, string symbol) { return functionPointer ~ " = cast(typeof(" ~ functionPointer ~ "))library.loadSymbol(`" ~ symbol ~ "`);"; } //#if !defined(SWIG_D_NO_EXCEPTION_HELPER) mixin(bindCode("swigRegisterExceptionCallbacks$module", "SWIGRegisterExceptionCallbacks_$module")); //#endif // SWIG_D_NO_EXCEPTION_HELPER //#if !defined(SWIG_D_NO_STRING_HELPER) mixin(bindCode("swigRegisterStringCallback$module", "SWIGRegisterStringCallback_$module")); //#endif // SWIG_D_NO_STRING_HELPER $wrapperloaderbindcode } //#if !defined(SWIG_D_NO_EXCEPTION_HELPER) extern(C) void function( SwigExceptionCallback exceptionCallback, SwigExceptionCallback illegalArgumentCallback, SwigExceptionCallback illegalElementCallback, SwigExceptionCallback ioCallback, SwigExceptionCallback noSuchElementCallback) swigRegisterExceptionCallbacks$module; //#endif // SWIG_D_NO_EXCEPTION_HELPER //#if !defined(SWIG_D_NO_STRING_HELPER) extern(C) void function(SwigStringCallback callback) swigRegisterStringCallback$module; //#endif // SWIG_D_NO_STRING_HELPER %} %pragma(d) wrapperloaderbindcommand = %{ mixin(bindCode("$function", "$symbol"));%}