[Dart, C, Go, Flutter] Вызов кода Go из Dart с использованием cgo и Dart FFI на простом примере
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Ключевой мотивацией для написания данной статьи является факт сильного недостатка информации (особенно в русскоязычном сообществе) по использованию cgo и Dart FFI для вызова Go кода из языка Dart.Язык Dart, не смотря на свою возрастающую популярность, на данный момент до сих пор не имеет такого же большого сообщества, как у языка Go. Dart заточен под выполнение других задач, по этому он иногда не содержит тех реализаций и функционала, который уже есть на языке Go.В случае если можно можно избежать экспорта go кода в Dart (например экспортировать готовую c библиотеку), то лучше воспользоваться такой возможностью и не использовать cgo. Однако, могут возникать случаи, когда перегонка go в dart кода является оптимальным решением (например вы уже знакомы с Go и Dart, и не хотите писать код на C, в таком случае есть смысл задуматься об использованием cgo и Dart FFI).В данной статье на простом примере будет показано как можно вызвать код Go из языка Dart (например в приложениях на Flutter).Что должно быть установлено:
- Go
- Dart
- Текстовый редактор/IDE (я буду использовать VSCode, так как это самая популярная среда среди Dart и Go сообщества, так же будут установлены специальные плагины для поддержки языков Go и Flutter)
Шаг 1 - Создаем пустое консольное приложение на Dart
Вызываем 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.Далее при написании своих функций следует учитывать, что форматы данных в языках Go, C и Dart могут отличаться (и зачастую так происходит), что приводит к необходимости использовать различные конвертации на стороне go/dart кода, более подробно можно ознакомиться по следующим ссылкам:
Полный код на Dart:
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());
}
При необходимости передавать параметры в вызываемую функцию можно использовать поинтеры и объявить их в вызываемой функции, например:
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();
Главное помнить, что необходимо проверять форматы передаваемых данных.
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность, Криптография, JavaScript, Node.JS, Криптовалюты] Поиск коллизий в SHA-256 на платформе Node.js при помощи Bitcoin Hasher
- [Интернет-маркетинг, Бизнес-модели, Социальные сети и сообщества, Транспорт, IT-компании] «Развод» компаний: Mail.ru Group заберёт себе фудтех и отдаст Сбербанку транспорт
- [Экология] Цифровые технологии не спасут окружающую среду?
- [Системное администрирование, Серверное администрирование, DevOps] Аварии как опыт #3. Как мы спасали свой мониторинг во время аварии в OVH
- [Программирование, Разработка мобильных приложений, Dart, Flutter] Flutter 2.2: что нового (перевод)
- [Настройка Linux, Информационная безопасность, Open source, *nix] Linux-дистрибутивы для анонимной работы в интернете — что нового?
- [Научно-популярное, Биотехнологии, Химия, Экология] Суперклей 2.0: адгезивный материал, вдохновленный морскими обитателями
- Arch Linux прекращает поддержку MD5 и SHA1 для новых паролей
- [Haskell, Функциональное программирование] Заберите свои скобки
- [Сетевые технологии, Беспроводные технологии, Разработка систем связи, Научно-популярное, Космонавтика] Всё о проекте «Спутниковый интернет Starlink». Часть 31. Описание антенны Ка-диапазона
Теги для поиска: #_dart, #_c, #_go, #_flutter, #_dart, #_cgo, #_flutter, #_golang, #_ffi, #_go, #_dart, #_c, #_go, #_flutter
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:15
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Ключевой мотивацией для написания данной статьи является факт сильного недостатка информации (особенно в русскоязычном сообществе) по использованию cgo и Dart FFI для вызова Go кода из языка Dart.Язык Dart, не смотря на свою возрастающую популярность, на данный момент до сих пор не имеет такого же большого сообщества, как у языка Go. Dart заточен под выполнение других задач, по этому он иногда не содержит тех реализаций и функционала, который уже есть на языке Go.В случае если можно можно избежать экспорта go кода в Dart (например экспортировать готовую c библиотеку), то лучше воспользоваться такой возможностью и не использовать cgo. Однако, могут возникать случаи, когда перегонка go в dart кода является оптимальным решением (например вы уже знакомы с Go и Dart, и не хотите писать код на C, в таком случае есть смысл задуматься об использованием cgo и Dart FFI).В данной статье на простом примере будет показано как можно вызвать код Go из языка Dart (например в приложениях на Flutter).Что должно быть установлено:
Вызываем 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 // 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() {} go build -buildmode=c-shared -o lib.a lib.go
Она должна содержать следующие файлы:
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()); } 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()); } 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(); =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:15
Часовой пояс: UTC + 5