Home | History | Annotate | Download | only in d
      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