Getting started
Overview
What C2Go produces, where it runs, and when it is a good fit.Maintained byC2Go contributorsC2Go is a Clang mode that compiles C source into artifacts the Go toolchain can build as a Go package. The resulting code runs under the Go runtime: it uses goroutine stacks and scheduling, can allocate objects visible to the Go garbage collector, and can call across the C/Go boundary.
This is ahead-of-time compilation. C2Go does not embed a C compiler in your application and it does not compile C at startup.
What the toolchain produces
For one or more C translation units, c2go-clang produces:
- Plan 9 assembly (
.s) for the Go assembler; - a JSON manifest describing exported symbols, types, target information, callbacks, and linker inputs.
c2go-bind consumes the assembly and manifest and writes generated .go and .s files into a normal Go package. go build or go test completes the build.
The generated package does not use import "C". c2go-libc integrates a PureGo native-call bridge, so consumers can build with CGO_ENABLED=0 and no host C compiler; only the generation step requires the C2Go toolchain.
C source
│
▼
c2go-clang + c2go-lto
│ Plan 9 assembly + JSON manifest
▼
c2go-bind
│ generated .go + .s package
▼
Go toolchain + c2go-libc
What is different from ordinary C
C2Go adds an explicit distinction between two memory worlds. In the current implementation, the translation-unit default is unmanaged. Normally, use a bare #pragma c2go managed push region to enable every managed default, or apply record/pointer attributes for local annotations:
- managed values participate in the Go runtime’s memory model and carry precise GC metadata;
- unmanaged values represent native C memory and external C ABI boundaries.
That distinction lets the compiler preserve precise GC information. It also means some C operations that are normally unchecked become warnings or errors when they could hide pointers from the collector.
The public extensions in <c2go.h> include:
| Feature | Purpose |
|---|---|
gc_malloc and c2go_typeinfo |
Allocate typed objects on the Go heap |
c2go_extern |
Export a defined C function to Go |
c2go_linkname |
Bind a C declaration to a Go symbol |
unmanaged |
Explicitly mark a native representation or boundary |
c2go_callback / c2go_callout |
Move callable function pointers across the boundary |
c2go_returntype |
Describe a Go multi-value result with a C struct |
For the complete spelling, category, and constraints of each extension, use the C2Go extensions reference.
Release baseline
The current coordinated release is built around:
- C only; C++ is not supported;
- 64-bit
amd64andarm64code generation; - Go 1.25.x and Go 1.26.x for the current SDK release;
- separate generated output for each OS and architecture; and
- pre-1.0 APIs and ABI details that may still change.
The release page lists the host SDK archives that are actually built and tested. Before migrating an existing library, review Platforms and current limitations for the canonical language, ABI, callback, and packaging boundaries.
When to use C2Go
C2Go is useful when you want to port or reuse C implementation code while presenting a normal Go package to its consumers. It is especially relevant when the code benefits from Go-managed allocation or needs tighter runtime integration than a conventional process boundary.
It is not yet a drop-in replacement for every cgo project. Use the linked limitations page as the adoption checklist instead of assuming that every construct accepted by upstream Clang is part of the C2Go release contract.
Next step
Install the matching SDK and Go runtime module, then compile one exported C function in Hello World.