使用 C2Go
多文件项目
编译多个 translation unit,使用 C2Go LTO,并安全绑定 archive。维护者C2Go contributors真实项目中,构成同一个生成 package 的所有 translation unit,必须使用一致的 package path、target、manifest schema 和两个 contract epoch。它们的最低 Go 版本与验证快照会按保守方式合并。
一次 driver 调用
最简单的多文件构建是把所有源码交给一次 c2go-clang 调用:
c2go-clang --target="$C2GO_TARGET" \
-fc2go \
-fc2go-package=example.com/acme/engine \
-O2 \
-fc2go-emit-plan9-asm=engine.s \
-fc2go-emit-manifest=engine.json \
parser.c runtime.c storage.c
driver 将每个源码编译为 bitcode,调用 c2go-lto,然后输出一对合并的汇编与 manifest。优化级别 2 及以上会启用跨 translation unit 内联。
正常绑定合并产物:
mkdir -p engine
c2go-bind \
--out=engine \
--sidecar=engine.json \
engine.s
直接驱动 c2go-lto
高级构建系统可以先生成 bitcode,再显式调用 linker:
c2go-clang --target="$C2GO_TARGET" \
-fc2go -fc2go-package=example.com/acme/engine -O2 -c \
parser.c runtime.c storage.c
c2go-lto parser.o runtime.o storage.o \
--c2go-emit-asm=engine.s \
--c2go-emit-manifest=engine.json
这些编译产物虽然使用 .o 后缀,内容却是 pre-link LLVM bitcode;它们属于 c2go-lto 输入,不能交给系统 linker。
常用选项:
| 选项 | 用途 |
|---|---|
--c2go-emit-archive=engine.a |
把汇编与 manifest member 打包进一个 ar archive |
--c2go-lto-inline=0 |
诊断时关闭跨单元内联 |
--c2go-escape-nonfatal |
抑制逃逸报告并返回成功;只用于受控诊断 |
--c2go-print-stats |
打印管线统计 |
不使用 nonfatal 选项时,退出码 0 表示干净,1 表示发现 stack-to-heap escape,2 表示工具或输入错误,3 表示跨 TU 属性冲突。Clang driver 的普通管线会传入 nonfatal 策略,因此 driver 构建成功不是逃逸安全门禁。发布构建必须执行独立的栈指针逃逸审计。
绑定多个输入或 archive
c2go-bind 也可以合并多个汇编输入,或直接读取 C2Go archive:
c2go-bind --out=engine a.s b.s
c2go-bind --out=engine engine.a
binder 会精确去重,并拒绝符号、类型、全局变量、linkname、GC mask、callback、target、manifest generation 或 contract epoch 冲突。
构建系统规则
把每个 .s 与其 manifest 视为不可拆分的一对。cache key 必须包含 target triple、package path、优化级别和协同工具链版本。不要在未经过 c2go-bind 生成目标选择结构的情况下,把不同 OS 产物塞进同一个 package。
可直接采用的 Makefile 规则、有限的 AR=c2go-lto 兼容边界以及 CMake custom target,见接入现有构建系统。
项目构建协调完成后,继续学习从 C 调用 Go。