Merge pull request #842 from visualfc/libffi
[WIP] c/ffi x/ffi: import libffi
This commit is contained in:
25
c/ffi/_demo/_wrap/wrap.c
Normal file
25
c/ffi/_demo/_wrap/wrap.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
|
||||
struct array
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
int k;
|
||||
};
|
||||
|
||||
int demo1(struct array a)
|
||||
{
|
||||
printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k);
|
||||
return a.x+a.y+a.z+a.k;
|
||||
}
|
||||
|
||||
int demo2( int (*fn)(struct array)) {
|
||||
printf("c.demo2: %p\n",fn);
|
||||
struct array a;
|
||||
a.x = 1;
|
||||
a.y = 2;
|
||||
a.z = 3;
|
||||
a.k = 4;
|
||||
return (*fn)(a);
|
||||
}
|
||||
65
c/ffi/_demo/cfunc/main.go
Normal file
65
c/ffi/_demo/cfunc/main.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "../_wrap/wrap.c"
|
||||
)
|
||||
|
||||
//llgo:type C
|
||||
type Callback func(array) c.Int
|
||||
|
||||
//go:linkname demo1 C.demo1
|
||||
func demo1(array) c.Int
|
||||
|
||||
//go:linkname demo2 C.demo2
|
||||
func demo2(fn Callback) c.Int
|
||||
|
||||
//llgo:type C
|
||||
type array struct {
|
||||
x c.Int
|
||||
y c.Int
|
||||
z c.Int
|
||||
k c.Int
|
||||
}
|
||||
|
||||
var (
|
||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
||||
)
|
||||
|
||||
func main() {
|
||||
cdemo1()
|
||||
cdemo2()
|
||||
}
|
||||
|
||||
func cdemo1() {
|
||||
var cif ffi.Cif
|
||||
tarray := &ffi.Type{0, 0, ffi.Struct, &[]*ffi.Type{typeInt32, typeInt32, typeInt32, typeInt32, nil}[0]}
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{tarray}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
ar := array{1, 2, 3, 4}
|
||||
var ret int32
|
||||
ffi.Call(&cif, c.Func(demo1), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&ar)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
|
||||
func cdemo2() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
fn := c.Func(demo1)
|
||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fn)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
93
c/ffi/_demo/closure/main.go
Normal file
93
c/ffi/_demo/closure/main.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "../_wrap/wrap.c"
|
||||
)
|
||||
|
||||
//llgo:type C
|
||||
type Callback func(array) c.Int
|
||||
|
||||
//go:linkname demo1 C.demo1
|
||||
func demo1(array) c.Int
|
||||
|
||||
//go:linkname demo2 C.demo2
|
||||
func demo2(fn Callback) c.Int
|
||||
|
||||
//llgo:type C
|
||||
type array struct {
|
||||
x c.Int
|
||||
y c.Int
|
||||
z c.Int
|
||||
k c.Int
|
||||
}
|
||||
|
||||
func demo(a array) c.Int {
|
||||
c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k)
|
||||
return a.x + a.y + a.z + a.k
|
||||
}
|
||||
|
||||
var (
|
||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
||||
)
|
||||
|
||||
func main() {
|
||||
gofn()
|
||||
c.Printf(c.Str("\n"))
|
||||
goclosure()
|
||||
}
|
||||
|
||||
func gofn() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var fncode unsafe.Pointer
|
||||
closure := ffi.ClosureAlloc(&fncode)
|
||||
defer ffi.ClosureFree(closure)
|
||||
status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
ar := *(*array)(ffi.Index(args, 0))
|
||||
*(*c.Int)(ret) = demo(ar)
|
||||
}, nil, fncode)
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
|
||||
func goclosure() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
fn := func(ar array) c.Int {
|
||||
c.Printf(c.Str("call closure %d\n"), cif.NArgs)
|
||||
return demo(ar)
|
||||
}
|
||||
var fncode unsafe.Pointer
|
||||
closure := ffi.ClosureAlloc(&fncode)
|
||||
defer ffi.ClosureFree(closure)
|
||||
status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
ar := *(*array)(ffi.Index(args, 0))
|
||||
fn := *(*func(array) c.Int)(userdata)
|
||||
*(*c.Int)(ret) = fn(ar)
|
||||
}, unsafe.Pointer(&fn), fncode)
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
26
c/ffi/_demo/printf/main.go
Normal file
26
c/ffi/_demo/printf/main.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
var (
|
||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
||||
)
|
||||
|
||||
func main() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, 1, 2, typeInt32, &[]*ffi.Type{typePointer, typeInt32}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
text := c.Str("hello world: %d\n")
|
||||
var n int32 = 100
|
||||
ffi.Call(&cif, c.Func(c.Printf), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&text), unsafe.Pointer(&n)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
5
c/ffi/_wrap/libffi.c
Normal file
5
c/ffi/_wrap/libffi.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <ffi.h>
|
||||
|
||||
void *llog_ffi_closure_alloc(void **code) {
|
||||
return ffi_closure_alloc(sizeof(ffi_closure), code);
|
||||
}
|
||||
7
c/ffi/abi.go
Normal file
7
c/ffi/abi.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64))
|
||||
|
||||
package ffi
|
||||
|
||||
const (
|
||||
DefaultAbi = 1
|
||||
)
|
||||
7
c/ffi/abi_amd64.go
Normal file
7
c/ffi/abi_amd64.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build freebsd || linux || darwin
|
||||
|
||||
package ffi
|
||||
|
||||
const (
|
||||
DefaultAbi = 2
|
||||
)
|
||||
132
c/ffi/ffi.go
Normal file
132
c/ffi/ffi.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package ffi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
||||
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
||||
)
|
||||
|
||||
const (
|
||||
Void = iota
|
||||
Int
|
||||
Float
|
||||
Double
|
||||
LongDouble
|
||||
Uint8
|
||||
Sint8
|
||||
Uint16
|
||||
Sint16
|
||||
Uint32
|
||||
Sint32
|
||||
Uint64
|
||||
Sint64
|
||||
Struct
|
||||
Pointer
|
||||
Complex
|
||||
)
|
||||
|
||||
const (
|
||||
OK = iota
|
||||
BAD_TYPEDEF
|
||||
BAD_ABI
|
||||
BAD_ARGTYPE
|
||||
)
|
||||
|
||||
type Type struct {
|
||||
Size uintptr
|
||||
Alignment uint16
|
||||
Type uint16
|
||||
Elements **Type
|
||||
}
|
||||
|
||||
/*typedef struct {
|
||||
ffi_abi abi;
|
||||
unsigned nargs;
|
||||
ffi_type **arg_types;
|
||||
ffi_type *rtype;
|
||||
unsigned bytes;
|
||||
unsigned flags;
|
||||
#ifdef FFI_EXTRA_CIF_FIELDS
|
||||
FFI_EXTRA_CIF_FIELDS;
|
||||
#endif
|
||||
} ffi_cif;
|
||||
*/
|
||||
|
||||
type Cif struct {
|
||||
Abi c.Uint
|
||||
NArgs c.Uint
|
||||
ArgTypes **Type
|
||||
RType *Type
|
||||
Bytes c.Uint
|
||||
Flags c.Uint
|
||||
//Extra c.Uint
|
||||
}
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_cif(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCif C.ffi_prep_cif
|
||||
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCifVar C.ffi_prep_cif_var
|
||||
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
void ffi_call(ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
void **avalue);
|
||||
*/
|
||||
//go:linkname Call C.ffi_call
|
||||
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer)
|
||||
|
||||
// void *ffi_closure_alloc (size_t size, void **code);
|
||||
//
|
||||
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
||||
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
// void ffi_closure_free (void *);
|
||||
//
|
||||
//go:linkname ClosureFree C.ffi_closure_free
|
||||
func ClosureFree(unsafe.Pointer)
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure*,
|
||||
ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
*/
|
||||
|
||||
//llgo:type C
|
||||
type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer)
|
||||
|
||||
//go:linkname PreClosureLoc C.ffi_prep_closure_loc
|
||||
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint
|
||||
|
||||
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + offset)
|
||||
}
|
||||
|
||||
func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer {
|
||||
return (*(*unsafe.Pointer)(add(unsafe.Pointer(args), i*unsafe.Sizeof(0))))
|
||||
}
|
||||
25
x/ffi/_demo/_wrap/wrap.c
Normal file
25
x/ffi/_demo/_wrap/wrap.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
|
||||
struct array
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
int k;
|
||||
};
|
||||
|
||||
int demo1(struct array a)
|
||||
{
|
||||
printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k);
|
||||
return a.x+a.y+a.z+a.k;
|
||||
}
|
||||
|
||||
int demo2( int (*fn)(struct array)) {
|
||||
printf("c.demo2: %p\n",fn);
|
||||
struct array a;
|
||||
a.x = 1;
|
||||
a.y = 2;
|
||||
a.z = 3;
|
||||
a.k = 4;
|
||||
return (*fn)(a);
|
||||
}
|
||||
57
x/ffi/_demo/cfunc/main.go
Normal file
57
x/ffi/_demo/cfunc/main.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/x/ffi"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "../_wrap/wrap.c"
|
||||
)
|
||||
|
||||
//llgo:type C
|
||||
type Callback func(array) c.Int
|
||||
|
||||
//go:linkname demo1 C.demo1
|
||||
func demo1(array) c.Int
|
||||
|
||||
//go:linkname demo2 C.demo2
|
||||
func demo2(fn Callback) c.Int
|
||||
|
||||
//llgo:type C
|
||||
type array struct {
|
||||
x c.Int
|
||||
y c.Int
|
||||
z c.Int
|
||||
k c.Int
|
||||
}
|
||||
|
||||
func main() {
|
||||
cdemo1()
|
||||
cdemo2()
|
||||
}
|
||||
|
||||
func cdemo1() {
|
||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.StructOf(ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ar := array{1, 2, 3, 4}
|
||||
var ret int32
|
||||
ffi.Call(sig, c.Func(demo1), unsafe.Pointer(&ret), unsafe.Pointer(&ar))
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
|
||||
func cdemo2() {
|
||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var ret int32
|
||||
fn := c.Func(demo1)
|
||||
ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&fn))
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
78
x/ffi/_demo/closure/main.go
Normal file
78
x/ffi/_demo/closure/main.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/x/ffi"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "../_wrap/wrap.c"
|
||||
)
|
||||
|
||||
//llgo:type C
|
||||
type Callback func(array) c.Int
|
||||
|
||||
//go:linkname demo1 C.demo1
|
||||
func demo1(array) c.Int
|
||||
|
||||
//go:linkname demo2 C.demo2
|
||||
func demo2(fn Callback) c.Int
|
||||
|
||||
//llgo:type C
|
||||
type array struct {
|
||||
x c.Int
|
||||
y c.Int
|
||||
z c.Int
|
||||
k c.Int
|
||||
}
|
||||
|
||||
func demo(a array) c.Int {
|
||||
c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k)
|
||||
return a.x + a.y + a.z + a.k
|
||||
}
|
||||
|
||||
func main() {
|
||||
gofn()
|
||||
c.Printf(c.Str("\n"))
|
||||
goclosure()
|
||||
}
|
||||
|
||||
func gofn() {
|
||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
closure := ffi.NewClosure()
|
||||
defer closure.Free()
|
||||
err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
ar := *(*array)(ffi.Index(args, 0))
|
||||
*(*c.Int)(ret) = demo(ar)
|
||||
}, nil)
|
||||
var ret int32
|
||||
ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn))
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
|
||||
func goclosure() {
|
||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fn := func(ar array) c.Int {
|
||||
c.Printf(c.Str("call closure %d\n"), sig.NArgs)
|
||||
return demo(ar)
|
||||
}
|
||||
closure := ffi.NewClosure()
|
||||
defer closure.Free()
|
||||
err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
ar := *(*array)(ffi.Index(args, 0))
|
||||
fn := *(*func(array) c.Int)(userdata)
|
||||
*(*c.Int)(ret) = fn(ar)
|
||||
}, unsafe.Pointer(&fn))
|
||||
var ret int32
|
||||
ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn))
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
62
x/ffi/_demo/gofunc/main.go
Normal file
62
x/ffi/_demo/gofunc/main.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/x/ffi"
|
||||
)
|
||||
|
||||
type array struct {
|
||||
x int
|
||||
y int
|
||||
z int
|
||||
k int
|
||||
}
|
||||
|
||||
type Func func(ar array, i interface{}, s string, slice []int) (int, float64)
|
||||
|
||||
func demo(p1 array, p2 interface{}, p3 string, p4 []int) (int, float64) {
|
||||
println(p1.x, p1.y, p1.z, p1.k)
|
||||
println(p2)
|
||||
println(p3)
|
||||
println(p4)
|
||||
for _, v := range p4 {
|
||||
println(v)
|
||||
}
|
||||
return 200, 3.14
|
||||
}
|
||||
|
||||
func main() {
|
||||
sig, err := ffi.NewSignature(ffi.StructOf(ffi.TypeInt, ffi.TypeFloat64),
|
||||
ffi.StructOf(ffi.TypeInt, ffi.TypeInt, ffi.TypeInt, ffi.TypeInt),
|
||||
ffi.TypeInterface, ffi.TypeString, ffi.TypeSlice)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fn := demo
|
||||
closure := ffi.NewClosure()
|
||||
defer closure.Free()
|
||||
err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
p1 := *(*array)(ffi.Index(args, 0))
|
||||
p2 := *(*any)(ffi.Index(args, 1))
|
||||
p3 := *(*string)(ffi.Index(args, 2))
|
||||
p4 := *(*[]int)(ffi.Index(args, 3))
|
||||
fn := *(*Func)(userdata)
|
||||
p := (*struct {
|
||||
i int
|
||||
f float64
|
||||
})(ret)
|
||||
p.i, p.f = fn(p1, p2, p3, p4)
|
||||
}, unsafe.Pointer(&fn))
|
||||
var ret struct {
|
||||
i int
|
||||
f float64
|
||||
}
|
||||
p1 := array{1, 2, 3, 4}
|
||||
var p2 any = 100
|
||||
p3 := "hello world"
|
||||
p4 := []int{100, 200, 300}
|
||||
ffi.Call(sig, closure.Fn, unsafe.Pointer(&ret),
|
||||
unsafe.Pointer(&p1), unsafe.Pointer(&p2), unsafe.Pointer(&p3), unsafe.Pointer(&p4))
|
||||
println("ret:", ret.i, ret.f)
|
||||
}
|
||||
20
x/ffi/_demo/printf/main.go
Normal file
20
x/ffi/_demo/printf/main.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/x/ffi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sig, err := ffi.NewSignatureVar(ffi.TypeInt32, 1, ffi.TypePointer, ffi.TypeInt32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var ret int32
|
||||
text := c.Str("hello world: %d\n")
|
||||
var n int32 = 100
|
||||
ffi.Call(sig, c.Func(c.Printf), unsafe.Pointer(&ret), unsafe.Pointer(&text), unsafe.Pointer(&n))
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
93
x/ffi/ffi.go
Normal file
93
x/ffi/ffi.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package ffi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
type Type = ffi.Type
|
||||
|
||||
type Signature = ffi.Cif
|
||||
|
||||
type Error int
|
||||
|
||||
func (s Error) Error() string {
|
||||
switch s {
|
||||
case ffi.OK:
|
||||
return "ok"
|
||||
case ffi.BAD_TYPEDEF:
|
||||
return "bad type def"
|
||||
case ffi.BAD_ABI:
|
||||
return "bad ABI"
|
||||
case ffi.BAD_ARGTYPE:
|
||||
return "bad argument type"
|
||||
}
|
||||
return fmt.Sprintf("invalid status: %v", int(s))
|
||||
}
|
||||
|
||||
func NewSignature(ret *Type, args ...*Type) (*Signature, error) {
|
||||
var cif Signature
|
||||
var atype **Type
|
||||
if len(args) > 0 {
|
||||
atype = &args[0]
|
||||
}
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, c.Uint(len(args)), ret, atype)
|
||||
if status == 0 {
|
||||
return &cif, nil
|
||||
}
|
||||
return nil, Error(status)
|
||||
}
|
||||
|
||||
func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) {
|
||||
var cif Signature
|
||||
var atype **Type
|
||||
if len(args) > 0 {
|
||||
atype = &args[0]
|
||||
}
|
||||
status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, c.Uint(fixed), c.Uint(len(args)), ret, atype)
|
||||
if status == ffi.OK {
|
||||
return &cif, nil
|
||||
}
|
||||
return nil, Error(status)
|
||||
}
|
||||
|
||||
func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) {
|
||||
var avalues *unsafe.Pointer
|
||||
if len(args) > 0 {
|
||||
avalues = &args[0]
|
||||
}
|
||||
ffi.Call(cif, fn, ret, avalues)
|
||||
}
|
||||
|
||||
type Closure struct {
|
||||
ptr unsafe.Pointer
|
||||
Fn unsafe.Pointer
|
||||
}
|
||||
|
||||
func NewClosure() *Closure {
|
||||
c := &Closure{}
|
||||
c.ptr = ffi.ClosureAlloc(&c.Fn)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Closure) Free() {
|
||||
if c != nil && c.ptr != nil {
|
||||
ffi.ClosureFree(c.ptr)
|
||||
c.ptr = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error {
|
||||
status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn)
|
||||
if status == ffi.OK {
|
||||
return nil
|
||||
}
|
||||
return Error(status)
|
||||
}
|
||||
|
||||
func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer {
|
||||
return ffi.Index(args, i)
|
||||
}
|
||||
124
x/ffi/type.go
Normal file
124
x/ffi/type.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package ffi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
type BasicKind int
|
||||
|
||||
const (
|
||||
Void BasicKind = iota // type is invalid
|
||||
|
||||
// predeclared types
|
||||
Bool
|
||||
Int
|
||||
Int8
|
||||
Int16
|
||||
Int32
|
||||
Int64
|
||||
Uint
|
||||
Uint8
|
||||
Uint16
|
||||
Uint32
|
||||
Uint64
|
||||
Uintptr
|
||||
Float32
|
||||
Float64
|
||||
Complex64
|
||||
Complex128
|
||||
String
|
||||
UnsafePointer
|
||||
Interface
|
||||
Slice
|
||||
|
||||
// aliases
|
||||
Byte = Uint8
|
||||
Rune = Int32
|
||||
)
|
||||
|
||||
const (
|
||||
_64bit = 1 << (^uintptr(0) >> 63) / 2
|
||||
_Int = _64bit*ffi.Sint64 + (1-_64bit)*ffi.Sint32
|
||||
_Uint = _64bit*ffi.Uint64 + (1-_64bit)*ffi.Uint32
|
||||
_sizei = unsafe.Sizeof(0)
|
||||
_aligni = uint16(unsafe.Alignof(0))
|
||||
_sizeci = unsafe.Sizeof(c.Int(0))
|
||||
_alignci = uint16(unsafe.Alignof(c.Int(0)))
|
||||
_sizes = unsafe.Sizeof("")
|
||||
_aligns = uint16(unsafe.Alignof(""))
|
||||
)
|
||||
|
||||
var (
|
||||
TypeVoid = &Type{1, 1, ffi.Void, nil}
|
||||
TypeBool = &Type{1, 1, ffi.Uint8, nil}
|
||||
TypeInt8 = &Type{1, 1, ffi.Sint8, nil}
|
||||
TypeInt16 = &Type{2, 2, ffi.Sint16, nil}
|
||||
TypeInt32 = &Type{4, 4, ffi.Sint32, nil}
|
||||
TypeInt64 = &Type{8, 8, ffi.Sint64, nil}
|
||||
TypeUint8 = &Type{1, 1, ffi.Uint8, nil}
|
||||
TypeUint16 = &Type{2, 2, ffi.Uint16, nil}
|
||||
TypeUint32 = &Type{4, 4, ffi.Uint32, nil}
|
||||
TypeUint64 = &Type{8, 8, ffi.Uint64, nil}
|
||||
TypeFloat32 = &Type{4, 4, ffi.Float, nil}
|
||||
TypeFloat64 = &Type{8, 8, ffi.Double, nil}
|
||||
TypeComplex64 = &Type{8, 4, ffi.Complex, &[]*Type{TypeFloat32, nil}[0]}
|
||||
TypeComplex128 = &Type{16, 8, ffi.Complex, &[]*Type{TypeFloat64, nil}[0]}
|
||||
TypeInt = &Type{_sizei, _aligni, _Int, nil}
|
||||
TypeUint = &Type{_sizei, _aligni, _Uint, nil}
|
||||
TypeUintptr = &Type{_sizei, _aligni, _Uint, nil}
|
||||
TypePointer = &Type{_sizei, _aligni, ffi.Pointer, nil}
|
||||
TypeString = StructOf(TypePointer, TypeInt)
|
||||
TypeInterface = StructOf(TypePointer, TypePointer)
|
||||
TypeSlice = StructOf(TypePointer, TypeInt, TypeInt)
|
||||
)
|
||||
|
||||
var Typ = []*Type{
|
||||
Void: TypeVoid,
|
||||
Bool: TypeBool,
|
||||
Int: TypeInt,
|
||||
Int8: TypeInt8,
|
||||
Int16: TypeInt16,
|
||||
Int32: TypeInt32,
|
||||
Int64: TypeInt64,
|
||||
Uint: TypeUint,
|
||||
Uint8: TypeUint8,
|
||||
Uint16: TypeUint16,
|
||||
Uint32: TypeUint32,
|
||||
Uint64: TypeUint64,
|
||||
Uintptr: TypeUintptr,
|
||||
Float32: TypeFloat32,
|
||||
Float64: TypeFloat64,
|
||||
Complex64: TypeComplex64,
|
||||
Complex128: TypeComplex128,
|
||||
String: TypeString,
|
||||
UnsafePointer: TypePointer,
|
||||
Interface: TypeInterface,
|
||||
Slice: TypeSlice,
|
||||
}
|
||||
|
||||
func ArrayOf(elem *Type, N int) *Type {
|
||||
fs := make([]*Type, N+1)
|
||||
for i := 0; i < N; i++ {
|
||||
fs[i] = elem
|
||||
}
|
||||
return &Type{
|
||||
0,
|
||||
0,
|
||||
ffi.Struct,
|
||||
&fs[0],
|
||||
}
|
||||
}
|
||||
|
||||
func StructOf(fields ...*Type) *Type {
|
||||
fs := make([]*Type, len(fields)+1)
|
||||
copy(fs, fields)
|
||||
return &Type{
|
||||
0,
|
||||
0,
|
||||
ffi.Struct,
|
||||
&fs[0],
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user