I am trying to create the possibility to call a Rust function from Go and then said rust function makes a function call back to Go. I use CGO as an FFI interface between Go and Rust. The following is my Go code (src/main.go):
package main
import (
"C"
"fmt"
"unsafe"
)
/*
#cgo CFLAGS: -I./../lib
#cgo LDFLAGS: -L./../bin -lgo_move -Wl,-rpath=./bin
#include "move.h"
*/
//export cosmosCallbackWrapper
func cosmosCallbackWrapper(data *C.uchar, dataLen C.int) {
// Convert data to Go slice
goData := C.GoBytes(unsafe.Pointer(data), dataLen)
// Call the actual callback function
cosmosCallback(goData)
}
// SetCosmosCallback sets the callback function to be called by the Move VM.
func SetCosmosCallback(callback func([]byte)) {
cosmosCallback = callback
C.set_cosmos_callback((C.cosmos_callback)(unsafe.Pointer(C.cosmosCallbackWrapper)))
}
var cosmosCallback func([]byte)
func main() {
// Create a new Move interpreter
// Set the callback function
SetCosmosCallback(func(data []byte) {
fmt.Println("Received data from Move VM:", data)
// Handle data and call Cosmos SDK functions as needed
})
}
This is my Rust code (src/lib.rs)
use std::os::raw::{c_char, c_int};
use std::ffi::CString;
use std::sync::Mutex;
#[macro_use] extern crate lazy_static;
pub fn main() {
}
pub type CosmosCallback = extern "C" fn(*const c_char, c_int);
lazy_static! {
static ref CALLBACK: Mutex<Option<CosmosCallback>> = Mutex::new(None);
}
#[no_mangle]
pub extern "C" fn set_cosmos_callback(callback: CosmosCallback) {
let mut cb = CALLBACK.lock().unwrap();
*cb = Some(callback);
}
#[no_mangle]
pub extern "C" fn cosmosCallbackWrapper(data: *const c_char, data_len: c_int) {
let cb = CALLBACK.lock().unwrap();
if let Some(callback) = &*cb {
callback(data, data_len);
}
}
This is my Cargo.toml file:
[package]
name = "go-move"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
libc = "0.2"
lazy_static = "1.4.0"
[workspace]
members = [ ".",]
This is lib/move.h (the header file for the shared lib):
#ifndef MOVE_VM_LIB_H
#define MOVE_VM_LIB_H
#include <stdint.h>
//typedef void (*cosmos_callback)(const unsigned char *data, int data_len);
//void set_cosmos_callback(cosmos_callback callback);
typedef void (*cosmos_callback)(const uint8_t* data, int32_t data_len);
void set_cosmos_callback(cosmos_callback callback);
#endif
And this is my Makefile:
SHELL := /bin/bash
.PHONY: build
OS = $(shell uname)
clean:
rm -rf bin
rm -rf target
build:
@echo The OS is $(OS)
mkdir bin
cargo build --release
ifeq ($(OS),Linux)
cp target/release/libgo_move.so bin/
else
cp target/release/libgo_move.dylib bin/
endif
cp -a lib/. bin/
go build --ldflags="-L./bin -lgo_move" -o bin/main src/main.go
run:
export LD_LIBRARY_PATH=./bin && ./main
The File structure is as follows:
src
main.go
main.rs
bin
libgo_move.so (after cargo build)
lib
move.h
Cargo.toml
Makefile
After running make clean build
, I am getting the following output:
cp target/release/libgo_move.so bin/
cp -a lib/. bin/
go build -o bin/main src/main.go
# command-line-arguments
src/main.go:27:59: could not determine kind of name for C.cosmosCallbackWrapper
src/main.go:27:25: could not determine kind of name for C.cosmos_callback
src/main.go:27:2: could not determine kind of name for C.set_cosmos_callback
For some reason, it cant find the the ffi functions.
It was a silly mistake:
/*
#cgo CFLAGS: -I./../lib
#cgo LDFLAGS: -L./../bin -lgo_move -Wl,-rpath=./bin
#include "move.h"
*/
has to go prior to the imports. That's all it was.