LLGo: Go compiler based on LLVM that integrate Go with the C ecosystem LLGo, a Go compiler based on LLVM from the XGo project, aims to integrate Go with the C ecosystem by supporting Go 1.20+ source code and the complete Go 1.26 language syntax, including cgo. It uses a different runtime with native goroutines mapped 1:1 to OS threads and a conservative BDWGC garbage collector, enabling direct C calls without cgo overhead. The compiler supports native Linux and macOS targets, as well as js/wasm and wasip1/wasm builds, and allows importing C/C++ libraries directly via go:linkname bindings. LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem, including Python and JavaScript. It's a subproject of the XGo project https://github.com/goplus/xgo . LLGo aims to expand the boundaries of Go/XGo, providing limitless possibilities such as: - Game development - AI and data science - WebAssembly - Embedded development - ... How can these be achieved? LLGo := Go C ecosystem LLGo is compatible with the C ecosystem through the C Application Binary Interface ABI , while LLGo is compatible with Go at the source-code level . The C ecosystem includes languages that expose C-compatible interfaces e.g. C/C++, Python, JavaScript, Objective-C, and Swift . LLGo is compatible with Go 1.20+ source code and supports the complete Go 1.26 language syntax, as well as cgo . Compatibility is checked against applicable upstream GOROOT/test /xgo-dev/llgo/blob/main/test/goroot/README.md cases using pinned Go 1.25 and Go 1.26 toolchains. Remaining applicable differences are recorded in ; gc-specific mechanisms outside LLGo's compatibility goals are documented in /xgo-dev/llgo/blob/main/test/goroot/xfail.yaml xfail.yaml . /xgo-dev/llgo/blob/main/test/goroot/notapplicable.yaml notapplicable.yaml LLGo uses a different runtime from the standard Go toolchain. Native goroutines map 1:1 to OS threads with fixed native stacks, so direct C calls require no Go-to-C stack or scheduler transition, avoiding the cgo overhead that makes frequent C calls costly in standard Go. The default garbage collector is conservative BDWGC https://www.hboehm.info/gc/ also known as libgc . Bare-metal embedded targets instead use a TinyGo-derived conservative mark-and-sweep collector. Garbage collection can be disabled with the nogc build tag. For example: llgo run -tags nogc . LLGo fully supports the Go standard library on supported native platforms. CI requires compatibility coverage for every public package and exported symbol in the primary Go toolchain, and runs test/std /xgo-dev/llgo/blob/main/test/std/README.md with both supported toolchains. Other targets may not provide every OS service or implementation-specific runtime behavior. | Target | Current coverage | |---|---| | Native | Linux amd64/arm64 and macOS amd64/arm64 | js/wasm and wasip1/wasm builds; WASI and Emscripten CI coverage configurations for supported boards and MCUs, with selected QEMU/emulator smoke tests /xgo-dev/llgo/blob/main/doc/Embedded Cmd.md -target LLGo lets you import and call C/C++ libraries directly, without wrappers or cgo overhead. LLGo uses go:linkname to bind a Go declaration directly to a C ABI symbol: python import "unsafe" // for go:linkname //go:linkname Sqrt C.sqrt func Sqrt x float64 float64 You can use this directly in your own code: python package main import "unsafe" // for go:linkname //go:linkname Sqrt C.sqrt func Sqrt x float64 float64 func main { println "sqrt 2 =", Sqrt 2 } Or organize such bindings into a package, as c/math https://github.com/goplus/lib/tree/main/c/math/math.go does: package main import "github.com/goplus/lib/c/math" func main { println "sqrt 2 =", math.Sqrt 2 } Because calls into C compile to native calls against the C ABI, there is no Go-to-C stack or scheduler transition, so frequent C calls stay cheap. On Windows, bind APIs declared with WINAPI or stdcall through the stdcall. namespace. The convention is distinct on 386; Windows amd64 and arm64 use their unified native C ABI. An explicitly decorated 386 name such as MessageBoxW@16 is also accepted and is normalized to MessageBoxW on 64-bit targets. //go:linkname MessageBoxW stdcall.MessageBoxW func MessageBoxW hwnd uintptr, text, caption uint16, flags uint32 int32 //llgo:type stdcall type Callback func context uintptr uintptr stdcall. declarations and //llgo:type stdcall apply only to non-variadic function types. A native callback is one function pointer, so a Go callback must be a direct function reference; pass state through an explicit context pointer rather than a capturing closure. LLGo provides Go bindings for the C/C++ standard library: | Package | Description | |---|---| | c/syscall https://pkg.go.dev/github.com/goplus/lib/c/syscall c/sys https://pkg.go.dev/github.com/goplus/lib/c/sys c/os https://pkg.go.dev/github.com/goplus/lib/c/os c/math https://pkg.go.dev/github.com/goplus/lib/c/math c/math/cmplx https://pkg.go.dev/github.com/goplus/lib/c/math/cmplx c/math/rand https://pkg.go.dev/github.com/goplus/lib/c/math/rand c/pthread https://pkg.go.dev/github.com/goplus/lib/c/pthread c/pthread/sync https://pkg.go.dev/github.com/goplus/lib/c/pthread/sync c/sync/atomic https://pkg.go.dev/github.com/goplus/lib/c/sync/atomic c/time https://pkg.go.dev/github.com/goplus/lib/c/time c/net https://pkg.go.dev/github.com/goplus/lib/c/net cpp/std https://pkg.go.dev/github.com/goplus/lib/cpp/std Here is a simple example calling the C printf function: package main import "github.com/goplus/lib/c" func main { c.Printf c.Str "Hello world\n" } c.Str is not a runtime conversion from a Go string to a C string — it is a built-in instruction that llgo recognizes and compiles directly into a C string constant. Additional demos are available in the demo directory prefixed with so the go command skips them : hello /xgo-dev/llgo/blob/main/ demo/c/hello/hello.go : call C printf to print Hello world concat /xgo-dev/llgo/blob/main/ demo/c/concat/concat.go : call C fprintf with stderr qsort /xgo-dev/llgo/blob/main/ demo/c/qsort/qsort.go : call a C function that takes a callback e.g. qsort To run a demo see How to install how-to-install if llgo isn't installed yet : cd