Llgo
A Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python and JavaScript
Install / Use
/learn @goplus/LlgoREADME
llgo - A Go compiler based on LLVM
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 C ecosystem through the language's Application Binary Interface (ABI), while LLGo is compatible with Go through its syntax (source code). C ecosystem includes all languages that are ABI compatible with C (eg. C/C++, Python, JavaScript, Objective-C, Swift, etc).
C/C++ standard libary 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:
<!-- embedme doc/_readme/llgo_simple/simple.go -->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 some C standard libary related demos (it start 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 use go:linkname to link an extern symbol througth its 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:
<!-- embedme doc/_readme/llgo_call_c/call_c.go -->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):
<!-- embedme doc/_readme/llgo_call_cmath/call_cmath.go -->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!
And you can import any Python library into llgo through a program called llpyg (see Development tools). The following libraries have been included in llgo:
- 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
Note: For third-party libraries (such as pandas and pytorch), you still need to install the library files.
Here is an example:
<!-- embedme doc/_readme/llgo_call_py/call_py.go -->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:
<!-- embedme doc/_readme/llgo_call_py/call_math.py -->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 any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports.
The currently supported libraries 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 (It's 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
Go syntax support
All Go syntax (including cgo) is already supported. Here are some examples:
- concat: define a variadic function
- genints: various forms of closure usage (including C function, recv.method and anonymous function)
- errors: demo to implement error interface
- defer: defer demo
- goroutine: goroutine demo
Defer
LLGo now supports defer within loops, matching Go's semantics of executing defers in LIFO order for every iteration. The usual caveat from Go still applies: be mindful of loop-heavy defer usage because it allocates per iteration.
Garbage Collection (GC)
By default, LLGo implements gc based on bdwgc (also known as libgc).
However, you can disable gc by specifying the nogc tag. For example:
llgo run -tags nogc .
Go packages support
Here are the Go packages that can be imported correctly:
