I've no idea here...
[gtkD.git] / srcgl / lib / Loader.d
blob545d2ee4f6d50a72ea6ec01a1fb753910fbb47ef
1 /*
2 * MODULE: loader.d
3 *
4 * Dynamic Library Loader for DUI
6 * Added 2004-12-11 -- John Reimer
7 * Updated 2005-02-21: class and symbol names change; versioning modification.
8 * Updated 2005-05-04: repairs to support linux
10 * Design/implementation of loader module inspired by Kris Bell's ICU.d dynamic
11 * loader -- mango.icu
13 * Thanks Kris! see www.dsource.org/projects/mango for more details.
17 module lib.Loader;
19 //debug = loadLib;
20 //debug = loadSymbol;
22 alias void* HANDLE;
24 version (Windows)
26 extern(Windows)
28 HANDLE LoadLibraryA( char* );
29 void* GetProcAddress( void*, char* );
31 // getSymbol - cross-platform access point
32 alias GetProcAddress getSymbol;
35 version (linux)
37 extern(C)
40 void* dlopen(char*, int);
41 char* dlerror();
42 void* dlsym(void*,char*);
43 int dlclose(void*);
45 // // getSymbol - cross-platform access point
46 alias dlsym getSymbol;
49 version (Darwin)
51 private void* getSymbol(void* handle,char* name) {}
55 /*
56 * ProcLink is used to record the library, function, and function name
57 * that will be loaded by dynamic loader.
60 public struct Symbol
62 char[] name; // Name of the exported procedure in dynamic library
63 void** pointer; // Address of the procedure pointer variable
66 private import lib.paths;
69 * Linker : simple class to handle the loading
70 * of the library and exported functions
73 //alias void function( char[] ) failureFN;
75 public class Linker
78 private import std.stdio;
80 const int RTLD_LAZY = 0x00001; // Lazy function call binding
81 const int RTLD_NOW = 0x00002; // Immediate function call binding
82 const int RTLD_NOLOAD = 0x00004; // No object load
83 const int RTLD_DEEPBIND = 0x00008; //
84 const int RTLD_GLOBAL = 0x00100; // Make object available to whole program
86 static char[][][char[]] loadFailures;
88 /**
89 * Gets all the failed loads for a specific library.
90 * This is filled in only if the default onFailure method is used durin load
91 * returns: An array of the names hat failed to load for a specific library
92 * or null if none was found
94 public static char[][] getLoadFailures(char[] libName)
96 if ( libName in loadFailures )
98 return loadFailures[libName];
100 else
102 return null;
107 * Gets all libraries loaded.
108 * This is filled in only if the default onFailure method is used durin load
109 * returns: An array of the library names
111 public static char[][] getLoadLibraries()
113 return loadFailures.keys;
117 * Checks if any symbol failed to load
118 * Returns: true is ALL symbols loaded
120 public static bool isPerfectLoad()
122 return loadFailures.keys.length == 0;
125 public static void dumpFailedLoads()
127 foreach ( char[] lib ; Linker.getLoadLibraries() )
129 foreach ( char[] symbol ; Linker.getLoadFailures(lib) )
131 writefln("failed (%s) %s", lib, symbol);
136 private HANDLE handle;
137 private HANDLE alternateHandle;
139 private char[] libraryName;
140 private char[] alternateLibraryName;
142 // private bool continueOnFail = false;
144 alias void function( char[] libraryName, char[] symbolName, char[] message=null) failureFN;
146 private failureFN onLoadFailure;
148 // -----------------------------------------------------
150 this( char[] libraryName, char[] alternateLibraryName=null )
152 this(libraryName, alternateLibraryName, &(Linker.defaultFail));
155 // ---------------------------------------
157 this (char[] libraryName, char[] alternateLibraryName, failureFN fn )
159 this.libraryName = libraryName;
160 this.alternateLibraryName = alternateLibraryName;
161 onLoadFailure = fn;
163 version(Windows)
165 handle = LoadLibraryA( this.libraryName ~ "\0" );
166 if ( alternateLibraryName !is null )
168 alternateHandle = LoadLibraryA( this.alternateLibraryName ~ "\0" );
171 version(linux)
173 handle = dlopen( (this.libraryName ~ "\0").ptr, RTLD_NOW);
174 if ( alternateLibraryName !is null )
176 alternateHandle = dlopen( (this.alternateLibraryName ~ "\0").ptr, RTLD_NOW);
178 // clear the error buffer
179 dlerror();
181 version(Darwin)
184 else
187 if (handle is null)
189 throw new Exception("Library load failed: " ~ libraryName);
191 else
193 writefln("Loaded lib = %s", libraryName);
198 // ----------------------------------------
200 ~this()
202 version(Windows)
204 // FreeLibrary(handle);
206 version(linux)
208 // Linux version
210 version(Darwin)
213 else
218 * Default on load fail.
219 * Logs the symbols that failed to load
221 static void defaultFail( char[] libraryName, char[] symbolName, char[] message=null )
223 //writefln("failed to load (%s): %s",libraryName , message );
225 if ( !(libraryName in loadFailures) )
227 char[][] cc;
228 loadFailures[libraryName] = cc;
231 loadFailures[libraryName] ~= symbolName.dup; // need dup?
233 //throw new Exception("Function failed to load from library: " ~ libraryName);
237 * Loads all the simbols for this library
238 * symbols: All the simbol names to be loaded
240 void link( inout Symbol[] symbols )
242 foreach( Symbol link; symbols )
244 *link.pointer = getSymbol(handle, (link.name~"\0").ptr);
245 debug(loadSymbol) writefln("Loaded...", libraryName, " ", link.name);
246 if (*link.pointer is null)
248 // if gthread try on glib
249 if ( alternateHandle !is null )
251 *link.pointer = getSymbol(alternateHandle, (link.name~"\0").ptr);
252 writefln("Loader.Linker.link trying alternate lib <<<<<<<<< %s", link.name);
254 if (*link.pointer is null)
256 onLoadFailure( libraryName, link.name );