Introduction

Go's CGO allows calling C code from Go, but cross-compiling CGO-enabled programs requires a C cross-compilation toolchain for the target platform. Without it, the linker fails with errors like "exec gcc not found" or "cannot find -lc".

This is common when building Docker images for different architectures or creating cross-platform binaries with native dependencies.

Symptoms

  • go build fails with "exec gcc: not found" when cross-compiling
  • Linker error "cannot find -lc" or "ld: library not found for -lSystem"
  • Build works for GOOS/GOARCH matching the host but fails for other targets

Common Causes

  • No C cross-compilation toolchain installed for the target platform
  • CGO_ENABLED=1 is set but no cross-compiler is available
  • Missing target-specific C libraries or headers

Step-by-Step Fix

  1. 1.Disable CGO for pure Go builds: If your code doesn't actually need CGO, disable it.
  2. 2.```bash
  3. 3.# Check if your code uses CGO:
  4. 4.go list -f '{{.CgoFiles}}' ./...

# If no CGO files, disable CGO for cross-compilation: CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o myapp-linux-arm64

# Pure Go cross-compiles without any C toolchain ```

  1. 1.Install cross-compilation toolchain: Install the appropriate cross-compiler for the target.
  2. 2.```bash
  3. 3.# On Ubuntu/Debian for Linux ARM64:
  4. 4.sudo apt-get install -y gcc-aarch64-linux-gnu

# Then cross-compile: CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build

# For Windows from Linux: sudo apt-get install -y gcc-mingw-w64-x86-64 CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build ```

  1. 1.Use Docker for cross-compilation: Build in a container with the target toolchain.
  2. 2.```dockerfile
  3. 3.FROM golang:1.22 AS builder
  4. 4.RUN apt-get update && apt-get install -y \
  5. 5.gcc-aarch64-linux-gnu \
  6. 6.gcc-x86-64-linux-gnu

ARG TARGETARCH RUN if [ "$TARGETARCH" = "arm64" ]; then \ export CC=aarch64-linux-gnu-gcc; \ fi && \ CGO_ENABLED=1 GOARCH=$TARGETARCH go build -o /app/myapp ./cmd/myapp ```

  1. 1.Use zig as a universal C compiler for cross-compilation: Zig ships with cross-compilation support built-in.
  2. 2.```bash
  3. 3.# Use zig as CC for any target:
  4. 4.CC="zig cc -target x86_64-linux" CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build
  5. 5.CC="zig cc -target aarch64-linux" CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build
  6. 6.CC="zig cc -target x86_64-windows" CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build
  7. 7.`

Prevention

  • Prefer pure Go packages over CGO-dependent packages when possible
  • Use Docker with buildx for reproducible cross-platform builds
  • Document the required C toolchains for each target platform
  • Consider using zig cc for reliable cross-compilation of C dependencies