Call a function in a shared library
You are encouraged to solve this task according to the task description, using any language you may know.
Show how to call a function in a shared library (without dynamically linking to it at compile-time). In particular, show how to call the shared library function if the library is available, otherwise use an internal equivalent function.
AutoHotkey
dllhost.ahk <lang AutoHotkey> ahkdll := DllCall("LoadLibrary", "str", "AutoHotkey.dll") clientHandle := DllCall("AutoHotkey\ahkdll", "str", "dllclient.ahk", "str" , "", "str", "parameter1 parameter2", "Cdecl Int") </lang> dllclient.ahk <lang AutoHotkey> Msgbox, hello from client </lang>
C
Tested with gcc on a GNU/Linux system (on GNU/Linux dl*
functions are available linking to libdl, i.e. with -ldl option)
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <dlfcn.h>
int myopenimage(const char *in) {
static int handle=0; fprintf(stderr, "internal openimage opens %s...\n", in); return handle++;
}
int main() {
void *imglib; int (*extopenimage)(const char *); int imghandle;
imglib = dlopen("./fakeimglib.so", RTLD_LAZY); if ( imglib != NULL ) { /* extopenimage = (int (*)(const char *))dlsym(imglib,...) "man dlopen" says that C99 standard leaves casting from "void *" to a function pointer undefined. The following is the POSIX.1-2003 workaround found in man */ *(void **)(&extopenimage) = dlsym(imglib, "openimage"); /* the following works with gcc, gives no warning even with -Wall -std=c99 -pedantic options... :D */ /* extopenimage = dlsym(imglib, "openimage"); */ imghandle = extopenimage("fake.img"); } else { imghandle = myopenimage("fake.img"); } printf("opened with handle %d\n", imghandle); /* ... */ if (imglib != NULL ) dlclose(imglib); return EXIT_SUCCESS;
}</lang>
The fake fakeimglib.so code is
<lang c>#include <stdio.h> /* gcc -shared -nostartfiles fakeimglib.c -o fakeimglib.so */ int openimage(const char *s) {
static int handle = 100; fprintf(stderr, "opening %s\n", s); return handle++;
}</lang>
When the library fakeimglib.c exists in the current directory (this choice is senseful only for testing purposes), the output is:
opening fake.img opened with handle 100
otherwise the output is:
internal openimage opens fake.img... opened with handle 0
C#
In Windows.
<lang csharp>using System.Runtime.InteropServices;
class Program {
[DllImport("fakelib.dll")] public static extern int fakefunction(int args);
static void Main(string[] args) { int r = fakefunction(10); }
}</lang>
Java
The native keyword is the key here. For this method, the library must be written to the Java Native Interface; this is not a general FFI. <lang java>public class LoadLib{
private static native void functionInSharedLib(); //change return type or parameters as necessary
public static void main(String[] args){ System.loadLibrary("Path/to/library/here/lib.dll"); functionInSharedLib(); }
}</lang>
<lang java>import com.sun.jna.Library; import com.sun.jna.Native;
public class LoadLibJNA{
private interface YourSharedLibraryName extends Library{ //put shared library functions here with no definition public void sharedLibraryfunction(); }
public static void main(String[] args){ YourSharedLibraryName lib = (YourSharedLibraryName )Native.loadLibrary("sharedLibrary",//as in "sharedLibrary.dll" YourSharedLibraryName.class); lib.sharedLibraryFunction(); }
}</lang>
Python
The import statement can be done in a try/except block <lang python>try:
import psyco psyco.full() print "# With psyco JIT compiler"
except:
print "# Without psyco JIT compiler"
- Rest of program</lang>
Smalltalk
The code tries to load the fakeimglib (cfr C example); if it succeed, the symbol openimage will exist, and will be called; otherwise, it is executed an "internal" code for openimage. In this example return code of the function of the library is ignored (ValueHolder null)
<lang smalltalk>DLD addLibrary: 'fakeimglib'.
Object subclass: ExtLib [
ExtLib class >> openimage: aString [ (CFunctionDescriptor isFunction: 'openimage') ifTrue: [ (CFunctionDescriptor for: 'openimage' returning: #int withArgs: #( #string ) ) callInto: (ValueHolder null). ] ifFalse: [ ('internal open image %1' % { aString }) displayNl ] ]
].
ExtLib openimage: 'test.png'.</lang>
Tcl
<lang Tcl>package require Ffidl
if {[catch {
ffidl::callout OpenImage {pointer-utf8} int [ffidl::symbol fakeimglib.so openimage]
}]} then {
# Create the OpenImage command by other means here...
}
set handle [OpenImage "/the/file/name"]</lang>
Note that if the library is appropriately set up with the correct entry function, it can be accessed directly with load
which will cause it to register a Tcl command for the functionality it exports. SWIG can be used to automatically generate the interface code. Alternatively, critcl can be used to allow writing glue C code directly embedded within a Tcl script.
With this many ways to perform the call, the best approach often depends on the size and complexity of the API being mapped. SWIG excels at large APIs, Ffidl is better when you just want to call a particular simple function, and critcl handles complex cases (callbacks, etc.) better than the other two.
Ursala
When abs(x) is evaluated, a run time check is performed for the availability of the system library's absolute value function (fabs), and if found, it is used. If not, the user defined replacement function is invoked. <lang Ursala>
- import std
- import flo
my_replacement = fleq/0.?/~& negative
abs = math.|fabs my_replacement </lang>