Open-Source Wikis

/

Go

/

Components

/

cgo

golang/go

cgo

cmd/cgo (in src/cmd/cgo/) is the bridge between Go and C. It is a preprocessor: when a Go package imports the special pseudo-package "C", the go command runs cgo first to translate the package's .go files into a mix of regular Go files and generated C glue files.

The runtime side of cgo lives in src/runtime/cgo/ and src/runtime/cgocall.go. Together they let Go call into C and vice versa.

Purpose

cgo solves three problems:

  1. Calling C from Go. A Go function calls into C; cgo generates the calling-convention adapter on both sides.
  2. Calling Go from C. The reverse — typically used for callbacks. cgo generates a Go-callable trampoline registered with the runtime.
  3. C type interop. Go code can declare variables of C types (C.int, C.struct_foo, C.char), and cgo generates Go shadow types matching the underlying ABI.

How it works

graph TD
    Source[foo.go with import "C"] --> Cgo[cmd/cgo]
    CHeader[CGO_CFLAGS, // #include comments] --> Cgo
    Cgo --> GoOut[_cgo_gotypes.go, _cgo_defun.c, _cgo_main.c, etc.]
    GoOut --> Compile[cmd/compile + host C compiler]
    Compile --> Link[cmd/link external mode]
    Link --> Binary

Step-by-step for a package that uses cgo:

  1. cmd/go detects an import "C" line.
  2. It invokes cmd/cgo, passing the Go source files plus any in-comment #cgo directives:
    // #cgo CFLAGS: -DFOO=1
    // #include <stdio.h>
    import "C"
  3. cmd/cgo parses the Go file, finds C.foo references, and generates several outputs in a temporary directory:
    • _cgo_gotypes.go — Go declarations for every C type and function used.
    • _cgo_main.c, _cgo_export.c — C glue.
    • Modified .go files where C.foo(args) becomes _Cfunc_foo(args).
  4. cmd/go then compiles the generated Go files with cmd/compile and the C glue with the host C compiler.
  5. The package archive contains both Go-compiled objects and C-compiled objects.
  6. cmd/link links them, using external linkmode if the C side requires the host linker.

What cgocall does at runtime

When Go code calls a C function, control reaches runtime.cgocall (in src/runtime/cgocall.go):

  1. Save the current G's state.
  2. Switch to the M's g0 (system) stack.
  3. Lock the M to the current OS thread (some C libraries require thread affinity).
  4. Call into the C function via asmcgocall (per-arch assembly).
  5. On return, swap back to the user G.

The reverse direction (C calls Go) goes through cgoCallback, which:

  1. Acquires a G (creates one if needed) on the calling thread.
  2. Switches from C to Go calling convention.
  3. Runs the Go callback.
  4. Returns control to the C caller.

These transitions are expensive relative to a normal Go function call, which is why cgo is reserved for "I really need C" cases, not for normal interop.

Directory layout

src/cmd/cgo/
├── doc.go                 # User-facing cgo manual ('go help cgo')
├── main.go                # Entry: parse args, drive
├── ast.go                 # Walk Go AST for C.foo references
├── gcc.go                 # Invoke C compiler to extract types/decls
├── out.go                 # Emit Go and C glue files
├── godefs.go              # Support 'godefs' mode
├── doc.go                 # Manual page
├── internal/
│   ├── test/              # cgo integration tests (programs)
│   ├── teststdio/, testtls/, ... # Specialized tests
│   └── ...
src/runtime/cgo/
├── cgo.go                 # Public symbols visible from cgo-emitted code
├── callbacks.go           # Go ↔ C callback table
├── gcc_<os>.c             # Host C glue per OS (signal handling, TLS, ...)
├── asm_<arch>.s           # Per-arch trampolines
└── ...
src/runtime/cgocall.go     # Runtime side of Go→C calls

Key source files

File Purpose
src/cmd/cgo/main.go cgo driver
src/cmd/cgo/gcc.go Use the host C compiler to extract types
src/cmd/cgo/out.go Emit generated Go and C glue (the largest cgo file)
src/cmd/cgo/doc.go The cgo user manual; output of go doc cmd/cgo
src/runtime/cgocall.go Go→C and C→Go runtime helpers
src/runtime/cgo/asm_<arch>.s Per-arch trampolines
src/runtime/cgo/callbacks.go Callback registration

CGO flags

In a Go file, #cgo lines configure the C compile/link environment per-package:

// #cgo CFLAGS: -I${SRCDIR}/include
// #cgo LDFLAGS: -L${SRCDIR}/lib -lfoo
// #cgo darwin LDFLAGS: -framework Cocoa
// #cgo pkg-config: openssl
// #include "foo.h"
import "C"

CGO_ENABLED=0 disables cgo entirely (and the build system removes any _cgo files from the build set).

CC, CC_FOR_TARGET, CXX_FOR_TARGET choose the C/C++ compilers. See src/make.bash for the full list.

Testing cgo

A substantial chunk of cgo correctness lives under src/cmd/cgo/internal/:

  • test/, testcarchive/, testcshared/ — integration tests for various build modes.
  • teststdio/, testtls/, testsanitizers/ — specialized scenarios.
  • testlife/, testfortran/, etc. — language interop and unusual languages.

These run as part of cmd/dist test (the cgo_test bucket).

Special considerations

  • GC interaction. When Go code calls C, the Go GC must not move or reclaim Go objects whose pointers were passed across the boundary. The compiler's cgocheck (cheap; default) and cgocheck2 (GODEBUG=cgocheck=1/2, deeper) catch many violations. runtime.Pinner (in src/runtime/pinner.go) lets you explicitly pin a Go object for cgo.
  • Linkmode. cgo usually forces -linkmode=external (host linker), which is slower than internal linking but required for many C libraries.
  • Thread-locking. When entering C, the calling goroutine is locked to its OS thread. C code that calls back into Go gets a fresh G but the same thread.
  • Signal handling. Cgo-enabled binaries have a more elaborate signal-handler dance (in runtime/signal_*.go and runtime/cgo/gcc_*.c) to coexist with C libraries that install their own handlers.

Integration points

  • cmd/go (go-command) drives cgo invocation per package.
  • cmd/compile (compiler) consumes the Go files cgo generates.
  • cmd/link (linker) typically runs in external mode for cgo packages.
  • runtime (runtime) provides the call-into-C and call-from-C primitives.
  • net, os/user, crypto/internal/... — several standard library packages use cgo when CGO_ENABLED=1 for OS-native resolvers and crypto.

Entry points for modification

  • Cgo bug in code generation: start in src/cmd/cgo/out.go. Many bugs end up here.
  • Cgo runtime issue: src/runtime/cgocall.go and src/runtime/cgo/asm_<arch>.s.
  • Adding a build mode for cgo: usually touches both cmd/go, cmd/link, and runtime/cgo.
  • src/cmd/cgo/doc.go — the user-facing cgo manual.
  • Runtime — the GMP scheduler's interaction with cgo, signal handling.
  • Linker — when external linking is required and how it differs.
  • Go command — how cgo invocation fits into the build pipeline.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

cgo – Go wiki | Factory