Compare commits
179 Commits
v0.10.0-pr
...
v0.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b11eb742cb | ||
|
|
b63a7f64fd | ||
|
|
cafc438972 | ||
|
|
33ef7f737b | ||
|
|
3e26685a44 | ||
|
|
6a306be480 | ||
|
|
9defb6289b | ||
|
|
a47ad2886f | ||
|
|
c8d791f206 | ||
|
|
8c5f915569 | ||
|
|
ed366568b4 | ||
|
|
0a8a4eb6a6 | ||
|
|
fdc6cf4838 | ||
|
|
e52af0077b | ||
|
|
847f544839 | ||
|
|
685d3202d0 | ||
|
|
33a2580cc3 | ||
|
|
a8da654597 | ||
|
|
ae01a023ad | ||
|
|
ec20af3c4d | ||
|
|
a6f1ad1c2c | ||
|
|
c3532f17de | ||
|
|
86eac2f04d | ||
|
|
3b9b71643c | ||
|
|
19417cdd52 | ||
|
|
a7c23e25d8 | ||
|
|
f96ab87536 | ||
|
|
d65d49f504 | ||
|
|
8cd5924bf2 | ||
|
|
9f38338c58 | ||
|
|
8c76436d81 | ||
|
|
0e71576265 | ||
|
|
71b34003ca | ||
|
|
2c417d75a2 | ||
|
|
74ededd8c8 | ||
|
|
a732fa237c | ||
|
|
fd4c22308d | ||
|
|
d6f18894e6 | ||
|
|
992d54693f | ||
|
|
9be1bd0775 | ||
|
|
29cc689abd | ||
|
|
39d28e507d | ||
|
|
eacb5bc6f8 | ||
|
|
19658454bd | ||
|
|
02e3a6ae8b | ||
|
|
77376087db | ||
|
|
52a77f9efb | ||
|
|
d483b13107 | ||
|
|
dea4d9df63 | ||
|
|
b7601a7f08 | ||
|
|
2e148d6d0e | ||
|
|
8835a1a232 | ||
|
|
00e3b6b5a0 | ||
|
|
3bb51c5d51 | ||
|
|
433df05858 | ||
|
|
22524b03c8 | ||
|
|
508fa62a48 | ||
|
|
e7f7f98c02 | ||
|
|
9edaa8eb93 | ||
|
|
32587c1a40 | ||
|
|
019c482d18 | ||
|
|
ca906d9c71 | ||
|
|
35ba8476b0 | ||
|
|
a473901cfd | ||
|
|
b163d71aed | ||
|
|
d561f1399a | ||
|
|
00406e08fb | ||
|
|
0e4ca910d6 | ||
|
|
b00f52472b | ||
|
|
95a6e356ee | ||
|
|
f4da8e8876 | ||
|
|
1a08a59b49 | ||
|
|
758ceb791b | ||
|
|
6a1e0084f4 | ||
|
|
e318cab252 | ||
|
|
6b12547303 | ||
|
|
96d6c00815 | ||
|
|
7be79d81f9 | ||
|
|
2be558d554 | ||
|
|
60fac0a010 | ||
|
|
df0f239929 | ||
|
|
4e1aea4597 | ||
|
|
60224dd77d | ||
|
|
ded408f145 | ||
|
|
69deeca321 | ||
|
|
5e1e7bdad0 | ||
|
|
22f4924d8e | ||
|
|
8591275eb2 | ||
|
|
d91bb33178 | ||
|
|
d8e782f3f1 | ||
|
|
51755b8da3 | ||
|
|
e5c0aed75e | ||
|
|
6d7e984238 | ||
|
|
4dcc944f53 | ||
|
|
fbb978e8a5 | ||
|
|
46a3a4f7e3 | ||
|
|
e74d2b45c0 | ||
|
|
d40298ac58 | ||
|
|
87d7a4862e | ||
|
|
8be9a560e9 | ||
|
|
0d218bb4b9 | ||
|
|
1b3464b610 | ||
|
|
c4e66a104b | ||
|
|
d4eaef6ac8 | ||
|
|
9a634b22a7 | ||
|
|
54f5f38637 | ||
|
|
21a5180b2f | ||
|
|
8116d34a60 | ||
|
|
c6462cbcc7 | ||
|
|
4e34ce7470 | ||
|
|
c2299818cd | ||
|
|
2d06dc5cfe | ||
|
|
5329f28580 | ||
|
|
66909b3000 | ||
|
|
ae92904e7d | ||
|
|
70fb5ec7e1 | ||
|
|
058f74c12c | ||
|
|
3a2d24d7cc | ||
|
|
49f2f0dbfd | ||
|
|
5b216153e9 | ||
|
|
43175bb642 | ||
|
|
c1da220a99 | ||
|
|
164c3e0e7b | ||
|
|
491a23b21e | ||
|
|
727ec8a5cf | ||
|
|
28b3ec322c | ||
|
|
38cb89a946 | ||
|
|
b07116f302 | ||
|
|
623b5a511a | ||
|
|
d5d2d6826f | ||
|
|
227f6a4ed7 | ||
|
|
e23d7082fe | ||
|
|
569a29454e | ||
|
|
a07f711e22 | ||
|
|
946f304bb2 | ||
|
|
6b11c100ba | ||
|
|
6048693423 | ||
|
|
a7287754be | ||
|
|
d9037a7fce | ||
|
|
f06d292382 | ||
|
|
85d01d6f28 | ||
|
|
5cfeddef73 | ||
|
|
b975e77a63 | ||
|
|
ba46181365 | ||
|
|
370604f8eb | ||
|
|
368c7d6cda | ||
|
|
0a9dfdc5c0 | ||
|
|
72d0d4e274 | ||
|
|
d0067ccf68 | ||
|
|
409793cb21 | ||
|
|
a9eb65926f | ||
|
|
18d8677fe6 | ||
|
|
09c8567e39 | ||
|
|
6bbd4b214a | ||
|
|
a345746cbd | ||
|
|
0a0bb128d6 | ||
|
|
29ec3014e7 | ||
|
|
9ddd4d4161 | ||
|
|
3caae31374 | ||
|
|
b69abd1058 | ||
|
|
114c6bd6fc | ||
|
|
d81c5e750d | ||
|
|
281d29a100 | ||
|
|
46492009a1 | ||
|
|
ec549a6a25 | ||
|
|
71766d9c55 | ||
|
|
d2d8bd550a | ||
|
|
0c2f6c46f6 | ||
|
|
c90b93c1b7 | ||
|
|
faef4fffab | ||
|
|
8e8b97f623 | ||
|
|
e23d18dab8 | ||
|
|
3a0d1466cc | ||
|
|
83dd77f4c4 | ||
|
|
c601c992c1 | ||
|
|
5727761551 | ||
|
|
08365721de | ||
|
|
692c3542d9 | ||
|
|
60dc1f7d75 |
20
.github/actions/setup-deps/action.yml
vendored
20
.github/actions/setup-deps/action.yml
vendored
@@ -4,7 +4,7 @@ inputs:
|
|||||||
llvm-version:
|
llvm-version:
|
||||||
description: "LLVM version to install"
|
description: "LLVM version to install"
|
||||||
required: true
|
required: true
|
||||||
default: "18"
|
default: "19"
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
@@ -14,17 +14,17 @@ runs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
brew update
|
brew update
|
||||||
brew install llvm@${{inputs.llvm-version}} bdw-gc openssl libffi
|
brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} bdw-gc openssl libffi libuv
|
||||||
brew link --force libffi
|
brew link --overwrite lld@${{inputs.llvm-version}} libffi
|
||||||
echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH
|
echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
# Install optional deps for demos.
|
# Install optional deps for demos.
|
||||||
#
|
#
|
||||||
# NOTE: Keep this list updated as new deps are introduced.
|
# NOTE: Keep this list updated as new deps are introduced.
|
||||||
opt_deps=(
|
opt_deps=(
|
||||||
cjson # for github.com/goplus/llgo/c/cjson
|
cjson # for github.com/goplus/lib/c/cjson
|
||||||
sqlite # for github.com/goplus/llgo/c/sqlite
|
sqlite # for github.com/goplus/lib/c/sqlite
|
||||||
python@3.12 # for github.com/goplus/llgo/py
|
python@3.12 # for github.com/goplus/lib/py
|
||||||
)
|
)
|
||||||
brew install "${opt_deps[@]}"
|
brew install "${opt_deps[@]}"
|
||||||
- name: Install Ubuntu dependencies
|
- name: Install Ubuntu dependencies
|
||||||
@@ -34,15 +34,15 @@ runs:
|
|||||||
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{inputs.llvm-version}} main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{inputs.llvm-version}} main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y llvm-${{inputs.llvm-version}}-dev clang-${{inputs.llvm-version}} libclang-${{inputs.llvm-version}}-dev lld-${{inputs.llvm-version}} pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libunwind-dev
|
sudo apt-get install -y llvm-${{inputs.llvm-version}}-dev clang-${{inputs.llvm-version}} libclang-${{inputs.llvm-version}}-dev lld-${{inputs.llvm-version}} pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libunwind-dev libuv1-dev
|
||||||
echo "/usr/lib/llvm-${{inputs.llvm-version}}/bin" >> $GITHUB_PATH
|
echo "/usr/lib/llvm-${{inputs.llvm-version}}/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
# Install optional deps for demos.
|
# Install optional deps for demos.
|
||||||
#
|
#
|
||||||
# NOTE: Keep this list updated as new deps are introduced.
|
# NOTE: Keep this list updated as new deps are introduced.
|
||||||
opt_deps=(
|
opt_deps=(
|
||||||
libcjson-dev # for github.com/goplus/llgo/c/cjson
|
libcjson-dev # for github.com/goplus/lib/c/cjson
|
||||||
libsqlite3-dev # for github.com/goplus/llgo/c/sqlite
|
libsqlite3-dev # for github.com/goplus/lib/c/sqlite
|
||||||
python3.12-dev # for github.com/goplus/llgo/py
|
python3.12-dev # for github.com/goplus/lib/py
|
||||||
)
|
)
|
||||||
sudo apt-get install -y "${opt_deps[@]}"
|
sudo apt-get install -y "${opt_deps[@]}"
|
||||||
|
|||||||
51
.github/actions/setup-go/action.yml
vendored
Normal file
51
.github/actions/setup-go/action.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: "Setup Go"
|
||||||
|
description: "Setup Go environment by downloading and extracting from go.dev"
|
||||||
|
inputs:
|
||||||
|
go-version:
|
||||||
|
description: "The Go version to download and use"
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Download and setup Go
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
GO_VERSION="${{ inputs.go-version }}"
|
||||||
|
GO_VERSION="${GO_VERSION#go}" # Remove 'go' prefix if present
|
||||||
|
|
||||||
|
# Determine OS and architecture
|
||||||
|
if [[ "$RUNNER_OS" == "macOS" ]]; then
|
||||||
|
OS="darwin"
|
||||||
|
ARCH="arm64"
|
||||||
|
else
|
||||||
|
OS="linux"
|
||||||
|
ARCH="amd64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOWNLOAD_URL="https://go.dev/dl/go${GO_VERSION}.${OS}-${ARCH}.tar.gz"
|
||||||
|
echo "Downloading Go from: ${DOWNLOAD_URL}"
|
||||||
|
|
||||||
|
# Create temporary directory for download
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
curl -L "${DOWNLOAD_URL}" -o "${TMP_DIR}/go.tar.gz"
|
||||||
|
|
||||||
|
# Remove existing Go installation if any
|
||||||
|
sudo rm -rf /usr/local/go
|
||||||
|
|
||||||
|
# Extract to /usr/local
|
||||||
|
sudo tar -C /usr/local -xzf "${TMP_DIR}/go.tar.gz"
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf "${TMP_DIR}"
|
||||||
|
|
||||||
|
# Add to PATH
|
||||||
|
echo "/usr/local/go/bin" >> $GITHUB_PATH
|
||||||
|
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Verify Go installation
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Verify installation
|
||||||
|
echo "Verifying Go installation..."
|
||||||
|
go version
|
||||||
2
.github/actions/test-helloworld/action.yml
vendored
2
.github/actions/test-helloworld/action.yml
vendored
@@ -23,7 +23,7 @@ runs:
|
|||||||
package main
|
package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
)
|
)
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Hello, LLGo!")
|
fmt.Println("Hello, LLGo!")
|
||||||
|
|||||||
8
.github/codecov.yml
vendored
8
.github/codecov.yml
vendored
@@ -1,3 +1,9 @@
|
|||||||
coverage:
|
coverage:
|
||||||
ignore:
|
ignore:
|
||||||
- "compiler/chore"
|
- "chore"
|
||||||
|
- "cmd/internal"
|
||||||
|
- "internal/build"
|
||||||
|
- "internal/llgen"
|
||||||
|
- "internal/mockable"
|
||||||
|
- "internal/packages"
|
||||||
|
- "internal/typepatch"
|
||||||
|
|||||||
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -17,13 +17,3 @@ updates:
|
|||||||
directory: "/" # Location of package manifests
|
directory: "/" # Location of package manifests
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
|
||||||
- package-ecosystem: "gomod" # See documentation for possible values
|
|
||||||
directory: "/compiler/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|
||||||
- package-ecosystem: "gomod" # See documentation for possible values
|
|
||||||
directory: "/runtime/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|||||||
99
.github/workflows/doc.yml
vendored
99
.github/workflows/doc.yml
vendored
@@ -21,9 +21,52 @@ jobs:
|
|||||||
run: npm install -g embedme
|
run: npm install -g embedme
|
||||||
|
|
||||||
- name: Verify README.md embedded code
|
- name: Verify README.md embedded code
|
||||||
run: npx embedme --verify README.md
|
run: embedme --verify README.md
|
||||||
|
|
||||||
doc_test:
|
- name: Link Checker
|
||||||
|
id: lychee
|
||||||
|
uses: lycheeverse/lychee-action@v2
|
||||||
|
with:
|
||||||
|
args: --max-concurrency 3 --retry-wait-time 15 README.md
|
||||||
|
|
||||||
|
remote_install:
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- macos-latest
|
||||||
|
- ubuntu-24.04
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: ./.github/actions/setup-go
|
||||||
|
with:
|
||||||
|
go-version: '1.23.6'
|
||||||
|
|
||||||
|
- name: Install dependencies on macOS
|
||||||
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
source doc/_readme/scripts/install_macos.sh
|
||||||
|
|
||||||
|
- name: Install dependencies on Ubuntu
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
source doc/_readme/scripts/install_ubuntu.sh
|
||||||
|
|
||||||
|
- name: Test doc code blocks
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
source doc/_readme/scripts/run.sh
|
||||||
|
|
||||||
|
local_install:
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
@@ -52,7 +95,7 @@ jobs:
|
|||||||
set -x
|
set -x
|
||||||
source doc/_readme/scripts/install_ubuntu.sh
|
source doc/_readme/scripts/install_ubuntu.sh
|
||||||
|
|
||||||
- name: Install llgo
|
- name: Install llgo with tools
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
@@ -73,3 +116,53 @@ jobs:
|
|||||||
set -x
|
set -x
|
||||||
source doc/_readme/scripts/run.sh
|
source doc/_readme/scripts/run.sh
|
||||||
|
|
||||||
|
local_install_full:
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- macos-latest
|
||||||
|
- ubuntu-24.04
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.23'
|
||||||
|
|
||||||
|
- name: Install dependencies on macOS
|
||||||
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
source doc/_readme/scripts/install_macos.sh
|
||||||
|
|
||||||
|
- name: Install dependencies on Ubuntu
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
source doc/_readme/scripts/install_ubuntu.sh
|
||||||
|
|
||||||
|
- name: Install llgo with tools
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
git() {
|
||||||
|
if [ "$1" = "clone" ]; then
|
||||||
|
# do nothing because we already have the branch
|
||||||
|
cd ..
|
||||||
|
else
|
||||||
|
command git "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
source doc/_readme/scripts/install_full.sh
|
||||||
|
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Test doc code blocks
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
source doc/_readme/scripts/run.sh
|
||||||
|
|||||||
6
.github/workflows/fmt.yml
vendored
6
.github/workflows/fmt.yml
vendored
@@ -13,13 +13,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: ./.github/actions/setup-go
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.24.0'
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: |
|
run: |
|
||||||
for dir in . compiler runtime; do
|
for dir in . runtime; do
|
||||||
pushd $dir
|
pushd $dir
|
||||||
if [ -n "$(go fmt ./...)" ]; then
|
if [ -n "$(go fmt ./...)" ]; then
|
||||||
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
|
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
|
||||||
|
|||||||
14
.github/workflows/go.yml
vendored
14
.github/workflows/go.yml
vendored
@@ -11,16 +11,14 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- macos-latest
|
- macos-latest
|
||||||
- ubuntu-24.04
|
- ubuntu-24.04
|
||||||
llvm: [18]
|
llvm: [19]
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: compiler
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -35,20 +33,20 @@ jobs:
|
|||||||
clang --version
|
clang --version
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: ./.github/actions/setup-go
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: "1.24.0"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: go build -v ./...
|
run: go build -v ./...
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
if: ${{!startsWith(matrix.os, 'macos')}}
|
if: ${{!startsWith(matrix.os, 'macos')}}
|
||||||
run: go test -v ./...
|
run: go test ./...
|
||||||
|
|
||||||
- name: Test with coverage
|
- name: Test with coverage
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
run: go test -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||||
|
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v5
|
||||||
|
|||||||
138
.github/workflows/llgo.yml
vendored
138
.github/workflows/llgo.yml
vendored
@@ -10,14 +10,31 @@ on:
|
|||||||
branches: ["**"]
|
branches: ["**"]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
llgo-test:
|
download-model:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download model file
|
||||||
|
run: |
|
||||||
|
mkdir -p ./_demo/llama2-c
|
||||||
|
wget -P ./_demo/llama2-c https://huggingface.co/karpathy/tinyllamas/resolve/main/stories15M.bin
|
||||||
|
|
||||||
|
- name: Upload model as artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: llama2-model
|
||||||
|
path: ./_demo/llama2-c/stories15M.bin
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
llgo:
|
||||||
|
needs: download-model
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- macos-latest
|
- macos-latest
|
||||||
- ubuntu-24.04
|
- ubuntu-24.04
|
||||||
llvm: [18]
|
llvm: [19]
|
||||||
go: ['1.20', '1.21', '1.22', '1.23']
|
go: ['1.21.13', '1.22.12', '1.23.6', '1.24.0']
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -25,22 +42,25 @@ jobs:
|
|||||||
uses: ./.github/actions/setup-deps
|
uses: ./.github/actions/setup-deps
|
||||||
with:
|
with:
|
||||||
llvm-version: ${{matrix.llvm}}
|
llvm-version: ${{matrix.llvm}}
|
||||||
|
- name: Download model artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: llama2-model
|
||||||
|
path: ./_demo/llama2-c/
|
||||||
- name: Install further optional dependencies for demos
|
- name: Install further optional dependencies for demos
|
||||||
run: |
|
run: |
|
||||||
wget -P ./_demo/llama2-c https://huggingface.co/karpathy/tinyllamas/resolve/main/stories15M.bin
|
|
||||||
py_deps=(
|
py_deps=(
|
||||||
numpy # for github.com/goplus/llgo/py/numpy
|
numpy # for github.com/goplus/lib/py/numpy
|
||||||
torch # for github.com/goplus/llgo/py/torch
|
torch # for github.com/goplus/lib/py/torch
|
||||||
)
|
)
|
||||||
pip3.12 install --break-system-packages "${py_deps[@]}"
|
pip3.12 install --break-system-packages "${py_deps[@]}"
|
||||||
|
|
||||||
- name: Set up Go for build
|
- name: Set up Go for build
|
||||||
uses: actions/setup-go@v5
|
uses: ./.github/actions/setup-go
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: "1.24.0"
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
working-directory: compiler
|
|
||||||
run: |
|
run: |
|
||||||
go install ./...
|
go install ./...
|
||||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||||
@@ -50,26 +70,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go}}
|
go-version: ${{matrix.go}}
|
||||||
|
|
||||||
- name: Verify Go version
|
|
||||||
run: |
|
|
||||||
go_version=$(go version | cut -d' ' -f3 | sed 's/go//')
|
|
||||||
if [[ "$go_version" != "${{matrix.go}}"* ]]; then
|
|
||||||
echo "Expected Go version ${{matrix.go}}, but got $go_version"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Using Go version: $go_version"
|
|
||||||
|
|
||||||
- name: _xtool build tests
|
- name: _xtool build tests
|
||||||
run: |
|
run: |
|
||||||
cd _xtool
|
cd _xtool
|
||||||
llgo build -v ./...
|
llgo build -v ./...
|
||||||
|
|
||||||
- name: LLGO tests
|
|
||||||
if: ${{!startsWith(matrix.os, 'ubuntu')}}
|
|
||||||
run: |
|
|
||||||
echo "Test result on ${{matrix.os}} with LLVM ${{matrix.llvm}}" > result.md
|
|
||||||
bash ./.github/workflows/test_llgo.sh
|
|
||||||
|
|
||||||
- name: Test demos
|
- name: Test demos
|
||||||
run: |
|
run: |
|
||||||
# TODO(lijie): force python3-embed to be linked with python-3.12-embed
|
# TODO(lijie): force python3-embed to be linked with python-3.12-embed
|
||||||
@@ -88,17 +93,19 @@ jobs:
|
|||||||
|
|
||||||
- name: LLDB tests
|
- name: LLDB tests
|
||||||
if: ${{startsWith(matrix.os, 'macos')}}
|
if: ${{startsWith(matrix.os, 'macos')}}
|
||||||
working-directory: compiler
|
|
||||||
run: |
|
run: |
|
||||||
echo "Test lldb with llgo plugin on ${{matrix.os}} with LLVM ${{matrix.llvm}}"
|
echo "Test lldb with llgo plugin on ${{matrix.os}} with LLVM ${{matrix.llvm}}"
|
||||||
bash _lldb/runtest.sh -v
|
bash _lldb/runtest.sh -v
|
||||||
|
|
||||||
helloworld-test:
|
test:
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-24.04, macos-latest]
|
os:
|
||||||
llvm: [18]
|
- macos-latest
|
||||||
go: ['1.20', '1.21', '1.22', '1.23']
|
- ubuntu-24.04
|
||||||
|
llvm: [19]
|
||||||
|
go: ["1.24.0"]
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -106,14 +113,20 @@ jobs:
|
|||||||
uses: ./.github/actions/setup-deps
|
uses: ./.github/actions/setup-deps
|
||||||
with:
|
with:
|
||||||
llvm-version: ${{matrix.llvm}}
|
llvm-version: ${{matrix.llvm}}
|
||||||
|
- name: Install further optional dependencies for demos
|
||||||
|
run: |
|
||||||
|
py_deps=(
|
||||||
|
numpy # for github.com/goplus/lib/py/numpy
|
||||||
|
torch # for github.com/goplus/lib/py/torch
|
||||||
|
)
|
||||||
|
pip3.12 install --break-system-packages "${py_deps[@]}"
|
||||||
|
|
||||||
- name: Set up Go 1.23 for building llgo
|
- name: Set up Go for build
|
||||||
uses: actions/setup-go@v5
|
uses: ./.github/actions/setup-go
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: "1.24.0"
|
||||||
|
|
||||||
- name: Install llgo
|
- name: Install
|
||||||
working-directory: compiler
|
|
||||||
run: |
|
run: |
|
||||||
go install ./...
|
go install ./...
|
||||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||||
@@ -123,23 +136,64 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go}}
|
go-version: ${{matrix.go}}
|
||||||
|
|
||||||
- name: Test Hello World with go.mod 1.20
|
- name: run llgo test
|
||||||
if: matrix.go == '1.20' || matrix.go == '1.21' || matrix.go == '1.22' || matrix.go == '1.23'
|
run: |
|
||||||
uses: ./.github/actions/test-helloworld
|
llgo test ./...
|
||||||
|
|
||||||
|
hello:
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-24.04, macos-latest]
|
||||||
|
llvm: [19]
|
||||||
|
go: ['1.21.13', '1.22.12', '1.23.6', '1.24.0']
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: ./.github/actions/setup-deps
|
||||||
|
with:
|
||||||
|
llvm-version: ${{matrix.llvm}}
|
||||||
|
|
||||||
|
- name: Set up Go 1.23 for building llgo
|
||||||
|
uses: ./.github/actions/setup-go
|
||||||
|
with:
|
||||||
|
go-version: "1.24.0"
|
||||||
|
|
||||||
|
- name: Install llgo
|
||||||
|
run: |
|
||||||
|
go install ./...
|
||||||
|
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set up Go for testing
|
||||||
|
uses: ./.github/actions/setup-go
|
||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go}}
|
go-version: ${{matrix.go}}
|
||||||
mod-version: '1.20'
|
|
||||||
|
|
||||||
- name: Test Hello World with go.mod 1.21
|
- name: Test Hello World with go.mod 1.21
|
||||||
if: matrix.go == '1.21' || matrix.go == '1.22' || matrix.go == '1.23'
|
if: startsWith(matrix.go, '1.21') || startsWith(matrix.go, '1.22') || startsWith(matrix.go, '1.23') || startsWith(matrix.go, '1.24')
|
||||||
uses: ./.github/actions/test-helloworld
|
uses: ./.github/actions/test-helloworld
|
||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go}}
|
go-version: ${{matrix.go}}
|
||||||
mod-version: '1.21'
|
mod-version: "1.21"
|
||||||
|
|
||||||
- name: Test Hello World with go.mod 1.22
|
- name: Test Hello World with go.mod 1.22
|
||||||
if: matrix.go == '1.22' || matrix.go == '1.23'
|
if: startsWith(matrix.go, '1.22') || startsWith(matrix.go, '1.23') || startsWith(matrix.go, '1.24')
|
||||||
uses: ./.github/actions/test-helloworld
|
uses: ./.github/actions/test-helloworld
|
||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go}}
|
go-version: ${{matrix.go}}
|
||||||
mod-version: '1.22'
|
mod-version: "1.22"
|
||||||
|
|
||||||
|
- name: Test Hello World with go.mod 1.23
|
||||||
|
if: startsWith(matrix.go, '1.23') || startsWith(matrix.go, '1.24')
|
||||||
|
uses: ./.github/actions/test-helloworld
|
||||||
|
with:
|
||||||
|
go-version: ${{matrix.go}}
|
||||||
|
mod-version: "1.23"
|
||||||
|
|
||||||
|
- name: Test Hello World with go.mod 1.24
|
||||||
|
if: startsWith(matrix.go, '1.24')
|
||||||
|
uses: ./.github/actions/test-helloworld
|
||||||
|
with:
|
||||||
|
go-version: ${{matrix.go}}
|
||||||
|
mod-version: "1.24"
|
||||||
|
|||||||
6
.github/workflows/populate_darwin_sysroot.sh
vendored
6
.github/workflows/populate_darwin_sysroot.sh
vendored
@@ -6,12 +6,12 @@ TMPDIR="$(mktemp -d)"
|
|||||||
export TMPDIR
|
export TMPDIR
|
||||||
trap 'rm -rf "${TMPDIR}"' EXIT
|
trap 'rm -rf "${TMPDIR}"' EXIT
|
||||||
|
|
||||||
DARWIN_AMD64_LLVM_PREFIX=.sysroot/darwin/amd64/usr/local/opt/llvm@18
|
DARWIN_AMD64_LLVM_PREFIX=.sysroot/darwin/amd64/usr/local/opt/llvm@19
|
||||||
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@18
|
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@19
|
||||||
mkdir -p "${DARWIN_AMD64_LLVM_PREFIX}" "${DARWIN_ARM64_LLVM_PREFIX}"
|
mkdir -p "${DARWIN_AMD64_LLVM_PREFIX}" "${DARWIN_ARM64_LLVM_PREFIX}"
|
||||||
|
|
||||||
BREW_LLVM_FORMULA_JSON="$(mktemp)"
|
BREW_LLVM_FORMULA_JSON="$(mktemp)"
|
||||||
curl -fsSL https://formulae.brew.sh/api/formula/llvm@18.json > "${BREW_LLVM_FORMULA_JSON}"
|
curl -fsSL https://formulae.brew.sh/api/formula/llvm@19.json > "${BREW_LLVM_FORMULA_JSON}"
|
||||||
BREW_LLVM_AMD64_BOTTLE_URL=$(jq -r '.bottle.stable.files.sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
BREW_LLVM_AMD64_BOTTLE_URL=$(jq -r '.bottle.stable.files.sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
||||||
BREW_LLVM_ARM64_BOTTLE_URL=$(jq -r '.bottle.stable.files.arm64_sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
BREW_LLVM_ARM64_BOTTLE_URL=$(jq -r '.bottle.stable.files.arm64_sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
||||||
curl -fsSL -H "Authorization: Bearer QQ==" "${BREW_LLVM_AMD64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_AMD64_LLVM_PREFIX}"
|
curl -fsSL -H "Authorization: Bearer QQ==" "${BREW_LLVM_AMD64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_AMD64_LLVM_PREFIX}"
|
||||||
|
|||||||
12
.github/workflows/populate_linux_sysroot.sh
vendored
12
.github/workflows/populate_linux_sysroot.sh
vendored
@@ -19,10 +19,10 @@ export DEBIAN_FRONTEND=noninteractive
|
|||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y lsb-release gnupg2 wget rsync
|
apt-get install -y lsb-release gnupg2 wget rsync
|
||||||
|
|
||||||
echo "deb http://apt.llvm.org/\$(lsb_release -cs)/ llvm-toolchain-\$(lsb_release -cs)-18 main" | tee /etc/apt/sources.list.d/llvm.list
|
echo "deb http://apt.llvm.org/\$(lsb_release -cs)/ llvm-toolchain-\$(lsb_release -cs)-19 main" | tee /etc/apt/sources.list.d/llvm.list
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y llvm-18-dev
|
apt-get install -y llvm-19-dev
|
||||||
|
|
||||||
error() {
|
error() {
|
||||||
echo -e "\$1" >&2
|
echo -e "\$1" >&2
|
||||||
@@ -106,7 +106,6 @@ do-sync() {
|
|||||||
args+=(-d)
|
args+=(-d)
|
||||||
args+=(-h)
|
args+=(-h)
|
||||||
args+=(--keep-dirlinks)
|
args+=(--keep-dirlinks)
|
||||||
args+=("--info=progress2")
|
|
||||||
args+=(--delete)
|
args+=(--delete)
|
||||||
args+=(--prune-empty-dirs)
|
args+=(--prune-empty-dirs)
|
||||||
args+=(--sparse)
|
args+=(--sparse)
|
||||||
@@ -139,5 +138,8 @@ populate_linux_sysroot() {
|
|||||||
debian:bullseye \
|
debian:bullseye \
|
||||||
/populate_linux_sysroot.sh
|
/populate_linux_sysroot.sh
|
||||||
}
|
}
|
||||||
populate_linux_sysroot amd64 "${LINUX_AMD64_PREFIX}"
|
populate_linux_sysroot amd64 "${LINUX_AMD64_PREFIX}" &
|
||||||
populate_linux_sysroot arm64 "${LINUX_ARM64_PREFIX}"
|
populate_linux_sysroot arm64 "${LINUX_ARM64_PREFIX}" &
|
||||||
|
|
||||||
|
# Wait for both background processes to complete
|
||||||
|
wait
|
||||||
|
|||||||
13
.github/workflows/release-build.yml
vendored
13
.github/workflows/release-build.yml
vendored
@@ -11,18 +11,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Cache Darwin sysroot
|
|
||||||
id: cache-sysroot
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
.sysroot/darwin.tar.gz
|
|
||||||
key: darwin-sysroot-${{ runner.os }}-${{ hashFiles('.github/workflows/populate_darwin_sysroot.sh') }}
|
|
||||||
- name: Populate Darwin sysroot
|
- name: Populate Darwin sysroot
|
||||||
if: steps.cache-sysroot.outputs.cache-hit != 'true'
|
|
||||||
run: bash .github/workflows/populate_darwin_sysroot.sh
|
run: bash .github/workflows/populate_darwin_sysroot.sh
|
||||||
- name: Create Darwin sysroot tarball
|
- name: Create Darwin sysroot tarball
|
||||||
if: steps.cache-sysroot.outputs.cache-hit != 'true'
|
|
||||||
run: tar -czvf .sysroot/darwin.tar.gz -C .sysroot darwin
|
run: tar -czvf .sysroot/darwin.tar.gz -C .sysroot darwin
|
||||||
- name: Upload Darwin sysroot tarball
|
- name: Upload Darwin sysroot tarball
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -41,9 +32,11 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23.x
|
go-version: 1.24.x
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
with:
|
||||||
|
image: tonistiigi/binfmt:qemu-v7.0.0-28
|
||||||
- name: Download Darwin sysroot tarball
|
- name: Download Darwin sysroot tarball
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
36
.github/workflows/test_llgo.sh
vendored
36
.github/workflows/test_llgo.sh
vendored
@@ -1,36 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
testcmd=/tmp/test
|
|
||||||
llgo build -o $testcmd ./c/bdwgc/_test
|
|
||||||
cases=$($testcmd)
|
|
||||||
total=$(echo "$cases" | wc -l | tr -d ' ')
|
|
||||||
failed=0
|
|
||||||
failed_cases=""
|
|
||||||
|
|
||||||
for idx in $(seq 1 $((total))); do
|
|
||||||
case=$(echo "$cases" | sed -n "${idx}p")
|
|
||||||
case_name=$(echo "$case" | cut -d',' -f2)
|
|
||||||
echo "=== Test case: $case_name"
|
|
||||||
set +e
|
|
||||||
out=$("$testcmd" "$((idx-1))" 2>&1)
|
|
||||||
exit_code=$?
|
|
||||||
set -e
|
|
||||||
if [ "${exit_code:-0}" -ne 0 ]; then
|
|
||||||
echo "failed: $out"
|
|
||||||
failed=$((failed+1))
|
|
||||||
failed_cases="$failed_cases\n* :x: $case_name"
|
|
||||||
else
|
|
||||||
echo "passed"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "=== Done"
|
|
||||||
echo "$((total-failed))/$total tests passed"
|
|
||||||
|
|
||||||
if [ "$failed" -ne 0 ]; then
|
|
||||||
echo ":bangbang: Failed llgo cases:" | tee -a result.md
|
|
||||||
echo -e "$failed_cases" | tee -a result.md
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo ":white_check_mark: All llgo tests passed" | tee -a result.md
|
|
||||||
fi
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,6 +22,7 @@ _tinygo/
|
|||||||
_output/
|
_output/
|
||||||
build.dir/
|
build.dir/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.venv/
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "c/llama2/llama2.c"]
|
|
||||||
path = c/llama2/llama2.c
|
|
||||||
url = https://github.com/karpathy/llama2.c.git
|
|
||||||
|
|||||||
@@ -16,74 +16,70 @@ before:
|
|||||||
|
|
||||||
builds:
|
builds:
|
||||||
- id: llgo-darwin-amd64
|
- id: llgo-darwin-amd64
|
||||||
dir: compiler
|
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
binary: bin/llgo
|
||||||
flags:
|
flags:
|
||||||
- -tags=darwin,amd64,byollvm
|
- -tags=darwin,amd64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@18/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@19/bin/llvm-config
|
||||||
env:
|
env:
|
||||||
- CC=o64-clang
|
- CC=o64-clang
|
||||||
- CXX=o64-clang++
|
- CXX=o64-clang++
|
||||||
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@19/include -mmacosx-version-min=10.13 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||||
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-18 -lz -lm
|
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@19/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm
|
||||||
targets:
|
targets:
|
||||||
- darwin_amd64
|
- darwin_amd64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
- id: llgo-darwin-arm64
|
- id: llgo-darwin-arm64
|
||||||
dir: compiler
|
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
binary: bin/llgo
|
||||||
flags:
|
flags:
|
||||||
- -tags=darwin,arm64,byollvm
|
- -tags=darwin,arm64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@18/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@19/bin/llvm-config
|
||||||
env:
|
env:
|
||||||
- CC=oa64-clang
|
- CC=oa64-clang
|
||||||
- CXX=oa64-clang++
|
- CXX=oa64-clang++
|
||||||
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@19/include -mmacosx-version-min=10.13 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||||
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-18 -lz -lm
|
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@19/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm
|
||||||
targets:
|
targets:
|
||||||
- darwin_arm64
|
- darwin_arm64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
- id: llgo-linux-amd64
|
- id: llgo-linux-amd64
|
||||||
dir: compiler
|
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
binary: bin/llgo
|
||||||
flags:
|
flags:
|
||||||
- -tags=linux,amd64,byollvm
|
- -tags=linux,amd64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-19/bin/llvm-config
|
||||||
env:
|
env:
|
||||||
- CC=x86_64-linux-gnu-gcc
|
- CC=x86_64-linux-gnu-gcc
|
||||||
- CXX=x86_64-linux-gnu-g++
|
- CXX=x86_64-linux-gnu-g++
|
||||||
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-18 -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-19 -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-c-19 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||||
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-18/lib -lLLVM-18
|
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-19/lib -lLLVM-19
|
||||||
targets:
|
targets:
|
||||||
- linux_amd64
|
- linux_amd64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
- id: llgo-linux-arm64
|
- id: llgo-linux-arm64
|
||||||
dir: compiler
|
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
binary: bin/llgo
|
||||||
flags:
|
flags:
|
||||||
- -tags=linux,arm64,byollvm
|
- -tags=linux,arm64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-19/bin/llvm-config
|
||||||
env:
|
env:
|
||||||
- CC=aarch64-linux-gnu-gcc
|
- CC=aarch64-linux-gnu-gcc
|
||||||
- CXX=aarch64-linux-gnu-g++
|
- CXX=aarch64-linux-gnu-g++
|
||||||
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-18 -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-19 -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-c-19 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||||
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-18/lib -lLLVM-18
|
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-19/lib -lLLVM-19
|
||||||
targets:
|
targets:
|
||||||
- linux_arm64
|
- linux_arm64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
|
|||||||
149
README.md
149
README.md
@@ -31,19 +31,19 @@ LLGo is compatible with C and Python through the language's **Application Binary
|
|||||||
|
|
||||||
You can import a C/C++ standard library in LLGo!
|
You can import a C/C++ standard library in LLGo!
|
||||||
|
|
||||||
* [c](https://pkg.go.dev/github.com/goplus/llgo/c)
|
* [c](https://pkg.go.dev/github.com/goplus/lib/c)
|
||||||
* [c/syscall](https://pkg.go.dev/github.com/goplus/llgo/c/syscall)
|
* [c/syscall](https://pkg.go.dev/github.com/goplus/lib/c/syscall)
|
||||||
* [c/sys](https://pkg.go.dev/github.com/goplus/llgo/c/sys)
|
* [c/sys](https://pkg.go.dev/github.com/goplus/lib/c/sys)
|
||||||
* [c/os](https://pkg.go.dev/github.com/goplus/llgo/c/os)
|
* [c/os](https://pkg.go.dev/github.com/goplus/lib/c/os)
|
||||||
* [c/math](https://pkg.go.dev/github.com/goplus/llgo/c/math)
|
* [c/math](https://pkg.go.dev/github.com/goplus/lib/c/math)
|
||||||
* [c/math/cmplx](https://pkg.go.dev/github.com/goplus/llgo/c/math/cmplx)
|
* [c/math/cmplx](https://pkg.go.dev/github.com/goplus/lib/c/math/cmplx)
|
||||||
* [c/math/rand](https://pkg.go.dev/github.com/goplus/llgo/c/math/rand)
|
* [c/math/rand](https://pkg.go.dev/github.com/goplus/lib/c/math/rand)
|
||||||
* [c/pthread](https://pkg.go.dev/github.com/goplus/llgo/c/pthread)
|
* [c/pthread](https://pkg.go.dev/github.com/goplus/lib/c/pthread)
|
||||||
* [c/pthread/sync](https://pkg.go.dev/github.com/goplus/llgo/c/pthread/sync)
|
* [c/pthread/sync](https://pkg.go.dev/github.com/goplus/lib/c/pthread/sync)
|
||||||
* [c/sync/atomic](https://pkg.go.dev/github.com/goplus/llgo/c/sync/atomic)
|
* [c/sync/atomic](https://pkg.go.dev/github.com/goplus/lib/c/sync/atomic)
|
||||||
* [c/time](https://pkg.go.dev/github.com/goplus/llgo/c/time)
|
* [c/time](https://pkg.go.dev/github.com/goplus/lib/c/time)
|
||||||
* [c/net](https://pkg.go.dev/github.com/goplus/llgo/c/net)
|
* [c/net](https://pkg.go.dev/github.com/goplus/lib/c/net)
|
||||||
* [cpp/std](https://pkg.go.dev/github.com/goplus/llgo/cpp/std)
|
* [cpp/std](https://pkg.go.dev/github.com/goplus/lib/cpp/std)
|
||||||
|
|
||||||
Here is a simple example:
|
Here is a simple example:
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ Here is a simple example:
|
|||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/llgo/c"
|
import "github.com/goplus/lib/c"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c.Printf(c.Str("Hello world\n"))
|
c.Printf(c.Str("Hello world\n"))
|
||||||
@@ -105,14 +105,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Or put it into a package (see [c/math](c/math/math.go)):
|
Or put it into a package (see [c/math](https://github.com/goplus/lib/tree/main/c/math/math.go)):
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_call_cmath/call_cmath.go -->
|
<!-- embedme doc/_readme/llgo_call_cmath/call_cmath.go -->
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/llgo/c/math"
|
import "github.com/goplus/lib/c/math"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("sqrt(2) =", math.Sqrt(2))
|
println("sqrt(2) =", math.Sqrt(2))
|
||||||
@@ -126,18 +126,18 @@ 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](#development-tools)). The following libraries have been included in `llgo`:
|
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`:
|
||||||
|
|
||||||
* [py](https://pkg.go.dev/github.com/goplus/llgo/py) (abi)
|
* [py](https://pkg.go.dev/github.com/goplus/lib/py) (abi)
|
||||||
* [py/std](https://pkg.go.dev/github.com/goplus/llgo/py/std) (builtins)
|
* [py/std](https://pkg.go.dev/github.com/goplus/lib/py/std) (builtins)
|
||||||
* [py/sys](https://pkg.go.dev/github.com/goplus/llgo/py/sys)
|
* [py/sys](https://pkg.go.dev/github.com/goplus/lib/py/sys)
|
||||||
* [py/os](https://pkg.go.dev/github.com/goplus/llgo/py/os)
|
* [py/os](https://pkg.go.dev/github.com/goplus/lib/py/os)
|
||||||
* [py/math](https://pkg.go.dev/github.com/goplus/llgo/py/math)
|
* [py/math](https://pkg.go.dev/github.com/goplus/lib/py/math)
|
||||||
* [py/json](https://pkg.go.dev/github.com/goplus/llgo/py/json)
|
* [py/json](https://pkg.go.dev/github.com/goplus/lib/py/json)
|
||||||
* [py/inspect](https://pkg.go.dev/github.com/goplus/llgo/py/inspect)
|
* [py/inspect](https://pkg.go.dev/github.com/goplus/lib/py/inspect)
|
||||||
* [py/statistics](https://pkg.go.dev/github.com/goplus/llgo/py/statistics)
|
* [py/statistics](https://pkg.go.dev/github.com/goplus/lib/py/statistics)
|
||||||
* [py/numpy](https://pkg.go.dev/github.com/goplus/llgo/py/numpy)
|
* [py/numpy](https://pkg.go.dev/github.com/goplus/lib/py/numpy)
|
||||||
* [py/pandas](https://pkg.go.dev/github.com/goplus/llgo/py/pandas)
|
* [py/pandas](https://pkg.go.dev/github.com/goplus/lib/py/pandas)
|
||||||
* [py/torch](https://pkg.go.dev/github.com/goplus/llgo/py/torch)
|
* [py/torch](https://pkg.go.dev/github.com/goplus/lib/py/torch)
|
||||||
* [py/matplotlib](https://pkg.go.dev/github.com/goplus/llgo/py/matplotlib)
|
* [py/matplotlib](https://pkg.go.dev/github.com/goplus/lib/py/matplotlib)
|
||||||
|
|
||||||
Note: For third-party libraries (such as pandas and pytorch), you still need to install the library files.
|
Note: For third-party libraries (such as pandas and pytorch), you still need to install the library files.
|
||||||
|
|
||||||
@@ -149,9 +149,9 @@ Here is an example:
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/math"
|
"github.com/goplus/lib/py/math"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -181,9 +181,9 @@ Let's look at a slightly more complex example. For example, we use `numpy` to ca
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/numpy"
|
"github.com/goplus/lib/py/numpy"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -225,27 +225,27 @@ LLGo can easily import any libraries from the C ecosystem. Currently, this impor
|
|||||||
|
|
||||||
The currently supported libraries include:
|
The currently supported libraries include:
|
||||||
|
|
||||||
* [c/bdwgc](https://pkg.go.dev/github.com/goplus/llgo/c/bdwgc)
|
* [c/bdwgc](https://pkg.go.dev/github.com/goplus/lib/c/bdwgc)
|
||||||
* [c/cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
|
* [c/cjson](https://pkg.go.dev/github.com/goplus/lib/c/cjson)
|
||||||
* [c/clang](https://pkg.go.dev/github.com/goplus/llgo/c/clang)
|
* [c/clang](https://pkg.go.dev/github.com/goplus/lib/c/clang)
|
||||||
* [c/ffi](https://pkg.go.dev/github.com/goplus/llgo/c/ffi)
|
* [c/ffi](https://pkg.go.dev/github.com/goplus/lib/c/ffi)
|
||||||
* [c/libuv](https://pkg.go.dev/github.com/goplus/llgo/c/libuv)
|
* [c/libuv](https://pkg.go.dev/github.com/goplus/lib/c/libuv)
|
||||||
* [c/llama2](https://pkg.go.dev/github.com/goplus/llgo/c/llama2)
|
* [c/llama2](https://pkg.go.dev/github.com/goplus/lib/c/llama2)
|
||||||
* [c/lua](https://pkg.go.dev/github.com/goplus/llgo/c/lua)
|
* [c/lua](https://pkg.go.dev/github.com/goplus/lib/c/lua)
|
||||||
* [c/neco](https://pkg.go.dev/github.com/goplus/llgo/c/neco)
|
* [c/neco](https://pkg.go.dev/github.com/goplus/lib/c/neco)
|
||||||
* [c/openssl](https://pkg.go.dev/github.com/goplus/llgo/c/openssl)
|
* [c/openssl](https://pkg.go.dev/github.com/goplus/lib/c/openssl)
|
||||||
* [c/raylib](https://pkg.go.dev/github.com/goplus/llgo/c/raylib)
|
* [c/raylib](https://pkg.go.dev/github.com/goplus/lib/c/raylib)
|
||||||
* [c/sqlite](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite)
|
* [c/sqlite](https://pkg.go.dev/github.com/goplus/lib/c/sqlite)
|
||||||
* [c/zlib](https://pkg.go.dev/github.com/goplus/llgo/c/zlib)
|
* [c/zlib](https://pkg.go.dev/github.com/goplus/lib/c/zlib)
|
||||||
* [cpp/inih](https://pkg.go.dev/github.com/goplus/llgo/cpp/inih)
|
* [cpp/inih](https://pkg.go.dev/github.com/goplus/lib/cpp/inih)
|
||||||
* [cpp/llvm](https://pkg.go.dev/github.com/goplus/llgo/cpp/llvm)
|
* [cpp/llvm](https://pkg.go.dev/github.com/goplus/lib/cpp/llvm)
|
||||||
|
|
||||||
Here are some examples related to them:
|
Here are some examples related to them:
|
||||||
|
|
||||||
* [llama2-c](_demo/llama2-c): inference Llama 2 (It's the first llgo AI example)
|
* [llama2-c](_demo/llama2-c): inference Llama 2 (It's the first llgo AI example)
|
||||||
* [mkjson](c/cjson/_demo/mkjson/mkjson.go): create a json object and print it
|
* [mkjson](https://github.com/goplus/lib/tree/main/c/cjson/_demo/mkjson/mkjson.go): create a json object and print it
|
||||||
* [sqlitedemo](c/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
|
* [sqlitedemo](https://github.com/goplus/lib/tree/main/c/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
|
||||||
* [tetris](c/raylib/_demo/tetris/tetris.go): a tetris game based on raylib
|
* [tetris](https://github.com/goplus/lib/tree/main/c/raylib/_demo/tetris/tetris.go): a tetris game based on raylib
|
||||||
|
|
||||||
|
|
||||||
## Go syntax support
|
## Go syntax support
|
||||||
@@ -339,7 +339,7 @@ Here are the Go packages that can be imported correctly:
|
|||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- [Go 1.20+](https://go.dev)
|
- [Go 1.21+](https://go.dev)
|
||||||
- [LLVM 18](https://llvm.org)
|
- [LLVM 18](https://llvm.org)
|
||||||
- [Clang 18](https://clang.llvm.org)
|
- [Clang 18](https://clang.llvm.org)
|
||||||
- [LLD 18](https://lld.llvm.org)
|
- [LLD 18](https://lld.llvm.org)
|
||||||
@@ -347,7 +347,7 @@ Here are the Go packages that can be imported correctly:
|
|||||||
- [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/)
|
- [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/)
|
||||||
- [OpenSSL 3.0+](https://www.openssl.org/)
|
- [OpenSSL 3.0+](https://www.openssl.org/)
|
||||||
- [zlib 1.2+](https://www.zlib.net)
|
- [zlib 1.2+](https://www.zlib.net)
|
||||||
- [Python 3.12+](https://www.python.org) (optional, for [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py))
|
- [Python 3.12+](https://www.python.org) (optional, for [github.com/goplus/lib/py](https://pkg.go.dev/github.com/goplus/lib/py))
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|
||||||
@@ -359,11 +359,11 @@ Follow these steps to generate the `llgo` command (its usage is the same as the
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew update
|
brew update
|
||||||
brew install llvm@18 bdw-gc openssl cjson libffi pkg-config
|
brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config
|
||||||
brew install python@3.12 # optional
|
brew install python@3.12 # optional
|
||||||
brew link --force libffi
|
brew link --overwrite lld@19 libffi
|
||||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
# curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash
|
||||||
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### on Linux
|
### on Linux
|
||||||
@@ -373,12 +373,13 @@ go install -v github.com/goplus/llgo/cmd/llgo@latest
|
|||||||
<!-- embedme doc/_readme/scripts/install_ubuntu.sh#L2-L1000 -->
|
<!-- embedme doc/_readme/scripts/install_ubuntu.sh#L2-L1000 -->
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
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
|
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-19 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y llvm-18-dev clang-18 libclang-18-dev lld-18 pkg-config libgc-dev libssl-dev zlib1g-dev libcjson-dev libsqlite3-dev libunwind-dev
|
sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 pkg-config libgc-dev libssl-dev zlib1g-dev libcjson-dev libsqlite3-dev libunwind-dev libuv1-dev
|
||||||
sudo apt-get install -y python3.12-dev # optional
|
sudo apt-get install -y python3.12-dev # optional
|
||||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
#curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash
|
||||||
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Alpine Linux
|
#### Alpine Linux
|
||||||
@@ -391,17 +392,26 @@ export LLVM_CONFIG=/usr/lib/llvm18/bin/llvm-config
|
|||||||
export CGO_CPPFLAGS="$($LLVM_CONFIG --cppflags)"
|
export CGO_CPPFLAGS="$($LLVM_CONFIG --cppflags)"
|
||||||
export CGO_CXXFLAGS=-std=c++17
|
export CGO_CXXFLAGS=-std=c++17
|
||||||
export CGO_LDFLAGS="$($LLVM_CONFIG --ldflags) $($LLVM_CONFIG --libs all)"
|
export CGO_LDFLAGS="$($LLVM_CONFIG --ldflags) $($LLVM_CONFIG --libs all)"
|
||||||
go install -v -tags=byollvm -ldflags="-X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=$LLVM_CONFIG" github.com/goplus/llgo/cmd/llgo@latest
|
curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
### on Windows
|
### on Windows
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
|
### Install from source
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/scripts/install_llgo.sh#L2-L1000 -->
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/goplus/llgo.git
|
||||||
|
cd llgo
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Development tools
|
## 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`.
|
* [pydump](_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`.
|
||||||
* [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.
|
* [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.
|
* [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.
|
||||||
* [llgen](chore/llgen): It is used to compile Go packages into LLVM IR files (*.ll).
|
* [llgen](chore/llgen): It is used to compile Go packages into LLVM IR files (*.ll).
|
||||||
@@ -409,23 +419,24 @@ TODO
|
|||||||
|
|
||||||
How do I generate these tools?
|
How do I generate these tools?
|
||||||
|
|
||||||
<!-- embedme doc/_readme/scripts/install_llgo.sh#L2-L1000 -->
|
<!-- embedme doc/_readme/scripts/install_full.sh#L2-L1000 -->
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/goplus/llgo.git
|
git clone https://github.com/goplus/llgo.git
|
||||||
cd llgo/compiler
|
cd llgo
|
||||||
go install -v ./cmd/...
|
go install -v ./cmd/...
|
||||||
go install -v ./chore/... # compile all tools except pydump
|
go install -v ./chore/... # compile all tools except pydump
|
||||||
export LLGO_ROOT=$PWD/..
|
export LLGO_ROOT=$PWD
|
||||||
cd ../_xtool
|
cd _xtool
|
||||||
llgo install ./... # compile pydump
|
llgo install ./... # compile pydump
|
||||||
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
|
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key modules
|
## Key modules
|
||||||
|
|
||||||
Below are the key modules for understanding the implementation principles of `llgo`:
|
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`.
|
* [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`.
|
* [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`.
|
* [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`.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c/sync/atomic"
|
"github.com/goplus/lib/c/sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/os"
|
"github.com/goplus/lib/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
func concat(args ...string) (ret string) {
|
func concat(args ...string) (ret string) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/goplus/lib/c"
|
||||||
|
"github.com/goplus/lib/c/math"
|
||||||
"github.com/goplus/llgo/_demo/cppintf/foo"
|
"github.com/goplus/llgo/_demo/cppintf/foo"
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/math"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bar struct {
|
type Bar struct {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/lib/c"
|
||||||
|
"github.com/goplus/lib/c/math"
|
||||||
"github.com/goplus/llgo/_demo/cppmintf/foo"
|
"github.com/goplus/llgo/_demo/cppmintf/foo"
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/math"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bar struct {
|
type Bar struct {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/math/rand"
|
"github.com/goplus/lib/c/math/rand"
|
||||||
"github.com/goplus/llgo/c/time"
|
"github.com/goplus/lib/c/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fastrand64() uint64 {
|
func fastrand64() uint64 {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/llgo/c/time"
|
import "github.com/goplus/lib/c/time"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var tv time.Timespec
|
var tv time.Timespec
|
||||||
|
|||||||
18
_demo/defer/main.go
Normal file
18
_demo/defer/main.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var a int = 5
|
||||||
|
defer println(a)
|
||||||
|
defer func() {
|
||||||
|
println(a)
|
||||||
|
}()
|
||||||
|
defer func() {
|
||||||
|
println(recover().(string))
|
||||||
|
}()
|
||||||
|
a = 10
|
||||||
|
panic("error")
|
||||||
|
//Output:
|
||||||
|
// error
|
||||||
|
// 10
|
||||||
|
// 5
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/os"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/lib/c"
|
||||||
|
"github.com/goplus/lib/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -45,8 +46,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
c.Printf(c.Str("set file status successfully\n"))
|
c.Printf(c.Str("set file status successfully\n"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
c.Printf(c.Str("111"))
|
c.Printf(c.Str("111"))
|
||||||
// Close file
|
// Close file
|
||||||
os.Close(fd)
|
os.Close(fd)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
type generator struct {
|
type generator struct {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/os"
|
"github.com/goplus/lib/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
5
_demo/go.mod
Normal file
5
_demo/go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/goplus/llgo/_demo
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require github.com/goplus/lib v0.1.0
|
||||||
2
_demo/go.sum
Normal file
2
_demo/go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||||
|
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goplus/lib/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c.Printf(c.Str("Hello world\n"))
|
println("hello world by println")
|
||||||
|
fmt.Println("hello world by fmt.Println")
|
||||||
|
c.Printf(c.Str("Hello world by c.Printf\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expected output:
|
/* Expected output:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/llama2"
|
"github.com/goplus/lib/c/llama2"
|
||||||
"github.com/goplus/llgo/c/time"
|
"github.com/goplus/lib/c/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/net"
|
"github.com/goplus/lib/c/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c/setjmp"
|
"github.com/goplus/lib/c/setjmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/net"
|
"github.com/goplus/lib/c/net"
|
||||||
"github.com/goplus/llgo/c/os"
|
"github.com/goplus/lib/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/net"
|
"github.com/goplus/lib/c/net"
|
||||||
"github.com/goplus/llgo/c/os"
|
"github.com/goplus/lib/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
112
_demo/sync/sync.go
Normal file
112
_demo/sync/sync.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Counter represents a thread-safe counter
|
||||||
|
type Counter struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
value int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment increases the counter value by 1
|
||||||
|
func (c *Counter) Increment() {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.value++
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue returns the current value of the counter
|
||||||
|
func (c *Counter) GetValue() int64 {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant values for the test
|
||||||
|
const (
|
||||||
|
numGoroutines = 64
|
||||||
|
numIterations = 10000
|
||||||
|
expectedTotal = numGoroutines * numIterations
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Create a new counter instance
|
||||||
|
counter := &Counter{}
|
||||||
|
|
||||||
|
// Create a wait group to wait for all goroutines to finish
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Track active goroutines for monitoring
|
||||||
|
var activeGoroutines int32
|
||||||
|
|
||||||
|
// Start time
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
|
// Launch goroutines
|
||||||
|
for i := 0; i < numGoroutines; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
atomic.AddInt32(&activeGoroutines, 1)
|
||||||
|
|
||||||
|
go func(id int) {
|
||||||
|
defer func() {
|
||||||
|
wg.Done()
|
||||||
|
atomic.AddInt32(&activeGoroutines, -1)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Each goroutine increments the counter numIterations times
|
||||||
|
for j := 0; j < numIterations; j++ {
|
||||||
|
counter.Increment()
|
||||||
|
|
||||||
|
// Simulate varying workload with random sleeps
|
||||||
|
if j%100 == 0 {
|
||||||
|
time.Sleep(time.Microsecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Goroutine %d finished\n", id)
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monitor progress in a separate goroutine
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
active := atomic.LoadInt32(&activeGoroutines)
|
||||||
|
if active == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("Active goroutines: %d\n", active)
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for all goroutines to complete
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
// Calculate execution time
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
|
||||||
|
// Get and verify the final result
|
||||||
|
finalValue := counter.GetValue()
|
||||||
|
fmt.Printf("\nExecution completed in: %v\n", duration)
|
||||||
|
fmt.Printf("Final counter value: %d\n", finalValue)
|
||||||
|
fmt.Printf("Expected value: %d\n", expectedTotal)
|
||||||
|
|
||||||
|
// Assert the result
|
||||||
|
if finalValue != expectedTotal {
|
||||||
|
panic(fmt.Sprintf("ERROR: Counter value mismatch! Expected %d, got %d\n",
|
||||||
|
expectedTotal, finalValue))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("SUCCESS: Counter value matches expected total\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print some statistics
|
||||||
|
opsPerSecond := float64(expectedTotal) / duration.Seconds()
|
||||||
|
fmt.Printf("\nStatistics:\n")
|
||||||
|
fmt.Printf("Operations per second: %.2f\n", opsPerSecond)
|
||||||
|
fmt.Printf("Average time per operation: %.2f ns\n",
|
||||||
|
float64(duration.Nanoseconds())/float64(expectedTotal))
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
llsync "github.com/goplus/llgo/c/pthread/sync"
|
llsync "github.com/goplus/lib/c/pthread/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type L struct {
|
type L struct {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/pthread"
|
"github.com/goplus/lib/c/pthread"
|
||||||
)
|
)
|
||||||
|
|
||||||
var key pthread.Key
|
var key pthread.Key
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
### Build with debug info
|
### Build with debug info
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
LLGO_DEBUG=1 llgo build -o cl/_testdata/debug/out ./cl/_testdata/debug
|
LLGO_DEBUG_SYMBOLS=1 llgo build -o cl/_testdata/debug/out ./cl/_testdata/debug
|
||||||
```
|
```
|
||||||
|
|
||||||
### Debug with lldb
|
### Debug with lldb
|
||||||
@@ -44,7 +44,7 @@ build_project() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LLGO_DEBUG=1 llgo build -o "debug.out" . || {
|
LLGO_DEBUG_SYMBOLS=1 llgo build -o "debug.out" . || {
|
||||||
local ret=$?
|
local ret=$?
|
||||||
cd "$current_dir" || return
|
cd "$current_dir" || return
|
||||||
return $ret
|
return $ret
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/math"
|
"github.com/goplus/lib/py/math"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
5
_pydemo/go.mod
Normal file
5
_pydemo/go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/goplus/llgo/_pydemo
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require github.com/goplus/lib v0.1.0
|
||||||
2
_pydemo/go.sum
Normal file
2
_pydemo/go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||||
|
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/numpy"
|
"github.com/goplus/lib/py/numpy"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/py/math"
|
"github.com/goplus/lib/py/math"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/statistics"
|
"github.com/goplus/lib/py/statistics"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/std"
|
"github.com/goplus/lib/py/std"
|
||||||
"github.com/goplus/llgo/py/torch"
|
"github.com/goplus/lib/py/torch"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/clang"
|
"github.com/goplus/lib/c/clang"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Data struct {
|
type Data struct {
|
||||||
|
|||||||
5
_xtool/go.mod
Normal file
5
_xtool/go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/goplus/llgo/_xtool
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require github.com/goplus/lib v0.1.0
|
||||||
2
_xtool/go.sum
Normal file
2
_xtool/go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||||
|
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/lib/c"
|
||||||
"github.com/goplus/llgo/c/cjson"
|
"github.com/goplus/lib/c/cjson"
|
||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/lib/py"
|
||||||
"github.com/goplus/llgo/py/inspect"
|
"github.com/goplus/lib/py/inspect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/bdwgc"
|
|
||||||
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ------ Test malloc ------
|
|
||||||
|
|
||||||
func TestMalloc(t *testing.T) {
|
|
||||||
pn := (*int)(bdwgc.Malloc(unsafe.Sizeof(int(0))))
|
|
||||||
*pn = 1 << 30
|
|
||||||
c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn)
|
|
||||||
|
|
||||||
pl := (*int64)(bdwgc.Realloc(c.Pointer(pn), unsafe.Sizeof(int64(0))))
|
|
||||||
*pl = 1 << 60
|
|
||||||
c.Printf(c.Str("value: %lld, %llx, %p, %p\n"), *pl, *pl, pl, &pl)
|
|
||||||
|
|
||||||
bdwgc.Free(c.Pointer(pl))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------ Test finalizer ------
|
|
||||||
|
|
||||||
const (
|
|
||||||
RETURN_VALUE_FREED = 1 << 31
|
|
||||||
)
|
|
||||||
|
|
||||||
var called uint = 0
|
|
||||||
|
|
||||||
func setReturnValueFreed(pobj c.Pointer, clientData c.Pointer) {
|
|
||||||
called |= RETURN_VALUE_FREED
|
|
||||||
c.Printf(c.Str("called: %x\n"), called)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setLoopValueFreed(pobj c.Pointer, clientData c.Pointer) {
|
|
||||||
pmask := (*uint)(clientData)
|
|
||||||
called |= *pmask
|
|
||||||
c.Printf(c.Str("called: %x\n"), called)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isCalled(mask uint) bool {
|
|
||||||
return called&mask != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func returnValue() *int {
|
|
||||||
pn := bdwgc.Malloc(unsafe.Sizeof(int(0)))
|
|
||||||
bdwgc.RegisterFinalizer(pn, setReturnValueFreed, nil, nil, nil)
|
|
||||||
return (*int)(pn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func callFunc() {
|
|
||||||
pn := returnValue()
|
|
||||||
*pn = 1 << 30
|
|
||||||
c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn)
|
|
||||||
bdwgc.Gcollect()
|
|
||||||
check(!isCalled(RETURN_VALUE_FREED), c.Str("finalizer should not be called"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func loop() {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
p := bdwgc.Malloc(unsafe.Sizeof(int(0)))
|
|
||||||
pn := (*int)(p)
|
|
||||||
*pn = i
|
|
||||||
c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn)
|
|
||||||
pflag := (*uint)(c.Malloc(unsafe.Sizeof(uint(0))))
|
|
||||||
*pflag = 1 << i
|
|
||||||
bdwgc.RegisterFinalizer(p, setLoopValueFreed, c.Pointer(pflag), nil, nil)
|
|
||||||
bdwgc.Gcollect()
|
|
||||||
check(!isCalled(1<<i), c.Str("finalizer should not be called"))
|
|
||||||
for j := 0; j < i; j++ {
|
|
||||||
check(isCalled(1<<j), c.Str("finalizers of previous objects should be called"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear stack to avoid reference
|
|
||||||
func clearStack() {
|
|
||||||
p := c.Alloca(128)
|
|
||||||
c.Memset(p, 0, 128)
|
|
||||||
}
|
|
||||||
|
|
||||||
func check(b bool, msg *c.Char) {
|
|
||||||
if !b {
|
|
||||||
c.Printf(c.Str("check failed: %s\n"), msg)
|
|
||||||
panic("check failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFinalizer(t *testing.T) {
|
|
||||||
bdwgc.Init()
|
|
||||||
|
|
||||||
callFunc()
|
|
||||||
clearStack()
|
|
||||||
bdwgc.Gcollect()
|
|
||||||
check(isCalled(RETURN_VALUE_FREED), c.Str("finalizer should be called"))
|
|
||||||
|
|
||||||
loop()
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestCase struct {
|
|
||||||
Name string
|
|
||||||
F func(*testing.T)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tests := []TestCase{
|
|
||||||
{"TestMalloc", TestMalloc},
|
|
||||||
{"TestFinalizer", TestFinalizer},
|
|
||||||
}
|
|
||||||
if c.Argc == 1 {
|
|
||||||
for _, test := range tests {
|
|
||||||
c.Printf(c.Str("%s\n"), c.AllocaCStr(test.Name))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Fprintf(c.Stderr, c.Str("arg: %s\n"), c.Index(c.Argv, 1))
|
|
||||||
idx := int(c.Atoi(c.Index(c.Argv, 1)))
|
|
||||||
if idx < 0 || idx >= len(tests) {
|
|
||||||
c.Printf(c.Str("invalid test index %d"), idx)
|
|
||||||
panic("invalid test index")
|
|
||||||
}
|
|
||||||
tests[idx].F(nil)
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package testing
|
|
||||||
|
|
||||||
type T struct {
|
|
||||||
}
|
|
||||||
103
c/bdwgc/bdwgc.go
103
c/bdwgc/bdwgc.go
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package bdwgc
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "link: $(pkg-config --libs bdw-gc); -lgc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Init C.GC_init
|
|
||||||
func Init()
|
|
||||||
|
|
||||||
//go:linkname Malloc C.GC_malloc
|
|
||||||
func Malloc(size uintptr) c.Pointer
|
|
||||||
|
|
||||||
//go:linkname Realloc C.GC_realloc
|
|
||||||
func Realloc(ptr c.Pointer, size uintptr) c.Pointer
|
|
||||||
|
|
||||||
//go:linkname Free C.GC_free
|
|
||||||
func Free(ptr c.Pointer)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname RegisterFinalizer C.GC_register_finalizer
|
|
||||||
func RegisterFinalizer(
|
|
||||||
obj c.Pointer,
|
|
||||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
|
||||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
|
||||||
|
|
||||||
//go:linkname RegisterFinalizerNoOrder C.GC_register_finalizer_no_order
|
|
||||||
func RegisterFinalizerNoOrder(
|
|
||||||
obj c.Pointer,
|
|
||||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
|
||||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
|
||||||
|
|
||||||
//go:linkname RegisterFinalizerIgnoreSelf C.GC_register_finalizer_ignore_self
|
|
||||||
func RegisterFinalizerIgnoreSelf(
|
|
||||||
obj c.Pointer,
|
|
||||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
|
||||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
|
||||||
|
|
||||||
//go:linkname RegisterFinalizerUnreachable C.GC_register_finalizer_unreachable
|
|
||||||
func RegisterFinalizerUnreachable(
|
|
||||||
obj c.Pointer,
|
|
||||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
|
||||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Enable C.GC_enable
|
|
||||||
func Enable()
|
|
||||||
|
|
||||||
//go:linkname Disable C.GC_disable
|
|
||||||
func Disable()
|
|
||||||
|
|
||||||
//go:linkname IsDisabled C.GC_is_disabled
|
|
||||||
func IsDisabled() c.Int
|
|
||||||
|
|
||||||
//go:linkname Gcollect C.GC_gcollect
|
|
||||||
func Gcollect()
|
|
||||||
|
|
||||||
//go:linkname GetMemoryUse C.GC_get_memory_use
|
|
||||||
func GetMemoryUse() uintptr
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname EnableIncremental C.GC_enable_incremental
|
|
||||||
func EnableIncremental()
|
|
||||||
|
|
||||||
//go:linkname IsIncrementalMode C.GC_is_incremental_mode
|
|
||||||
func IsIncrementalMode() c.Int
|
|
||||||
|
|
||||||
//go:linkname IncrementalProtectionNeeds C.GC_incremental_protection_needs
|
|
||||||
func IncrementalProtectionNeeds() c.Int
|
|
||||||
|
|
||||||
//go:linkname StartIncrementalCollection C.GC_start_incremental_collection
|
|
||||||
func StartIncrementalCollection()
|
|
||||||
|
|
||||||
//go:linkname CollectALittle C.GC_collect_a_little
|
|
||||||
func CollectALittle()
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
typedef union {
|
|
||||||
double d;
|
|
||||||
float f;
|
|
||||||
long v;
|
|
||||||
} castUnion;
|
|
||||||
|
|
||||||
double llgoToFloat64(long v) {
|
|
||||||
castUnion k;
|
|
||||||
k.v = v;
|
|
||||||
return k.d;
|
|
||||||
}
|
|
||||||
|
|
||||||
float llgoToFloat32(long v) {
|
|
||||||
castUnion k;
|
|
||||||
k.v = v;
|
|
||||||
return k.f;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package bitcast
|
|
||||||
|
|
||||||
import _ "unsafe"
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoFiles = "_cast/cast.c"
|
|
||||||
LLGoPackage = "link"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:linkname ToFloat64 C.llgoToFloat64
|
|
||||||
func ToFloat64(v uintptr) float64
|
|
||||||
|
|
||||||
//go:linkname ToFloat32 C.llgoToFloat32
|
|
||||||
func ToFloat32(v uintptr) float32
|
|
||||||
302
c/c.go
302
c/c.go
@@ -1,302 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package c
|
|
||||||
|
|
||||||
// typedef unsigned int uint;
|
|
||||||
// typedef unsigned long ulong;
|
|
||||||
// typedef unsigned long long ulonglong;
|
|
||||||
// typedef long long longlong;
|
|
||||||
import "C"
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "decl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Void = [0]byte
|
|
||||||
Char = int8
|
|
||||||
Float = float32
|
|
||||||
Double = float64
|
|
||||||
Pointer = unsafe.Pointer
|
|
||||||
FilePtr = *FILE
|
|
||||||
)
|
|
||||||
|
|
||||||
type FILE struct {
|
|
||||||
Unused [8]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
Int C.int
|
|
||||||
Uint C.uint
|
|
||||||
|
|
||||||
Long C.long
|
|
||||||
Ulong C.ulong
|
|
||||||
|
|
||||||
LongLong C.longlong
|
|
||||||
UlongLong C.ulonglong
|
|
||||||
)
|
|
||||||
|
|
||||||
type integer interface {
|
|
||||||
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type SizeT = uintptr
|
|
||||||
|
|
||||||
type IntptrT = uintptr
|
|
||||||
type UintptrT = uintptr
|
|
||||||
type Int8T = int8
|
|
||||||
type Int16T = int16
|
|
||||||
type Int32T = int32
|
|
||||||
type Int64T = int64
|
|
||||||
|
|
||||||
type Uint8T = uint8
|
|
||||||
type Uint16T = uint16
|
|
||||||
type Uint32T = uint32
|
|
||||||
type Uint64T = uint64
|
|
||||||
|
|
||||||
type IntmaxT = LongLong
|
|
||||||
type UintmaxT = UlongLong
|
|
||||||
|
|
||||||
//go:linkname Str llgo.cstr
|
|
||||||
func Str(string) *Char
|
|
||||||
|
|
||||||
//go:linkname Func llgo.funcAddr
|
|
||||||
func Func(any) Pointer
|
|
||||||
|
|
||||||
// llgo:link Advance llgo.advance
|
|
||||||
func Advance[PtrT any, I integer](ptr PtrT, offset I) PtrT { return ptr }
|
|
||||||
|
|
||||||
// llgo:link Index llgo.index
|
|
||||||
func Index[T any, I integer](ptr *T, offset I) T { return *ptr }
|
|
||||||
|
|
||||||
//go:linkname Alloca llgo.alloca
|
|
||||||
func Alloca(size uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname AllocaCStr llgo.allocaCStr
|
|
||||||
func AllocaCStr(s string) *Char
|
|
||||||
|
|
||||||
//go:linkname AllocaCStrs llgo.allocaCStrs
|
|
||||||
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
|
||||||
|
|
||||||
// TODO(xsw):
|
|
||||||
// llgo:link AllocaNew llgo.allocaNew
|
|
||||||
func AllocaNew[T any]() *T { return nil }
|
|
||||||
|
|
||||||
//go:linkname Malloc C.malloc
|
|
||||||
func Malloc(size uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Calloc C.calloc
|
|
||||||
func Calloc(num uintptr, size uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Free C.free
|
|
||||||
func Free(ptr Pointer)
|
|
||||||
|
|
||||||
//go:linkname Realloc C.realloc
|
|
||||||
func Realloc(ptr Pointer, size uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Memcpy C.memcpy
|
|
||||||
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Memmove C.memmove
|
|
||||||
func Memmove(dst, src Pointer, n uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Memset C.memset
|
|
||||||
func Memset(s Pointer, c Int, n uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Memchr C.memchr
|
|
||||||
func Memchr(s Pointer, c Int, n uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Memcmp C.memcmp
|
|
||||||
func Memcmp(s1, s2 Pointer, n uintptr) Int
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Strlen C.strlen
|
|
||||||
func Strlen(s *Char) uintptr
|
|
||||||
|
|
||||||
//go:linkname Strcpy C.strcpy
|
|
||||||
func Strcpy(dst, src *Char) *Char
|
|
||||||
|
|
||||||
//go:linkname Strncpy C.strncpy
|
|
||||||
func Strncpy(dst, src *Char, n uintptr) *Char
|
|
||||||
|
|
||||||
//go:linkname Strcat C.strcat
|
|
||||||
func Strcat(dst, src *Char) *Char
|
|
||||||
|
|
||||||
//go:linkname Strncat C.strncat
|
|
||||||
func Strncat(dst, src *Char, n uintptr) *Char
|
|
||||||
|
|
||||||
//go:linkname Strcmp C.strcmp
|
|
||||||
func Strcmp(s1, s2 *Char) Int
|
|
||||||
|
|
||||||
//go:linkname Strncmp C.strncmp
|
|
||||||
func Strncmp(s1, s2 *Char, n uintptr) Int
|
|
||||||
|
|
||||||
//go:linkname Strchr C.strchr
|
|
||||||
func Strchr(s *Char, c Int) *Char
|
|
||||||
|
|
||||||
//go:linkname Strrchr C.strrchr
|
|
||||||
func Strrchr(s *Char, c Int) *Char
|
|
||||||
|
|
||||||
//go:linkname Strstr C.strstr
|
|
||||||
func Strstr(s1, s2 *Char) *Char
|
|
||||||
|
|
||||||
//go:linkname Strdup C.strdup
|
|
||||||
func Strdup(s *Char) *Char
|
|
||||||
|
|
||||||
//go:linkname Strndup C.strndup
|
|
||||||
func Strndup(s *Char, n uintptr) *Char
|
|
||||||
|
|
||||||
//go:linkname Strtok C.strtok
|
|
||||||
func Strtok(s, delim *Char) *Char
|
|
||||||
|
|
||||||
//go:linkname Strerror C.strerror
|
|
||||||
func Strerror(errnum Int) *Char
|
|
||||||
|
|
||||||
//go:linkname Sprintf C.sprintf
|
|
||||||
func Sprintf(s *Char, format *Char, __llgo_va_list ...any) Int
|
|
||||||
|
|
||||||
//go:linkname Snprintf C.snprintf
|
|
||||||
func Snprintf(s *Char, n uintptr, format *Char, __llgo_va_list ...any) Int
|
|
||||||
|
|
||||||
//go:linkname Vsnprintf C.vsnprintf
|
|
||||||
func Vsnprintf(s *Char, n uintptr, format *Char, ap Pointer) Int
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// GoString converts a C string to a Go string.
|
|
||||||
// TODO(xsw): any => int
|
|
||||||
//
|
|
||||||
//go:linkname GoString llgo.string
|
|
||||||
func GoString(cstr *Char, __llgo_va_list /* n */ ...any) string
|
|
||||||
|
|
||||||
//go:linkname GoStringData llgo.stringData
|
|
||||||
func GoStringData(string) *Char
|
|
||||||
|
|
||||||
//go:linkname GoDeferData llgo.deferData
|
|
||||||
func GoDeferData() Pointer
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname AllocaSigjmpBuf llgo.sigjmpbuf
|
|
||||||
func AllocaSigjmpBuf() Pointer
|
|
||||||
|
|
||||||
//go:linkname Sigsetjmp llgo.sigsetjmp
|
|
||||||
func Sigsetjmp(jb Pointer, savemask Int) Int
|
|
||||||
|
|
||||||
//go:linkname Siglongjmp llgo.siglongjmp
|
|
||||||
func Siglongjmp(jb Pointer, retval Int)
|
|
||||||
|
|
||||||
//go:linkname Unreachable llgo.unreachable
|
|
||||||
func Unreachable()
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Exit C.exit
|
|
||||||
func Exit(Int)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Rand C.rand
|
|
||||||
func Rand() Int
|
|
||||||
|
|
||||||
//go:linkname Qsort C.qsort
|
|
||||||
func Qsort(base Pointer, count, elem uintptr, compar func(a, b Pointer) Int)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Atoi C.atoi
|
|
||||||
func Atoi(s *Char) Int
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Printf C.printf
|
|
||||||
func Printf(format *Char, __llgo_va_list ...any) Int
|
|
||||||
|
|
||||||
//go:linkname Fprintf C.fprintf
|
|
||||||
func Fprintf(fp FilePtr, format *Char, __llgo_va_list ...any) Int
|
|
||||||
|
|
||||||
//go:linkname Fwrite C.fwrite
|
|
||||||
func Fwrite(data Pointer, size, count uintptr, fp FilePtr) uintptr
|
|
||||||
|
|
||||||
//go:linkname Fputc C.fputc
|
|
||||||
func Fputc(c Int, fp FilePtr) Int
|
|
||||||
|
|
||||||
//go:linkname Fputs C.fputs
|
|
||||||
func Fputs(s *Char, fp FilePtr) Int
|
|
||||||
|
|
||||||
//go:linkname Fread C.fread
|
|
||||||
func Fread(data Pointer, size, count uintptr, fp FilePtr) uintptr
|
|
||||||
|
|
||||||
//go:linkname Fflush C.fflush
|
|
||||||
func Fflush(fp FilePtr) Int
|
|
||||||
|
|
||||||
//go:linkname Fopen C.fopen
|
|
||||||
func Fopen(c *Char, mod *Char) FilePtr
|
|
||||||
|
|
||||||
//go:linkname Fclose C.fclose
|
|
||||||
func Fclose(fp FilePtr) Int
|
|
||||||
|
|
||||||
//go:linkname Perror C.perror
|
|
||||||
func Perror(s *Char)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Usleep C.usleep
|
|
||||||
func Usleep(useconds Uint) Int
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type Option struct {
|
|
||||||
Name *Char
|
|
||||||
HasArg Int
|
|
||||||
Flag *Int
|
|
||||||
Val Int
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname Argc __llgo_argc
|
|
||||||
var Argc Int
|
|
||||||
|
|
||||||
//go:linkname Argv __llgo_argv
|
|
||||||
var Argv **Char
|
|
||||||
|
|
||||||
//go:linkname Optarg optarg
|
|
||||||
var Optarg *Char
|
|
||||||
|
|
||||||
//go:linkname Optind optind
|
|
||||||
var Optind Int
|
|
||||||
|
|
||||||
//go:linkname Opterr opterr
|
|
||||||
var Opterr Int
|
|
||||||
|
|
||||||
//go:linkname Optopt optopt
|
|
||||||
var Optopt Int
|
|
||||||
|
|
||||||
//go:linkname Getopt C.getopt
|
|
||||||
func Getopt(argc Int, argv **Char, optstring *Char) Int
|
|
||||||
|
|
||||||
//go:linkname GetoptLong C.getopt_long
|
|
||||||
func GetoptLong(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
|
||||||
|
|
||||||
//go:linkname GetoptLongOnly C.getopt_long_only
|
|
||||||
func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Sysconf C.sysconf
|
|
||||||
func Sysconf(name Int) Long
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
//go:build !linux
|
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package c
|
|
||||||
|
|
||||||
import _ "unsafe"
|
|
||||||
|
|
||||||
//go:linkname Stdin __stdinp
|
|
||||||
var Stdin FilePtr
|
|
||||||
|
|
||||||
//go:linkname Stdout __stdoutp
|
|
||||||
var Stdout FilePtr
|
|
||||||
|
|
||||||
//go:linkname Stderr __stderrp
|
|
||||||
var Stderr FilePtr
|
|
||||||
31
c/c_linux.go
31
c/c_linux.go
@@ -1,31 +0,0 @@
|
|||||||
//go:build linux
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package c
|
|
||||||
|
|
||||||
import _ "unsafe"
|
|
||||||
|
|
||||||
//go:linkname Stdin stdin
|
|
||||||
var Stdin FilePtr
|
|
||||||
|
|
||||||
//go:linkname Stdout stdout
|
|
||||||
var Stdout FilePtr
|
|
||||||
|
|
||||||
//go:linkname Stderr stderr
|
|
||||||
var Stderr FilePtr
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
LLGo wrapper of DaveGamble/cJSON
|
|
||||||
=====
|
|
||||||
|
|
||||||
## How to install
|
|
||||||
|
|
||||||
### on macOS (Homebrew)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
brew install cjson
|
|
||||||
```
|
|
||||||
|
|
||||||
### on Linux (Debian/Ubuntu)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
apt-get install -y libcjson-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Demos
|
|
||||||
|
|
||||||
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it):
|
|
||||||
|
|
||||||
* [mkjson](_demo/mkjson/mkjson.go): create a json object and print it
|
|
||||||
|
|
||||||
### How to run demos
|
|
||||||
|
|
||||||
To run the demos in directory `_demo`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cd <demo-directory> # eg. cd _demo/mkjson
|
|
||||||
llgo run .
|
|
||||||
```
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
mod := cjson.Object()
|
|
||||||
mod.SetItem(c.Str("name"), cjson.String(c.Str("math")))
|
|
||||||
|
|
||||||
syms := cjson.Array()
|
|
||||||
|
|
||||||
fn := cjson.Object()
|
|
||||||
fn.SetItem(c.Str("name"), cjson.String(c.Str("sqrt")))
|
|
||||||
fn.SetItem(c.Str("sig"), cjson.String(c.Str("(x, /)")))
|
|
||||||
syms.AddItem(fn)
|
|
||||||
|
|
||||||
v := cjson.Object()
|
|
||||||
v.SetItem(c.Str("name"), cjson.String(c.Str("pi")))
|
|
||||||
syms.AddItem(v)
|
|
||||||
|
|
||||||
mod.SetItem(c.Str("items"), syms)
|
|
||||||
|
|
||||||
cstr := mod.CStr()
|
|
||||||
str := c.GoString(cstr)
|
|
||||||
c.Printf(c.Str("%s\n"), cstr)
|
|
||||||
cjson.FreeCStr(cstr)
|
|
||||||
|
|
||||||
mod.Delete()
|
|
||||||
|
|
||||||
cjsonLoad(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cjsonLoad(str string) {
|
|
||||||
mod := cjson.ParseString(str)
|
|
||||||
|
|
||||||
cstr := mod.Print()
|
|
||||||
c.Printf(c.Str("%s\n"), cstr)
|
|
||||||
cjson.FreeCStr(cstr)
|
|
||||||
|
|
||||||
mod.Delete()
|
|
||||||
}
|
|
||||||
670
c/cjson/cjson.go
670
c/cjson/cjson.go
@@ -1,670 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package cjson
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "link: $(pkg-config --libs libcjson); -lcjson"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Bool c.Int
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type JSON struct {
|
|
||||||
Unused [0]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseBytes(value []byte) *JSON {
|
|
||||||
return ParseWithLength((*c.Char)(unsafe.Pointer(unsafe.SliceData(value))), uintptr(len(value)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseString(value string) *JSON {
|
|
||||||
return ParseWithLength((*c.Char)(unsafe.Pointer(unsafe.StringData(value))), uintptr(len(value)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
|
||||||
//
|
|
||||||
// Render a cJSON entity to text for transfer/storage without any formatting.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).CStr C.cJSON_PrintUnformatted
|
|
||||||
func (o *JSON) CStr() *c.Char { return nil }
|
|
||||||
|
|
||||||
// Same as CStr. Provided for Go+.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).Cstr C.cJSON_PrintUnformatted
|
|
||||||
func (o *JSON) Cstr() *c.Char { return nil }
|
|
||||||
|
|
||||||
// malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks
|
|
||||||
//
|
|
||||||
//go:linkname FreeCStr C.cJSON_free
|
|
||||||
func FreeCStr(*c.Char)
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(const char*) cJSON_Version(void);
|
|
||||||
//
|
|
||||||
// returns the version of cJSON as a string
|
|
||||||
//
|
|
||||||
//go:linkname Version C.cJSON_Version
|
|
||||||
func Version() *c.Char
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
|
||||||
//
|
|
||||||
// Memory Management: the caller is always responsible to free
|
|
||||||
// the results from all variants of cJSON_Parse (with cJSON_Delete)
|
|
||||||
// and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or
|
|
||||||
// cJSON_free as appropriate). The exception is cJSON_PrintPreallocated,
|
|
||||||
// where the caller has full responsibility of the buffer.
|
|
||||||
//
|
|
||||||
//go:linkname Parse C.cJSON_Parse
|
|
||||||
func Parse(value *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
|
||||||
//
|
|
||||||
// Memory Management: the caller is always responsible to free
|
|
||||||
// the results from all variants of cJSON_Parse (with cJSON_Delete)
|
|
||||||
// and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or
|
|
||||||
// cJSON_free as appropriate). The exception is cJSON_PrintPreallocated,
|
|
||||||
// where the caller has full responsibility of the buffer.
|
|
||||||
//
|
|
||||||
//go:linkname ParseWithLength C.cJSON_ParseWithLength
|
|
||||||
func ParseWithLength(value *c.Char, valueLength uintptr) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_Bool require_null_terminated);
|
|
||||||
//
|
|
||||||
// ParseWithOpts allows you to require (and check) that the JSON is null terminated,
|
|
||||||
// and to retrieve the pointer to the final byte parsed.
|
|
||||||
// If you supply a ptr in return_parse_end and parsing fails, then
|
|
||||||
// return_parse_end will contain a pointer to the error so will match
|
|
||||||
// cJSON_GetErrorPtr().
|
|
||||||
//
|
|
||||||
//go:linkname ParseWithOpts C.cJSON_ParseWithOpts
|
|
||||||
func ParseWithOpts(value *c.Char, return_parse_end **c.Char, require_null_terminated Bool) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_Bool require_null_terminated);
|
|
||||||
//
|
|
||||||
// ParseWithOpts allows you to require (and check) that the JSON is null terminated,
|
|
||||||
// and to retrieve the pointer to the final byte parsed.
|
|
||||||
// If you supply a ptr in return_parse_end and parsing fails, then
|
|
||||||
// return_parse_end will contain a pointer to the error so will match
|
|
||||||
// cJSON_GetErrorPtr().
|
|
||||||
//
|
|
||||||
//go:linkname ParseWithLengthOpts C.cJSON_ParseWithLengthOpts
|
|
||||||
func ParseWithLengthOpts(value *c.Char, buffer_length uintptr, return_parse_end **c.Char, require_null_terminated Bool) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
|
||||||
// Render a JSON entity to text for transfer/storage.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).Print C.cJSON_Print
|
|
||||||
func (o *JSON) Print() *c.Char { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
|
||||||
// Render a JSON entity to text for transfer/storage without any formatting.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).PrintUnformatted C.cJSON_PrintUnformatted
|
|
||||||
func (o *JSON) PrintUnformatted() *c.Char { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_Bool fmt);
|
|
||||||
//
|
|
||||||
// Render a JSON entity to text using a buffered strategy.
|
|
||||||
// prebuffer is a guess at the final size. guessing well reduces reallocation.
|
|
||||||
// fmt=0 gives unformatted, =1 gives formatted.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).PrintBuffered C.cJSON_PrintBuffered
|
|
||||||
func (o *JSON) PrintBuffered(prebuffer c.Int, fmt Bool) *c.Char { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_Bool format);
|
|
||||||
//
|
|
||||||
// Render a cJSON entity to text using a buffer already allocated in memory with given
|
|
||||||
// length. Returns 1 on success and 0 on failure.
|
|
||||||
// note that cJSON is not always 100% accurate in estimating how much memory it will use,
|
|
||||||
// so to be safe allocate 5 bytes more than you actually need
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).PrintPreallocated C.cJSON_PrintPreallocated
|
|
||||||
func (o *JSON) PrintPreallocated(buffer *c.Char, length c.Int, format Bool) Bool {
|
|
||||||
return Bool(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
|
||||||
// Delete a JSON entity and all subentities.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).Delete C.cJSON_Delete
|
|
||||||
func (o *JSON) Delete() {}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
|
||||||
//
|
|
||||||
// Returns the number of items in an array (or object).
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).GetArraySize C.cJSON_GetArraySize
|
|
||||||
func (o *JSON) GetArraySize() c.Int { return 0 }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
|
||||||
//
|
|
||||||
// Retrieve item number "index" from array "array". Returns NULL if unsuccessful.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).GetArrayItem C.cJSON_GetArrayItem
|
|
||||||
func (o *JSON) GetArrayItem(index c.Int) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
|
||||||
//
|
|
||||||
// Get item "string" from object. Case insensitive.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).GetObjectItem C.cJSON_GetObjectItem
|
|
||||||
func (o *JSON) GetObjectItem(s *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
|
||||||
//
|
|
||||||
// Get item "string" from object. Case sensitive.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).GetObjectItemCaseSensitive C.cJSON_GetObjectItemCaseSensitive
|
|
||||||
func (o *JSON) GetObjectItemCaseSensitive(key *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).HasObjectItem C.cJSON_HasObjectItem
|
|
||||||
func (o *JSON) HasObjectItem(s *c.Char) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
|
||||||
//
|
|
||||||
// For analysing failed parses. This returns a pointer to the parse error.
|
|
||||||
// You'll probably need to look a few chars back to make sense of it.
|
|
||||||
// Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds.
|
|
||||||
//
|
|
||||||
//go:linkname GetErrorPtr C.cJSON_GetErrorPtr
|
|
||||||
func GetErrorPtr() *c.Char
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// Check item type and return its value
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).GetStringValue C.cJSON_GetStringValue
|
|
||||||
func (o *JSON) GetStringValue() *c.Char { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// Check item type and return its value
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).GetNumberValue C.cJSON_GetNumberValue
|
|
||||||
func (o *JSON) GetNumberValue() c.Double { return 0 }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsInvalid(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsInvalid C.cJSON_IsInvalid
|
|
||||||
func (o *JSON) IsInvalid() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsFalse(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsFalse C.cJSON_IsFalse
|
|
||||||
func (o *JSON) IsFalse() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsTrue(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsTrue C.cJSON_IsTrue
|
|
||||||
func (o *JSON) IsTrue() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsBool(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsBool C.cJSON_IsBool
|
|
||||||
func (o *JSON) IsBool() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsNull(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsNull C.cJSON_IsNull
|
|
||||||
func (o *JSON) IsNull() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsNumber(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsNumber C.cJSON_IsNumber
|
|
||||||
func (o *JSON) IsNumber() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsString(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsString C.cJSON_IsString
|
|
||||||
func (o *JSON) IsString() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsArray(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsArray C.cJSON_IsArray
|
|
||||||
func (o *JSON) IsArray() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsObject(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsObject C.cJSON_IsObject
|
|
||||||
func (o *JSON) IsObject() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsRaw(const cJSON * const item);
|
|
||||||
//
|
|
||||||
// These functions check the type of an item
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).IsRaw C.cJSON_IsRaw
|
|
||||||
func (o *JSON) IsRaw() Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
|
||||||
//
|
|
||||||
// These calls create a cJSON item of the appropriate type.
|
|
||||||
//
|
|
||||||
//go:linkname Null C.cJSON_CreateNull
|
|
||||||
func Null() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
|
||||||
//
|
|
||||||
// same as Null func
|
|
||||||
//
|
|
||||||
//go:linkname CreateNull C.cJSON_CreateNull
|
|
||||||
func CreateNull() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
|
||||||
//
|
|
||||||
//go:linkname True C.cJSON_CreateTrue
|
|
||||||
func True() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
|
||||||
//
|
|
||||||
// same as True func
|
|
||||||
//
|
|
||||||
//go:linkname CreateTrue C.cJSON_CreateTrue
|
|
||||||
func CreateTrue() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
|
||||||
//
|
|
||||||
//go:linkname False C.cJSON_CreateFalse
|
|
||||||
func False() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
|
||||||
//
|
|
||||||
// same as False func
|
|
||||||
//
|
|
||||||
//go:linkname CreateFalse C.cJSON_CreateFalse
|
|
||||||
func CreateFalse() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_Bool boolean);
|
|
||||||
//
|
|
||||||
// same as Bool func
|
|
||||||
//
|
|
||||||
//go:linkname CreateBool C.cJSON_CreateBool
|
|
||||||
func CreateBool(boolean c.Int) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
|
||||||
//
|
|
||||||
//go:linkname Number C.cJSON_CreateNumber
|
|
||||||
func Number(num float64) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
|
||||||
//
|
|
||||||
// same as Number func
|
|
||||||
//
|
|
||||||
//go:linkname CreateNumber C.cJSON_CreateNumber
|
|
||||||
func CreateNumber(num float64) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
|
||||||
//
|
|
||||||
//go:linkname String C.cJSON_CreateString
|
|
||||||
func String(str *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
|
||||||
//
|
|
||||||
// same as String func
|
|
||||||
//
|
|
||||||
//go:linkname CreateString C.cJSON_CreateString
|
|
||||||
func CreateString(str *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
|
||||||
// raw json
|
|
||||||
//
|
|
||||||
//go:linkname Raw C.cJSON_CreateRaw
|
|
||||||
func Raw(raw *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
|
||||||
//
|
|
||||||
// same as Raw func
|
|
||||||
//
|
|
||||||
//go:linkname CreateRaw C.cJSON_CreateRaw
|
|
||||||
func CreateRaw(raw *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
|
||||||
//
|
|
||||||
//go:linkname Array C.cJSON_CreateArray
|
|
||||||
func Array() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
|
||||||
//
|
|
||||||
// same as Array func
|
|
||||||
//
|
|
||||||
//go:linkname CreateArray C.cJSON_CreateArray
|
|
||||||
func CreateArray() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
|
||||||
//
|
|
||||||
//go:linkname Object C.cJSON_CreateObject
|
|
||||||
func Object() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
|
||||||
//
|
|
||||||
// same as Object func
|
|
||||||
//
|
|
||||||
//go:linkname CreateObject C.cJSON_CreateObject
|
|
||||||
func CreateObject() *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
|
||||||
//
|
|
||||||
// Create a string where valuestring references a string so
|
|
||||||
// it will not be freed by Delete
|
|
||||||
//
|
|
||||||
//go:linkname StringRef C.cJSON_CreateStringReference
|
|
||||||
func StringRef(str *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
|
||||||
//
|
|
||||||
// same as StringRef func
|
|
||||||
//
|
|
||||||
//go:linkname CreateStringReference C.cJSON_CreateStringReference
|
|
||||||
func CreateStringReference(str *c.Char) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
|
||||||
//
|
|
||||||
// Create an object that only references it's elements so
|
|
||||||
// they will not be freed by Delete
|
|
||||||
//
|
|
||||||
//go:linkname ObjectRef C.cJSON_CreateObjectReference
|
|
||||||
func ObjectRef(child *JSON) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
|
||||||
//
|
|
||||||
// same as ObjectRef func
|
|
||||||
//
|
|
||||||
//go:linkname CreateObjectReference C.cJSON_CreateObjectReference
|
|
||||||
func CreateObjectReference(child *JSON) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
|
||||||
//
|
|
||||||
// Create an array that only references it's elements so
|
|
||||||
// they will not be freed by Delete
|
|
||||||
//
|
|
||||||
//go:linkname ArrayRef C.cJSON_CreateArrayReference
|
|
||||||
func ArrayRef(child *JSON) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
|
||||||
//
|
|
||||||
// same as ArrayRef func
|
|
||||||
//
|
|
||||||
//go:linkname CreateArrayReference C.cJSON_CreateArrayReference
|
|
||||||
func CreateArrayReference(child *JSON) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
|
||||||
//
|
|
||||||
//go:linkname CreateIntArray C.cJSON_CreateIntArray
|
|
||||||
func CreateIntArray(numbers *c.Int, count c.Int) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
|
||||||
//
|
|
||||||
//go:linkname CreateFloatArray C.cJSON_CreateFloatArray
|
|
||||||
func CreateFloatArray(numbers *c.Float, count c.Int) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
|
||||||
//
|
|
||||||
//go:linkname CreateDoubleArray C.cJSON_CreateDoubleArray
|
|
||||||
func CreateDoubleArray(numbers *c.Double, count c.Int) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
|
||||||
//
|
|
||||||
//go:linkname CreateStringArray C.cJSON_CreateStringArray
|
|
||||||
func CreateStringArray(strings *c.Char, count c.Int) *JSON
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
|
||||||
//
|
|
||||||
// Append item to the specified array.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddItem C.cJSON_AddItemToArray
|
|
||||||
func (o *JSON) AddItem(item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
|
||||||
//
|
|
||||||
// same as AddItem func
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddItemToArray C.cJSON_AddItemToArray
|
|
||||||
func (o *JSON) AddItemToArray(item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
|
||||||
//
|
|
||||||
// Append item to the specified object.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).SetItem C.cJSON_AddItemToObject
|
|
||||||
func (o *JSON) SetItem(key *c.Char, item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
|
||||||
//
|
|
||||||
// same as SetItem func
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddItemToObject C.cJSON_AddItemToObject
|
|
||||||
func (o *JSON) AddItemToObject(key *c.Char, item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
|
||||||
//
|
|
||||||
// Use this when string is definitely const (i.e. a literal, or as good as),
|
|
||||||
// and will definitely survive the cJSON object.
|
|
||||||
// warning that When this function was used, make sure to always check that
|
|
||||||
// (item->type & cJSON_StringIsConst) is zero before writing to `item->string`
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddItemToObjectCS C.cJSON_AddItemToObjectCS
|
|
||||||
func (o *JSON) AddItemToObjectCS(s *c.Char, item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
|
||||||
//
|
|
||||||
// Append reference to item to the specified array/object.
|
|
||||||
// Use this when you want to add an existing cJSON to a new cJSON,
|
|
||||||
// but don't want to corrupt your existing cJSON.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddItemReferenceToArray C.cJSON_AddItemReferenceToArray
|
|
||||||
func (o *JSON) AddItemReferenceToArray(item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddItemReferenceToObject C.cJSON_AddItemReferenceToObject
|
|
||||||
func (o *JSON) AddItemReferenceToObject(s *c.Char, item *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
|
||||||
//
|
|
||||||
// Remove/Detach items from Arrays/Objects.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DetachItemViaPointer C.cJSON_DetachItemViaPointer
|
|
||||||
func (o *JSON) DetachItemViaPointer(item *JSON) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DetachItemFromArray C.cJSON_DetachItemFromArray
|
|
||||||
func (o *JSON) DetachItemFromArray(which c.Int) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DeleteItemFromArray C.cJSON_DeleteItemFromArray
|
|
||||||
func (o *JSON) DeleteItemFromArray(which c.Int) {}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DetachItemFromObject C.cJSON_DetachItemFromObject
|
|
||||||
func (o *JSON) DetachItemFromObject(s *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DetachItemFromObjectCaseSensitive C.cJSON_DetachItemFromObjectCaseSensitive
|
|
||||||
func (o *JSON) DetachItemFromObjectCaseSensitive(s *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DeleteItemFromObject C.cJSON_DeleteItemFromObject
|
|
||||||
func (o *JSON) DeleteItemFromObject(s *c.Char) {}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).DeleteItemFromObjectCaseSensitive C.cJSON_DeleteItemFromObjectCaseSensitive
|
|
||||||
func (o *JSON) DeleteItemFromObjectCaseSensitive(s *c.Char) {}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem);
|
|
||||||
//
|
|
||||||
// Update array items.
|
|
||||||
// Shifts pre-existing items to the right.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).InsertItemInArray C.cJSON_InsertItemInArray
|
|
||||||
func (o *JSON) InsertItemInArray(which c.Int, newitem *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).ReplaceItemViaPointer C.cJSON_ReplaceItemViaPointer
|
|
||||||
func (o *JSON) ReplaceItemViaPointer(item *JSON, replacement *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).ReplaceItemInArray C.cJSON_ReplaceItemInArray
|
|
||||||
func (o *JSON) ReplaceItemInArray(which c.Int, newitem *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).ReplaceItemInObject C.cJSON_ReplaceItemInObject
|
|
||||||
func (o *JSON) ReplaceItemInObject(s *c.Char, newitem *JSON) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).ReplaceItemInObjectCaseSensitive C.cJSON_ReplaceItemInObjectCaseSensitive
|
|
||||||
func (o *JSON) ReplaceItemInObjectCaseSensitive(s *c.Char, newitem *JSON) Bool {
|
|
||||||
return Bool(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_Bool recurse);
|
|
||||||
//
|
|
||||||
// Duplicate a cJSON item
|
|
||||||
//
|
|
||||||
// Duplicate will create a new, identical cJSON item to the one you pass,
|
|
||||||
// in new memory that will need to be released. With recurse!=0,
|
|
||||||
// it will duplicate any children connected to the item.
|
|
||||||
// The item->next and ->prev pointers are always zero on return from Duplicate.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).Duplicate C.cJSON_Duplicate
|
|
||||||
func (o *JSON) Duplicate(recurse Bool) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_Bool case_sensitive);
|
|
||||||
//
|
|
||||||
// Recursively compare two cJSON items for equality. If either a or b is NULL or invalid,
|
|
||||||
// they will be considered unequal. case_sensitive determines if object keys are treated
|
|
||||||
// case sensitive (1) or case insensitive (0)
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).Compare C.cJSON_Compare
|
|
||||||
func (o *JSON) Compare(b *JSON, case_sensitive Bool) Bool { return Bool(0) }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
|
||||||
//
|
|
||||||
// Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
|
||||||
// The input pointer json cannot point to a read-only address area, such as a string constant,
|
|
||||||
// but should point to a readable and writable address area.
|
|
||||||
//
|
|
||||||
//go:linkname Minify C.cJSON_Minify
|
|
||||||
func Minify()
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
|
||||||
//
|
|
||||||
// Helper functions for creating and adding items to an object at the same time.
|
|
||||||
// They return the added item or NULL on failure.
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddNullToObject C.cJSON_AddNullToObject
|
|
||||||
func (o *JSON) AddNullToObject(name *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddTrueToObject C.cJSON_AddTrueToObject
|
|
||||||
func (o *JSON) AddTrueToObject(name *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddFalseToObject C.cJSON_AddFalseToObject
|
|
||||||
func (o *JSON) AddFalseToObject(name *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_Bool boolean);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddBoolToObject C.cJSON_AddBoolToObject
|
|
||||||
func (o *JSON) AddBoolToObject(name *c.Char, b Bool) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddNumberToObject C.cJSON_AddNumberToObject
|
|
||||||
func (o *JSON) AddNumberToObject(name *c.Char, num c.Double) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddStringToObject C.cJSON_AddStringToObject
|
|
||||||
func (o *JSON) AddStringToObject(name *c.Char, s *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddRawToObject C.cJSON_AddRawToObject
|
|
||||||
func (o *JSON) AddRawToObject(name *c.Char, raw *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddObjectToObject C.cJSON_AddObjectToObject
|
|
||||||
func (o *JSON) AddObjectToObject(name *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).AddArrayToObject C.cJSON_AddArrayToObject
|
|
||||||
func (o *JSON) AddArrayToObject(name *c.Char) *JSON { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
|
||||||
//
|
|
||||||
// helper for the cJSON_SetNumberValue macro
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).SetNumberHelper C.cJSON_SetNumberHelper
|
|
||||||
func (o *JSON) SetNumberHelper(number c.Double) c.Double { return 0 }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
|
||||||
//
|
|
||||||
// Change the valuestring of a cJSON_String object, only takes effect when type of
|
|
||||||
// object is cJSON_String
|
|
||||||
//
|
|
||||||
// llgo:link (*JSON).SetValuestring C.cJSON_SetValuestring
|
|
||||||
func (o *JSON) SetValuestring(v *c.Char) *c.Char { return nil }
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
|
||||||
//
|
|
||||||
// malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks
|
|
||||||
//
|
|
||||||
//go:linkname Malloc C.cJSON_malloc
|
|
||||||
func Malloc(size uintptr)
|
|
||||||
|
|
||||||
// CJSON_PUBLIC(void) cJSON_free(void *object);
|
|
||||||
//
|
|
||||||
//go:linkname Free C.cJSON_free
|
|
||||||
func Free(ptr unsafe.Pointer)
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
"github.com/goplus/llgo/compiler/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
_, unit, err := clangutils.CreateTranslationUnit(&clangutils.Config{
|
|
||||||
File: "#include <stddef.h>",
|
|
||||||
Temp: true,
|
|
||||||
IsCpp: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
println(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clang.GetInclusions(unit, func(included_file clang.File, inclusion_stack *clang.SourceLocation, include_len c.Uint, client_data c.Pointer) {
|
|
||||||
filename := included_file.FileName()
|
|
||||||
c.Printf(c.Str("Included file: %s Include length: %d\n"), filename.CStr(), include_len)
|
|
||||||
inclusions := unsafe.Slice(inclusion_stack, include_len)
|
|
||||||
for i := range inclusions {
|
|
||||||
loc := inclusions[i]
|
|
||||||
var file clang.File
|
|
||||||
var line, column c.Uint
|
|
||||||
loc.SpellingLocation(&file, &line, &column, nil)
|
|
||||||
filename = file.FileName()
|
|
||||||
c.Printf(c.Str(" included from: %s:%d:%d\n"), filename.CStr(), line, column)
|
|
||||||
}
|
|
||||||
}, nil)
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Context struct {
|
|
||||||
namespaceName string
|
|
||||||
className string
|
|
||||||
unit *clang.TranslationUnit
|
|
||||||
}
|
|
||||||
|
|
||||||
func newContext() *Context {
|
|
||||||
return &Context{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) setNamespaceName(name string) {
|
|
||||||
c.namespaceName = name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) setClassName(name string) {
|
|
||||||
c.className = name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) setUnit(unit *clang.TranslationUnit) {
|
|
||||||
c.unit = unit
|
|
||||||
}
|
|
||||||
|
|
||||||
var context = newContext()
|
|
||||||
|
|
||||||
func printCursorLocation(cursor clang.Cursor) {
|
|
||||||
loc := cursor.Location()
|
|
||||||
var file clang.File
|
|
||||||
var line, column c.Uint
|
|
||||||
|
|
||||||
loc.SpellingLocation(&file, &line, &column, nil)
|
|
||||||
filename := file.FileName()
|
|
||||||
defer filename.Dispose()
|
|
||||||
|
|
||||||
c.Printf(c.Str("%s:%d:%d\n"), filename.CStr(), line, column)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printMarcoInfo(cursor clang.Cursor) {
|
|
||||||
printCursorLocation(cursor)
|
|
||||||
name := cursor.String()
|
|
||||||
c.Printf(c.Str("Marco Name: %s\n"), name.CStr())
|
|
||||||
ran := cursor.Extent()
|
|
||||||
var numTokens c.Uint
|
|
||||||
var tokens *clang.Token
|
|
||||||
context.unit.Tokenize(ran, &tokens, &numTokens)
|
|
||||||
c.Printf(c.Str("Content: "))
|
|
||||||
|
|
||||||
tokensSlice := unsafe.Slice(tokens, int(numTokens))
|
|
||||||
for _, tok := range tokensSlice {
|
|
||||||
tokStr := context.unit.Token(tok)
|
|
||||||
c.Printf(c.Str("%s "), tokStr.CStr())
|
|
||||||
tokStr.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Printf(c.Str("\n"))
|
|
||||||
println("--------------------------------")
|
|
||||||
}
|
|
||||||
func printFuncInfo(cursor clang.Cursor) {
|
|
||||||
printCursorLocation(cursor)
|
|
||||||
|
|
||||||
cursorStr := cursor.String()
|
|
||||||
symbol := cursor.Mangling()
|
|
||||||
defer symbol.Dispose()
|
|
||||||
defer cursorStr.Dispose()
|
|
||||||
|
|
||||||
if context.namespaceName != "" && context.className != "" {
|
|
||||||
fmt.Printf("%s:%s:", context.namespaceName, context.className)
|
|
||||||
} else if context.namespaceName != "" {
|
|
||||||
fmt.Printf("%s:", context.namespaceName)
|
|
||||||
}
|
|
||||||
c.Printf(c.Str("%s\n"), cursorStr.CStr())
|
|
||||||
|
|
||||||
if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl {
|
|
||||||
c.Printf(c.Str("symbol:%s\n"), symbol.CStr())
|
|
||||||
|
|
||||||
typeStr := cursor.ResultType().String()
|
|
||||||
defer typeStr.Dispose()
|
|
||||||
c.Printf(c.Str("Return Type: %s\n"), typeStr.CStr())
|
|
||||||
c.Printf(c.Str("Parameters(%d): ( "), cursor.NumArguments())
|
|
||||||
|
|
||||||
for i := 0; i < int(cursor.NumArguments()); i++ {
|
|
||||||
argCurSor := cursor.Argument(c.Uint(i))
|
|
||||||
argType := argCurSor.Type().String()
|
|
||||||
argName := argCurSor.String()
|
|
||||||
c.Printf(c.Str("%s %s"), argType.CStr(), argName.CStr())
|
|
||||||
if i < int(cursor.NumArguments())-1 {
|
|
||||||
c.Printf(c.Str(", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
argType.Dispose()
|
|
||||||
argName.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Printf(c.Str(" )\n"))
|
|
||||||
println("--------------------------------")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
|
||||||
if cursor.Kind == clang.CursorMacroDefinition {
|
|
||||||
printMarcoInfo(cursor)
|
|
||||||
} else if cursor.Kind == clang.CursorNamespace {
|
|
||||||
nameStr := cursor.String()
|
|
||||||
context.setNamespaceName(c.GoString(nameStr.CStr()))
|
|
||||||
clang.VisitChildren(cursor, visit, nil)
|
|
||||||
context.setNamespaceName("")
|
|
||||||
} else if cursor.Kind == clang.CursorClassDecl {
|
|
||||||
nameStr := cursor.String()
|
|
||||||
context.setClassName(c.GoString(nameStr.CStr()))
|
|
||||||
clang.VisitChildren(cursor, visit, nil)
|
|
||||||
context.setClassName("")
|
|
||||||
} else if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl {
|
|
||||||
printFuncInfo(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(filename *c.Char) {
|
|
||||||
index := clang.CreateIndex(0, 0)
|
|
||||||
args := make([]*c.Char, 3)
|
|
||||||
args[0] = c.Str("-x")
|
|
||||||
args[1] = c.Str("c++")
|
|
||||||
args[2] = c.Str("-std=c++11")
|
|
||||||
unit := index.ParseTranslationUnit(
|
|
||||||
filename,
|
|
||||||
unsafe.SliceData(args), 3,
|
|
||||||
nil, 0,
|
|
||||||
clang.DetailedPreprocessingRecord,
|
|
||||||
)
|
|
||||||
|
|
||||||
if unit == nil {
|
|
||||||
println("Unable to parse translation unit. Quitting.")
|
|
||||||
c.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
context.setUnit(unit)
|
|
||||||
cursor := unit.Cursor()
|
|
||||||
|
|
||||||
clang.VisitChildren(cursor, visit, nil)
|
|
||||||
unit.Dispose()
|
|
||||||
index.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if c.Argc != 2 {
|
|
||||||
fmt.Fprintln(os.Stderr, "Usage: <C++ header file>\n")
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
sourceFile := *c.Advance(c.Argv, 1)
|
|
||||||
parse(sourceFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
#include <clang-c/Index.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
typedef enum CXChildVisitResult (*wrap_CXCursorVisitor)(CXCursor *cursor, CXCursor *parent, CXClientData client_data);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
CXClientData data;
|
|
||||||
wrap_CXCursorVisitor visitor;
|
|
||||||
} wrap_data;
|
|
||||||
|
|
||||||
CXChildVisitResult wrap_visitor(CXCursor cursor, CXCursor parent, CXClientData data) {
|
|
||||||
wrap_data *d = (wrap_data *)(data);
|
|
||||||
return d->visitor(&cursor, &parent, d->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
void wrap_clang_getLocation(CXTranslationUnit tu, CXFile file, unsigned line, unsigned column, CXSourceLocation *loc) {
|
|
||||||
*loc = clang_getLocation(tu, file, line, column);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_getLocationForOffset(CXTranslationUnit tu, CXFile file, unsigned offset, CXSourceLocation *loc) {
|
|
||||||
*loc = clang_getLocationForOffset(tu, file, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_getTranslationUnitCursor(CXTranslationUnit uint, CXCursor *cur) {
|
|
||||||
*cur = clang_getTranslationUnitCursor(uint);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_equalCursors(CXCursor *cursor1, CXCursor *cursor2) {
|
|
||||||
return clang_equalCursors(*cursor1, *cursor2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int wrap_clang_Cursor_isNull(CXCursor *cursor) { return clang_Cursor_isNull(*cursor); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorSemanticParent(CXCursor *C, CXCursor *parent) { *parent = clang_getCursorSemanticParent(*C); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorDefinition(CXCursor *C, CXCursor *def) { *def = clang_getCursorDefinition(*C); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorLexicalParent(CXCursor *C, CXCursor *parent) { *parent = clang_getCursorLexicalParent(*C); }
|
|
||||||
|
|
||||||
void wrap_clang_getOverriddenCursors(CXCursor *cursor, CXCursor **overridden, unsigned *num_overridden) {
|
|
||||||
clang_getOverriddenCursors(*cursor, overridden, num_overridden);
|
|
||||||
}
|
|
||||||
|
|
||||||
CXFile wrap_clang_getIncludedFile(CXCursor *cursor) { return clang_getIncludedFile(*cursor); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursor(CXTranslationUnit uint, CXSourceLocation *loc, CXCursor *cur) {
|
|
||||||
*cur = clang_getCursor(uint, *loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_getCursorLocation(CXCursor *cur, CXSourceLocation *loc) { *loc = clang_getCursorLocation(*cur); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorType(*cur); }
|
|
||||||
|
|
||||||
CXString wrap_clang_getTypeSpelling(CXType *typ) { return clang_getTypeSpelling(*typ); }
|
|
||||||
|
|
||||||
void wrap_clang_getTypedefDeclUnderlyingType(CXCursor *cur, CXType *typ) {
|
|
||||||
*typ = clang_getTypedefDeclUnderlyingType(*cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
long long wrap_clang_getEnumConstantDeclValue(CXCursor *cur) { return clang_getEnumConstantDeclValue(*cur); }
|
|
||||||
|
|
||||||
int wrap_clang_Cursor_getNumArguments(CXCursor *cur) { return clang_Cursor_getNumArguments(*cur); }
|
|
||||||
|
|
||||||
void wrap_clang_Cursor_getArgument(CXCursor *C, unsigned i, CXCursor *argCur) {
|
|
||||||
*argCur = clang_Cursor_getArgument(*C, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_getCanonicalType(CXType *typ, CXType *canonicalType) { *canonicalType = clang_getCanonicalType(*typ); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_isConstQualifiedType(CXType *typ) { return clang_isConstQualifiedType(*typ); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_Cursor_isMacroFunctionLike(CXCursor *cur) { return clang_Cursor_isMacroFunctionLike(*cur); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_Cursor_isMacroBuiltin(CXCursor *cur) { return clang_Cursor_isMacroBuiltin(*cur); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_Cursor_isFunctionInlined(CXCursor *cur) { return clang_Cursor_isFunctionInlined(*cur); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_isVolatileQualifiedType(CXType *T) { return clang_isVolatileQualifiedType(*T); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_isRestrictQualifiedType(CXType *T) { return clang_isRestrictQualifiedType(*T); }
|
|
||||||
|
|
||||||
void wrap_clang_getPointeeType(CXType *pointerTyp, CXType *pointeeTyp) {
|
|
||||||
*pointeeTyp = clang_getPointeeType(*pointerTyp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_getNonReferenceType(CXType *typ, CXType *nonRefTyp) { *nonRefTyp = clang_getNonReferenceType(*typ); }
|
|
||||||
|
|
||||||
void wrap_clang_getTypeDeclaration(CXType *typ, CXCursor *cur) { *cur = clang_getTypeDeclaration(*typ); }
|
|
||||||
|
|
||||||
void wrap_clang_getResultType(CXType *typ, CXType *resultTyp) { *resultTyp = clang_getResultType(*typ); }
|
|
||||||
|
|
||||||
int wrap_clang_getNumArgTypes(CXType *typ) { return clang_getNumArgTypes(*typ); }
|
|
||||||
|
|
||||||
void wrap_clang_getArgType(CXType *typ, unsigned i, CXType *argTyp) { *argTyp = clang_getArgType(*typ, i); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_isFunctionTypeVariadic(CXType *typ) { return clang_isFunctionTypeVariadic(*typ); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorResultType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorResultType(*cur); }
|
|
||||||
|
|
||||||
void wrap_clang_getElementType(CXType *Typ, CXType *elemTyp) { *elemTyp = clang_getElementType(*Typ); }
|
|
||||||
|
|
||||||
void wrap_clang_getArrayElementType(CXType *arrayTyp, CXType *elemTyp) {
|
|
||||||
*elemTyp = clang_getArrayElementType(*arrayTyp);
|
|
||||||
}
|
|
||||||
|
|
||||||
long long wrap_clang_getArraySize(CXType *arrayTyp) { return clang_getArraySize(*arrayTyp); }
|
|
||||||
|
|
||||||
void wrap_clang_Type_getNamedType(CXType *typ, CXType *namedTyp) { *namedTyp = clang_Type_getNamedType(*typ); }
|
|
||||||
|
|
||||||
long long wrap_clang_Type_getSizeOf(CXType *typ) { return clang_Type_getSizeOf(*typ); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_Cursor_isAnonymous(CXCursor *cursor) { return clang_Cursor_isAnonymous(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_Cursor_isAnonymousRecordDecl(CXCursor *cursor) {
|
|
||||||
return clang_Cursor_isAnonymousRecordDecl(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CX_CXXAccessSpecifier wrap_clang_getCXXAccessSpecifier(CXCursor *cursor) {
|
|
||||||
return clang_getCXXAccessSpecifier(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CX_StorageClass wrap_clang_Cursor_getStorageClass(CXCursor *cursor) {
|
|
||||||
return clang_Cursor_getStorageClass(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
CXString wrap_clang_getCursorUSR(CXCursor *cur) { return clang_getCursorUSR(*cur); }
|
|
||||||
|
|
||||||
CXString wrap_clang_getCursorSpelling(CXCursor *cur) { return clang_getCursorSpelling(*cur); }
|
|
||||||
|
|
||||||
CXString wrap_clang_getCursorDisplayName(CXCursor *cur) { return clang_getCursorDisplayName(*cur); }
|
|
||||||
|
|
||||||
void wrap_clang_getCursorReferenced(CXCursor *cur, CXCursor *referenced) {
|
|
||||||
*referenced = clang_getCursorReferenced(*cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_Cursor_isVariadic(CXCursor *cur) { return clang_Cursor_isVariadic(*cur); }
|
|
||||||
|
|
||||||
void wrap_clang_Cursor_getCommentRange(CXCursor *cur, CXSourceRange *range) {
|
|
||||||
*range = clang_Cursor_getCommentRange(*cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
CXString wrap_clang_Cursor_getRawCommentText(CXCursor *cursor) { return clang_Cursor_getRawCommentText(*cursor); }
|
|
||||||
|
|
||||||
CXString wrap_clang_Cursor_getMangling(CXCursor *cur) { return clang_Cursor_getMangling(*cur); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXConstructor_isConvertingConstructor(CXCursor *cursor) {
|
|
||||||
return clang_CXXConstructor_isConvertingConstructor(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXConstructor_isCopyConstructor(CXCursor *cursor) {
|
|
||||||
return clang_CXXConstructor_isCopyConstructor(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXConstructor_isDefaultConstructor(CXCursor *cursor) {
|
|
||||||
return clang_CXXConstructor_isDefaultConstructor(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXConstructor_isMoveConstructor(CXCursor *cursor) {
|
|
||||||
return clang_CXXConstructor_isMoveConstructor(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXField_isMutable(CXCursor *cursor) { return clang_CXXField_isMutable(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isDefaulted(CXCursor *cursor) { return clang_CXXMethod_isDefaulted(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isDeleted(CXCursor *cursor) { return clang_CXXMethod_isDeleted(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isPureVirtual(CXCursor *cursor) { return clang_CXXMethod_isPureVirtual(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isStatic(CXCursor *cursor) { return clang_CXXMethod_isStatic(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isVirtual(CXCursor *cursor) { return clang_CXXMethod_isVirtual(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isCopyAssignmentOperator(CXCursor *cursor) {
|
|
||||||
return clang_CXXMethod_isCopyAssignmentOperator(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isMoveAssignmentOperator(CXCursor *cursor) {
|
|
||||||
return clang_CXXMethod_isMoveAssignmentOperator(*cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isExplicit(CXCursor *cursor) { return clang_CXXMethod_isExplicit(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXRecord_isAbstract(CXCursor *cursor) { return clang_CXXRecord_isAbstract(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_EnumDecl_isScoped(CXCursor *cursor) { return clang_EnumDecl_isScoped(*cursor); }
|
|
||||||
|
|
||||||
unsigned wrap_clang_CXXMethod_isConst(CXCursor *cursor) { return clang_CXXMethod_isConst(*cursor); }
|
|
||||||
|
|
||||||
CXTokenKind wrap_clang_getTokenKind(CXToken *token) { return clang_getTokenKind(*token); }
|
|
||||||
|
|
||||||
CXString wrap_clang_getTokenSpelling(CXTranslationUnit unit, CXToken *token) {
|
|
||||||
return clang_getTokenSpelling(unit, *token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_tokenize(CXTranslationUnit unit, CXSourceRange *Range, CXToken **Tokens, unsigned *NumTokens) {
|
|
||||||
clang_tokenize(unit, *Range, Tokens, NumTokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wrap_clang_visitChildren(CXCursor *parent, wrap_CXCursorVisitor visitor, CXClientData client_data) {
|
|
||||||
wrap_data data = {client_data, visitor};
|
|
||||||
return clang_visitChildren(*parent, wrap_visitor, CXClientData(&data));
|
|
||||||
}
|
|
||||||
|
|
||||||
int wrap_clang_Location_isInSystemHeader(CXSourceLocation *loc) { return clang_Location_isInSystemHeader(*loc); }
|
|
||||||
|
|
||||||
void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigned *line, unsigned *column,
|
|
||||||
unsigned *offset) {
|
|
||||||
clang_getSpellingLocation(*loc, file, line, column, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_clang_getRangeStart(CXSourceRange *range, CXSourceLocation *loc) { *loc = clang_getRangeStart(*range); }
|
|
||||||
|
|
||||||
void wrap_clang_getRangeEnd(CXSourceRange *range, CXSourceLocation *loc) { *loc = clang_getRangeEnd(*range); }
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <clang-c/Index.h>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
printf("sizeof(clang.Cursor) = %lu\n", sizeof(CXCursor));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoCFlags = "-I$(llvm-config --includedir)"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
c.Printf(c.Str("sizeof(clang.Cursor) = %lu\n"), unsafe.Sizeof(clang.Cursor{}))
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package clang
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A character string.
|
|
||||||
*
|
|
||||||
* The \c CXString type is used to return strings from the interface when
|
|
||||||
* the ownership of that string might differ from one call to the next.
|
|
||||||
* Use \c clang_getCString() to retrieve the string data and, once finished
|
|
||||||
* with the string data, call \c clang_disposeString() to free the string.
|
|
||||||
*/
|
|
||||||
type String struct {
|
|
||||||
Data c.Pointer
|
|
||||||
PrivateFlags c.Uint
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the character data associated with the given string.
|
|
||||||
*/
|
|
||||||
// llgo:link String.CStr C.clang_getCString
|
|
||||||
func (String) CStr() *c.Char { return nil }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free the given string.
|
|
||||||
*/
|
|
||||||
// llgo:link String.Dispose C.clang_disposeString
|
|
||||||
func (String) Dispose() {}
|
|
||||||
|
|
||||||
type StringSet struct {
|
|
||||||
Strings *String
|
|
||||||
Count c.Uint
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free the given string set.
|
|
||||||
*/
|
|
||||||
// llgo:link (*StringSet).Dispose C.clang_disposeStringSet
|
|
||||||
func (*StringSet) Dispose() {}
|
|
||||||
|
|
||||||
func GoString(clangStr String) (str string) {
|
|
||||||
defer clangStr.Dispose()
|
|
||||||
cstr := clangStr.CStr()
|
|
||||||
if cstr != nil {
|
|
||||||
str = c.GoString(cstr)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
2906
c/clang/clang.go
2906
c/clang/clang.go
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
type T struct {
|
|
||||||
n int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Demo() {
|
|
||||||
println(t.n)
|
|
||||||
addr := debug.Address()
|
|
||||||
c.Printf(c.Str("addr:0x%x\n"), addr)
|
|
||||||
var info debug.Info
|
|
||||||
r := debug.Addrinfo(addr, &info)
|
|
||||||
if r == 0 {
|
|
||||||
panic("not found info")
|
|
||||||
}
|
|
||||||
c.Printf(c.Str("func file:%s name:%s base:0x%x addr:0x%x\n"), info.Fname, info.Sname, info.Fbase, info.Saddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
t := &T{100}
|
|
||||||
t.Demo()
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
type T struct {
|
|
||||||
n int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Demo() {
|
|
||||||
println(t.n)
|
|
||||||
debug.StackTrace(0, func(fr *debug.Frame) bool {
|
|
||||||
var info debug.Info
|
|
||||||
debug.Addrinfo(unsafe.Pointer(fr.PC), &info)
|
|
||||||
println("[", fr.PC, "]", fr.Name, "+", fr.Offset, ", SP =", fr.SP)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
t := &T{100}
|
|
||||||
t.Demo()
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#if defined(__linux__)
|
|
||||||
#define UNW_LOCAL_ONLY
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <features.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <libunwind.h>
|
|
||||||
|
|
||||||
void *llgo_address() {
|
|
||||||
return __builtin_return_address(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int llgo_addrinfo(void *addr, Dl_info *info) {
|
|
||||||
return dladdr(addr, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void llgo_stacktrace(int skip, void *ctx, int (*fn)(void *ctx, void *pc, void *offset, void *sp, char *name)) {
|
|
||||||
unw_cursor_t cursor;
|
|
||||||
unw_context_t context;
|
|
||||||
unw_word_t offset, pc, sp;
|
|
||||||
char fname[256];
|
|
||||||
unw_getcontext(&context);
|
|
||||||
unw_init_local(&cursor, &context);
|
|
||||||
int depth = 0;
|
|
||||||
while (unw_step(&cursor) > 0) {
|
|
||||||
if (depth < skip) {
|
|
||||||
depth++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (unw_get_reg(&cursor, UNW_REG_IP, &pc) == 0) {
|
|
||||||
unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
|
|
||||||
unw_get_reg(&cursor, UNW_REG_SP, &sp);
|
|
||||||
if (fn(ctx, (void*)pc, (void*)offset, (void*)sp, fname) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package debug
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo linux LDFLAGS: -lunwind
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "link"
|
|
||||||
LLGoFiles = "_wrap/debug.c"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Info struct {
|
|
||||||
Fname *c.Char
|
|
||||||
Fbase c.Pointer
|
|
||||||
Sname *c.Char
|
|
||||||
Saddr c.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname Address C.llgo_address
|
|
||||||
func Address() unsafe.Pointer
|
|
||||||
|
|
||||||
//go:linkname Addrinfo C.llgo_addrinfo
|
|
||||||
func Addrinfo(addr unsafe.Pointer, info *Info) c.Int
|
|
||||||
|
|
||||||
//go:linkname stacktrace C.llgo_stacktrace
|
|
||||||
func stacktrace(skip c.Int, ctx unsafe.Pointer, fn func(ctx, pc, offset, sp unsafe.Pointer, name *c.Char) c.Int)
|
|
||||||
|
|
||||||
type Frame struct {
|
|
||||||
PC uintptr
|
|
||||||
Offset uintptr
|
|
||||||
SP unsafe.Pointer
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func StackTrace(skip int, fn func(fr *Frame) bool) {
|
|
||||||
stacktrace(c.Int(1+skip), unsafe.Pointer(&fn), func(ctx, pc, offset, sp unsafe.Pointer, name *c.Char) c.Int {
|
|
||||||
fn := *(*func(fr *Frame) bool)(ctx)
|
|
||||||
if !fn(&Frame{uintptr(pc), uintptr(offset), sp, c.GoString(name)}) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
struct array
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int z;
|
|
||||||
int k;
|
|
||||||
};
|
|
||||||
|
|
||||||
int demo1(struct array a)
|
|
||||||
{
|
|
||||||
printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k);
|
|
||||||
return a.x+a.y+a.z+a.k;
|
|
||||||
}
|
|
||||||
|
|
||||||
int demo2( int (*fn)(struct array)) {
|
|
||||||
printf("c.demo2: %p\n",fn);
|
|
||||||
struct array a;
|
|
||||||
a.x = 1;
|
|
||||||
a.y = 2;
|
|
||||||
a.z = 3;
|
|
||||||
a.k = 4;
|
|
||||||
return (*fn)(a);
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/ffi"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "link"
|
|
||||||
LLGoFiles = "../_wrap/wrap.c"
|
|
||||||
)
|
|
||||||
|
|
||||||
//llgo:type C
|
|
||||||
type Callback func(array) c.Int
|
|
||||||
|
|
||||||
//go:linkname demo1 C.demo1
|
|
||||||
func demo1(array) c.Int
|
|
||||||
|
|
||||||
//go:linkname demo2 C.demo2
|
|
||||||
func demo2(fn Callback) c.Int
|
|
||||||
|
|
||||||
//llgo:type C
|
|
||||||
type array struct {
|
|
||||||
x c.Int
|
|
||||||
y c.Int
|
|
||||||
z c.Int
|
|
||||||
k c.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
|
||||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cdemo1()
|
|
||||||
cdemo2()
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdemo1() {
|
|
||||||
var cif ffi.Cif
|
|
||||||
tarray := &ffi.Type{0, 0, ffi.Struct, &[]*ffi.Type{typeInt32, typeInt32, typeInt32, typeInt32, nil}[0]}
|
|
||||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{tarray}[0])
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
ar := array{1, 2, 3, 4}
|
|
||||||
var ret int32
|
|
||||||
ffi.Call(&cif, c.Func(demo1), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&ar)}[0])
|
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdemo2() {
|
|
||||||
var cif ffi.Cif
|
|
||||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
var ret int32
|
|
||||||
fn := c.Func(demo1)
|
|
||||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fn)}[0])
|
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/ffi"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "link"
|
|
||||||
LLGoFiles = "../_wrap/wrap.c"
|
|
||||||
)
|
|
||||||
|
|
||||||
//llgo:type C
|
|
||||||
type Callback func(array) c.Int
|
|
||||||
|
|
||||||
//go:linkname demo1 C.demo1
|
|
||||||
func demo1(array) c.Int
|
|
||||||
|
|
||||||
//go:linkname demo2 C.demo2
|
|
||||||
func demo2(fn Callback) c.Int
|
|
||||||
|
|
||||||
//llgo:type C
|
|
||||||
type array struct {
|
|
||||||
x c.Int
|
|
||||||
y c.Int
|
|
||||||
z c.Int
|
|
||||||
k c.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func demo(a array) c.Int {
|
|
||||||
c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k)
|
|
||||||
return a.x + a.y + a.z + a.k
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
|
||||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
gofn()
|
|
||||||
c.Printf(c.Str("\n"))
|
|
||||||
goclosure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func gofn() {
|
|
||||||
var cif ffi.Cif
|
|
||||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
var fncode unsafe.Pointer
|
|
||||||
closure := ffi.ClosureAlloc(&fncode)
|
|
||||||
defer ffi.ClosureFree(closure)
|
|
||||||
status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
|
||||||
ar := *(*array)(ffi.Index(args, 0))
|
|
||||||
*(*c.Int)(ret) = demo(ar)
|
|
||||||
}, nil, fncode)
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
var ret int32
|
|
||||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
func goclosure() {
|
|
||||||
var cif ffi.Cif
|
|
||||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
fn := func(ar array) c.Int {
|
|
||||||
c.Printf(c.Str("call closure %d\n"), cif.NArgs)
|
|
||||||
return demo(ar)
|
|
||||||
}
|
|
||||||
var fncode unsafe.Pointer
|
|
||||||
closure := ffi.ClosureAlloc(&fncode)
|
|
||||||
defer ffi.ClosureFree(closure)
|
|
||||||
status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
|
||||||
ar := *(*array)(ffi.Index(args, 0))
|
|
||||||
fn := *(*func(array) c.Int)(userdata)
|
|
||||||
*(*c.Int)(ret) = fn(ar)
|
|
||||||
}, unsafe.Pointer(&fn), fncode)
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
var ret int32
|
|
||||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/ffi"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
|
||||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var cif ffi.Cif
|
|
||||||
status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, 1, 2, typeInt32, &[]*ffi.Type{typePointer, typeInt32}[0])
|
|
||||||
if status != ffi.OK {
|
|
||||||
panic(status)
|
|
||||||
}
|
|
||||||
var ret int32
|
|
||||||
text := c.Str("hello world: %d\n")
|
|
||||||
var n int32 = 100
|
|
||||||
ffi.Call(&cif, c.Func(c.Printf), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&text), unsafe.Pointer(&n)}[0])
|
|
||||||
c.Printf(c.Str("ret: %d\n"), ret)
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#include <ffi.h>
|
|
||||||
|
|
||||||
void *llog_ffi_closure_alloc(void **code) {
|
|
||||||
return ffi_closure_alloc(sizeof(ffi_closure), code);
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64))
|
|
||||||
|
|
||||||
package ffi
|
|
||||||
|
|
||||||
const (
|
|
||||||
DefaultAbi = 1
|
|
||||||
)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
//go:build freebsd || linux || darwin
|
|
||||||
|
|
||||||
package ffi
|
|
||||||
|
|
||||||
const (
|
|
||||||
DefaultAbi = 2
|
|
||||||
)
|
|
||||||
132
c/ffi/ffi.go
132
c/ffi/ffi.go
@@ -1,132 +0,0 @@
|
|||||||
package ffi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
|
||||||
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Void = iota
|
|
||||||
Int
|
|
||||||
Float
|
|
||||||
Double
|
|
||||||
LongDouble
|
|
||||||
Uint8
|
|
||||||
Sint8
|
|
||||||
Uint16
|
|
||||||
Sint16
|
|
||||||
Uint32
|
|
||||||
Sint32
|
|
||||||
Uint64
|
|
||||||
Sint64
|
|
||||||
Struct
|
|
||||||
Pointer
|
|
||||||
Complex
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
OK = iota
|
|
||||||
BAD_TYPEDEF
|
|
||||||
BAD_ABI
|
|
||||||
BAD_ARGTYPE
|
|
||||||
)
|
|
||||||
|
|
||||||
type Type struct {
|
|
||||||
Size uintptr
|
|
||||||
Alignment uint16
|
|
||||||
Type uint16
|
|
||||||
Elements **Type
|
|
||||||
}
|
|
||||||
|
|
||||||
/*typedef struct {
|
|
||||||
ffi_abi abi;
|
|
||||||
unsigned nargs;
|
|
||||||
ffi_type **arg_types;
|
|
||||||
ffi_type *rtype;
|
|
||||||
unsigned bytes;
|
|
||||||
unsigned flags;
|
|
||||||
#ifdef FFI_EXTRA_CIF_FIELDS
|
|
||||||
FFI_EXTRA_CIF_FIELDS;
|
|
||||||
#endif
|
|
||||||
} ffi_cif;
|
|
||||||
*/
|
|
||||||
|
|
||||||
type Cif struct {
|
|
||||||
Abi c.Uint
|
|
||||||
NArgs c.Uint
|
|
||||||
ArgTypes **Type
|
|
||||||
RType *Type
|
|
||||||
Bytes c.Uint
|
|
||||||
Flags c.Uint
|
|
||||||
//Extra c.Uint
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_cif(ffi_cif *cif,
|
|
||||||
ffi_abi abi,
|
|
||||||
unsigned int nargs,
|
|
||||||
ffi_type *rtype,
|
|
||||||
ffi_type **atypes);
|
|
||||||
*/
|
|
||||||
//go:linkname PrepCif C.ffi_prep_cif
|
|
||||||
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
|
||||||
|
|
||||||
/*
|
|
||||||
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
|
||||||
ffi_abi abi,
|
|
||||||
unsigned int nfixedargs,
|
|
||||||
unsigned int ntotalargs,
|
|
||||||
ffi_type *rtype,
|
|
||||||
ffi_type **atypes);
|
|
||||||
*/
|
|
||||||
//go:linkname PrepCifVar C.ffi_prep_cif_var
|
|
||||||
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint
|
|
||||||
|
|
||||||
/*
|
|
||||||
void ffi_call(ffi_cif *cif,
|
|
||||||
void (*fn)(void),
|
|
||||||
void *rvalue,
|
|
||||||
void **avalue);
|
|
||||||
*/
|
|
||||||
//go:linkname Call C.ffi_call
|
|
||||||
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer)
|
|
||||||
|
|
||||||
// void *ffi_closure_alloc (size_t size, void **code);
|
|
||||||
//
|
|
||||||
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
|
||||||
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
|
||||||
|
|
||||||
// void ffi_closure_free (void *);
|
|
||||||
//
|
|
||||||
//go:linkname ClosureFree C.ffi_closure_free
|
|
||||||
func ClosureFree(unsafe.Pointer)
|
|
||||||
|
|
||||||
/*
|
|
||||||
ffi_status
|
|
||||||
ffi_prep_closure_loc (ffi_closure*,
|
|
||||||
ffi_cif *,
|
|
||||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
|
||||||
void *user_data,
|
|
||||||
void *codeloc);
|
|
||||||
*/
|
|
||||||
|
|
||||||
//llgo:type C
|
|
||||||
type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer)
|
|
||||||
|
|
||||||
//go:linkname PreClosureLoc C.ffi_prep_closure_loc
|
|
||||||
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint
|
|
||||||
|
|
||||||
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
|
||||||
return unsafe.Pointer(uintptr(ptr) + offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer {
|
|
||||||
return (*(*unsafe.Pointer)(add(unsafe.Pointer(args), i*unsafe.Sizeof(0))))
|
|
||||||
}
|
|
||||||
26
c/llama2/.gitignore
vendored
26
c/llama2/.gitignore
vendored
@@ -1,26 +0,0 @@
|
|||||||
# If you prefer the allow list template instead of the deny list, see community template:
|
|
||||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
|
||||||
#
|
|
||||||
# Binaries for programs and plugins
|
|
||||||
*.exe
|
|
||||||
*.exe~
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
stories*.bin
|
|
||||||
.DS_Store
|
|
||||||
err.log
|
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
|
||||||
*.test
|
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
|
||||||
*.out
|
|
||||||
*.swp
|
|
||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
|
||||||
# vendor/
|
|
||||||
|
|
||||||
# Go workspace file
|
|
||||||
go.work*
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
LLGo wrapper of karpathy/llama2.c
|
|
||||||
=====
|
|
||||||
|
|
||||||
## How to update source to llgo
|
|
||||||
|
|
||||||
```
|
|
||||||
git submodule init
|
|
||||||
git submodule update
|
|
||||||
cp llama2.c/run.c llama2/run.c
|
|
||||||
```
|
|
||||||
Submodule c/llama2/llama2.c deleted from b3c4b6c3c4
@@ -1,160 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package llama2
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LLGoFiles = "llama2/llama2.c"
|
|
||||||
LLGoPackage = "link: -lm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type TokenIndex struct {
|
|
||||||
Str *c.Char
|
|
||||||
Id c.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type Tokenizer struct {
|
|
||||||
Vocab **c.Char
|
|
||||||
VocabScores *c.Float
|
|
||||||
SortedVocab *TokenIndex
|
|
||||||
VocabSize c.Int
|
|
||||||
MaxTokenLength c.Uint
|
|
||||||
BytePieces [512]uint8 // stores all single-byte strings
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname BuildTokenizer C.build_tokenizer
|
|
||||||
func BuildTokenizer(t *Tokenizer, tokenizerPath *c.Char, vocabSize c.Int)
|
|
||||||
|
|
||||||
//go:linkname FreeTokenizer C.free_tokenizer
|
|
||||||
func FreeTokenizer(t *Tokenizer)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type Config struct {
|
|
||||||
Dim c.Int // transformer dimension
|
|
||||||
HiddenDim c.Int // for ffn layers
|
|
||||||
NLayers c.Int // number of layers
|
|
||||||
NHeads c.Int // number of query heads
|
|
||||||
NKVHeads c.Int // number of key/value heads (can be < query heads because of multiquery)
|
|
||||||
VocabSize c.Int // vocabulary size, usually 256 (byte-level)
|
|
||||||
SeqLen c.Int // max sequence length
|
|
||||||
}
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type TransformerWeights struct {
|
|
||||||
// token embedding table
|
|
||||||
TokenEmbeddingTable *c.Float // (vocab_size, dim)
|
|
||||||
// weights for rmsnorms
|
|
||||||
RmsAttWeight *c.Float // (layer, dim) rmsnorm weights
|
|
||||||
RmsFfnWeight *c.Float // (layer, dim)
|
|
||||||
// weights for matmuls. note dim == n_heads * head_size
|
|
||||||
Wq *c.Float // (layer, dim, n_heads * head_size)
|
|
||||||
Wk *c.Float // (layer, dim, n_kv_heads * head_size)
|
|
||||||
Wv *c.Float // (layer, dim, n_kv_heads * head_size)
|
|
||||||
Wo *c.Float // (layer, n_heads * head_size, dim)
|
|
||||||
// weights for ffn
|
|
||||||
W1 *c.Float // (layer, hidden_dim, dim)
|
|
||||||
W2 *c.Float // (layer, dim, hidden_dim)
|
|
||||||
W3 *c.Float // (layer, hidden_dim, dim)
|
|
||||||
// final rmsnorm
|
|
||||||
RmsFinalWeight *c.Float // (dim,)
|
|
||||||
// (optional) classifier weights for the logits, on the last layer
|
|
||||||
Wcls *c.Float
|
|
||||||
}
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type RunState struct {
|
|
||||||
// current wave of activations
|
|
||||||
X *c.Float // activation at current time stamp (dim,)
|
|
||||||
Xb *c.Float // same, but inside a residual branch (dim,)
|
|
||||||
Xb2 *c.Float // an additional buffer just for convenience (dim,)
|
|
||||||
Hb *c.Float // buffer for hidden dimension in the ffn (hidden_dim,)
|
|
||||||
Hb2 *c.Float // buffer for hidden dimension in the ffn (hidden_dim,)
|
|
||||||
Q *c.Float // query (dim,)
|
|
||||||
K *c.Float // key (dim,)
|
|
||||||
V *c.Float // value (dim,)
|
|
||||||
Att *c.Float // buffer for scores/attention values (n_heads, seq_len)
|
|
||||||
Logits *c.Float // output logits
|
|
||||||
// kv cache
|
|
||||||
KeyCache *c.Float // (layer, seq_len, dim)
|
|
||||||
ValueCache *c.Float // (layer, seq_len, dim)
|
|
||||||
}
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type Transformer struct {
|
|
||||||
Config Config // the hyperparameters of the architecture (the blueprint)
|
|
||||||
Weights TransformerWeights // the weights of the model
|
|
||||||
State RunState // buffers for the "wave" of activations in the forward pass
|
|
||||||
|
|
||||||
// some more state needed to properly clean up the memory mapping (sigh)
|
|
||||||
Fd c.Int // file descriptor for memory mapping
|
|
||||||
Data *c.Float // memory mapped data pointer
|
|
||||||
FileSize uintptr // size of the checkpoint file in bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname BuildTransformer C.build_transformer
|
|
||||||
func BuildTransformer(t *Transformer, checkpointPath *c.Char)
|
|
||||||
|
|
||||||
//go:linkname FreeTransformer C.free_transformer
|
|
||||||
func FreeTransformer(t *Transformer)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type ProbIndex struct {
|
|
||||||
Prob c.Float
|
|
||||||
Index c.Int
|
|
||||||
} // struct used when sorting probabilities during top-p sampling
|
|
||||||
|
|
||||||
// llgo:type C
|
|
||||||
type Sampler struct {
|
|
||||||
VocabSize c.Int
|
|
||||||
Probindex *ProbIndex // buffer used in top-p sampling
|
|
||||||
Temperature c.Float
|
|
||||||
Topp c.Float
|
|
||||||
RngState uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname BuildSampler C.build_sampler
|
|
||||||
func BuildSampler(sampler *Sampler, vocabSize c.Int, temperature c.Float, topp c.Float, rngSeed uint64)
|
|
||||||
|
|
||||||
//go:linkname FreeSampler C.free_sampler
|
|
||||||
func FreeSampler(sampler *Sampler)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Generate C.generate
|
|
||||||
func Generate(
|
|
||||||
transformer *Transformer, tokenizer *Tokenizer, sampler *Sampler,
|
|
||||||
prompt *c.Char, steps c.Int)
|
|
||||||
|
|
||||||
//go:linkname Chat C.chat
|
|
||||||
func Chat(
|
|
||||||
transformer *Transformer, tokenizer *Tokenizer, sampler *Sampler,
|
|
||||||
cliUserPrompt *c.Char, cliSystemPrompt *c.Char, steps c.Int)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#define TESTING
|
|
||||||
#include "./run.c"
|
|
||||||
@@ -1,973 +0,0 @@
|
|||||||
/* Inference for Llama-2 Transformer model in pure C */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#if defined _WIN32
|
|
||||||
#include "win.h"
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Transformer model
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int dim; // transformer dimension
|
|
||||||
int hidden_dim; // for ffn layers
|
|
||||||
int n_layers; // number of layers
|
|
||||||
int n_heads; // number of query heads
|
|
||||||
int n_kv_heads; // number of key/value heads (can be < query heads because of multiquery)
|
|
||||||
int vocab_size; // vocabulary size, usually 256 (byte-level)
|
|
||||||
int seq_len; // max sequence length
|
|
||||||
} Config;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// token embedding table
|
|
||||||
float* token_embedding_table; // (vocab_size, dim)
|
|
||||||
// weights for rmsnorms
|
|
||||||
float* rms_att_weight; // (layer, dim) rmsnorm weights
|
|
||||||
float* rms_ffn_weight; // (layer, dim)
|
|
||||||
// weights for matmuls. note dim == n_heads * head_size
|
|
||||||
float* wq; // (layer, dim, n_heads * head_size)
|
|
||||||
float* wk; // (layer, dim, n_kv_heads * head_size)
|
|
||||||
float* wv; // (layer, dim, n_kv_heads * head_size)
|
|
||||||
float* wo; // (layer, n_heads * head_size, dim)
|
|
||||||
// weights for ffn
|
|
||||||
float* w1; // (layer, hidden_dim, dim)
|
|
||||||
float* w2; // (layer, dim, hidden_dim)
|
|
||||||
float* w3; // (layer, hidden_dim, dim)
|
|
||||||
// final rmsnorm
|
|
||||||
float* rms_final_weight; // (dim,)
|
|
||||||
// (optional) classifier weights for the logits, on the last layer
|
|
||||||
float* wcls;
|
|
||||||
} TransformerWeights;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// current wave of activations
|
|
||||||
float *x; // activation at current time stamp (dim,)
|
|
||||||
float *xb; // same, but inside a residual branch (dim,)
|
|
||||||
float *xb2; // an additional buffer just for convenience (dim,)
|
|
||||||
float *hb; // buffer for hidden dimension in the ffn (hidden_dim,)
|
|
||||||
float *hb2; // buffer for hidden dimension in the ffn (hidden_dim,)
|
|
||||||
float *q; // query (dim,)
|
|
||||||
float *k; // key (dim,)
|
|
||||||
float *v; // value (dim,)
|
|
||||||
float *att; // buffer for scores/attention values (n_heads, seq_len)
|
|
||||||
float *logits; // output logits
|
|
||||||
// kv cache
|
|
||||||
float* key_cache; // (layer, seq_len, dim)
|
|
||||||
float* value_cache; // (layer, seq_len, dim)
|
|
||||||
} RunState;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Config config; // the hyperparameters of the architecture (the blueprint)
|
|
||||||
TransformerWeights weights; // the weights of the model
|
|
||||||
RunState state; // buffers for the "wave" of activations in the forward pass
|
|
||||||
// some more state needed to properly clean up the memory mapping (sigh)
|
|
||||||
int fd; // file descriptor for memory mapping
|
|
||||||
float* data; // memory mapped data pointer
|
|
||||||
ssize_t file_size; // size of the checkpoint file in bytes
|
|
||||||
} Transformer;
|
|
||||||
|
|
||||||
void malloc_run_state(RunState* s, Config* p) {
|
|
||||||
// we calloc instead of malloc to keep valgrind happy
|
|
||||||
int kv_dim = (p->dim * p->n_kv_heads) / p->n_heads;
|
|
||||||
s->x = calloc(p->dim, sizeof(float));
|
|
||||||
s->xb = calloc(p->dim, sizeof(float));
|
|
||||||
s->xb2 = calloc(p->dim, sizeof(float));
|
|
||||||
s->hb = calloc(p->hidden_dim, sizeof(float));
|
|
||||||
s->hb2 = calloc(p->hidden_dim, sizeof(float));
|
|
||||||
s->q = calloc(p->dim, sizeof(float));
|
|
||||||
s->key_cache = calloc(p->n_layers * p->seq_len * kv_dim, sizeof(float));
|
|
||||||
s->value_cache = calloc(p->n_layers * p->seq_len * kv_dim, sizeof(float));
|
|
||||||
s->att = calloc(p->n_heads * p->seq_len, sizeof(float));
|
|
||||||
s->logits = calloc(p->vocab_size, sizeof(float));
|
|
||||||
// ensure all mallocs went fine
|
|
||||||
if (!s->x || !s->xb || !s->xb2 || !s->hb || !s->hb2 || !s->q
|
|
||||||
|| !s->key_cache || !s->value_cache || !s->att || !s->logits) {
|
|
||||||
fprintf(stderr, "malloc failed!\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_run_state(RunState* s) {
|
|
||||||
free(s->x);
|
|
||||||
free(s->xb);
|
|
||||||
free(s->xb2);
|
|
||||||
free(s->hb);
|
|
||||||
free(s->hb2);
|
|
||||||
free(s->q);
|
|
||||||
free(s->att);
|
|
||||||
free(s->logits);
|
|
||||||
free(s->key_cache);
|
|
||||||
free(s->value_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
void memory_map_weights(TransformerWeights *w, Config* p, float* ptr, int shared_weights) {
|
|
||||||
int head_size = p->dim / p->n_heads;
|
|
||||||
// make sure the multiplications below are done in 64bit to fit the parameter counts of 13B+ models
|
|
||||||
unsigned long long n_layers = p->n_layers;
|
|
||||||
w->token_embedding_table = ptr;
|
|
||||||
ptr += p->vocab_size * p->dim;
|
|
||||||
w->rms_att_weight = ptr;
|
|
||||||
ptr += n_layers * p->dim;
|
|
||||||
w->wq = ptr;
|
|
||||||
ptr += n_layers * p->dim * (p->n_heads * head_size);
|
|
||||||
w->wk = ptr;
|
|
||||||
ptr += n_layers * p->dim * (p->n_kv_heads * head_size);
|
|
||||||
w->wv = ptr;
|
|
||||||
ptr += n_layers * p->dim * (p->n_kv_heads * head_size);
|
|
||||||
w->wo = ptr;
|
|
||||||
ptr += n_layers * (p->n_heads * head_size) * p->dim;
|
|
||||||
w->rms_ffn_weight = ptr;
|
|
||||||
ptr += n_layers * p->dim;
|
|
||||||
w->w1 = ptr;
|
|
||||||
ptr += n_layers * p->dim * p->hidden_dim;
|
|
||||||
w->w2 = ptr;
|
|
||||||
ptr += n_layers * p->hidden_dim * p->dim;
|
|
||||||
w->w3 = ptr;
|
|
||||||
ptr += n_layers * p->dim * p->hidden_dim;
|
|
||||||
w->rms_final_weight = ptr;
|
|
||||||
ptr += p->dim;
|
|
||||||
ptr += p->seq_len * head_size / 2; // skip what used to be freq_cis_real (for RoPE)
|
|
||||||
ptr += p->seq_len * head_size / 2; // skip what used to be freq_cis_imag (for RoPE)
|
|
||||||
w->wcls = shared_weights ? w->token_embedding_table : ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_checkpoint(char* checkpoint, Config* config, TransformerWeights* weights,
|
|
||||||
int* fd, float** data, ssize_t* file_size) {
|
|
||||||
FILE *file = fopen(checkpoint, "rb");
|
|
||||||
if (!file) { fprintf(stderr, "Couldn't open file %s\n", checkpoint); exit(EXIT_FAILURE); }
|
|
||||||
// read in the config header
|
|
||||||
if (fread(config, sizeof(Config), 1, file) != 1) { exit(EXIT_FAILURE); }
|
|
||||||
// negative vocab size is hacky way of signaling unshared weights. bit yikes.
|
|
||||||
int shared_weights = config->vocab_size > 0 ? 1 : 0;
|
|
||||||
config->vocab_size = abs(config->vocab_size);
|
|
||||||
// figure out the file size
|
|
||||||
fseek(file, 0, SEEK_END); // move file pointer to end of file
|
|
||||||
*file_size = ftell(file); // get the file size, in bytes
|
|
||||||
fclose(file);
|
|
||||||
// memory map the Transformer weights into the data pointer
|
|
||||||
*fd = open(checkpoint, O_RDONLY); // open in read only mode
|
|
||||||
if (*fd == -1) { fprintf(stderr, "open failed!\n"); exit(EXIT_FAILURE); }
|
|
||||||
*data = mmap(NULL, *file_size, PROT_READ, MAP_PRIVATE, *fd, 0);
|
|
||||||
if (*data == MAP_FAILED) { fprintf(stderr, "mmap failed!\n"); exit(EXIT_FAILURE); }
|
|
||||||
float* weights_ptr = *data + sizeof(Config)/sizeof(float);
|
|
||||||
memory_map_weights(weights, config, weights_ptr, shared_weights);
|
|
||||||
}
|
|
||||||
|
|
||||||
void build_transformer(Transformer *t, char* checkpoint_path) {
|
|
||||||
// read in the Config and the Weights from the checkpoint
|
|
||||||
read_checkpoint(checkpoint_path, &t->config, &t->weights, &t->fd, &t->data, &t->file_size);
|
|
||||||
// allocate the RunState buffers
|
|
||||||
malloc_run_state(&t->state, &t->config);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_transformer(Transformer* t) {
|
|
||||||
// close the memory mapping
|
|
||||||
if (t->data != MAP_FAILED) { munmap(t->data, t->file_size); }
|
|
||||||
if (t->fd != -1) { close(t->fd); }
|
|
||||||
// free the RunState buffers
|
|
||||||
free_run_state(&t->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// neural net blocks; the dynamics of the Transformer
|
|
||||||
|
|
||||||
void rmsnorm(float* o, float* x, float* weight, int size) {
|
|
||||||
// calculate sum of squares
|
|
||||||
float ss = 0.0f;
|
|
||||||
for (int j = 0; j < size; j++) {
|
|
||||||
ss += x[j] * x[j];
|
|
||||||
}
|
|
||||||
ss /= size;
|
|
||||||
ss += 1e-5f;
|
|
||||||
ss = 1.0f / sqrtf(ss);
|
|
||||||
// normalize and scale
|
|
||||||
for (int j = 0; j < size; j++) {
|
|
||||||
o[j] = weight[j] * (ss * x[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void softmax(float* x, int size) {
|
|
||||||
// find max value (for numerical stability)
|
|
||||||
float max_val = x[0];
|
|
||||||
for (int i = 1; i < size; i++) {
|
|
||||||
if (x[i] > max_val) {
|
|
||||||
max_val = x[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// exp and sum
|
|
||||||
float sum = 0.0f;
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
x[i] = expf(x[i] - max_val);
|
|
||||||
sum += x[i];
|
|
||||||
}
|
|
||||||
// normalize
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
x[i] /= sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void matmul(float* xout, float* x, float* w, int n, int d) {
|
|
||||||
// W (d,n) @ x (n,) -> xout (d,)
|
|
||||||
// by far the most amount of time is spent inside this little function
|
|
||||||
int i;
|
|
||||||
#pragma omp parallel for private(i)
|
|
||||||
for (i = 0; i < d; i++) {
|
|
||||||
float val = 0.0f;
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
val += w[i * n + j] * x[j];
|
|
||||||
}
|
|
||||||
xout[i] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float* forward(Transformer* transformer, int token, int pos) {
|
|
||||||
|
|
||||||
// a few convenience variables
|
|
||||||
Config* p = &transformer->config;
|
|
||||||
TransformerWeights* w = &transformer->weights;
|
|
||||||
RunState* s = &transformer->state;
|
|
||||||
float *x = s->x;
|
|
||||||
int dim = p->dim;
|
|
||||||
int kv_dim = (p->dim * p->n_kv_heads) / p->n_heads;
|
|
||||||
int kv_mul = p->n_heads / p->n_kv_heads; // integer multiplier of the kv sharing in multiquery
|
|
||||||
int hidden_dim = p->hidden_dim;
|
|
||||||
int head_size = dim / p->n_heads;
|
|
||||||
|
|
||||||
// copy the token embedding into x
|
|
||||||
float* content_row = w->token_embedding_table + token * dim;
|
|
||||||
memcpy(x, content_row, dim*sizeof(*x));
|
|
||||||
|
|
||||||
// forward all the layers
|
|
||||||
for(unsigned long long l = 0; l < p->n_layers; l++) {
|
|
||||||
|
|
||||||
// attention rmsnorm
|
|
||||||
rmsnorm(s->xb, x, w->rms_att_weight + l*dim, dim);
|
|
||||||
|
|
||||||
// key and value point to the kv cache
|
|
||||||
int loff = l * p->seq_len * kv_dim; // kv cache layer offset for convenience
|
|
||||||
s->k = s->key_cache + loff + pos * kv_dim;
|
|
||||||
s->v = s->value_cache + loff + pos * kv_dim;
|
|
||||||
|
|
||||||
// qkv matmuls for this position
|
|
||||||
matmul(s->q, s->xb, w->wq + l*dim*dim, dim, dim);
|
|
||||||
matmul(s->k, s->xb, w->wk + l*dim*kv_dim, dim, kv_dim);
|
|
||||||
matmul(s->v, s->xb, w->wv + l*dim*kv_dim, dim, kv_dim);
|
|
||||||
|
|
||||||
// RoPE relative positional encoding: complex-valued rotate q and k in each head
|
|
||||||
for (int i = 0; i < dim; i+=2) {
|
|
||||||
int head_dim = i % head_size;
|
|
||||||
float freq = 1.0f / powf(10000.0f, head_dim / (float)head_size);
|
|
||||||
float val = pos * freq;
|
|
||||||
float fcr = cosf(val);
|
|
||||||
float fci = sinf(val);
|
|
||||||
int rotn = i < kv_dim ? 2 : 1; // how many vectors? 2 = q & k, 1 = q only
|
|
||||||
for (int v = 0; v < rotn; v++) {
|
|
||||||
float* vec = v == 0 ? s->q : s->k; // the vector to rotate (query or key)
|
|
||||||
float v0 = vec[i];
|
|
||||||
float v1 = vec[i+1];
|
|
||||||
vec[i] = v0 * fcr - v1 * fci;
|
|
||||||
vec[i+1] = v0 * fci + v1 * fcr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// multihead attention. iterate over all heads
|
|
||||||
int h;
|
|
||||||
#pragma omp parallel for private(h)
|
|
||||||
for (h = 0; h < p->n_heads; h++) {
|
|
||||||
// get the query vector for this head
|
|
||||||
float* q = s->q + h * head_size;
|
|
||||||
// attention scores for this head
|
|
||||||
float* att = s->att + h * p->seq_len;
|
|
||||||
// iterate over all timesteps, including the current one
|
|
||||||
for (int t = 0; t <= pos; t++) {
|
|
||||||
// get the key vector for this head and at this timestep
|
|
||||||
float* k = s->key_cache + loff + t * kv_dim + (h / kv_mul) * head_size;
|
|
||||||
// calculate the attention score as the dot product of q and k
|
|
||||||
float score = 0.0f;
|
|
||||||
for (int i = 0; i < head_size; i++) {
|
|
||||||
score += q[i] * k[i];
|
|
||||||
}
|
|
||||||
score /= sqrtf(head_size);
|
|
||||||
// save the score to the attention buffer
|
|
||||||
att[t] = score;
|
|
||||||
}
|
|
||||||
|
|
||||||
// softmax the scores to get attention weights, from 0..pos inclusively
|
|
||||||
softmax(att, pos + 1);
|
|
||||||
|
|
||||||
// weighted sum of the values, store back into xb
|
|
||||||
float* xb = s->xb + h * head_size;
|
|
||||||
memset(xb, 0, head_size * sizeof(float));
|
|
||||||
for (int t = 0; t <= pos; t++) {
|
|
||||||
// get the value vector for this head and at this timestep
|
|
||||||
float* v = s->value_cache + loff + t * kv_dim + (h / kv_mul) * head_size;
|
|
||||||
// get the attention weight for this timestep
|
|
||||||
float a = att[t];
|
|
||||||
// accumulate the weighted value into xb
|
|
||||||
for (int i = 0; i < head_size; i++) {
|
|
||||||
xb[i] += a * v[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// final matmul to get the output of the attention
|
|
||||||
matmul(s->xb2, s->xb, w->wo + l*dim*dim, dim, dim);
|
|
||||||
|
|
||||||
// residual connection back into x
|
|
||||||
for (int i = 0; i < dim; i++) {
|
|
||||||
x[i] += s->xb2[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ffn rmsnorm
|
|
||||||
rmsnorm(s->xb, x, w->rms_ffn_weight + l*dim, dim);
|
|
||||||
|
|
||||||
// Now for FFN in PyTorch we have: self.w2(F.silu(self.w1(x)) * self.w3(x))
|
|
||||||
// first calculate self.w1(x) and self.w3(x)
|
|
||||||
matmul(s->hb, s->xb, w->w1 + l*dim*hidden_dim, dim, hidden_dim);
|
|
||||||
matmul(s->hb2, s->xb, w->w3 + l*dim*hidden_dim, dim, hidden_dim);
|
|
||||||
|
|
||||||
// SwiGLU non-linearity
|
|
||||||
for (int i = 0; i < hidden_dim; i++) {
|
|
||||||
float val = s->hb[i];
|
|
||||||
// silu(x)=x*σ(x), where σ(x) is the logistic sigmoid
|
|
||||||
val *= (1.0f / (1.0f + expf(-val)));
|
|
||||||
// elementwise multiply with w3(x)
|
|
||||||
val *= s->hb2[i];
|
|
||||||
s->hb[i] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// final matmul to get the output of the ffn
|
|
||||||
matmul(s->xb, s->hb, w->w2 + l*dim*hidden_dim, hidden_dim, dim);
|
|
||||||
|
|
||||||
// residual connection
|
|
||||||
for (int i = 0; i < dim; i++) {
|
|
||||||
x[i] += s->xb[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// final rmsnorm
|
|
||||||
rmsnorm(x, x, w->rms_final_weight, dim);
|
|
||||||
|
|
||||||
// classifier into logits
|
|
||||||
matmul(s->logits, x, w->wcls, p->dim, p->vocab_size);
|
|
||||||
return s->logits;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// The Byte Pair Encoding (BPE) Tokenizer that translates strings <-> tokens
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *str;
|
|
||||||
int id;
|
|
||||||
} TokenIndex;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char** vocab;
|
|
||||||
float* vocab_scores;
|
|
||||||
TokenIndex *sorted_vocab;
|
|
||||||
int vocab_size;
|
|
||||||
unsigned int max_token_length;
|
|
||||||
unsigned char byte_pieces[512]; // stores all single-byte strings
|
|
||||||
} Tokenizer;
|
|
||||||
|
|
||||||
int compare_tokens(const void *a, const void *b) {
|
|
||||||
return strcmp(((TokenIndex*)a)->str, ((TokenIndex*)b)->str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void build_tokenizer(Tokenizer* t, char* tokenizer_path, int vocab_size) {
|
|
||||||
// i should have written the vocab_size into the tokenizer file... sigh
|
|
||||||
t->vocab_size = vocab_size;
|
|
||||||
// malloc space to hold the scores and the strings
|
|
||||||
t->vocab = (char**)malloc(vocab_size * sizeof(char*));
|
|
||||||
t->vocab_scores = (float*)malloc(vocab_size * sizeof(float));
|
|
||||||
t->sorted_vocab = NULL; // initialized lazily
|
|
||||||
for (int i = 0; i < 256; i++) {
|
|
||||||
t->byte_pieces[i * 2] = (unsigned char)i;
|
|
||||||
t->byte_pieces[i * 2 + 1] = '\0';
|
|
||||||
}
|
|
||||||
// read in the file
|
|
||||||
FILE *file = fopen(tokenizer_path, "rb");
|
|
||||||
if (!file) { fprintf(stderr, "couldn't load %s\n", tokenizer_path); exit(EXIT_FAILURE); }
|
|
||||||
if (fread(&t->max_token_length, sizeof(int), 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE); }
|
|
||||||
int len;
|
|
||||||
for (int i = 0; i < vocab_size; i++) {
|
|
||||||
if (fread(t->vocab_scores + i, sizeof(float), 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE);}
|
|
||||||
if (fread(&len, sizeof(int), 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE); }
|
|
||||||
t->vocab[i] = (char *)malloc(len + 1);
|
|
||||||
if (fread(t->vocab[i], len, 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE); }
|
|
||||||
t->vocab[i][len] = '\0'; // add the string terminating token
|
|
||||||
}
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_tokenizer(Tokenizer* t) {
|
|
||||||
for (int i = 0; i < t->vocab_size; i++) { free(t->vocab[i]); }
|
|
||||||
free(t->vocab);
|
|
||||||
free(t->vocab_scores);
|
|
||||||
free(t->sorted_vocab);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* decode(Tokenizer* t, int prev_token, int token) {
|
|
||||||
char *piece = t->vocab[token];
|
|
||||||
// following BOS (1) token, sentencepiece decoder strips any leading whitespace (see PR #89)
|
|
||||||
if (prev_token == 1 && piece[0] == ' ') { piece++; }
|
|
||||||
// careful, some tokens designate raw bytes, and look like e.g. '<0x01>'
|
|
||||||
// parse this and convert and return the actual byte
|
|
||||||
unsigned char byte_val;
|
|
||||||
if (sscanf(piece, "<0x%02hhX>", &byte_val) == 1) {
|
|
||||||
piece = (char*)t->byte_pieces + byte_val * 2;
|
|
||||||
}
|
|
||||||
return piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
void safe_printf(char *piece) {
|
|
||||||
// piece might be a raw byte token, and we only want to print printable chars or whitespace
|
|
||||||
// because some of the other bytes can be various control codes, backspace, etc.
|
|
||||||
if (piece == NULL) { return; }
|
|
||||||
if (piece[0] == '\0') { return; }
|
|
||||||
if (piece[1] == '\0') {
|
|
||||||
unsigned char byte_val = piece[0];
|
|
||||||
if (!(isprint(byte_val) || isspace(byte_val))) {
|
|
||||||
return; // bad byte, don't print it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%s", piece);
|
|
||||||
}
|
|
||||||
|
|
||||||
int str_lookup(char *str, TokenIndex *sorted_vocab, int vocab_size) {
|
|
||||||
// efficiently find the perfect match for str in vocab, return its index or -1 if not found
|
|
||||||
TokenIndex tok = { .str = str }; // acts as the key to search for
|
|
||||||
TokenIndex *res = bsearch(&tok, sorted_vocab, vocab_size, sizeof(TokenIndex), compare_tokens);
|
|
||||||
return res != NULL ? res->id : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(Tokenizer* t, char *text, int8_t bos, int8_t eos, int *tokens, int *n_tokens) {
|
|
||||||
// encode the string text (input) into an upper-bound preallocated tokens[] array
|
|
||||||
// bos != 0 means prepend the BOS token (=1), eos != 0 means append the EOS token (=2)
|
|
||||||
if (text == NULL) { fprintf(stderr, "cannot encode NULL text\n"); exit(EXIT_FAILURE); }
|
|
||||||
|
|
||||||
if (t->sorted_vocab == NULL) {
|
|
||||||
// lazily malloc and sort the vocabulary
|
|
||||||
t->sorted_vocab = malloc(t->vocab_size * sizeof(TokenIndex));
|
|
||||||
for (int i = 0; i < t->vocab_size; i++) {
|
|
||||||
t->sorted_vocab[i].str = t->vocab[i];
|
|
||||||
t->sorted_vocab[i].id = i;
|
|
||||||
}
|
|
||||||
qsort(t->sorted_vocab, t->vocab_size, sizeof(TokenIndex), compare_tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a temporary buffer that will store merge candidates of always two consecutive tokens
|
|
||||||
// *2 for concat, +1 for null terminator +2 for UTF8 (in case max_token_length is 1)
|
|
||||||
char* str_buffer = malloc((t->max_token_length*2 +1 +2) * sizeof(char));
|
|
||||||
size_t str_len = 0;
|
|
||||||
|
|
||||||
// start at 0 tokens
|
|
||||||
*n_tokens = 0;
|
|
||||||
|
|
||||||
// add optional BOS (=1) token, if desired
|
|
||||||
if (bos) tokens[(*n_tokens)++] = 1;
|
|
||||||
|
|
||||||
// add_dummy_prefix is true by default
|
|
||||||
// so prepend a dummy prefix token to the input string, but only if text != ""
|
|
||||||
// TODO: pretty sure this isn't correct in the general case but I don't have the
|
|
||||||
// energy to read more of the sentencepiece code to figure out what it's doing
|
|
||||||
if (text[0] != '\0') {
|
|
||||||
int dummy_prefix = str_lookup(" ", t->sorted_vocab, t->vocab_size);
|
|
||||||
tokens[(*n_tokens)++] = dummy_prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Okay UTF-8 time. This will get messy. Here is the reference from Wikipedia:
|
|
||||||
// Code point ↔ UTF-8 conversion
|
|
||||||
// First code point Last code point Byte 1 Byte 2 Byte 3 Byte 4
|
|
||||||
// U+0000 U+007F 0xxxxxxx
|
|
||||||
// U+0080 U+07FF 110xxxxx 10xxxxxx
|
|
||||||
// U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
|
|
||||||
// U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
|
||||||
|
|
||||||
// process the raw (UTF-8) byte sequence of the input string
|
|
||||||
for (char *c = text; *c != '\0'; c++) {
|
|
||||||
|
|
||||||
// reset buffer if the current byte is ASCII or a leading byte
|
|
||||||
// 0xC0 is 11000000, so (*c & 0xC0) keeps the first 2 bits and zeros the rest
|
|
||||||
// 0x80 is 10000000
|
|
||||||
// in UTF-8, all continuation bytes start with "10" in first two bits
|
|
||||||
// so in English this is: "if this byte is not a continuation byte"
|
|
||||||
if ((*c & 0xC0) != 0x80) {
|
|
||||||
// this byte must be either a leading byte (11...) or an ASCII char (0x...)
|
|
||||||
// => reset our location, as we're starting a new UTF-8 codepoint
|
|
||||||
str_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// append the current byte to the buffer
|
|
||||||
str_buffer[str_len++] = *c; // ++ is post-increment, incremented after this line
|
|
||||||
str_buffer[str_len] = '\0';
|
|
||||||
|
|
||||||
// while the next character is a continuation byte, continue appending
|
|
||||||
// but if there are too many of them, just stop to avoid overruning str_buffer size.
|
|
||||||
if ((*(c+1) & 0xC0) == 0x80 && str_len < 4) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok c+1 is not a continuation byte, so we've read in a full codepoint
|
|
||||||
int id = str_lookup(str_buffer, t->sorted_vocab, t->vocab_size);
|
|
||||||
|
|
||||||
if (id != -1) {
|
|
||||||
// we found this codepoint in vocab, add it as a token
|
|
||||||
tokens[(*n_tokens)++] = id;
|
|
||||||
} else {
|
|
||||||
// byte_fallback encoding: just encode each byte as a token
|
|
||||||
// +3 is here because the first 3 vocab elements are <unk>, <s>, </s>
|
|
||||||
// so the individual bytes only start at index 3
|
|
||||||
for (int i=0; i < str_len; i++) {
|
|
||||||
tokens[(*n_tokens)++] = (unsigned char)str_buffer[i] + 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
str_len = 0; // protect against a sequence of stray UTF8 continuation bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge the best consecutive pair each iteration, according the scores in vocab_scores
|
|
||||||
while (1) {
|
|
||||||
float best_score = -1e10;
|
|
||||||
int best_id = -1;
|
|
||||||
int best_idx = -1;
|
|
||||||
|
|
||||||
for (int i=0; i < (*n_tokens-1); i++) {
|
|
||||||
// check if we can merge the pair (tokens[i], tokens[i+1])
|
|
||||||
sprintf(str_buffer, "%s%s", t->vocab[tokens[i]], t->vocab[tokens[i+1]]);
|
|
||||||
int id = str_lookup(str_buffer, t->sorted_vocab, t->vocab_size);
|
|
||||||
if (id != -1 && t->vocab_scores[id] > best_score) {
|
|
||||||
// this merge pair exists in vocab! record its score and position
|
|
||||||
best_score = t->vocab_scores[id];
|
|
||||||
best_id = id;
|
|
||||||
best_idx = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best_idx == -1) {
|
|
||||||
break; // we couldn't find any more pairs to merge, so we're done
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge the consecutive pair (best_idx, best_idx+1) into new token best_id
|
|
||||||
tokens[best_idx] = best_id;
|
|
||||||
// delete token at position best_idx+1, shift the entire sequence back 1
|
|
||||||
for (int i = best_idx+1; i < (*n_tokens-1); i++) {
|
|
||||||
tokens[i] = tokens[i+1];
|
|
||||||
}
|
|
||||||
(*n_tokens)--; // token length decreased
|
|
||||||
}
|
|
||||||
|
|
||||||
// add optional EOS (=2) token, if desired
|
|
||||||
if (eos) tokens[(*n_tokens)++] = 2;
|
|
||||||
|
|
||||||
free(str_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// The Sampler, which takes logits and returns a sampled token
|
|
||||||
// sampling can be done in a few ways: greedy argmax, sampling, top-p sampling
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float prob;
|
|
||||||
int index;
|
|
||||||
} ProbIndex; // struct used when sorting probabilities during top-p sampling
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int vocab_size;
|
|
||||||
ProbIndex* probindex; // buffer used in top-p sampling
|
|
||||||
float temperature;
|
|
||||||
float topp;
|
|
||||||
unsigned long long rng_state;
|
|
||||||
} Sampler;
|
|
||||||
|
|
||||||
int sample_argmax(float* probabilities, int n) {
|
|
||||||
// return the index that has the highest probability
|
|
||||||
int max_i = 0;
|
|
||||||
float max_p = probabilities[0];
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
if (probabilities[i] > max_p) {
|
|
||||||
max_i = i;
|
|
||||||
max_p = probabilities[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sample_mult(float* probabilities, int n, float coin) {
|
|
||||||
// sample index from probabilities (they must sum to 1!)
|
|
||||||
// coin is a random number in [0, 1), usually from random_f32()
|
|
||||||
float cdf = 0.0f;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
cdf += probabilities[i];
|
|
||||||
if (coin < cdf) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n - 1; // in case of rounding errors
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare(const void* a, const void* b) {
|
|
||||||
ProbIndex* a_ = (ProbIndex*) a;
|
|
||||||
ProbIndex* b_ = (ProbIndex*) b;
|
|
||||||
if (a_->prob > b_->prob) return -1;
|
|
||||||
if (a_->prob < b_->prob) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sample_topp(float* probabilities, int n, float topp, ProbIndex* probindex, float coin) {
|
|
||||||
// top-p sampling (or "nucleus sampling") samples from the smallest set of
|
|
||||||
// tokens that exceed probability topp. This way we never sample tokens that
|
|
||||||
// have very low probabilities and are less likely to go "off the rails".
|
|
||||||
// coin is a random number in [0, 1), usually from random_f32()
|
|
||||||
|
|
||||||
int n0 = 0;
|
|
||||||
// quicksort indices in descending order of probabilities
|
|
||||||
// values smaller than (1 - topp) / (n - 1) cannot be part of the result
|
|
||||||
// so for efficiency we crop these out as candidates before sorting
|
|
||||||
const float cutoff = (1.0f - topp) / (n - 1);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
if (probabilities[i] >= cutoff) {
|
|
||||||
probindex[n0].index = i;
|
|
||||||
probindex[n0].prob = probabilities[i];
|
|
||||||
n0++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qsort(probindex, n0, sizeof(ProbIndex), compare);
|
|
||||||
|
|
||||||
// truncate the list where cumulative probability exceeds topp
|
|
||||||
float cumulative_prob = 0.0f;
|
|
||||||
int last_idx = n0 - 1; // in case of rounding errors consider all elements
|
|
||||||
for (int i = 0; i < n0; i++) {
|
|
||||||
cumulative_prob += probindex[i].prob;
|
|
||||||
if (cumulative_prob > topp) {
|
|
||||||
last_idx = i;
|
|
||||||
break; // we've exceeded topp by including last_idx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sample from the truncated list
|
|
||||||
float r = coin * cumulative_prob;
|
|
||||||
float cdf = 0.0f;
|
|
||||||
for (int i = 0; i <= last_idx; i++) {
|
|
||||||
cdf += probindex[i].prob;
|
|
||||||
if (r < cdf) {
|
|
||||||
return probindex[i].index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return probindex[last_idx].index; // in case of rounding errors
|
|
||||||
}
|
|
||||||
|
|
||||||
void build_sampler(Sampler* sampler, int vocab_size, float temperature, float topp, unsigned long long rng_seed) {
|
|
||||||
sampler->vocab_size = vocab_size;
|
|
||||||
sampler->temperature = temperature;
|
|
||||||
sampler->topp = topp;
|
|
||||||
sampler->rng_state = rng_seed;
|
|
||||||
// buffer only used with nucleus sampling; may not need but it's ~small
|
|
||||||
sampler->probindex = malloc(sampler->vocab_size * sizeof(ProbIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_sampler(Sampler* sampler) {
|
|
||||||
free(sampler->probindex);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int random_u32(unsigned long long *state) {
|
|
||||||
// xorshift rng: https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
|
|
||||||
*state ^= *state >> 12;
|
|
||||||
*state ^= *state << 25;
|
|
||||||
*state ^= *state >> 27;
|
|
||||||
return (*state * 0x2545F4914F6CDD1Dull) >> 32;
|
|
||||||
}
|
|
||||||
float random_f32(unsigned long long *state) { // random float32 in [0,1)
|
|
||||||
return (random_u32(state) >> 8) / 16777216.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sample(Sampler* sampler, float* logits) {
|
|
||||||
// sample the token given the logits and some hyperparameters
|
|
||||||
int next;
|
|
||||||
if (sampler->temperature == 0.0f) {
|
|
||||||
// greedy argmax sampling: take the token with the highest probability
|
|
||||||
next = sample_argmax(logits, sampler->vocab_size);
|
|
||||||
} else {
|
|
||||||
// apply the temperature to the logits
|
|
||||||
for (int q=0; q<sampler->vocab_size; q++) { logits[q] /= sampler->temperature; }
|
|
||||||
// apply softmax to the logits to get the probabilities for next token
|
|
||||||
softmax(logits, sampler->vocab_size);
|
|
||||||
// flip a (float) coin (this is our source of entropy for sampling)
|
|
||||||
float coin = random_f32(&sampler->rng_state);
|
|
||||||
// we sample from this distribution to get the next token
|
|
||||||
if (sampler->topp <= 0 || sampler->topp >= 1) {
|
|
||||||
// simply sample from the predicted probability distribution
|
|
||||||
next = sample_mult(logits, sampler->vocab_size, coin);
|
|
||||||
} else {
|
|
||||||
// top-p (nucleus) sampling, clamping the least likely tokens to zero
|
|
||||||
next = sample_topp(logits, sampler->vocab_size, sampler->topp, sampler->probindex, coin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// utilities: time
|
|
||||||
|
|
||||||
long time_in_ms() {
|
|
||||||
// return time in milliseconds, for benchmarking the model speed
|
|
||||||
struct timespec time;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &time);
|
|
||||||
return time.tv_sec * 1000 + time.tv_nsec / 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// generation loop
|
|
||||||
|
|
||||||
void generate(Transformer *transformer, Tokenizer *tokenizer, Sampler *sampler, char *prompt, int steps) {
|
|
||||||
char *empty_prompt = "";
|
|
||||||
if (prompt == NULL) { prompt = empty_prompt; }
|
|
||||||
|
|
||||||
// encode the (string) prompt into tokens sequence
|
|
||||||
int num_prompt_tokens = 0;
|
|
||||||
int* prompt_tokens = (int*)malloc((strlen(prompt)+3) * sizeof(int)); // +3 for '\0', ?BOS, ?EOS
|
|
||||||
encode(tokenizer, prompt, 1, 0, prompt_tokens, &num_prompt_tokens);
|
|
||||||
if (num_prompt_tokens < 1) {
|
|
||||||
fprintf(stderr, "something is wrong, expected at least 1 prompt token\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// start the main loop
|
|
||||||
long start = 0; // used to time our code, only initialized after first iteration
|
|
||||||
int next; // will store the next token in the sequence
|
|
||||||
int token = prompt_tokens[0]; // kick off with the first token in the prompt
|
|
||||||
int pos = 0; // position in the sequence
|
|
||||||
while (pos < steps) {
|
|
||||||
|
|
||||||
// forward the transformer to get logits for the next token
|
|
||||||
float* logits = forward(transformer, token, pos);
|
|
||||||
|
|
||||||
// advance the state machine
|
|
||||||
if (pos < num_prompt_tokens - 1) {
|
|
||||||
// if we are still processing the input prompt, force the next prompt token
|
|
||||||
next = prompt_tokens[pos + 1];
|
|
||||||
} else {
|
|
||||||
// otherwise sample the next token from the logits
|
|
||||||
next = sample(sampler, logits);
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
// data-dependent terminating condition: the BOS (=1) token delimits sequences
|
|
||||||
if (next == 1) { break; }
|
|
||||||
|
|
||||||
// print the token as string, decode it with the Tokenizer object
|
|
||||||
char* piece = decode(tokenizer, token, next);
|
|
||||||
safe_printf(piece); // same as printf("%s", piece), but skips "unsafe" bytes
|
|
||||||
fflush(stdout);
|
|
||||||
token = next;
|
|
||||||
|
|
||||||
// init the timer here because the first iteration can be slower
|
|
||||||
if (start == 0) { start = time_in_ms(); }
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// report achieved tok/s (pos-1 because the timer starts after first iteration)
|
|
||||||
if (pos > 1) {
|
|
||||||
long end = time_in_ms();
|
|
||||||
fprintf(stderr, "achieved tok/s: %f\n", (pos-1) / (double)(end-start)*1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(prompt_tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_stdin(const char* guide, char* buffer, size_t bufsize) {
|
|
||||||
// read a line from stdin, up to but not including \n
|
|
||||||
printf("%s", guide);
|
|
||||||
if (fgets(buffer, bufsize, stdin) != NULL) {
|
|
||||||
size_t len = strlen(buffer);
|
|
||||||
if (len > 0 && buffer[len - 1] == '\n') {
|
|
||||||
buffer[len - 1] = '\0'; // strip newline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// chat loop
|
|
||||||
// I manually inspected the tokens for a few chat conversations compared to
|
|
||||||
// python reference and that seemed ok, but this was not thoroughly tested and
|
|
||||||
// is not safely implemented, it's more a proof of concept atm.
|
|
||||||
|
|
||||||
void chat(Transformer *transformer, Tokenizer *tokenizer, Sampler *sampler,
|
|
||||||
char *cli_user_prompt, char *cli_system_prompt, int steps) {
|
|
||||||
|
|
||||||
// buffers for reading the system prompt and user prompt from stdin
|
|
||||||
// you'll notice they are soomewhat haphazardly and unsafely set atm
|
|
||||||
char system_prompt[512];
|
|
||||||
char user_prompt[512];
|
|
||||||
char rendered_prompt[1152];
|
|
||||||
int num_prompt_tokens = 0;
|
|
||||||
int* prompt_tokens = (int*)malloc(1152 * sizeof(int));
|
|
||||||
int user_idx;
|
|
||||||
|
|
||||||
// start the main loop
|
|
||||||
int8_t user_turn = 1; // user starts
|
|
||||||
int next; // will store the next token in the sequence
|
|
||||||
int token; // stores the current token to feed into the transformer
|
|
||||||
int prev_token;
|
|
||||||
int pos = 0; // position in the sequence
|
|
||||||
while (pos < steps) {
|
|
||||||
|
|
||||||
// when it is the user's turn to contribute tokens to the dialog...
|
|
||||||
if (user_turn) {
|
|
||||||
// get the (optional) system prompt at position 0
|
|
||||||
if (pos == 0) {
|
|
||||||
// at position 0, the user can also contribute a system prompt
|
|
||||||
if (cli_system_prompt == NULL) {
|
|
||||||
// system prompt was not passed in, attempt to get it from stdin
|
|
||||||
read_stdin("Enter system prompt (optional): ", system_prompt, sizeof(system_prompt));
|
|
||||||
} else {
|
|
||||||
// system prompt was passed in, use it
|
|
||||||
strcpy(system_prompt, cli_system_prompt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// get the user prompt
|
|
||||||
if (pos == 0 && cli_user_prompt != NULL) {
|
|
||||||
// user prompt for position 0 was passed in, use it
|
|
||||||
strcpy(user_prompt, cli_user_prompt);
|
|
||||||
} else {
|
|
||||||
// otherwise get user prompt from stdin
|
|
||||||
read_stdin("User: ", user_prompt, sizeof(user_prompt));
|
|
||||||
}
|
|
||||||
// render user/system prompts into the Llama 2 Chat schema
|
|
||||||
if (pos == 0 && system_prompt[0] != '\0') {
|
|
||||||
char system_template[] = "[INST] <<SYS>>\n%s\n<</SYS>>\n\n%s [/INST]";
|
|
||||||
sprintf(rendered_prompt, system_template, system_prompt, user_prompt);
|
|
||||||
} else {
|
|
||||||
char user_template[] = "[INST] %s [/INST]";
|
|
||||||
sprintf(rendered_prompt, user_template, user_prompt);
|
|
||||||
}
|
|
||||||
// encode the rendered prompt into tokens
|
|
||||||
encode(tokenizer, rendered_prompt, 1, 0, prompt_tokens, &num_prompt_tokens);
|
|
||||||
user_idx = 0; // reset the user index
|
|
||||||
user_turn = 0;
|
|
||||||
printf("Assistant: ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the token to pass into the transformer next
|
|
||||||
if (user_idx < num_prompt_tokens) {
|
|
||||||
// if we are still processing the input prompt, force the next prompt token
|
|
||||||
token = prompt_tokens[user_idx++];
|
|
||||||
} else {
|
|
||||||
// otherwise use the next token sampled from previous turn
|
|
||||||
token = next;
|
|
||||||
}
|
|
||||||
// EOS (=2) token ends the Assistant turn
|
|
||||||
if (token == 2) { user_turn = 1; }
|
|
||||||
|
|
||||||
// forward the transformer to get logits for the next token
|
|
||||||
float* logits = forward(transformer, token, pos);
|
|
||||||
next = sample(sampler, logits);
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
if (user_idx >= num_prompt_tokens && next != 2) {
|
|
||||||
// the Assistant is responding, so print its output
|
|
||||||
char* piece = decode(tokenizer, token, next);
|
|
||||||
safe_printf(piece); // same as printf("%s", piece), but skips "unsafe" bytes
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
if (next == 2) { printf("\n"); }
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
free(prompt_tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// CLI, include only if not testing
|
|
||||||
#ifndef TESTING
|
|
||||||
|
|
||||||
void error_usage() {
|
|
||||||
fprintf(stderr, "Usage: run <checkpoint> [options]\n");
|
|
||||||
fprintf(stderr, "Example: run model.bin -n 256 -i \"Once upon a time\"\n");
|
|
||||||
fprintf(stderr, "Options:\n");
|
|
||||||
fprintf(stderr, " -t <float> temperature in [0,inf], default 1.0\n");
|
|
||||||
fprintf(stderr, " -p <float> p value in top-p (nucleus) sampling in [0,1] default 0.9\n");
|
|
||||||
fprintf(stderr, " -s <int> random seed, default time(NULL)\n");
|
|
||||||
fprintf(stderr, " -n <int> number of steps to run for, default 256. 0 = max_seq_len\n");
|
|
||||||
fprintf(stderr, " -i <string> input prompt\n");
|
|
||||||
fprintf(stderr, " -z <string> optional path to custom tokenizer\n");
|
|
||||||
fprintf(stderr, " -m <string> mode: generate|chat, default: generate\n");
|
|
||||||
fprintf(stderr, " -y <string> (optional) system prompt in chat mode\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
// default parameters
|
|
||||||
char *checkpoint_path = NULL; // e.g. out/model.bin
|
|
||||||
char *tokenizer_path = "tokenizer.bin";
|
|
||||||
float temperature = 1.0f; // 0.0 = greedy deterministic. 1.0 = original. don't set higher
|
|
||||||
float topp = 0.9f; // top-p in nucleus sampling. 1.0 = off. 0.9 works well, but slower
|
|
||||||
int steps = 256; // number of steps to run for
|
|
||||||
char *prompt = NULL; // prompt string
|
|
||||||
unsigned long long rng_seed = 0; // seed rng with time by default
|
|
||||||
char *mode = "generate"; // generate|chat
|
|
||||||
char *system_prompt = NULL; // the (optional) system prompt to use in chat mode
|
|
||||||
|
|
||||||
// poor man's C argparse so we can override the defaults above from the command line
|
|
||||||
if (argc >= 2) { checkpoint_path = argv[1]; } else { error_usage(); }
|
|
||||||
for (int i = 2; i < argc; i+=2) {
|
|
||||||
// do some basic validation
|
|
||||||
if (i + 1 >= argc) { error_usage(); } // must have arg after flag
|
|
||||||
if (argv[i][0] != '-') { error_usage(); } // must start with dash
|
|
||||||
if (strlen(argv[i]) != 2) { error_usage(); } // must be -x (one dash, one letter)
|
|
||||||
// read in the args
|
|
||||||
if (argv[i][1] == 't') { temperature = atof(argv[i + 1]); }
|
|
||||||
else if (argv[i][1] == 'p') { topp = atof(argv[i + 1]); }
|
|
||||||
else if (argv[i][1] == 's') { rng_seed = atoi(argv[i + 1]); }
|
|
||||||
else if (argv[i][1] == 'n') { steps = atoi(argv[i + 1]); }
|
|
||||||
else if (argv[i][1] == 'i') { prompt = argv[i + 1]; }
|
|
||||||
else if (argv[i][1] == 'z') { tokenizer_path = argv[i + 1]; }
|
|
||||||
else if (argv[i][1] == 'm') { mode = argv[i + 1]; }
|
|
||||||
else if (argv[i][1] == 'y') { system_prompt = argv[i + 1]; }
|
|
||||||
else { error_usage(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameter validation/overrides
|
|
||||||
if (rng_seed <= 0) rng_seed = (unsigned int)time(NULL);
|
|
||||||
if (temperature < 0.0) temperature = 0.0;
|
|
||||||
if (topp < 0.0 || 1.0 < topp) topp = 0.9;
|
|
||||||
if (steps < 0) steps = 0;
|
|
||||||
|
|
||||||
// build the Transformer via the model .bin file
|
|
||||||
Transformer transformer;
|
|
||||||
build_transformer(&transformer, checkpoint_path);
|
|
||||||
if (steps == 0 || steps > transformer.config.seq_len) steps = transformer.config.seq_len; // override to ~max length
|
|
||||||
|
|
||||||
// build the Tokenizer via the tokenizer .bin file
|
|
||||||
Tokenizer tokenizer;
|
|
||||||
build_tokenizer(&tokenizer, tokenizer_path, transformer.config.vocab_size);
|
|
||||||
|
|
||||||
// build the Sampler
|
|
||||||
Sampler sampler;
|
|
||||||
build_sampler(&sampler, transformer.config.vocab_size, temperature, topp, rng_seed);
|
|
||||||
|
|
||||||
// run!
|
|
||||||
if (strcmp(mode, "generate") == 0) {
|
|
||||||
generate(&transformer, &tokenizer, &sampler, prompt, steps);
|
|
||||||
} else if (strcmp(mode, "chat") == 0) {
|
|
||||||
chat(&transformer, &tokenizer, &sampler, prompt, system_prompt, steps);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "unknown mode: %s\n", mode);
|
|
||||||
error_usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// memory and file handles cleanup
|
|
||||||
free_sampler(&sampler);
|
|
||||||
free_tokenizer(&tokenizer);
|
|
||||||
free_transformer(&transformer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/lua"
|
|
||||||
)
|
|
||||||
|
|
||||||
func coroutineFunc(L *lua.State) c.Int {
|
|
||||||
c.Printf(c.Str("Coroutine started\n"))
|
|
||||||
L.Yield(0) // Pause the coroutine
|
|
||||||
c.Printf(c.Str("Coroutine resumed\n"))
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
L := lua.Newstate__1()
|
|
||||||
defer L.Close()
|
|
||||||
|
|
||||||
L.Openlibs()
|
|
||||||
co := L.Newthread()
|
|
||||||
L.Pushcfunction(coroutineFunc)
|
|
||||||
L.Xmove(co, 1)
|
|
||||||
|
|
||||||
var nres c.Int
|
|
||||||
|
|
||||||
c.Printf(c.Str("Resuming coroutine for the first time\n"))
|
|
||||||
result := co.Resume(nil, 0, &nres)
|
|
||||||
if result == lua.YIELD {
|
|
||||||
c.Printf(c.Str("Coroutine yielded\n"))
|
|
||||||
result = co.Resume(nil, 0, &nres)
|
|
||||||
if result == 0 {
|
|
||||||
c.Printf(c.Str("Coroutine finished\n"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expected output:
|
|
||||||
Resuming coroutine for the first time
|
|
||||||
Coroutine started
|
|
||||||
Coroutine yielded
|
|
||||||
Coroutine finished
|
|
||||||
*/
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/lua"
|
|
||||||
)
|
|
||||||
|
|
||||||
func coroutineFunc(L *lua.State) {
|
|
||||||
L.Loadstring(c.Str(`
|
|
||||||
function coro_func()
|
|
||||||
for i = 1, 5 do
|
|
||||||
coroutine.yield(i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`))
|
|
||||||
L.Pcall(0, 0, 0)
|
|
||||||
L.Getglobal(c.Str("coro_func"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
L := lua.Newstate__1()
|
|
||||||
defer L.Close()
|
|
||||||
|
|
||||||
L.Openlibs()
|
|
||||||
|
|
||||||
coroutineFunc(L) // Load and get the coroutine function
|
|
||||||
|
|
||||||
co := L.Newthread() // Create a new coroutine/thread
|
|
||||||
L.Pushvalue(-2) // Move the function to the top of the stack
|
|
||||||
L.Xmove(co, 1) // Move the function to the new coroutine
|
|
||||||
|
|
||||||
var nres c.Int
|
|
||||||
var status c.Int
|
|
||||||
|
|
||||||
c.Printf(c.Str("Resuming coroutine...\n"))
|
|
||||||
// Resume coroutine and handle yields
|
|
||||||
for {
|
|
||||||
status = co.Resume(nil, 0, &nres)
|
|
||||||
if status == lua.YIELD {
|
|
||||||
c.Printf(c.Str("Resuming coroutine %d...\n"), status)
|
|
||||||
yieldValue := co.Tointeger(-1)
|
|
||||||
c.Printf(c.Str("Yield value: %d\n"), yieldValue)
|
|
||||||
co.Pop(1) // Clean up the stack
|
|
||||||
|
|
||||||
// Check if the coroutine is yieldable
|
|
||||||
if co.Isyieldable() != 0 {
|
|
||||||
c.Printf(c.Str("Coroutine is yieldable.\n"))
|
|
||||||
} else {
|
|
||||||
c.Printf(c.Str("Coroutine is not yieldable.\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the final status of the coroutine
|
|
||||||
finalStatus := co.Status()
|
|
||||||
c.Printf(c.Str("Final status of coroutine: %d\n"), finalStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expected output:
|
|
||||||
Resuming coroutine...
|
|
||||||
Resuming coroutine 1...
|
|
||||||
Yield value: 1
|
|
||||||
Coroutine is yieldable.
|
|
||||||
Resuming coroutine 1...
|
|
||||||
Yield value: 2
|
|
||||||
Coroutine is yieldable.
|
|
||||||
Resuming coroutine 1...
|
|
||||||
Yield value: 3
|
|
||||||
Coroutine is yieldable.
|
|
||||||
Resuming coroutine 1...
|
|
||||||
Yield value: 4
|
|
||||||
Coroutine is yieldable.
|
|
||||||
Resuming coroutine 1...
|
|
||||||
Yield value: 5
|
|
||||||
Coroutine is yieldable.
|
|
||||||
Final status of coroutine: 0
|
|
||||||
*/
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user