unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Matt Wette <matt.wette@gmail.com>
To: guile-devel <guile-devel@gnu.org>
Subject: ffi-help: status to date
Date: Sun, 22 Oct 2017 11:31:27 -0700	[thread overview]
Message-ID: <47398F30-BD71-43ED-B9A0-DA86CCCA4D40@gmail.com> (raw)
In-Reply-To: <84325B67-FE0B-4802-861B-0FC50D7CB5D7@gmail.com>

Hi All,

I am working on a ffi-helper (FH): a program that will read in a C dot-h file and generate a Guile dot-scm file 
which defines a module to provide hooks into the associated C library.  

Since last report I have removed the un-hygienic macros: all names are passed to macros now.  This makes
the generated Scheme code about double the size it was before, but so what.  Also, the "wrap" and "unwrap"
functions are now mostly hidden: they should not be needed directly by the user.

I am fine-tuning the type handling.  Note:
1) In Scheme we need to have something that represents the pointer types.  When the FH sees a C type like
   typedef struct { ... } foo_t then the it generates SCM types for foo_t and foo_t*, a pointer-to-foo_t type.
   These types are connected to that (pointer-to <obj>) for an object of type foo_t generates a foo_t* object.
2) The FH does not generate types for numerics: typedef int int_t; is just left alone, but wrappers are used
   to convert numerics.
3) The FH does not generate types for typedef enum { ... } enum_t;
4) I am using the bytestructures package from Taylan UB (github-dot-com/TaylanUB/scheme-bytestructures).
5) I have developed a function pseudo-descriptor for bytestructures so that (bs:pointer (fh:function ...))
   provides a way to deal with function pointers in structs.  Passing Scheme procedures as arguments to 
   pointer->procedure generated procedures works also.

Issues:
1) I am still working on a solution to functions w/ varargs.  I believe I have a solution for calling C vararg
   functions from Guile: the user provides casts for extra args, e.g., (printf "the value is %d\n" (fh-cast int 4)).
   The implementation will take a bit of work.
2) clean up some inefficiencies.  Not going into details here
3) Documentation:  This will have to be good because the FFI helper is not bullet proof.  Sometimes one needs
   to add extra pointer-types etc in the dot-ffi module, and there needs to be a document to help the user go
   through the process of finding the reason for error messages and how to add code to get things working.
4) Maybe a C to Guile C-SMOB generated is needed also.  The gtk2+ dot-go file is now ~ 20 MB.

I was able to generate scm code for glib, gobject, gio, pango, and gtk2+.  The following demo code actually works.
I get a GUI and click the button and it closes, though with an error message:
    gtkdemo.scm:16:0: Wrong number of arguments to #<procedure hello (widget data)>

The code is being worked in the c99dev branch of nyacc, hosted on https://savannah.nongnu.org/projects/nyacc.

#!/opt/local/bin/guile
!#

;; https://developer.gnome.org/gtk-tutorial/stable/c39.html#SEC-HELLOWORLD

(use-modules (ffi glib))
(use-modules (ffi gobject))
(use-modules (ffi gtk2+))
(use-modules (bytestructures guile))
(use-modules (system ffi-help-rt))
(use-modules ((system foreign) #:prefix ffi:))

(define NULL ffi:%null-pointer)

(define (hello widget data)
  ;;(g_print "Hello World!\n")
  (display "Hello World!\n")
  )

(define (delete-event widget event data)
  (display "delete event occurred\n")
  1)

(define (destroy widget data)
  (gtk_main_quit))

(define (main)
  (define window #f)
  (define button #f)
  (define argc (bytestructure int 0))

  (gtk_init (pointer-to argc) NULL)

  (set! window (gtk_window_new 'GTK_WINDOW_TOPLEVEL))
  (g_signal_connect window "delete-event" delete-event NULL)
  (g_signal_connect window "destroy" destroy NULL)
  (gtk_container_set_border_width window 10)

  (set! button (gtk_button_new_with_label "Hello World"))
  (g_signal_connect button "clicked" hello NULL)
  (g_signal_connect_swapped button "clicked" gtk_widget_destroy window)
  (gtk_container_add window button)

  (gtk_widget_show button)
  (gtk_widget_show window)

  (gtk_main))

;; --- last line ---

And here, for example, is the FFI module for gtk2+ and gobject:
;; gtk2+.ffi				-*- Scheme -*-

(define-ffi-module (ffi gtk2+)
  #:pkg-config "gtk+-2.0"
  #:include '("gtk/gtk.h")
  #:inc-filter (lambda (f p) (string-contains p "gtk/" 0))
  #:use-ffi-module (ffi gdk2)
  #:use-ffi-module (ffi pango)
  #:use-ffi-module (ffi gobject)
  #:use-ffi-module (ffi glib)
  )

(define-fh-pointer-type GtkEnumValue* int*-desc
  GtkEnumValue*? make-GtkEnumValue*)
(export GtkEnumValue* GtkEnumValue*? make-GtkEnumValue*)
  
;; --- last line ---

;; gobject.ffi				-*- Scheme -*-

(define-ffi-module (ffi gobject)
  #:use-ffi-module (ffi glib)
  #:pkg-config "gobject-2.0"
  #:include '("glib-object.h")
  #:inc-filter (lambda (file-spec path-spec)
		 (string-contains path-spec "gobject/" 0))
  #:use-module ((system foreign) #:prefix ffi: #:select(%null-pointer))
  )

(define NULL ffi:%null-pointer)

(define-public (g_signal_connect instance detailed_signal c_handler data)
  (g_signal_connect_data instance detailed_signal c_handler data NULL 0))

(define-public (g_signal_connect_after instance detailed_signal c_handler data)
  (g_signal_connect_data instance detailed_signal c_handler data NULL
			 'G_CONNECT_AFTER))

(define-public (g_signal_connect_swapped instance detailed_signal c_handler
					 data)
  (g_signal_connect_data instance detailed_signal c_handler data NULL
			 'G_CONNECT_SWAPPED))

;; --- last line ---

; pango.ffi                            -*- Scheme -*-

(define-ffi-module (ffi pango)
  #:pkg-config "pango"
  #:include '("pango/pango.h")
  #:inc-filter (lambda (f p) (string-contains p "pango/" 0))
  #:use-ffi-module (ffi glib)
  #:use-ffi-module (ffi gobject)
  )

;; PangoScript is an enum.  Some routines return pointer to int for this.
(define-public wrap-PangoScript* (fht-wrap int*))

;; --- last line ---




  parent reply	other threads:[~2017-10-22 18:31 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-03 17:25 ffi-help: documentation Matt Wette
2017-08-19 15:30 ` ffi-help: status to 19 Aug 2017 Matt Wette
2017-09-08  3:32   ` ffi-help: #:use-ffi-module Matt Wette
2017-09-08  3:40     ` Matt Wette
2017-10-22 18:31     ` Matt Wette [this message]
2017-10-25  0:18       ` ffi-help: status to date Matt Wette
2017-11-09 19:10   ` ffi-help: status to 19 Aug 2017 Roel Janssen
2017-11-10  1:00     ` Matt Wette
2017-11-10  2:34       ` Matt Wette
2017-11-10  2:39     ` Matt Wette
2017-11-10 23:04       ` Stefan Israelsson Tampe
2017-11-11  4:38         ` Matt Wette
2017-11-14 18:06     ` Ricardo Wurmus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47398F30-BD71-43ED-B9A0-DA86CCCA4D40@gmail.com \
    --to=matt.wette@gmail.com \
    --cc=guile-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).