Files
llgo/README.md

291 lines
12 KiB
Markdown
Raw Normal View History

2024-04-15 04:24:36 +08:00
llgo - A Go compiler based on LLVM
=====
[![Build Status](https://github.com/goplus/llgo/actions/workflows/go.yml/badge.svg)](https://github.com/goplus/llgo/actions/workflows/go.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/goplus/llgo)](https://goreportcard.com/report/github.com/goplus/llgo)
2024-04-22 01:04:38 +08:00
[![GitHub release](https://img.shields.io/github/v/tag/goplus/llgo.svg?label=release)](https://github.com/goplus/llgo/releases)
2024-04-15 04:24:36 +08:00
[![Coverage Status](https://codecov.io/gh/goplus/llgo/branch/main/graph/badge.svg)](https://codecov.io/gh/goplus/llgo)
2024-04-25 07:29:45 +08:00
[![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo)
[![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop)
2024-05-16 00:02:10 +08:00
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](https://github.com/goplus/gop).
2024-05-06 12:31:55 +08:00
2024-05-11 05:18:17 +08:00
## C standard libary support
2024-05-12 13:05:15 +08:00
```go
package main
import "github.com/goplus/llgo/c"
func main() {
c.Printf(c.Str("Hello world\n"))
}
```
2024-05-16 00:02:10 +08:00
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](_demo/hello/hello.go): call C `printf` to print `Hello world`
* [concat](_demo/concat/concat.go): call C `fprintf` with `stderr`
* [qsort](_demo/qsort/qsort.go): 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](#how-to-install)):
```sh
2024-05-16 01:08:21 +08:00
cd <demo-directory> # eg. cd _demo/hello
2024-05-16 00:02:10 +08:00
llgo run .
```
2024-05-12 13:05:15 +08:00
See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c) for more detials.
2024-05-11 05:18:17 +08:00
## Python support
2024-05-16 00:02:10 +08:00
You can import a Python library in LLGo!
2024-05-15 16:04:20 +08:00
2024-05-19 16:42:22 +08:00
And you can import any Python library into `llgo` through a program called `llpyg` (see [Development tools](#development-tools)). The following libraries have been included in `llgo`:
2024-05-15 16:04:20 +08:00
* [builtins](https://pkg.go.dev/github.com/goplus/llgo/py/std)
2024-05-15 16:04:20 +08:00
* [sys](https://pkg.go.dev/github.com/goplus/llgo/py/sys)
* [os](https://pkg.go.dev/github.com/goplus/llgo/py/os)
* [math](https://pkg.go.dev/github.com/goplus/llgo/py/math)
* [json](https://pkg.go.dev/github.com/goplus/llgo/py/json)
* [inspect](https://pkg.go.dev/github.com/goplus/llgo/py/inspect)
* [statistics](https://pkg.go.dev/github.com/goplus/llgo/py/statistics)
* [numpy](https://pkg.go.dev/github.com/goplus/llgo/py/numpy)
2024-05-18 19:51:39 +08:00
* [pandas](https://pkg.go.dev/github.com/goplus/llgo/py/pandas)
* [pytorch](https://pkg.go.dev/github.com/goplus/llgo/py/torch)
2024-05-19 07:28:56 +08:00
* [matplotlib](https://pkg.go.dev/github.com/goplus/llgo/py/matplotlib)
2024-05-15 16:04:20 +08:00
Note: For third-party libraries (such as pandas and pytorch), you still need to install the library files.
2024-05-15 16:04:20 +08:00
Here is an example using the Python `math` library:
2024-05-12 23:59:24 +08:00
```go
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/math"
)
func main() {
x := math.Sqrt(py.Float(2))
c.Printf(c.Str("sqrt(2) = %f\n"), x.Float64())
}
```
2024-05-13 01:27:02 +08:00
Here, We call `py.Float(2)` to create a Python number 2, and pass it to Pythons `math.sqrt` to get `x`. Then use `x.Float64()` to convert x to Go's `float64` type, and print the value through the C `printf` function.
2024-05-15 16:04:20 +08:00
Let's look at a slightly more complex example. For example, we use `numpy` to calculate:
```go
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/numpy"
)
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)
c.Printf(c.Str("a+b = %s\n"), x.Str().CStr())
}
```
Here we define two 3x3 matrices a and b, add them to get x, and then print the result.
2024-05-16 00:02:10 +08:00
The `_pydemo` directory contains some python related demos:
2024-05-11 05:18:17 +08:00
2024-05-16 00:02:10 +08:00
* [callpy](_pydemo/callpy/callpy.go): call Python standard library function `math.sqrt`
* [pi](_pydemo/pi/pi.go): print python constants `math.pi`
* [statistics](_pydemo/statistics/statistics.go): define a python list and call `statistics.mean` to get the mean
* [matrix](_pydemo/matrix/matrix.go): a basic `numpy` demo
2024-05-11 05:18:17 +08:00
2024-05-16 00:02:10 +08:00
To run these demos, you need to set the `LLGO_LIB_PYTHON` environment variable first.
2024-05-11 05:18:17 +08:00
2024-05-16 00:02:10 +08:00
If Python is in the search path for `clang` linking, then `LLGO_LIB_PYTHON` only needs to be set to the name of the Python library. For example:
2024-05-11 05:18:17 +08:00
2024-05-16 00:02:10 +08:00
```sh
export LLGO_LIB_PYTHON=python3.12
```
2024-05-11 05:18:17 +08:00
2024-05-16 00:02:10 +08:00
You can also specify the path to tell `llgo` where the Python library is located:
2024-05-06 12:31:55 +08:00
2024-05-16 00:02:10 +08:00
```sh
export LLGO_LIB_PYTHON=/foo/bar/python3.12
```
2024-05-06 12:31:55 +08:00
For example, `/opt/homebrew/Frameworks/Python.framework/Versions/3.12/lib/libpython3.12.dylib` is a typical python library location under macOS. So we should set it like this:
2024-05-06 12:31:55 +08:00
```sh
export LLGO_LIB_PYTHON=/opt/homebrew/Frameworks/Python.framework/Versions/3.12/lib/python3.12
2024-05-06 12:31:55 +08:00
```
2024-05-16 00:02:10 +08:00
Note that the file name must be written in a platform-independent format, using `python3.12` instead of `libpython3.12.dylib`.
Then you can run the demos:
2024-05-06 12:31:55 +08:00
```sh
2024-05-16 00:02:10 +08:00
cd <demo-directory> # eg. cd _pydemo/callpy
llgo run .
2024-05-06 12:31:55 +08:00
```
2024-05-16 00:02:10 +08:00
See [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py) for more detials.
2024-05-09 07:19:13 +08:00
2024-05-16 00:02:10 +08:00
## Other frequently used libraries
2024-05-09 07:19:13 +08:00
2024-05-16 00:02:10 +08:00
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.
2024-05-06 12:31:55 +08:00
The currently supported libraries include:
2024-05-16 00:02:10 +08:00
2024-05-17 22:33:57 +08:00
* [llama2.c](https://pkg.go.dev/github.com/goplus/llgo/c/llama2)
* [cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
* [sqlite](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite)
2024-05-16 00:02:10 +08:00
Here are some examples related to them:
2024-05-06 12:31:55 +08:00
2024-05-07 18:44:51 +08:00
* [llama2-c](_demo/llama2-c): inference Llama 2 (It's the first llgo AI example)
2024-05-17 22:33:57 +08:00
* [mkjson](c/cjson/_demo/mkjson/mkjson.go): create a json object and print it
* [sqlitedemo](c/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
2024-05-11 05:04:02 +08:00
2024-05-12 23:59:24 +08:00
2024-05-16 00:02:10 +08:00
## Go syntax support
2024-05-11 05:04:02 +08:00
2024-05-16 00:02:10 +08:00
Common Go syntax is already supported. Except for the following, which needs to be improved:
2024-05-11 05:04:02 +08:00
2024-05-16 00:02:10 +08:00
* map (Very limited support)
* chan (Not supported yet)
* generics (Not supported yet)
2024-05-11 05:04:02 +08:00
2024-05-16 00:02:10 +08:00
Here are some examples related to Go syntax:
2024-05-11 05:04:02 +08:00
2024-05-16 00:02:10 +08:00
* [concat](_demo/concat/concat.go): define a variadic function
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
2024-05-31 08:31:00 +08:00
* [errors](_demo/errors/errors.go): demo to implement error interface
2024-06-03 01:43:17 +08:00
* [defer](_demo/defer/defer.go): defer demo
2024-06-01 16:14:26 +08:00
* [goroutine](_demo/goroutine/goroutine.go): goroutine demo
2024-05-16 00:02:10 +08:00
2024-06-12 23:27:54 +08:00
## Defer
2024-06-13 17:11:58 +08:00
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.
2024-06-12 23:27:54 +08:00
2024-06-08 23:06:55 +08:00
### Garbage Collection (GC)
2024-06-11 10:35:27 +08:00
By default, LLGo implements `gc` based on [bdwgc](https://www.hboehm.info/gc/) (also known as [libgc](https://www.hboehm.info/gc/)).
2024-06-08 23:06:55 +08:00
However, you can disable gc by specifying the `nogc` tag. For example:
```sh
llgo run -tags nogc .
```
## Go packages support
Here are the Go packages that can be imported correctly:
* [unsafe](https://pkg.go.dev/unsafe)
2024-05-19 12:38:22 +08:00
* [unicode](https://pkg.go.dev/unicode)
* [unicode/utf8](https://pkg.go.dev/unicode/utf8)
2024-05-19 12:38:22 +08:00
* [unicode/utf16](https://pkg.go.dev/unicode/utf16)
2024-06-13 03:00:55 +08:00
* [math/bits](https://pkg.go.dev/math/bits)
2024-06-15 15:58:22 +08:00
* [math](https://pkg.go.dev/math)
2024-06-18 00:10:21 +08:00
* [sync](https://pkg.go.dev/sync) (partially)
2024-06-17 03:52:05 +08:00
* [sync/atomic](https://pkg.go.dev/sync/atomic) (partially)
## Dependencies
- [Go 1.20+](https://go.dev) (build only)
- [LLVM 17](https://llvm.org)
- [Clang 17](https://clang.llvm.org)
- [LLD 17](https://lld.llvm.org)
- [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/)
- [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/)
- [cJSON 1.7+](https://github.com/DaveGamble/cJSON) (optional, for [`github.com/goplus/llgo/c/cjson`](https://pkg.go.dev/github.com/goplus/llgo/c/cjson))
- [SQLite 3](https://www.sqlite.org) (optional, for [`github.com/goplus/llgo/c/sqlite`](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite))
- [Python 3.11+](https://www.python.org) (optional, for [`github.com/goplus/llgo/py`](https://pkg.go.dev/github.com/goplus/llgo/py))
2024-05-16 00:02:10 +08:00
## How to install
Follow these steps to generate the `llgo` command (its usage is the same as the `go` command):
2024-05-11 05:04:02 +08:00
2024-05-16 00:02:10 +08:00
### on macOS
2024-05-11 05:04:02 +08:00
```sh
brew update # execute if needed
brew install llvm@17 pkg-config libgc
brew install cjson sqlite python@3.12 # optional
export PATH=$(brew --prefix llvm@17)/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.zshrc
export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers
git clone https://github.com/goplus/llgo.git
cd llgo
export LLGOROOT="/path/to/llgo" # Replace this with the root directory of the llgo project
2024-05-16 00:02:10 +08:00
go install -v ./...
2024-05-11 05:04:02 +08:00
```
### on Linux (Debian/Ubuntu)
2024-05-11 05:04:02 +08:00
```sh
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-17 main" | sudo tee /etc/apt/sources.list.d/llvm.list
2024-05-16 00:02:10 +08:00
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-get update # execute if needed
sudo apt-get install -y llvm-17-dev clang-17 lld-17 pkg-config libgc-dev
sudo apt-get install -y libcjson-dev libsqlite3-dev python3.12-dev # optional
export PATH=/usr/lib/llvm-17/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.bashrc
export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers
git clone https://github.com/goplus/llgo.git
cd llgo
export LLGOROOT="/path/to/llgo" # Replace this with the root directory of the llgo project
2024-05-16 00:02:10 +08:00
go install -v ./...
2024-05-11 05:04:02 +08:00
```
2024-05-16 00:02:10 +08:00
### on Windows
TODO
2024-05-16 06:34:18 +08:00
## Development tools
* [pydump](chore/_xtool/pydump): It's the first program compiled by `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`.
2024-05-18 20:07:41 +08:00
* [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` project, but we depend on it.
* [llpyg](chore/llpyg): It is used to automatically convert Python libraries into Go packages that `llgo` can import. It depends on `pydump` and `pysigfetch` to accomplish the task.
2024-05-16 06:34:18 +08:00
* [llgen](chore/llgen): It is used to compile Go packages into LLVM IR files (*.ll).
* [ssadump](chore/ssadump): It is a Go SSA builder and interpreter.
How do I generate these tools?
```sh
export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers
2024-05-16 06:34:18 +08:00
go install -v ./... # compile all tools except pydump
cd chore/_xtool
llgo install ./... # compile pydump
2024-05-18 20:07:41 +08:00
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
2024-05-16 06:34:18 +08:00
```
2024-05-16 07:08:10 +08:00
## Key modules
Below are the key modules for understanding the implementation principles of `llgo`:
* [llgo/ssa](https://pkg.go.dev/github.com/goplus/llgo/ssa): It generates LLVM IR files (LLVM SSA) using the semantics (interfaces) of Go SSA. Although `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/cl](https://pkg.go.dev/github.com/goplus/llgo/cl): It is the core of the llgo compiler. It converts a Go package into LLVM IR files. It depends on `llgo/ssa`.
* [llgo/internal/build](https://pkg.go.dev/github.com/goplus/llgo/internal/build): It strings together the entire compilation process of `llgo`. It depends on `llgo/ssa` and `llgo/cl`.