guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Dynamic Foreign Function Interface with dynamic-link*


From: Amirouche Boubekki
Subject: Dynamic Foreign Function Interface with dynamic-link*
Date: Sun, 21 Feb 2016 16:28:01 +0100
User-agent: Roundcube Webmail/1.1.2

Héllo everyone!


I created a `dynamic-link*` procedure to help during the creation of
dynamic ffi bindings (which is the prefered way to go now on).

It's helpful for several reasons:

- no need to explicitly call `dynamic-func` and `pointer->procedure`,
  so it's two less procedures to know about.

- It mimicks the C signature, so it's easier to read.

This documentation is meant to be self sufficient which means that you
should be able to fully bind your favorite *function based* C library
just by reading this.

The code of the procedure is at the bottom.

## `((dynamic-link* [library-name]) return-type function-name . arguments)`

Return a lambda that returns a scheme procedure linked against
FUNCTION-NAME found in LIBRARY-NAME. If LIBRARY-NAME is not provided
this links against the C standard library.

The returned procedure takes the signature of the function that you
want to link against.

RETURN-TYPE and ARGUMENTS must be foreign types. They can be found in
`(system foreign)` [1]:

- int8
- uint8
- uint16
- int16
- uint32
- int32
- uint64
- int64
- float
- double

In addition, platform-dependent types variables exists:

- int
- unsigned-int
- long
- unsigned-long
- size_t
- ssize_t
- ptrdiff_t

There is also a `void` variable that must be used to wrap
function that returns nothing.

Last but not least, the symbol `'*` is used by convention
to denote pointer types.

[1] https://www.gnu.org/software/guile/manual/html_node/Foreign-Types.html#Foreign-Types

## Example

Here is a REPL run, showing how it works:

```scheme
(define stdlib (dynamic-link*))  ;; link against stdlib
(define strlen (stdlib int "strlen" '*)) ;; retrieve a procedure associated to "strlen"
(strlen (string->pointer "abc"))
```

Since you probably don't want to expose the pointer api
to the dev. You might define the following `strlen` procedure:

```scheme
(define stdlib (dynamic-link*))  ;; link against stdlib

(define (strlen string)
(let ((function (stdlib (int "strlen" '*)))) ;; retrieve strlen function as a procedure
  (function (string->pointer string))))
```

AFAIK, there is no performance gain in memoizing `stdlib`.

## Where to go from here?

If you need to bind structures the proper way to go is to use scheme
bytestructures [2].

[2] https://github.com/TaylanUB/scheme-bytestructures

## The code

```scheme
(use-modules (system foreign))

(define* (dynamic-link* #:optional library-name)
(let ((shared-object (if library-name (dynamic-link library-name) (dynamic-link))))
    (lambda (return-value function-name . arguments)
      (let ((function (dynamic-func function-name shared-object)))
        (pointer->procedure return-value function arguments)))))
```

HTH!

--
Amirouche ~ amz3 ~ http://www.hypermove.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]