cgo
Packages that import "C" build with marmot, and C calls are direct native calls.
New
cgo support is new. Cross builds of cgo packages are not supported yet.
Packages that import "C" build unchanged. marmot runs cmd/cgo and compiles the generated
code and the package's .c, .s and .S files with clang. #cgo CFLAGS, LDFLAGS and
pkg-config lines work, and are checked against the same allowlists as the go command.
package main
/*
#include <stdlib.h>
#include <string.h>
static int twice(int x) { return 2 * x; }
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
s := C.CString("marmot")
defer C.free(unsafe.Pointer(s))
fmt.Println(C.strlen(s), C.twice(21))
}Cheaper calls
A call to a C function is a direct native call with the C ABI, on the goroutine's own stack.
There is no argument frame and no switch to another stack. The runtime is told when a goroutine
enters and leaves C so the scheduler can keep other goroutines running; for functions marked
with both #cgo noescape and #cgo nocallback, and for libc leaf functions, even that is
reduced to a mark.
| cost of one call to an empty C function | marmot | go (cgo) |
|---|---|---|
| linux/amd64, -release | 2.3 ns | 33 to 57 ns |
In release builds the C code is compiled to LLVM bitcode and optimized together with the Go code, so small C functions can be inlined into Go.
What works
- C functions, variables, constants, structs, unions, arrays, enums and function pointers.
C.CString,C.GoString,C.GoStringN,C.GoBytes,C.CBytes,C.mallocandC.free.- The
errnosecond result. //export: C calling Go, including nested calls, blocking callbacks and threads created in C.marmot testof cgo packages.- Blocking C calls do not stop other goroutines.
Not yet
- Cross builds (
-target) of cgo packages.
A fault inside a C call stops the program with a fatal error.
M0111 heap allocation
marmot build -allocs lists where the program allocates on the heap and why the object could not live in the frame: it is returned, stored in memory that outlives the function or in a global, passed to a call that may keep it, captured by an escaping closure, converted to an interface, kept across loop iterations, or too large for the frame.
Agent setup
Use marmot from a coding agent, over the Model Context Protocol or as a plain command.