wrapperloader.swg 7.7 KB

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