From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Amirouche Boubekki Newsgroups: gmane.lisp.guile.user Subject: Dynamic Foreign Function Interface with dynamic-link* Date: Sun, 21 Feb 2016 16:28:01 +0100 Message-ID: <474768c2a6bf720e5cc91402628aa8bc@hypermove.net> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1456068514 12298 80.91.229.3 (21 Feb 2016 15:28:34 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 21 Feb 2016 15:28:34 +0000 (UTC) To: Guile User Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Sun Feb 21 16:28:26 2016 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1aXVvp-0006gK-8n for guile-user@m.gmane.org; Sun, 21 Feb 2016 16:28:21 +0100 Original-Received: from localhost ([::1]:41805 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXVvo-0004ZQ-LT for guile-user@m.gmane.org; Sun, 21 Feb 2016 10:28:20 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:56795) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXVve-0004ZJ-Sk for guile-user@gnu.org; Sun, 21 Feb 2016 10:28:12 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aXVvZ-0002vY-Sj for guile-user@gnu.org; Sun, 21 Feb 2016 10:28:10 -0500 Original-Received: from relay3-d.mail.gandi.net ([2001:4b98:c:538::195]:37982) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXVvZ-0002vK-M4 for guile-user@gnu.org; Sun, 21 Feb 2016 10:28:05 -0500 Original-Received: from mfilter17-d.gandi.net (mfilter17-d.gandi.net [217.70.178.145]) by relay3-d.mail.gandi.net (Postfix) with ESMTP id 576B3A80CE for ; Sun, 21 Feb 2016 16:28:04 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mfilter17-d.gandi.net Original-Received: from relay3-d.mail.gandi.net ([IPv6:::ffff:217.70.183.195]) by mfilter17-d.gandi.net (mfilter17-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id wy-0kxGVLlYR for ; Sun, 21 Feb 2016 16:28:02 +0100 (CET) X-Originating-IP: 10.58.1.142 Original-Received: from webmail.gandi.net (webmail2-d.mgt.gandi.net [10.58.1.142]) (Authenticated sender: amirouche@hypermove.net) by relay3-d.mail.gandi.net (Postfix) with ESMTPA id 93C31A809B for ; Sun, 21 Feb 2016 16:28:01 +0100 (CET) X-Sender: amirouche@hypermove.net User-Agent: Roundcube Webmail/1.1.2 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:4b98:c:538::195 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: guile-user-bounces+guile-user=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.user:12420 Archived-At: 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