goplus / llgo

A Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python
Apache License 2.0
344 stars 26 forks source link

llgo - A Go compiler based on LLVM

Build Status Go Report Card GitHub release Coverage Status GoDoc Language

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).

C/C++ standard libary support

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):

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 .

How 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:

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))
}

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:

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:

To 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 .

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:

Here are some examples related to them:

Go syntax support

All Go syntax (not including cgo) is already supported. Here are some examples:

Defer

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.

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:

Dependencies

How to install

Follow these steps to generate the llgo command (its usage is the same as the go command):

on macOS

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

on Linux (Debian/Ubuntu)

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

on Windows

TODO

Development tools

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

Key modules

Below are the key modules for understanding the implementation principles of llgo: