From 92c267758e7c0de67fb594a2aa21d995fbe9ab78 Mon Sep 17 00:00:00 2001 From: visualfc Date: Tue, 22 Oct 2024 21:30:38 +0800 Subject: [PATCH] c/ffi: add _demo --- c/ffi/_demo/_wrap/wrap.c | 25 ++++++++++++ c/ffi/_demo/cfunc/main.go | 57 +++++++++++++++++++++++++++ c/ffi/_demo/closure/main.go | 78 +++++++++++++++++++++++++++++++++++++ c/ffi/_demo/gofunc/main.go | 62 +++++++++++++++++++++++++++++ c/ffi/_demo/printf/main.go | 20 ++++++++++ c/ffi/ffi.go | 8 ++++ 6 files changed, 250 insertions(+) create mode 100644 c/ffi/_demo/_wrap/wrap.c create mode 100644 c/ffi/_demo/cfunc/main.go create mode 100644 c/ffi/_demo/closure/main.go create mode 100644 c/ffi/_demo/gofunc/main.go create mode 100644 c/ffi/_demo/printf/main.go diff --git a/c/ffi/_demo/_wrap/wrap.c b/c/ffi/_demo/_wrap/wrap.c new file mode 100644 index 00000000..07f31c0a --- /dev/null +++ b/c/ffi/_demo/_wrap/wrap.c @@ -0,0 +1,25 @@ +#include + +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); +} diff --git a/c/ffi/_demo/cfunc/main.go b/c/ffi/_demo/cfunc/main.go new file mode 100644 index 00000000..d9aa66f9 --- /dev/null +++ b/c/ffi/_demo/cfunc/main.go @@ -0,0 +1,57 @@ +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 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) +} diff --git a/c/ffi/_demo/closure/main.go b/c/ffi/_demo/closure/main.go new file mode 100644 index 00000000..e8c4be4f --- /dev/null +++ b/c/ffi/_demo/closure/main.go @@ -0,0 +1,78 @@ +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 +} + +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) +} diff --git a/c/ffi/_demo/gofunc/main.go b/c/ffi/_demo/gofunc/main.go new file mode 100644 index 00000000..10af70a8 --- /dev/null +++ b/c/ffi/_demo/gofunc/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c/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) +} diff --git a/c/ffi/_demo/printf/main.go b/c/ffi/_demo/printf/main.go new file mode 100644 index 00000000..ac849d0b --- /dev/null +++ b/c/ffi/_demo/printf/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/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) +} diff --git a/c/ffi/ffi.go b/c/ffi/ffi.go index 9b2266b9..586a50fc 100644 --- a/c/ffi/ffi.go +++ b/c/ffi/ffi.go @@ -96,3 +96,11 @@ func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Point } return Error(status) } + +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)))) +}