Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee0e0a5c51 | ||
|
|
7b2747ce0c | ||
|
|
578bc165c4 | ||
|
|
a1d46e905b | ||
|
|
9102ca6b1e | ||
|
|
835d6fee1e | ||
|
|
294abb5126 | ||
|
|
5fca8ebd4e | ||
|
|
d3df782fca | ||
|
|
b04ac8df30 | ||
|
|
bb03df7059 | ||
|
|
98072f3f4b | ||
|
|
3bf0780a67 | ||
|
|
a1fdc05e26 | ||
|
|
93bff83e3d | ||
|
|
e470bc2069 | ||
|
|
efa771f3ff | ||
|
|
806193fc6e | ||
|
|
cdfa0166bd | ||
|
|
0687efaec6 | ||
|
|
0d3e78ad94 | ||
|
|
375b2b579e | ||
|
|
a578155dcb | ||
|
|
df5f1afb74 | ||
|
|
b2a2b2f29d | ||
|
|
91df9957f5 | ||
|
|
08e0ace9a2 | ||
|
|
a4286dbd4b | ||
|
|
f2e15a6846 |
48
.github/actions/setup-deps/action.yml
vendored
48
.github/actions/setup-deps/action.yml
vendored
@@ -1,48 +0,0 @@
|
|||||||
name: "Setup LLGO Dependencies"
|
|
||||||
description: "Install all required dependencies for LLGO"
|
|
||||||
inputs:
|
|
||||||
llvm-version:
|
|
||||||
description: "LLVM version to install"
|
|
||||||
required: true
|
|
||||||
default: "19"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Install macOS dependencies
|
|
||||||
if: runner.os == 'macOS'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
brew update
|
|
||||||
brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} bdw-gc openssl libffi libuv
|
|
||||||
brew link --overwrite llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} libffi
|
|
||||||
echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
# Install optional deps for demos.
|
|
||||||
#
|
|
||||||
# NOTE: Keep this list updated as new deps are introduced.
|
|
||||||
opt_deps=(
|
|
||||||
cjson # for github.com/goplus/lib/c/cjson
|
|
||||||
sqlite # for github.com/goplus/lib/c/sqlite
|
|
||||||
python@3.12 # for github.com/goplus/lib/py
|
|
||||||
)
|
|
||||||
brew install "${opt_deps[@]}"
|
|
||||||
- name: Install Ubuntu dependencies
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
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 -
|
|
||||||
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 libuv1-dev
|
|
||||||
echo "PATH=/usr/lib/llvm-${{inputs.llvm-version}}/bin:$PATH" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# Install optional deps for demos.
|
|
||||||
#
|
|
||||||
# NOTE: Keep this list updated as new deps are introduced.
|
|
||||||
opt_deps=(
|
|
||||||
libcjson-dev # for github.com/goplus/lib/c/cjson
|
|
||||||
libsqlite3-dev # for github.com/goplus/lib/c/sqlite
|
|
||||||
python3.12-dev # for github.com/goplus/lib/py
|
|
||||||
)
|
|
||||||
sudo apt-get install -y "${opt_deps[@]}"
|
|
||||||
51
.github/actions/setup-go/action.yml
vendored
51
.github/actions/setup-go/action.yml
vendored
@@ -1,51 +0,0 @@
|
|||||||
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
|
|
||||||
35
.github/actions/test-helloworld/action.yml
vendored
35
.github/actions/test-helloworld/action.yml
vendored
@@ -1,35 +0,0 @@
|
|||||||
name: 'Test Hello World'
|
|
||||||
description: 'Test Hello World with specific Go and module versions'
|
|
||||||
inputs:
|
|
||||||
go-version:
|
|
||||||
description: 'Go version being tested'
|
|
||||||
required: true
|
|
||||||
mod-version:
|
|
||||||
description: 'Go module version to use'
|
|
||||||
required: true
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Test Hello World
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "Testing with Go ${{ inputs.go-version }} and go.mod ${{ inputs.mod-version }}"
|
|
||||||
mkdir -p _test/helloworld && cd _test/helloworld
|
|
||||||
cat > go.mod << 'EOL'
|
|
||||||
module hello
|
|
||||||
go ${{ inputs.mod-version }}
|
|
||||||
EOL
|
|
||||||
cat > main.go << 'EOL'
|
|
||||||
package main
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/goplus/lib/c"
|
|
||||||
)
|
|
||||||
func main() {
|
|
||||||
fmt.Println("Hello, LLGo!")
|
|
||||||
println("Hello, LLGo!")
|
|
||||||
c.Printf(c.Str("Hello, LLGo!\n"))
|
|
||||||
}
|
|
||||||
EOL
|
|
||||||
go mod tidy
|
|
||||||
llgo run .
|
|
||||||
9
.github/codecov.yml
vendored
9
.github/codecov.yml
vendored
@@ -1,9 +0,0 @@
|
|||||||
coverage:
|
|
||||||
ignore:
|
|
||||||
- "chore"
|
|
||||||
- "cmd/internal"
|
|
||||||
- "internal/build"
|
|
||||||
- "internal/llgen"
|
|
||||||
- "internal/mockable"
|
|
||||||
- "internal/packages"
|
|
||||||
- "internal/typepatch"
|
|
||||||
169
.github/workflows/doc.yml
vendored
169
.github/workflows/doc.yml
vendored
@@ -1,169 +0,0 @@
|
|||||||
name: Docs
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["**"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["**"]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
doc_verify:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- name: Install embedme
|
|
||||||
run: npm install -g embedme
|
|
||||||
|
|
||||||
- name: Verify README.md embedded code
|
|
||||||
run: embedme --verify README.md
|
|
||||||
|
|
||||||
- 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.24.2"
|
|
||||||
|
|
||||||
- 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:
|
|
||||||
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_llgo.sh
|
|
||||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Test doc code blocks
|
|
||||||
run: |
|
|
||||||
set -e
|
|
||||||
set -x
|
|
||||||
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
|
|
||||||
echo "PATH=/usr/lib/llvm-19/bin:$PATH" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- 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
|
|
||||||
30
.github/workflows/fmt.yml
vendored
30
.github/workflows/fmt.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: Format Check
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["**"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["**"]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
fmt:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: ./.github/actions/setup-go
|
|
||||||
with:
|
|
||||||
go-version: "1.24.2"
|
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
run: |
|
|
||||||
for dir in . runtime; do
|
|
||||||
pushd $dir
|
|
||||||
if [ -n "$(go fmt ./...)" ]; then
|
|
||||||
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
popd
|
|
||||||
done
|
|
||||||
echo "All files are properly formatted."
|
|
||||||
89
.github/workflows/go.yml
vendored
89
.github/workflows/go.yml
vendored
@@ -5,26 +5,67 @@ name: Go
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["**"]
|
branches: [ "*" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["**"]
|
branches: [ "*" ]
|
||||||
|
|
||||||
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: [19]
|
llvm: [18]
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
uses: ./.github/actions/setup-deps
|
if: startsWith(matrix.os, 'macos')
|
||||||
with:
|
run: |
|
||||||
llvm-version: ${{matrix.llvm}}
|
brew update
|
||||||
|
brew install llvm@${{matrix.llvm}} pkg-config bdw-gc openssl
|
||||||
|
echo "$(brew --prefix llvm@${{matrix.llvm}})/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
# Install optional deps for demos.
|
||||||
|
#
|
||||||
|
# NOTE: Keep this list updated as new deps are introduced.
|
||||||
|
opt_deps=(
|
||||||
|
cjson # for github.com/goplus/llgo/c/cjson
|
||||||
|
sqlite # for github.com/goplus/llgo/c/sqlite
|
||||||
|
python@3.12 # for github.com/goplus/llgo/py
|
||||||
|
)
|
||||||
|
brew install "${opt_deps[@]}"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
run: |
|
||||||
|
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{matrix.llvm}} main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y llvm-${{matrix.llvm}}-dev clang-${{matrix.llvm}} lld-${{matrix.llvm}} pkg-config libgc-dev libssl-dev zlib1g-dev
|
||||||
|
echo "/usr/lib/llvm-${{matrix.llvm}}/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
# Install optional deps for demos.
|
||||||
|
#
|
||||||
|
# NOTE: Keep this list updated as new deps are introduced.
|
||||||
|
opt_deps=(
|
||||||
|
libcjson-dev # for github.com/goplus/llgo/c/cjson
|
||||||
|
libsqlite3-dev # for github.com/goplus/llgo/c/sqlite
|
||||||
|
python3.12-dev # for github.com/goplus/llgo/py
|
||||||
|
)
|
||||||
|
sudo apt-get install -y "${opt_deps[@]}"
|
||||||
|
|
||||||
|
- name: Install further optional dependencies for demos
|
||||||
|
run: |
|
||||||
|
wget -P ./_demo/llama2-c https://huggingface.co/karpathy/tinyllamas/resolve/main/stories15M.bin
|
||||||
|
py_deps=(
|
||||||
|
numpy # for github.com/goplus/llgo/py/numpy
|
||||||
|
torch # for github.com/goplus/llgo/py/torch
|
||||||
|
)
|
||||||
|
pip3 install --break-system-packages "${py_deps[@]}"
|
||||||
|
|
||||||
- name: Clang information
|
- name: Clang information
|
||||||
run: |
|
run: |
|
||||||
@@ -33,22 +74,46 @@ jobs:
|
|||||||
clang --version
|
clang --version
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: ./.github/actions/setup-go
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.24.2"
|
go-version: '1.20'
|
||||||
|
|
||||||
- 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 ./...
|
run: go test -v ./...
|
||||||
|
|
||||||
- name: Test with coverage
|
- name: Test with coverage
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
run: go test -coverprofile="coverage.txt" -covermode=atomic ./...
|
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: go install ./...
|
||||||
|
|
||||||
|
- 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
|
||||||
|
continue-on-error: true
|
||||||
|
run: bash .github/workflows/test_demo.sh
|
||||||
|
|
||||||
|
- name: Show test result
|
||||||
|
run: cat result.md
|
||||||
|
|
||||||
|
- name: PR comment with test result
|
||||||
|
uses: thollander/actions-comment-pull-request@v2
|
||||||
|
if: false
|
||||||
|
with:
|
||||||
|
filePath: result.md
|
||||||
|
comment_tag: test-result-on-${{matrix.os}}-with-llvm-${{matrix.llvm}}
|
||||||
|
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
token: ${{secrets.CODECOV_TOKEN}}
|
token: ${{secrets.CODECOV_TOKEN}}
|
||||||
|
slug: goplus/llgo
|
||||||
|
|||||||
247
.github/workflows/llgo.yml
vendored
247
.github/workflows/llgo.yml
vendored
@@ -1,247 +0,0 @@
|
|||||||
# This workflow will build a golang project
|
|
||||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
|
||||||
|
|
||||||
name: LLGo
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["**"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["**"]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
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:
|
|
||||||
matrix:
|
|
||||||
os:
|
|
||||||
- macos-latest
|
|
||||||
- ubuntu-24.04
|
|
||||||
llvm: [19]
|
|
||||||
go: ["1.21.13", "1.22.12", "1.23.6", "1.24.2"]
|
|
||||||
runs-on: ${{matrix.os}}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install dependencies
|
|
||||||
uses: ./.github/actions/setup-deps
|
|
||||||
with:
|
|
||||||
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
|
|
||||||
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 for build
|
|
||||||
uses: ./.github/actions/setup-go
|
|
||||||
with:
|
|
||||||
go-version: "1.24.2"
|
|
||||||
|
|
||||||
- name: Install
|
|
||||||
run: |
|
|
||||||
go install ./...
|
|
||||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Go for testing
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ${{matrix.go}}
|
|
||||||
|
|
||||||
- name: _xtool build tests
|
|
||||||
run: |
|
|
||||||
cd _xtool
|
|
||||||
llgo build -v ./...
|
|
||||||
|
|
||||||
- name: Test demos
|
|
||||||
run: |
|
|
||||||
# TODO(lijie): force python3-embed to be linked with python-3.12-embed
|
|
||||||
# Currently, python3-embed is python-3.13-embed, doesn't work with pytorch
|
|
||||||
# Will remove this after pytorch is fixed.
|
|
||||||
pcdir=$HOME/pc
|
|
||||||
mkdir -p $pcdir
|
|
||||||
libdir=$(pkg-config --variable=libdir python-3.12-embed)
|
|
||||||
echo "libdir: $libdir"
|
|
||||||
ln -s $libdir/pkgconfig/python-3.12-embed.pc $pcdir/python3-embed.pc
|
|
||||||
export PKG_CONFIG_PATH=$pcdir
|
|
||||||
bash .github/workflows/test_demo.sh
|
|
||||||
|
|
||||||
- name: Show test result
|
|
||||||
run: cat result.md
|
|
||||||
|
|
||||||
- name: LLDB tests
|
|
||||||
if: ${{startsWith(matrix.os, 'macos')}}
|
|
||||||
run: |
|
|
||||||
echo "Test lldb with llgo plugin on ${{matrix.os}} with LLVM ${{matrix.llvm}}"
|
|
||||||
bash _lldb/runtest.sh -v
|
|
||||||
|
|
||||||
test:
|
|
||||||
continue-on-error: true
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os:
|
|
||||||
- macos-latest
|
|
||||||
- ubuntu-24.04
|
|
||||||
llvm: [19]
|
|
||||||
go: ["1.24.2"]
|
|
||||||
runs-on: ${{matrix.os}}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install dependencies
|
|
||||||
uses: ./.github/actions/setup-deps
|
|
||||||
with:
|
|
||||||
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 for build
|
|
||||||
uses: ./.github/actions/setup-go
|
|
||||||
with:
|
|
||||||
go-version: "1.24.2"
|
|
||||||
|
|
||||||
- name: Install
|
|
||||||
run: |
|
|
||||||
go install ./...
|
|
||||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Go for testing
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ${{matrix.go}}
|
|
||||||
|
|
||||||
- name: run llgo test
|
|
||||||
run: |
|
|
||||||
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.2"]
|
|
||||||
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.2"
|
|
||||||
|
|
||||||
- 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:
|
|
||||||
go-version: ${{matrix.go}}
|
|
||||||
|
|
||||||
- name: Test Hello World with go.mod 1.21
|
|
||||||
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
|
|
||||||
with:
|
|
||||||
go-version: ${{matrix.go}}
|
|
||||||
mod-version: "1.21"
|
|
||||||
|
|
||||||
- name: Test Hello World with go.mod 1.22
|
|
||||||
if: startsWith(matrix.go, '1.22') || startsWith(matrix.go, '1.23') || startsWith(matrix.go, '1.24')
|
|
||||||
uses: ./.github/actions/test-helloworld
|
|
||||||
with:
|
|
||||||
go-version: ${{matrix.go}}
|
|
||||||
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"
|
|
||||||
|
|
||||||
cross-compile:
|
|
||||||
continue-on-error: true
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [macos-latest]
|
|
||||||
llvm: [19]
|
|
||||||
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 for building llgo
|
|
||||||
uses: ./.github/actions/setup-go
|
|
||||||
with:
|
|
||||||
go-version: "1.24.2"
|
|
||||||
|
|
||||||
- name: Install wamr
|
|
||||||
run: |
|
|
||||||
git clone https://github.com/bytecodealliance/wasm-micro-runtime.git
|
|
||||||
mkdir wasm-micro-runtime/product-mini/platforms/darwin/build
|
|
||||||
cd wasm-micro-runtime/product-mini/platforms/darwin/build
|
|
||||||
cmake -D WAMR_BUILD_EXCE_HANDLING=1 -D WAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_SHARED_MEMORY=1 -DWAMR_BUILD_LIB_WASI_THREADS=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_DEBUG_INTERP=1 ..
|
|
||||||
make -j8
|
|
||||||
echo "$PWD" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Install llgo
|
|
||||||
run: |
|
|
||||||
go install ./...
|
|
||||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Test Cross Compilation (wasm)
|
|
||||||
shell: bash
|
|
||||||
working-directory: _demo
|
|
||||||
run: |
|
|
||||||
echo "Testing cross-compilation wasm with Go 1.24.2"
|
|
||||||
|
|
||||||
# Compile for wasm architecture
|
|
||||||
GOOS=wasip1 GOARCH=wasm llgo build -o hello -tags=nogc -v ./helloc
|
|
||||||
|
|
||||||
# Check file type
|
|
||||||
file hello.wasm
|
|
||||||
|
|
||||||
# Run the wasm binary using llgo_wasm
|
|
||||||
iwasm --stack-size=819200000 --heap-size=800000000 hello.wasm
|
|
||||||
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@19
|
DARWIN_AMD64_LLVM_PREFIX=.sysroot/darwin/amd64/usr/local/opt/llvm@18
|
||||||
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@19
|
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@18
|
||||||
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@19.json > "${BREW_LLVM_FORMULA_JSON}"
|
curl -fsSL https://formulae.brew.sh/api/formula/llvm.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)-19 main" | tee /etc/apt/sources.list.d/llvm.list
|
echo "deb http://apt.llvm.org/\$(lsb_release -cs)/ llvm-toolchain-\$(lsb_release -cs)-18 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-19-dev
|
apt-get install -y llvm-18-dev
|
||||||
|
|
||||||
error() {
|
error() {
|
||||||
echo -e "\$1" >&2
|
echo -e "\$1" >&2
|
||||||
@@ -106,6 +106,7 @@ 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)
|
||||||
@@ -138,8 +139,5 @@ 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
|
|
||||||
|
|||||||
4
.github/workflows/release-build.yml
vendored
4
.github/workflows/release-build.yml
vendored
@@ -32,11 +32,9 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.24.x
|
go-version: 1.20.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:
|
||||||
|
|||||||
6
.github/workflows/test_demo.sh
vendored
6
.github/workflows/test_demo.sh
vendored
@@ -1,13 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# llgo run subdirectories under _demo and _pydemo that contain *.go files
|
# llgo run subdirectories under _demo and _pydemo
|
||||||
total=0
|
total=0
|
||||||
failed=0
|
failed=0
|
||||||
failed_cases=""
|
failed_cases=""
|
||||||
for d in ./_demo/* ./_pydemo/*; do
|
for d in ./_demo/* ./_pydemo/*; do
|
||||||
if [ -d "$d" ] && [ -n "$(ls "$d"/*.go 2>/dev/null)" ]; then
|
total=$((total+1))
|
||||||
total=$((total+1))
|
if [ -d "$d" ]; then
|
||||||
echo "Testing $d"
|
echo "Testing $d"
|
||||||
if ! (cd "$d" && llgo run .); then
|
if ! (cd "$d" && llgo run .); then
|
||||||
echo "FAIL"
|
echo "FAIL"
|
||||||
|
|||||||
36
.github/workflows/test_llgo.sh
vendored
Normal file
36
.github/workflows/test_llgo.sh
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/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
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -22,14 +22,10 @@ _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
|
||||||
|
|
||||||
# Debug symbols
|
|
||||||
*.dSYM
|
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
*.swp
|
*.swp
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "c/llama2/llama2.c"]
|
||||||
|
path = c/llama2/llama2.c
|
||||||
|
url = https://github.com/karpathy/llama2.c.git
|
||||||
|
|||||||
@@ -17,69 +17,65 @@ before:
|
|||||||
builds:
|
builds:
|
||||||
- id: llgo-darwin-amd64
|
- id: llgo-darwin-amd64
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
|
||||||
flags:
|
flags:
|
||||||
- -tags=darwin,amd64,byollvm
|
- -tags=darwin,amd64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@19/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@18/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@19/include -mmacosx-version-min=10.13 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
- 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_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
|
- 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
|
||||||
targets:
|
targets:
|
||||||
- darwin_amd64
|
- darwin_amd64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
- id: llgo-darwin-arm64
|
- id: llgo-darwin-arm64
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
|
||||||
flags:
|
flags:
|
||||||
- -tags=darwin,arm64,byollvm
|
- -tags=darwin,arm64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@19/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@18/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@19/include -mmacosx-version-min=10.13 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
- 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_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
|
- 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
|
||||||
targets:
|
targets:
|
||||||
- darwin_arm64
|
- darwin_arm64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
- id: llgo-linux-amd64
|
- id: llgo-linux-amd64
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
|
||||||
flags:
|
flags:
|
||||||
- -tags=linux,amd64,byollvm
|
- -tags=linux,amd64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-19/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/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-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_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_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-19/lib -lLLVM-19
|
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-18/lib -lLLVM-18
|
||||||
targets:
|
targets:
|
||||||
- linux_amd64
|
- linux_amd64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
- id: llgo-linux-arm64
|
- id: llgo-linux-arm64
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
|
||||||
flags:
|
flags:
|
||||||
- -tags=linux,arm64,byollvm
|
- -tags=linux,arm64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
||||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-19/bin/llvm-config
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/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-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_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_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-19/lib -lLLVM-19
|
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-18/lib -lLLVM-18
|
||||||
targets:
|
targets:
|
||||||
- linux_arm64
|
- linux_arm64
|
||||||
mod_timestamp: "{{.CommitTimestamp}}"
|
mod_timestamp: "{{.CommitTimestamp}}"
|
||||||
@@ -92,7 +88,6 @@ archives:
|
|||||||
files:
|
files:
|
||||||
- LICENSE
|
- LICENSE
|
||||||
- README.md
|
- README.md
|
||||||
- runtime
|
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: "{{.ProjectName}}{{.Version}}.checksums.txt"
|
name_template: "{{.ProjectName}}{{.Version}}.checksums.txt"
|
||||||
|
|||||||
188
README.md
188
README.md
@@ -24,35 +24,33 @@ How can these be achieved?
|
|||||||
LLGo := Go + C + Python
|
LLGo := Go + C + Python
|
||||||
```
|
```
|
||||||
|
|
||||||
LLGo is compatible with C and Python through the language's **Application Binary Interface (ABI)**, while LLGo is compatible with Go through its **syntax (source code)**. And here C doesn't just include C, but all languages that are ABI compatible with C, including C/C++, Objective-C, Swift, etc.
|
LLGo is compatible with C and Python through the language's **Application Binary Interface (ABI)**, while LLGo is compatible with Go through its **syntax (source code)**.
|
||||||
|
|
||||||
|
|
||||||
## C/C++ standard libary support
|
## C/C++ standard libary support
|
||||||
|
|
||||||
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/lib/c)
|
* [c](https://pkg.go.dev/github.com/goplus/llgo/c)
|
||||||
* [c/syscall](https://pkg.go.dev/github.com/goplus/lib/c/syscall)
|
* [c/syscall](https://pkg.go.dev/github.com/goplus/llgo/c/syscall)
|
||||||
* [c/sys](https://pkg.go.dev/github.com/goplus/lib/c/sys)
|
* [c/sys](https://pkg.go.dev/github.com/goplus/llgo/c/sys)
|
||||||
* [c/os](https://pkg.go.dev/github.com/goplus/lib/c/os)
|
* [c/os](https://pkg.go.dev/github.com/goplus/llgo/c/os)
|
||||||
* [c/math](https://pkg.go.dev/github.com/goplus/lib/c/math)
|
* [c/math](https://pkg.go.dev/github.com/goplus/llgo/c/math)
|
||||||
* [c/math/cmplx](https://pkg.go.dev/github.com/goplus/lib/c/math/cmplx)
|
* [c/math/cmplx](https://pkg.go.dev/github.com/goplus/llgo/c/math/cmplx)
|
||||||
* [c/math/rand](https://pkg.go.dev/github.com/goplus/lib/c/math/rand)
|
* [c/math/rand](https://pkg.go.dev/github.com/goplus/llgo/c/math/rand)
|
||||||
* [c/pthread](https://pkg.go.dev/github.com/goplus/lib/c/pthread)
|
* [c/pthread](https://pkg.go.dev/github.com/goplus/llgo/c/pthread)
|
||||||
* [c/pthread/sync](https://pkg.go.dev/github.com/goplus/lib/c/pthread/sync)
|
* [c/pthread/sync](https://pkg.go.dev/github.com/goplus/llgo/c/pthread/sync)
|
||||||
* [c/sync/atomic](https://pkg.go.dev/github.com/goplus/lib/c/sync/atomic)
|
* [c/sync/atomic](https://pkg.go.dev/github.com/goplus/llgo/c/sync/atomic)
|
||||||
* [c/time](https://pkg.go.dev/github.com/goplus/lib/c/time)
|
* [c/time](https://pkg.go.dev/github.com/goplus/llgo/c/time)
|
||||||
* [c/net](https://pkg.go.dev/github.com/goplus/lib/c/net)
|
* [c/net](https://pkg.go.dev/github.com/goplus/llgo/c/net)
|
||||||
* [cpp/std](https://pkg.go.dev/github.com/goplus/lib/cpp/std)
|
* [cpp/std](https://pkg.go.dev/github.com/goplus/llgo/cpp/std)
|
||||||
|
|
||||||
Here is a simple example:
|
Here is a simple example:
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_simple/simple.go -->
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/lib/c"
|
import "github.com/goplus/llgo/c"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c.Printf(c.Str("Hello world\n"))
|
c.Printf(c.Str("Hello world\n"))
|
||||||
@@ -75,12 +73,10 @@ llgo run .
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## How to support C/C++ and Python
|
## How support C/C++ and Python
|
||||||
|
|
||||||
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_call_c/call_c.go#L3-L6 -->
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import _ "unsafe" // for go:linkname
|
import _ "unsafe" // for go:linkname
|
||||||
|
|
||||||
@@ -90,8 +86,6 @@ func Sqrt(x float64) float64
|
|||||||
|
|
||||||
You can directly integrate it into [your own code](_demo/linkname/linkname.go):
|
You can directly integrate it into [your own code](_demo/linkname/linkname.go):
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_call_c/call_c.go -->
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -105,14 +99,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Or put it into a package (see [c/math](https://github.com/goplus/lib/tree/main/c/math/math.go)):
|
Or put it into a package (see [c/math](c/math/math.go)):
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_call_cmath/call_cmath.go -->
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/lib/c/math"
|
import "github.com/goplus/llgo/c/math"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("sqrt(2) =", math.Sqrt(2))
|
println("sqrt(2) =", math.Sqrt(2))
|
||||||
@@ -126,32 +118,30 @@ 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/lib/py) (abi)
|
* [py](https://pkg.go.dev/github.com/goplus/llgo/py) (abi)
|
||||||
* [py/std](https://pkg.go.dev/github.com/goplus/lib/py/std) (builtins)
|
* [py/std](https://pkg.go.dev/github.com/goplus/llgo/py/std) (builtins)
|
||||||
* [py/sys](https://pkg.go.dev/github.com/goplus/lib/py/sys)
|
* [py/sys](https://pkg.go.dev/github.com/goplus/llgo/py/sys)
|
||||||
* [py/os](https://pkg.go.dev/github.com/goplus/lib/py/os)
|
* [py/os](https://pkg.go.dev/github.com/goplus/llgo/py/os)
|
||||||
* [py/math](https://pkg.go.dev/github.com/goplus/lib/py/math)
|
* [py/math](https://pkg.go.dev/github.com/goplus/llgo/py/math)
|
||||||
* [py/json](https://pkg.go.dev/github.com/goplus/lib/py/json)
|
* [py/json](https://pkg.go.dev/github.com/goplus/llgo/py/json)
|
||||||
* [py/inspect](https://pkg.go.dev/github.com/goplus/lib/py/inspect)
|
* [py/inspect](https://pkg.go.dev/github.com/goplus/llgo/py/inspect)
|
||||||
* [py/statistics](https://pkg.go.dev/github.com/goplus/lib/py/statistics)
|
* [py/statistics](https://pkg.go.dev/github.com/goplus/llgo/py/statistics)
|
||||||
* [py/numpy](https://pkg.go.dev/github.com/goplus/lib/py/numpy)
|
* [py/numpy](https://pkg.go.dev/github.com/goplus/llgo/py/numpy)
|
||||||
* [py/pandas](https://pkg.go.dev/github.com/goplus/lib/py/pandas)
|
* [py/pandas](https://pkg.go.dev/github.com/goplus/llgo/py/pandas)
|
||||||
* [py/torch](https://pkg.go.dev/github.com/goplus/lib/py/torch)
|
* [py/torch](https://pkg.go.dev/github.com/goplus/llgo/py/torch)
|
||||||
* [py/matplotlib](https://pkg.go.dev/github.com/goplus/lib/py/matplotlib)
|
* [py/matplotlib](https://pkg.go.dev/github.com/goplus/llgo/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.
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_call_py/call_py.go -->
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/math"
|
"github.com/goplus/llgo/py/math"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -162,8 +152,6 @@ func main() {
|
|||||||
|
|
||||||
It is equivalent to the following Python code:
|
It is equivalent to the following Python code:
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_call_py/call_math.py -->
|
|
||||||
|
|
||||||
```py
|
```py
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@@ -175,15 +163,13 @@ Here, We call `py.Float(2)` to create a Python number 2, and pass it to Python
|
|||||||
|
|
||||||
Let's look at a slightly more complex example. For example, we use `numpy` to calculate:
|
Let's look at a slightly more complex example. For example, we use `numpy` to calculate:
|
||||||
|
|
||||||
<!-- embedme doc/_readme/llgo_py_list/py_list.go -->
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/numpy"
|
"github.com/goplus/llgo/py/numpy"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -225,32 +211,31 @@ 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/lib/c/bdwgc)
|
* [c/bdwgc](https://pkg.go.dev/github.com/goplus/llgo/c/bdwgc)
|
||||||
* [c/cjson](https://pkg.go.dev/github.com/goplus/lib/c/cjson)
|
* [c/cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
|
||||||
* [c/clang](https://pkg.go.dev/github.com/goplus/lib/c/clang)
|
* [c/clang](https://pkg.go.dev/github.com/goplus/llgo/c/clang)
|
||||||
* [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](https://github.com/goplus/lib/tree/main/c/cjson/_demo/mkjson/mkjson.go): create a json object and print it
|
* [mkjson](c/cjson/_demo/mkjson/mkjson.go): create a json object and print it
|
||||||
* [sqlitedemo](https://github.com/goplus/lib/tree/main/c/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
|
* [sqlitedemo](c/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
|
||||||
* [tetris](https://github.com/goplus/lib/tree/main/c/raylib/_demo/tetris/tetris.go): a tetris game based on raylib
|
* [tetris](c/raylib/_demo/tetris/tetris.go): a tetris game based on raylib
|
||||||
|
|
||||||
|
|
||||||
## Go syntax support
|
## Go syntax support
|
||||||
|
|
||||||
All Go syntax (including `cgo`) is already supported. Here are some examples:
|
All Go syntax (not including `cgo`) is already supported. Here are some examples:
|
||||||
|
|
||||||
* [concat](_demo/concat/concat.go): define a variadic function
|
* [concat](_demo/concat/concat.go): define a variadic function
|
||||||
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
|
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
|
||||||
@@ -318,7 +303,6 @@ Here are the Go packages that can be imported correctly:
|
|||||||
* [encoding/base32](https://pkg.go.dev/encoding/base32)
|
* [encoding/base32](https://pkg.go.dev/encoding/base32)
|
||||||
* [encoding/base64](https://pkg.go.dev/encoding/base64)
|
* [encoding/base64](https://pkg.go.dev/encoding/base64)
|
||||||
* [encoding/csv](https://pkg.go.dev/encoding/csv)
|
* [encoding/csv](https://pkg.go.dev/encoding/csv)
|
||||||
* [net/textproto](https://pkg.go.dev/net/textproto)
|
|
||||||
* [hash](https://pkg.go.dev/hash)
|
* [hash](https://pkg.go.dev/hash)
|
||||||
* [hash/adler32](https://pkg.go.dev/hash/adler32)
|
* [hash/adler32](https://pkg.go.dev/hash/adler32)
|
||||||
* [hash/crc32](https://pkg.go.dev/hash/crc32) (partially)
|
* [hash/crc32](https://pkg.go.dev/hash/crc32) (partially)
|
||||||
@@ -328,9 +312,7 @@ Here are the Go packages that can be imported correctly:
|
|||||||
* [crypto/sha1](https://pkg.go.dev/crypto/sha1)
|
* [crypto/sha1](https://pkg.go.dev/crypto/sha1)
|
||||||
* [crypto/sha256](https://pkg.go.dev/crypto/sha256)
|
* [crypto/sha256](https://pkg.go.dev/crypto/sha256)
|
||||||
* [crypto/sha512](https://pkg.go.dev/crypto/sha512) (partially)
|
* [crypto/sha512](https://pkg.go.dev/crypto/sha512) (partially)
|
||||||
* [crypto/hmac](https://pkg.go.dev/crypto/hmac) (partially)
|
|
||||||
* [crypto/rand](https://pkg.go.dev/crypto/rand) (partially)
|
* [crypto/rand](https://pkg.go.dev/crypto/rand) (partially)
|
||||||
* [crypto/subtle](https://pkg.go.dev/crypto/subtle) (partially)
|
|
||||||
* [regexp](https://pkg.go.dev/regexp)
|
* [regexp](https://pkg.go.dev/regexp)
|
||||||
* [regexp/syntax](https://pkg.go.dev/regexp/syntax)
|
* [regexp/syntax](https://pkg.go.dev/regexp/syntax)
|
||||||
* [go/token](https://pkg.go.dev/go/token)
|
* [go/token](https://pkg.go.dev/go/token)
|
||||||
@@ -339,15 +321,15 @@ Here are the Go packages that can be imported correctly:
|
|||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- [Go 1.21+](https://go.dev)
|
- [Go 1.20+](https://go.dev)
|
||||||
- [LLVM 18](https://llvm.org)
|
- [LLVM 18](https://llvm.org)
|
||||||
- [Clang 18](https://clang.llvm.org)
|
|
||||||
- [LLD 18](https://lld.llvm.org)
|
- [LLD 18](https://lld.llvm.org)
|
||||||
|
- [Clang 18](https://clang.llvm.org)
|
||||||
- [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
- [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||||
- [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/lib/py](https://pkg.go.dev/github.com/goplus/lib/py))
|
- [Python 3.12+](https://www.python.org) (optional, for [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py))
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|
||||||
@@ -355,63 +337,32 @@ Follow these steps to generate the `llgo` command (its usage is the same as the
|
|||||||
|
|
||||||
### on macOS
|
### on macOS
|
||||||
|
|
||||||
<!-- embedme doc/_readme/scripts/install_macos.sh#L2-L1000 -->
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew update
|
brew update
|
||||||
brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config
|
brew install llvm@18 pkg-config bdw-gc openssl
|
||||||
brew install python@3.12 # optional
|
brew install python@3.12 # optional
|
||||||
brew link --overwrite llvm@19 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 (Debian/Ubuntu)
|
||||||
|
|
||||||
#### Debian/Ubuntu
|
|
||||||
|
|
||||||
<!-- 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)-19 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-18 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
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-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 llvm-18-dev clang-18 lld-18 pkg-config libgc-dev libssl-dev zlib1g-dev
|
||||||
sudo apt-get install -y python3.12-dev # optional
|
sudo apt-get install -y python3.12-dev # optional
|
||||||
#curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash
|
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||||
./install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Alpine Linux
|
|
||||||
|
|
||||||
```sh
|
|
||||||
apk add go llvm18-dev clang18-dev lld18 pkgconf gc-dev openssl-dev zlib-dev
|
|
||||||
apk add python3-dev # optional
|
|
||||||
apk add g++ # build only
|
|
||||||
export LLVM_CONFIG=/usr/lib/llvm18/bin/llvm-config
|
|
||||||
export CGO_CPPFLAGS="$($LLVM_CONFIG --cppflags)"
|
|
||||||
export CGO_CXXFLAGS=-std=c++17
|
|
||||||
export CGO_LDFLAGS="$($LLVM_CONFIG --ldflags) $($LLVM_CONFIG --libs all)"
|
|
||||||
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](_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](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`.
|
||||||
* [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).
|
||||||
@@ -419,24 +370,19 @@ cd llgo
|
|||||||
|
|
||||||
How do I generate these tools?
|
How do I generate these tools?
|
||||||
|
|
||||||
<!-- 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
|
cd llgo
|
||||||
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
|
cd chore/_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`:
|
||||||
|
|
||||||
* [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/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`.
|
||||||
* [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/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`.
|
||||||
* [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`.
|
* [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`.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fib() {
|
func main() {
|
||||||
// Initialize two big ints with the first two numbers in the sequence.
|
// Initialize two big ints with the first two numbers in the sequence.
|
||||||
a := big.NewInt(0)
|
a := big.NewInt(0)
|
||||||
b := big.NewInt(1)
|
b := big.NewInt(1)
|
||||||
@@ -23,41 +23,3 @@ func fib() {
|
|||||||
}
|
}
|
||||||
fmt.Println(a) // 100-digit Fibonacci number
|
fmt.Println(a) // 100-digit Fibonacci number
|
||||||
}
|
}
|
||||||
|
|
||||||
func abs() {
|
|
||||||
a := big.NewInt(64)
|
|
||||||
b := big.NewInt(-52)
|
|
||||||
a.Set(b)
|
|
||||||
a.Abs(a)
|
|
||||||
a.Set(big.NewInt(-164))
|
|
||||||
a.Abs(a)
|
|
||||||
fmt.Println("value: ", a.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func neg() {
|
|
||||||
fmt.Println("value: ", big.NewInt(-64).Neg(big.NewInt(-64)))
|
|
||||||
fmt.Println("value: ", big.NewInt(64).Neg(big.NewInt(64)))
|
|
||||||
fmt.Println("value: ", big.NewInt(0).Neg(big.NewInt(0)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func calc() {
|
|
||||||
a := big.NewInt(64)
|
|
||||||
b := big.NewInt(-52)
|
|
||||||
c := big.NewInt(54)
|
|
||||||
fmt.Println("value:", a.Add(a, b))
|
|
||||||
fmt.Println("value:", a.Sub(b, c))
|
|
||||||
d := big.NewInt(10)
|
|
||||||
e := big.NewInt(4)
|
|
||||||
fmt.Println("value:", d.Mul(d, e))
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitop() {
|
|
||||||
a := big.NewInt(4)
|
|
||||||
fmt.Println("value:", a.Lsh(a, 1))
|
|
||||||
b := big.NewInt(16)
|
|
||||||
fmt.Println("value:", b.Rsh(b, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
bitop()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha1"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
h := hmac.New(sha1.New, []byte("<key>"))
|
|
||||||
io.WriteString(h, "The fog is getting thicker!")
|
|
||||||
io.WriteString(h, "And Leon's getting laaarger!")
|
|
||||||
fmt.Printf("%x", h.Sum(nil))
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package async
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Void = [0]byte
|
|
||||||
|
|
||||||
type Future[T any] interface {
|
|
||||||
Then(cb func(T))
|
|
||||||
}
|
|
||||||
|
|
||||||
type future[T any] struct {
|
|
||||||
cb func(func(T))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *future[T]) Then(cb func(T)) {
|
|
||||||
f.cb(cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Async[T any](fn func(func(T))) Future[T] {
|
|
||||||
return &future[T]{fn}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run[T any](future Future[T]) T {
|
|
||||||
var ret T
|
|
||||||
future.Then(func(v T) {
|
|
||||||
ret = v
|
|
||||||
})
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/_demo/async/async"
|
|
||||||
"github.com/goplus/llgo/_demo/async/timeout"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Sleep(i int, d time.Duration) async.Future[int] {
|
|
||||||
return async.Async(func(resolve func(int)) {
|
|
||||||
timeout.Timeout(d).Then(func(async.Void) {
|
|
||||||
resolve(i)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
async.Run(async.Async(func(resolve func(async.Void)) {
|
|
||||||
println("read file")
|
|
||||||
defer resolve(async.Void{})
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package timeout
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/_demo/async/async"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Timeout(d time.Duration) async.Future[async.Void] {
|
|
||||||
return async.Async(func(resolve func(async.Void)) {
|
|
||||||
go func() {
|
|
||||||
time.Sleep(d)
|
|
||||||
resolve(async.Void{})
|
|
||||||
}()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c/sync/atomic"
|
"github.com/goplus/llgo/c/sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/runtime/internal/runtime"
|
"github.com/goplus/llgo/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/runtime/internal/runtime"
|
"github.com/goplus/llgo/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/os"
|
"github.com/goplus/llgo/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -DBAR
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "foo.h"
|
|
||||||
static void foo(Foo* f) {
|
|
||||||
printf("foo in bar: %d\n", f->a);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Bar(f *C.Foo) {
|
|
||||||
C.print_foo(f)
|
|
||||||
C.foo(f)
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo windows,!amd64 CFLAGS: -D_WIN32
|
|
||||||
#cgo !windows CFLAGS: -D_POSIX
|
|
||||||
#cgo windows,amd64 CFLAGS: -D_WIN64
|
|
||||||
#cgo linux,amd64 CFLAGS: -D_LINUX64
|
|
||||||
#cgo !windows,amd64 CFLAGS: -D_UNIX64
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <Python.h>
|
|
||||||
#include "foo.h"
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
} s4;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
} s8;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
} s12;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
int d;
|
|
||||||
} s16;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
int d;
|
|
||||||
int e;
|
|
||||||
} s20;
|
|
||||||
|
|
||||||
static int test_structs(s4* s4, s8* s8, s12* s12, s16* s16, s20* s20) {
|
|
||||||
printf("s4.a: %d\n", s4->a);
|
|
||||||
printf("s8.a: %d, s8.b: %d\n", s8->a, s8->b);
|
|
||||||
printf("s12.a: %d, s12.b: %d, s12.c: %d\n", s12->a, s12->b, s12->c);
|
|
||||||
printf("s16.a: %d, s16.b: %d, s16.c: %d, s16.d: %d\n", s16->a, s16->b, s16->c, s16->d);
|
|
||||||
printf("s20.a: %d, s20.b: %d, s20.c: %d, s20.d: %d, s20.e: %d\n", s20->a, s20->b, s20->c, s20->d, s20->e);
|
|
||||||
|
|
||||||
return s4->a + s8->a + s8->b + s12->a + s12->b + s12->c + s16->a + s16->b + s16->c + s16->d + s20->a + s20->b + s20->c + s20->d + s20->e;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_macros() {
|
|
||||||
#ifdef FOO
|
|
||||||
printf("FOO is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef BAR
|
|
||||||
printf("BAR is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
printf("WIN32 is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _POSIX
|
|
||||||
printf("POSIX is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN64
|
|
||||||
printf("WIN64 is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _LINUX64
|
|
||||||
printf("LINUX64 is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _UNIX64
|
|
||||||
printf("UNIX64 is defined\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MY_VERSION "1.0.0"
|
|
||||||
#define MY_CODE 0x12345678
|
|
||||||
|
|
||||||
static void test_void() {
|
|
||||||
printf("test_void\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int (*Cb)(int);
|
|
||||||
|
|
||||||
extern int go_callback(int);
|
|
||||||
|
|
||||||
extern int c_callback(int i);
|
|
||||||
|
|
||||||
static void test_callback(Cb cb) {
|
|
||||||
printf("test_callback, cb: %p, go_callback: %p, c_callback: %p\n", cb, go_callback, c_callback);
|
|
||||||
printf("test_callback, *cb: %p, *go_callback: %p, *c_callback: %p\n", *(void**)cb, *(void**)(go_callback), *(void**)(c_callback));
|
|
||||||
printf("cb result: %d\n", cb(123));
|
|
||||||
printf("done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int go_callback_not_use_in_go(int);
|
|
||||||
|
|
||||||
static void run_callback() {
|
|
||||||
test_callback(c_callback);
|
|
||||||
test_callback(go_callback_not_use_in_go);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/_demo/cgofull/pymod1"
|
|
||||||
"github.com/goplus/llgo/_demo/cgofull/pymod2"
|
|
||||||
)
|
|
||||||
|
|
||||||
//export go_callback_not_use_in_go
|
|
||||||
func go_callback_not_use_in_go(i C.int) C.int {
|
|
||||||
return i + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
//export go_callback
|
|
||||||
func go_callback(i C.int) C.int {
|
|
||||||
return i + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
runPy()
|
|
||||||
f := &C.Foo{a: 1}
|
|
||||||
Foo(f)
|
|
||||||
Bar(f)
|
|
||||||
C.test_macros()
|
|
||||||
r := C.test_structs(&C.s4{a: 1}, &C.s8{a: 1, b: 2}, &C.s12{a: 1, b: 2, c: 3}, &C.s16{a: 1, b: 2, c: 3, d: 4}, &C.s20{a: 1, b: 2, c: 3, d: 4, e: 5})
|
|
||||||
fmt.Println(r)
|
|
||||||
if r != 35 {
|
|
||||||
panic("test_structs failed")
|
|
||||||
}
|
|
||||||
fmt.Println(C.MY_VERSION)
|
|
||||||
fmt.Println(int(C.MY_CODE))
|
|
||||||
C.test_void()
|
|
||||||
|
|
||||||
println("call run_callback")
|
|
||||||
C.run_callback()
|
|
||||||
|
|
||||||
// test _Cgo_ptr and _cgoCheckResult
|
|
||||||
println("call with go_callback")
|
|
||||||
C.test_callback((C.Cb)(C.go_callback))
|
|
||||||
|
|
||||||
println("call with c_callback")
|
|
||||||
C.test_callback((C.Cb)(C.c_callback))
|
|
||||||
}
|
|
||||||
|
|
||||||
func runPy() {
|
|
||||||
Initialize()
|
|
||||||
defer Finalize()
|
|
||||||
Run("print('Hello, Python!')")
|
|
||||||
C.PyObject_Print((*C.PyObject)(unsafe.Pointer(pymod1.Float(1.23))), C.stderr, 0)
|
|
||||||
C.PyObject_Print((*C.PyObject)(unsafe.Pointer(pymod2.Long(123))), C.stdout, 0)
|
|
||||||
// test _Cgo_use
|
|
||||||
C.PyObject_Print((*C.PyObject)(unsafe.Pointer(C.PyComplex_FromDoubles(C.double(1.23), C.double(4.56)))), C.stdout, 0)
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "foo.h"
|
|
||||||
|
|
||||||
void print_foo(Foo *f)
|
|
||||||
{
|
|
||||||
printf("print_foo: %d\n", f->a);
|
|
||||||
}
|
|
||||||
|
|
||||||
int c_callback(int i)
|
|
||||||
{
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -DFOO
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "foo.h"
|
|
||||||
static void foo(Foo* f) {
|
|
||||||
printf("foo in bar: %d\n", f->a);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Foo(f *C.Foo) {
|
|
||||||
C.print_foo(f)
|
|
||||||
C.foo(f)
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
} Foo;
|
|
||||||
|
|
||||||
extern void print_foo(Foo* f);
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <Python.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func Initialize() {
|
|
||||||
C.Py_Initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Finalize() {
|
|
||||||
C.Py_Finalize()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run(code string) error {
|
|
||||||
if C.PyRun_SimpleString(C.CString(code)) != 0 {
|
|
||||||
C.PyErr_Print()
|
|
||||||
return fmt.Errorf("failed to run code")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package pymod1
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <Python.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Float(f float64) *C.PyObject {
|
|
||||||
return C.PyFloat_FromDouble(C.double(f))
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package pymod2
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <Python.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Long(l int64) *C.PyObject {
|
|
||||||
return C.PyLong_FromLongLong(C.longlong(l))
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tempDir := os.TempDir()
|
|
||||||
noexist := filepath.Join(tempDir, "noexist.txt")
|
|
||||||
|
|
||||||
if _, err := os.Stat(noexist); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
fmt.Println("noexist:", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println("exist,other err:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Open(noexist); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
fmt.Println("noexist:", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println("exist,other err:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var data bytes.Buffer
|
|
||||||
cmd := exec.Command("echo", "hello llgo")
|
|
||||||
cmd.Stdout = &data
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
println("len:", len(data.Bytes()))
|
|
||||||
println("data:", data.String())
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/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/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/math/rand"
|
"github.com/goplus/llgo/c/math/rand"
|
||||||
"github.com/goplus/lib/c/time"
|
"github.com/goplus/llgo/c/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fastrand64() uint64 {
|
func fastrand64() uint64 {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/lib/c/time"
|
import "github.com/goplus/llgo/c/time"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var tv time.Timespec
|
var tv time.Timespec
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
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,42 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MyStruct[T any] struct {
|
|
||||||
value T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MyStruct[T]) Method() {
|
|
||||||
fmt.Println("In generic method")
|
|
||||||
genericFunc[T](m.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func genericFunc[T any](v T) {
|
|
||||||
fmt.Println("In generic function")
|
|
||||||
normalFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalFunc() {
|
|
||||||
fmt.Println("In normal function")
|
|
||||||
panic("panic occurs here")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
m := &MyStruct[string]{value: "hello"}
|
|
||||||
m.Method()
|
|
||||||
}
|
|
||||||
|
|
||||||
//Expected:
|
|
||||||
// In generic method
|
|
||||||
// In generic function
|
|
||||||
// In normal function
|
|
||||||
// panic: panic occurs here
|
|
||||||
|
|
||||||
// [0x00C6D310 github.com/goplus/llgo/internal/runtime.Rethrow+0x2f, SP = 0x60]
|
|
||||||
// [0x00C6CF44 github.com/goplus/llgo/internal/runtime.Panic+0x2d, SP = 0x50]
|
|
||||||
// [0x00C69420 main.normalFunc+0xf, SP = 0xa8]
|
|
||||||
// [0x00C69564 main.genericFunc[string]+0x18, SP = 0x74]
|
|
||||||
// [0x00C694A8 main.(*MyStruct[string]).Method+0x1f, SP = 0x84]
|
|
||||||
// [0x00C6936C main+0x4, SP = 0x40]
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
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() {
|
||||||
@@ -46,6 +45,8 @@ 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/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
type generator struct {
|
type generator struct {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/os"
|
"github.com/goplus/llgo/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
module github.com/goplus/llgo/_demo
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require github.com/goplus/lib v0.2.0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
|
||||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/goplus/llgo/c"
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("hello world by println")
|
c.Printf(c.Str("Hello world\n"))
|
||||||
fmt.Println("hello world by fmt.Println")
|
|
||||||
c.Printf(c.Str("Hello world by c.Printf\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expected output:
|
/* Expected output:
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
c.Printf(c.Str("Hello world by c.Printf\n"))
|
|
||||||
c.Printf(c.Str("%ld\n"), unsafe.Sizeof(int(0)))
|
|
||||||
c.Printf(c.Str("%ld\n"), unsafe.Sizeof(uintptr(0)))
|
|
||||||
// var v any = int(0)
|
|
||||||
// c.Printf(c.Str("%ld\n"), unsafe.Sizeof(v))
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/llama2"
|
"github.com/goplus/llgo/c/llama2"
|
||||||
"github.com/goplus/lib/c/time"
|
"github.com/goplus/llgo/c/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "net/textproto"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
h := make(textproto.MIMEHeader)
|
|
||||||
h.Set("host", "www.example.com")
|
|
||||||
println(h.Get("Host"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expected output:
|
|
||||||
www.example.com
|
|
||||||
*/
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tempDir, err := os.MkdirTemp("", "example*")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to create temp directory:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(tempDir)
|
|
||||||
fmt.Println("Temp directory:", tempDir)
|
|
||||||
|
|
||||||
tempFile, err := os.CreateTemp("", "example*.txt")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to create temp file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer tempFile.Close()
|
|
||||||
defer os.Remove(tempFile.Name())
|
|
||||||
fmt.Println("Temp file:", tempFile.Name())
|
|
||||||
|
|
||||||
nestedDir := filepath.Join("nested", "directory")
|
|
||||||
err = os.MkdirAll(nestedDir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to create nested directory:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("Nest directory:", nestedDir)
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/net"
|
"github.com/goplus/llgo/c/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func add(a, b int) int {
|
|
||||||
return a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fn := func(a, b int) int {
|
|
||||||
return a + b
|
|
||||||
}
|
|
||||||
var i int
|
|
||||||
fn1 := func() {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
fn2 := func() func() {
|
|
||||||
return func() {
|
|
||||||
println("closure", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fns := []any{add, fn, fn1, fn2}
|
|
||||||
for _, fn := range fns {
|
|
||||||
v := reflect.ValueOf(fn)
|
|
||||||
fmt.Println(v.Type())
|
|
||||||
fmt.Println(v.Kind())
|
|
||||||
if v.Kind() != reflect.Func {
|
|
||||||
panic(fmt.Sprintf("not func: %T", fn))
|
|
||||||
}
|
|
||||||
|
|
||||||
t := v.Type()
|
|
||||||
fmt.Println(t)
|
|
||||||
fmt.Println(t.Kind())
|
|
||||||
if t.Kind() != reflect.Func {
|
|
||||||
panic(fmt.Sprintf("not func: %T", fn))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c/setjmp"
|
"github.com/goplus/llgo/c/setjmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/net"
|
"github.com/goplus/llgo/c/net"
|
||||||
"github.com/goplus/lib/c/os"
|
"github.com/goplus/llgo/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/net"
|
"github.com/goplus/llgo/c/net"
|
||||||
"github.com/goplus/lib/c/os"
|
"github.com/goplus/llgo/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
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))
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
llsync "github.com/goplus/lib/c/pthread/sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type L struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
s string
|
|
||||||
i int
|
|
||||||
w io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
l := &L{s: "hello", i: 123, w: os.Stdout}
|
|
||||||
println("sizeof(L):", unsafe.Sizeof(L{}))
|
|
||||||
println("sizeof(sync.Mutex):", unsafe.Sizeof(sync.Mutex{}))
|
|
||||||
println("sizeof(llsync.Mutex):", unsafe.Sizeof(llsync.Mutex{}))
|
|
||||||
println("l:", l, "l.s:", l.s, "l.i:", l.i, "l.w:", l.w)
|
|
||||||
l.mu.Lock()
|
|
||||||
println("locked")
|
|
||||||
println("l:", l, "l.s:", l.s, "l.i:", l.i, "l.w:", l.w)
|
|
||||||
l.w.Write([]byte(l.s))
|
|
||||||
l.w.Write([]byte("\n"))
|
|
||||||
l.mu.Unlock()
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/pthread"
|
"github.com/goplus/llgo/c/pthread"
|
||||||
)
|
)
|
||||||
|
|
||||||
var key pthread.Key
|
var key pthread.Key
|
||||||
|
|||||||
115
_lldb/README.md
115
_lldb/README.md
@@ -1,115 +0,0 @@
|
|||||||
## LLGo Plugin of LLDB
|
|
||||||
|
|
||||||
### Build with debug info
|
|
||||||
|
|
||||||
```shell
|
|
||||||
LLGO_DEBUG_SYMBOLS=1 llgo build -o cl/_testdata/debug/out ./cl/_testdata/debug
|
|
||||||
```
|
|
||||||
|
|
||||||
### Debug with lldb
|
|
||||||
|
|
||||||
```shell
|
|
||||||
_lldb/runlldb.sh ./cl/_testdata/debug/out
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```shell
|
|
||||||
/opt/homebrew/bin/lldb -O "command script import _lldb/llgo_plugin.py" ./cl/_testdata/debug/out
|
|
||||||
# github.com/goplus/llgo/cl/_testdata/debug
|
|
||||||
Breakpoint 1: no locations (pending).
|
|
||||||
Breakpoint set in dummy target, will get copied into future targets.
|
|
||||||
(lldb) command script import _lldb/llgo_plugin.py
|
|
||||||
(lldb) target create "./cl/_testdata/debug/out"
|
|
||||||
Current executable set to '/Users/lijie/source/goplus/llgo/cl/_testdata/debug/out' (arm64).
|
|
||||||
(lldb) r
|
|
||||||
Process 21992 launched: '/Users/lijie/source/goplus/llgo/cl/_testdata/debug/out' (arm64)
|
|
||||||
globalInt: 301
|
|
||||||
s: 0x100123e40
|
|
||||||
0x100123be0
|
|
||||||
5 8
|
|
||||||
called function with struct
|
|
||||||
1 2 3 4 5 6 7 8 9 10 +1.100000e+01 +1.200000e+01 true (+1.300000e+01+1.400000e+01i) (+1.500000e+01+1.600000e+01i) [3/3]0x1001129a0 [3/3]0x100112920 hello 0x1001149b0 0x100123ab0 0x100123d10 0x1001149e0 (0x100116810,0x1001149d0) 0x10011bf00 0x10010fa80 (0x100116840,0x100112940) 0x10001b4a4
|
|
||||||
9
|
|
||||||
1 (0x1001167e0,0x100112900)
|
|
||||||
called function with types
|
|
||||||
0x100123e40
|
|
||||||
0x1000343d0
|
|
||||||
Process 21992 stopped
|
|
||||||
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|
||||||
frame #0: 0x000000010001b3b4 out`main at in.go:225:12
|
|
||||||
222 // s.i8: '\x01'
|
|
||||||
223 // s.i16: 2
|
|
||||||
224 s.i8 = 0x12
|
|
||||||
-> 225 println(s.i8)
|
|
||||||
226 // Expected:
|
|
||||||
227 // all variables: globalInt globalStruct globalStructPtr s i err
|
|
||||||
228 // s.i8: '\x12'
|
|
||||||
(lldb) v
|
|
||||||
var i int = <variable not available>
|
|
||||||
var s github.com/goplus/llgo/cl/_testdata/debug.StructWithAllTypeFields = {
|
|
||||||
i8 = '\x12',
|
|
||||||
i16 = 2,
|
|
||||||
i32 = 3,
|
|
||||||
i64 = 4,
|
|
||||||
i = 5,
|
|
||||||
u8 = '\x06',
|
|
||||||
u16 = 7,
|
|
||||||
u32 = 8,
|
|
||||||
u64 = 9,
|
|
||||||
u = 10,
|
|
||||||
f32 = 11,
|
|
||||||
f64 = 12,
|
|
||||||
b = true,
|
|
||||||
c64 = {real = 13, imag = 14},
|
|
||||||
c128 = {real = 15, imag = 16},
|
|
||||||
slice = []int{21, 22, 23},
|
|
||||||
arr = [3]int{24, 25, 26},
|
|
||||||
arr2 = [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}},
|
|
||||||
s = "hello",
|
|
||||||
e = {i = 30},
|
|
||||||
pf = 0x0000000100123d10,
|
|
||||||
pi = 0x00000001001149e0,
|
|
||||||
intr = {type = 0x0000000100116810, data = 0x00000001001149d0},
|
|
||||||
m = {count = 4296130304},
|
|
||||||
c = {},
|
|
||||||
err = {type = 0x0000000100116840, data = 0x0000000100112940},
|
|
||||||
fn = {f = 0x000000010001b4a4, data = 0x00000001001149c0},
|
|
||||||
pad1 = 100,
|
|
||||||
pad2 = 200
|
|
||||||
}
|
|
||||||
var globalStructPtr *github.com/goplus/llgo/cl/_testdata/debug.StructWithAllTypeFields = <variable not available>
|
|
||||||
var globalStruct github.com/goplus/llgo/cl/_testdata/debug.StructWithAllTypeFields = {
|
|
||||||
i8 = '\x01',
|
|
||||||
i16 = 2,
|
|
||||||
i32 = 3,
|
|
||||||
i64 = 4,
|
|
||||||
i = 5,
|
|
||||||
u8 = '\x06',
|
|
||||||
u16 = 7,
|
|
||||||
u32 = 8,
|
|
||||||
u64 = 9,
|
|
||||||
u = 10,
|
|
||||||
f32 = 11,
|
|
||||||
f64 = 12,
|
|
||||||
b = true,
|
|
||||||
c64 = {real = 13, imag = 14},
|
|
||||||
c128 = {real = 15, imag = 16},
|
|
||||||
slice = []int{21, 22, 23},
|
|
||||||
arr = [3]int{24, 25, 26},
|
|
||||||
arr2 = [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}},
|
|
||||||
s = "hello",
|
|
||||||
e = {i = 30},
|
|
||||||
pf = 0x0000000100123d10,
|
|
||||||
pi = 0x00000001001149e0,
|
|
||||||
intr = {type = 0x0000000100116810, data = 0x00000001001149d0},
|
|
||||||
m = {count = 4296130304},
|
|
||||||
c = {},
|
|
||||||
err = {type = 0x0000000100116840, data = 0x0000000100112940},
|
|
||||||
fn = {f = 0x000000010001b4a4, data = 0x00000001001149c0},
|
|
||||||
pad1 = 100,
|
|
||||||
pad2 = 200
|
|
||||||
}
|
|
||||||
var globalInt int = 301
|
|
||||||
var err error = {type = 0x0000000100112900, data = 0x000000000000001a}
|
|
||||||
```
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Function to find LLDB 18+
|
|
||||||
find_lldb() {
|
|
||||||
local lldb_paths=(
|
|
||||||
"/opt/homebrew/bin/lldb"
|
|
||||||
"/usr/local/bin/lldb"
|
|
||||||
"/usr/bin/lldb"
|
|
||||||
"lldb" # This will use the system PATH
|
|
||||||
)
|
|
||||||
|
|
||||||
for lldb_path in "${lldb_paths[@]}"; do
|
|
||||||
if command -v "$lldb_path" >/dev/null 2>&1; then
|
|
||||||
local version
|
|
||||||
version=$("$lldb_path" --version | grep -oE '[0-9]+' | head -1)
|
|
||||||
if [ "$version" -ge 18 ]; then
|
|
||||||
echo "$lldb_path"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Error: LLDB 18 or higher not found" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Find LLDB 18+
|
|
||||||
LLDB_PATH=$(find_lldb)
|
|
||||||
echo "LLDB_PATH: $LLDB_PATH"
|
|
||||||
$LLDB_PATH --version
|
|
||||||
export LLDB_PATH
|
|
||||||
|
|
||||||
# Default package path
|
|
||||||
export DEFAULT_PACKAGE_PATH="./_lldb/lldbtest"
|
|
||||||
|
|
||||||
# Function to build the project
|
|
||||||
build_project() {
|
|
||||||
# package_path parameter is kept for backward compatibility
|
|
||||||
local current_dir
|
|
||||||
current_dir=$(pwd) || return
|
|
||||||
|
|
||||||
if ! cd "${DEFAULT_PACKAGE_PATH}"; then
|
|
||||||
echo "Failed to change directory to ${DEFAULT_PACKAGE_PATH}" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
LLGO_DEBUG_SYMBOLS=1 llgo build -o "debug.out" . || {
|
|
||||||
local ret=$?
|
|
||||||
cd "$current_dir" || return
|
|
||||||
return $ret
|
|
||||||
}
|
|
||||||
|
|
||||||
cd "$current_dir" || return
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module lldbtest
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
@@ -1,569 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
type Base struct {
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
type E struct {
|
|
||||||
// Base
|
|
||||||
i int
|
|
||||||
}
|
|
||||||
type StructWithAllTypeFields struct {
|
|
||||||
i8 int8
|
|
||||||
i16 int16
|
|
||||||
i32 int32
|
|
||||||
i64 int64
|
|
||||||
i int
|
|
||||||
u8 uint8
|
|
||||||
u16 uint16
|
|
||||||
u32 uint32
|
|
||||||
u64 uint64
|
|
||||||
u uint
|
|
||||||
f32 float32
|
|
||||||
f64 float64
|
|
||||||
b bool
|
|
||||||
c64 complex64
|
|
||||||
c128 complex128
|
|
||||||
slice []int
|
|
||||||
arr [3]int
|
|
||||||
arr2 [3]E
|
|
||||||
s string
|
|
||||||
e E
|
|
||||||
pf *StructWithAllTypeFields // resursive
|
|
||||||
pi *int
|
|
||||||
intr Interface
|
|
||||||
m map[string]uint64
|
|
||||||
c chan int
|
|
||||||
err error
|
|
||||||
fn func(string) (int, error)
|
|
||||||
pad1 int
|
|
||||||
pad2 int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Interface interface {
|
|
||||||
Foo(a []int, b string) int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Struct struct{}
|
|
||||||
|
|
||||||
func (s *Struct) Foo(a []int, b string) int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func FuncWithAllTypeStructParam(s StructWithAllTypeFields) {
|
|
||||||
println(&s)
|
|
||||||
// Expected:
|
|
||||||
// all variables: s
|
|
||||||
// s.i8: '\x01'
|
|
||||||
// s.i16: 2
|
|
||||||
// s.i32: 3
|
|
||||||
// s.i64: 4
|
|
||||||
// s.i: 5
|
|
||||||
// s.u8: '\x06'
|
|
||||||
// s.u16: 7
|
|
||||||
// s.u32: 8
|
|
||||||
// s.u64: 9
|
|
||||||
// s.u: 10
|
|
||||||
// s.f32: 11
|
|
||||||
// s.f64: 12
|
|
||||||
// s.b: true
|
|
||||||
// s.c64: complex64{real = 13, imag = 14}
|
|
||||||
// s.c128: complex128{real = 15, imag = 16}
|
|
||||||
// s.slice: []int{21, 22, 23}
|
|
||||||
// s.arr: [3]int{24, 25, 26}
|
|
||||||
// s.arr2: [3]lldbtest.E{{i = 27}, {i = 28}, {i = 29}}
|
|
||||||
// s.s: "hello"
|
|
||||||
// s.e: lldbtest.E{i = 30}
|
|
||||||
// s.pad1: 100
|
|
||||||
// s.pad2: 200
|
|
||||||
s.i8 = '\b'
|
|
||||||
// Expected:
|
|
||||||
// s.i8: '\b'
|
|
||||||
// s.i16: 2
|
|
||||||
println(len(s.s), s.i8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params is a function with all types of parameters.
|
|
||||||
func FuncWithAllTypeParams(
|
|
||||||
i8 int8,
|
|
||||||
i16 int16,
|
|
||||||
i32 int32,
|
|
||||||
i64 int64,
|
|
||||||
i int,
|
|
||||||
u8 uint8,
|
|
||||||
u16 uint16,
|
|
||||||
u32 uint32,
|
|
||||||
u64 uint64,
|
|
||||||
u uint,
|
|
||||||
f32 float32,
|
|
||||||
f64 float64,
|
|
||||||
b bool,
|
|
||||||
c64 complex64,
|
|
||||||
c128 complex128,
|
|
||||||
slice []int,
|
|
||||||
arr [3]int,
|
|
||||||
arr2 [3]E,
|
|
||||||
s string,
|
|
||||||
e E,
|
|
||||||
f StructWithAllTypeFields,
|
|
||||||
pf *StructWithAllTypeFields,
|
|
||||||
pi *int,
|
|
||||||
intr Interface,
|
|
||||||
m map[string]uint64,
|
|
||||||
c chan int,
|
|
||||||
err error,
|
|
||||||
fn func(string) (int, error),
|
|
||||||
) (int, error) {
|
|
||||||
// Expected:
|
|
||||||
// all variables: i8 i16 i32 i64 i u8 u16 u32 u64 u f32 f64 b c64 c128 slice arr arr2 s e f pf pi intr m c err fn
|
|
||||||
// i32: 3
|
|
||||||
// i64: 4
|
|
||||||
// i: 5
|
|
||||||
// u32: 8
|
|
||||||
// u64: 9
|
|
||||||
// u: 10
|
|
||||||
// f32: 11
|
|
||||||
// f64: 12
|
|
||||||
// slice: []int{21, 22, 23}
|
|
||||||
// arr: [3]int{24, 25, 26}
|
|
||||||
// arr2: [3]lldbtest.E{{i = 27}, {i = 28}, {i = 29}}
|
|
||||||
// slice[0]: 21
|
|
||||||
// slice[1]: 22
|
|
||||||
// slice[2]: 23
|
|
||||||
// arr[0]: 24
|
|
||||||
// arr[1]: 25
|
|
||||||
// arr[2]: 26
|
|
||||||
// arr2[0].i: 27
|
|
||||||
// arr2[1].i: 28
|
|
||||||
// arr2[2].i: 29
|
|
||||||
// e: lldbtest.E{i = 30}
|
|
||||||
|
|
||||||
// Expected(skip):
|
|
||||||
// i8: '\b'
|
|
||||||
// i16: 2
|
|
||||||
// u8: '\x06'
|
|
||||||
// u16: 7
|
|
||||||
// b: true
|
|
||||||
println(
|
|
||||||
i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
|
||||||
f32, f64, b,
|
|
||||||
c64, c128,
|
|
||||||
slice, arr[0:],
|
|
||||||
s,
|
|
||||||
&e,
|
|
||||||
&f, pf, pi, intr, m,
|
|
||||||
c,
|
|
||||||
err,
|
|
||||||
fn,
|
|
||||||
)
|
|
||||||
i8 = 9
|
|
||||||
i16 = 10
|
|
||||||
i32 = 11
|
|
||||||
i64 = 12
|
|
||||||
i = 13
|
|
||||||
u8 = 14
|
|
||||||
u16 = 15
|
|
||||||
u32 = 16
|
|
||||||
u64 = 17
|
|
||||||
u = 18
|
|
||||||
f32 = 19
|
|
||||||
f64 = 20
|
|
||||||
b = false
|
|
||||||
c64 = 21 + 22i
|
|
||||||
c128 = 23 + 24i
|
|
||||||
slice = []int{31, 32, 33}
|
|
||||||
arr = [3]int{34, 35, 36}
|
|
||||||
arr2 = [3]E{{i: 37}, {i: 38}, {i: 39}}
|
|
||||||
s = "world"
|
|
||||||
e = E{i: 40}
|
|
||||||
|
|
||||||
println(i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
|
||||||
f32, f64, b,
|
|
||||||
c64, c128,
|
|
||||||
slice, arr[0:], &arr2,
|
|
||||||
s,
|
|
||||||
&e,
|
|
||||||
&f, pf, pi, intr, m,
|
|
||||||
c,
|
|
||||||
err,
|
|
||||||
fn,
|
|
||||||
)
|
|
||||||
// Expected:
|
|
||||||
// i8: '\t'
|
|
||||||
// i16: 10
|
|
||||||
// i32: 11
|
|
||||||
// i64: 12
|
|
||||||
// i: 13
|
|
||||||
// u8: '\x0e'
|
|
||||||
// u16: 15
|
|
||||||
// u32: 16
|
|
||||||
// u64: 17
|
|
||||||
// u: 18
|
|
||||||
// f32: 19
|
|
||||||
// f64: 20
|
|
||||||
// b: false
|
|
||||||
// c64: complex64{real = 21, imag = 22}
|
|
||||||
// c128: complex128{real = 23, imag = 24}
|
|
||||||
// slice: []int{31, 32, 33}
|
|
||||||
// arr2: [3]lldbtest.E{{i = 37}, {i = 38}, {i = 39}}
|
|
||||||
// s: "world"
|
|
||||||
// e: lldbtest.E{i = 40}
|
|
||||||
|
|
||||||
// Expected(skip):
|
|
||||||
// arr: [3]int{34, 35, 36}
|
|
||||||
return 1, errors.New("some error")
|
|
||||||
}
|
|
||||||
|
|
||||||
type TinyStruct struct {
|
|
||||||
I int
|
|
||||||
}
|
|
||||||
|
|
||||||
type SmallStruct struct {
|
|
||||||
I int
|
|
||||||
J int
|
|
||||||
}
|
|
||||||
|
|
||||||
type MidStruct struct {
|
|
||||||
I int
|
|
||||||
J int
|
|
||||||
K int
|
|
||||||
}
|
|
||||||
|
|
||||||
type BigStruct struct {
|
|
||||||
I int
|
|
||||||
J int
|
|
||||||
K int
|
|
||||||
L int
|
|
||||||
M int
|
|
||||||
N int
|
|
||||||
O int
|
|
||||||
P int
|
|
||||||
Q int
|
|
||||||
R int
|
|
||||||
}
|
|
||||||
|
|
||||||
func FuncStructParams(t TinyStruct, s SmallStruct, m MidStruct, b BigStruct) {
|
|
||||||
// println(&t, &s, &m, &b)
|
|
||||||
// Expected:
|
|
||||||
// all variables: t s m b
|
|
||||||
// t.I: 1
|
|
||||||
// s.I: 2
|
|
||||||
// s.J: 3
|
|
||||||
// m.I: 4
|
|
||||||
// m.J: 5
|
|
||||||
// m.K: 6
|
|
||||||
// b.I: 7
|
|
||||||
// b.J: 8
|
|
||||||
// b.K: 9
|
|
||||||
// b.L: 10
|
|
||||||
// b.M: 11
|
|
||||||
// b.N: 12
|
|
||||||
// b.O: 13
|
|
||||||
// b.P: 14
|
|
||||||
// b.Q: 15
|
|
||||||
// b.R: 16
|
|
||||||
println(t.I, s.I, s.J, m.I, m.J, m.K, b.I, b.J, b.K, b.L, b.M, b.N, b.O, b.P, b.Q, b.R)
|
|
||||||
t.I = 10
|
|
||||||
s.I = 20
|
|
||||||
s.J = 21
|
|
||||||
m.I = 40
|
|
||||||
m.J = 41
|
|
||||||
m.K = 42
|
|
||||||
b.I = 70
|
|
||||||
b.J = 71
|
|
||||||
b.K = 72
|
|
||||||
b.L = 73
|
|
||||||
b.M = 74
|
|
||||||
b.N = 75
|
|
||||||
b.O = 76
|
|
||||||
b.P = 77
|
|
||||||
b.Q = 78
|
|
||||||
b.R = 79
|
|
||||||
// Expected:
|
|
||||||
// all variables: t s m b
|
|
||||||
// t.I: 10
|
|
||||||
// s.I: 20
|
|
||||||
// s.J: 21
|
|
||||||
// m.I: 40
|
|
||||||
// m.J: 41
|
|
||||||
// m.K: 42
|
|
||||||
// b.I: 70
|
|
||||||
// b.J: 71
|
|
||||||
// b.K: 72
|
|
||||||
// b.L: 73
|
|
||||||
// b.M: 74
|
|
||||||
// b.N: 75
|
|
||||||
// b.O: 76
|
|
||||||
// b.P: 77
|
|
||||||
// b.Q: 78
|
|
||||||
// b.R: 79
|
|
||||||
println("done")
|
|
||||||
}
|
|
||||||
|
|
||||||
func FuncStructPtrParams(t *TinyStruct, s *SmallStruct, m *MidStruct, b *BigStruct) {
|
|
||||||
// Expected:
|
|
||||||
// all variables: t s m b
|
|
||||||
// t.I: 1
|
|
||||||
// s.I: 2
|
|
||||||
// s.J: 3
|
|
||||||
// m.I: 4
|
|
||||||
// m.J: 5
|
|
||||||
// m.K: 6
|
|
||||||
// b.I: 7
|
|
||||||
// b.J: 8
|
|
||||||
// b.K: 9
|
|
||||||
// b.L: 10
|
|
||||||
// b.M: 11
|
|
||||||
// b.N: 12
|
|
||||||
// b.O: 13
|
|
||||||
// b.P: 14
|
|
||||||
// b.Q: 15
|
|
||||||
// b.R: 16
|
|
||||||
println(t, s, m, b)
|
|
||||||
t.I = 10
|
|
||||||
s.I = 20
|
|
||||||
s.J = 21
|
|
||||||
m.I = 40
|
|
||||||
m.J = 41
|
|
||||||
m.K = 42
|
|
||||||
b.I = 70
|
|
||||||
b.J = 71
|
|
||||||
b.K = 72
|
|
||||||
b.L = 73
|
|
||||||
b.M = 74
|
|
||||||
b.N = 75
|
|
||||||
b.O = 76
|
|
||||||
b.P = 77
|
|
||||||
b.Q = 78
|
|
||||||
b.R = 79
|
|
||||||
// Expected:
|
|
||||||
// all variables: t s m b
|
|
||||||
// t.I: 10
|
|
||||||
// s.I: 20
|
|
||||||
// s.J: 21
|
|
||||||
// m.I: 40
|
|
||||||
// m.J: 41
|
|
||||||
// m.K: 42
|
|
||||||
// b.I: 70
|
|
||||||
// b.J: 71
|
|
||||||
// b.K: 72
|
|
||||||
// b.L: 73
|
|
||||||
// b.M: 74
|
|
||||||
// b.N: 75
|
|
||||||
// b.O: 76
|
|
||||||
// b.P: 77
|
|
||||||
// b.Q: 78
|
|
||||||
// b.R: 79
|
|
||||||
println(t.I, s.I, s.J, m.I, m.J, m.K, b.I, b.J, b.K, b.L, b.M, b.N, b.O, b.P, b.Q, b.R)
|
|
||||||
println("done")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ScopeIf(branch int) {
|
|
||||||
a := 1
|
|
||||||
// Expected:
|
|
||||||
// all variables: a branch
|
|
||||||
// a: 1
|
|
||||||
if branch == 1 {
|
|
||||||
b := 2
|
|
||||||
c := 3
|
|
||||||
// Expected:
|
|
||||||
// all variables: a b c branch
|
|
||||||
// a: 1
|
|
||||||
// b: 2
|
|
||||||
// c: 3
|
|
||||||
// branch: 1
|
|
||||||
println(a, b, c)
|
|
||||||
} else {
|
|
||||||
c := 3
|
|
||||||
d := 4
|
|
||||||
// Expected:
|
|
||||||
// all variables: a c d branch
|
|
||||||
// a: 1
|
|
||||||
// c: 3
|
|
||||||
// d: 4
|
|
||||||
// branch: 0
|
|
||||||
println(a, c, d)
|
|
||||||
}
|
|
||||||
// Expected:
|
|
||||||
// all variables: a branch
|
|
||||||
// a: 1
|
|
||||||
println("a:", a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ScopeFor() {
|
|
||||||
a := 1
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
switch i {
|
|
||||||
case 0:
|
|
||||||
println("i is 0")
|
|
||||||
// Expected:
|
|
||||||
// all variables: i a
|
|
||||||
// i: 0
|
|
||||||
// a: 1
|
|
||||||
println("i:", i)
|
|
||||||
case 1:
|
|
||||||
println("i is 1")
|
|
||||||
// Expected:
|
|
||||||
// all variables: i a
|
|
||||||
// i: 1
|
|
||||||
// a: 1
|
|
||||||
println("i:", i)
|
|
||||||
default:
|
|
||||||
println("i is", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println("a:", a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ScopeSwitch(i int) {
|
|
||||||
a := 0
|
|
||||||
switch i {
|
|
||||||
case 1:
|
|
||||||
b := 1
|
|
||||||
println("i is 1")
|
|
||||||
// Expected:
|
|
||||||
// all variables: i a b
|
|
||||||
// i: 1
|
|
||||||
// a: 0
|
|
||||||
// b: 1
|
|
||||||
println("i:", i, "a:", a, "b:", b)
|
|
||||||
case 2:
|
|
||||||
c := 2
|
|
||||||
println("i is 2")
|
|
||||||
// Expected:
|
|
||||||
// all variables: i a c
|
|
||||||
// i: 2
|
|
||||||
// a: 0
|
|
||||||
// c: 2
|
|
||||||
println("i:", i, "a:", a, "c:", c)
|
|
||||||
default:
|
|
||||||
d := 3
|
|
||||||
println("i is", i)
|
|
||||||
// Expected:
|
|
||||||
// all variables: i a d
|
|
||||||
// i: 3
|
|
||||||
// a: 0
|
|
||||||
// d: 3
|
|
||||||
println("i:", i, "a:", a, "d:", d)
|
|
||||||
}
|
|
||||||
// Expected:
|
|
||||||
// all variables: a i
|
|
||||||
// a: 0
|
|
||||||
println("a:", a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
FuncStructParams(TinyStruct{I: 1}, SmallStruct{I: 2, J: 3}, MidStruct{I: 4, J: 5, K: 6}, BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
|
|
||||||
FuncStructPtrParams(&TinyStruct{I: 1}, &SmallStruct{I: 2, J: 3}, &MidStruct{I: 4, J: 5, K: 6}, &BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
|
|
||||||
i := 100
|
|
||||||
s := StructWithAllTypeFields{
|
|
||||||
i8: 1,
|
|
||||||
i16: 2,
|
|
||||||
i32: 3,
|
|
||||||
i64: 4,
|
|
||||||
i: 5,
|
|
||||||
u8: 6,
|
|
||||||
u16: 7,
|
|
||||||
u32: 8,
|
|
||||||
u64: 9,
|
|
||||||
u: 10,
|
|
||||||
f32: 11,
|
|
||||||
f64: 12,
|
|
||||||
b: true,
|
|
||||||
c64: 13 + 14i,
|
|
||||||
c128: 15 + 16i,
|
|
||||||
slice: []int{21, 22, 23},
|
|
||||||
arr: [3]int{24, 25, 26},
|
|
||||||
arr2: [3]E{{i: 27}, {i: 28}, {i: 29}},
|
|
||||||
s: "hello",
|
|
||||||
e: E{i: 30},
|
|
||||||
pf: &StructWithAllTypeFields{i16: 100},
|
|
||||||
pi: &i,
|
|
||||||
intr: &Struct{},
|
|
||||||
m: map[string]uint64{"a": 31, "b": 32},
|
|
||||||
c: make(chan int),
|
|
||||||
err: errors.New("Test error"),
|
|
||||||
fn: func(s string) (int, error) {
|
|
||||||
println("fn:", s)
|
|
||||||
i = 201
|
|
||||||
return 1, errors.New("fn error")
|
|
||||||
},
|
|
||||||
pad1: 100,
|
|
||||||
pad2: 200,
|
|
||||||
}
|
|
||||||
// Expected:
|
|
||||||
// all variables: s i err
|
|
||||||
// s.i8: '\x01'
|
|
||||||
// s.i16: 2
|
|
||||||
// s.i32: 3
|
|
||||||
// s.i64: 4
|
|
||||||
// s.i: 5
|
|
||||||
// s.u8: '\x06'
|
|
||||||
// s.u16: 7
|
|
||||||
// s.u32: 8
|
|
||||||
// s.u64: 9
|
|
||||||
// s.u: 10
|
|
||||||
// s.f32: 11
|
|
||||||
// s.f64: 12
|
|
||||||
// s.b: true
|
|
||||||
// s.c64: complex64{real = 13, imag = 14}
|
|
||||||
// s.c128: complex128{real = 15, imag = 16}
|
|
||||||
// s.slice: []int{21, 22, 23}
|
|
||||||
// s.arr: [3]int{24, 25, 26}
|
|
||||||
// s.arr2: [3]lldbtest.E{{i = 27}, {i = 28}, {i = 29}}
|
|
||||||
// s.s: "hello"
|
|
||||||
// s.e: lldbtest.E{i = 30}
|
|
||||||
// s.pf.i16: 100
|
|
||||||
// *(s.pf).i16: 100
|
|
||||||
// *(s.pi): 100
|
|
||||||
globalStructPtr = &s
|
|
||||||
globalStruct = s
|
|
||||||
println("globalInt:", globalInt)
|
|
||||||
// Expected(skip):
|
|
||||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
|
||||||
println("s:", &s)
|
|
||||||
FuncWithAllTypeStructParam(s)
|
|
||||||
println("called function with struct")
|
|
||||||
i, err := FuncWithAllTypeParams(
|
|
||||||
s.i8, s.i16, s.i32, s.i64, s.i, s.u8, s.u16, s.u32, s.u64, s.u,
|
|
||||||
s.f32, s.f64, s.b,
|
|
||||||
s.c64, s.c128,
|
|
||||||
s.slice, s.arr, s.arr2,
|
|
||||||
s.s,
|
|
||||||
s.e, s,
|
|
||||||
s.pf, s.pi,
|
|
||||||
s.intr,
|
|
||||||
s.m,
|
|
||||||
s.c,
|
|
||||||
s.err,
|
|
||||||
s.fn,
|
|
||||||
)
|
|
||||||
println(i, err)
|
|
||||||
ScopeIf(1)
|
|
||||||
ScopeIf(0)
|
|
||||||
ScopeFor()
|
|
||||||
ScopeSwitch(1)
|
|
||||||
ScopeSwitch(2)
|
|
||||||
ScopeSwitch(3)
|
|
||||||
println(globalStructPtr)
|
|
||||||
println(&globalStruct)
|
|
||||||
s.i8 = 0x12
|
|
||||||
println(s.i8)
|
|
||||||
// Expected:
|
|
||||||
// all variables: s i err
|
|
||||||
// s.i8: '\x12'
|
|
||||||
|
|
||||||
// Expected(skip):
|
|
||||||
// globalStruct.i8: '\x01'
|
|
||||||
println((*globalStructPtr).i8)
|
|
||||||
println("done")
|
|
||||||
println("")
|
|
||||||
println(&s, &globalStruct, globalStructPtr.i16, globalStructPtr)
|
|
||||||
globalStructPtr = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var globalInt int = 301
|
|
||||||
var globalStruct StructWithAllTypeFields
|
|
||||||
var globalStructPtr *StructWithAllTypeFields
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
|
|
||||||
|
|
||||||
from typing import List, Optional, Dict, Any, Tuple
|
|
||||||
import re
|
|
||||||
import lldb
|
|
||||||
|
|
||||||
|
|
||||||
def log(*args: Any, **kwargs: Any) -> None:
|
|
||||||
print(*args, **kwargs, flush=True)
|
|
||||||
|
|
||||||
|
|
||||||
def __lldb_init_module(debugger: lldb.SBDebugger, _: Dict[str, Any]) -> None:
|
|
||||||
debugger.HandleCommand(
|
|
||||||
'command script add -f llgo_plugin.print_go_expression p')
|
|
||||||
debugger.HandleCommand(
|
|
||||||
'command script add -f llgo_plugin.print_all_variables v')
|
|
||||||
|
|
||||||
|
|
||||||
def is_llgo_compiler(_target: lldb.SBTarget) -> bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_indexed_value(value: lldb.SBValue, index: int) -> Optional[lldb.SBValue]:
|
|
||||||
if not value or not value.IsValid():
|
|
||||||
return None
|
|
||||||
|
|
||||||
type_name = value.GetType().GetName()
|
|
||||||
|
|
||||||
if type_name.startswith('[]'): # Slice
|
|
||||||
data_ptr = value.GetChildMemberWithName('data')
|
|
||||||
element_type = data_ptr.GetType().GetPointeeType()
|
|
||||||
element_size = element_type.GetByteSize()
|
|
||||||
ptr_value = int(data_ptr.GetValue(), 16)
|
|
||||||
element_address = ptr_value + index * element_size
|
|
||||||
target = value.GetTarget()
|
|
||||||
return target.CreateValueFromAddress(
|
|
||||||
f"element_{index}", lldb.SBAddress(element_address, target), element_type)
|
|
||||||
elif value.GetType().IsArrayType(): # Array
|
|
||||||
return value.GetChildAtIndex(index)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def evaluate_expression(frame: lldb.SBFrame, expression: str) -> Optional[lldb.SBValue]:
|
|
||||||
parts = re.findall(r'\*|\w+|\(|\)|\[.*?\]|\.', expression)
|
|
||||||
|
|
||||||
def evaluate_part(i: int) -> Tuple[Optional[lldb.SBValue], int]:
|
|
||||||
nonlocal parts
|
|
||||||
value: Optional[lldb.SBValue] = None
|
|
||||||
while i < len(parts):
|
|
||||||
part = parts[i]
|
|
||||||
|
|
||||||
if part == '*':
|
|
||||||
sub_value, i = evaluate_part(i + 1)
|
|
||||||
if sub_value and sub_value.IsValid():
|
|
||||||
value = sub_value.Dereference()
|
|
||||||
else:
|
|
||||||
return None, i
|
|
||||||
elif part == '(':
|
|
||||||
depth = 1
|
|
||||||
j = i + 1
|
|
||||||
while j < len(parts) and depth > 0:
|
|
||||||
if parts[j] == '(':
|
|
||||||
depth += 1
|
|
||||||
elif parts[j] == ')':
|
|
||||||
depth -= 1
|
|
||||||
j += 1
|
|
||||||
value, i = evaluate_part(i + 1)
|
|
||||||
i = j - 1
|
|
||||||
elif part == ')':
|
|
||||||
return value, i + 1
|
|
||||||
elif part == '.':
|
|
||||||
if value is None:
|
|
||||||
value = frame.FindVariable(parts[i+1])
|
|
||||||
else:
|
|
||||||
value = value.GetChildMemberWithName(parts[i+1])
|
|
||||||
i += 2
|
|
||||||
elif part.startswith('['):
|
|
||||||
index = int(part[1:-1])
|
|
||||||
value = get_indexed_value(value, index)
|
|
||||||
i += 1
|
|
||||||
else:
|
|
||||||
if value is None:
|
|
||||||
value = frame.FindVariable(part)
|
|
||||||
else:
|
|
||||||
value = value.GetChildMemberWithName(part)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if not value or not value.IsValid():
|
|
||||||
return None, i
|
|
||||||
|
|
||||||
return value, i
|
|
||||||
|
|
||||||
value, _ = evaluate_part(0)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def print_go_expression(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, _internal_dict: Dict[str, Any]) -> None:
|
|
||||||
frame = debugger.GetSelectedTarget().GetProcess(
|
|
||||||
).GetSelectedThread().GetSelectedFrame()
|
|
||||||
value = evaluate_expression(frame, command)
|
|
||||||
if value and value.IsValid():
|
|
||||||
result.AppendMessage(format_value(value, debugger))
|
|
||||||
else:
|
|
||||||
result.AppendMessage(
|
|
||||||
f"Error: Unable to evaluate expression '{command}'")
|
|
||||||
|
|
||||||
|
|
||||||
def print_all_variables(debugger: lldb.SBDebugger, _command: str, result: lldb.SBCommandReturnObject, _internal_dict: Dict[str, Any]) -> None:
|
|
||||||
target = debugger.GetSelectedTarget()
|
|
||||||
if not is_llgo_compiler(target):
|
|
||||||
result.AppendMessage("Not a LLGo compiled binary.")
|
|
||||||
return
|
|
||||||
|
|
||||||
frame = debugger.GetSelectedTarget().GetProcess(
|
|
||||||
).GetSelectedThread().GetSelectedFrame()
|
|
||||||
variables = frame.GetVariables(True, True, True, True)
|
|
||||||
|
|
||||||
output: List[str] = []
|
|
||||||
for var in variables:
|
|
||||||
type_name = map_type_name(var.GetType().GetName())
|
|
||||||
formatted = format_value(var, debugger, include_type=False, indent=0)
|
|
||||||
output.append(f"var {var.GetName()} {type_name} = {formatted}")
|
|
||||||
|
|
||||||
result.AppendMessage("\n".join(output))
|
|
||||||
|
|
||||||
|
|
||||||
def is_pointer(frame: lldb.SBFrame, var_name: str) -> bool:
|
|
||||||
var = frame.FindVariable(var_name)
|
|
||||||
return var.IsValid() and var.GetType().IsPointerType()
|
|
||||||
|
|
||||||
|
|
||||||
def format_value(var: lldb.SBValue, debugger: lldb.SBDebugger, include_type: bool = True, indent: int = 0) -> str:
|
|
||||||
if not var.IsValid():
|
|
||||||
return "<variable not available>"
|
|
||||||
|
|
||||||
var_type = var.GetType()
|
|
||||||
type_class = var_type.GetTypeClass()
|
|
||||||
type_name = map_type_name(var_type.GetName())
|
|
||||||
|
|
||||||
# Handle typedef types
|
|
||||||
original_type_name = type_name
|
|
||||||
while var_type.IsTypedefType():
|
|
||||||
var_type = var_type.GetTypedefedType()
|
|
||||||
type_name = map_type_name(var_type.GetName())
|
|
||||||
type_class = var_type.GetTypeClass()
|
|
||||||
|
|
||||||
if var_type.IsPointerType():
|
|
||||||
return format_pointer(var, debugger, indent, original_type_name)
|
|
||||||
|
|
||||||
if type_name.startswith('[]'): # Slice
|
|
||||||
return format_slice(var, debugger, indent)
|
|
||||||
elif var_type.IsArrayType():
|
|
||||||
return format_array(var, debugger, indent)
|
|
||||||
elif type_name == 'string': # String
|
|
||||||
return format_string(var)
|
|
||||||
elif type_class in [lldb.eTypeClassStruct, lldb.eTypeClassClass]:
|
|
||||||
return format_struct(var, debugger, include_type, indent, original_type_name)
|
|
||||||
else:
|
|
||||||
value = var.GetValue()
|
|
||||||
summary = var.GetSummary()
|
|
||||||
if value is not None:
|
|
||||||
return f"{value}" if include_type else str(value)
|
|
||||||
elif summary is not None:
|
|
||||||
return f"{summary}" if include_type else summary
|
|
||||||
else:
|
|
||||||
return "<variable not available>"
|
|
||||||
|
|
||||||
|
|
||||||
def format_slice(var: lldb.SBValue, debugger: lldb.SBDebugger, indent: int) -> str:
|
|
||||||
length = var.GetChildMemberWithName('len').GetValue()
|
|
||||||
if length is None:
|
|
||||||
return "<variable not available>"
|
|
||||||
length = int(length)
|
|
||||||
data_ptr = var.GetChildMemberWithName('data')
|
|
||||||
elements: List[str] = []
|
|
||||||
|
|
||||||
ptr_value = int(data_ptr.GetValue(), 16)
|
|
||||||
element_type = data_ptr.GetType().GetPointeeType()
|
|
||||||
element_size = element_type.GetByteSize()
|
|
||||||
|
|
||||||
target = debugger.GetSelectedTarget()
|
|
||||||
indent_str = ' ' * indent
|
|
||||||
next_indent_str = ' ' * (indent + 1)
|
|
||||||
|
|
||||||
for i in range(length):
|
|
||||||
element_address = ptr_value + i * element_size
|
|
||||||
element = target.CreateValueFromAddress(
|
|
||||||
f"element_{i}", lldb.SBAddress(element_address, target), element_type)
|
|
||||||
value = format_value(
|
|
||||||
element, debugger, include_type=False, indent=indent+1)
|
|
||||||
elements.append(value)
|
|
||||||
|
|
||||||
type_name = var.GetType().GetName()
|
|
||||||
|
|
||||||
if len(elements) > 5: # 如果元素数量大于5,则进行折行显示
|
|
||||||
result = f"{type_name}{{\n{next_indent_str}" + \
|
|
||||||
f",\n{next_indent_str}".join(elements) + f"\n{indent_str}}}"
|
|
||||||
else:
|
|
||||||
result = f"{type_name}{{{', '.join(elements)}}}"
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def format_array(var: lldb.SBValue, debugger: lldb.SBDebugger, indent: int) -> str:
|
|
||||||
elements: List[str] = []
|
|
||||||
indent_str = ' ' * indent
|
|
||||||
next_indent_str = ' ' * (indent + 1)
|
|
||||||
|
|
||||||
for i in range(var.GetNumChildren()):
|
|
||||||
value = format_value(var.GetChildAtIndex(
|
|
||||||
i), debugger, include_type=False, indent=indent+1)
|
|
||||||
elements.append(value)
|
|
||||||
|
|
||||||
array_size = var.GetNumChildren()
|
|
||||||
element_type = map_type_name(var.GetType().GetArrayElementType().GetName())
|
|
||||||
type_name = f"[{array_size}]{element_type}"
|
|
||||||
|
|
||||||
if len(elements) > 5: # wrap line if too many elements
|
|
||||||
return f"{type_name}{{\n{next_indent_str}" + f",\n{next_indent_str}".join(elements) + f"\n{indent_str}}}"
|
|
||||||
else:
|
|
||||||
return f"{type_name}{{{', '.join(elements)}}}"
|
|
||||||
|
|
||||||
|
|
||||||
def format_string(var: lldb.SBValue) -> str:
|
|
||||||
summary = var.GetSummary()
|
|
||||||
if summary is not None:
|
|
||||||
return summary # Keep the quotes
|
|
||||||
else:
|
|
||||||
data = var.GetChildMemberWithName('data').GetValue()
|
|
||||||
length = var.GetChildMemberWithName('len').GetValue()
|
|
||||||
if data and length:
|
|
||||||
length = int(length)
|
|
||||||
error = lldb.SBError()
|
|
||||||
return '"%s"' % var.process.ReadCStringFromMemory(int(data, 16), length + 1, error)
|
|
||||||
return "<variable not available>"
|
|
||||||
|
|
||||||
|
|
||||||
def format_struct(var: lldb.SBValue, debugger: lldb.SBDebugger, include_type: bool = True, indent: int = 0, type_name: str = "") -> str:
|
|
||||||
children: List[str] = []
|
|
||||||
indent_str = ' ' * indent
|
|
||||||
next_indent_str = ' ' * (indent + 1)
|
|
||||||
|
|
||||||
for i in range(var.GetNumChildren()):
|
|
||||||
child = var.GetChildAtIndex(i)
|
|
||||||
child_name = child.GetName()
|
|
||||||
child_value = format_value(
|
|
||||||
child, debugger, include_type=False, indent=indent+1)
|
|
||||||
children.append(f"{child_name} = {child_value}")
|
|
||||||
|
|
||||||
if len(children) > 5: # 如果字段数量大于5,则进行折行显示
|
|
||||||
struct_content = "{\n" + ",\n".join(
|
|
||||||
[f"{next_indent_str}{child}" for child in children]) + f"\n{indent_str}}}"
|
|
||||||
else:
|
|
||||||
struct_content = f"{{{', '.join(children)}}}"
|
|
||||||
|
|
||||||
if include_type:
|
|
||||||
return f"{type_name}{struct_content}"
|
|
||||||
else:
|
|
||||||
return struct_content
|
|
||||||
|
|
||||||
|
|
||||||
def format_pointer(var: lldb.SBValue, _debugger: lldb.SBDebugger, _indent: int, _type_name: str) -> str:
|
|
||||||
if not var.IsValid() or var.GetValueAsUnsigned() == 0:
|
|
||||||
return "<variable not available>"
|
|
||||||
return var.GetValue() # Return the address as a string
|
|
||||||
|
|
||||||
|
|
||||||
def map_type_name(type_name: str) -> str:
|
|
||||||
# Handle pointer types
|
|
||||||
if type_name.endswith('*'):
|
|
||||||
base_type = type_name[:-1].strip()
|
|
||||||
mapped_base_type = map_type_name(base_type)
|
|
||||||
return f"*{mapped_base_type}"
|
|
||||||
|
|
||||||
# Map other types
|
|
||||||
type_mapping: Dict[str, str] = {
|
|
||||||
'long': 'int',
|
|
||||||
'void': 'unsafe.Pointer',
|
|
||||||
'char': 'byte',
|
|
||||||
'short': 'int16',
|
|
||||||
'int': 'int32',
|
|
||||||
'long long': 'int64',
|
|
||||||
'unsigned char': 'uint8',
|
|
||||||
'unsigned short': 'uint16',
|
|
||||||
'unsigned int': 'uint32',
|
|
||||||
'unsigned long': 'uint',
|
|
||||||
'unsigned long long': 'uint64',
|
|
||||||
'float': 'float32',
|
|
||||||
'double': 'float64',
|
|
||||||
}
|
|
||||||
|
|
||||||
for c_type, go_type in type_mapping.items():
|
|
||||||
if type_name.startswith(c_type):
|
|
||||||
return type_name.replace(c_type, go_type, 1)
|
|
||||||
|
|
||||||
return type_name
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Source common functions and variables
|
|
||||||
# shellcheck source=./_lldb/common.sh
|
|
||||||
source "$(dirname "$0")/common.sh"
|
|
||||||
|
|
||||||
executable="$1"
|
|
||||||
|
|
||||||
# Get the directory of the current script
|
|
||||||
script_dir="$(dirname "$0")"
|
|
||||||
|
|
||||||
# Run LLDB with the LLGO plugin
|
|
||||||
"$LLDB_PATH" -O "command script import ${script_dir}/llgo_plugin.py" "$executable"
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Source common functions and variables
|
|
||||||
# shellcheck source=./_lldb/common.sh
|
|
||||||
# shellcheck disable=SC1091
|
|
||||||
source "$(dirname "$0")/common.sh" || exit 1
|
|
||||||
|
|
||||||
# Parse command-line arguments
|
|
||||||
package_path="$DEFAULT_PACKAGE_PATH"
|
|
||||||
verbose=False
|
|
||||||
interactive=False
|
|
||||||
plugin_path=None
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
-v|--verbose)
|
|
||||||
verbose=True
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-i|--interactive)
|
|
||||||
interactive=True
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-p|--plugin)
|
|
||||||
plugin_path="\"$2\""
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
package_path="$1"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Build the project
|
|
||||||
build_project "$package_path" || exit 1
|
|
||||||
|
|
||||||
# Set up the result file path
|
|
||||||
result_file="/tmp/lldb_exit_code"
|
|
||||||
|
|
||||||
# Prepare LLDB commands
|
|
||||||
lldb_commands=(
|
|
||||||
"command script import ../llgo_plugin.py"
|
|
||||||
"command script import ../test.py"
|
|
||||||
"script test.run_tests_with_result('./debug.out', ['main.go'], $verbose, $interactive, $plugin_path, '$result_file')"
|
|
||||||
"quit"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Run LLDB with prepared commands
|
|
||||||
lldb_command_string=""
|
|
||||||
for cmd in "${lldb_commands[@]}"; do
|
|
||||||
lldb_command_string+=" -o \"$cmd\""
|
|
||||||
done
|
|
||||||
|
|
||||||
cd "$package_path"
|
|
||||||
# Run LLDB with the test script
|
|
||||||
eval "$LLDB_PATH $lldb_command_string"
|
|
||||||
|
|
||||||
# Read the exit code from the result file
|
|
||||||
if [ -f "$result_file" ]; then
|
|
||||||
exit_code=$(cat "$result_file")
|
|
||||||
rm "$result_file"
|
|
||||||
exit "$exit_code"
|
|
||||||
else
|
|
||||||
echo "Error: Could not find exit code file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
402
_lldb/test.py
402
_lldb/test.py
@@ -1,402 +0,0 @@
|
|||||||
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
import signal
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import List, Optional, Set, Dict, Any
|
|
||||||
import lldb
|
|
||||||
import llgo_plugin
|
|
||||||
from llgo_plugin import log
|
|
||||||
|
|
||||||
|
|
||||||
class LLDBTestException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Test:
|
|
||||||
source_file: str
|
|
||||||
line_number: int
|
|
||||||
variable: str
|
|
||||||
expected_value: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TestResult:
|
|
||||||
test: Test
|
|
||||||
status: str
|
|
||||||
actual: Optional[str] = None
|
|
||||||
message: Optional[str] = None
|
|
||||||
missing: Optional[Set[str]] = None
|
|
||||||
extra: Optional[Set[str]] = None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TestCase:
|
|
||||||
source_file: str
|
|
||||||
start_line: int
|
|
||||||
end_line: int
|
|
||||||
tests: List[Test]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CaseResult:
|
|
||||||
test_case: TestCase
|
|
||||||
function: str
|
|
||||||
results: List[TestResult]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TestResults:
|
|
||||||
total: int = 0
|
|
||||||
passed: int = 0
|
|
||||||
failed: int = 0
|
|
||||||
case_results: List[CaseResult] = field(default_factory=list)
|
|
||||||
|
|
||||||
|
|
||||||
class LLDBDebugger:
|
|
||||||
def __init__(self, executable_path: str, plugin_path: Optional[str] = None) -> None:
|
|
||||||
self.executable_path: str = executable_path
|
|
||||||
self.plugin_path: Optional[str] = plugin_path
|
|
||||||
self.debugger: lldb.SBDebugger = lldb.SBDebugger.Create()
|
|
||||||
self.debugger.SetAsync(False)
|
|
||||||
self.target: Optional[lldb.SBTarget] = None
|
|
||||||
self.process: Optional[lldb.SBProcess] = None
|
|
||||||
self.type_mapping: Dict[str, str] = {
|
|
||||||
'long': 'int',
|
|
||||||
'unsigned long': 'uint',
|
|
||||||
}
|
|
||||||
|
|
||||||
def setup(self) -> None:
|
|
||||||
if self.plugin_path:
|
|
||||||
self.debugger.HandleCommand(
|
|
||||||
f'command script import "{self.plugin_path}"')
|
|
||||||
self.target = self.debugger.CreateTarget(self.executable_path)
|
|
||||||
if not self.target:
|
|
||||||
raise LLDBTestException(
|
|
||||||
f"Failed to create target for {self.executable_path}")
|
|
||||||
|
|
||||||
self.debugger.HandleCommand(
|
|
||||||
'command script add -f llgo_plugin.print_go_expression p')
|
|
||||||
self.debugger.HandleCommand(
|
|
||||||
'command script add -f llgo_plugin.print_all_variables v')
|
|
||||||
|
|
||||||
def set_breakpoint(self, file_spec: str, line_number: int) -> lldb.SBBreakpoint:
|
|
||||||
bp = self.target.BreakpointCreateByLocation(file_spec, line_number)
|
|
||||||
if not bp.IsValid():
|
|
||||||
raise LLDBTestException(
|
|
||||||
f"Failed to set breakpoint at {file_spec}: {line_number}")
|
|
||||||
return bp
|
|
||||||
|
|
||||||
def run_to_breakpoint(self) -> None:
|
|
||||||
if not self.process:
|
|
||||||
self.process = self.target.LaunchSimple(None, None, os.getcwd())
|
|
||||||
else:
|
|
||||||
self.process.Continue()
|
|
||||||
if self.process.GetState() != lldb.eStateStopped:
|
|
||||||
raise LLDBTestException("Process didn't stop at breakpoint")
|
|
||||||
|
|
||||||
def get_variable_value(self, var_expression: str) -> Optional[str]:
|
|
||||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
|
||||||
value = llgo_plugin.evaluate_expression(frame, var_expression)
|
|
||||||
if value and value.IsValid():
|
|
||||||
return llgo_plugin.format_value(value, self.debugger)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_all_variable_names(self) -> Set[str]:
|
|
||||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
|
||||||
return set(var.GetName() for var in frame.GetVariables(True, True, True, True))
|
|
||||||
|
|
||||||
def get_current_function_name(self) -> str:
|
|
||||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
|
||||||
return frame.GetFunctionName()
|
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
|
||||||
if self.process and self.process.IsValid():
|
|
||||||
self.process.Kill()
|
|
||||||
lldb.SBDebugger.Destroy(self.debugger)
|
|
||||||
|
|
||||||
def run_console(self) -> bool:
|
|
||||||
log("\nEntering LLDB interactive mode.")
|
|
||||||
log("Type 'quit' to exit and continue with the next test case.")
|
|
||||||
log("Use Ctrl+D to exit and continue, or Ctrl+C to abort all tests.")
|
|
||||||
|
|
||||||
old_stdin, old_stdout, old_stderr = sys.stdin, sys.stdout, sys.stderr
|
|
||||||
sys.stdin, sys.stdout, sys.stderr = sys.__stdin__, sys.__stdout__, sys.__stderr__
|
|
||||||
|
|
||||||
self.debugger.SetAsync(True)
|
|
||||||
self.debugger.HandleCommand("settings set auto-confirm true")
|
|
||||||
self.debugger.HandleCommand("command script import lldb")
|
|
||||||
|
|
||||||
interpreter = self.debugger.GetCommandInterpreter()
|
|
||||||
continue_tests = True
|
|
||||||
|
|
||||||
def keyboard_interrupt_handler(_sig: Any, _frame: Any) -> None:
|
|
||||||
nonlocal continue_tests
|
|
||||||
log("\nTest execution aborted by user.")
|
|
||||||
continue_tests = False
|
|
||||||
raise KeyboardInterrupt
|
|
||||||
|
|
||||||
original_handler = signal.signal(
|
|
||||||
signal.SIGINT, keyboard_interrupt_handler)
|
|
||||||
|
|
||||||
try:
|
|
||||||
while continue_tests:
|
|
||||||
log("\n(lldb) ", end="")
|
|
||||||
try:
|
|
||||||
command = input().strip()
|
|
||||||
except EOFError:
|
|
||||||
log("\nExiting LLDB interactive mode. Continuing with next test case.")
|
|
||||||
break
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
break
|
|
||||||
|
|
||||||
if command.lower() == 'quit':
|
|
||||||
log("\nExiting LLDB interactive mode. Continuing with next test case.")
|
|
||||||
break
|
|
||||||
|
|
||||||
result = lldb.SBCommandReturnObject()
|
|
||||||
interpreter.HandleCommand(command, result)
|
|
||||||
log(result.GetOutput().rstrip() if result.Succeeded()
|
|
||||||
else result.GetError().rstrip())
|
|
||||||
|
|
||||||
finally:
|
|
||||||
signal.signal(signal.SIGINT, original_handler)
|
|
||||||
sys.stdin, sys.stdout, sys.stderr = old_stdin, old_stdout, old_stderr
|
|
||||||
|
|
||||||
return continue_tests
|
|
||||||
|
|
||||||
|
|
||||||
def parse_expected_values(source_files: List[str]) -> List[TestCase]:
|
|
||||||
test_cases: List[TestCase] = []
|
|
||||||
for source_file in source_files:
|
|
||||||
with open(source_file, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.readlines()
|
|
||||||
i = 0
|
|
||||||
while i < len(content):
|
|
||||||
line = content[i].strip()
|
|
||||||
if line.startswith('// Expected:'):
|
|
||||||
start_line = i + 1
|
|
||||||
tests: List[Test] = []
|
|
||||||
i += 1
|
|
||||||
while i < len(content):
|
|
||||||
line = content[i].strip()
|
|
||||||
if not line.startswith('//'):
|
|
||||||
break
|
|
||||||
parts = line.lstrip('//').strip().split(':', 1)
|
|
||||||
if len(parts) == 2:
|
|
||||||
var, value = map(str.strip, parts)
|
|
||||||
tests.append(Test(source_file, i + 1, var, value))
|
|
||||||
i += 1
|
|
||||||
end_line = i
|
|
||||||
test_cases.append(
|
|
||||||
TestCase(source_file, start_line, end_line, tests))
|
|
||||||
else:
|
|
||||||
i += 1
|
|
||||||
return test_cases
|
|
||||||
|
|
||||||
|
|
||||||
def execute_tests(executable_path: str, test_cases: List[TestCase], verbose: bool, interactive: bool, plugin_path: Optional[str]) -> TestResults:
|
|
||||||
results = TestResults()
|
|
||||||
|
|
||||||
for test_case in test_cases:
|
|
||||||
debugger = LLDBDebugger(executable_path, plugin_path)
|
|
||||||
try:
|
|
||||||
if verbose:
|
|
||||||
log(
|
|
||||||
f"\nSetting breakpoint at {test_case.source_file}:{test_case.end_line}")
|
|
||||||
debugger.setup()
|
|
||||||
debugger.set_breakpoint(test_case.source_file, test_case.end_line)
|
|
||||||
debugger.run_to_breakpoint()
|
|
||||||
|
|
||||||
all_variable_names = debugger.get_all_variable_names()
|
|
||||||
|
|
||||||
case_result = execute_test_case(
|
|
||||||
debugger, test_case, all_variable_names)
|
|
||||||
|
|
||||||
results.total += len(case_result.results)
|
|
||||||
results.passed += sum(1 for r in case_result.results if r.status == 'pass')
|
|
||||||
results.failed += sum(1 for r in case_result.results if r.status != 'pass')
|
|
||||||
results.case_results.append(case_result)
|
|
||||||
|
|
||||||
case = case_result.test_case
|
|
||||||
loc = f"{case.source_file}:{case.start_line}-{case.end_line}"
|
|
||||||
if verbose or interactive or any(r.status != 'pass' for r in case_result.results):
|
|
||||||
log(f"\nTest case: {loc} in function '{case_result.function}'")
|
|
||||||
for result in case_result.results:
|
|
||||||
print_test_result(result, verbose=verbose)
|
|
||||||
|
|
||||||
if interactive and any(r.status != 'pass' for r in case_result.results):
|
|
||||||
log("\nTest case failed. Entering LLDB interactive mode.")
|
|
||||||
continue_tests = debugger.run_console()
|
|
||||||
if not continue_tests:
|
|
||||||
log("Aborting all tests.")
|
|
||||||
break
|
|
||||||
|
|
||||||
finally:
|
|
||||||
debugger.cleanup()
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
def run_tests(executable_path: str, source_files: List[str], verbose: bool, interactive: bool, plugin_path: Optional[str]) -> int:
|
|
||||||
test_cases = parse_expected_values(source_files)
|
|
||||||
if verbose:
|
|
||||||
log(f"Running tests for {', '.join(source_files)} with {executable_path}")
|
|
||||||
log(f"Found {len(test_cases)} test cases")
|
|
||||||
|
|
||||||
results = execute_tests(executable_path, test_cases,
|
|
||||||
verbose, interactive, plugin_path)
|
|
||||||
print_test_results(results)
|
|
||||||
|
|
||||||
# Return 0 if all tests passed, 1 otherwise
|
|
||||||
return 0 if results.failed == 0 else 1
|
|
||||||
|
|
||||||
|
|
||||||
def execute_test_case(debugger: LLDBDebugger, test_case: TestCase, all_variable_names: Set[str]) -> CaseResult:
|
|
||||||
results: List[TestResult] = []
|
|
||||||
|
|
||||||
for test in test_case.tests:
|
|
||||||
if test.variable == "all variables":
|
|
||||||
result = execute_all_variables_test(test, all_variable_names)
|
|
||||||
else:
|
|
||||||
result = execute_single_variable_test(debugger, test)
|
|
||||||
results.append(result)
|
|
||||||
|
|
||||||
return CaseResult(test_case, debugger.get_current_function_name(), results)
|
|
||||||
|
|
||||||
|
|
||||||
def execute_all_variables_test(test: Test, all_variable_names: Set[str]) -> TestResult:
|
|
||||||
expected_vars = set(test.expected_value.split())
|
|
||||||
if expected_vars == all_variable_names:
|
|
||||||
return TestResult(
|
|
||||||
test=test,
|
|
||||||
status='pass',
|
|
||||||
actual=all_variable_names
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return TestResult(
|
|
||||||
test=test,
|
|
||||||
status='fail',
|
|
||||||
actual=all_variable_names,
|
|
||||||
missing=expected_vars - all_variable_names,
|
|
||||||
extra=all_variable_names - expected_vars
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def execute_single_variable_test(debugger: LLDBDebugger, test: Test) -> TestResult:
|
|
||||||
actual_value = debugger.get_variable_value(test.variable)
|
|
||||||
if actual_value is None:
|
|
||||||
return TestResult(
|
|
||||||
test=test,
|
|
||||||
status='error',
|
|
||||||
message=f'Unable to fetch value for {test.variable}'
|
|
||||||
)
|
|
||||||
|
|
||||||
actual_value = actual_value.strip()
|
|
||||||
expected_value = test.expected_value.strip()
|
|
||||||
|
|
||||||
if actual_value == expected_value:
|
|
||||||
return TestResult(
|
|
||||||
test=test,
|
|
||||||
status='pass',
|
|
||||||
actual=actual_value
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return TestResult(
|
|
||||||
test=test,
|
|
||||||
status='fail',
|
|
||||||
actual=actual_value
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def print_test_results(results: TestResults) -> None:
|
|
||||||
log("\nTest results:")
|
|
||||||
log(f" Total tests: {results.total}")
|
|
||||||
log(f" Passed tests: {results.passed}")
|
|
||||||
log(f" Failed tests: {results.failed}")
|
|
||||||
if results.total == results.passed:
|
|
||||||
log("All tests passed!")
|
|
||||||
else:
|
|
||||||
log("Some tests failed")
|
|
||||||
|
|
||||||
|
|
||||||
def print_test_result(result: TestResult, verbose: bool) -> None:
|
|
||||||
status_symbol = "✓" if result.status == 'pass' else "✗"
|
|
||||||
status_text = "Pass" if result.status == 'pass' else "Fail"
|
|
||||||
test = result.test
|
|
||||||
|
|
||||||
if result.status == 'pass':
|
|
||||||
if verbose:
|
|
||||||
log(f"{status_symbol} Line {test.line_number}, {test.variable}: {status_text}")
|
|
||||||
if test.variable == 'all variables':
|
|
||||||
log(f" Variables: {', '.join(sorted(result.actual))}")
|
|
||||||
else: # fail or error
|
|
||||||
log(f"{status_symbol} Line {test.line_number}, {test.variable}: {status_text}")
|
|
||||||
if test.variable == 'all variables':
|
|
||||||
if result.missing:
|
|
||||||
log(f" Missing variables: {', '.join(sorted(result.missing))}")
|
|
||||||
if result.extra:
|
|
||||||
log(f" Extra variables: {', '.join(sorted(result.extra))}")
|
|
||||||
log(f" Expected: {', '.join(sorted(test.expected_value.split()))}")
|
|
||||||
log(f" Actual: {', '.join(sorted(result.actual))}")
|
|
||||||
elif result.status == 'error':
|
|
||||||
log(f" Error: {result.message}")
|
|
||||||
else:
|
|
||||||
log(f" Expected: {test.expected_value}")
|
|
||||||
log(f" Actual: {result.actual}")
|
|
||||||
|
|
||||||
|
|
||||||
def run_tests_with_result(executable_path: str, source_files: List[str], verbose: bool, interactive: bool, plugin_path: Optional[str], result_path: str) -> int:
|
|
||||||
try:
|
|
||||||
exit_code = run_tests(executable_path, source_files,
|
|
||||||
verbose, interactive, plugin_path)
|
|
||||||
except Exception as e:
|
|
||||||
log(f"An error occurred during test execution: {str(e)}")
|
|
||||||
exit_code = 2 # Use a different exit code for unexpected errors
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(result_path, 'w', encoding='utf-8') as f:
|
|
||||||
f.write(str(exit_code))
|
|
||||||
except IOError as e:
|
|
||||||
log(f"Error writing result to file {result_path}: {str(e)}")
|
|
||||||
# If we can't write to the file, we should still return the exit code
|
|
||||||
|
|
||||||
return exit_code
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
log(sys.argv)
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="LLDB 18 Debug Script with DWARF 5 Support")
|
|
||||||
parser.add_argument("executable", help="Path to the executable")
|
|
||||||
parser.add_argument("sources", nargs='+', help="Paths to the source files")
|
|
||||||
parser.add_argument("-v", "--verbose", action="store_true",
|
|
||||||
help="Enable verbose output")
|
|
||||||
parser.add_argument("-i", "--interactive", action="store_true",
|
|
||||||
help="Enable interactive mode on test failure")
|
|
||||||
parser.add_argument("--plugin", help="Path to the LLDB plugin")
|
|
||||||
parser.add_argument("--result-path", help="Path to write the result")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
plugin_path = args.plugin or os.path.join(os.path.dirname(
|
|
||||||
os.path.realpath(__file__)), "go_lldb_plugin.py")
|
|
||||||
|
|
||||||
try:
|
|
||||||
if args.result_path:
|
|
||||||
exit_code = run_tests_with_result(args.executable, args.sources,
|
|
||||||
args.verbose, args.interactive, plugin_path, args.result_path)
|
|
||||||
else:
|
|
||||||
exit_code = run_tests(args.executable, args.sources,
|
|
||||||
args.verbose, args.interactive, plugin_path)
|
|
||||||
except Exception as e:
|
|
||||||
log(f"An unexpected error occurred: {str(e)}")
|
|
||||||
exit_code = 2 # Use a different exit code for unexpected errors
|
|
||||||
|
|
||||||
sys.exit(exit_code)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/math"
|
"github.com/goplus/llgo/py/math"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
module github.com/goplus/llgo/_pydemo
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require github.com/goplus/lib v0.2.0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
|
||||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/numpy"
|
"github.com/goplus/llgo/py/numpy"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/py/math"
|
"github.com/goplus/llgo/py/math"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/statistics"
|
"github.com/goplus/llgo/py/statistics"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/py"
|
"github.com/goplus/llgo/py"
|
||||||
"github.com/goplus/lib/py/std"
|
"github.com/goplus/llgo/py/std"
|
||||||
"github.com/goplus/lib/py/torch"
|
"github.com/goplus/llgo/py/torch"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,221 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
|
||||||
"github.com/goplus/lib/c/clang"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Data struct {
|
|
||||||
Depth c.Uint
|
|
||||||
Unit *clang.TranslationUnit
|
|
||||||
}
|
|
||||||
|
|
||||||
var accessMap = map[clang.CXXAccessSpecifier]string{
|
|
||||||
clang.CXXInvalidAccessSpecifier: "invalid",
|
|
||||||
clang.CXXPublic: "public",
|
|
||||||
clang.CXXProtected: "protected",
|
|
||||||
clang.CXXPrivate: "private",
|
|
||||||
}
|
|
||||||
|
|
||||||
func printIndent(depth c.Uint) {
|
|
||||||
fmt.Print(strings.Repeat(" ", int(depth)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func accessToString(spec clang.CXXAccessSpecifier) string {
|
|
||||||
if str, ok := accessMap[spec]; ok {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
func visit(cursor, parent clang.Cursor, ClientData c.Pointer) clang.ChildVisitResult {
|
|
||||||
data := (*Data)(ClientData)
|
|
||||||
printAST(cursor, data)
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
}
|
|
||||||
|
|
||||||
func printType(t clang.Type, data *Data) {
|
|
||||||
printIndent(data.Depth)
|
|
||||||
|
|
||||||
typeSpell := t.String()
|
|
||||||
typeKind := t.Kind.String()
|
|
||||||
|
|
||||||
if t.Kind == clang.TypeInvalid {
|
|
||||||
} else if t.Kind == clang.TypeUnexposed {
|
|
||||||
c.Printf(c.Str("<UnexposedType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
|
|
||||||
} else if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin {
|
|
||||||
c.Printf(c.Str("<BuiltinType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
|
|
||||||
} else if t.Kind > clang.TypeComplex {
|
|
||||||
c.Printf(c.Str("<ComplexType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Depth++
|
|
||||||
switch t.Kind {
|
|
||||||
case clang.TypePointer:
|
|
||||||
printType(t.PointeeType(), data)
|
|
||||||
case clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray, clang.TypeConstantArray:
|
|
||||||
printType(t.ArrayElementType(), data)
|
|
||||||
case clang.TypeTypedef:
|
|
||||||
printType(t.TypeDeclaration().TypedefDeclUnderlyingType(), data)
|
|
||||||
case clang.TypeElaborated:
|
|
||||||
printType(t.NamedType(), data)
|
|
||||||
case clang.TypeFunctionProto:
|
|
||||||
printType(t.ResultType(), data)
|
|
||||||
for i := 0; i < int(t.NumArgTypes()); i++ {
|
|
||||||
printType(t.ArgType(c.Uint(i)), data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.Depth--
|
|
||||||
|
|
||||||
typeKind.Dispose()
|
|
||||||
typeSpell.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printLocation(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("(Loc:%s:%d:%d)\n"), filename.CStr(), line, column)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printAccess(cursor clang.Cursor) {
|
|
||||||
kind := cursor.Kind.String()
|
|
||||||
spell := cursor.String()
|
|
||||||
defer kind.Dispose()
|
|
||||||
defer spell.Dispose()
|
|
||||||
|
|
||||||
c.Printf(c.Str("%s: %s %s"), kind.CStr(), spell.CStr(), c.AllocaCStr(accessToString(cursor.CXXAccessSpecifier())))
|
|
||||||
printLocation(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printMacro(cursor clang.Cursor, unit *clang.TranslationUnit) {
|
|
||||||
kind := cursor.Kind.String()
|
|
||||||
defer kind.Dispose()
|
|
||||||
|
|
||||||
c.Printf(c.Str("%s: "), kind.CStr())
|
|
||||||
ran := cursor.Extent()
|
|
||||||
var numTokens c.Uint
|
|
||||||
var tokens *clang.Token
|
|
||||||
unit.Tokenize(ran, &tokens, &numTokens)
|
|
||||||
defer unit.DisposeTokens(tokens, numTokens)
|
|
||||||
|
|
||||||
tokensSlice := unsafe.Slice(tokens, int(numTokens))
|
|
||||||
for _, tok := range tokensSlice {
|
|
||||||
tokStr := unit.Token(tok)
|
|
||||||
c.Printf(c.Str("%s "), tokStr.CStr())
|
|
||||||
tokStr.Dispose()
|
|
||||||
}
|
|
||||||
printLocation(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printFunc(cursor clang.Cursor, data *Data) {
|
|
||||||
kind := cursor.Kind.String()
|
|
||||||
spell := cursor.String()
|
|
||||||
symbol := cursor.Mangling()
|
|
||||||
defer symbol.Dispose()
|
|
||||||
defer kind.Dispose()
|
|
||||||
defer spell.Dispose()
|
|
||||||
|
|
||||||
c.Printf(c.Str("%s: %s (Symbol: %s)"), kind.CStr(), spell.CStr(), symbol.CStr())
|
|
||||||
printLocation(cursor)
|
|
||||||
printType(cursor.Type(), data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printEnumConstant(cursor clang.Cursor) {
|
|
||||||
kind := cursor.Kind.String()
|
|
||||||
spell := cursor.String()
|
|
||||||
defer kind.Dispose()
|
|
||||||
defer spell.Dispose()
|
|
||||||
|
|
||||||
c.Printf(c.Str("%s: %s:%lld"), kind.CStr(), spell.CStr(), cursor.EnumConstantDeclValue())
|
|
||||||
printLocation(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printDefault(cursor clang.Cursor, data *Data) {
|
|
||||||
kind := cursor.Kind.String()
|
|
||||||
spell := cursor.String()
|
|
||||||
defer kind.Dispose()
|
|
||||||
defer spell.Dispose()
|
|
||||||
|
|
||||||
// node which has type
|
|
||||||
if cursor.Type().Kind != clang.TypeInvalid {
|
|
||||||
c.Printf(c.Str("%s: %s"), kind.CStr(), spell.CStr())
|
|
||||||
printLocation(cursor)
|
|
||||||
printType(cursor.Type(), data)
|
|
||||||
} else {
|
|
||||||
c.Printf(c.Str("%s: %s\n"), kind.CStr(), spell.CStr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printAST(cursor clang.Cursor, data *Data) {
|
|
||||||
kind := cursor.Kind.String()
|
|
||||||
spell := cursor.String()
|
|
||||||
|
|
||||||
printIndent(data.Depth)
|
|
||||||
|
|
||||||
switch cursor.Kind {
|
|
||||||
case clang.CursorCXXAccessSpecifier:
|
|
||||||
printAccess(cursor)
|
|
||||||
case clang.CursorMacroDefinition:
|
|
||||||
printMacro(cursor, data.Unit)
|
|
||||||
case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor:
|
|
||||||
printFunc(cursor, data)
|
|
||||||
case clang.CursorEnumConstantDecl:
|
|
||||||
printEnumConstant(cursor)
|
|
||||||
default:
|
|
||||||
printDefault(cursor, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Depth++
|
|
||||||
clang.VisitChildren(cursor, visit, c.Pointer(data))
|
|
||||||
data.Depth--
|
|
||||||
|
|
||||||
kind.Dispose()
|
|
||||||
spell.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if c.Argc != 2 {
|
|
||||||
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]*c.Char, 3)
|
|
||||||
args[0] = c.Str("-x")
|
|
||||||
args[1] = c.Str("c++")
|
|
||||||
args[2] = c.Str("-std=c++11")
|
|
||||||
|
|
||||||
sourceFile := *c.Advance(c.Argv, 1)
|
|
||||||
index := clang.CreateIndex(0, 0)
|
|
||||||
unit := index.ParseTranslationUnit(
|
|
||||||
sourceFile,
|
|
||||||
unsafe.SliceData(args), 3,
|
|
||||||
nil, 0,
|
|
||||||
clang.DetailedPreprocessingRecord,
|
|
||||||
)
|
|
||||||
defer index.Dispose()
|
|
||||||
defer unit.Dispose()
|
|
||||||
|
|
||||||
if unit == nil {
|
|
||||||
println("Unable to parse translation unit. Quitting.")
|
|
||||||
c.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor := unit.Cursor()
|
|
||||||
|
|
||||||
Data := &Data{
|
|
||||||
Depth: 0,
|
|
||||||
Unit: unit,
|
|
||||||
}
|
|
||||||
printAST(cursor, Data)
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module github.com/goplus/llgo/_xtool
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require github.com/goplus/lib v0.2.0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
|
||||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
|
||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/runtime/internal/clite/bdwgc"
|
"github.com/goplus/llgo/c/bdwgc"
|
||||||
"github.com/goplus/llgo/runtime/internal/clite/bdwgc/_test/testing"
|
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ------ Test malloc ------
|
// ------ Test malloc ------
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/runtime/internal/clite/bdwgc/_test/testing"
|
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
@@ -19,7 +19,7 @@ package bdwgc
|
|||||||
import (
|
import (
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
17
c/bitcast/_cast/cast.c
Normal file
17
c/bitcast/_cast/cast.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -24,13 +24,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname ToFloat64 C.llgoToFloat64
|
//go:linkname ToFloat64 C.llgoToFloat64
|
||||||
func ToFloat64(v int64) float64
|
func ToFloat64(v uintptr) float64
|
||||||
|
|
||||||
//go:linkname ToFloat32 C.llgoToFloat32
|
//go:linkname ToFloat32 C.llgoToFloat32
|
||||||
func ToFloat32(v int32) float32
|
func ToFloat32(v uintptr) float32
|
||||||
|
|
||||||
//go:linkname FromFloat64 C.llgoFromFloat64
|
|
||||||
func FromFloat64(v float64) int64
|
|
||||||
|
|
||||||
//go:linkname FromFloat32 C.llgoFromFloat32
|
|
||||||
func FromFloat32(v float32) int32
|
|
||||||
@@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package c
|
package c
|
||||||
|
|
||||||
import (
|
// typedef unsigned int uint;
|
||||||
"unsafe"
|
// typedef unsigned long ulong;
|
||||||
)
|
// typedef unsigned long long ulonglong;
|
||||||
|
// typedef long long longlong;
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LLGoPackage = "decl"
|
LLGoPackage = "decl"
|
||||||
@@ -30,50 +33,24 @@ type (
|
|||||||
Float = float32
|
Float = float32
|
||||||
Double = float64
|
Double = float64
|
||||||
Pointer = unsafe.Pointer
|
Pointer = unsafe.Pointer
|
||||||
FilePtr = *FILE
|
FilePtr = unsafe.Pointer
|
||||||
)
|
)
|
||||||
|
|
||||||
type FILE struct {
|
|
||||||
Unused [8]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Int = int32
|
Int C.int
|
||||||
Uint = uint32
|
Uint C.uint
|
||||||
|
|
||||||
// Long and Ulong are defined in platform-specific files
|
Long C.long
|
||||||
// Windows (both 32-bit and 64-bit): int32/uint32
|
Ulong C.ulong
|
||||||
// Unix/Linux/macOS 32-bit: int32/uint32
|
|
||||||
// Unix/Linux/macOS 64-bit: int64/uint64
|
|
||||||
|
|
||||||
LongLong = int64
|
LongLong C.longlong
|
||||||
UlongLong = uint64
|
UlongLong C.ulonglong
|
||||||
)
|
)
|
||||||
|
|
||||||
type integer interface {
|
type integer interface {
|
||||||
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type SizeT = uintptr
|
|
||||||
type SsizeT = Long
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
type VaList = Pointer
|
|
||||||
|
|
||||||
//go:linkname Str llgo.cstr
|
//go:linkname Str llgo.cstr
|
||||||
func Str(string) *Char
|
func Str(string) *Char
|
||||||
|
|
||||||
@@ -92,9 +69,6 @@ func Alloca(size uintptr) Pointer
|
|||||||
//go:linkname AllocaCStr llgo.allocaCStr
|
//go:linkname AllocaCStr llgo.allocaCStr
|
||||||
func AllocaCStr(s string) *Char
|
func AllocaCStr(s string) *Char
|
||||||
|
|
||||||
//go:linkname AllocCStr llgo.allocCStr
|
|
||||||
func AllocCStr(s string) *Char
|
|
||||||
|
|
||||||
//go:linkname AllocaCStrs llgo.allocaCStrs
|
//go:linkname AllocaCStrs llgo.allocaCStrs
|
||||||
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
||||||
|
|
||||||
@@ -105,15 +79,9 @@ func AllocaNew[T any]() *T { return nil }
|
|||||||
//go:linkname Malloc C.malloc
|
//go:linkname Malloc C.malloc
|
||||||
func Malloc(size uintptr) Pointer
|
func Malloc(size uintptr) Pointer
|
||||||
|
|
||||||
//go:linkname Calloc C.calloc
|
|
||||||
func Calloc(num uintptr, size uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Free C.free
|
//go:linkname Free C.free
|
||||||
func Free(ptr Pointer)
|
func Free(ptr Pointer)
|
||||||
|
|
||||||
//go:linkname Realloc C.realloc
|
|
||||||
func Realloc(ptr Pointer, size uintptr) Pointer
|
|
||||||
|
|
||||||
//go:linkname Memcpy C.memcpy
|
//go:linkname Memcpy C.memcpy
|
||||||
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
||||||
|
|
||||||
@@ -245,9 +213,6 @@ func Fputc(c Int, fp FilePtr) Int
|
|||||||
//go:linkname Fputs C.fputs
|
//go:linkname Fputs C.fputs
|
||||||
func Fputs(s *Char, fp FilePtr) Int
|
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
|
//go:linkname Fflush C.fflush
|
||||||
func Fflush(fp FilePtr) Int
|
func Fflush(fp FilePtr) Int
|
||||||
|
|
||||||
@@ -262,14 +227,6 @@ func Perror(s *Char)
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type IconvT = Pointer
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type LocaleT = Pointer
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//go:linkname Usleep C.usleep
|
//go:linkname Usleep C.usleep
|
||||||
func Usleep(useconds Uint) Int
|
func Usleep(useconds Uint) Int
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//go:build darwin
|
//go:build !linux
|
||||||
// +build darwin
|
// +build !linux
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//go:build !darwin
|
//go:build linux
|
||||||
// +build !darwin
|
// +build linux
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
31
c/cjson/README.md
Normal file
31
c/cjson/README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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 .
|
||||||
|
```
|
||||||
43
c/cjson/_demo/mkjson/mkjson.go
Normal file
43
c/cjson/_demo/mkjson/mkjson.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
153
c/cjson/cjson.go
Normal file
153
c/cjson/cjson.go
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// llgo:type C
|
||||||
|
type JSON struct {
|
||||||
|
Unused [0]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname Parse C.cJSON_Parse
|
||||||
|
func Parse(value *c.Char) *JSON
|
||||||
|
|
||||||
|
//go:linkname ParseWithLength C.cJSON_ParseWithLength
|
||||||
|
func ParseWithLength(value *byte, valueLength uintptr) *JSON
|
||||||
|
|
||||||
|
func ParseBytes(value []byte) *JSON {
|
||||||
|
return ParseWithLength(unsafe.SliceData(value), uintptr(len(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseString(value string) *JSON {
|
||||||
|
return ParseWithLength(unsafe.StringData(value), uintptr(len(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname Null C.cJSON_CreateNull
|
||||||
|
func Null() *JSON
|
||||||
|
|
||||||
|
//go:linkname True C.cJSON_CreateTrue
|
||||||
|
func True() *JSON
|
||||||
|
|
||||||
|
//go:linkname False C.cJSON_CreateFalse
|
||||||
|
func False() *JSON
|
||||||
|
|
||||||
|
//go:linkname Bool C.cJSON_CreateBool
|
||||||
|
func Bool(boolean c.Int) *JSON
|
||||||
|
|
||||||
|
//go:linkname Number C.cJSON_CreateNumber
|
||||||
|
func Number(num float64) *JSON
|
||||||
|
|
||||||
|
//go:linkname String C.cJSON_CreateString
|
||||||
|
func String(str *c.Char) *JSON
|
||||||
|
|
||||||
|
//go:linkname Array C.cJSON_CreateArray
|
||||||
|
func Array() *JSON
|
||||||
|
|
||||||
|
//go:linkname Object C.cJSON_CreateObject
|
||||||
|
func Object() *JSON
|
||||||
|
|
||||||
|
// raw json
|
||||||
|
//
|
||||||
|
//go:linkname Raw C.cJSON_CreateRaw
|
||||||
|
func Raw(raw *c.Char) *JSON
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Delete a JSON entity and all subentities.
|
||||||
|
//
|
||||||
|
// llgo:link (*JSON).Delete C.cJSON_Delete
|
||||||
|
func (o *JSON) Delete() {}
|
||||||
|
|
||||||
|
// Append item to the specified array.
|
||||||
|
//
|
||||||
|
// llgo:link (*JSON).AddItem C.cJSON_AddItemToArray
|
||||||
|
func (o *JSON) AddItem(item *JSON) c.Int { return 0 }
|
||||||
|
|
||||||
|
// Append item to the specified object.
|
||||||
|
//
|
||||||
|
// llgo:link (*JSON).SetItem C.cJSON_AddItemToObject
|
||||||
|
func (o *JSON) SetItem(key *c.Char, item *JSON) c.Int { return 0 }
|
||||||
|
|
||||||
|
// 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 }
|
||||||
|
|
||||||
|
// Render a JSON entity to text for transfer/storage.
|
||||||
|
//
|
||||||
|
// llgo:link (*JSON).Print C.cJSON_Print
|
||||||
|
func (o *JSON) Print() *c.Char { return nil }
|
||||||
|
|
||||||
|
// 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 }
|
||||||
|
|
||||||
|
// 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 c.Int) *c.Char { return nil }
|
||||||
|
|
||||||
|
// llgo:link (*JSON).GetObjectItemCaseSensitive C.cJSON_GetObjectItemCaseSensitive
|
||||||
|
func (o *JSON) GetObjectItemCaseSensitive(key *c.Char) *JSON { return nil }
|
||||||
|
|
||||||
|
// llgo:link (*JSON).GetArraySize C.cJSON_GetArraySize
|
||||||
|
func (o *JSON) GetArraySize() c.Int { return 0 }
|
||||||
|
|
||||||
|
// llgo:link (*JSON).GetArrayItem C.cJSON_GetArrayItem
|
||||||
|
func (o *JSON) GetArrayItem(index c.Int) *JSON { return nil }
|
||||||
|
|
||||||
|
// llgo:link (*JSON).GetStringValue C.cJSON_GetStringValue
|
||||||
|
func (o *JSON) GetStringValue() *c.Char { return nil }
|
||||||
|
|
||||||
|
//go:linkname Free C.cJSON_free
|
||||||
|
func Free(ptr unsafe.Pointer)
|
||||||
|
|
||||||
|
//go:linkname FreeCStr C.cJSON_free
|
||||||
|
func FreeCStr(*c.Char)
|
||||||
61
c/clang/_demo/castdump/astdump.go
Normal file
61
c/clang/_demo/castdump/astdump.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/c/clang"
|
||||||
|
)
|
||||||
|
|
||||||
|
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
||||||
|
depth := *(*c.Uint)(clientData)
|
||||||
|
printAST(cursor, depth+1)
|
||||||
|
return clang.ChildVisit_Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func printAST(cursor clang.Cursor, depth c.Uint) {
|
||||||
|
cursorKind := cursor.Kind.String()
|
||||||
|
|
||||||
|
cursorSpelling := cursor.String()
|
||||||
|
|
||||||
|
for i := c.Uint(0); i < depth; i++ {
|
||||||
|
c.Fputs(c.Str(" "), c.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Printf(c.Str("%s: %s\n"), cursorKind.CStr(), cursorSpelling.CStr())
|
||||||
|
|
||||||
|
cursorKind.Dispose()
|
||||||
|
cursorSpelling.Dispose()
|
||||||
|
|
||||||
|
clang.VisitChildren(cursor, visit, c.Pointer(&depth))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if c.Argc != 2 {
|
||||||
|
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sourceFile := *c.Advance(c.Argv, 1)
|
||||||
|
|
||||||
|
index := clang.CreateIndex(0, 0)
|
||||||
|
|
||||||
|
unit := index.ParseTranslationUnit(
|
||||||
|
sourceFile,
|
||||||
|
nil, 0,
|
||||||
|
nil, 0,
|
||||||
|
clang.TranslationUnit_None,
|
||||||
|
)
|
||||||
|
|
||||||
|
if unit == nil {
|
||||||
|
println("Unable to parse translation unit. Quitting.")
|
||||||
|
c.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := unit.Cursor()
|
||||||
|
|
||||||
|
printAST(cursor, 0)
|
||||||
|
|
||||||
|
unit.Dispose()
|
||||||
|
index.Dispose()
|
||||||
|
}
|
||||||
163
c/clang/_demo/symboldump/symboldump.go
Normal file
163
c/clang/_demo/symboldump/symboldump.go
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
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.CXXMethod || cursor.Kind == clang.FunctionDecl {
|
||||||
|
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.MacroDefinition {
|
||||||
|
printMarcoInfo(cursor)
|
||||||
|
} else if cursor.Kind == clang.Namespace {
|
||||||
|
nameStr := cursor.String()
|
||||||
|
context.setNamespaceName(c.GoString(nameStr.CStr()))
|
||||||
|
clang.VisitChildren(cursor, visit, nil)
|
||||||
|
context.setNamespaceName("")
|
||||||
|
} else if cursor.Kind == clang.ClassDecl {
|
||||||
|
nameStr := cursor.String()
|
||||||
|
context.setClassName(c.GoString(nameStr.CStr()))
|
||||||
|
clang.VisitChildren(cursor, visit, nil)
|
||||||
|
context.setClassName("")
|
||||||
|
} else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
60
c/clang/_wrap/cursor.cpp
Normal file
60
c/clang/_wrap/cursor.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#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" {
|
||||||
|
|
||||||
|
CXString wrap_clang_getCursorSpelling(CXCursor *cur) { return clang_getCursorSpelling(*cur); }
|
||||||
|
|
||||||
|
CXString wrap_clang_Cursor_getMangling(CXCursor *cur) { return clang_Cursor_getMangling(*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_getTranslationUnitCursor(CXTranslationUnit uint, CXCursor *cur) {
|
||||||
|
*cur = clang_getTranslationUnitCursor(uint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrap_clang_getCursorType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorType(*cur); }
|
||||||
|
|
||||||
|
void wrap_clang_getCursorResultType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorResultType(*cur); }
|
||||||
|
|
||||||
|
CXString wrap_clang_getTypeSpelling(CXType *typ) { return clang_getTypeSpelling(*typ); }
|
||||||
|
|
||||||
|
CXString wrap_clang_getTokenSpelling(CXTranslationUnit unit, CXToken *token) {
|
||||||
|
return clang_getTokenSpelling(unit, *token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrap_clang_getCursorLocation(CXCursor *cur, CXSourceLocation *loc) { *loc = clang_getCursorLocation(*cur); }
|
||||||
|
|
||||||
|
void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigned *line, unsigned *column,
|
||||||
|
unsigned *offset) {
|
||||||
|
clang_getSpellingLocation(*loc, file, line, column, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); }
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
7
c/clang/_wrap/llgo_check.cpp
Normal file
7
c/clang/_wrap/llgo_check.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("sizeof(clang.Cursor) = %lu\n", sizeof(CXCursor));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
16
c/clang/_wrap/llgo_check.go
Normal file
16
c/clang/_wrap/llgo_check.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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{}))
|
||||||
|
}
|
||||||
59
c/clang/basic.go
Normal file
59
c/clang/basic.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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() {}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user