Call a function in a shared library

From Rosetta Code
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.

This is a special case of calling a foreign language function where the focus is close to the ABI level and not at the normal API level.

Related tasks[edit]

  • OpenGL -- OpenGL is usually maintained as a shared library.



The following solution calls MessageBox from Windows' dynamic library user32.dll. It does not use Win32 bindings, which would be meaningless, because MessageBox is already there. Instead of that it links statically to kernel32.dll, which required to load anything under Windows. From there it uses LoadLibrary to load user32.dll and then GetProcAddress to get the MessageBox entry point there. Note how Windows mangles names of functions in the import libraries. So "LoadLibrary" becomes "[email protected]", which is its real name. "A" means ASCII. Once address of MessageBox is obtained it is converted to a pointer to a function that has an interface corresponding to it. Note Windows' call convention, which is stdcall.

with Ada.Text_IO;   use Ada.Text_IO;
with Interfaces; use Interfaces;
with Interfaces.C; use Interfaces.C;
with System; use System;
with Ada.Unchecked_Conversion;
procedure Shared_Library_Call is
-- Interface to kernel32.dll which is responsible for loading DLLs under Windows.
-- There are ready to use Win32 bindings. We don't want to use them here.
type HANDLE is new Unsigned_32;
function LoadLibrary (lpFileName : char_array) return HANDLE;
pragma Import (stdcall, LoadLibrary, "LoadLibrary", "_LoadLibraryA"); -- Ada95 does not have the @n suffix.
function GetProcAddress (hModule : HANDLE; lpProcName : char_array)
return Address;
pragma Import (stdcall, GetProcAddress, "GetProcAddress", "_GetProcAddress"); --
-- The interface of the function we want to call. It is a pointer (access type)
-- because we will link it dynamically. The function is from User32.dll
type MessageBox is access function
( hWnd  : Address  := Null_Address;
lpText  : char_array;
lpCaption : char_array  := To_C ("Greeting");
uType  : Unsigned_16 := 0
) return Integer_16;
pragma Convention (Stdcall, MessageBox);
function To_MessageBox is new Ada.Unchecked_Conversion (Address, MessageBox);
Library : HANDLE  := LoadLibrary (To_C ("user32.dll"));
Pointer : Address := GetProcAddress (Library, To_C ("MessageBoxA"));
if Pointer /= Null_Address then
Result : Integer_16;
Result := To_MessageBox (Pointer) (lpText => To_C ("Hello!"));
Put_Line ("Unable to load the library " & HANDLE'Image (Library));
end if;
end Shared_Library_Call;


Here we are using the dl library statically (-ldl switch upon linking) and Xlib dynamically ( The function dlopen loads a library. The function dlsym looks up for an entry point there. From, first XOpenDisplay is called to open an X11 display, which name is in the DISPLAY environment variable. Then XDisplayWidth of the display is obtained an printed into the standard output.

with Ada.Environment_Variables;  use Ada.Environment_Variables;
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces; use Interfaces;
with Interfaces.C; use Interfaces.C;
with System; use System;
with Ada.Unchecked_Conversion;
procedure Shared_Library_Call is
-- Interface to libdl to load dynamically linked libraries
function dlopen (FileName : char_array; Flag : int) return Address;
pragma Import (C, dlopen);
function dlsym (Handle : address; Symbol : char_array) return Address;
pragma Import (C, dlsym);
-- The interfaces of the functions we want to call. These are pointers
-- (access type) because we will link it dynamically. The functions
-- come from
type XOpenDisplay is access function (Display_Name : char_array) return Address;
pragma Convention (C, XOpenDisplay);
function To_Ptr is new Ada.Unchecked_Conversion (Address, XOpenDisplay);
type XDisplayWidth is access function (Display : Address; Screen : int) return int;
pragma Convention (C, XDisplayWidth);
function To_Ptr is new Ada.Unchecked_Conversion (Address, XDisplayWidth);
Library : Address := dlopen (To_C (""), 1);
OpenDisplay  : XOpenDisplay  := To_Ptr (dlsym (Library, To_C ("XOpenDisplay")));
DisplayWidth : XDisplayWidth := To_Ptr (dlsym (Library, To_C ("XDisplayWidth")));
if OpenDisplay /= null and then DisplayWidth /= null then
Display : Address;
Display := OpenDisplay (To_C (Value ("DISPLAY")));
if Display = Null_Address then
Put_Line ("Unable to open display " & Value ("DISPLAY"));
Put_Line (Value ("DISPLAY") & " width is" & int'image (DisplayWidth (Display, 0)));
end if;
Put_Line ("Unable to load the library");
end if;
end Shared_Library_Call;


Works with: [AutoHotkey.dll]


ahkdll := DllCall("LoadLibrary", "str", "AutoHotkey.dll")
clientHandle := DllCall("AutoHotkey\ahkdll", "str", "dllclient.ahk", "str"
, "", "str", "parameter1 parameter2", "Cdecl Int")


Msgbox, hello from client


The following shared libraries are automatically available: ADVAPI32.DLL, COMCTL32.DLL, COMDLG32.DLL, GDI32.DLL, KERNEL32.DLL, SHELL32.DLL, USER32.DLL and WINMM.DLL.

      SYS "MessageBox", @hwnd%, "This is a test message", 0, 0


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)

#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("./", 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);

The fake code is

#include <stdio.h>
/* gcc -shared -nostartfiles fakeimglib.c -o */
int openimage(const char *s)
static int handle = 100;
fprintf(stderr, "opening %s\n", s);
return handle++;

When the library 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


In Windows.

using System.Runtime.InteropServices;
class Program {
public static extern int fakefunction(int args);
static void Main(string[] args) {
int r = fakefunction(10);


Tested with GnuCOBOL, GNU/Linux.

       identification division.
program-id. callsym.
data division.
working-storage section.
01 handle usage pointer.
01 addr usage program-pointer.
procedure division.
call "dlopen" using
by reference null
by value 1
returning handle
on exception
display function exception-statement upon syserr
if handle equal null then
display function module-id ": error getting dlopen handle"
upon syserr
call "dlsym" using
by value handle
by content z"perror"
returning addr
if addr equal null then
display function module-id ": error getting perror symbol"
upon syserr
call addr returning omitted
end program callsym.
prompt$ cobc -xj callsym.cob

Common Lisp[edit]

Library: CFFI
CL-USER> (cffi:load-foreign-library "")
CL-USER> (cffi:foreign-funcall "XOpenDisplay"
:string #+sbcl (sb-posix:getenv "DISPLAY")
#-sbcl ":0.0"
#.(SB-SYS:INT-SAP #X00650FD0)


pragma(lib, "user32.lib");
import std.stdio,;
extern(Windows) UINT GetDoubleClickTime();
void main() {


Static loading[edit]

Loads library on startup.

procedure DoSomething; external 'MYLIB.DLL';

Delayed loading[edit]

Loads library on first call to DoSomething.

procedure DoSomething; external 'MYLIB.DLL' delayed;

Dynamic loading[edit]

Loads and unloads library on demand.

lLibraryHandle: THandle;
lDoSomething: procedure; stdcall;
lLibraryHandle := LoadLibrary('MYLIB.DLL');
if lLibraryHandle >= 32 then { success }
lDoSomething := GetProcAddress(lLibraryHandle, 'DoSomething');


Works on Linux with GNU gcc and gfortran 5.1.1

This is a slightly modified version of Call a foreign-language function task.

A simple "C" function add_n in add_n.c

double add_n(double* a, double* b)
return *a + *b;

compile it

gcc -c -shared -fPIC add_n.c

We can also use fortran function in the shared library which should be, however, implemented using C interoperability module.

File add_nf.f90

function add_nf(a,b) bind(c, name='add_nf')
use, intrinsic :: iso_c_binding
implicit none
real(c_double), intent(in) :: a,b
real(c_double) :: add_nf
add_nf = a + b
end function add_nf

Compile it

gfortran -c -shared -fPIC add_nf.f90

create shared library containing two functions "add_n" and "add_nf"

gcc -shared -fPIC add_nf.o add_n.o -o

Using C binding load and call functions add_n, add_nf dynamically.

File shared_lib_new_test.f90

!module dll_module
module dll_module
use iso_c_binding
implicit none
private ! all by default
public :: os_type, dll_type, load_dll, free_dll, init_os_type, init_dll
! general constants:
! the number of bits in an address (32-bit or 64-bit).
integer, parameter :: bits_in_addr = c_intptr_t*8
! global error-level variables:
integer, parameter :: errid_none = 0
integer, parameter :: errid_info = 1
integer, parameter :: errid_warn = 2
integer, parameter :: errid_severe = 3
integer, parameter :: errid_fatal = 4
integer :: os_id
type os_type
character(10) :: endian
character(len=:), allocatable :: newline
character(len=:), allocatable :: os_desc
character(1) :: pathsep
character(1) :: swchar
character(11) :: unfform
end type os_type
type dll_type
integer(c_intptr_t) :: fileaddr
type(c_ptr) :: fileaddrx
type(c_funptr) :: procaddr
character(1024) :: filename
character(1024) :: procname
end type dll_type
! interface to linux API
function dlopen(filename,mode) bind(c,name="dlopen")
! void *dlopen(const char *filename, int mode);
use iso_c_binding
implicit none
type(c_ptr) :: dlopen
character(c_char), intent(in) :: filename(*)
integer(c_int), value :: mode
end function
function dlsym(handle,name) bind(c,name="dlsym")
! void *dlsym(void *handle, const char *name);
use iso_c_binding
implicit none
type(c_funptr) :: dlsym
type(c_ptr), value :: handle
character(c_char), intent(in) :: name(*)
end function
function dlclose(handle) bind(c,name="dlclose")
! int dlclose(void *handle);
use iso_c_binding
implicit none
integer(c_int) :: dlclose
type(c_ptr), value :: handle
end function
end interface
!Subroutine init_dll
subroutine init_dll(dll)
implicit none
type(dll_type), intent(inout) :: dll
dll % fileaddr = 0
dll % fileaddrx = c_null_ptr
dll % procaddr = c_null_funptr
dll % filename = " "
dll % procname = " "
end subroutine init_dll
!Subroutine init_os_type
subroutine init_os_type(os_id,os)
implicit none
integer, intent(in) :: os_id
type(os_type), intent(inout) :: os
select case (os_id)
case (1) ! Linux
os % endian = 'big_endian'
os % newline = achar(10)
os % os_desc = 'Linux'
os % pathsep = '/'
os % swchar = '-'
os % unfform = 'unformatted'
case (2) ! MacOS
os % endian = 'big_endian'
os % newline = achar(10)
os % os_desc = 'MacOS'
os % pathsep = '/'
os % swchar = '-'
os % unfform = 'unformatted'
case default
end select
end subroutine init_os_type
!Subroutine load_dll
subroutine load_dll (os, dll, errstat, errmsg )
! this subroutine is used to dynamically load a dll.
type (os_type), intent(in) :: os
type (dll_type), intent(inout) :: dll
integer, intent( out) :: errstat
character(*), intent( out) :: errmsg
integer(c_int), parameter :: rtld_lazy=1
integer(c_int), parameter :: rtld_now=2
integer(c_int), parameter :: rtld_global=256
integer(c_int), parameter :: rtld_local=0
errstat = errid_none
errmsg = ''
select case (os%os_desc)
case ("Linux","MacOS")
! load the dll and get the file address:
dll%fileaddrx = dlopen( trim(dll%filename)//c_null_char, rtld_lazy )
if( .not. c_associated(dll%fileaddrx) ) then
errstat = errid_fatal
write(errmsg,'(i2)') bits_in_addr
errmsg = 'the dynamic library '//trim(dll%filename)//' could not be loaded. check that the file '// &
'exists in the specified location and that it is compiled for '//trim(errmsg)//'-bit systems.'
end if
! get the procedure address:
dll%procaddr = dlsym( dll%fileaddrx, trim(dll%procname)//c_null_char )
if(.not. c_associated(dll%procaddr)) then
errstat = errid_fatal
errmsg = 'the procedure '//trim(dll%procname)//' in file '//trim(dll%filename)//' could not be loaded.'
end if
case ("Windows")
errstat = errid_fatal
errmsg = ' load_dll not implemented for '//trim(os%os_desc)
case default
errstat = errid_fatal
errmsg = ' load_dll not implemented for '//trim(os%os_desc)
end select
end subroutine load_dll
!Subroutine free_dll
subroutine free_dll (os, dll, errstat, errmsg )
! this subroutine is used to free a dynamically loaded dll
type (os_type), intent(in) :: os
type (dll_type), intent(inout) :: dll
integer, intent( out) :: errstat
character(*), intent( out) :: errmsg
integer(c_int) :: success
errstat = errid_none
errmsg = ''
select case (os%os_desc)
case ("Linux","MacOS")
! close the library:
success = dlclose( dll%fileaddrx )
if ( success /= 0 ) then
errstat = errid_fatal
errmsg = 'the dynamic library could not be freed.'
errstat = errid_none
errmsg = ''
end if
case ("Windows")
errstat = errid_fatal
errmsg = ' free_dll not implemented for '//trim(os%os_desc)
case default
errstat = errid_fatal
errmsg = ' free_dll not implemented for '//trim(os%os_desc)
end select
end subroutine free_dll
end module dll_module
!Main program
program test_load_dll
use, intrinsic :: iso_c_binding
use dll_module
implicit none
! interface to our shared lib
abstract interface
function add_n(a,b)
use, intrinsic :: iso_c_binding
implicit none
real(c_double), intent(in) :: a,b
real(c_double) :: add_n
end function add_n
end interface
type(os_type) :: os
type(dll_type) :: dll
integer :: errstat
character(1024) :: errmsg
type(c_funptr) :: cfun
procedure(add_n), pointer :: fproc
call init_os_type(1,os)
call init_dll(dll)
! name of the procedure in shared_lib
! c version of the function
write(*,*) "address: ", dll%procaddr
call load_dll(os, dll, errstat, errmsg )
write(*,*)"load_dll: errstat=", errstat
write(*,*) "address: ", dll%procaddr
call c_f_procpointer(dll%procaddr,fproc)
write(*,*) "add_n(2,5)=",fproc(2.d0,5.d0)
call free_dll (os, dll, errstat, errmsg )
write(*,*)"free_dll: errstat=", errstat
! fortran version
call load_dll(os, dll, errstat, errmsg )
write(*,*)"load_dll: errstat=", errstat
write(*,*) "address: ", dll%procaddr
call c_f_procpointer(dll%procaddr,fproc)
write(*,*) "add_nf(2,5)=",fproc(2.d0,5.d0)
call free_dll (os, dll, errstat, errmsg )
write(*,*)"free_dll: errstat=", errstat
end program test_load_dll

Compile test program

gfortran shared_lib_new_test.f90 -ldl -o shared_lib_new_test.x



 address:                     0
 load_dll: errstat=           0
 address:        47476893497132
 add_n(2,5)=   7.0000000000000000     
 free_dll: errstat=           0
 load_dll: errstat=           0
 address:        47476893497088
 add_nf(2,5)=   7.0000000000000000     
 free_dll: errstat=           0

Finally, using C language interoperability you can call every foreign-language function in fortran if you are able to write some additional wrapper function in C language.


Most of this was borrowed from Call a foreign-language function#J

require 'dll'
strdup=: 'msvcrt.dll _strdup >x *' cd <
free=: 'msvcrt.dll free n x' cd <
getstr=: free ] memr@,&0 _1
DupStr=:verb define
[email protected] y

You get a domain error when the required library is not present at run time. A try/catch will let you handle this (as would the :: adverse operator).

Example use:

   DupStr 'hello'
[email protected] ::] 'hello'


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.

public class LoadLib{
private static native void functionInSharedLib(); //change return type or parameters as necessary
public static void main(String[] args){
Library: JNA
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"


Julia has the `ccall` function which follows the form: ccall((symbol, library), RetType, (ArgType1, ...), ArgVar1, ...)

#this example works on Windows
ccall( (:GetDoubleClickTime, "User32"), stdcall,
Uint, (), )
ccall( (:clock, "libc"), Int32, ())

For more information, see here [1]


> cfloor := define_external( floor, s::float[8], RETURN::float[8], LIB = "" ):
> cfloor( 2.3 );


This works on windows and on linux/mac too (through Mono)

externalFloor = DefineDLLFunction["floor", "msvcrt.dll", "double", { "double" }];
-> 4.


Interacting with C code[edit]

proc openimage(s: cstring): cint {.importc, dynlib: "./".}
echo openimage("foo")
echo openimage("bar")
echo openimage("baz")

The fake code is

#include <stdio.h>
/* gcc -shared -nostartfiles fakeimglib.c -o */
int openimage(const char *s)
static int handle = 100;
fprintf(stderr, "opening %s\n", s);
return handle++;


opening foo
opening bar
opening baz

Interacting with Nim code[edit]

proc openimage(s: string): int {.importc, dynlib: "./".}
echo openimage("foo")
echo openimage("bar")
echo openimage("baz")

The fake code is

# nim c --app:lib fakeimg.nim
var handle = 100
proc openimage*(s: string): int {.exportc, dynlib.} =
stderr.writeln "opening ", s
result = handle


opening foo
opening bar
opening baz


As far as I know there is no solution in OCaml standard library to load a function from a C library dynamically. So I have quickly implemented a module named Dlffi that you can find in this sub-page. It is basically a wrapper around the GNU/Linux dl* functions and the libffi.

On Windows there is FlexDLL.

Here is an example of use of this Dlffi module:

open Dlffi
let get_int = function Int v -> v | _ -> failwith "get_int"
let get_ptr = function Ptr v -> v | _ -> failwith "get_ptr"
let get_float = function Float v -> v | _ -> failwith "get_float"
let get_double = function Double v -> v | _ -> failwith "get_double"
let get_string = function String v -> v | _ -> failwith "get_string"
let () =
(* load the library *)
let xlib = dlopen "/usr/lib/" [RTLD_LAZY] in
(* load the functions *)
let _open_display = dlsym xlib "XOpenDisplay"
and _default_screen = dlsym xlib "XDefaultScreen"
and _display_width = dlsym xlib "XDisplayWidth"
and _display_height = dlsym xlib "XDisplayHeight"
(* wrap functions to provide a higher level interface *)
let open_display ~name = get_ptr(fficall _open_display [| String name |] Return_ptr)
and default_screen ~dpy = get_int(fficall _default_screen [| (Ptr dpy) |] Return_int)
and display_width ~dpy ~scr = get_int(fficall _display_width [| (Ptr dpy); (Int scr) |] Return_int)
and display_height ~dpy ~scr = get_int(fficall _display_height [| (Ptr dpy); (Int scr) |] Return_int)
(* use our functions *)
let dpy = open_display ~name:":0" in
let screen_number = default_screen ~dpy in
let width = display_width ~dpy ~scr:screen_number
and height = display_height ~dpy ~scr:screen_number in
Printf.printf "# Screen dimensions are: %d x %d pixels\n" width height;
dlclose xlib;


'Loading a shared library at run time and calling a function.
declare MessageBox(sys hWnd, String text,caption, sys utype)
sys user32 = LoadLibrary "user32.dll"
if user32 then @Messagebox = getProcAddress user32,"MessageBoxA"
if @MessageBox then MessageBox 0,"Hello","OxygenBasic",0
FreeLibrary user32



where "G" is the parser code; see section 5.7.3 in the User's Guide to the PARI library for more information.


See Delphi

Perl 6[edit]

Works with: Rakudo version 2015.12
use NativeCall;
constant libX11 = '/usr/lib/x86_64-linux-gnu/';
sub XOpenDisplay(Str $s --> Int) is native(libX11) {*}
sub XCloseDisplay(Int $i --> Int) is native(libX11) {*}
if try my $d = XOpenDisplay ":0.0" {
say "ID = $d";
else {
say "No library {libX11}!";
say "Use this window instead --> ⬜";
ID = 124842864


This differs between the 32-bit and 64-bit versions. While the 64-bit version can interface directly to C functions (in external libraries or not), requires the 32-bit function some glue code.

32-bit version[edit]

For the 32-bit version, we need some glue code:

(load "@lib/gcc.l")
(gcc "x11" '("-lX11") 'xOpenDisplay 'xCloseDisplay)
#include <X11/Xlib.h>
any xOpenDisplay(any ex) {
any x = evSym(cdr(ex)); // Get display name
char display[bufSize(x)]; // Create a buffer for the name
bufString(x, display); // Upack the name
return boxCnt((long)XOpenDisplay(display));
any xCloseDisplay(any ex) {
return boxCnt(XCloseDisplay((Display*)evCnt(ex, cdr(ex))));
# With that we can open and close the display:
: (setq Display (xOpenDisplay ":0.7")) # Wrong
-> 0
: (setq Display (xOpenDisplay ":0.0")) # Correct
-> 158094320
: (xCloseDisplay Display)
-> 0

64-bit version[edit]

In the 64-bit version, we can call the library directly:

: (setq Display (native "/usr/lib/" "XOpenDisplay" 'N ":0.0"))
-> 6502688
: (native "/usr/lib/" "XCloseDisplay" 'I Display)
-> 0


In this example, if the library can't be found (user32), or the desired function in the library (MessageBoxA), the equivalent built-in function (MSGBOX) is at the "epicFail" label... but really, if you can't find user32.dll, you've got bigger things to worry about.

DIM msg AS ASCIIZ * 14, titl AS ASCIIZ * 8
hWnd = LoadLibrary ("user32")
msg = "Hello, world!"
titl = "Example"
funcAddr& = GetProcAddress (hWnd, "MessageBoxA")
IF ISTRUE (funcAddr&) THEN
ASM push 0&
tAdr& = VARPTR(titl)
ASM push tAdr&
mAdr& = VARPTR(msg)
ASM push mAdr&
ASM push 0&
CALL DWORD funcAddr&
GOTO epicFail
GOTO epicFail
GOTO getMeOuttaHere
MSGBOX msg, , titl
tmp& = FreeLibrary (hWnd)
IF ISFALSE(tmp&) THEN MSGBOX "Error freeing library... [shrug]"


Older PureBasic versions normally relied on CallFunction() and CallFunctionFast()

if OpenLibrary(0, "USER32.DLL")
*MessageBox = GetFunction(0, "MessageBoxA")
CallFunctionFast(*MessageBox, 0, "Body", "Title", 0)

Since versions 4 the recommended way is via the usage of Prototypes even if the old system still is supported.

Prototype.l ProtoMessageBoxW(Window.l, Body.p-unicode, Title.p-unicode, Flags.l = 0)
If OpenLibrary(0, "User32.dll")
MsgBox.ProtoMessageBoxW = GetFunction(0, "MessageBoxW")
MsgBox(0, "Hello", "World")


Example that call User32.dll::GetDoubleClickTime() in windows.

import ctypes
user32_dll = ctypes.cdll.LoadLibrary('User32.dll')
print user32_dll.GetDoubleClickTime()


This is possible in R in only a few limited ways. If the library function one wishes to call is a (C-level) R function (of type SEXP), then one may call

.Call("my_lib_fun", arg1, arg2)

It is also possible to use .C() and .Fortran() to call voids and subroutines respectively; here the return value(s) should be in the argument list (rather than merely modifying state). An example of this might look like

.C("my_lib_fun", arg1, arg2, ret)

The return of the .C() function is an R list.


#lang racket
(require ffi/unsafe)
(define libm (ffi-lib "libm")) ; get a handle for the C math library
; look up sqrt in the math library. if we can't find it, return the builtin sqrt
(define extern-sqrt (get-ffi-obj 'sqrt libm (_fun _double -> _double)
(lambda () sqrt)))
> (extern-sqrt 42.0)


Works with: Regina REXX

The example is using the standard library that is supplied with Regina REXX that contains a wide range of functions.

/*REXX pgm calls a function (systextscreensize) in a shared library (regutil).*/
z=rxfuncadd('sysloadfuncs', "regutil", 'sysloadfuncs') /*add a function lib.*/
if z\==0 then do /*test the return cod*/
say 'return code' z "from rxfuncadd" /*tell about bad RC. */
exit z /*exit this program. */
call sysloadfuncs /*load the functions.*/
/* [↓] call a particular function. */
y=systextscreensize() /*Y now contains 2 numbers: rows cols */
parse var y rows cols . /*obtain the two numeric words in Y. */
say 'rows=' rows /*display the number of (terminal) rows*/
say 'cols=' cols /* " " " " " cols*/
call SysDropFuncs /*clean up: make functions inaccessible*/
/*stick a fork in it, we're all done. */

output   (which happens to reflect the program's author's particular screen size for the "DOS" window):

rows= 62
cols= 86


Using the standard
Library: Ruby/DL
require 'dl/import'
FakeImgLib = DL.dlopen("/path/to/")
module FakeImage
def self.openimage filename
FakeImgLib["openimage", "IS"].call(filename)[0]
handle = FakeImage.openimage("path/to/image")
Using the nicer
Library: RubyGems
package ffi, following C example
require 'ffi'
module FakeImgLib
extend FFI::Library
ffi_lib "path/to/"
attach_function :openimage, [:string], :int
handle = FakeImgLib.openimage("path/to/image")



Get free disk space[edit]

import com.sun.jna.ptr.IntByReference
object GetDiskFreeSpace extends App with SNA {
snaLibrary = "Kernel32" // Native library name
* Important Note!
* The val holding the SNA-returned function must have the same name as the native function itself
* (see line following this comment). This is the only place you specify the native function name.

val GetDiskFreeSpaceA = SNA[String, IntByReference, IntByReference, IntByReference, IntByReference, Boolean]
// This Windows function is described here:
val (disk, spc, bps, fc, tc) = ("C:\\",
new IntByReference, // Sectors per cluster
new IntByReference, // Bytes per sector
new IntByReference, // Free clusters
new IntByReference) // Total clusters
val ok = GetDiskFreeSpaceA(disk, spc, bps, fc, tc) // status
println(f"'$disk%s' ($ok%s): sectors/cluster: ${spc.getValue}%d, bytes/sector: ${bps.getValue}%d, " +
f" free-clusters: ${fc.getValue}%d, total/clusters: ${tc.getValue}%d%n")


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)

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


Library: Ffidl
package require Ffidl
if {[catch {
ffidl::callout OpenImage {pointer-utf8} int [ffidl::symbol openimage]
}]} then {
# Create the OpenImage command by other means here...
set handle [OpenImage "/the/file/name"]

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.


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.

#import std
#import flo
my_replacement = fleq/0.?/~& negative
abs = math.|fabs my_replacement


In zkl, extensions/new objects are written in C as shared libraries. For example, big nums are implemented as a small glue library in front of GMP:

var BN=Import("zklBigNum");
BN(1)+2 //--> BN(3)

and it "just works" as all objects are "the same" whether statically or dynamically linked.

FFI is supported by another DLL/so. For all but pedantic examples, very ugly (like most FFIs), so no example.