开始使用
项目概览
理解 C2Go 会生成什么、代码在哪里运行,以及它适合解决哪些问题。维护者C2Go contributorsC2Go 是 Clang 的一种编译模式,它会把 C 源码编译成可由 Go 工具链构建的 Go package 产物。生成的代码运行在 Go runtime 下:使用 goroutine 栈和调度器,可以分配 Go GC 可见的对象,也可以跨越 C/Go 边界调用函数。
这是提前编译,不会把 C 编译器嵌入应用,也不会在程序启动时临时编译 C。
工具链会生成什么
对于一组 C 源文件,c2go-clang 会生成:
- 交给 Go assembler 的 Plan 9 汇编(
.s); - 描述导出符号、类型、目标平台、回调和链接参数的 JSON manifest。
c2go-bind 读取汇编与 manifest,把生成的 .go、.s 文件写入普通 Go package,最后由 go build 或 go test 完成构建。
生成的 package 不使用 import "C"。c2go-libc 集成 PureGo 原生调用桥,因此消费者可以在 CGO_ENABLED=0、没有宿主 C 编译器的环境中构建;只有生成阶段需要 C2Go 工具链。
C 源码
│
▼
c2go-clang + c2go-lto
│ Plan 9 汇编 + JSON manifest
▼
c2go-bind
│ 生成的 .go + .s package
▼
Go 工具链 + c2go-libc
它与普通 C 有什么区别
C2Go 明确区分两个内存世界。当前实现的 translation unit 默认是 unmanaged;通常使用无参数的 #pragma c2go managed push 区域启用全部 managed 默认行为,也可以通过 record/pointer 属性进行局部标注:
- managed 值参与 Go runtime 的内存模型,并携带精确 GC 元数据;
- unmanaged 值表示原生 C 内存或外部 C ABI 边界。
这个区别让编译器能够保留精确的 GC 信息。代价是:某些普通 C 中不会检查的操作,如果可能让 GC 看不到指针,在 C2Go 中会产生 warning 或 error。
<c2go.h> 提供的主要扩展包括:
| 特性 | 用途 |
|---|---|
gc_malloc 与 c2go_typeinfo |
在 Go heap 上分配带类型的对象 |
c2go_extern |
将已定义的 C 函数导出给 Go |
c2go_linkname |
将 C 声明绑定到 Go 符号 |
unmanaged |
显式标记原生 C 表示或边界 |
c2go_callback / c2go_callout |
在边界两侧传递可调用函数指针 |
c2go_returntype |
用 C struct 描述 Go 多返回值 |
每个扩展的完整拼写、类别和限制见 C2Go 扩展速查。
当前版本基线
当前协同版本的基线是:
- 只支持 C,不支持 C++;
- 只生成 64 位
amd64与arm64代码; - 当前 SDK 支持 Go 1.25.x 与 Go 1.26.x;
- 每个 OS 与架构分别生成产物;
- 项目仍处于 pre-1.0,API 与 ABI 细节可能变化。
发布页列出真正构建并测试过的宿主 SDK。迁移现有 C 库前,请阅读平台与当前限制;语言、ABI、回调与打包边界以该页为准。
什么时候适合使用 C2Go
当你希望复用或迁移 C 实现,同时向使用者暴露普通 Go package 时,C2Go 很有价值。对于需要 Go 管理内存、或希望比独立进程边界更深入地接入 Go runtime 的代码尤其如此。
它目前还不能无差别替代所有 cgo 项目。不要因为上游 Clang 能接受某种写法,就默认它已经进入 C2Go 的发布契约;采用前应以链接的限制页为检查清单。
下一步
先安装匹配的 SDK与 Go runtime module,然后在 Hello World 中编译第一个导出 C 函数。