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
13 * Thanks Kris! see www.dsource.org/projects/mango for more details.
28 HANDLE
LoadLibraryA( char* );
29 void* GetProcAddress( void*, char* );
31 // getSymbol - cross-platform access point
32 alias GetProcAddress getSymbol
;
40 void* dlopen(char*, int);
42 void* dlsym(void*,char*);
45 // // getSymbol - cross-platform access point
46 alias dlsym getSymbol
;
51 private void* getSymbol(void* handle
,char* name
) {}
56 * ProcLink is used to record the library, function, and function name
57 * that will be loaded by dynamic loader.
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;
80 private import tango
.stdc
.stdio
;
81 private import tango
.io
.Stdout
;
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
;
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
];
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
;
174 handle
= LoadLibraryA( (this.libraryName
~ "\0").ptr
);
175 if ( alternateLibraryName
!is null )
177 alternateHandle
= LoadLibraryA( (this.alternateLibraryName
~ "\0").ptr
);
182 handle
= dlopen( (this.libraryName
~ "\0").ptr
, RTLD_NOW
);
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
203 throw new Exception("Library load failed: " ~ libraryName
);
207 version(Tango
) Stdout("Loaded lib = {}", libraryName
).newline
;
208 else writefln("Loaded lib = %s", libraryName
);
213 // ----------------------------------------
219 // FreeLibrary(handle);
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
) )
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
);