1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 module gtkc.Loader; 21 22 version(Tango) 23 { 24 import tango.io.Stdout; 25 import tango.stdc.stringz; 26 27 import gtkc.glibtypes; 28 // private alias char[] string; 29 } 30 else 31 { 32 import std.stdio; 33 import std.string; 34 } 35 36 import gtkc.paths; 37 38 public struct Linker 39 { 40 private static void*[string] loadedLibraries; 41 private static string[][string] loadFailures; 42 43 /* 44 * Links the provided symbol 45 * Params: 46 * funct = The function we are linking 47 * symbol = The name of the symbol to link 48 * libraries = One or more libraries to search for the symbol 49 */ 50 public static void link(T)(ref T funct, string symbol, LIBRARY[] libraries ...) 51 { 52 funct = cast(T)getSymbol(symbol, libraries); 53 } 54 55 /* 56 * Links the provided symbol 57 * Params: 58 * funct = The function we are linking 59 * symbol = The name of the symbol to link 60 * libraries = One or more libraries to search for the symbol 61 */ 62 public static void link(T)(ref T funct, string symbol, string[] libraries ...) 63 { 64 funct = cast(T)getSymbol(symbol, libraries); 65 } 66 67 /* 68 * Gets a simbol from one of the provided libraries 69 * Params: 70 * symbol = The name of the symbol to link 71 * libraries = One or more libraries to search for the symbol 72 */ 73 public static void* getSymbol(string symbol, LIBRARY[] libraries ...) 74 { 75 string[] libStr = new string[libraries.length]; 76 77 foreach (i, library; libraries ) 78 { 79 libStr[i] = importLibs[library]; 80 } 81 82 return getSymbol(symbol, libStr); 83 } 84 85 /* 86 * Gets a simbol from one of the provided libraries 87 * Params: 88 * symbol = The name of the symbol to link 89 * libraries = One or more libraries to search for the symbol 90 */ 91 public static void* getSymbol(string symbol, string[] libraries ...) 92 { 93 void* handle; 94 95 foreach ( library; libraries ) 96 { 97 if( !(library in loadedLibraries) ) 98 loadLibrary(library); 99 100 handle = pGetSymbol(loadedLibraries[library], symbol); 101 102 if ( handle !is null ) 103 break; 104 } 105 106 if ( handle is null ) 107 { 108 foreach ( library; libraries ) 109 loadFailures[library] ~= symbol; 110 } 111 112 return handle; 113 } 114 115 /* 116 * Loads a library 117 */ 118 public static void loadLibrary(string library) 119 { 120 void* handle = pLoadLibrary(libPath ~ library); 121 122 if ( handle is null ) 123 throw new Exception("Library load failed: " ~ library); 124 125 loadedLibraries[library] = handle; 126 } 127 128 /* 129 * Unload a library 130 */ 131 public static void unloadLibrary(LIBRARY library) 132 { 133 unloadLibrary( importLibs[library] ); 134 } 135 136 /* 137 * Unload a library 138 */ 139 public static void unloadLibrary(string library) 140 { 141 pUnloadLibrary(loadedLibraries[library]); 142 143 loadedLibraries.remove(library); 144 } 145 146 /** 147 * Checks if any symbol failed to load 148 * Returns: true if ALL symbols are loaded 149 */ 150 public static bool isPerfectLoad() 151 { 152 return loadFailures.keys.length == 0; 153 } 154 155 /** 156 * Gets all libraries loaded. 157 * returns: An array with the loaded libraries 158 */ 159 public static string[] getLoadLibraries() 160 { 161 return loadedLibraries.keys; 162 } 163 164 /** 165 * Print all libraries loaded. 166 */ 167 public static void dumpLoadLibraries() 168 { 169 foreach ( lib; getLoadLibraries() ) 170 { 171 version(Tango) 172 Stdout.formatln("Loaded lib = {}", lib); 173 else 174 writefln("Loaded lib = %s", lib); 175 } 176 } 177 178 /** 179 * Checks if a library is loaded. 180 * Returns: true is the library was loaded sucsessfully. 181 */ 182 public static bool isLoaded(LIBRARY library) 183 { 184 return isLoaded(importLibs[library]); 185 } 186 187 /** 188 * Checks if a library is loaded. 189 * Returns: true is the library was loaded sucsessfully. 190 */ 191 public static bool isLoaded(string library) 192 { 193 if ( library in loadedLibraries ) 194 return true; 195 else 196 return false; 197 } 198 199 /** 200 * Gets all the failed loads for a specific library. 201 * returns: An array of the names hat failed to load for a specific library 202 * or null if none was found 203 */ 204 public static string[] getLoadFailures(LIBRARY library) 205 { 206 return getLoadFailures(importLibs[library]); 207 } 208 209 /** 210 * Gets all the failed loads for a specific library. 211 * returns: An array of the names hat failed to load for a specific library 212 * or null if none was found 213 */ 214 public static string[] getLoadFailures(string library) 215 { 216 if ( library in loadFailures ) 217 return loadFailures[library]; 218 else 219 return null; 220 } 221 222 /** 223 * Print all symbols that failed to load 224 */ 225 public static void dumpFailedLoads() 226 { 227 foreach ( library; loadedLibraries.keys ) 228 { 229 foreach ( symbol; getLoadFailures(library) ) 230 { 231 version(Tango) 232 Stdout.formatln("failed ({}) {}", library, symbol); 233 else 234 writefln("failed (%s) %s", library, symbol); 235 } 236 } 237 } 238 239 static ~this() 240 { 241 foreach ( library; loadedLibraries.keys ) 242 unloadLibrary(library); 243 } 244 } 245 246 // Platform specific implementation below. 247 248 version(Windows) 249 { 250 extern(Windows) 251 { 252 void* LoadLibraryA(char*); 253 void* GetProcAddress(void*, char*); 254 void FreeLibrary(void*); 255 } 256 257 private void* pLoadLibrary(string libraryName) 258 { 259 return LoadLibraryA(cast(char*)toStringz(libraryName)); 260 } 261 262 private void* pGetSymbol(void* handle, string symbol) 263 { 264 return GetProcAddress(handle, cast(char*)toStringz(symbol)); 265 } 266 267 private alias FreeLibrary pUnloadLibrary; 268 } 269 else 270 { 271 extern(C) 272 { 273 void* dlopen(char*, int); 274 char* dlerror(); 275 void* dlsym(void*,char*); 276 int dlclose(void*); 277 } 278 279 enum RTLD 280 { 281 GDC_BUG_WORKAROUND, 282 LAZY = 0x00001, // Lazy function call binding 283 NOW = 0x00002, // Immediate function call binding 284 NOLOAD = 0x00004, // No object load 285 DEEPBIND = 0x00008, // 286 GLOBAL = 0x00100 // Make object available to whole program 287 } 288 289 private void* pLoadLibrary(string libraryName, RTLD flag = RTLD.NOW) 290 { 291 void* handle = dlopen(cast(char*)toStringz(libraryName), flag); 292 293 // clear the error buffer 294 dlerror(); 295 296 return handle; 297 } 298 299 private void* pGetSymbol(void* libraryHandle, string symbol) 300 { 301 void* symbolHandle = dlsym(libraryHandle, cast(char*)toStringz(symbol)); 302 303 // clear the error buffer 304 dlerror(); 305 306 return symbolHandle; 307 } 308 309 private int pUnloadLibrary(void* libraryHandle) 310 { 311 return dlclose(libraryHandle); 312 } 313 314 version(build) version(linux) 315 { 316 pragma(link, "dl"); // tell dsss to link libdl 317 } 318 }