Call a function in a shared library

From Rosetta Code
Revision as of 20:58, 29 July 2009 by rosettacode>Dkf (→‎{{header|Tcl}}: expand on choices)
Task
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

Works with: [AutoHotkey.dll]


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

Works with: POSIX version .1-2001

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>

  1. include <stdlib.h>
  2. 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>

Library: JNA

<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"
  1. Rest of program</lang>

Smalltalk

Works with: GNU 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

Library: Ffidl

<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>

  1. import std
  2. import flo

my_replacement = fleq/0.?/~& negative

abs = math.|fabs my_replacement </lang>