Foreign Function Interfaces
Example Library
The Source Files
// lib.h
#ifndef __LIB__
#define __LIB__
int add( int a, int b );
#endif
// lib.c
#include "lib.h"
int add( int a, int b )
{
return a+b;
}
# Makefile
CC=gcc-12
CFLAGS=-Wall -Wextra -pedantic -std=c17
LDFLAGS=
LDLIBS=
DEPFILE=dep.mk
OBJ=lib.so
SRC=lib.c
.PHONY: all
all: $(OBJ)
.PHONY: clean
clean:
$(RM) *.o
$(RM) $(DEPFILE)
$(RM) $(OBJ)
$(OBJ): $(SRC:%.c=%.o)
$(CC) $(LDFLAGS) -shared -o $@ $(LDLIBS) $^
$(DEPFILE): $(SRC)
$(CC) -o $@ -MM -MG $^
include $(DEPFILE)
Note
Most C++ compilers apply some form of name mangling. Thus, to get a shared object file exporting the add symbol as is it is important to use a strict C compiler (in this case gcc-12).
Building and Inspecting the Library
To build the shared object file we use the make tool.
$ make
gcc-12 -o dep.mk -MM -MG lib.c
gcc-12 -Wall -Wextra -pedantic -std=c17 -c -o lib.o lib.c
gcc-12 -shared -o lib.so lib.o
To inspect the file type of the shared object file we use the file tool.
$ file lib.so
lib.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=7758d4c0a8d91c7033a6cd37bef86eb34330979c, not stripped
To list the symbols defined in the shared object file we use the nm tool. In the listing below, the -g flag filters the results so that only external symbols are listed. The -D flag displays dynamic symbols rather than normal symbols. We can see that the add symbol is indeed external.
$ nm -gD lib.so
00000000000010f9 T add
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
The readelf tool provides another way to investigate the symbols in a shared object file.
$ readelf --dyn-syms lib.so
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMC[...]
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 00000000000010f9 24 FUNC GLOBAL DEFAULT 10 add
Foreign Functions in Racket
Reading
Basic Example
#lang racket/base
(require ffi/unsafe
ffi/unsafe/define)
(define-ffi-definer define-lib (ffi-lib "lib.so"))
(define-lib add (_fun _int _int -> _int))
(add 1 2)