參考官網文章: https://dart.dev/guides/libraries/c-interop
1. 使用 linux 作業系統, 安裝好dart sdk , c 語言編譯程式加上 cmake
2. 新增一個 dart 專案, 專案內新增一個 hello 目錄 , 進入 hello 目錄, 準備要編譯成 hello 模組(libhello.so):
2.1 先在 hello 目錄裡面編輯一個檔案 CMakeLists.txt:
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(hello_library VERSION 1.0.0 LANGUAGES C)
add_library(hello_library SHARED hello.c hello.def)
add_executable(hello_test hello.c)
set_target_properties(hello_library PROPERTIES
PUBLIC_HEADER hello.h
VERSION ${PROJECT_VERSION}
SOVERSION 1
OUTPUT_NAME "hello"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Hex_Identity_ID_Goes_Here"
)
2.2. 為了指示要將函數(testWork, add, reverse 等等) 導出來(export)使用, 要編輯一個文字檔案 hello.def:
LIBRARY hello
EXPORTS
testWork
add
reverse
2.3. 編輯一個 c 程式,用來宣告函式原型的標頭檔 hello.h:
void testWork( );
int add(int a, double b);
char *reverse(char *str);
2.4. 編輯 c 模組程式的原始碼 hello.c:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "hello.h"
int main( ) {
testWork( );
printf("3 + 5 = %d\n", add(3, 5));
printf("%s\n",reverse("Hello-String") );
return 0;
}
void testWork( ) {
printf("It works!\n");
}
int add(int a, double b) {
return a + b;
}
char *_bufferPointer = NULL;
int _buffrLength = 0;
char *reverse(char *src) {
int size = strlen(src);
if(size == 0) return NULL;
else if(size > _buffrLength) { // allocate if space not enough
if(_bufferPointer != NULL) free(_bufferPointer);
_bufferPointer = (char *)malloc(size + 1);//from heap
_buffrLength = size;// maximum characters to hold
}
_bufferPointer[size] = '\0';// eos
for (int i = 0; i < size; i++) _bufferPointer[size - 1 - i] = src[i];// reverse
return _bufferPointer;
}
2.5 上述檔案都編輯完成後就能執行 make 作業, 製作成動態程式庫 (hello/libhello.so)
cmake .
make
3. 在專案內新增 pubspec.yaml 檔案, 完成後, 開啟終端機執行 pub get 準備使用 ffi:
name: cinterop
version: 0.0.1
description: >-
An example of calling C code from Dart through FFI
author: MyName<email@google.com>
environment:
sdk: '>=2.6.0 <3.0.0'
dependencies:
ffi: ^0.1.3
dev_dependencies:
test: ^1.5.3
4.編輯一個透過 ffi 界面呼叫 c 語言的 dart 範例程式 main.dart:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
main( ) {
final libso = DynamicLibrary.open('hello/libhello.so');
final testFun= libso.lookup<NativeFunction<Void Function( )>>('testWork').
asFunction<void Function()>();
final addFun = libso.lookup<NativeFunction<Int32 Function(Int32, Double)>>('add').
asFunction<int Function(int,double)>( );
final revFun = libso.lookup<NativeFunction<Pointer<Utf8> Function(Pointer<Utf8>)>>('reverse').
asFunction<Pointer<Utf8> Function(Pointer<Utf8>)>( );
final c2dartString = (Pointer<Utf8> _pointer) => Utf8.fromUtf8(_pointer);
final dartstring2c = (String _string) => Utf8.toUtf8(_string);
final reverse = (String _string) => c2dartString(revFun(dartstring2c(_string)));
testFun( );
print('adder: 334 + 5 = ${addFun(334, 5.0)}');
for(int i=0; i<20 ; i++) print('${reverse("$i.Hello-string")}');
}
5. 用 dart VM 執行上述 main.dart 看看: /pathToDartSDK/bin/dart main.dart
It works!
adder: 334 + 5 = 339
gnirts-olleH.0
gnirts-olleH.1
gnirts-olleH.2
gnirts-olleH.3
gnirts-olleH.4
gnirts-olleH.5
gnirts-olleH.6
gnirts-olleH.7
gnirts-olleH.8
gnirts-olleH.9
gnirts-olleH.01
gnirts-olleH.11
gnirts-olleH.21
gnirts-olleH.31
gnirts-olleH.41
gnirts-olleH.51
gnirts-olleH.61
gnirts-olleH.71
gnirts-olleH.81
gnirts-olleH.91
後記: dart SDK 的 dart2native 可以將原始碼轉成可執行檔, 不用 dart VM, 直接就能執行:
/pathToDartSDK/bin/dart2native main.dart && ./main.exe
沒有留言:
張貼留言