{"slug": "llgo-go-compiler-based-on-llvm-that-integrate-go-with-the-c-ecosystem", "title": "LLGo: Go compiler based on LLVM that integrate Go with the C ecosystem", "summary": "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.", "body_md": "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).\n\nLLGo aims to expand the boundaries of Go/XGo, providing limitless possibilities such as:\n\n- Game development\n- AI and data science\n- WebAssembly\n- Embedded development\n- ...\n\nHow can these be achieved?\n\n```\nLLGo := Go * C ecosystem\n```\n\nLLGo 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).\n\nLLGo is compatible with Go 1.20+ source code and supports the complete Go 1.26 language syntax, as well as `cgo`\n\n.\n\nCompatibility 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\n\n[; gc-specific mechanisms outside LLGo's compatibility goals are documented in](/xgo-dev/llgo/blob/main/test/goroot/xfail.yaml)\n\n`xfail.yaml`\n\n[.](/xgo-dev/llgo/blob/main/test/goroot/notapplicable.yaml)\n\n`notapplicable.yaml`\n\nLLGo 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.\n\nThe 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.\n\nGarbage collection can be disabled with the `nogc`\n\nbuild tag. For example:\n\n```\nllgo run -tags nogc .\n```\n\nLLGo 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.\n\nOther targets may not provide every OS service or implementation-specific runtime behavior.\n\n| Target | Current coverage |\n|---|---|\n| Native | Linux amd64/arm64 and macOS amd64/arm64\n|\n\n`js/wasm`\n\nand `wasip1/wasm`\n\nbuilds; 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`\n\nLLGo lets you import and call C/C++ libraries directly, without wrappers or cgo overhead.\n\nLLGo uses `go:linkname`\n\nto bind a Go declaration directly to a C ABI symbol:\n\n``` python\nimport _ \"unsafe\" // for go:linkname\n\n//go:linkname Sqrt C.sqrt\nfunc Sqrt(x float64) float64\n```\n\nYou can use this directly in your own code:\n\n``` python\npackage main\n\nimport _ \"unsafe\" // for go:linkname\n\n//go:linkname Sqrt C.sqrt\nfunc Sqrt(x float64) float64\n\nfunc main() {\n\tprintln(\"sqrt(2) =\", Sqrt(2))\n}\n```\n\nOr organize such bindings into a package, as [c/math](https://github.com/goplus/lib/tree/main/c/math/math.go) does:\n\n```\npackage main\n\nimport \"github.com/goplus/lib/c/math\"\n\nfunc main() {\n\tprintln(\"sqrt(2) =\", math.Sqrt(2))\n}\n```\n\nBecause 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.\n\nOn Windows, bind APIs declared with `WINAPI`\n\nor `__stdcall`\n\nthrough the\n`stdcall.`\n\nnamespace. The convention is distinct on 386; Windows amd64 and\narm64 use their unified native C ABI. An explicitly decorated 386 name such as\n`_MessageBoxW@16`\n\nis also accepted and is normalized to `MessageBoxW`\n\non\n64-bit targets.\n\n```\n//go:linkname MessageBoxW stdcall.MessageBoxW\nfunc MessageBoxW(hwnd uintptr, text, caption *uint16, flags uint32) int32\n\n//llgo:type stdcall\ntype Callback func(context uintptr) uintptr\n```\n\n`stdcall.`\n\ndeclarations and `//llgo:type stdcall`\n\napply only to non-variadic\nfunction types. A native callback is one function pointer, so a Go callback\nmust be a direct function reference; pass state through an explicit context\npointer rather than a capturing closure.\n\nLLGo provides Go bindings for the C/C++ standard library:\n\n| Package | Description |\n|---|---|\n|\n\n[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`\n\nfunction:\n\n```\npackage main\n\nimport \"github.com/goplus/lib/c\"\n\nfunc main() {\n\tc.Printf(c.Str(\"Hello world\\n\"))\n}\n```\n\n`c.Str`\n\nis not a runtime conversion from a Go string to a C string — it is a built-in instruction that `llgo`\n\nrecognizes and compiles directly into a C string constant.\n\nAdditional demos are available in the `_demo`\n\ndirectory (prefixed with `_`\n\nso the `go`\n\ncommand skips them):\n\n[hello](/xgo-dev/llgo/blob/main/_demo/c/hello/hello.go): call C`printf`\n\nto print`Hello world`\n\n[concat](/xgo-dev/llgo/blob/main/_demo/c/concat/concat.go): call C`fprintf`\n\nwith`stderr`\n\n[qsort](/xgo-dev/llgo/blob/main/_demo/c/qsort/qsort.go): call a C function that takes a callback (e.g.`qsort`\n\n)\n\nTo run a demo (see [How to install](#how-to-install) if `llgo`\n\nisn't installed yet):\n\n```\ncd <demo-directory>  # e.g. cd _demo/c/hello\nllgo run .\n```\n\nBeyond the standard library, LLGo can import libraries from across the C/C++ ecosystem. Bindings are currently maintained by hand; automating this process, as is already done for Python library imports, is planned for the future.\n\nAvailable bindings include:\n\n[c/bdwgc](https://pkg.go.dev/github.com/goplus/lib/c/bdwgc)[c/cjson](https://pkg.go.dev/github.com/goplus/lib/c/cjson)[c/clang](https://pkg.go.dev/github.com/goplus/lib/c/clang)[c/ffi](https://pkg.go.dev/github.com/goplus/lib/c/ffi)[c/libuv](https://pkg.go.dev/github.com/goplus/lib/c/libuv)[c/llama2](https://pkg.go.dev/github.com/goplus/lib/c/llama2)[c/lua](https://pkg.go.dev/github.com/goplus/lib/c/lua)[c/neco](https://pkg.go.dev/github.com/goplus/lib/c/neco)[c/openssl](https://pkg.go.dev/github.com/goplus/lib/c/openssl)[c/raylib](https://pkg.go.dev/github.com/goplus/lib/c/raylib)[c/sqlite](https://pkg.go.dev/github.com/goplus/lib/c/sqlite)[c/zlib](https://pkg.go.dev/github.com/goplus/lib/c/zlib)[cpp/inih](https://pkg.go.dev/github.com/goplus/lib/cpp/inih)[cpp/llvm](https://pkg.go.dev/github.com/goplus/lib/cpp/llvm)\n\nExamples built on these bindings:\n\n[llama2-c](/xgo-dev/llgo/blob/main/_demo/c/llama2-c): inference Llama 2 (the first LLGo AI example)[mkjson](https://github.com/goplus/lib/tree/main/c/cjson/_demo/mkjson/mkjson.go): create a JSON object and print it[sqlitedemo](https://github.com/goplus/lib/tree/main/c/sqlite/_demo/sqlitedemo/demo.go): a basic SQLite demo[tetris](https://github.com/goplus/lib/tree/main/c/raylib/_demo/tetris/tetris.go): a Tetris game based on raylib\n\nYou can import a Python library in LLGo!\n\nYou can import Python libraries into `llgo`\n\nthrough `llpyg`\n\n(see [Development tools](#development-tools)). Available bindings include:\n\n[py](https://pkg.go.dev/github.com/goplus/lib/py)(abi)[py/std](https://pkg.go.dev/github.com/goplus/lib/py/std)(builtins)[py/sys](https://pkg.go.dev/github.com/goplus/lib/py/sys)[py/os](https://pkg.go.dev/github.com/goplus/lib/py/os)[py/math](https://pkg.go.dev/github.com/goplus/lib/py/math)[py/json](https://pkg.go.dev/github.com/goplus/lib/py/json)[py/inspect](https://pkg.go.dev/github.com/goplus/lib/py/inspect)[py/statistics](https://pkg.go.dev/github.com/goplus/lib/py/statistics)[py/numpy](https://pkg.go.dev/github.com/goplus/lib/py/numpy)[py/pandas](https://pkg.go.dev/github.com/goplus/lib/py/pandas)[py/torch](https://pkg.go.dev/github.com/goplus/lib/py/torch)[py/matplotlib](https://pkg.go.dev/github.com/goplus/lib/py/matplotlib)\n\nThird-party libraries such as pandas and PyTorch must be installed separately.\n\nHere is an example:\n\n```\npackage main\n\nimport (\n\t\"github.com/goplus/lib/py\"\n\t\"github.com/goplus/lib/py/math\"\n\t\"github.com/goplus/lib/py/std\"\n)\n\nfunc main() {\n\tx := math.Sqrt(py.Float(2))       // x = sqrt(2)\n\tstd.Print(py.Str(\"sqrt(2) =\"), x) // print(\"sqrt(2) =\", x)\n}\n```\n\nIt is equivalent to the following Python code:\n\n``` python\nimport math\n\nx = math.sqrt(2)\nprint(\"sqrt =\", x)\n```\n\nHere, We call `py.Float(2)`\n\nto create a Python number 2, and pass it to Python’s `math.sqrt`\n\nto get `x`\n\n. Then we call `std.Print`\n\nto print the result.\n\nLet's look at a slightly more complex example. For example, we use `numpy`\n\nto calculate:\n\n```\npackage main\n\nimport (\n\t\"github.com/goplus/lib/py\"\n\t\"github.com/goplus/lib/py/numpy\"\n\t\"github.com/goplus/lib/py/std\"\n)\n\nfunc main() {\n\ta := py.List(\n\t\tpy.List(1.0, 2.0, 3.0),\n\t\tpy.List(4.0, 5.0, 6.0),\n\t\tpy.List(7.0, 8.0, 9.0),\n\t)\n\tb := py.List(\n\t\tpy.List(9.0, 8.0, 7.0),\n\t\tpy.List(6.0, 5.0, 4.0),\n\t\tpy.List(3.0, 2.0, 1.0),\n\t)\n\tx := numpy.Add(a, b)\n\tstd.Print(py.Str(\"a+b =\"), x)\n}\n```\n\nHere we define two 3x3 matrices a and b, add them to get x, and then print the result.\n\nThe `_demo/py/`\n\ndirectory contains some python related demos:\n\n[callpy](/xgo-dev/llgo/blob/main/_demo/py/callpy/callpy.go): call Python standard library function`math.sqrt`\n\n[pi](/xgo-dev/llgo/blob/main/_demo/py/pi/pi.go): print python constants`math.pi`\n\n[statistics](/xgo-dev/llgo/blob/main/_demo/py/statistics/statistics.go): define a python list and call`statistics.mean`\n\nto get the mean[matrix](/xgo-dev/llgo/blob/main/_demo/py/matrix/matrix.go): a basic`numpy`\n\ndemo\n\nTo run these demos (If you haven't installed `llgo`\n\nyet, please refer to [How to install](#how-to-install)):\n\n```\ncd <demo-directory>  # eg. cd _demo/py/callpy\nllgo run .\n```\n\n[Go 1.25+](https://go.dev)(to build LLGo; CI also validates user packages with pinned Go 1.25 and Go 1.26 toolchains)[LLVM 19](https://llvm.org)[Clang 19](https://clang.llvm.org)[LLD 19](https://lld.llvm.org)[pkg-config 0.29+](https://gitlab.freedesktop.org/pkg-config/pkg-config)[bdwgc/libgc 8.0+](https://www.hboehm.info/gc/)[libffi](https://sourceware.org/libffi/)[libuv](https://libuv.org/)[OpenSSL 3.0+](https://www.openssl.org/)[zlib 1.2+](https://github.com/madler/zlib)[Python 3.12+](https://www.python.org)(optional, for[github.com/goplus/lib/py](https://pkg.go.dev/github.com/goplus/lib/py))\n\nFollow these steps to install the `llgo`\n\ncommand, whose usage is similar to the `go`\n\ncommand:\n\n```\nbrew update\nbrew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config\nbrew install python@3.12 # optional\nbrew link --overwrite llvm@19 lld@19 libffi\n# curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash\n./install.sh\necho \"deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-19 main\" | sudo tee /etc/apt/sources.list.d/llvm.list\nwget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -\nsudo apt-get update\nsudo 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\nsudo apt-get install -y python3.12-dev # optional\n#curl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash\n./install.sh\napk add go llvm19-dev clang19-dev lld19 pkgconf gc-dev libunwind-dev openssl-dev zlib-dev\napk add python3-dev # optional\napk add g++ # build only\nexport LLVM_CONFIG=/usr/lib/llvm19/bin/llvm-config\nexport CGO_CPPFLAGS=\"$($LLVM_CONFIG --cppflags)\"\nexport CGO_CXXFLAGS=-std=c++17\nexport CGO_LDFLAGS=\"$($LLVM_CONFIG --ldflags) $($LLVM_CONFIG --libs all)\"\ncurl https://raw.githubusercontent.com/xgo-dev/llgo/refs/heads/main/install.sh | bash\n```\n\ndocker alpine 386 llgo environment\n\n```\nexport GCC_ROOT_DIR=$(gcc -print-search-dirs | grep 'install:' | awk -F': ' '{print $2}')\nexport LDFLAGS=\"-L$GCC_ROOT_DIR -B$GCC_ROOT_DIR -Wl,-dynamic-linker,/lib/ld-musl-i386.so.1\"\nllgo run .\n```\n\nTODO\n\n```\ngit clone https://github.com/xgo-dev/llgo.git\ncd llgo\n./install.sh\n```\n\n[pydump](/xgo-dev/llgo/blob/main/_xtool/pydump): It is the first production program compiled with`llgo`\n\nrather than`go`\n\n. It outputs symbol information (functions, variables, and constants) from a Python library in JSON format, preparing for the generation of corresponding packages in`llgo`\n\n.[pysigfetch](https://github.com/goplus/hdq/tree/main/chore/pysigfetch): It generates symbol information by extracting information from Python's documentation site. This tool is not part of the`llgo`\n\nproject, but we depend on it.[llpyg](/xgo-dev/llgo/blob/main/chore/llpyg): It is used to automatically convert Python libraries into Go packages that`llgo`\n\ncan import. It depends on`pydump`\n\nand`pysigfetch`\n\nto accomplish the task.[llgen](/xgo-dev/llgo/blob/main/chore/llgen): It is used to compile Go packages into LLVM IR files (*.ll).[gentests](/xgo-dev/llgo/blob/main/chore/gentests): It refreshes runtime-output and package-metadata golden data under`cl/_test*`\n\n. LLVM IR checks live in Go sources as`// LITTEST`\n\nFileCheck directives.[litgen](/xgo-dev/llgo/blob/main/chore/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](/xgo-dev/llgo/blob/main/chore/ssadump): It is a Go SSA builder and interpreter.\n\nFor local workflows and test-golden refresh commands, see [dev/README.md](/xgo-dev/llgo/blob/main/dev/README.md#6-refresh-test-goldens).\n\nHow do I generate these tools?\n\n```\ngit clone https://github.com/xgo-dev/llgo.git\ncd llgo\ngo install -v ./cmd/...\ngo install -v ./chore/...  # compile all tools except pydump\nexport LLGO_ROOT=$PWD\ncd _xtool\nllgo install ./...   # compile pydump\ngo install github.com/goplus/hdq/chore/pysigfetch@v0.8.1  # compile pysigfetch\n```\n\nBelow are the key modules for understanding the implementation principles of `llgo`\n\n:\n\n[ssa](https://pkg.go.dev/github.com/xgo-dev/llgo/ssa): It generates LLVM IR files (LLVM SSA) using the semantics and interfaces of Go SSA. Although`LLVM SSA`\n\nand`Go SSA`\n\nare both IR languages, they work at completely different levels.`LLVM SSA`\n\nis closer to machine code and abstracts over different instruction sets, while`Go SSA`\n\nis closer to a high-level language. We can think of it as the instruction set of the`Go computer`\n\n.`llgo/ssa`\n\nis not limited to the`llgo`\n\ncompiler. If we view it as providing the high-level expressive power of`LLVM`\n\n, it is very useful. Its advanced SSA form lets clients use LLVM without operating directly on machine-code semantics.[cl](https://pkg.go.dev/github.com/xgo-dev/llgo/cl): It is the core of the llgo compiler. It converts a Go package into LLVM IR files. It depends on`llgo/ssa`\n\n.[internal/build](https://pkg.go.dev/github.com/xgo-dev/llgo/internal/build): It strings together the entire compilation process of`llgo`\n\n. It depends on`llgo/ssa`\n\nand`llgo/cl`\n\n.", "url": "https://wpnews.pro/news/llgo-go-compiler-based-on-llvm-that-integrate-go-with-the-c-ecosystem", "canonical_source": "https://github.com/xgo-dev/llgo", "published_at": "2026-08-29 04:16:59+00:00", "updated_at": "2026-08-29 04:48:37.508215+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence"], "entities": ["LLGo", "XGo project", "LLVM", "Go", "BDWGC", "TinyGo", "Emscripten", "WASI"], "alternates": {"html": "https://wpnews.pro/news/llgo-go-compiler-based-on-llvm-that-integrate-go-with-the-c-ecosystem", "markdown": "https://wpnews.pro/news/llgo-go-compiler-based-on-llvm-that-integrate-go-with-the-c-ecosystem.md", "text": "https://wpnews.pro/news/llgo-go-compiler-based-on-llvm-that-integrate-go-with-the-c-ecosystem.txt", "jsonld": "https://wpnews.pro/news/llgo-go-compiler-based-on-llvm-that-integrate-go-with-the-c-ecosystem.jsonld"}}