ktakashi / r6rs-pffi Goto Github PK
View Code? Open in Web Editor NEWPortable Foreign Function Interface (FFI) for R6RS
Portable Foreign Function Interface (FFI) for R6RS
How would you specify that a foreign procedures uses an integer type like size_t
or mode_t
whose size can vary by operating system and CPU architecture?
Is there a way to allocate structs without manually initialising each field?
Hi,
Thanks for the library!
Could you please suggest how to pass the address of a double to a foreign procedure? For instance, given:
void
set_pi (double *x)
{
*x = 3.14;
}
I'd like the equivalent of set_pi (&x)
in scheme. I guess something like:
(define set-pi! (foreign-procedure lib void set_pi (pointer)))
(let ((x 0.0))
(set-pi! (... x))
x) ; -> 3.14
where I don't know how to fill the ellipses.
Sorry if I missed the relevant part in the examples.
The pointer->bytevector
should have the following signature:
(define (pointer->bytevector p len . maybe-offset)
But the Chez version accepts only one argument.
There's no way to declare a char*
as an argument. At least, Larceny and Chez complain passing a string as a pointer.
So it's better to add string
type.
Currently there is no (?) way to specify additional ABI properties (calling convention, etc.) of foreign procedures in Chez (and other) implementation of pffi
.
Chez supports those (here is the doc) and most of the time they are not really required to be able to build an FFI wrapper around C library. However, there is an exception to that, in particular, on MacOS X M1.
This comment in a Racket Chez branch mentions that in order to correctly set up a call for C procedure that uses va_list
on an Apple Silicon architecture one needs to provide (__varargs_after X)
ABI specifier.
Inability to specify it prevents akku
Scheme package manager from working on M1 Mac OS - it binds to libcurl
and uses curl_easy_setopt
function that is actually a vararg-taking C func.
On the other hand, I'm not sure if any other Scheme implementation actually allows specifying ABI conventions so I wonder what would be the best way to add such support in a uniform way.
I try to define the following struct:
struct tb_event {
uint8_t type;
uint8_t mod; /* modifiers to either 'key' or 'ch' below */
uint16_t key; /* one of the TB_KEY_* constants */
uint32_t ch; /* unicode character */
int32_t w;
int32_t h;
int32_t x;
int32_t y;
};
Here is what I have:
(define-foreign-struct (tb-event make-tb-event tb-event?)
(fields (uint8_t type tb-event-type)
(uint8_t mod tb-event-mod)
(uint16_t key tb-event-key)
(uint32_t ch tb-event-ch)
(int32_t w tb-event-w)
(int32_t h tb-event-h)
(int32_t x tb-event-x)
(int32_t y tb-event-y)))
Chez scheme keep compaining:
$ scheme src/azul/main/editor.scm
Exception in define-foreign-struct: invalid define-foreign-struct ((fields (uint8_t type tb-event-type) (uint8_t mod tb-event-mod) (uint16_t key tb-event-key) (uint32_t ch tb-event-ch) (int32_t w tb-event-w) ...) (protocol (lambda args args))) in (define-foreign-struct (tb-event make-tb-event tb-event?) (fields (uint8_t type tb-event-type) (uint8_t mod tb-event-mod) (uint16_t key tb-event-key) (uint32_t ch tb-event-ch) (int32_t w tb-event-w) ...) (protocol (lambda args args))) near line 295, char 7 ...
Hi Kato! Is this project alive and might you consider adding support for Chez Scheme now that it's open source?
Could open-shared-object
auto-append the right file name extension if there is no #\.
character in the filename given by the caller? E.g. (open-shared-object "libarchive")
would open libarchive.dylib
on MacOS, libarchive.so
on Linux, libarchive.dll
on Windows.
There's some code already to do that for Chez:
(case (machine-type)
((ta6le a6le i3le ti3le arm32le ppc32le) (load-shared-object "libc.so.6"))
((i3osx ti3osx a6osx ta6osx) (load-shared-object "libc.dylib"))
((ta6nt a6nt i3nt ti3nt) (load-shared-object "msvcrt.dll"))
(else (load-shared-object "libc.so")))
I'm not sure what to do about the version numbers in the .so
filenames.
I don't understand the purpose of parent
and protocol
in defined strcut?
Hello,
Besides the missing machine types that I commented on separately on a commit, there is an error in how returned pointers are handled:
> (import (pffi))
> (define libc (open-shared-object "libc.so.6"))
> ((foreign-procedure libc pointer strerror (int)) 123)
140663955681195
Should it not be a pointer record rather than an integer?
Would it make sense to include these?
(define (utf8-pointer->string pointer)
(and (not (= 0 (pointer->integer pointer)))
(let loop ((n 0))
(if (= 0 (pointer-ref-c-uint8 pointer n))
(utf8->string (pointer->bytevector pointer n))
(loop (+ n 1))))))
(define (string->utf8-pointer string)
(let* ((bytes (string->utf8 string))
(len (bytevector-length bytes))
(bytes0 (make-bytevector (+ len 1) 0)))
(bytevector-copy! bytes 0 bytes0 0 len)
(bytevector->pointer bytes0)))
Hi!
Thank you for the nice FFI library! I have a question related to bytevector->pointer
implementation for Chez Scheme.
As it stands now, the procedure basically converts the bytevector to a pointer by calling a memmove
pointer with zero size argument. To my understanding the purpose of this approach is to utilise Chez built-in conversion mechanisms to first convert the bytevector to u8*
and then convert it via memmove
to uptr
. However, the lifetime of the retrieved pointer is something that I'm concerned about - the documentation for foreign-procedure
states that (I omit non-relevant part):
u8*: The argument must be a Scheme bytevector or #f. ... . The bytevector should not be retained in foreign variables or data structures, since the memory management system may relocate or discard them between foreign procedure calls, and use their storage for some other purpose.
This means that the value returned by bytevector->pointer
is not guaranteed to (correctly) survive a garbage collection. Since GC can kick at any time it means that the value cannot be reliably used/passed to C libraries.
As far as I can tell, the only way to make sure that returned pointer is valid always is to explicitly allocate memory (but then it has to be reclaimed).
So my question - am I missing something? If not, I can prepare a PR that addresses this issue using guardians and explicit copying of bytevector's data.
This kind of trick may work on Chez
> (load-shared-object "msvcrt.dll")
> (define f (foreign-procedure "memmove" (u8* u8* size_t) uptr))
> (define (bytevector->pointer bv) (f bv bv (bytevector-length bv)))
> (bytevector->pointer #vu8(1 2 3 4))
1326944305800
This basically provides the same as the one I've written in C (may add some overheads, though).
Does PSSI support union?
I'm trying to define this in scheme:
struct gsl_function_struct
{
double (* function) (double x, void * params);
void * params;
};
My attempt:
(define-foreign-struct gsl-function
(fields ((callback double (double pointer)) function)
(pointer params)))
Chez gives Exception in symbol->string: (callback double (double pointer)) is not a symbol
. However, (symbol->string (callback double (double pointer)))
works fine. Is this expected?
Does PSSI support struct packing see https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
Running make prepare-guile followed by make guile (guile 2.011 installed) fails with:
make guile
cd tests; gcc -fPIC -shared -Wall -o functions.so functions.c
echo (set! %load-extensions '(".guile.sls" ".sls" ".scm")) > .guile.rc
LD_LIBRARY_PATH=:tests; guile --no-auto-compile -l .guile.rc -L src tests/test.scm
%%%% Starting test PFFI (Writing full log to "PFFI.log")
Backtrace:
In ice-9/boot-9.scm:
157: 10 [catch #t #<catch-closure 28133a0> ...]
In unknown file:
?: 9 [apply-smob/1 #<catch-closure 28133a0>]
In ice-9/boot-9.scm:
63: 8 [call-with-prompt prompt0 ...]
In ice-9/eval.scm:
432: 7 [eval # #]
In ice-9/boot-9.scm:
2401: 6 [save-module-excursion #<procedure 2833780 at ice-9/boot-9.scm:4045:3 ()>]
4052: 5 [#<procedure 2833780 at ice-9/boot-9.scm:4045:3 ()>]
1724: 4 [%start-stack load-stack ...]
1729: 3 [#<procedure 284bb70 ()>]
In unknown file:
?: 2 [primitive-load "/home/erje/builds/ffi/r6rs-pffi-master/tests/test.scm"]
In ice-9/eval.scm:
453: 1 [eval # ()]
In unknown file:
?: 0 [dynamic-link "functions.so"]
ERROR: In procedure dynamic-link:
ERROR: In procedure dynamic-link: file: "functions.so", message: "file not found"
Makefile:42: recipe for target 'guile' failed
make: *** [guile] Error 1
Hi,
I am just playing/exploring, but I love this library!
A question came up when I was trying to do a minimal hello world example with gtk+.
How would we represent foreign enums, like GTK_WINDOW_TOPLEVEL?
I know I can pass an int corresponding to the value of the enum, but I'm interested in the more idomatic, correct way to do this in pffi. Thanks!
Hello Takashi,
PFFI on Chez Scheme uses eval
to get Chez's foreign-procedure
and it's causing a small problem. My binary distributions of Akku.scm come bundled with Petite Chez Scheme, which doesn't have the compiler. I can compile Akku.scm just fine, but due to eval
, I get this error: Exception in interpret: cannot compile foreign-procedure: compiler is not loaded
.
It would be better if PFFI's foreign-procedure
expanded to Chez's foreign-procedure
and didn't need to use eval. I had a cursory glance at the code and it looks like make-c-function
and make-c-callback
in compat.chezscheme.sls
can be written as syntax-case macros. What do you think?
From compat.larceny.sls
:
(define (null-pointer? pointer) (zero? (pointer->integer pointer)))
Might as well make this part of the public interface?
Can someone please add links to some real-world examples, e.g. for some popular C libraries?
At this moment, this library doesn't support varargs C function call.
Adding an extra marker ___
(as ...
is already taken by syntax)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.