The D(eimos) Dynamic Loader portably loads C libraries at run time and binds extern(C) function declared in a module given its module name at compile time. These functions can then be loaded at run time.
Loading a library at run time is useful for graceful degradation. First check
whether a library exists and then use the provided functionality. Otherwise
provide only a basic set of features.
For a module name given at compile time its extern(C) functions are loadable
at run time. Writing a module containing extern(C) declared functions is
easy. Even better there are already modules for the purpose of calling C
libraries from within D provided by Deimos.
This set of modules is steadily growing and it is easy to add a new module
by converting a C library's header file(s) to D.
Note, that loading overloaded functions is not possible. Only the
function name is used for loading. This may give surprising results when
overloaded functions are loaded.
This module is written such that is should work on Windows but has been
only compiled and tested on Linux. Please report any issue while trying it
out.
unittest { import ddl; import std.string : toStringz; import core.stdc.stdio; // import the module as usual // load the library C to resolve extern(C) functions declared // in core.std.stdio, but load no functions yet auto stdio = loadLibrary!(core.stdc.stdio)(libraryFilename("c")~".6", false); // not loaded yet assert(stdio.printf == null); // load the function printf stdio.loadFunction!("printf")(); // ... and call it stdio.printf(toStringz("Hello World.\n")); }
unittest { import ddl; import deimos.openssl.aes; auto aes = loadLibrary!(deimos.openssl.aes)("ssl"); assert(aes.loadedFunctions == ["AES_options", "AES_set_encrypt_key", "AES_set_decrypt_key", "AES_encrypt", "AES_decrypt", "AES_ecb_encrypt", "AES_cbc_encrypt", "AES_cfb128_encrypt", "AES_cfb1_encrypt", "AES_cfb8_encrypt", "AES_ofb128_encrypt", "AES_ctr128_encrypt", "AES_ige_encrypt", "AES_bi_ige_encrypt", "AES_wrap_key", "AES_unwrap_key"]); }
import ddl; // declare either Library!(deimos.openssl.sha) sha or import deimos.openssl.sha version(ddl) mixin declareLibraryAndAlias!("deimos.openssl.sha", "sha"); else import deimos.openssl.sha; unittest { version(ddl) sha = loadLibrary!(deimos.openssl.sha)("ssl"); // use as usual ubyte[] ibuf = [0x61, 0x62, 0x63]; ubyte[20] obuf; SHA1(ibuf.ptr, ibuf.length, obuf.ptr); assert(obuf == [0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA,0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D]); }
unittest { import ddl; import std.string : toStringz; import core.stdc.stdio; // throws if some_library could not be loaded assertThrown!UnsatisfiedLinkException(loadLibrary!(core.stdc.stdio)("some_library", false)); auto stdio = loadLibrary!(core.stdc.stdio)(libraryFilename("c")~".6", false); // compile error, since foobar is not extern(C) function in core.stdc.stdio static assert(!__traits(compiles, stdio.loadFunction!("foobar")())); // stdio.printf is not loaded assert(stdio.printf == null); // calling it results in a segfault //stdio.printf(toStringz("Hello World\n")); // assuming fun is a extern(C) declared function but not defined assertThrown!UnsatisfiedLinkException(stdio.loadFunction!("fun")()); }
On Posix the libraryFilenamePrefix is "lib". On Windows it is "".
On Posix the libraryFilenameExtension is ".so". On Windows it is ".dll".
moduleName | is the module name those extern(C) functions will be loaded |
libraryName | is the library name to load |
Same as above but the library name is inferred from the module name.
import deimos.openssl.aes; auto aes = loadLibrary!(deimos.openssl.aes); // loads library with name "aes
Imports moduleName, declares Library!(moduleName) and alias to all the libraries extern(C) functions.
moduleName | is the module name those extern(C) functions will be loaded |
as | is the variable name used when declaring Library!(moduleName) |
mixin declareLibraryAndAlias!("deimos.openssl.sha", "sha");
A Library is capable of loading all extern(C) functions declared in module moduleName.
On construction a given library will be loaded which is unloaded on destruction. Note, that all instances of a Library share the extern(C) functions as these are declared as static member variables.
moduleName | is the module name those extern(C) functions will be loaded |
ExternCFunctions is a TypeTuple containing the names of all extern(C) functions declared in moduleName.
Loads the library with given name.
A loaded library is unloaded on destruction. Note, that loaded functions are not unset, which can be a source of errors.
string libraryName | specifies the library to load. libraryName may either be a library name, a filename, or a path to a library. |
bool loadAllNow | specifies whether all functions should be loaded. |
Load function with given functionName.
After successful execution the function with name functionName is loaded
and accessible by all instances of this Library.
Fails at compile time, if functionName is not declared in moduleName.
functionName | is the name of the extern(C) function to load. |
Unload function with given functionName.
Note, that the function is unavailable for all instances of this Library
after unloading.
Fails at compile time, if functionName is not declared in moduleName.
functionName | is the name of the extern(C) function to unload. |
Load all functions.
It calls loadFunction for each ExternCFunctions.
Unload all functions by calling unloadFunction for each ExternCFunctions.
Exception that is thrown if a library or function could not be loaded.