dart如何通过ffi调用golang静态库

本篇文章主要讲述如何使用dart ffi 调用 golang静态库

一、生成golang静态库

本篇教程代码目录结构如下:

进入go-lib目录使用如下命令生成golang 静态库文件 lib.a 以及c 程序:

go build -buildmode=c-shared -o lib.a lib.go

lib.go源码如下:

//Package go_lib
/*
 * @Time    : 2021年11月22日 11:37:39
 * @Author  : user
 * @Project : SEGI
 * @File    : lib.go
 * @Software: GoLand
 * @Describe:
 */
package main

//#include <file.h>
import "C"
import (
	"fmt"
	"os"
	"os/exec"
)

//export GetKey
func GetKey() *C.char {
	fmt.Println("hello,dart")
	theKey := "123-456-789"
	return C.CString(theKey)
}

//export Sum
func Sum(a, b int) C.int {
	return C.int(a + b)
}

//export CreateFile
func CreateFile(filePath *C.char) C.CreateFileResponse {
	file, err := os.OpenFile(C.GoString(filePath), os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
	path, _ := exec.LookPath(os.Args[0])
	if err != nil {
		return C.CreateFileResponse{
			errMsg:   C.CString(err.Error()),
			path:C.CString(path),
			fileName: C.CString(""),
			ok:       C.FALSE,
		}
	}
	defer file.Close()
	fileStat, err := file.Stat()
	if err != nil {
		return C.CreateFileResponse{
			errMsg:   C.CString(err.Error()),
			path:C.CString(path),
			fileName: C.CString(""),
			ok:       C.FALSE,
		}
	}
	return C.CreateFileResponse{
		errMsg:   C.CString(""),
		path:C.CString(path),
		fileName: C.CString(fileStat.Name()),
		ok:       C.TRUE,
	}
}

func main() {
	//createFileResponse := C.CreateFileResponse{
	//	errMsg: C.CString("hello"),
	//	ok:     C.TRUE,
	//}
	//fmt.Println(createFileResponse)
	//fmt.Println(C.GoString(createFileResponse.errMsg))
}

file.h C头文件定义如下:

#define BOOL int
#define TRUE 1
#define FALSE 0
typedef struct{
char *errMsg;
char *path;
char *fileName;
BOOL ok;
}CreateFileResponse;

基于lib.go生成的静态库文件,有以下几种测试功能,返回不定长的字符串、整数加法、以及文件读写。

二、golang 数据类型、C数据类型、Dart数据类型说明

以下是数据类型对应关系

golang数据类型

CGO数据类型

C数据类型

Dart数据类型

byte

C.char

char

Uint8

int8

C.schar或C.int8_t

signed char或int8_t

Int8

uint8

C.uchar或C.uint8_t

unsigned char或uint8_t

Uint8

int16

C.short或C.int16_t

signed short或int16_t

Int16

uint16

C.ushort或C.uint16_t

unsigned short或uint16_t

Uint16

int32

C.int或C.int32_t

int或int32_t

Int32

uint32

C.uint或C.uint32_t

unsigned int或uint32_t

Uint32

int32

C.long或C.int32_t

long或int32_t

Int32

uint32

C.ulong或C.uint32_t

unsigned long或uint32_t

Uint32

int64

C.longlong或C.int64_t

long long int或int64_t

Int64

uint64

C.ulonglong或C.uint64_t

unsinged long long int或uint64_t

Uint64

float32

C.float

float

Float

float64

C.double

double

Double

unit

C.size_t

size_t

Uint32或Uint64

string

*C.char

char *

Pointer<utf8>

三、dart 调用golang生成的静态库

dart_learn_example.dart源码如下:

import 'dart:ffi';
import 'dart:io';

import 'package:ffi/ffi.dart';
import 'package:path/path.dart' as path;

class CreateFileResponse extends Struct {
  external Pointer<Utf8> errMsg;
  external Pointer<Utf8> path;
  external Pointer<Utf8> fileName;
  @Int64()
  external int ok;
}

typedef GetKeyFunc = Pointer<Utf8> Function();
typedef SumFunc = Int64 Function(Int64 a, Int64 b);
typedef CreateFileFuncNative = CreateFileResponse Function(
    Pointer<Utf8> filePath);
typedef CreateFileFunc = CreateFileResponse Function(Pointer<Utf8> filePath);

void main() async {
  var libraryPath = path.join(Directory.current.path, "example", "lib.a");
  final dylib = DynamicLibrary.open(libraryPath);
  final GetKeyFunc getKey =
      dylib.lookup<NativeFunction<GetKeyFunc>>('GetKey').asFunction();
  print(getKey().toDartString());
  final sum = dylib
      .lookup<NativeFunction<SumFunc>>('Sum')
      .asFunction<int Function(int a, int b)>();
  print(sum(100, 200));
  final createFile =
      dylib.lookupFunction<CreateFileFuncNative, CreateFileFunc>('CreateFile');
  final filePath = './test.dat'.toNativeUtf8();
  final createFileResponse = createFile(filePath);
  print(Directory.current);
  print(createFileResponse.path.toDartString());
  print(createFileResponse.fileName.toDartString());
  calloc.free(filePath);
}

源码中定义结构体接收golang静态库生成的结构体响应,具体的代码写法和数据类型参见第二小章节介绍的数据类型对应关系表。

dart官方ffi调用文档链接如下:C interop using dart:ffi | Dart,根据github里的仓库C代码,可以反推出cgo代码,当要传输不定长字符串时,使用*C.char作为golang端的输入输出参数,如果使用golang原生的string,需要在dart 中定义GoSting对象用来接收golang的string值,这种实现方式比较少见,资料也比较少。

如有不对的地方,希望能够指正,互相学习,互相进步!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值