LLGo - A Go compiler based on LLVM
August 22, 2026 · View on GitHub
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.
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).
Go support
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 cases using pinned Go 1.25 and Go 1.26 toolchains. Remaining applicable differences are recorded in xfail.yaml; gc-specific mechanisms outside LLGo's compatibility goals are documented in notapplicable.yaml.
| Target | Current coverage |
|---|---|
| Native | Linux amd64/arm64 and macOS amd64/arm64 release artifacts; primary CI on Linux amd64 and macOS arm64 |
| WebAssembly | js/wasm and wasip1/wasm builds; WASI and Emscripten CI coverage |
| Embedded | -target configurations for supported boards and MCUs, with selected QEMU/emulator smoke tests |
Runtime
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 (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 .
Standard libraries
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 with both supported toolchains.
Other targets may not provide every OS service or implementation-specific runtime behavior.
C/C++ standard library support
You can import a C/C++ standard library in LLGo!
- c
- c/syscall
- c/sys
- c/os
- c/math
- c/math/cmplx
- c/math/rand
- c/pthread
- c/pthread/sync
- c/sync/atomic
- c/time
- c/net
- cpp/std
Here is a simple example:
package main
import "github.com/goplus/lib/c"
func main() {
c.Printf(c.Str("Hello world\n"))
}
This is a simple example of calling the C printf function to print Hello world. Here, c.Str is not a function for converting a Go string to a C string, but a built-in instruction supported by llgo for generating a C string constant.
The _demo directory contains C library demos (it starts with _ to prevent the go command from compiling it):
- hello: call C
printfto printHello world - concat: call C
fprintfwithstderr - qsort: call C function with a callback (eg.
qsort)
To run these demos (If you haven't installed llgo yet, please refer to How to install):
cd <demo-directory> # eg. cd _demo/c/hello
llgo run .
How to support C/C++ and Python
LLGo uses go:linkname to link an external symbol through the C ABI:
import _ "unsafe" // for go:linkname
//go:linkname Sqrt C.sqrt
func Sqrt(x float64) float64
You can directly integrate it into your own code:
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 put it into a package (see c/math):
package main
import "github.com/goplus/lib/c/math"
func main() {
println("sqrt(2) =", math.Sqrt(2))
}
Python support
You can import a Python library in LLGo!
You can import Python libraries into llgo through llpyg (see Development tools). Available bindings include:
- py (abi)
- py/std (builtins)
- py/sys
- py/os
- py/math
- py/json
- py/inspect
- py/statistics
- py/numpy
- py/pandas
- py/torch
- py/matplotlib
Third-party libraries such as pandas and PyTorch must be installed separately.
Here is an example:
package main
import (
"github.com/goplus/lib/py"
"github.com/goplus/lib/py/math"
"github.com/goplus/lib/py/std"
)
func main() {
x := math.Sqrt(py.Float(2)) // x = sqrt(2)
std.Print(py.Str("sqrt(2) ="), x) // print("sqrt(2) =", x)
}
It is equivalent to the following Python code:
import math
x = math.sqrt(2)
print("sqrt =", x)
Here, We call py.Float(2) to create a Python number 2, and pass it to Python’s math.sqrt to get x. Then we call std.Print to print the result.
Let's look at a slightly more complex example. For example, we use numpy to calculate:
package main
import (
"github.com/goplus/lib/py"
"github.com/goplus/lib/py/numpy"
"github.com/goplus/lib/py/std"
)
func main() {
a := py.List(
py.List(1.0, 2.0, 3.0),
py.List(4.0, 5.0, 6.0),
py.List(7.0, 8.0, 9.0),
)
b := py.List(
py.List(9.0, 8.0, 7.0),
py.List(6.0, 5.0, 4.0),
py.List(3.0, 2.0, 1.0),
)
x := numpy.Add(a, b)
std.Print(py.Str("a+b ="), x)
}
Here we define two 3x3 matrices a and b, add them to get x, and then print the result.
The _demo/py/ directory contains some python related demos:
- callpy: call Python standard library function
math.sqrt - pi: print python constants
math.pi - statistics: define a python list and call
statistics.meanto get the mean - matrix: a basic
numpydemo
To run these demos (If you haven't installed llgo yet, please refer to How to install):
cd <demo-directory> # eg. cd _demo/py/callpy
llgo run .
Other frequently used libraries
LLGo can easily import libraries from the C ecosystem. C/C++ bindings are maintained manually, but the import process will be automated in the future, as with Python library imports.
Available bindings include:
- c/bdwgc
- c/cjson
- c/clang
- c/ffi
- c/libuv
- c/llama2
- c/lua
- c/neco
- c/openssl
- c/raylib
- c/sqlite
- c/zlib
- cpp/inih
- cpp/llvm
Here are some examples related to them:
- llama2-c: inference Llama 2 (the first LLGo AI example)
- mkjson: create a json object and print it
- sqlitedemo: a basic sqlite demo
- tetris: a tetris game based on raylib
Dependencies
- Go 1.25+ (to build LLGo; CI also validates user packages with pinned Go 1.25 and Go 1.26 toolchains)
- LLVM 19
- Clang 19
- LLD 19
- pkg-config 0.29+
- bdwgc/libgc 8.0+
- libffi
- libuv
- OpenSSL 3.0+
- zlib 1.2+
- Python 3.12+ (optional, for github.com/goplus/lib/py)
How to install
Follow these steps to install the llgo command, whose usage is similar to the go command:
on macOS
brew update
brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config
brew install python@3.12 # optional
brew link --overwrite llvm@19 lld@19 libffi
# curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash
./install.sh
on Linux
Debian/Ubuntu
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-19 main" | sudo tee /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 libunwind-19-dev libc++-19-dev pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libsqlite3-dev libuv1-dev
sudo apt-get install -y python3.12-dev # optional
#curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash
./install.sh
Alpine Linux
apk add go llvm19-dev clang19-dev lld19 pkgconf gc-dev libunwind-dev openssl-dev zlib-dev
apk add python3-dev # optional
apk add g++ # build only
export LLVM_CONFIG=/usr/lib/llvm19/bin/llvm-config
export CGO_CPPFLAGS="$($LLVM_CONFIG --cppflags)"
export CGO_CXXFLAGS=-std=c++17
export CGO_LDFLAGS="$($LLVM_CONFIG --ldflags) $($LLVM_CONFIG --libs all)"
curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash
docker alpine 386 llgo environment
export GCC_ROOT_DIR=$(gcc -print-search-dirs | grep 'install:' | awk -F': ' '{print \$2}')
export LDFLAGS="-L$GCC_ROOT_DIR -B$GCC_ROOT_DIR -Wl,-dynamic-linker,/lib/ld-musl-i386.so.1"
llgo run .
on Windows
TODO
Install from source
git clone https://github.com/xgo-dev/llgo.git
cd llgo
./install.sh
Development tools
- pydump: It is the first production program compiled with
llgorather thango. It outputs symbol information (functions, variables, and constants) from a Python library in JSON format, preparing for the generation of corresponding packages inllgo. - pysigfetch: It generates symbol information by extracting information from Python's documentation site. This tool is not part of the
llgoproject, but we depend on it. - llpyg: It is used to automatically convert Python libraries into Go packages that
llgocan import. It depends onpydumpandpysigfetchto accomplish the task. - llgen: It is used to compile Go packages into LLVM IR files (*.ll).
- gentests: It refreshes runtime-output and package-metadata golden data under
cl/_test*. LLVM IR checks live in Go sources as// LITTESTFileCheck directives. - litgen: It maintains explicitly opted-in, source-embedded FileCheck snapshots. It supports function/global selection, update-only operation, stale-check verification, and stable LLVM value abstractions. Small handwritten checks remain manual.
- ssadump: It is a Go SSA builder and interpreter.
For local workflows and test-golden refresh commands, see dev/README.md.
How do I generate these tools?
git clone https://github.com/xgo-dev/llgo.git
cd llgo
go install -v ./cmd/...
go install -v ./chore/... # compile all tools except pydump
export LLGO_ROOT=$PWD
cd _xtool
llgo install ./... # compile pydump
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
Key modules
Below are the key modules for understanding the implementation principles of llgo:
- ssa: It generates LLVM IR files (LLVM SSA) using the semantics and interfaces of Go SSA. Although
LLVM SSAandGo SSAare both IR languages, they work at completely different levels.LLVM SSAis closer to machine code and abstracts over different instruction sets, whileGo SSAis closer to a high-level language. We can think of it as the instruction set of theGo computer.llgo/ssais not limited to thellgocompiler. If we view it as providing the high-level expressive power ofLLVM, it is very useful. Its advanced SSA form lets clients use LLVM without operating directly on machine-code semantics. - cl: It is the core of the llgo compiler. It converts a Go package into LLVM IR files. It depends on
llgo/ssa. - internal/build: It strings together the entire compilation process of
llgo. It depends onllgo/ssaandllgo/cl.