Appeler le code Go de Dart en utilisant cgo et Dart FFI avec un exemple simple

La principale motivation pour écrire cet article est le fait d'un fort manque d'information (surtout dans la communauté russophone) sur l'utilisation de cgo et Dart FFI pour appeler du code Go depuis le langage Dart.





Le langage Dart, malgré sa popularité croissante, n'a pas encore pour le moment la même grande communauté que le langage Go. Dart est conçu pour effectuer d'autres tâches, il ne contient donc parfois pas les implémentations et les fonctionnalités que Go possède déjà.





Si vous pouvez éviter d'exporter le code go vers Dart (par exemple, exporter une bibliothèque prête à l'emploi), il est alors préférable d'utiliser cette opportunité et de ne pas utiliser cgo. Cependant, il peut y avoir des cas où la distillation du code go in dart est la solution optimale (par exemple, vous êtes déjà familiarisé avec Go et Dart et ne souhaitez pas écrire de code en C, auquel cas il est logique de penser à utiliser cgo et Dart FFI).





Dans cet article, à l'aide d'un exemple simple, il sera montré comment vous pouvez appeler du code Go à partir du langage Dart (par exemple, dans les applications Flutter).





Ce qu'il faut installer :





  • Va





  • Dard





  • Éditeur de texte / IDE (j'utiliserai VSCode, car c'est l'environnement le plus populaire parmi la communauté Dart and Go, des plugins spéciaux seront également installés pour prendre en charge les langues Go et Flutter)





Étape 1 - Créez une application de console de fléchettes vierge

Command Palette F1 Dart, Console Application ( , cgo Flutter Dart).





, cgo_dartffi_helloworld, . ( Dart, ffi pubspec.yaml ).





.





2 - ffi yaml

ffi yaml go dart.





name: cgo_dartffi_helloworld
description: A sample command-line application.
version: 1.0.0

environment:
  sdk: '>=2.12.0 <3.0.0'

dependencies:
  path: ^1.8.0
  ffi: ^0.1.3

dev_dependencies:
  pedantic: ^1.10.0
  test: ^1.16.0
      
      



3 - .go

go, ( , lib.go) Dart. - HelloFromGo().





// filename: lib.go
package main

import "C"

//export HelloFromGo
func HelloFromGo() *C.char {
	message := "Hello to dart lang from go"
	return C.CString(message)
}

func main() {}

      
      



cgo , . cgo (, ), ( export). cgo https://golang.org/cmd/cgo/, .





4 - go

:





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



lib.a ( c ). ( , go, go, cgo).





5 -

:





:





  • pubspec.yaml





  • lib.h, lib.a lib.go





  • bin dart ( )





6 - cgo Dart

( ) . ( ), .





  • 6.1 - bin/cgo_dartffi_helloworld.dart





  • 6.2 - ( ffi utf8 )





import 'dart:ffi' as ffi;
import 'package:ffi/src/utf8.dart';
      
      



  • 6.3 -






final dylib = ffi.DynamicLibrary.open('lib.a');

      
      



  • 6.4 - dart





typedef HelloFromGo = ffi.Pointer<Utf8> Function();
typedef HelloFromGoFunc = ffi.Pointer<Utf8> Function();
final HelloFromGo _finalFunction = dylib
    .lookup<ffi.NativeFunction<HelloFromGoFunc>>('HelloFromGo')
    .asFunction();
      
      



  • 6.5 - ( , .toDartString C Dart):





void main() {
  print(_finalFunction().toDartString());
}
      
      



go, string Dart.





De plus, lors de l'écriture de vos fonctions, vous devez tenir compte du fait que les formats de données dans les langages Go, C et Dart peuvent différer (et cela arrive souvent), ce qui entraîne la nécessité d'utiliser diverses conversions sur le code go/dart côté, pour plus de détails, voir les liens suivants :





  • https://github.com/dart-lang/samples/tree/master/ffi





  • https://golang.org/cmd/cgo/





Code complet de la fléchette :





import 'dart:ffi' as ffi;
import 'package:ffi/src/utf8.dart';

final dylib = ffi.DynamicLibrary.open('lib.a');

typedef HelloFromGo = ffi.Pointer<Utf8> Function();
typedef HelloFromGoFunc = ffi.Pointer<Utf8> Function();
final HelloFromGo _finalFunction = dylib
    .lookup<ffi.NativeFunction<HelloFromGoFunc>>('HelloFromGo')
    .asFunction();

void main() {
  print(_finalFunction().toDartString());
}

      
      



Si vous devez passer des paramètres à la fonction appelée, vous pouvez utiliser des pointeurs et les déclarer dans la fonction appelée, par exemple :





typedef GetHash = Pointer<Utf8> Function(Pointer<Utf8> str);
typedef GetHashFunc = Pointer<Utf8> Function(Pointer<Utf8> str);
final GetHash _getHashGoFunction =
    _lib.lookup<NativeFunction<GetHashFunc>>('GetHash').asFunction();
      
      



La principale chose à retenir est que vous devez vérifier les formats des données transmises.








All Articles