I need to write a function in GO, compile it as a shared library, and then call it from Dart. For example, to return a key as in the code below:
package main
func getKey() string {
theKey := "123-456-789"
return theKey
}
func main() {}
I need to write a function in GO, compile it as a shared library, and then call it from Dart. For example, to return a key as in the code below:
package main
func getKey() string {
theKey := "123-456-789"
return theKey
}
func main() {}
The answer is:
Part One the GO side:
GetKey()cgo so that we can create shared library, cgo means we need to:2.1. Use import "C"
2.2. Use comment with the function as //export GetKey
2.3. Use C.type interface, in this example to instead of string use C.char and C.CString and as working with pointer is the preferable way, use *C.char
So, the Go function in the question, should be re-written as:
// filename: lib.go
package main
import "C"
//export GetKey
func GetKey() *C.char {
theKey := "123-456-789"
return C.CString(theKey)
}
func main() {}
go build -buildmode=c-shared -o lib.a lib.go
Part Two the Dart side:
pubspec.yaml and add to its dependencies the ffi: ^0.1.3, so it be as:name: dart_app
description: A new Dart application.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
ffi: ^0.1.3
lib.a and lib.h to the dart projetc folderffi and the utf83.2. Define the FFI funtion signature as typedef get_key_func = ffi.Pointer<Utf8> Function();
3.3. Define the Dart funtion signature as typedef GetKey = ffi.Pointer<Utf8> Function();
3.4. Load the shared library as final dylib = ffi.DynamicLibrary.open('lib.a');
3.5. Map FFI and Dart function signatures as final GetKey getKey dylib.lookup<ffi.NativeFunction<get_key_func>>('GetKey').asFunction();
3.6. Define a function todo the execution, and inside this function do the following:
3.6.1. Invoke the Dart function and assign the output to a variabe as var addressOf = getKey();
3.6.2. Decode the result, which is the address of the pointer, and get the string from it, as: print(addressOf.ref.toString());
So, the Dart code will become:
//file name fficheck.dart
import 'dart:ffi' as ffi; // For FFI
import 'package:ffi/ffi.dart';
import 'package:ffi/src/utf8.dart';
typedef get_key_func = ffi.Pointer<Utf8> Function(); // FFI fn signature
typedef GetKey = ffi.Pointer<Utf8> Function(); // Dart fn signature
final dylib = ffi.DynamicLibrary.open('lib.a');
final GetKey getKey =
dylib.lookup<ffi.NativeFunction<get_key_func>>('GetKey').asFunction();
void testffi() {
print("Hi from dart");
var addressOf = getKey();
print(addressOf.ref.toString());
}
// file name lib.dart
import 'fficheck.dart';
main() {
print("Hello, World!");
testffi();
}
dart main.dartQuick note, not to go far from the scope of the question, if you return a string, then the return value from this function must be explicitly freed in the C code if if you call it from C code, but as you call it from garbage collector environment, Java/Kotlin you do not want to worry about it.
If freeing the allocated buffer isn't convenient, its common to fill a buffer provided by the caller:
func GetKey(buff *C.char, n int) int
If you can allocate the memory but don't want to handle C strings, you can insert the buffer into a pointer and return the size.
func GetKey(buff **C.char) int