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 import std.stdio; 23 import std.string; 24 25 import gtkc.paths; 26 27 public struct Linker 28 { 29 private static void*[string] loadedLibraries; 30 private static string[][string] loadFailures; 31 32 extern(C) static void unsuportedSymbol() 33 { 34 throw new Error("The funcion your calling is not pressent in your version of Gtk+."); 35 } 36 37 /* 38 * Links the provided symbol 39 * Params: 40 * funct = The function we are linking 41 * symbol = The name of the symbol to link 42 * libraries = One or more libraries to search for the symbol 43 */ 44 public static void link(T)(ref T funct, string symbol, LIBRARY[] libraries ...) 45 { 46 funct = cast(T)getSymbol(symbol, libraries); 47 } 48 49 /* 50 * Links the provided symbol 51 * Params: 52 * funct = The function we are linking 53 * symbol = The name of the symbol to link 54 * libraries = One or more libraries to search for the symbol 55 */ 56 public static void link(T)(ref T funct, string symbol, string[] libraries ...) 57 { 58 funct = cast(T)getSymbol(symbol, libraries); 59 } 60 61 /* 62 * Gets a simbol from one of the provided libraries 63 * Params: 64 * symbol = The name of the symbol to link 65 * libraries = One or more libraries to search for the symbol 66 */ 67 public static void* getSymbol(string symbol, LIBRARY[] libraries ...) 68 { 69 string[] libStr = new string[libraries.length]; 70 71 foreach (i, library; libraries ) 72 { 73 libStr[i] = importLibs[library]; 74 } 75 76 return getSymbol(symbol, libStr); 77 } 78 79 /* 80 * Gets a simbol from one of the provided libraries 81 * Params: 82 * symbol = The name of the symbol to link 83 * libraries = One or more libraries to search for the symbol 84 */ 85 public static void* getSymbol(string symbol, string[] libraries ...) 86 { 87 void* handle; 88 89 foreach ( library; libraries ) 90 { 91 if( !(library in loadedLibraries) ) 92 loadLibrary(library); 93 94 handle = pGetSymbol(loadedLibraries[library], symbol); 95 96 if ( handle !is null ) 97 break; 98 } 99 100 if ( handle is null ) 101 { 102 foreach ( library; libraries ) 103 loadFailures[library] ~= symbol; 104 105 handle = &unsuportedSymbol; 106 } 107 108 return handle; 109 } 110 111 /* 112 * Loads a library 113 */ 114 public static void loadLibrary(string library) 115 { 116 void* handle = pLoadLibrary(library); 117 118 //TODO: A more general way to try more than one version. 119 if ( handle is null && library == importLibs[LIBRARY.GSV] ) 120 handle = pLoadLibrary(importLibs[LIBRARY.GSV1]); 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 writefln("Loaded lib = %s", lib); 172 } 173 } 174 175 /** 176 * Checks if a library is loaded. 177 * Returns: true is the library was loaded sucsessfully. 178 */ 179 public static bool isLoaded(LIBRARY library) 180 { 181 return isLoaded(importLibs[library]); 182 } 183 184 /** 185 * Checks if a library is loaded. 186 * Returns: true is the library was loaded sucsessfully. 187 */ 188 public static bool isLoaded(string library) 189 { 190 if ( library in loadedLibraries ) 191 return true; 192 else 193 return false; 194 } 195 196 /** 197 * Gets all the failed loads for a specific library. 198 * returns: An array of the names hat failed to load for a specific library 199 * or null if none was found 200 */ 201 public static string[] getLoadFailures(LIBRARY library) 202 { 203 return getLoadFailures(importLibs[library]); 204 } 205 206 /** 207 * Gets all the failed loads for a specific library. 208 * returns: An array of the names hat failed to load for a specific library 209 * or null if none was found 210 */ 211 public static string[] getLoadFailures(string library) 212 { 213 if ( library in loadFailures ) 214 return loadFailures[library]; 215 else 216 return null; 217 } 218 219 /** 220 * Print all symbols that failed to load 221 */ 222 public static void dumpFailedLoads() 223 { 224 foreach ( library; loadedLibraries.keys ) 225 { 226 foreach ( symbol; getLoadFailures(library) ) 227 { 228 writefln("failed (%s) %s", library, symbol); 229 } 230 } 231 } 232 233 static ~this() 234 { 235 foreach ( library; loadedLibraries.keys ) 236 unloadLibrary(library); 237 } 238 } 239 240 // Platform specific implementation below. 241 242 version(Windows) 243 { 244 extern(Windows) 245 { 246 void* LoadLibraryA(char*); 247 void* GetProcAddress(void*, char*); 248 void FreeLibrary(void*); 249 250 int SetDllDirectoryA(const(char)* path); 251 252 enum MachineType : ushort 253 { 254 UNKNOWN = 0x0, 255 AM33 = 0x1d3, 256 AMD64 = 0x8664, 257 ARM = 0x1c0, 258 EBC = 0xebc, 259 I386 = 0x14c, 260 IA64 = 0x200, 261 M32R = 0x9041, 262 MIPS16 = 0x266, 263 MIPSFPU = 0x366, 264 MIPSFPU16 = 0x466, 265 POWERPC = 0x1f0, 266 POWERPCFP = 0x1f1, 267 R4000 = 0x166, 268 SH3 = 0x1a2, 269 SH3DSP = 0x1a3, 270 SH4 = 0x1a6, 271 SH5 = 0x1a8, 272 THUMB = 0x1c2, 273 WCEMIPSV2 = 0x169, 274 } 275 } 276 277 private void* pLoadLibrary(string libraryName) 278 { 279 setDllPath(); 280 281 return LoadLibraryA(cast(char*)toStringz(libraryName)); 282 } 283 284 private void* pGetSymbol(void* handle, string symbol) 285 { 286 return GetProcAddress(handle, cast(char*)toStringz(symbol)); 287 } 288 289 private alias FreeLibrary pUnloadLibrary; 290 291 private void setDllPath() 292 { 293 static bool isSet; 294 295 if ( isSet ) 296 return; 297 298 string gtkPath = getGtkPath(); 299 300 if ( gtkPath.length > 0 ) 301 SetDllDirectoryA((gtkPath~'\0').ptr); 302 303 isSet = true; 304 } 305 306 private string getGtkPath() 307 { 308 import std.algorithm; 309 import std.path; 310 import std.process; 311 import std.file; 312 313 string exePath = buildNormalizedPath(thisExePath().dirName(), "gtk", "bin"); 314 string dllPath = buildNormalizedPath(exePath, "libgtk-3-0.dll"); 315 316 if ( exists(dllPath) ) 317 { 318 if ( checkArchitecture(dllPath) ) 319 return exePath; 320 } 321 322 foreach (path; splitter(environment.get("PATH"), ';')) 323 { 324 dllPath = buildNormalizedPath(path, "libgtk-3-0.dll"); 325 326 if ( !exists(dllPath) ) 327 continue; 328 329 if ( checkArchitecture(dllPath) ) 330 return path; 331 } 332 333 return null; 334 } 335 336 private bool checkArchitecture(string dllPath) 337 { 338 import std.stdio; 339 340 File dll = File(dllPath); 341 342 dll.seek(0x3c); 343 int offset = dll.rawRead(new int[1])[0]; 344 345 dll.seek(offset); 346 uint peHead = dll.rawRead(new uint[1])[0]; 347 348 //Not a PE Header. 349 if( peHead != 0x00004550) 350 return false; 351 352 MachineType type = dll.rawRead(new MachineType[1])[0]; 353 354 version(Win32) 355 { 356 if ( type == MachineType.I386 ) 357 return true; 358 } 359 else version(Win64) 360 { 361 if ( type == MachineType.AMD64 ) 362 return true; 363 } 364 365 return false; 366 } 367 } 368 else 369 { 370 extern(C) 371 { 372 void* dlopen(char*, int); 373 char* dlerror(); 374 void* dlsym(void*,char*); 375 int dlclose(void*); 376 } 377 378 enum RTLD 379 { 380 LAZY = 0x00001, // Lazy function call binding 381 NOW = 0x00002, // Immediate function call binding 382 NOLOAD = 0x00004, // No object load 383 DEEPBIND = 0x00008, // 384 GLOBAL = 0x00100 // Make object available to whole program 385 } 386 387 private void* pLoadLibrary(string libraryName, RTLD flag = RTLD.NOW) 388 { 389 void* handle = dlopen(cast(char*)toStringz(libraryName), flag); 390 391 // clear the error buffer 392 dlerror(); 393 394 return handle; 395 } 396 397 private void* pGetSymbol(void* libraryHandle, string symbol) 398 { 399 void* symbolHandle = dlsym(libraryHandle, cast(char*)toStringz(symbol)); 400 401 // clear the error buffer 402 dlerror(); 403 404 return symbolHandle; 405 } 406 407 private int pUnloadLibrary(void* libraryHandle) 408 { 409 return dlclose(libraryHandle); 410 } 411 }