搜索文档搜索当前语言
互操作
候选版本v0.20260809.0-rc.5

本文档对应当前协同发布候选版本。

互操作

原生库

导入宿主 C ABI 符号,同时明确保持 managed 边界。

在当前实现中,只有声明、没有定义的普通函数默认就是 unmanaged host import。因此普通原生函数只需要常规 C 声明,不要求写 unmanaged extern。符号会通过宿主 C ABI 从真实 .so、.dylib 或 .dll 解析。

显式 unmanaged extern 是可选但更强的契约:它表示该函数之后不会再得到 C2Go 定义。当参数或返回值本身是函数指针时,它还会选择 host-callback 函数指针规则。回调章节只因这个特殊目的使用显式形式。

声明导入

#include <c2go.h>

extern double vendor_scale(double value);

c2go_extern double scaled_value(double value) {
    return vendor_scale(value);
}

未使用的普通声明不会进入生成的 import metadata。显式 unmanaged extern 即使未被 C 代码引用,也可以继续暴露给生成的 Go;这也是只在确实需要该契约时才使用显式形式的另一个原因。

c2go_extern 不是 import 标记:它把一个 C 定义导出给 Go。这两个概念有意保持分离。

告诉 c2go-bind 加载哪个库

绑定时传入动态库名称和可选搜索目录:

c2go-bind \
  --out=native \
  --sidecar=native.json \
  -l vendor \
  -L /opt/example/lib \
  native.s

manifest 通常会决定需要 Unix 还是 Windows dispatch glue。--extern-os=unix|windows 只用于受控覆盖,不应用它掩盖 target mismatch。

无 cgo 构建

C2Go 生成的是普通 Go 文件和 Plan 9 汇编,不会生成 import "C"。c2go-libc 在 Unix 上使用固定版本的 PureGo bridge 完成原生调用;Windows 使用对应的 syscall bridge。因此生成后的 package 可以在关闭 cgo 的环境构建:

CGO_ENABLED=0 go build ./...

最终构建不需要宿主 C 编译器。若程序调用外部动态库,该 .so、.dylib 或 .dll 在运行时仍然必须存在;无 cgo 不等于把第三方动态库静态打进程序。

指针仍然需要所有权规则

wrapper 负责 calling convention 和 runtime transition,但不会凭空创造所有权策略。传递指针前必须明确:

  • 内存由哪一侧分配;
  • callee 是否在返回后继续保存;
  • buffer 是否可能包含 managed 指针;
  • 最终由哪一侧释放。

如果外部库会保存 buffer,应遵守该库规定的 allocator/释放函数,或改用稳定 handle;不能假定 c2go-libc 的 malloc 就是宿主系统 allocator。把 managed 指针传过边界可能产生有损转换 warning,并需要明确设计生命周期。

受支持的调用形状

当前 Unix 与 Windows target 支持标量、指针、float 和 double 导入。在目标 ABI 限制内支持小 record 按值传递;更大或特殊形状会使用 wrapper 或 fail closed。变参导入和平台特有 record 应增加专门的跨目标测试。

直接调用与函数指针

调用 vendor_scale(value) 会自动经过生成的宿主桥。如果需要 C2Go 可调用的函数指针,使用 c2go_callout(vendor_scale);如果需要把原生地址交回另一个 native API,使用 &vendor_scale,但不要从 C2Go 直接调用这个裸地址。

下一章通过回调详细说明两个方向。