blob: b3c1d0dcf5e8332e58091440f5d35ac7afbe8cda [file] [log] [blame]
/* -----------------------------------------------------------------------------
* 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;
}
static import std.string;
static import std.c.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 std.c.linux.linux;
} 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"));%}