x/ffi: wrap c/ffi
This commit is contained in:
@@ -29,29 +29,37 @@ type array struct {
|
|||||||
k 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() {
|
func main() {
|
||||||
cdemo1()
|
cdemo1()
|
||||||
cdemo2()
|
cdemo2()
|
||||||
}
|
}
|
||||||
|
|
||||||
func cdemo1() {
|
func cdemo1() {
|
||||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.StructOf(ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32))
|
var cif ffi.Cif
|
||||||
if err != nil {
|
tarray := &ffi.Type{0, 0, ffi.Struct, &[]*ffi.Type{typeInt32, typeInt32, typeInt32, typeInt32, nil}[0]}
|
||||||
panic(err)
|
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{tarray}[0])
|
||||||
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
}
|
}
|
||||||
ar := array{1, 2, 3, 4}
|
ar := array{1, 2, 3, 4}
|
||||||
var ret int32
|
var ret int32
|
||||||
ffi.Call(sig, c.Func(demo1), unsafe.Pointer(&ret), unsafe.Pointer(&ar))
|
ffi.Call(&cif, c.Func(demo1), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&ar)}[0])
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
c.Printf(c.Str("ret: %d\n"), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cdemo2() {
|
func cdemo2() {
|
||||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer)
|
var cif ffi.Cif
|
||||||
if err != nil {
|
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||||
panic(err)
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
}
|
}
|
||||||
var ret int32
|
var ret int32
|
||||||
fn := c.Func(demo1)
|
fn := c.Func(demo1)
|
||||||
ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&fn))
|
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fn)}[0])
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
c.Printf(c.Str("ret: %d\n"), ret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ func demo(a array) c.Int {
|
|||||||
return 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() {
|
func main() {
|
||||||
gofn()
|
gofn()
|
||||||
c.Printf(c.Str("\n"))
|
c.Printf(c.Str("\n"))
|
||||||
@@ -41,38 +46,48 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func gofn() {
|
func gofn() {
|
||||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer)
|
var cif ffi.Cif
|
||||||
if err != nil {
|
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||||
panic(err)
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
}
|
}
|
||||||
closure := ffi.NewClosure()
|
var fncode unsafe.Pointer
|
||||||
defer closure.Free()
|
closure := ffi.ClosureAlloc(&fncode)
|
||||||
err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
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))
|
ar := *(*array)(ffi.Index(args, 0))
|
||||||
*(*c.Int)(ret) = demo(ar)
|
*(*c.Int)(ret) = demo(ar)
|
||||||
}, nil)
|
}, nil, fncode)
|
||||||
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
|
}
|
||||||
var ret int32
|
var ret int32
|
||||||
ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn))
|
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
c.Printf(c.Str("ret: %d\n"), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func goclosure() {
|
func goclosure() {
|
||||||
sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer)
|
var cif ffi.Cif
|
||||||
if err != nil {
|
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||||
panic(err)
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
}
|
}
|
||||||
fn := func(ar array) c.Int {
|
fn := func(ar array) c.Int {
|
||||||
c.Printf(c.Str("call closure %d\n"), sig.NArgs)
|
c.Printf(c.Str("call closure %d\n"), cif.NArgs)
|
||||||
return demo(ar)
|
return demo(ar)
|
||||||
}
|
}
|
||||||
closure := ffi.NewClosure()
|
var fncode unsafe.Pointer
|
||||||
defer closure.Free()
|
closure := ffi.ClosureAlloc(&fncode)
|
||||||
err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
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))
|
ar := *(*array)(ffi.Index(args, 0))
|
||||||
fn := *(*func(array) c.Int)(userdata)
|
fn := *(*func(array) c.Int)(userdata)
|
||||||
*(*c.Int)(ret) = fn(ar)
|
*(*c.Int)(ret) = fn(ar)
|
||||||
}, unsafe.Pointer(&fn))
|
}, unsafe.Pointer(&fn), fncode)
|
||||||
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
|
}
|
||||||
var ret int32
|
var ret int32
|
||||||
ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn))
|
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
c.Printf(c.Str("ret: %d\n"), ret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,20 @@ import (
|
|||||||
"github.com/goplus/llgo/c/ffi"
|
"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() {
|
func main() {
|
||||||
sig, err := ffi.NewSignatureVar(ffi.TypeInt32, 1, ffi.TypePointer, ffi.TypeInt32)
|
var cif ffi.Cif
|
||||||
if err != nil {
|
status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, 1, 2, typeInt32, &[]*ffi.Type{typePointer, typeInt32}[0])
|
||||||
panic(err)
|
if status != ffi.OK {
|
||||||
|
panic(status)
|
||||||
}
|
}
|
||||||
var ret int32
|
var ret int32
|
||||||
text := c.Str("hello world: %d\n")
|
text := c.Str("hello world: %d\n")
|
||||||
var n int32 = 100
|
var n int32 = 100
|
||||||
ffi.Call(sig, c.Func(c.Printf), unsafe.Pointer(&ret), unsafe.Pointer(&text), unsafe.Pointer(&n))
|
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)
|
c.Printf(c.Str("ret: %d\n"), ret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
package ffi
|
package ffi
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultAbi Abi = 1
|
DefaultAbi = 1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
package ffi
|
package ffi
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultAbi Abi = 2
|
DefaultAbi = 2
|
||||||
)
|
)
|
||||||
|
|||||||
174
c/ffi/ffi.go
174
c/ffi/ffi.go
@@ -1,101 +1,127 @@
|
|||||||
package ffi
|
package ffi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/c/ffi/ffi"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Type = ffi.Type
|
const (
|
||||||
|
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
||||||
type Signature = ffi.Cif
|
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
||||||
|
)
|
||||||
type Abi c.Uint
|
|
||||||
|
|
||||||
type Error c.Uint
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OK Error = iota
|
Void = iota
|
||||||
|
Int
|
||||||
|
Float
|
||||||
|
Double
|
||||||
|
LongDouble
|
||||||
|
Uint8
|
||||||
|
Sint8
|
||||||
|
Uint16
|
||||||
|
Sint16
|
||||||
|
Uint32
|
||||||
|
Sint32
|
||||||
|
Uint64
|
||||||
|
Sint64
|
||||||
|
Struct
|
||||||
|
Pointer
|
||||||
|
Complex
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OK = iota
|
||||||
BAD_TYPEDEF
|
BAD_TYPEDEF
|
||||||
BAD_ABI
|
BAD_ABI
|
||||||
BAD_ARGTYPE
|
BAD_ARGTYPE
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s Error) Error() string {
|
type Type struct {
|
||||||
switch s {
|
Size uintptr
|
||||||
case OK:
|
Alignment uint16
|
||||||
return "ok"
|
Type uint16
|
||||||
case BAD_TYPEDEF:
|
Elements **Type
|
||||||
return "bad type def"
|
|
||||||
case BAD_ABI:
|
|
||||||
return "bad ABI"
|
|
||||||
case BAD_ARGTYPE:
|
|
||||||
return "bad argument type"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("invalid status: %v", int(s))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSignature(ret *Type, args ...*Type) (*Signature, error) {
|
/*typedef struct {
|
||||||
var cif ffi.Cif
|
ffi_abi abi;
|
||||||
var atype **Type
|
unsigned nargs;
|
||||||
if len(args) > 0 {
|
ffi_type **arg_types;
|
||||||
atype = &args[0]
|
ffi_type *rtype;
|
||||||
}
|
unsigned bytes;
|
||||||
status := ffi.PrepCif(&cif, c.Uint(DefaultAbi), c.Uint(len(args)), ret, atype)
|
unsigned flags;
|
||||||
if status == 0 {
|
#ifdef FFI_EXTRA_CIF_FIELDS
|
||||||
return &cif, nil
|
FFI_EXTRA_CIF_FIELDS;
|
||||||
}
|
#endif
|
||||||
return nil, Error(status)
|
} ffi_cif;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type Cif struct {
|
||||||
|
Abi c.Uint
|
||||||
|
NArgs c.Uint
|
||||||
|
ArgTypes **Type
|
||||||
|
RType *Type
|
||||||
|
Bytes c.Uint
|
||||||
|
Flags c.Uint
|
||||||
|
//Extra c.Uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) {
|
/*
|
||||||
var cif ffi.Cif
|
ffi_status
|
||||||
var atype **Type
|
ffi_prep_cif(ffi_cif *cif,
|
||||||
if len(args) > 0 {
|
ffi_abi abi,
|
||||||
atype = &args[0]
|
unsigned int nargs,
|
||||||
}
|
ffi_type *rtype,
|
||||||
status := ffi.PrepCifVar(&cif, c.Uint(DefaultAbi), c.Uint(fixed), c.Uint(len(args)), ret, atype)
|
ffi_type **atypes);
|
||||||
if status == 0 {
|
*/
|
||||||
return &cif, nil
|
//go:linkname PrepCif C.ffi_prep_cif
|
||||||
}
|
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||||
return nil, Error(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) {
|
/*
|
||||||
var avalues *unsafe.Pointer
|
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||||
if len(args) > 0 {
|
ffi_abi abi,
|
||||||
avalues = &args[0]
|
unsigned int nfixedargs,
|
||||||
}
|
unsigned int ntotalargs,
|
||||||
ffi.Call(cif, fn, ret, avalues)
|
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
|
||||||
|
|
||||||
type Closure struct {
|
/*
|
||||||
ptr unsafe.Pointer
|
void ffi_call(ffi_cif *cif,
|
||||||
Fn unsafe.Pointer
|
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)
|
||||||
|
|
||||||
func NewClosure() *Closure {
|
// void *ffi_closure_alloc (size_t size, void **code);
|
||||||
c := &Closure{}
|
//
|
||||||
c.ptr = ffi.ClosureAlloc(&c.Fn)
|
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
||||||
return c
|
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Closure) Free() {
|
// void ffi_closure_free (void *);
|
||||||
if c != nil && c.ptr != nil {
|
//
|
||||||
ffi.ClosureFree(c.ptr)
|
//go:linkname ClosureFree C.ffi_closure_free
|
||||||
c.ptr = nil
|
func ClosureFree(unsafe.Pointer)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error {
|
/*
|
||||||
status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn)
|
ffi_status
|
||||||
if status == 0 {
|
ffi_prep_closure_loc (ffi_closure*,
|
||||||
return nil
|
ffi_cif *,
|
||||||
}
|
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||||
return Error(status)
|
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 {
|
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
||||||
return unsafe.Pointer(uintptr(ptr) + offset)
|
return unsafe.Pointer(uintptr(ptr) + offset)
|
||||||
|
|||||||
117
c/ffi/ffi/ffi.go
117
c/ffi/ffi/ffi.go
@@ -1,117 +0,0 @@
|
|||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
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)
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c/ffi"
|
"github.com/goplus/llgo/x/ffi"
|
||||||
)
|
)
|
||||||
|
|
||||||
type array struct {
|
type array struct {
|
||||||
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)
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/c/ffi/ffi"
|
"github.com/goplus/llgo/c/ffi"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BasicKind int
|
type BasicKind int
|
||||||
Reference in New Issue
Block a user