[cffi-devel] Help needed: Tcl/Tk via CFFI (OSX 10.4.6 Intel, AllegroCL)
![](https://secure.gravatar.com/avatar/9fda7fbd6217f4d84a55e5c5b48a2106.jpg?s=120&d=mm&r=g)
Hi! Thanks for looking into this ... I want to call the functions Tcl_CreateInterp and Tcl_Eval from Lisp. So I defined the libs and the functions : CODE: (in-package :cl-user) (defpackage :org.gt.test.cffi-tcltk (:use #:common-lisp) (:nicknames :gt.cffi-tcltk) (:export #:test-it ;; test function )) (in-package #:org.gt.test.cffi-tcltk) (eval-when (:load-toplevel :compile-toplevel :execute) #+asdf (progn #-cffi (progn (asdf:operate 'asdf:load-op :cffi) (use-package :cffi)) ) ) (eval-when (:load-toplevel :execute) (progn (define-foreign-library Tcl (:darwin (:framework "Tcl"))) (define-foreign-library Tk (:darwin (:framework "Tk"))) ) ) (eval-when (:load-toplevel :compile :execute) (progn ;; See also: ;; http://aspn.activestate.com/ASPN/docs/ActiveTcl_/8.4/tcl/ TclLib/Eval.htm ;; Tcl_CreateInterp (defcfun ("Tcl_CreateInterp" %Tcl_CreateInterp) :pointer) (defun Tcl_CreateInterp () (%Tcl_CreateInterp)) ;; Tcl_EvalFile (defcfun ("Tcl_EvalFile" %Tcl_EvalFile) :int (interp :pointer) (filename-cstr :pointer)) (defun Tcl_EvalFile (interp filename) (with-foreign-pointer (filename-cstr (length filename) strlen) (setf (mem-ref filename-cstr :char (1- strlen)) 0) (lisp-string-to-foreign filename filename-cstr strlen) %Tcl_EvalFile interp filename-cstr)) ;; Tcl_Eval (defcfun ("Tcl_Eval" %Tcl_Eval) :int (interp :pointer) (script-cstr :pointer)) (defun Tcl_Eval (interp script) (with-foreign-pointer (script-cstr (length script) strlen) (setf (mem-ref script-cstr :char (1- strlen)) 0) (lisp-string-to-foreign script script-cstr strlen) %Tcl_Eval interp script-cstr)) ) ) --- Now, we should be able to call the functions as expected: CODE: ;; Initialization mgmt - required to avoid multiple library loads (defvar *initialized* nil) (defun set-initialized () (setq *initialized* t)) (defun reset-initialized () (setq *initialized* nil)) ;; Tcl/Tk functions: execute a file and execute a script (defun exec-file (filename) (unless *initialized* ;; Could be simplified (use-foreign-library Tcl) (use-foreign-library Tk) (set-initialized)) (let* ((tcl-interp (Tcl_CreateInterp)) (rc (Tcl_EvalFile tcl-interp filename))) (format t "~%Tcl_EvalFile returned ~D~%" rc))) (defun exec-script (script) (unless *initialized* ;; Could be simplified (use-foreign-library Tcl) (use-foreign-library Tk) (set-initialized)) (let* ((tcl-interp (Tcl_CreateInterp)) (rc (Tcl_Eval tcl-interp script))) (format t "~%Tcl_Eval returned ~D~%" rc))) ;; We test just the script here (defun test-it () (exec-script "puts \"Hi !\"")) ;; Hmmm - no output generated. Why ? --- When calling the test function with: CL-USER > (gt.cffi-tcltk:test-it) I do not see any output anywhere. I also see that the returned value is like an error value ... I am on OS X 10.4.6 (Intel) with CFFI latest tarball and AllegroCL8.0. Any help really appreciated !!! Cheers Frank
![](https://secure.gravatar.com/avatar/85707c170bca7964097b9ee08480188d.jpg?s=120&d=mm&r=g)
Frank Goenninger wrote:
Hi!
Thanks for looking into this ... I want to call the functions Tcl_CreateInterp and Tcl_Eval from Lisp. So I defined the libs and the functions :
<skip>
I do not see any output anywhere. I also see that the returned value is like an error value ... I am on OS X 10.4.6 (Intel) with CFFI latest tarball and AllegroCL8.0.
Any help really appreciated !!!
Need also call Tcl_Init. And, may be, before this need call Tcl_FindExecutable. See help for Tcl Built-In Commands. -- WBR, Yaroslav Kavenchuk.
![](https://secure.gravatar.com/avatar/9ed6ab1d1019fe41799ee83440518e36.jpg?s=120&d=mm&r=g)
Frank Goenninger <fgoenninger@prion.de> writes:
Thanks for looking into this ... I want to call the functions Tcl_CreateInterp and Tcl_Eval from Lisp. So I defined the libs and the functions :
[ snippage ]
;; Tcl_EvalFile
(defcfun ("Tcl_EvalFile" %Tcl_EvalFile) :int (interp :pointer) (filename-cstr :pointer))
(defun Tcl_EvalFile (interp filename) (with-foreign-pointer (filename-cstr (length filename) strlen) (setf (mem-ref filename-cstr :char (1- strlen)) 0) (lisp-string-to-foreign filename filename-cstr strlen) %Tcl_EvalFile interp filename-cstr))
;; Tcl_Eval
(defcfun ("Tcl_Eval" %Tcl_Eval) :int (interp :pointer) (script-cstr :pointer))
(defun Tcl_Eval (interp script) (with-foreign-pointer (script-cstr (length script) strlen) (setf (mem-ref script-cstr :char (1- strlen)) 0) (lisp-string-to-foreign script script-cstr strlen) %Tcl_Eval interp script-cstr))
You seem to be going to a fair bit of trouble here to reproduce what the CFFI :STRING type does automatically... why not something like: (defcfun ("Tcl_EvalFile" tcl-eval-file) :int (interp :pointer) (filename :string)) (defcfun ("Tcl_Eval" tcl-eval) :int (interp :pointer) (script :string)) instead of mucking about with low-level stuff like null terminators. There is also WITH-FOREIGN-STRING that encapsulates this pattern in a macro when you don't want to use the :STRING type. Also, one technique I've found very handy when writing bindings for APIs that are consistent about returning error codes is to define a special result type and hang a translator on it, to get automatic error checking (untested, caveat executor): ;; Now TCL-EVAL-FILE and TCL-EVAL can return a TCL-ERROR instead of ;; :INT and the translator will get called on the return value. (defctype tcl-error :int) (defmethod translate-from-foreign (value (type (eql 'tcl-error))) (unless (zerop value) ;; or whatever (error "got some tcl error ~D..." value)) value) Apart from any other TCL-specific issues like Yaroslav mentioned, perhaps the TCL output stream is buffered and needs to be flushed somehow? James
![](https://secure.gravatar.com/avatar/85707c170bca7964097b9ee08480188d.jpg?s=120&d=mm&r=g)
James Bielman wrote:
You seem to be going to a fair bit of trouble here to reproduce what the CFFI :STRING type does automatically... why not something like:
(defcfun ("Tcl_EvalFile" tcl-eval-file) :int (interp :pointer) (filename :string))
(defcfun ("Tcl_Eval" tcl-eval) :int (interp :pointer) (script :string))
Small "but": tcl use strings in utf-8. If you want get/put non-ascii string... -- WBR, Yaroslav Kavenchuk.
![](https://secure.gravatar.com/avatar/9fda7fbd6217f4d84a55e5c5b48a2106.jpg?s=120&d=mm&r=g)
Am 26.04.2006 um 09:35 schrieb James Bielman:
You seem to be going to a fair bit of trouble here to reproduce what the CFFI :STRING type does automatically... why not something like:
(defcfun ("Tcl_EvalFile" tcl-eval-file) :int (interp :pointer) (filename :string))
(defcfun ("Tcl_Eval" tcl-eval) :int (interp :pointer) (script :string))
instead of mucking about with low-level stuff like null terminators. There is also WITH-FOREIGN-STRING that encapsulates this pattern in a macro when you don't want to use the :STRING type.
Thx for pointing out. I took my approach straight from the example cl- opengl as done by - Luis, I think... ;-)
Also, one technique I've found very handy when writing bindings for APIs that are consistent about returning error codes is to define a special result type and hang a translator on it, to get automatic error checking (untested, caveat executor):
;; Now TCL-EVAL-FILE and TCL-EVAL can return a TCL-ERROR instead of ;; :INT and the translator will get called on the return value. (defctype tcl-error :int)
(defmethod translate-from-foreign (value (type (eql 'tcl-error))) (unless (zerop value) ;; or whatever (error "got some tcl error ~D..." value)) value)
Superb. Works like a charm. Thanks!
Apart from any other TCL-specific issues like Yaroslav mentioned, perhaps the TCL output stream is buffered and needs to be flushed somehow?
Actually I had a typo in the source (missing paranthesis) that prevented the call of the Tcl function al all - so I was seeing the foreign ptr addresses as results ... That's why I was a bit surprised. Now I can call Tcl_Eval and do get the message as defined via the puts command on the standard output stream.
James
Thanks again! Frank
![](https://secure.gravatar.com/avatar/326b108ffcc42f27628703b0c11ed239.jpg?s=120&d=mm&r=g)
Frank Goenninger <fgoenninger@prion.de> writes:
instead of mucking about with low-level stuff like null terminators. There is also WITH-FOREIGN-STRING that encapsulates this pattern in a macro when you don't want to use the :STRING type.
Thx for pointing out. I took my approach straight from the example cl- opengl as done by - Luis, I think... ;-)
Oh, hmm. Really? Where? pomajxego:~/src/cl-opengl luis$ find . | xargs grep lisp-string-to-foreign <nothing> -- Luís Oliveira luismbo (@) gmail (.) com Equipa Portuguesa do Translation Project http://www.iro.umontreal.ca/translation/registry.cgi?team=pt
![](https://secure.gravatar.com/avatar/9fda7fbd6217f4d84a55e5c5b48a2106.jpg?s=120&d=mm&r=g)
Am 26.04.2006 um 14:31 schrieb Luís Oliveira:
Frank Goenninger <fgoenninger@prion.de> writes:
instead of mucking about with low-level stuff like null terminators. There is also WITH-FOREIGN-STRING that encapsulates this pattern in a macro when you don't want to use the :STRING type.
Thx for pointing out. I took my approach straight from the example cl- opengl as done by - Luis, I think... ;-)
Oh, hmm. Really? Where?
If only I could find that place again ... I have been reading that many code snippets out there on the Net ... Sorry for identifying you with this way of coding - I actually thought it is in cl-opengl but it doesn't seem to be, obviously. So: Beg pardon. I am now able to call Tcl from Lisp. Tk is still another story. Thx for CFFI, for the support, for fast reaction ... Cheers Frank
![](https://secure.gravatar.com/avatar/ae26b49096d78856a33e8ae9b61037c3.jpg?s=120&d=mm&r=g)
Thx for pointing out. I took my approach straight from the example cl- opengl as done by - Luis, I think... ;-)
Oh, hmm. Really? Where?
If only I could find that place again ... I have been reading that many code snippets out there on the Net ... Sorry for identifying you with this way of coding - I actually thought it is in cl-opengl but it doesn't seem to be, obviously. So: Beg pardon.
ha-ha, this is Luis's punishment for stealing the name cl-opengl from me. :) He will be fielding support calls from the legions of Cello users forever. Fortunately, Frank is the only legion. [Explanation: Luis, I am betting Frank is referring to my pre-CFFI cl-opengl code. Frank, there are two cl-opengl's, mine (deprecated) and Luis's.] hth, ken
participants (5)
-
Frank Goenninger
-
James Bielman
-
Ken Tilton
-
Luís Oliveira
-
Yaroslav Kavenchuk