LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of the Go+ project.
LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
How can these be achieved?
LLGo := Go + C + Python
LLGo is compatible with C and Python through the language's Application Binary Interface (ABI), while LLGo is compatible with Go through its syntax (source code).
You can import a C/C++ standard library in LLGo!
Here is a simple example:
package main
import "github.com/goplus/llgo/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):
printf
to print Hello world
fprintf
with stderr
qsort
)To run these demos (If you haven't installed llgo
yet, please refer to How to install):
cd <demo-directory> # eg. cd _demo/hello
llgo run .
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:
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/llgo/c/math"
func main() {
println("sqrt(2) =", math.Sqrt(2))
}
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
:
Note: For third-party libraries (such as pandas and pytorch), you still need to install the library files.
Here is an example:
package main
import (
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/math"
"github.com/goplus/llgo/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/llgo/py"
"github.com/goplus/llgo/py/numpy"
"github.com/goplus/llgo/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 _pydemo
directory contains some python related demos:
math.sqrt
math.pi
statistics.mean
to get the meannumpy
demoTo run these demos (If you haven't installed llgo
yet, please refer to How to install):
cd <demo-directory> # eg. cd _pydemo/callpy
llgo run .
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:
Here are some examples related to them:
All Go syntax (not including cgo
) is already supported. Here are some examples:
LLGo defer
does not support usage in loops. This is not a bug but a feature, because we think that using defer
in a loop is a very unrecommended practice.
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 .
Here are the Go packages that can be imported correctly:
Follow these steps to generate the llgo
command (its usage is the same as the go
command):
brew update
brew install llvm@18 pkg-config bdw-gc openssl
brew install python@3.12 # optional
go install -v github.com/goplus/llgo/cmd/llgo@latest
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-18 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-18-dev clang-18 lld-18 pkg-config libgc-dev libssl-dev zlib1g-dev
sudo apt-get install -y python3.12-dev # optional
go install -v github.com/goplus/llgo/cmd/llgo@latest
TODO
llgo
(NOT go
) in a production environment. It outputs symbol information (functions, variables, and constants) from a Python library in JSON format, preparing for the generation of corresponding packages in llgo
.llgo
project, but we depend on it.llgo
can import. It depends on pydump
and pysigfetch
to accomplish the task.How do I generate these tools?
git clone https://github.com/goplus/llgo.git
cd llgo
go install -v ./chore/... # compile all tools except pydump
cd chore/_xtool
llgo install ./... # compile pydump
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
Below are the key modules for understanding the implementation principles of llgo
:
LLVM SSA
and Go SSA
are both IR languages, they work at completely different levels. LLVM SSA
is closer to machine code, which abstracts different instruction sets. While Go SSA
is closer to a high-level language. We can think of it as the instruction set of the Go computer
. llgo/ssa
is not just limited to the llgo
compiler. If we view it as the high-level expressive power of LLVM
, you'll find it very useful. Prior to llgo/ssa
, you had to operate LLVM
using machine code semantics. But now, with the advanced SSA form (in the semantics of Go SSA), you can conveniently utilize LLVM
.llgo/ssa
.llgo
. It depends on llgo/ssa
and llgo/cl
.