You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go通过CGO调用Rust并实现回调时出现FFI函数查找失败问题

问题根源与解决步骤

以下是针对CGO无法识别Rust导出的FFI函数问题的具体解决方法:

1. 修正Rust函数的C导出规范

Rust导出的函数必须添加#[no_mangle]禁用名字修饰,并使用extern "C"遵循C调用约定,确保CGO能识别函数名:

use std::os::raw::c_char;

// 保存回调函数指针的静态变量
static mut CALLBACK: Option<extern "C" fn(*const c_char)> = None;

#[no_mangle]
pub extern "C" fn set_cosmos_callback(callback: extern "C" fn(*const c_char)) {
    unsafe {
        CALLBACK = Some(callback);
    }
}

#[no_mangle]
pub extern "C" fn cosmos_callback(msg: *const c_char) {
    unsafe {
        if let Some(cb) = CALLBACK {
            cb(msg);
        }
    }
}

2. 确保头文件与Rust函数签名完全匹配

move.h头文件必须准确声明所有要调用的FFI函数,大小写、参数类型完全一致:

#ifndef MOVE_H
#define MOVE_H

#ifdef __cplusplus
extern "C" {
#endif

// 声明Rust导出的函数
void set_cosmos_callback(void (*callback)(const char*));
void cosmos_callback(const char* msg);

// 声明Go导出给Rust的回调包装函数
void cosmosCallbackWrapper(const char* msg);

#ifdef __cplusplus
}
#endif

#endif

3. 配置Makefile正确链接Rust静态库

Makefile需要先编译Rust生成静态库,再让CGO编译时链接该库:

.PHONY: clean build

build:
    # 编译Rust生成静态库
    cargo build --release
    # 复制静态库到当前目录
    cp target/release/libmove.a .
    # 编译Go代码,指定头文件路径和链接参数
    go build -ldflags="-L. -lmove" -o go_rust_callback main.go

clean:
    cargo clean
    rm -f libmove.a go_rust_callback

4. 修正Go代码的CGO引入规则

Go代码必须通过#cgo指令指定头文件和链接参数,且//export声明要放在import "C"之前:

package main

// #cgo CFLAGS: -I.
// #cgo LDFLAGS: -L. -lmove
// #include "move.h"
import "C"
import "unsafe"

//export cosmosCallbackWrapper
func cosmosCallbackWrapper(msg *C.char) {
    goMsg := C.GoString(msg)
    println("Rust回调Go函数,收到消息:", goMsg)
}

func main() {
    // 向Rust注册Go回调函数
    C.set_cosmos_callback(C.cosmosCallbackWrapper)
    
    // 调用Rust函数,触发回调
    msg := C.CString("Hello from Go")
    defer C.free(unsafe.Pointer(msg))
    C.cosmos_callback(msg)
}

5. 调整Cargo.toml生成静态库

在Cargo.toml中配置生成静态库,确保CGO能直接链接:

[package]
name = "move"
version = "0.1.0"
edition = "2021"

[lib]
name = "move"
crate-type = ["staticlib"] # 生成静态库,避免动态库路径问题

6. 排查名字修饰问题

如果仍报错,用nm命令检查Rust库中的函数名是否为C风格的未修饰名称:

nm target/release/libmove.a | grep set_cosmos_callback

若输出的函数名包含额外前缀(如_Z...),说明未添加#[no_mangle],需重新检查Rust代码。

内容的提问来源于stack exchange,提问作者a6i09per5f

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:02:34