搜索文档搜索当前语言
开始使用
候选版本v0.20260809.0-rc.5

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

开始使用

Hello World

将一个 C 函数编译成 Go package,并在 Go 测试中调用它。

本章会把一个 C 加法函数编译成 Go package,并在 Go 测试中调用它。开始前,请确认匹配版本的 SDK 已加入 PATH,并把 C2GO_TARGET 设置为下载平台包对应的 target triple。

1. 创建 Go module

mkdir hello-c2go
cd hello-c2go
mkdir .c2go
go mod init example.com/hello-c2go
go get github.com/c2gohq/c2go_libc@v0.20260809.0-rc.5

设置与 SDK 匹配的 triple。以 macOS arm64 为例:

export C2GO_TARGET=aarch64-apple-darwin

2. 编写 C 函数

创建 .c2go/input.c:

#include <stdint.h>
#include <c2go.h>

c2go_extern int add(int a, int b) {
    return a + b;
}

c2go_extern 会把一个已经定义的 C 函数导出。默认 Go 名称会按下划线分段转换为 CamelCase:add 生成 Add,sqlite3_open 生成 Sqlite3Open。

C 的 int 在这些 64 位 target 上仍是 32 位,因此生成签名是 func Add(a, b int32) int32,不是 Go 的机器字宽 int。测试中的 20 和 22 是无类型常量,可以直接传入。

请把 C 源码和编译器中间产物放在隐藏的 .c2go/ 目录。未启用 cgo 时,Go command 会拒绝 package 目录中的普通 .c 文件;package discovery 会忽略点号开头的目录。

3. 使用 c2go-clang 编译

c2go-clang --target="$C2GO_TARGET" \
  -fc2go \
  -fc2go-package=example.com/hello-c2go/translated \
  -O2 \
  -fc2go-emit-plan9-asm=.c2go/translated.s \
  -fc2go-emit-manifest=.c2go/translated.json \
  .c2go/input.c

编译器会写入 .c2go/translated.s 与 .c2go/translated.json;这条 emit 路径不会产生可用的 translated.o 目标文件。

4. 生成 Go package

mkdir -p translated
c2go-bind \
  --out=translated \
  --sidecar=.c2go/translated.json \
  .c2go/translated.s

输出目录现在包含 Go 声明、汇编、ABI guard、runtime 胶水和生成代码授权记录。再分发生成的 package 时,应保留这些授权文件。

5. 从 Go 调用

在 module 根目录创建 add_test.go:

package hello_c2go_test

import (
    "testing"

    "example.com/hello-c2go/translated"
)

func TestAdd(t *testing.T) {
    got := translated.Add(20, 22)
    if got != 42 {
        t.Fatalf("translated.Add(20, 22) = %d, want 42", got)
    }
}

运行测试:

go test ./...

预期结果:

ok  example.com/hello-c2go
?   example.com/hello-c2go/translated  [no test files]

刚才发生了什么

编译器针对选定的 Go OS 与架构,把 C 降低成 Plan 9 汇编。manifest 告诉 c2go-bind:add 是导出函数、汇编使用哪个 target 和 contract epoch、以及需要哪些 runtime 支持。c2go-bind 生成 Go 可见的 Add 声明,并把匹配的汇编复制到 package 中。

下一章进入构建管线,理解 target、package path、汇编和 manifest 为什么必须保持一致。