在 7 月 28 日 ,dart在pub上发布了ffigen,用于解析c/cpp头文件,来自动生成能够对应调用的dart函数。java
因为 dart 对于底层的 c 语言的有些函数还不支持,好比我遇到的,对文件描述符的操做,还有诸多须要用ffi
的地方,例如视频的解码等,拿在 Flutter 上使用 dart 的状况,对于视频解码类,咱们通常是经过原生通道,让java/kotlin
、swift
去调c/cpp
,我以前的文章也自实现了dart ffi
调用ffmpeg
解码来实现视屏播放。linux
而使用原生通道这个思路来调一些c/cpp
其实就画蛇添足了,并且增长了很多的平台代码,不方便移植与适配,除非目前的视频播放器类,还不能彻底离开平台的一些支持,因此其余能脱离平台的,咱们无需再经过平台插件。android
在 Flutter 官方放出 ffi 在Flutter上的使用,我就比较关注,并借此完成了一个残废的终端模拟器 😄 。ios
c/cpp
经过交叉编译各个平台,windows
的dll
,unix
系统的so
库,而后经过DynamicLibrary
的open
函数去打开这个库,来得到其中函数的动态连接。随即按套路编写dart
调用ffi
的代码便可。每一个平台都有一些已经有的so
库,若是咱们的 c/cpp 语言实现的都是一些全部unix
设备或者windows
设备底层自带so、dll
中的函数,咱们不妨将里面每个函数都转换成dart
端能够对应调用的函数,也就是生成一个dart
可用的 ".h" 头,固然这个扩展名仍是 ".dart" 。macos
这样一来,咱们无需再为了 windows、macos、linux、android、ios
这5个平台分别交叉编译一份动态库,咱们只须要写一份通用的dart
代码便可。ubuntu
更多的是在linux、macos、android上。 这种思路一些开发者也早就想到过,包括 Flutter 前不久放出了一个在 Flutter平台调用一个win32 api 的例子swift
有兴趣看这个包---> win32windows
一个使用FFI包装一些最多见的Win32 API调用的程序包,使它们可使用Dart代码进行访问,而无需C编译器或Windows SDK。api
安装 libclangdev - sudo apt-get install libclang-dev
.数组
安装 Visual Studio with C++ development support.
安装 LLVM or winget install -e --id LLVM.LLVM.
安装 Xcode。
安装 LLVM - brew install llvm
。
# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
name: dart_ffi
environment:
sdk: '>=2.8.1 <3.0.0'
dev_dependencies:
ffigen: ^0.1.5
ffi: ^0.1.3
# ffigen:
# name: Dirent
# description: dirent.h 头文件在dart的移植.
# output: 'dirent.dart'
# headers:
# entry-points:
# - '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/dirent.h'
ffigen:
name: Stdio
description: stdio.h 头文件在dart的移植.
output: 'stdio.dart'
headers:
entry-points:
- '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h'
复制代码
而后执行pub get
我想经过一个项目来解析多个头文件,采用了比较 low 的注释来实现,须要解析哪一个,就单独放开哪部分的注释。
更多请移步ffigen。
执行pub run ffigen
好像不太顺利,其中的警告就是,c 语言的有些变量是 "_" 开头的,被转换后在 dart 会限制为私有。
还有一些 error 直接被我注释掉了,是一些不会用到的函数或变量。
我新建了一个 test.dart 文件以下
import 'dart:convert';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'stdio.dart';
void main() {
Stdio stdio = Stdio(DynamicLibrary.process());
String str = '123\n';
List<int> list = utf8.encode(str);
print(list);
Pointer<Int8> data = allocate<Int8>(count: 4);
for (int i = 0; i < list.length; i++) {
data[i] = list[i];
}
stdio.printf(data);
str = '456\n';
data = Utf8.toUtf8(str).cast<Int8>();
stdio.printf(data);
free(data);
}
复制代码
printf
函数的参数为Pointer<Int8>
,能够理解成一维数组,跟c语言的char
与int[]
都是差很少的,而c语言的char
在dart
中对应类型是Pointer<Utf8>
,其实都是8位的数组,因此我使用了两种传参方式,第二种要更方便。
还有须要注意,若是你的程序不是立马就结束的,好比一个 Flutter app ,请在任何使用完
allocate
函数后对它及时的释放,例如Utf8.toUtf8
这个函数,内部也使用的allocate
函数。
这样就在
dart
完成了c
语言printf
函数的调用。
其实按照c
语言的预编译思想,被调用到函数的实如今编译期间会copy
到当前文件,因此你能够根据本身使用到的去转换后的dart
删减来节省编译后的内存。