alternative to assert
[gtkD.git] / gtkD / src / gtkc / Loader.d
blob1749904f290d5d1ecf1c7156193aeb0eef49918d
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 gtkc.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 gtkc.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 version(Tango)
80 private import tango.stdc.stdio;
81 private import tango.io.Stdout;
83 else
85 private import std.stdio;
88 const int RTLD_LAZY = 0x00001; // Lazy function call binding
89 const int RTLD_NOW = 0x00002; // Immediate function call binding
90 const int RTLD_NOLOAD = 0x00004; // No object load
91 const int RTLD_DEEPBIND = 0x00008; //
92 const int RTLD_GLOBAL = 0x00100; // Make object available to whole program
94 static char[][][char[]] loadFailures;
96 /**
97 * Gets all the failed loads for a specific library.
98 * This is filled in only if the default onFailure method is used durin load
99 * returns: An array of the names hat failed to load for a specific library
100 * or null if none was found
102 public static char[][] getLoadFailures(char[] libName)
104 if ( libName in loadFailures )
106 return loadFailures[libName];
108 else
110 return null;
115 * Gets all libraries loaded.
116 * This is filled in only if the default onFailure method is used durin load
117 * returns: An array of the library names
119 public static char[][] getLoadLibraries()
121 return loadFailures.keys;
125 * Checks if any symbol failed to load
126 * Returns: true is ALL symbols loaded
128 public static bool isPerfectLoad()
130 return loadFailures.keys.length == 0;
133 public static void dumpFailedLoads()
135 foreach ( char[] lib ; Linker.getLoadLibraries() )
137 foreach ( char[] symbol ; Linker.getLoadFailures(lib) )
139 version(Tango) Stdout("failed ({}) {}", lib, symbol).newline;
140 else writefln("failed (%s) %s", lib, symbol);
145 private HANDLE handle;
146 private HANDLE alternateHandle;
148 private char[] libraryName;
149 private char[] alternateLibraryName;
151 // private bool continueOnFail = false;
153 alias void function( char[] libraryName, char[] symbolName, char[] message=null) failureFN;
155 private failureFN onLoadFailure;
157 // -----------------------------------------------------
159 this( char[] libraryName, char[] alternateLibraryName=null )
161 this(libraryName, alternateLibraryName, &(Linker.defaultFail));
164 // ---------------------------------------
166 this (char[] libraryName, char[] alternateLibraryName, failureFN fn )
168 this.libraryName = libraryName;
169 this.alternateLibraryName = alternateLibraryName;
170 onLoadFailure = fn;
172 version(Windows)
174 handle = LoadLibraryA( (this.libraryName ~ "\0").ptr );
175 if ( alternateLibraryName !is null )
177 alternateHandle = LoadLibraryA( (this.alternateLibraryName ~ "\0").ptr );
180 version(linux)
182 handle = dlopen( (this.libraryName ~ "\0").ptr, RTLD_NOW);
183 if (handle is null)
185 // non-dev libraries tend to be called xxxx.so.0
186 handle = dlopen( (this.libraryName ~ ".0\0").ptr, RTLD_NOW);
188 if ( alternateLibraryName !is null )
190 alternateHandle = dlopen( (this.alternateLibraryName ~ "\0").ptr, RTLD_NOW);
192 // clear the error buffer
193 dlerror();
195 version(Darwin)
198 else
201 if (handle is null)
203 throw new Exception("Library load failed: " ~ libraryName);
205 else
207 version(Tango) Stdout("Loaded lib = {}", libraryName).newline;
208 else writefln("Loaded lib = %s", libraryName);
213 // ----------------------------------------
215 ~this()
217 version(Windows)
219 // FreeLibrary(handle);
221 version(linux)
223 // Linux version
225 version(Darwin)
228 else
233 * Default on load fail.
234 * Logs the symbols that failed to load
236 static void defaultFail( char[] libraryName, char[] symbolName, char[] message=null )
238 //writefln("failed to load (%s): %s",libraryName , message );
240 if ( !(libraryName in loadFailures) )
242 char[][] cc;
243 loadFailures[libraryName] = cc;
246 loadFailures[libraryName] ~= symbolName.dup; // need dup?
248 //throw new Exception("Function failed to load from library: " ~ libraryName);
252 * Loads all the simbols for this library
253 * symbols: All the simbol names to be loaded
255 void link( inout Symbol[] symbols )
257 foreach( Symbol link; symbols )
259 *link.pointer = getSymbol(handle, (link.name~"\0").ptr);
260 version(Tango)debug(loadSymbol) Stdout("Loaded...")(libraryName)(" ")(link.name).newline;
261 else debug(loadSymbol) writefln("Loaded...", libraryName, " ", link.name);
262 if (*link.pointer is null)
264 // if gthread try on glib
265 if ( alternateHandle !is null )
267 *link.pointer = getSymbol(alternateHandle, (link.name~"\0").ptr);
268 version(Tango) Stdout("Loader.Linker.link trying alternate lib <<<<<<<<< {}", link.name).newline;
269 else writefln("Loader.Linker.link trying alternate lib <<<<<<<<< %s", link.name);
271 if (*link.pointer is null)
273 onLoadFailure( libraryName, link.name );