Compare commits

..

29 Commits

Author SHA1 Message Date
xushiwei
ee0e0a5c51 Merge pull request #666 from cpunion/async-functions
Async functions
2024-08-06 20:38:34 +08:00
Li Jie
7b2747ce0c asyncio: merge promise and coro frame allocation 2024-08-06 14:44:16 +08:00
Li Jie
578bc165c4 test: fix cl and ssa tests 2024-08-05 21:19:19 +08:00
Li Jie
a1d46e905b asyncio: demo & test 2024-08-05 20:36:02 +08:00
Li Jie
9102ca6b1e ssa: workaround for LLVM attribute compilation errors 2024-08-05 20:35:58 +08:00
Li Jie
835d6fee1e cl: test async function compiling 2024-08-05 18:10:57 +08:00
Li Jie
294abb5126 ssa: test Builder.Switch 2024-08-05 18:00:14 +08:00
Li Jie
5fca8ebd4e ssa: test coroutine builders 2024-08-05 17:25:13 +08:00
Li Jie
d3df782fca asyncic: coReturn 2024-08-05 17:25:13 +08:00
Li Jie
b04ac8df30 ssa: comment unused coroutine builders 2024-08-05 16:43:36 +08:00
Li Jie
bb03df7059 ssa: refactor Builder.BeginAsync 2024-08-05 16:42:51 +08:00
Li Jie
98072f3f4b asyncio: fix unreasonable return type of promise.Next() 2024-08-05 15:21:14 +08:00
Li Jie
3bf0780a67 asyncio: trap on unexpected resume 2024-08-05 15:19:42 +08:00
Li Jie
a1fdc05e26 cl: fix CoYield 2024-08-05 12:37:34 +08:00
Li Jie
93bff83e3d ssa: fix @llvm.coro.size.i64 doc 2024-08-05 10:41:39 +08:00
Li Jie
e470bc2069 Merge commit 'd06146ed970f52d564521ff0be7d56839c85e497' into async-functions
* commit 'd06146ed970f52d564521ff0be7d56839c85e497': (152 commits)
  perf(lib/sync): avoid using `defer`
  refactor(c-libuv): Added TODO(uid) comment & adjusted the position of Handle, Stream, Req, Write, Connect
  README: io/ioutil
  library: io/ioutil
  c/openssl: bio, pem, rsa
  refactor(c/libuv): Adapt libuv.Fs struct
  Revert "fix(c/libuv): Add libuv fs struct new func"
  fix(c/libuv): Fix async_fs demo return 255 error & pointer not allocated error
  fix(c/libuv): Add libuv fs struct new func
  doc/c:refine symbol visibility description
  README: math/big
  library: math/big.Int (mini-impl for _cmptest/bigintdemo)
  doc/c:update implicit destructors description
  c/openssl: bignum, rsa
  library: crypto
  library: crypto/{sha1, sha256, sha512}
  doc/c:fix incorrect usage in construtors
  doc/c:update destructor usage
  delete sum
  fix test error
  ...

# Conflicts:
#	ssa/eh.go
2024-08-04 10:26:27 +08:00
Li Jie
efa771f3ff cl: compile async functions 2024-08-04 10:22:22 +08:00
Li Jie
806193fc6e ssa: set expr name for debug readable 2024-08-03 20:57:38 +08:00
Li Jie
cdfa0166bd ssa: make block with label name for debug readable 2024-08-03 20:51:43 +08:00
Li Jie
0687efaec6 ssa: add coroution intrinsics 2024-07-31 21:57:32 +08:00
Li Jie
0d3e78ad94 asyncio: x/io -> x/async 2024-07-29 23:17:21 +08:00
Li Jie
375b2b579e asyncio: refactor 2024-07-29 15:42:00 +08:00
Li Jie
a578155dcb asyncio: multi return types promise/generator 2024-07-29 10:46:14 +08:00
Li Jie
df5f1afb74 asyncio: demo comments 2024-07-27 15:26:02 +08:00
Li Jie
b2a2b2f29d asyncio: generator 2024-07-27 15:08:09 +08:00
Li Jie
91df9957f5 asyncio: parallel and concurrent extra functions 2024-07-26 10:15:41 +08:00
Li Jie
08e0ace9a2 asyncio: improve schedule 2024-07-25 11:04:40 +08:00
Li Jie
a4286dbd4b asyncio: improve performance by scheduling last frame 2024-07-25 11:02:02 +08:00
Li Jie
f2e15a6846 asyncio: poc 2024-07-25 08:50:49 +08:00
2550 changed files with 91419 additions and 467437 deletions

View File

@@ -1,72 +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"
install-llvm:
description: "Whether to install LLVM"
required: false
default: "true"
runs:
using: "composite"
steps:
- name: Install macOS dependencies
if: runner.os == 'macOS'
shell: bash
run: |
brew update
# Install LLVM if requested
if [[ "${{ inputs.install-llvm }}" == "true" ]]; then
brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}}
brew link --overwrite llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}}
echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH
fi
# Install common dependencies
brew install bdw-gc openssl libffi libuv
brew link --overwrite libffi
# 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
)
brew install "${opt_deps[@]}"
brew install python@3.12 || true # for github.com/goplus/lib/py
brew link --overwrite python@3.12
- name: Install Ubuntu dependencies
if: runner.os == 'Linux'
shell: bash
run: |
# Install LLVM if requested
if [[ "${{ inputs.install-llvm }}" == "true" ]]; then
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}} libunwind-${{inputs.llvm-version}}-dev libc++-${{inputs.llvm-version}}-dev
echo "PATH=/usr/lib/llvm-${{inputs.llvm-version}}/bin:$PATH" >> $GITHUB_ENV
else
sudo apt-get update
fi
# Install common dependencies
sudo apt-get install -y pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libuv1-dev
# 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[@]}"

View File

@@ -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

View File

@@ -1,28 +0,0 @@
name: "Setup GoReleaser"
description: "Setup GoReleaser environment"
inputs:
linux-cache-key:
description: "Linux sysroot cache key"
required: true
runs:
using: "composite"
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.24.x
- name: Restore Linux sysroot cache
id: cache-linux-sysroot
uses: actions/cache/restore@v4
with:
path: .sysroot/linux.tar.gz
key: ${{ inputs.linux-cache-key }}
- name: Populate Linux sysroot
run: tar -xzvf .sysroot/linux.tar.gz -C .sysroot
shell: bash
- name: Check file
run: tree .sysroot
shell: bash
- name: Get Esp clang
run: bash .github/workflows/download_esp_clang.sh
shell: bash

View File

@@ -1,63 +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"
"github.com/goplus/lib/cpp/std"
)
func main() {
fmt.Println("Hello, LLGo!")
println("Hello, LLGo!")
c.Printf(c.Str("Hello, LLGo!\n"))
c.Printf(std.Str("Hello LLGo by cpp/std.Str\n").CStr())
}
EOL
go mod tidy
EXPECTED="Hello, LLGo!
Hello, LLGo!
Hello, LLGo!
Hello LLGo by cpp/std.Str"
OUTPUT=$(llgo run . 2>&1 | tee /dev/stderr)
if echo "$OUTPUT" | grep -qF "$EXPECTED"; then
echo "Basic test passed"
else
echo "Basic test failed"
echo "Expected to contain:"
echo "$EXPECTED"
echo "Got:"
echo "$OUTPUT"
exit 1
fi
cd ../..
mkdir -p _test/emb && cd _test/emb
cat > main.go << 'EOL'
package main
func main() {
}
EOL
llgo build -v -target esp32-coreboard-v2 -o demo.out .
test -f demo.out.elf && echo "ESP32 cross-compilation test passed: demo.out.elf generated"
exit $?

15
.github/codecov.yml vendored
View File

@@ -1,15 +0,0 @@
coverage:
ignore:
- "chore"
- "cmd"
- "cl/cltest"
- "internal/build"
- "internal/llgen"
- "internal/mockable"
- "internal/packages"
- "internal/typepatch"
- "internal/github"
- "internal/firmware"
- "internal/flash"
- "internal/monitor"
- "xtool"

View File

@@ -1,180 +0,0 @@
name: Docs
on:
push:
branches:
- "**"
- "!dependabot/**"
- "!xgopilot/**"
pull_request:
branches: ["**"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
doc_verify:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v6
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
timeout-minutes: 30
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- 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
timeout-minutes: 30
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v6
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
timeout-minutes: 30
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v6
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

View File

@@ -1,67 +0,0 @@
#!/bin/bash
set -e
ESP_CLANG_VERSION="19.1.2_20250905-3"
BASE_URL="https://github.com/goplus/espressif-llvm-project-prebuilt/releases/download/${ESP_CLANG_VERSION}"
get_esp_clang_platform() {
local platform="$1"
local os="${platform%-*}"
local arch="${platform##*-}"
case "${os}" in
"darwin")
case "${arch}" in
"amd64") echo "x86_64-apple-darwin" ;;
"arm64") echo "aarch64-apple-darwin" ;;
*) echo "Error: Unsupported darwin architecture: ${arch}" >&2; exit 1 ;;
esac
;;
"linux")
case "${arch}" in
"amd64") echo "x86_64-linux-gnu" ;;
"arm64") echo "aarch64-linux-gnu" ;;
*) echo "Error: Unsupported linux architecture: ${arch}" >&2; exit 1 ;;
esac
;;
*)
echo "Error: Unsupported OS: ${os}" >&2
exit 1
;;
esac
}
get_filename() {
local platform="$1"
local platform_suffix=$(get_esp_clang_platform "${platform}")
echo "clang-esp-${ESP_CLANG_VERSION}-${platform_suffix}.tar.xz"
}
download_and_extract() {
local platform="$1"
local os="${platform%-*}"
local arch="${platform##*-}"
local filename=$(get_filename "${platform}")
local download_url="${BASE_URL}/${filename}"
echo "Downloading ESP Clang for ${platform}..."
echo " URL: ${download_url}"
mkdir -p ".sysroot/${os}/${arch}/crosscompile/clang"
curl -fsSL "${download_url}" | tar -xJ -C ".sysroot/${os}/${arch}/crosscompile/clang" --strip-components=1
if [[ ! -f ".sysroot/${os}/${arch}/crosscompile/clang/bin/clang++" ]]; then
echo "Error: clang++ not found in ${platform} toolchain"
exit 1
fi
echo "${platform} ESP Clang ready in .sysroot/${os}/${arch}/crosscompile/clang"
}
echo "Downloading ESP Clang toolchain version ${ESP_CLANG_VERSION}..."
for platform in "darwin-amd64" "darwin-arm64" "linux-amd64" "linux-arm64"; do
download_and_extract "${platform}"
done
echo "ESP Clang toolchain completed successfully!"

View File

@@ -1,38 +0,0 @@
name: Format Check
on:
push:
branches:
- "**"
- "!dependabot/**"
- "!xgopilot/**"
pull_request:
branches: ["**"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
fmt:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- 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 ./... | grep -v xgo_autogen.go)" ]; then
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
exit 1
fi
popd
done
echo "All files are properly formatted."

View File

@@ -5,34 +5,67 @@ name: Go
on: on:
push: push:
branches: branches: [ "*" ]
- "**"
- "!dependabot/**"
- "!xgopilot/**"
pull_request: pull_request:
branches: ["**"] branches: [ "*" ]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
test: test:
continue-on-error: true
timeout-minutes: 30
strategy: strategy:
matrix: matrix:
os: os:
- macos-latest - macos-latest
- ubuntu-latest - ubuntu-24.04
llvm: [19] llvm: [18]
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- uses: actions/checkout@v5 - 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: |
@@ -41,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

View File

@@ -1,300 +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:
- "**"
- "!dependabot/**"
- "!xgopilot/**"
pull_request:
branches: ["**"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
download-model:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Download model file
run: |
mkdir -p ./_demo/c/llama2-c
wget -P ./_demo/c/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/c/llama2-c/stories15M.bin
retention-days: 1
llgo:
needs: download-model
continue-on-error: true
timeout-minutes: 30
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
llvm: [19]
go: ["1.21.13", "1.22.12", "1.23.6", "1.24.2"]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- name: Install dependencies
uses: ./.github/actions/setup-deps
with:
llvm-version: ${{matrix.llvm}}
- name: Download model artifact
uses: actions/download-artifact@v5
with:
name: llama2-model
path: ./_demo/c/llama2-c/
- name: Download platform-specific demo libs
run: |
if ${{ startsWith(matrix.os, 'macos') }}; then
DEMO_PKG="cargs_darwin_arm64.zip"
else
DEMO_PKG="cargs_linux_amd64.zip"
fi
mkdir -p ./_demo/c/cargs/libs
cd ./_demo/c/cargs/libs
wget https://github.com/goplus/llpkg/releases/download/cargs/v1.0.0/${DEMO_PKG}
unzip ${DEMO_PKG}
# Process pc template files - replace {{.Prefix}} with actual path
ACTUAL_PREFIX="$(pwd)"
for tmpl in lib/pkgconfig/*.pc.tmpl; do
pc_file="${tmpl%.tmpl}"
sed "s|{{.Prefix}}|${ACTUAL_PREFIX}|g" "$tmpl" > "$pc_file"
done
echo "PKG_CONFIG_PATH=${ACTUAL_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}" >> $GITHUB_ENV
- 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@v6
with:
go-version: ${{matrix.go}}
- name: Test demo without RPATH (expect failure)
run: |
echo "Testing demo without RPATH (should fail)..."
export LLGO_FULL_RPATH=false
pkg-config --libs cargs
if (cd ./_demo/c/cargs && llgo run .); then
echo "ERROR: cargs demo should have failed without RPATH!"
exit 1
else
echo "✓ cargs demo correctly failed without RPATH"
fi
- 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:${PKG_CONFIG_PATH}
export LLGO_FULL_RPATH=true
bash .github/workflows/test_demo.sh
- name: Test C header generation
run: |
echo "Testing C header generation in different build modes..."
cd _demo/go/export
chmod +x test.sh
./test.sh
- name: _xtool build tests
run: |
cd _xtool
llgo build -v ./...
- 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
timeout-minutes: 30
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
llvm: [19]
go: ["1.24.2"]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- 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@v6
with:
go-version: ${{matrix.go}}
- name: run llgo test
run: |
llgo test ./...
hello:
continue-on-error: true
timeout-minutes: 30
strategy:
matrix:
os: [ubuntu-latest, 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@v5
- 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
timeout-minutes: 30
strategy:
matrix:
os: [macos-latest]
llvm: [19]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- 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/c
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

40
.github/workflows/populate_darwin_sysroot.sh vendored Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
set -e
TMPDIR="$(mktemp -d)"
export TMPDIR
trap 'rm -rf "${TMPDIR}"' EXIT
DARWIN_AMD64_LLVM_PREFIX=.sysroot/darwin/amd64/usr/local/opt/llvm@18
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@18
mkdir -p "${DARWIN_AMD64_LLVM_PREFIX}" "${DARWIN_ARM64_LLVM_PREFIX}"
BREW_LLVM_FORMULA_JSON="$(mktemp)"
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_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_ARM64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_ARM64_LLVM_PREFIX}"
patch_homebrew_lib_dir() {
local LIB_DIR="$1"
local HOMEBREW_PREFIX="$2"
for DYLIB_FILE in "${LIB_DIR}"/*.dylib; do
if [[ -f "${DYLIB_FILE}" ]]; then
ID=$(otool -D "${DYLIB_FILE}" | grep '@@HOMEBREW_PREFIX@@' | awk '{print $1}')
if [[ -n "${ID}" ]]; then
NEW_ID=${ID/'@@HOMEBREW_PREFIX@@'/${HOMEBREW_PREFIX}}
install_name_tool -id "${NEW_ID}" "${DYLIB_FILE}"
fi
DEPS=$(otool -L "${DYLIB_FILE}" | grep '@@HOMEBREW_PREFIX@@' | awk '{print $1}')
for DEP in ${DEPS}; do
NEW_DEP=${DEP/'@@HOMEBREW_PREFIX@@'/${HOMEBREW_PREFIX}}
install_name_tool -change "${DEP}" "${NEW_DEP}" "${DYLIB_FILE}"
done
fi
done
}
patch_homebrew_lib_dir "${DARWIN_AMD64_LLVM_PREFIX}/lib" /usr/lib
patch_homebrew_lib_dir "${DARWIN_ARM64_LLVM_PREFIX}/lib" /opt/homebrew

View File

@@ -17,7 +17,12 @@ cat > "${POPULATE_LINUX_SYSROOT_SCRIPT}" << EOF
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
apt-get update apt-get update
apt-get install -y build-essential zlib1g-dev rsync apt-get install -y lsb-release gnupg2 wget rsync
echo "deb http://apt.llvm.org/\$(lsb_release -cs)/ llvm-toolchain-\$(lsb_release -cs)-18 main" | tee /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
apt-get update
apt-get install -y llvm-18-dev
error() { error() {
echo -e "\$1" >&2 echo -e "\$1" >&2
@@ -101,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)
@@ -133,11 +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}"
PID1=$! populate_linux_sysroot arm64 "${LINUX_ARM64_PREFIX}"
populate_linux_sysroot arm64 "${LINUX_ARM64_PREFIX}" &
PID2=$!
# Wait for both background processes to complete
wait $PID1 || exit $?
wait $PID2 || exit $?

View File

@@ -2,201 +2,52 @@ name: Release Build
on: on:
push: push:
branches: tags:
- "**" - "*"
- "!dependabot/**"
- "!xgopilot/**"
tags: ["*"]
pull_request:
branches: ["**"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
setup: populate-darwin-sysroot:
runs-on: ubuntu-latest runs-on: macos-latest
outputs:
linux-cache-key: ${{ steps.cache-keys.outputs.linux-key }}
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Calculate cache keys - name: Populate Darwin sysroot
id: cache-keys run: bash .github/workflows/populate_darwin_sysroot.sh
run: | - name: Create Darwin sysroot tarball
LINUX_KEY="linux-sysroot-${{ hashFiles('.github/workflows/populate_linux_sysroot.sh', '.github/workflows/release-build.yml') }}-v1.0.0" run: tar -czvf .sysroot/darwin.tar.gz -C .sysroot darwin
echo "linux-key=$LINUX_KEY" >> $GITHUB_OUTPUT - name: Upload Darwin sysroot tarball
populate-linux-sysroot: uses: actions/upload-artifact@v4
runs-on: ubuntu-latest
needs: setup
timeout-minutes: 30
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Check Linux sysroot cache
id: cache-linux-sysroot
uses: actions/cache/restore@v4
with: with:
path: .sysroot/linux.tar.gz name: darwin-sysroot-tarball
key: ${{ needs.setup.outputs.linux-cache-key }} path: .sysroot/darwin.tar.gz
lookup-only: true compression-level: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
if: steps.cache-linux-sysroot.outputs.cache-hit != 'true'
with:
image: tonistiigi/binfmt:qemu-v7.0.0-28
- name: Populate Linux sysroot
if: steps.cache-linux-sysroot.outputs.cache-hit != 'true'
run: bash .github/workflows/populate_linux_sysroot.sh
- name: Create Linux sysroot tarball
if: steps.cache-linux-sysroot.outputs.cache-hit != 'true'
run: tar -czvf .sysroot/linux.tar.gz -C .sysroot linux
- name: Save Linux sysroot cache
if: steps.cache-linux-sysroot.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: .sysroot/linux.tar.gz
key: ${{ needs.setup.outputs.linux-cache-key }}
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [setup, populate-linux-sysroot] needs: populate-darwin-sysroot
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Set up Release
uses: ./.github/actions/setup-goreleaser
with:
linux-cache-key: ${{ needs.setup.outputs.linux-cache-key }}
- name: Run GoReleaser (Build & Test)
env:
GITHUB_TOKEN: ${{github.token}}
run: |
docker run \
--rm \
-e GITHUB_TOKEN=${GITHUB_TOKEN} \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd):/go/src/llgo \
-w /go/src/llgo \
ghcr.io/goreleaser/goreleaser-cross:v1.22 \
release --verbose --skip=publish,nfpm,snapcraft --snapshot --clean
- name: Upload Darwin AMD64 Artifacts
uses: actions/upload-artifact@v4
with:
name: llgo-darwin-amd64
path: .dist/*darwin-amd64.tar.gz
retention-days: 3
include-hidden-files: true
- name: Upload Darwin ARM64 Artifacts
uses: actions/upload-artifact@v4
with:
name: llgo-darwin-arm64
path: .dist/*darwin-arm64.tar.gz
retention-days: 3
include-hidden-files: true
- name: Upload Linux AMD64 Artifacts
uses: actions/upload-artifact@v4
with:
name: llgo-linux-amd64
path: .dist/*linux-amd64.tar.gz
retention-days: 3
include-hidden-files: true
- name: Upload Linux ARM64 Artifacts
uses: actions/upload-artifact@v4
with:
name: llgo-linux-arm64
path: .dist/*linux-arm64.tar.gz
retention-days: 3
include-hidden-files: true
- name: Upload Checksums
uses: actions/upload-artifact@v4
with:
name: llgo-checksums
path: .dist/*checksums.txt
retention-days: 3
include-hidden-files: true
test-artifacts:
needs: build
strategy:
matrix:
include:
- os: macos-15-intel
goos: darwin
goarch: amd64
go-version: "1.24.2"
go-mod-version: "1.24"
- os: macos-latest
goos: darwin
goarch: arm64
go-version: "1.24.2"
go-mod-version: "1.24"
- os: ubuntu-latest
goos: linux
goarch: amd64
go-version: "1.24.2"
go-mod-version: "1.24"
- os: ubuntu-24.04-arm
goos: linux
goarch: arm64
go-version: "1.24.2"
go-mod-version: "1.24"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- name: Install dependencies
uses: ./.github/actions/setup-deps
with:
install-llvm: false
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
- name: Download Platform Artifact
uses: actions/download-artifact@v5
with:
name: llgo-${{ matrix.goos }}-${{ matrix.goarch }}
path: .
- name: Extract LLGO Archive
run: |
echo "Looking for ${{ matrix.goos }}_${{ matrix.goarch }} archive..."
ARCHIVE=$(ls *.tar.gz | head -n1)
mkdir -p release-llgo
tar -xzf "$ARCHIVE" -C release-llgo
ls -la release-llgo/
echo "${{ github.workspace }}/release-llgo/bin/" >> $GITHUB_PATH
- name: Test Hello World
uses: ./.github/actions/test-helloworld
with:
go-version: ${{matrix.go-version}}
mod-version: ${{ matrix.go-mod-version }}
release:
needs: [setup, test-artifacts, populate-linux-sysroot]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Check out code
uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Release - name: Set up Go
uses: ./.github/actions/setup-goreleaser uses: actions/setup-go@v5
with: with:
linux-cache-key: ${{ needs.setup.outputs.linux-cache-key }} go-version: 1.20.x
- name: Run GoReleaser (Release) - name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Download Darwin sysroot tarball
uses: actions/download-artifact@v4
with:
name: darwin-sysroot-tarball
path: .sysroot
- name: Populate Darwin sysroot
run: tar -xzvf .sysroot/darwin.tar.gz -C .sysroot
- name: Populate Linux sysroot
run: bash .github/workflows/populate_linux_sysroot.sh
- name: Run GoReleaser
env: env:
GITHUB_TOKEN: ${{github.token}} GITHUB_TOKEN: ${{github.token}}
run: | run: |
echo "Publishing release for tag: ${{ github.ref }}"
echo "All artifact tests passed, proceeding with release..."
docker run \ docker run \
--rm \ --rm \
-e GITHUB_TOKEN=${GITHUB_TOKEN} \ -e GITHUB_TOKEN=${GITHUB_TOKEN} \
@@ -204,4 +55,4 @@ jobs:
-v $(pwd):/go/src/llgo \ -v $(pwd):/go/src/llgo \
-w /go/src/llgo \ -w /go/src/llgo \
ghcr.io/goreleaser/goreleaser-cross:v1.22 \ ghcr.io/goreleaser/goreleaser-cross:v1.22 \
release --clean --verbose --skip nfpm,snapcraft release --clean --skip nfpm,snapcraft

View File

@@ -1,48 +0,0 @@
name: Targets
on:
push:
branches:
- "**"
- "!dependabot/**"
- "!xgopilot/**"
pull_request:
branches: ["**"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
llgo:
continue-on-error: true
timeout-minutes: 30
strategy:
matrix:
os:
- macos-latest
- ubuntu-latest
llvm: [19]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v5
- name: Install dependencies
uses: ./.github/actions/setup-deps
with:
llvm-version: ${{matrix.llvm}}
- 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: Build targets
run: |
cd _demo/embed/targetsbuild
bash build.sh

View File

@@ -1,13 +1,13 @@
#!/bin/bash #!/bin/bash
set -e set -e
# llgo run subdirectories under _demo 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/go/* ./_demo/py/* ./_demo/c/*; 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
View 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

14
.gitignore vendored
View File

@@ -7,7 +7,6 @@
*.dll *.dll
*.so *.so
*.dylib *.dylib
*.a
test.db test.db
demo.ll demo.ll
@@ -16,7 +15,6 @@ stories*.bin
.DS_Store .DS_Store
err.log err.log
numpy.txt numpy.txt
result.txt
_go/ _go/
_runtime/ _runtime/
@@ -24,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
@@ -45,11 +39,3 @@ go.work*
# GoReleaser # GoReleaser
.dist/ .dist/
.sysroot/ .sysroot/
# Embedded firmware files
*.bin
*.hex
*.elf
*.uf2
*.img
*.zip

3
.gitmodules vendored
View File

@@ -0,0 +1,3 @@
[submodule "c/llama2/llama2.c"]
path = c/llama2/llama2.c
url = https://github.com/karpathy/llama2.c.git

View File

@@ -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@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}}/crosscompile/clang/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}}/crosscompile/clang/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm -Wl,-rpath,@executable_path/../crosscompile/clang/lib - 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@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}}/crosscompile/clang/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}}/crosscompile/clang/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm -Wl,-rpath,@executable_path/../crosscompile/clang/lib - 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}}
- "-extldflags=-Wl,-rpath,$ORIGIN/../crosscompile/clang/lib" - -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}}/crosscompile/clang/include -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}}/crosscompile/clang/lib -L{{.Env.SYSROOT_LINUX_AMD64}}/lib/x86_64-linux-gnu -lLLVM-19 -lz - CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-18/lib -lLLVM-18
- CGO_LDFLAGS_ALLOW=--sysroot.*
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}}
- "-extldflags=-Wl,-rpath,$ORIGIN/../crosscompile/clang/lib" - -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}}/crosscompile/clang/include -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}}/crosscompile/clang/lib -L{{.Env.SYSROOT_LINUX_ARM64}}/lib/aarch64-linux-gnu -lLLVM-19 -lz - CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-18/lib -lLLVM-18
- CGO_LDFLAGS_ALLOW=--sysroot.*
targets: targets:
- linux_arm64 - linux_arm64
mod_timestamp: "{{.CommitTimestamp}}" mod_timestamp: "{{.CommitTimestamp}}"
@@ -92,12 +88,7 @@ archives:
files: files:
- LICENSE - LICENSE
- README.md - README.md
- runtime
- targets
- src: ".sysroot/{{.Os}}/{{.Arch}}/crosscompile/clang"
dst: crosscompile/clang
info:
mode: 0755
checksum: checksum:
name_template: "{{.ProjectName}}{{.Version}}.checksums.txt" name_template: "{{.ProjectName}}{{.Version}}.checksums.txt"
@@ -108,9 +99,9 @@ nfpms:
maintainer: Aofei Sheng <aofei@aofeisheng.com> maintainer: Aofei Sheng <aofei@aofeisheng.com>
description: | description: |
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a
subproject of the XGo project. subproject of the Go+ project.
LLGo aims to expand the boundaries of Go/XGo, providing limitless possibilities such as: LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
- Game development - Game development
- AI and data science - AI and data science
@@ -132,9 +123,9 @@ snapcrafts:
summary: A Go compiler based on LLVM summary: A Go compiler based on LLVM
description: | description: |
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a
subproject of the XGo project. subproject of the Go+ project.
LLGo aims to expand the boundaries of Go/XGo, providing limitless possibilities such as: LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
- Game development - Game development
- AI and data science - AI and data science

132
CLAUDE.md
View File

@@ -1,132 +0,0 @@
# LLGo Project AI Assistant Guide
This document provides essential information for AI assistants to help fix bugs and implement features in the LLGo project.
## About LLGo
LLGo is a Go compiler based on LLVM designed to better integrate Go with the C ecosystem, including Python and JavaScript. It's a subproject of the XGo project that aims to expand the boundaries of Go/XGo for game development, AI and data science, WebAssembly, and embedded development.
## Project Structure
- `cmd/llgo` - Main llgo compiler command (usage similar to `go` command)
- `cl/` - Core compiler logic that converts Go packages to LLVM IR
- `ssa/` - LLVM IR file generation using Go SSA semantics
- `internal/build/` - Build process orchestration
- `runtime/` - LLGo runtime library
- `chore/` - Development tools (llgen, llpyg, ssadump, etc.)
- `_demo/` - Example programs demonstrating C/C++ interop (`c/hello`, `c/qsort`) and Python integration (`py/callpy`, `py/numpy`)
- `_cmptest/` - Comparison tests to verify the same program gets the same output with Go and LLGo
## Development Environment
For detailed dependency requirements and installation instructions, see the [Dependencies](README.md#dependencies) and [How to install](README.md#how-to-install) sections in the README.
## Testing & Validation
The following commands and workflows are essential when fixing bugs or implementing features in the LLGo project:
### Run all tests
```bash
go test ./...
```
**Note:** Some tests may fail if optional dependencies (like Python) are not properly configured. The test suite includes comprehensive tests for:
- Compiler functionality
- SSA generation
- C interop
- Python integration (requires Python development headers)
### Write and run tests for your changes
When adding new functionality or fixing bugs, create appropriate test cases:
```bash
# Add your test to the relevant package's *_test.go file
# Then run tests for that package
go test ./path/to/package
# Or run all tests
go test ./...
```
**Important:** The `LLGO_ROOT` environment variable must be set to the repository root when running llgo commands during development.
## Code Quality
Before submitting any code updates, you must run the following formatting and validation commands:
### Format code
```bash
go fmt ./...
```
**Important:** Always run `go fmt ./...` before committing code changes. This ensures consistent code formatting across the project.
### Run static analysis
```bash
go vet ./...
```
**Note:** Currently reports some issues related to lock passing by value in `ssa/type_cvt.go` and a possible unsafe.Pointer misuse in `cl/builtin_test.go`. These are known issues.
## Common Development Tasks
### Build the entire project
```bash
go build -v ./...
```
### Build llgo command specifically
```bash
go build -o llgo ./cmd/llgo
```
### Check llgo version
```bash
llgo version
```
### Install llgo for system-wide use
```bash
./install.sh
```
### Build development tools
```bash
go install -v ./cmd/...
go install -v ./chore/...
```
## Key Modules for Understanding
- `ssa` - Generates LLVM IR using Go SSA semantics
- `cl` - Core compiler converting Go to LLVM IR
- `internal/build` - Orchestrates the compilation process
## Debugging
### Disable Garbage Collection
For testing purposes, you can disable GC:
```bash
LLGO_ROOT=/path/to/llgo llgo run -tags nogc .
```
## LLGO_ROOT Environment Variable
**CRITICAL:** Always set `LLGO_ROOT` to the repository root when running llgo during development:
```bash
export LLGO_ROOT=/path/to/llgo
# or
LLGO_ROOT=/path/to/llgo llgo run .
```
## Important Notes
1. **Testing Requirement:** All bug fixes and features MUST include tests
2. **Demo Directory:** Examples in `_demo` are prefixed with `_` to prevent standard `go` command from trying to compile them
3. **Defer in Loops:** LLGo intentionally does not support `defer` in loops (considered bad practice)
4. **C Ecosystem Integration:** LLGo uses `go:linkname` directive to link external symbols through ABI
5. **Python Integration:** Third-party Python libraries require separate installation of library files

235
README.md
View File

@@ -6,11 +6,11 @@ llgo - A Go compiler based on LLVM
[![GitHub release](https://img.shields.io/github/v/tag/goplus/llgo.svg?label=release)](https://github.com/goplus/llgo/releases) [![GitHub release](https://img.shields.io/github/v/tag/goplus/llgo.svg?label=release)](https://github.com/goplus/llgo/releases)
[![Coverage Status](https://codecov.io/gh/goplus/llgo/branch/main/graph/badge.svg)](https://codecov.io/gh/goplus/llgo) [![Coverage Status](https://codecov.io/gh/goplus/llgo/branch/main/graph/badge.svg)](https://codecov.io/gh/goplus/llgo)
[![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo) [![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo)
[![Language](https://img.shields.io/badge/language-XGo-blue.svg)](https://github.com/goplus/gop) [![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop)
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python and JavaScript. It's a subproject of [the XGo project](https://github.com/goplus/gop). LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of [the Go+ project](https://github.com/goplus/gop).
LLGo aims to expand the boundaries of Go/XGo, providing limitless possibilities such as: LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
* Game development * Game development
* AI and data science * AI and data science
@@ -21,38 +21,36 @@ LLGo aims to expand the boundaries of Go/XGo, providing limitless possibilities
How can these be achieved? How can these be achieved?
``` ```
LLGo := Go * C ecosystem LLGo := Go + C + Python
``` ```
LLGo is compatible with C ecosystem through the language's **Application Binary Interface (ABI)**, while LLGo is compatible with Go through its **syntax (source code)**. C ecosystem includes all languages that are ABI compatible with C (eg. C/C++, Python, JavaScript, 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"))
@@ -63,24 +61,22 @@ This is a simple example of calling the C `printf` function to print `Hello worl
The `_demo` directory contains some C standard libary related demos (it start with `_` to prevent the `go` command from compiling it): The `_demo` directory contains some C standard libary related demos (it start with `_` to prevent the `go` command from compiling it):
* [hello](_demo/c/hello/hello.go): call C `printf` to print `Hello world` * [hello](_demo/hello/hello.go): call C `printf` to print `Hello world`
* [concat](_demo/c/concat/concat.go): call C `fprintf` with `stderr` * [concat](_demo/concat/concat.go): call C `fprintf` with `stderr`
* [qsort](_demo/c/qsort/qsort.go): call C function with a callback (eg. `qsort`) * [qsort](_demo/qsort/qsort.go): call C function with a callback (eg. `qsort`)
To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)): To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)):
```sh ```sh
cd <demo-directory> # eg. cd _demo/c/hello cd <demo-directory> # eg. cd _demo/hello
llgo run . 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
@@ -88,9 +84,7 @@ import _ "unsafe" // for go:linkname
func Sqrt(x float64) float64 func Sqrt(x float64) float64
``` ```
You can directly integrate it into [your own code](_demo/c/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() {
@@ -204,17 +190,17 @@ func main() {
Here we define two 3x3 matrices a and b, add them to get x, and then print the result. Here we define two 3x3 matrices a and b, add them to get x, and then print the result.
The `_demo/py/` directory contains some python related demos: The `_pydemo` directory contains some python related demos:
* [callpy](_demo/py/callpy/callpy.go): call Python standard library function `math.sqrt` * [callpy](_pydemo/callpy/callpy.go): call Python standard library function `math.sqrt`
* [pi](_demo/py/pi/pi.go): print python constants `math.pi` * [pi](_pydemo/pi/pi.go): print python constants `math.pi`
* [statistics](_demo/py/statistics/statistics.go): define a python list and call `statistics.mean` to get the mean * [statistics](_pydemo/statistics/statistics.go): define a python list and call `statistics.mean` to get the mean
* [matrix](_demo/py/matrix/matrix.go): a basic `numpy` demo * [matrix](_pydemo/matrix/matrix.go): a basic `numpy` demo
To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)): To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)):
```sh ```sh
cd <demo-directory> # eg. cd _demo/py/callpy cd <demo-directory> # eg. cd _pydemo/callpy
llgo run . llgo run .
``` ```
@@ -225,38 +211,37 @@ 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/c/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/c/concat/concat.go): define a variadic function * [concat](_demo/concat/concat.go): define a variadic function
* [genints](_demo/c/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)
* [errors](_cmptest/errors/errors.go): demo to implement error interface * [errors](_cmptest/errors/errors.go): demo to implement error interface
* [defer](_cmptest/defer/defer.go): defer demo * [defer](_cmptest/defer/defer.go): defer demo
* [goroutine](_demo/go/goroutine/goroutine.go): goroutine demo * [goroutine](_demo/goroutine/goroutine.go): goroutine demo
### Defer ### Defer
@@ -318,38 +303,33 @@ 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)
* [hash/crc64](https://pkg.go.dev/hash/crc64) * [hash/crc64](https://pkg.go.dev/hash/crc64)
* [hash/maphash](https://pkg.go.dev/hash/maphash) (partially)
* [crypto](https://pkg.go.dev/crypto) * [crypto](https://pkg.go.dev/crypto)
* [crypto/md5](https://pkg.go.dev/crypto/md5) * [crypto/md5](https://pkg.go.dev/crypto/md5)
* [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)
* [go/scanner](https://pkg.go.dev/go/scanner) * [go/scanner](https://pkg.go.dev/go/scanner)
* [go/parser](https://pkg.go.dev/go/parser)
## 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
@@ -357,70 +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 libunwind-19-dev libc++-19-dev pkg-config libgc-dev libssl-dev zlib1g-dev libcjson-dev libsqlite3-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 llvm19-dev clang19-dev lld19 pkgconf gc-dev libunwind-dev openssl-dev zlib-dev
apk add python3-dev # optional
apk add g++ # build only
export LLVM_CONFIG=/usr/lib/llvm19/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
```
docker alpine 386 llgo environment
```
export GCC_ROOT_DIR=$(gcc -print-search-dirs | grep 'install:' | awk -F': ' '{print $2}')
export LDFLAGS="-L$GCC_ROOT_DIR -B$GCC_ROOT_DIR -Wl,-dynamic-linker,/lib/ld-musl-i386.so.1"
llgo run .
``` ```
### 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).
@@ -428,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`.

View File

@@ -1,33 +0,0 @@
package main
import (
"fmt"
"go/constant"
"go/token"
)
func main() {
// Create the complex number 2.3 + 5i.
ar := constant.MakeFloat64(2.3)
ai := constant.MakeImag(constant.MakeInt64(5))
a := constant.BinaryOp(ar, token.ADD, ai)
// Compute (2.3 + 5i) * 11.
b := constant.MakeUint64(11)
c := constant.BinaryOp(a, token.MUL, b)
// Convert c into a complex128.
Ar, exact := constant.Float64Val(constant.Real(c))
if !exact {
fmt.Printf("Could not represent real part %s exactly as float64\n", constant.Real(c))
}
Ai, exact := constant.Float64Val(constant.Imag(c))
if !exact {
fmt.Printf("Could not represent imaginary part %s as exactly as float64\n", constant.Imag(c))
}
C := complex(Ar, Ai)
fmt.Println("literal", 25.3+55i)
fmt.Println("go/constant", c)
fmt.Println("complex128", C)
}

View File

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

View File

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

View File

@@ -1,25 +0,0 @@
package main
import (
"fmt"
"math/big"
)
func main() {
// Initialize two big ints with the first two numbers in the sequence.
a := big.NewInt(0)
b := big.NewInt(1)
// Initialize limit as 10^99, the smallest integer with 100 digits.
var limit big.Int
limit.Exp(big.NewInt(10), big.NewInt(99), nil)
// Loop while a is smaller than 1e100.
for a.Cmp(&limit) < 0 {
// Compute the next Fibonacci number, storing it in a.
a.Add(a, b)
// Swap a and b so that b is the next number in the sequence.
a, b = b, a
}
fmt.Println(a) // 100-digit Fibonacci number
}

View File

@@ -1,18 +0,0 @@
package main
import (
"fmt"
"time"
)
//llgo:link asm llgo.asm
func asm(instruction string) {}
func main() {
start := time.Now()
for i := 0; i < 100000; i++ {
asm("nop")
}
duration := time.Since(start)
fmt.Println("Duration:", duration)
}

View File

@@ -1,21 +0,0 @@
package main
import (
"fmt"
)
//llgo:link asmFull llgo.asm
func asmFull(instruction string, regs map[string]any) uintptr { return 0 }
var testVar = 0
func main() {
verify()
}
func check(expected, actual int) {
if expected != actual {
panic(fmt.Sprintf("Expected: %d, Got: %d\n", expected, actual))
}
fmt.Println("asm check passed:", actual)
}

View File

@@ -1,31 +0,0 @@
//go:build darwin && arm64
package main
import "unsafe"
func verify() {
// 0 output & 0 input
asmFull("nop", nil)
// 0 output & 1 input with memory address
addr := uintptr(unsafe.Pointer(&testVar))
asmFull("str {value}, [{addr}]", map[string]any{
"addr": addr,
"value": 43,
})
check(43, testVar)
// 1 output & 1 input
res1 := asmFull("mov {}, {value}", map[string]any{
"value": 41,
})
check(41, int(res1))
// 1 output & 2 inputs
res2 := asmFull("add {}, {a}, {b}", map[string]any{
"a": 25,
"b": 17,
})
check(42, int(res2))
}

View File

@@ -1,30 +0,0 @@
//go:build linux && amd64
package main
import "unsafe"
func verify() {
// 0 output & 0 input
asmFull("nop", nil)
// 0 output & 1 input with memory address
addr := uintptr(unsafe.Pointer(&testVar))
asmFull("movq {value}, ({addr})", map[string]any{
"addr": addr,
"value": 43,
})
check(43, testVar)
// 1 output & 1 input
res1 := asmFull("movq {value}, {}", map[string]any{
"value": 41,
})
check(41, int(res1))
res2 := asmFull("leaq ({a},{b}), {}", map[string]any{
"a": 25,
"b": 17,
})
check(42, int(res2))
}

View File

@@ -1,395 +0,0 @@
package main
import (
_ "unsafe"
)
const (
LLGoFiles = "wrap/wrap.c"
)
type point struct {
x int32
y int32
}
//go:linkname pt C.pt
func pt(pt point) point
type point1 struct {
x int32
y int32
z int32
}
//go:linkname pt1 C.pt1
func pt1(pt point1) point1
type point2 struct {
x int8
y int32
z int32
}
//go:linkname pt2 C.pt2
func pt2(pt point2) point2
type point3 struct {
x int8
y int8
z int8
}
//go:linkname pt3 C.pt3
func pt3(pt point3) point3
type point4 struct {
x int8
y int8
z int8
m int32
}
//go:linkname pt4 C.pt4
func pt4(pt point4) point4
type point5 struct {
x int8
y int8
z int8
m int8
n int8
}
//go:linkname pt5 C.pt5
func pt5(pt point5) point5
type point6 struct {
x int8
y int8
z int8
m int8
n int8
k int32
}
//go:linkname pt6 C.pt6
func pt6(pt point6) point6
type point7 struct {
x int8
y int8
z int8
m int8
n int8
k int32
o int8
}
//go:linkname pt7 C.pt7
func pt7(pt point7) point7
type data1 struct {
x int8
y int64
}
//go:linkname fn1 C.fn1
func fn1(data1) data1
type data2 struct {
x int32
y int64
}
//go:linkname fn2 C.fn2
func fn2(data2) data2
type data3 struct {
x int64
y int8
}
//go:linkname fn3 C.fn3
func fn3(data3) data3
type fdata1 struct {
x float32
}
//go:linkname ff1 C.ff1
func ff1(fdata1) fdata1
type fdata2 struct {
x float32
y float32
}
//go:linkname ff2 C.ff2
func ff2(fdata2) fdata2
type fdata2i struct {
x float32
y int32
}
//go:linkname ff2i C.ff2i
func ff2i(fdata2i) fdata2i
type fdata3 struct {
x float32
y float32
z float32
}
//go:linkname ff3 C.ff3
func ff3(fdata3) fdata3
type fdata4 struct {
x float32
y float32
z float32
m float32
}
//go:linkname ff4 C.ff4
func ff4(fdata4) fdata4
type fdata5 struct {
x float32
y float32
z float32
m float32
n float32
}
//go:linkname ff5 C.ff5
func ff5(fdata5) fdata5
type fdata2id struct {
x int8
y int8
z float64
}
//go:linkname ff2id C.ff2id
func ff2id(fdata2id) fdata2id
type fdata7if struct {
x [7]int8
y float32
}
//go:linkname ff7if C.ff7if
func ff7if(fdata7if) fdata7if
type fdata4if struct {
x float32
y int8
z float32
m float32
}
//go:linkname ff4if C.ff4if
func ff4if(fdata4if) fdata4if
type array struct {
x [8]int32
}
//go:linkname demo64 C.demo64
func demo64(n int64) int64
//go:linkname demo32 C.demo32
func demo32(n int32) int32
type struct32 struct {
v int32
}
//go:linkname demo32s C.demo32s
func demo32s(v struct32) struct32
type point64 struct {
x int64
y int64
}
//go:linkname pt64 C.pt64
func pt64(pt point64) point64
//go:linkname demo C.demo
func demo(a array) array
//go:linkname demo2 C.demo2
func demo2(x int32) array
type ddata1 struct {
x float64
}
//go:linkname dd1 C.dd1
func dd1(d ddata1) ddata1
type ddata2 struct {
x float64
y float64
}
//go:linkname dd2 C.dd2
func dd2(d ddata2) ddata2
type ddata3 struct {
x float64
y float64
z float64
}
//go:linkname dd3 C.dd3
func dd3(d ddata3) ddata3
//llgo:type C
type Callback func(array, point, point1) array
//go:linkname callback C.callback
func callback(fn Callback, ar array)
//llgo:type C
type Callback1 func(array, point, point1) point
//go:linkname callback1 C.callback1
func callback1(fn Callback1, ar array)
//go:linkname mycallback C.mycallback
func mycallback(ar array, pt point, pt1 point1) point
func myfn1(ar array, pt point, pt1 point1) point {
println("=>", ar.x[0], ar.x[1], ar.x[7], pt.x, pt.y, pt1.x, pt1.y, pt1.z)
return point{100, 200}
}
//export export_demo
func export_demo(ar array) array {
println("=> export", ar.x[0], ar.x[1], ar.x[7])
return ar
}
func main() {
cabi_demo()
callback_demo()
}
func callback_demo() {
export_demo(array{x: [8]int32{1, 2, 3, 4, 5, 6, 7, 8}})
callback(func(ar array, pt point, pt1 point1) array {
println("=> callback", ar.x[0], ar.x[1], ar.x[7], pt.x, pt.y, pt1.x, pt1.y, pt1.z)
return array{x: [8]int32{8, 7, 6, 5, 4, 3, 2, 1}}
}, array{x: [8]int32{1, 2, 3, 4, 5, 6, 7, 8}})
callback1(func(ar array, pt point, pt1 point1) point {
println("=> callback1", ar.x[0], ar.x[1], ar.x[7], pt.x, pt.y, pt1.x, pt1.y, pt1.z)
return point{100, 200}
}, array{x: [8]int32{1, 2, 3, 4, 5, 6, 7, 8}})
ret := mycallback(array{x: [8]int32{1, 2, 3, 4, 5, 6, 7, 8}}, point{1, 2}, point1{1, 2, 3})
println("=> mycallback", ret.x, ret.y)
callback1(myfn1, array{x: [8]int32{1, 2, 3, 4, 5, 6, 7, 8}})
callback1(myfn1, array{x: [8]int32{8, 7, 6, 5, 4, 3, 2, 1}})
callback1(mycallback, array{x: [8]int32{10, 20, 30, 40, 50, 60, 70, 80}})
}
func cabi_demo() {
i32 := demo32(1024)
println("=> demo32", i32)
s32 := demo32s(struct32{100})
println("=> demo32s", s32.v)
i64 := demo64(1024)
println("=> demo64", i64)
p64 := pt64(point64{1024, -1024})
println("=> pt64", p64.x, p64.y)
r := demo(array{x: [8]int32{1, 2, 3, 4, 5, 6, 7, 8}})
println("=> demo", r.x[0], r.x[1])
r2 := demo2(100)
println("=> demo2", r2.x[0], r2.x[1], r2.x[7])
p0 := pt(point{1, 2})
println("=> pt0", p0.x, p0.y)
p1 := pt1(point1{1, 2, 3})
println("=> pt1", p1.x, p1.y, p1.z)
p2 := pt2(point2{1, 2, 3})
println("=> pt2", p2.x, p2.y, p2.z)
p3 := pt3(point3{1, 2, 3})
println("=> pt3", p3.x, p3.y, p3.z)
p4 := pt4(point4{1, 2, 3, 4})
println("=> pt4", p4.x, p4.y, p4.z, p4.m)
p5 := pt5(point5{1, 2, 3, 4, 5})
println("=> pt5", p5.x, p5.y, p5.z, p5.m, p5.n)
p6 := pt6(point6{1, 2, 3, 4, 5, 6})
println("=> pt6", p6.x, p6.y, p6.z, p6.m, p6.n, p6.k)
p7 := pt7(point7{1, 2, 3, 4, 5, 6, 7})
println("=> pt7", p7.x, p7.y, p7.z, p7.m, p7.n, p7.k, p7.o)
// skip wrap
fd1 := fn1(data1{1, 2})
println("=> fd1", fd1.x, fd1.y)
fd2 := fn2(data2{1, 2})
println("=> fd2", fd2.x, fd2.y)
fd3 := fn3(data3{1, 2})
println("=> fd3", fd3.x, fd3.y)
// float
f1 := ff1(fdata1{1.1})
println("=> f1", f1.x)
// float
f2 := ff2(fdata2{1.1, 2.1})
println("=> f2", f2.x, f2.y)
// float
f2i := ff2i(fdata2i{1.1, 2})
println("=> f2i", f2i.x, f2i.y)
// float
f3 := ff3(fdata3{1.1, 2.1, 3.1})
println("=> f3", f3.x, f3.y, f3.z)
// float
f4 := ff4(fdata4{1.1, 2.1, 3.1, 4.1})
println("=> f4", f4.x, f4.y, f4.z, f4.m)
// float
f5 := ff5(fdata5{1.1, 2.1, 3.1, 4.1, 5.1})
println("=> f5", f5.x, f5.y, f5.z, f5.m, f5.n)
f2id := ff2id(fdata2id{1, 2, 3.1})
println("=> f2id", f2id.x, f2id.y, f2id.z)
f7if := ff7if(fdata7if{[7]int8{1, 2, 3, 4, 5, 6, 7}, 3.1})
println("=> f7if", f7if.x[0], f7if.x[1], f7if.y)
f4if := ff4if(fdata4if{1.1, 2, 3.1, 4.1})
println("=> f4if", f4if.x, f4if.y, f4if.z, f4if.m)
d1 := dd1(ddata1{1.1})
println("=> dd1", d1.x)
d2 := dd2(ddata2{1.1, 2.1})
println("=> dd2", d2.x, d2.y)
d3 := dd3(ddata3{1.1, 2.1, 3.1})
println("=> dd3", d3.x, d3.y, d3.z)
}

View File

@@ -1,325 +0,0 @@
extern int printf(const char *format, ...);
int demo32(int v) {
return v+100;
}
long long demo64(long long v) {
return v+100;
}
struct struct32 {
int v;
};
struct point64 {
long long x;
long long y;
};
struct point64 pt64(struct point64 pt) {
printf("point64: %lld %lld\n",pt.x,pt.y);
return pt;
}
struct struct32 demo32s(struct struct32 v) {
printf("struct32: %d\n",v.v);
struct struct32 v2 = {v.v+100};
return v2;
}
struct point {
int x;
int y;
};
struct point pt(struct point pt) {
printf("point: %d %d\n",pt.x,pt.y);
return pt;
}
struct point1 {
int x;
int y;
int z;
};
struct point1 pt1(struct point1 pt) {
printf("point1: %d %d %d\n",pt.x,pt.y,pt.z);
return pt;
}
struct point2 {
char x;
int y;
int z;
};
struct point2 pt2(struct point2 pt) {
printf("point2: %d %d %d\n",pt.x,pt.y,pt.z);
return pt;
}
struct point3 {
char x;
char y;
char z;
};
struct point3 pt3(struct point3 pt) {
printf("point3: %d %d %d\n",pt.x,pt.y,pt.z);
return pt;
}
struct point4 {
char x;
char y;
char z;
int m;
};
struct point4 pt4(struct point4 pt) {
printf("point4: %d %d %d %d\n",pt.x,pt.y,pt.z,pt.m);
return pt;
}
struct point5 {
char x;
char y;
char z;
char m;
char n;
};
struct point5 pt5(struct point5 pt) {
printf("point5: %d %d %d %d %d\n",pt.x,pt.y,pt.z,pt.m,pt.n);
return pt;
}
struct point6 {
char x;
char y;
char z;
char m;
char n;
int k;
};
struct point6 pt6(struct point6 pt) {
printf("point6: %d %d %d %d %d %d\n",pt.x,pt.y,pt.z,pt.m,pt.n,pt.k);
return pt;
}
struct point7 {
char x;
char y;
char z;
char m;
char n;
int k;
char o;
};
struct point7 pt7(struct point7 pt) {
printf("point7: %d %d %d %d %d %d %d\n",pt.x,pt.y,pt.z,pt.m,pt.n,pt.k,pt.o);
return pt;
}
struct data1 {
char x;
long long y;
};
struct data1 fn1(struct data1 pt) {
printf("data1: %d %lld\n",pt.x,pt.y);
return pt;
}
struct data2 {
int x;
long long y;
};
struct data2 fn2(struct data2 pt) {
printf("data2: %d %lld\n",pt.x,pt.y);
return pt;
}
struct data3 {
long long x;
char y;
};
struct data3 fn3(struct data3 pt) {
printf("data3: %lld %d\n",pt.x,pt.y);
return pt;
}
struct fdata1 {
float x;
};
struct fdata1 ff1(struct fdata1 pt) {
printf("ff1: %f\n",pt.x);
return pt;
}
struct ddata1 {
double x;
};
struct ddata1 dd1(struct ddata1 pt) {
printf("dd1: %f\n",pt.x);
return pt;
}
struct ddata2 {
double x;
double y;
};
struct ddata2 dd2(struct ddata2 pt) {
printf("dd2: %f %f\n",pt.x,pt.y);
return pt;
}
struct ddata3 {
double x;
double y;
double z;
};
struct ddata3 dd3(struct ddata3 pt) {
printf("dd3: %f %f %f\n",pt.x,pt.y,pt.z);
return pt;
}
struct fdata2i {
float x;
int y;
};
struct fdata2i ff2i(struct fdata2i pt) {
printf("ff2i: %f %d\n",pt.x,pt.y);
return pt;
}
struct fdata2 {
float x;
float y;
};
struct fdata2 ff2(struct fdata2 pt) {
printf("ff2: %f %f\n",pt.x,pt.y);
return pt;
}
struct fdata3 {
float x;
float y;
float z;
};
struct fdata3 ff3(struct fdata3 pt) {
printf("ff3: %f %f %f\n",pt.x,pt.y,pt.z);
return pt;
}
struct fdata4 {
float x;
float y;
float z;
float m;
};
struct fdata4 ff4(struct fdata4 pt) {
printf("ff4: %f %f %f %f\n",pt.x,pt.y,pt.z,pt.m);
return pt;
}
struct fdata5 {
float x;
float y;
float z;
float m;
float n;
};
struct fdata5 ff5(struct fdata5 pt) {
printf("ff5: %f %f %f %f %f\n",pt.x,pt.y,pt.z,pt.m,pt.n);
return pt;
}
struct fdata2id {
char x;
char y;
double z;
};
struct fdata2id ff2id(struct fdata2id pt) {
printf("ff6: %d %d %f\n",pt.x,pt.y,pt.z);
return pt;
}
struct fdata7if {
char x[7];
float z;
};
struct fdata7if ff7if(struct fdata7if pt) {
printf("ff7if: %d %d %f\n",pt.x[0],pt.x[1],pt.z);
return pt;
}
struct fdata4if {
float x;
char y;
float z;
float m;
};
struct fdata4if ff4if(struct fdata4if pt) {
printf("ff4if: %f %d %f %f\n",pt.x,pt.y,pt.z,pt.m);
return pt;
}
struct array {
int x[8];
};
struct array demo(struct array a) {
printf("demo: %d %d %d\n",a.x[0],a.x[1],a.x[2]);
return a;
}
struct array demo2(int a1){
struct array x;
for (int i = 0; i < 8; i++) {
x.x[i] = i+a1;
}
return x;
}
void callback(struct array (*fn)(struct array ar, struct point pt, struct point1 pt1), struct array ar) {
demo(ar);
struct point pt = {1,2};
struct point1 pt1 = {1,2,3};
struct array ret = fn(ar,pt,pt1);
demo(ret);
}
void callback1(struct point (*fn)(struct array ar, struct point pt, struct point1 pt1), struct array ar) {
printf("callback1 array: %d %d %d\n",ar.x[0],ar.x[1],ar.x[7]);
struct point pt = {1,2};
struct point1 pt1 = {1,2,3};
struct point ret = fn(ar,pt,pt1);
printf("callback1 ret: %d,%d\n",ret.x,ret.y);
}
struct point mycallback(struct array ar, struct point pt, struct point1 pt1) {
printf("mycallback array: %d %d %d\n",ar.x[0],ar.x[1],ar.x[7]);
printf("mycallback pt: %d %d\n",pt.x,pt.y);
printf("mycallback pt1: %d %d %d\n",pt1.x,pt1.y,pt1.z);
struct point ret = {pt.x+pt1.x, pt.y+pt1.y};
return ret;
}

View File

@@ -1,39 +0,0 @@
package main
type array9 struct {
x [9]float32
}
func demo1(a array9) array9 {
a.x[0] += 1
return a
}
func demo2(a array9) array9 {
for i := 0; i < 1024*128; i++ {
a = demo1(a)
}
return a
}
func testDemo() {
ar := array9{x: [9]float32{1, 2, 3, 4, 5, 6, 7, 8, 9}}
for i := 0; i < 1024*128; i++ {
ar = demo1(ar)
}
ar = demo2(ar)
println(ar.x[0], ar.x[1])
}
func testSlice() {
var b []byte
for i := 0; i < 1024*128; i++ {
b = append(b, byte(i))
}
_ = b
}
func main() {
testDemo()
testSlice()
}

View File

@@ -1,144 +0,0 @@
package main
import (
"fmt"
"os"
_ "unsafe"
"github.com/goplus/lib/c"
)
const LLGoPackage string = "link: $(pkg-config --libs cargs);"
type Option struct {
Identifier c.Char
AccessLetters *c.Char
AccessName *c.Char
ValueName *c.Char
Description *c.Char
}
type OptionContext struct {
Options *Option
OptionCount c.SizeT
Argc c.Int
Argv **c.Char
Index c.Int
InnerIndex c.Int
ErrorIndex c.Int
ErrorLetter c.Char
ForcedEnd bool
Identifier c.Char
Value *c.Char
}
// llgo:type C
type Printer func(__llgo_arg_0 c.Pointer, __llgo_arg_1 *c.Char, __llgo_va_list ...interface{}) c.Int
// llgo:link (*OptionContext).OptionInit C.cag_option_init
func (recv_ *OptionContext) OptionInit(options *Option, option_count c.SizeT, argc c.Int, argv **c.Char) {
}
// llgo:link (*OptionContext).OptionFetch C.cag_option_fetch
func (recv_ *OptionContext) OptionFetch() bool {
return false
}
// llgo:link (*OptionContext).OptionGetIdentifier C.cag_option_get_identifier
func (recv_ *OptionContext) OptionGetIdentifier() c.Char {
return 0
}
// llgo:link (*OptionContext).OptionGetValue C.cag_option_get_value
func (recv_ *OptionContext) OptionGetValue() *c.Char {
return nil
}
// llgo:link (*OptionContext).OptionGetIndex C.cag_option_get_index
func (recv_ *OptionContext) OptionGetIndex() c.Int {
return 0
}
// llgo:link (*OptionContext).OptionGetErrorIndex C.cag_option_get_error_index
func (recv_ *OptionContext) OptionGetErrorIndex() c.Int {
return 0
}
// llgo:link (*OptionContext).OptionGetErrorLetter C.cag_option_get_error_letter
func (recv_ *OptionContext) OptionGetErrorLetter() c.Char {
return 0
}
// llgo:link (*OptionContext).OptionPrintError C.cag_option_print_error
func (recv_ *OptionContext) OptionPrintError(destination *c.FILE) {
}
// llgo:link (*OptionContext).OptionPrinterError C.cag_option_printer_error
func (recv_ *OptionContext) OptionPrinterError(printer Printer, printer_ctx c.Pointer) {
}
// llgo:link (*Option).OptionPrint C.cag_option_print
func (recv_ *Option) OptionPrint(option_count c.SizeT, destination *c.FILE) {
}
// llgo:link (*Option).OptionPrinter C.cag_option_printer
func (recv_ *Option) OptionPrinter(option_count c.SizeT, printer Printer, printer_ctx c.Pointer) {
}
// llgo:link (*OptionContext).OptionPrepare C.cag_option_prepare
func (recv_ *OptionContext) OptionPrepare(options *Option, option_count c.SizeT, argc c.Int, argv **c.Char) {
}
// llgo:link (*OptionContext).OptionGet C.cag_option_get
func (recv_ *OptionContext) OptionGet() c.Char {
return 0
}
func main() {
options := []Option{
{
Identifier: 'h',
AccessLetters: c.Str("h"),
AccessName: c.Str("help"),
ValueName: nil,
Description: c.Str("Show help information"),
},
{
Identifier: 'v',
AccessLetters: c.Str("v"),
AccessName: c.Str("version"),
ValueName: nil,
Description: c.Str("Show version information"),
},
}
args := os.Args
// Convert Go string array to C-style argv
argv := make([]*int8, len(args))
for i, arg := range args {
argv[i] = c.AllocaCStr(arg)
}
// Initialize option context
var context OptionContext
context.OptionInit(&options[0], uintptr(len(options)), c.Int(len(args)), &argv[0])
// Process all options
identifierFound := false
for context.OptionFetch() {
identifierFound = true
identifier := context.OptionGetIdentifier()
switch identifier {
case 'h':
fmt.Println("Help: This is a simple command-line parser demo")
case 'v':
fmt.Println("Version: 1.0.0")
}
}
// Default output if no identifier is found
if !identifierFound {
fmt.Println("Demo Command-line Tool\nIdentifier:\n\t-h: Help\n\t-v: Version")
}
}

View File

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

View File

@@ -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/c/cgofull/pymod1"
"github.com/goplus/llgo/_demo/c/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)
}

View File

@@ -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;
}

View File

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

View File

@@ -1,7 +0,0 @@
#pragma once
typedef struct {
int a;
} Foo;
extern void print_foo(Foo* f);

View File

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

View File

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

View File

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

View File

@@ -1,5 +0,0 @@
module github.com/goplus/llgo/_demo/c
go 1.20
require github.com/goplus/lib v0.3.0

View File

@@ -1,2 +0,0 @@
github.com/goplus/lib v0.3.0 h1:y0ZGb5Q/RikW1oMMB4Di7XIZIpuzh/7mlrR8HNbxXCA=
github.com/goplus/lib v0.3.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=

View File

@@ -1,13 +0,0 @@
package main
import (
"fmt"
"github.com/goplus/lib/c"
)
func main() {
println("hello world by println")
fmt.Println("hello world by fmt.Println")
c.Printf(c.Str("Hello world by c.Printf\n"))
}

View File

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

View File

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

View File

@@ -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() {

View File

@@ -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 (

View File

@@ -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 (

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -1,9 +1,9 @@
package main package main
import ( import (
"github.com/goplus/lib/c" "github.com/goplus/llgo/_demo/cppintf/foo"
"github.com/goplus/lib/c/math" "github.com/goplus/llgo/c"
"github.com/goplus/llgo/_demo/c/cppintf/foo" "github.com/goplus/llgo/c/math"
) )
type Bar struct { type Bar struct {

View File

@@ -3,9 +3,9 @@ package main
import ( import (
"unsafe" "unsafe"
"github.com/goplus/lib/c" "github.com/goplus/llgo/_demo/cppmintf/foo"
"github.com/goplus/lib/c/math" "github.com/goplus/llgo/c"
"github.com/goplus/llgo/_demo/c/cppmintf/foo" "github.com/goplus/llgo/c/math"
) )
type Bar struct { type Bar struct {

View File

@@ -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 {

View File

@@ -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

View File

@@ -1,16 +0,0 @@
package main
import "github.com/goplus/lib/c"
func myprint(s *c.Char) {
for i := 0; i < int(c.Strlen(s)); i++ {
WriteByte(byte(c.Index(s, i)))
}
}
func main() {
for {
myprint(c.Str("hello world"))
sleep(1)
}
}

View File

@@ -1,13 +0,0 @@
package main
import (
_ "unsafe"
"github.com/goplus/lib/c"
)
//go:linkname WriteByte C.board_uart_write_char
func WriteByte(b byte)
//go:linkname sleep sleep
func sleep(c c.Int)

File diff suppressed because it is too large Load Diff

View File

@@ -1,385 +0,0 @@
package main
import (
_ "unsafe"
"github.com/goplus/llgo/_demo/embed/esp32/watchdog"
)
//
//go:linkname absvdi2 __absvdi2
func absvdi2(a int64) int64
//go:linkname absvsi2 __absvsi2
func absvsi2(a int32) int32
//go:linkname adddf3 __adddf3
func adddf3(a, b float64) float64
//go:linkname addsf3 __addsf3
func addsf3(a, b float32) float32
//go:linkname addvdi3 __addvdi3
func addvdi3(a, b int64) int64
//go:linkname addvsi3 __addvsi3
func addvsi3(a, b int32) int32
//go:linkname udivdi3 __udivdi3
func udivdi3(a, b uint64) uint64
//go:linkname clzdi2 __clzdi2
func clzdi2(a uint64) int32
//go:linkname clzsi2 __clzsi2
func clzsi2(a uint32) int32
//go:linkname ctzdi2 __ctzdi2
func ctzdi2(a uint64) int32
//go:linkname ctzsi2 __ctzsi2
func ctzsi2(a uint32) int32
//go:linkname popcountdi2 __popcountdi2
func popcountdi2(a uint64) int32
//go:linkname popcountsi2 __popcountsi2
func popcountsi2(a uint32) int32
//go:linkname divdf3 __divdf3
func divdf3(a, b float64) float64
//go:linkname divsf3 __divsf3
func divsf3(a, b float32) float32
//go:linkname mulsf3 __mulsf3
func mulsf3(a, b float32) float32
//go:linkname divdi3 __divdi3
func divdi3(a, b int64) int64
//go:linkname muldf3 __muldf3
func muldf3(a, b float64) float64
//go:linkname muldi3 __muldi3
func muldi3(a, b int64) int64
//go:linkname subdf3 __subdf3
func subdf3(a, b float64) float64
//go:linkname subsf3 __subsf3
func subsf3(a, b float32) float32
//go:linkname extendsfdf2 __extendsfdf2
func extendsfdf2(a float32) float64
//go:linkname fixdfdi __fixdfdi
func fixdfdi(a float64) int64
//go:linkname fixdfsi __fixdfsi
func fixdfsi(a float64) int32
//go:linkname fixsfdi __fixsfdi
func fixsfdi(a float32) int64
//go:linkname fixsfsi __fixsfsi
func fixsfsi(a float32) int32
//go:linkname floatdidf __floatdidf
func floatdidf(a int64) float64
//go:linkname floatsidf __floatsidf
func floatsidf(a int32) float64
//go:linkname ashldi3 __ashldi3
func ashldi3(a int64, b int32) int64
//go:linkname ashrdi3 __ashrdi3
func ashrdi3(a int64, b int32) int64
//go:linkname lshrdi3 __lshrdi3
func lshrdi3(a uint64, b int32) uint64
//go:linkname bswapdi2 __bswapdi2
func bswapdi2(a uint64) uint64
//go:linkname bswapsi2 __bswapsi2
func bswapsi2(a uint32) uint32
var totalTests = 0
var passedTests = 0
var failedTests = 0
func assertEqualInt32(name string, actual, expected int32) {
totalTests++
if actual != expected {
println("FAIL: %s: expected %d, got %d\n", name, expected, actual)
failedTests++
} else {
passedTests++
}
}
func assertEqualInt64(name string, actual, expected int64) {
totalTests++
if actual != expected {
println("FAIL: %s: expected %d, got %d\n", name, expected, actual)
failedTests++
} else {
passedTests++
}
}
func assertEqualUint32(name string, actual, expected uint32) {
totalTests++
if actual != expected {
println("FAIL: %s: expected %d, got %d\n", name, expected, actual)
failedTests++
} else {
passedTests++
}
}
func assertEqualUint64(name string, actual, expected uint64) {
totalTests++
if actual != expected {
println("FAIL: %s: expected %d, got %d\n", name, expected, actual)
failedTests++
} else {
passedTests++
}
}
func assertEqualFloat32(name string, actual, expected float32, epsilon float32) {
totalTests++
diff := actual - expected
if diff < 0 {
diff = -diff
}
if diff > epsilon {
println("FAIL: %s: expected %f, got %f\n", name, expected, actual)
failedTests++
} else {
passedTests++
}
}
func assertEqualFloat64(name string, actual, expected float64, epsilon float64) {
totalTests++
diff := actual - expected
if diff < 0 {
diff = -diff
}
if diff > epsilon {
println("FAIL: %s: expected %f, got %f\n", name, expected, actual)
failedTests++
} else {
passedTests++
}
}
func testAbsFunctions() {
println("Testing absolute value functions...")
// Test absvsi2
assertEqualInt32("absvsi2", absvsi2(12345), 12345)
assertEqualInt32("absvsi2", absvsi2(-12345), 12345)
assertEqualInt32("absvsi2", absvsi2(0), 0)
// Test absvdi2
assertEqualInt64("absvdi2", absvdi2(1234567890123456789), 1234567890123456789)
assertEqualInt64("absvdi2", absvdi2(-1234567890123456789), 1234567890123456789)
assertEqualInt64("absvdi2", absvdi2(0), 0)
}
func testAddFunctions() {
println("Testing addition functions...")
// Test addvsi3
assertEqualInt32("addvsi3", addvsi3(1000, 2000), 3000)
assertEqualInt32("addvsi3", addvsi3(-1000, -2000), -3000)
assertEqualInt32("addvsi3", addvsi3(0, 0), 0)
// Test addvdi3
assertEqualInt64("addvdi3", addvdi3(1000000000, 2000000000), 3000000000)
assertEqualInt64("addvdi3", addvdi3(-1000000000, -2000000000), -3000000000)
assertEqualInt64("addvdi3", addvdi3(0, 0), 0)
// Test adddf3
assertEqualFloat64("adddf3", adddf3(3.14, 2.71), 5.85, 1e-10)
assertEqualFloat64("adddf3", adddf3(-3.14, -2.71), -5.85, 1e-10)
assertEqualFloat64("adddf3", adddf3(0.0, 0.0), 0.0, 1e-10)
// Test addsf3
assertEqualFloat32("addsf3", addsf3(3.14, 2.71), 5.85, 1e-6)
assertEqualFloat32("addsf3", addsf3(-3.14, -2.71), -5.85, 1e-6)
assertEqualFloat32("addsf3", addsf3(0.0, 0.0), 0.0, 1e-6)
}
func testCountFunctions() {
println("Testing count functions...")
// Test clzsi2 - count leading zeros in 32-bit integer
assertEqualInt32("clzsi2", clzsi2(1), 31) // 0x00000001 has 31 leading zeros
assertEqualInt32("clzsi2", clzsi2(0x80000000), 0) // 0x80000000 has 0 leading zeros
assertEqualInt32("clzsi2", clzsi2(0), 32) // 0 has 32 leading zeros
// FIXME
// // Test clzdi2 - count leading zeros in 64-bit integer
// assertEqualInt32("clzdi2", clzdi2(1), 63) // 0x0000000000000001 has 63 leading zeros
// assertEqualInt32("clzdi2", clzdi2(0x8000000000000000), 0) // 0x8000000000000000 has 0 leading zeros
// assertEqualInt32("clzdi2", clzdi2(0), 64) // 0 has 64 leading zeros
// Test ctzsi2 - count trailing zeros in 32-bit integer
assertEqualInt32("ctzsi2", ctzsi2(1<<5), 5) // 0x00000020 has 5 trailing zeros
assertEqualInt32("ctzsi2", ctzsi2(0x80000000), 31) // 0x80000000 has 31 trailing zeros
assertEqualInt32("ctzsi2", ctzsi2(0), 32) // 0 has 32 trailing zeros
// Test ctzdi2 - count trailing zeros in 64-bit integer
assertEqualInt32("ctzdi2", ctzdi2(1<<10), 10) // 0x0000000000000400 has 10 trailing zeros
assertEqualInt32("ctzdi2", ctzdi2(0x8000000000000000), 63) // 0x8000000000000000 has 63 trailing zeros
assertEqualInt32("ctzdi2", ctzdi2(0), 64) // 0 has 64 trailing zeros
// Test popcountsi2 - population count of 32-bit integer
assertEqualInt32("popcountsi2", popcountsi2(0xF0F0F0F0), 16) // 0xF0F0F0F0 has 16 ones
assertEqualInt32("popcountsi2", popcountsi2(0), 0) // 0 has 0 ones
assertEqualInt32("popcountsi2", popcountsi2(0xFFFFFFFF), 32) // 0xFFFFFFFF has 32 ones
// Test popcountdi2 - population count of 64-bit integer
assertEqualInt32("popcountdi2", popcountdi2(0xFFFF0000FFFF0000), 32) // 0xFFFF0000FFFF0000 has 32 ones
assertEqualInt32("popcountdi2", popcountdi2(0), 0) // 0 has 0 ones
assertEqualInt32("popcountdi2", popcountdi2(0xFFFFFFFFFFFFFFFF), 64) // 0xFFFFFFFFFFFFFFFF has 64 ones
}
func testDivisionFunctions() {
println("Testing division functions...")
// Test udivdi3 - unsigned 64-bit division
assertEqualUint64("udivdi3", udivdi3(100, 5), 20)
assertEqualUint64("udivdi3", udivdi3(18446744073709551615, 3), 6148914691236517205)
assertEqualUint64("udivdi3", udivdi3(0, 123456789), 0)
// Test divdi3 - signed 64-bit division
assertEqualInt64("divdi3", divdi3(20, 3), 6)
assertEqualInt64("divdi3", divdi3(-20, 3), -6)
assertEqualInt64("divdi3", divdi3(20, -3), -6)
// Test divdf3 - double precision division
assertEqualFloat64("divdf3", divdf3(20.0, 3.0), 6.666666666666667, 1e-10)
assertEqualFloat64("divdf3", divdf3(-20.0, 3.0), -6.666666666666667, 1e-10)
// Test divsf3 - single precision division
assertEqualFloat32("divsf3", divsf3(20.0, 3.0), 6.6666665, 1e-6)
assertEqualFloat32("divsf3", divsf3(-20.0, 3.0), -6.6666665, 1e-6)
}
func testMultiplicationFunctions() {
println("Testing multiplication functions...")
// Test muldi3 - signed 64-bit multiplication
assertEqualInt64("muldi3", muldi3(5, 4), 20)
assertEqualInt64("muldi3", muldi3(-5, 4), -20)
assertEqualInt64("muldi3", muldi3(5, -4), -20)
// Test muldf3 - double precision multiplication
assertEqualFloat64("muldf3", muldf3(3.0, 4.0), 12.0, 1e-10)
assertEqualFloat64("muldf3", muldf3(-3.0, 4.0), -12.0, 1e-10)
// Test mulsf3 - single precision multiplication
assertEqualFloat32("mulsf3", mulsf3(3.0, 4.0), 12.0, 1e-6)
assertEqualFloat32("mulsf3", mulsf3(-3.0, 4.0), -12.0, 1e-6)
}
func testSubtractionFunctions() {
println("Testing subtraction functions...")
// Test subdf3 - double precision subtraction
assertEqualFloat64("subdf3", subdf3(5.0, 3.0), 2.0, 1e-10)
assertEqualFloat64("subdf3", subdf3(3.0, 5.0), -2.0, 1e-10)
// Test subsf3 - single precision subtraction
assertEqualFloat32("subsf3", subsf3(5.0, 3.0), 2.0, 1e-6)
assertEqualFloat32("subsf3", subsf3(3.0, 5.0), -2.0, 1e-6)
}
func testConversionFunctions() {
println("Testing conversion functions...")
// Test extendsfdf2 - single to double precision conversion
// FIXME
// assertEqualFloat64("extendsfdf2", extendsfdf2(3.14), 3.14, 1e-10)
// Test fixdfsi - double precision to int32 conversion
assertEqualInt32("fixdfsi", fixdfsi(123.45), 123)
assertEqualInt32("fixdfsi", fixdfsi(-123.45), -123)
// Test fixsfsi - single precision to int32 conversion
assertEqualInt32("fixsfsi", fixsfsi(123.45), 123)
assertEqualInt32("fixsfsi", fixsfsi(-123.45), -123)
// Test fixdfdi - double precision to int64 conversion
assertEqualInt64("fixdfdi", fixdfdi(123456789.123), 123456789)
assertEqualInt64("fixdfdi", fixdfdi(-123456789.123), -123456789)
// Test fixsfdi - single precision to int64 conversion
// FIXME
// assertEqualInt64("fixsfdi", fixsfdi(123456789.123), 123456789)
// assertEqualInt64("fixsfdi", fixsfdi(-123456789.123), -123456789)
// Test floatsidf - int32 to double precision conversion
assertEqualFloat64("floatsidf", floatsidf(42), 42.0, 1e-10)
assertEqualFloat64("floatsidf", floatsidf(-100), -100.0, 1e-10)
// Test floatdidf - int64 to double precision conversion
assertEqualFloat64("floatdidf", floatdidf(123456789), 123456789.0, 1e-10)
assertEqualFloat64("floatdidf", floatdidf(-123456789), -123456789.0, 1e-10)
}
func testShiftFunctions() {
println("Testing shift functions...")
// Test ashldi3 - arithmetic shift left
assertEqualInt64("ashldi3", ashldi3(1, 10), 1024)
// Test ashrdi3 - arithmetic shift right
assertEqualInt64("ashrdi3", ashrdi3(1024, 10), 1)
// Test lshrdi3 - logical shift right
assertEqualUint64("lshrdi3", lshrdi3(1024, 10), 1)
assertEqualUint64("lshrdi3", lshrdi3(0x8000000000000000, 63), 1)
}
func testBitManipulationFunctions() {
println("Testing bit manipulation functions...")
// Test bswapsi2 - byte swap 32-bit integer
assertEqualUint32("bswapsi2", bswapsi2(0x12345678), 0x78563412)
// Test bswapdi2 - byte swap 64-bit integer
assertEqualUint64("bswapdi2", bswapdi2(0x1234567890ABCDEF), 0xEFCDAB9078563412)
}
func main() {
watchdog.Disable()
println("Testing Compiler-RT Builtins Functions")
println("=====================================")
testAbsFunctions()
testAddFunctions()
testCountFunctions()
testDivisionFunctions()
testMultiplicationFunctions()
testSubtractionFunctions()
testConversionFunctions()
testShiftFunctions()
testBitManipulationFunctions()
println("\n=====================================")
println("Test Results: %d total, %d passed, %d failed\n", totalTests, passedTests, failedTests)
println("=====================================")
if failedTests == 0 {
println("All tests PASSED!")
} else {
println("Some tests FAILED!")
}
}

View File

@@ -1,16 +0,0 @@
package watchdog
import (
"unsafe"
_ "unsafe"
)
//go:linkname StoreUint32 llgo.atomicStore
func StoreUint32(addr *uint32, val uint32)
func Disable() {
StoreUint32((*uint32)(unsafe.Pointer(uintptr(0x3ff480A4))), 0x50D83AA1)
StoreUint32((*uint32)(unsafe.Pointer(uintptr(0x3ff4808C))), 0)
StoreUint32((*uint32)(unsafe.Pointer(uintptr(0x3ff5f048))), 0)
}

View File

@@ -1,31 +0,0 @@
package main
import (
_ "unsafe"
"github.com/goplus/lib/c"
)
//go:linkname write C.write
func write(c.Int, *c.Char, c.SizeT) int
func main() {
buf := c.Malloc(6)
c.Memset(buf, 0, 6)
c.Strncpy((*c.Char)(buf), c.Str("abcde"), 5)
if c.Strcmp((*c.Char)(buf), c.Str("abcde")) == 0 {
write(1, c.Str("pass strcmp"), 11)
}
if byte(c.Index((*c.Char)(buf), 0)) == 'a' {
write(1, c.Str("pass index"), 10)
}
c.Memset(buf, c.Int('A'), 5)
if c.Strcmp((*c.Char)(buf), c.Str("AAAAA")) == 0 {
write(1, c.Str("pass memeset"), 11)
}
write(1, (*c.Char)(buf), 5)
}

View File

@@ -1,5 +0,0 @@
module github.com/goplus/llgo/_demo/embed
go 1.20
require github.com/goplus/lib v0.3.0

View File

@@ -1,2 +0,0 @@
github.com/goplus/lib v0.3.0 h1:y0ZGb5Q/RikW1oMMB4Di7XIZIpuzh/7mlrR8HNbxXCA=
github.com/goplus/lib v0.3.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=

View File

@@ -1,21 +0,0 @@
package C
func XhandleHardFault() {
}
func Reset_Handler() {
}
func XhandleInterrupt() {
}
type dyn64 struct {
// Fields for dynamic loader
}
// For nintendo switch
func X__dynamic_loader(base uintptr, dyn *dyn64) {
}

View File

@@ -1,180 +0,0 @@
#!/bin/bash
# Function to display usage information
show_usage() {
cat << EOF
Usage: $(basename "$0") [OPTIONS] [TARGET_FILE]
Build targets for llgo across multiple platforms.
OPTIONS:
-h, --help Show this help message and exit
ARGUMENTS:
TARGET_FILE Optional. A text file containing target names, one per line.
Lines starting with # are treated as comments and ignored.
Empty lines are also ignored.
BEHAVIOR:
Without TARGET_FILE:
- Automatically discovers all targets from ../../targets/*.json files
- Extracts target names from JSON filenames
With TARGET_FILE:
- Reads target names from the specified file
- Supports comments (lines starting with #)
- Ignores empty lines and whitespace
IGNORED TARGETS:
The following targets are automatically ignored and not built:
atmega1280, atmega2560, atmega328p, atmega32u4, attiny85,
fe310, k210, riscv32, riscv64, rp2040
RESULT CATEGORIES:
✅ Successful: Build completed successfully
🔕 Ignored: Target is in the ignore list
⚠️ Warned: Build failed with configuration warnings
❌ Failed: Build failed with errors
EXIT CODES:
0 All builds successful, ignored, or warned only
1 One or more builds failed with errors
EXAMPLES:
$(basename "$0") # Build all targets from JSON files
$(basename "$0") my-targets.txt # Build targets from file
$(basename "$0") --help # Show this help
TARGET FILE FORMAT:
# This is a comment
esp32
cortex-m4
# Another comment
riscv64
EOF
}
# Check for help flag
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_usage
exit 0
fi
# Check for invalid number of arguments
if [ $# -gt 1 ]; then
echo "Error: Too many arguments."
echo "Use '$(basename "$0") --help' for usage information."
exit 1
fi
# Initialize arrays to store results
successful_targets=()
ignored_targets=()
warned_targets=()
failed_targets=()
targets_to_build=()
# Define ignore list
ignore_list=(
"atmega1280"
"atmega2560"
"atmega328p"
"atmega32u4"
"attiny85"
"fe310"
"k210"
"riscv32"
"riscv64"
"rp2040"
)
# Build the targets list based on input method
if [ $# -eq 1 ]; then
# Read targets from file
target_file="$1"
if [ ! -f "$target_file" ]; then
echo "Error: Target file '$target_file' not found."
echo "Use '$(basename "$0") --help' for usage information."
exit 1
fi
while IFS= read -r target || [[ -n "$target" ]]; do
# Skip empty lines and comments
if [[ -z "$target" || "$target" =~ ^[[:space:]]*# ]]; then
continue
fi
# Trim whitespace
target=$(echo "$target" | xargs)
targets_to_build+=("$target")
done < "$target_file"
else
# Use targets from *.json files
for target_file in ../../../targets/*.json; do
# Extract target name from filename (remove path and .json extension)
target=$(basename "$target_file" .json)
targets_to_build+=("$target")
done
fi
# Process each target
for target in "${targets_to_build[@]}"; do
# Check if target is in ignore list
if [[ " ${ignore_list[@]} " =~ " ${target} " ]]; then
echo 🔕 $target "(ignored)"
ignored_targets+=("$target")
continue
fi
output=$(../../../llgo.sh build -target $target -o hello.elf . 2>&1)
if [ $? -eq 0 ]; then
echo$target `file hello.elf`
successful_targets+=("$target")
else
# Check if output contains warning messages
if echo "$output" | grep -q "does not have a valid LLVM target triple\|does not have a valid CPU configuration"; then
echo ⚠️ $target
echo "$output"
warned_targets+=("$target")
else
echo$target
echo "$output"
failed_targets+=("$target")
fi
fi
done
echo ""
echo "----------------------------------------"
# Output successful targets
echo "Successful targets (${#successful_targets[@]} total):"
for target in "${successful_targets[@]}"; do
echo "$target"
done
echo ""
echo "Ignored targets (${#ignored_targets[@]} total):"
for target in "${ignored_targets[@]}"; do
echo "$target"
done
echo ""
echo "Warned targets (${#warned_targets[@]} total):"
for target in "${warned_targets[@]}"; do
echo "$target"
done
echo ""
echo "Failed targets (${#failed_targets[@]} total):"
for target in "${failed_targets[@]}"; do
echo "$target"
done
# Exit with error code if there are any failed targets
if [ ${#failed_targets[@]} -gt 0 ]; then
echo ""
echo "Build failed with ${#failed_targets[@]} failed targets."
exit 1
fi

View File

@@ -1,6 +0,0 @@
package main
import _ "github.com/goplus/llgo/_demo/embed/targetsbuild/C"
func main() {
}

View File

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

View File

@@ -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 {

View File

@@ -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() {

View File

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

View File

@@ -1,23 +0,0 @@
package main
import (
"time"
"github.com/goplus/llgo/_demo/go/async/async"
"github.com/goplus/llgo/_demo/go/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{})
}))
}

View File

@@ -1,16 +0,0 @@
package timeout
import (
"time"
"github.com/goplus/llgo/_demo/go/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{})
}()
})
}

View File

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

View File

@@ -1,20 +0,0 @@
package main
import (
"bytes"
"os/exec"
"path/filepath"
)
func main() {
var data bytes.Buffer
cmd := exec.Command("echo", "hello llgo")
cmd.Dir = filepath.Dir("./")
cmd.Stdout = &data
err := cmd.Run()
if err != nil {
panic(err)
}
println("len:", len(data.Bytes()))
println("data:", data.String())
}

View File

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

View File

@@ -1 +0,0 @@
libexport.h

View File

@@ -1,29 +0,0 @@
package C
// XType - struct for export.go to use
type XType struct {
ID int32 `json:"id"`
Name string `json:"name"`
Value float64 `json:"value"`
Flag bool `json:"flag"`
}
func XAdd(a, b int) int {
return a + b
}
func Sub(a, b int64) int64 {
return a - b
}
func sub(a, b uint32) uint32 {
return a - b
}
func Xmul(a, b float32) float32 {
return a * b
}
func Concat(a, b string) string {
return a + b
}

View File

@@ -1,674 +0,0 @@
package main
import (
"unsafe"
C "github.com/goplus/llgo/_demo/go/export/c"
)
// assert helper function for testing
func assert[T comparable](got, expected T, message string) {
if got != expected {
println("ASSERTION FAILED:", message)
println(" Expected:", expected)
println(" Got: ", got)
panic("assertion failed: " + message)
}
println("✓", message)
}
// Small struct
type SmallStruct struct {
ID int8 `json:"id"`
Flag bool `json:"flag"`
}
// Large struct
type LargeStruct struct {
ID int64 `json:"id"`
Name string `json:"name"`
Values [10]float64 `json:"values"`
Metadata map[string]int `json:"metadata"`
Children []SmallStruct `json:"children"`
Extra1 int32 `json:"extra1"`
Extra2 uint64 `json:"extra2"`
Extra3 float32 `json:"extra3"`
Extra4 bool `json:"extra4"`
Extra5 uintptr `json:"extra5"`
}
// Self-referential struct
type Node struct {
Data int `json:"data"`
Next *Node `json:"next"`
}
// Named types
type MyInt int
type MyString string
// Function types for callbacks
//
//llgo:type C
type IntCallback func(int) int
//llgo:type C
type StringCallback func(string) string
//llgo:type C
type VoidCallback func()
// Complex struct with mixed arrays and slices
type ComplexData struct {
Matrix [3][4]int32 `json:"matrix"` // 2D array
Slices [][]string `json:"slices"` // slice of slices - commented out
IntArray [5]int `json:"int_array"` // 1D array
DataList []float64 `json:"data_list"` // slice - commented out
}
//export HelloWorld
func HelloWorld() {
println("Hello, World!")
}
// Functions with small struct parameters and return values
//export CreateSmallStruct
func CreateSmallStruct(id int8, flag bool) SmallStruct {
return SmallStruct{ID: id, Flag: flag}
}
//export ProcessSmallStruct
func ProcessSmallStruct(s SmallStruct) SmallStruct {
s.ID += 1
s.Flag = !s.Flag
return s
}
//export ProcessSmallStructPtr
func ProcessSmallStructPtr(s *SmallStruct) *SmallStruct {
if s != nil {
s.ID *= 2
s.Flag = !s.Flag
}
return s
}
// Functions with large struct parameters and return values
//export CreateLargeStruct
func CreateLargeStruct(id int64, name string) LargeStruct {
return LargeStruct{
ID: id,
Name: name,
Values: [10]float64{1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0},
Metadata: map[string]int{"count": 42, "size": 100},
Children: []SmallStruct{{ID: 1, Flag: true}, {ID: 2, Flag: false}},
Extra1: 12345,
Extra2: 67890,
Extra3: 3.14,
Extra4: true,
Extra5: 0x1000,
}
}
//export ProcessLargeStruct
func ProcessLargeStruct(ls LargeStruct) int64 {
total := ls.ID + int64(len(ls.Name))
for _, v := range ls.Values {
total += int64(v)
}
total += int64(len(ls.Children))
total += int64(ls.Extra1) + int64(ls.Extra2) + int64(ls.Extra3)
if ls.Extra4 {
total += 1000
}
total += int64(ls.Extra5)
return total
}
//export ProcessLargeStructPtr
func ProcessLargeStructPtr(ls *LargeStruct) *LargeStruct {
if ls != nil {
ls.ID += 100
ls.Name = "processed_" + ls.Name
ls.Extra1 *= 2
ls.Extra4 = !ls.Extra4
}
return ls
}
// Functions with self-referential struct
//export CreateNode
func CreateNode(data int) *Node {
return &Node{Data: data, Next: nil}
}
//export LinkNodes
func LinkNodes(first, second *Node) int {
if first != nil && second != nil {
first.Next = second
return first.Data + second.Data // Return sum for verification
}
if first != nil {
return first.Data + 1000 // Return data + offset if only first exists
}
return 2000 // Return fixed value if both are nil
}
//export TraverseNodes
func TraverseNodes(head *Node) int {
count := 0
current := head
for current != nil {
count++
current = current.Next
if count > 100 { // Safety check
break
}
}
return count
}
// Functions covering all basic types
//export ProcessBool
func ProcessBool(b bool) bool {
return !b
}
//export ProcessInt8
func ProcessInt8(x int8) int8 {
return x + 1
}
//export ProcessUint8
func ProcessUint8(x uint8) uint8 {
return x + 1
}
//export ProcessInt16
func ProcessInt16(x int16) int16 {
return x * 2
}
//export ProcessUint16
func ProcessUint16(x uint16) uint16 {
return x * 2
}
//export ProcessInt32
func ProcessInt32(x int32) int32 {
return x * 3
}
//export ProcessUint32
func ProcessUint32(x uint32) uint32 {
return x * 3
}
//export ProcessInt64
func ProcessInt64(x int64) int64 {
return x * 4
}
//export ProcessUint64
func ProcessUint64(x uint64) uint64 {
return x * 4
}
//export ProcessInt
func ProcessInt(x int) int {
return x * 11
}
//export ProcessUint
func ProcessUint(x uint) uint {
return x * 21
}
//export ProcessUintptr
func ProcessUintptr(x uintptr) uintptr {
return x + 300
}
//export ProcessFloat32
func ProcessFloat32(x float32) float32 {
return x * 1.5
}
//export ProcessFloat64
func ProcessFloat64(x float64) float64 {
return x * 2.5
}
//export ProcessString
func ProcessString(s string) string {
return "processed_" + s
}
//export ProcessUnsafePointer
func ProcessUnsafePointer(p unsafe.Pointer) unsafe.Pointer {
return p
}
// Functions with named types
//export ProcessMyInt
func ProcessMyInt(x MyInt) MyInt {
return x * 10
}
//export ProcessMyString
func ProcessMyString(s MyString) MyString {
return MyString("modified_" + string(s))
}
// Functions with arrays, slices, maps, channels
//export ProcessIntArray
func ProcessIntArray(arr [5]int) int {
total := 0
for _, v := range arr {
total += v
}
return total
}
//export CreateComplexData
func CreateComplexData() ComplexData {
return ComplexData{
Matrix: [3][4]int32{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
Slices: [][]string{{"helo"}},
IntArray: [5]int{10, 20, 30, 40, 50},
DataList: []float64{1.0},
}
}
//export ProcessComplexData
func ProcessComplexData(data ComplexData) int32 {
// Sum all matrix elements
var sum int32
for i := 0; i < 3; i++ {
for j := 0; j < 4; j++ {
sum += data.Matrix[i][j]
}
}
return sum
}
// Functions with multidimensional arrays as parameters and return values
//export ProcessMatrix2D
func ProcessMatrix2D(matrix [3][4]int32) int32 {
var sum int32
for i := 0; i < 3; i++ {
for j := 0; j < 4; j++ {
sum += matrix[i][j]
}
}
return sum
}
//export CreateMatrix1D
func CreateMatrix1D() [4]int32 {
return [4]int32{1, 2, 3, 4}
}
//export CreateMatrix2D
func CreateMatrix2D() [3][4]int32 {
return [3][4]int32{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}
}
//export ProcessMatrix3D
func ProcessMatrix3D(cube [2][3][4]uint8) uint32 {
var sum uint32
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
for k := 0; k < 4; k++ {
sum += uint32(cube[i][j][k])
}
}
}
return sum
}
//export CreateMatrix3D
func CreateMatrix3D() [2][3][4]uint8 {
var cube [2][3][4]uint8
val := uint8(1)
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
for k := 0; k < 4; k++ {
cube[i][j][k] = val
val++
}
}
}
return cube
}
//export ProcessGrid5x4
func ProcessGrid5x4(grid [5][4]float64) float64 {
var sum float64
for i := 0; i < 5; i++ {
for j := 0; j < 4; j++ {
sum += grid[i][j]
}
}
return sum
}
//export CreateGrid5x4
func CreateGrid5x4() [5][4]float64 {
var grid [5][4]float64
val := 1.0
for i := 0; i < 5; i++ {
for j := 0; j < 4; j++ {
grid[i][j] = val
val += 0.5
}
}
return grid
}
//export ProcessIntSlice
func ProcessIntSlice(slice []int) int {
total := 0
for _, v := range slice {
total += v
}
return total
}
//export ProcessStringMap
func ProcessStringMap(m map[string]int) int {
total := 0
for _, v := range m {
total += v
}
return total
}
//export ProcessIntChannel
func ProcessIntChannel(ch chan int) int {
select {
case val := <-ch:
return val
default:
return -1
}
}
// Functions with function callbacks
//export ProcessWithIntCallback
func ProcessWithIntCallback(x int, callback IntCallback) int {
if callback != nil {
return callback(x)
}
return x
}
//export ProcessWithStringCallback
func ProcessWithStringCallback(s string, callback StringCallback) string {
if callback != nil {
return callback(s)
}
return s
}
//export ProcessWithVoidCallback
func ProcessWithVoidCallback(callback VoidCallback) int {
if callback != nil {
callback()
return 123 // Return non-zero to indicate callback was called
}
return 456 // Return different value if callback is nil
}
//export ProcessThreeUnnamedParams
func ProcessThreeUnnamedParams(a int, s string, b bool) float64 {
result := float64(a) + float64(len(s))
if b {
result *= 1.5
}
return result
}
// Functions with interface
//export ProcessInterface
func ProcessInterface(i interface{}) int {
switch v := i.(type) {
case int:
return v + 100
case string:
return len(v) * 10
default:
return 999 // Non-zero default to avoid false positives
}
}
// Functions with various parameter counts
//export NoParams
func NoParams() int {
return 42
}
//export OneParam
func OneParam(x int) int {
return x * 2
}
//export TwoParams
func TwoParams(a int, b string) string {
return string(rune(a)) + b
}
//export ThreeParams
func ThreeParams(a int32, b float64, c bool) float64 {
result := float64(a) + b
if c {
result *= 2
}
return result
}
//export MultipleParams
func MultipleParams(a int8, b uint16, c int32, d uint64, e float32, f float64, g string, h bool) string {
result := g + "_" + string(rune('A'+a)) + string(rune('0'+b%10)) + string(rune('0'+c%10))
if h {
result += "_true"
}
return result + "_" + string(rune('0'+int(d%10))) + "_" + string(rune('0'+int(e)%10)) + "_" + string(rune('0'+int(f)%10))
}
//export NoParamNames
func NoParamNames(int8, int16, bool) int32 {
return 789 // Return non-zero value for testing, params are unnamed by design
}
// Functions returning no value
//export NoReturn
func NoReturn(message string) {
println("Message:", message)
}
// Functions using XType from c package
//export CreateXType
func CreateXType(id int32, name string, value float64, flag bool) C.XType {
return C.XType{
ID: id,
Name: name,
Value: value,
Flag: flag,
}
}
//export ProcessXType
func ProcessXType(x C.XType) C.XType {
x.ID += 100
x.Name = "processed_" + x.Name
x.Value *= 2.0
x.Flag = !x.Flag
return x
}
//export ProcessXTypePtr
func ProcessXTypePtr(x *C.XType) *C.XType {
if x != nil {
x.ID *= 2
x.Name = "ptr_" + x.Name
x.Value += 10.0
x.Flag = !x.Flag
}
return x
}
func main() {
println("=== Export Demo ===")
// Test small struct
small := CreateSmallStruct(5, true)
assert(small.ID, int8(5), "CreateSmallStruct ID should be 5")
assert(small.Flag, true, "CreateSmallStruct Flag should be true")
println("Small struct:", small.ID, small.Flag)
processed := ProcessSmallStruct(small)
assert(processed.ID, int8(6), "ProcessSmallStruct should increment ID to 6")
assert(processed.Flag, false, "ProcessSmallStruct should flip Flag to false")
println("Processed small:", processed.ID, processed.Flag)
// Test large struct
large := CreateLargeStruct(12345, "test")
assert(large.ID, int64(12345), "CreateLargeStruct ID should be 12345")
assert(large.Name, "test", "CreateLargeStruct Name should be 'test'")
println("Large struct ID:", large.ID, "Name:", large.Name)
total := ProcessLargeStruct(large)
// Expected calculation:
// ID: 12345, Name len: 4, Values: 1+2+3+4+5+6+7+8+9+10=55, Children len: 2
// Extra1: 12345, Extra2: 67890, Extra3: 3, Extra4: +1000, Extra5: 4096
expectedTotal := int64(12345 + 4 + 55 + 2 + 12345 + 67890 + 3 + 1000 + 4096)
assert(total, expectedTotal, "ProcessLargeStruct total should match expected calculation")
println("Large struct total:", total)
// Test self-referential struct
node1 := CreateNode(100)
node2 := CreateNode(200)
linkResult := LinkNodes(node1, node2)
assert(linkResult, 300, "LinkNodes should return sum of node data (100 + 200)")
count := TraverseNodes(node1)
assert(count, 2, "TraverseNodes should count 2 linked nodes")
println("Node count:", count)
// Test basic types with assertions
assert(ProcessBool(true), false, "ProcessBool(true) should return false")
assert(ProcessInt8(10), int8(11), "ProcessInt8(10) should return 11")
f32Result := ProcessFloat32(3.14)
// Float comparison with tolerance
if f32Result < 4.7 || f32Result > 4.72 {
println("ASSERTION FAILED: ProcessFloat32(3.14) should return ~4.71, got:", f32Result)
panic("float assertion failed")
}
println("✓ ProcessFloat32(3.14) returns ~4.71")
assert(ProcessString("hello"), "processed_hello", "ProcessString should prepend 'processed_'")
println("Bool:", ProcessBool(true))
println("Int8:", ProcessInt8(10))
println("Float32:", ProcessFloat32(3.14))
println("String:", ProcessString("hello"))
// Test named types
myInt := ProcessMyInt(MyInt(42))
assert(myInt, MyInt(420), "ProcessMyInt(42) should return 420")
println("MyInt:", int(myInt))
myStr := ProcessMyString(MyString("world"))
assert(myStr, MyString("modified_world"), "ProcessMyString should prepend 'modified_'")
println("MyString:", string(myStr))
// Test collections
arr := [5]int{1, 2, 3, 4, 5}
arrSum := ProcessIntArray(arr)
assert(arrSum, 15, "ProcessIntArray([1,2,3,4,5]) should return 15")
println("Array sum:", arrSum)
slice := []int{10, 20, 30}
sliceSum := ProcessIntSlice(slice)
assert(sliceSum, 60, "ProcessIntSlice([10,20,30]) should return 60")
println("Slice sum:", sliceSum)
m := make(map[string]int)
m["a"] = 100
m["b"] = 200
mapSum := ProcessStringMap(m)
assert(mapSum, 300, "ProcessStringMap({'a':100,'b':200}) should return 300")
println("Map sum:", mapSum)
// Test multidimensional arrays
matrix2d := CreateMatrix2D()
matrix2dSum := ProcessMatrix2D(matrix2d)
assert(matrix2dSum, int32(78), "ProcessMatrix2D should return 78 (sum of 1+2+...+12)")
println("Matrix2D sum:", matrix2dSum)
matrix3d := CreateMatrix3D()
matrix3dSum := ProcessMatrix3D(matrix3d)
assert(matrix3dSum, uint32(300), "ProcessMatrix3D should return 300")
println("Matrix3D sum:", matrix3dSum)
grid5x4 := CreateGrid5x4()
gridSum := ProcessGrid5x4(grid5x4)
assert(gridSum, 115.0, "ProcessGrid5x4 should return 115.0")
println("Grid5x4 sum:", gridSum)
// Test complex data with multidimensional arrays
complexData := CreateComplexData()
complexSum := ProcessComplexData(complexData)
assert(complexSum, int32(78), "ProcessComplexData should return 78")
println("ComplexData matrix sum:", complexSum)
// Test various parameter counts
assert(NoParams(), 42, "NoParams should return 42")
assert(OneParam(5), 10, "OneParam(5) should return 10")
assert(TwoParams(65, "_test"), "A_test", "TwoParams should return 'A_test'")
assert(ThreeParams(10, 2.5, true), 25.0, "ThreeParams should return 25.0")
assert(NoParamNames(1, 2, false), int32(789), "NoParamNames should return 789")
println("NoParams:", NoParams())
println("OneParam:", OneParam(5))
println("TwoParams:", TwoParams(65, "_test"))
println("ThreeParams:", ThreeParams(10, 2.5, true))
println("MultipleParams:", MultipleParams(1, 2, 3, 4, 5.0, 6.0, "result", true))
println("NoParamNames:", NoParamNames(1, 2, false))
// Test XType from c package
xtype := CreateXType(42, "test", 3.14, true)
println("XType:", xtype.ID, xtype.Name, xtype.Value, xtype.Flag)
processedX := ProcessXType(xtype)
println("Processed XType:", processedX.ID, processedX.Name, processedX.Value, processedX.Flag)
ptrX := ProcessXTypePtr(&xtype)
if ptrX != nil {
println("Ptr XType:", ptrX.ID, ptrX.Name, ptrX.Value, ptrX.Flag)
}
// Test callback functions
intResult := ProcessWithIntCallback(10, func(x int) int { return x * 3 })
println("IntCallback result:", intResult)
stringResult := ProcessWithStringCallback("hello", func(s string) string { return s + "_callback" })
println("StringCallback result:", stringResult)
ProcessWithVoidCallback(func() { println("VoidCallback executed") })
NoReturn("demo completed")
}

View File

@@ -1,315 +0,0 @@
/* Code generated by llgo; DO NOT EDIT. */
#ifndef __LIBEXPORT_H_
#define __LIBEXPORT_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
// Platform-specific symbol renaming macro
#ifdef __APPLE__
#define GO_SYMBOL_RENAME(go_name) __asm("_" go_name);
#else
#define GO_SYMBOL_RENAME(go_name) __asm(go_name);
#endif
// Go runtime types
typedef struct { const char *p; intptr_t n; } GoString;
typedef struct { void *data; intptr_t len; intptr_t cap; } GoSlice;
typedef struct { void *data; } GoMap;
typedef struct { void *data; } GoChan;
typedef struct { void *data; void *type; } GoInterface;
typedef struct { float real; float imag; } GoComplex64;
typedef struct { double real; double imag; } GoComplex128;
typedef struct {
int32_t Matrix[3][4];
GoSlice Slices;
intptr_t IntArray[5];
GoSlice DataList;
} main_ComplexData;
typedef struct {
double data[5][4];
} Array_double_5_4;
typedef struct {
int8_t ID;
_Bool Flag;
} main_SmallStruct;
typedef struct {
int64_t ID;
GoString Name;
double Values[10];
GoMap Metadata;
GoSlice Children;
int32_t Extra1;
uint64_t Extra2;
float Extra3;
_Bool Extra4;
uintptr_t Extra5;
} main_LargeStruct;
typedef struct {
int32_t data[4];
} Array_int32_t_4;
typedef struct {
int32_t data[3][4];
} Array_int32_t_3_4;
typedef struct {
uint8_t data[2][3][4];
} Array_uint8_t_2_3_4;
typedef struct main_Node main_Node;
struct main_Node {
intptr_t Data;
main_Node* Next;
};
typedef struct {
int32_t ID;
GoString Name;
double Value;
_Bool Flag;
} C_XType;
typedef intptr_t main_MyInt;
typedef GoString main_MyString;
typedef intptr_t (*main_IntCallback)(intptr_t);
typedef GoString (*main_StringCallback)(GoString);
typedef void (*main_VoidCallback)(void);
GoString
Concat(GoString a, GoString b);
int64_t
Sub(int64_t a, int64_t b);
intptr_t
Add(intptr_t a, intptr_t b);
float
mul(float a, float b);
void
github_com_goplus_llgo__demo_go_export_c_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/_demo/go/export/c.init")
main_ComplexData
CreateComplexData(void);
Array_double_5_4
CreateGrid5x4(void);
main_LargeStruct
CreateLargeStruct(int64_t id, GoString name);
Array_int32_t_4
CreateMatrix1D(void);
Array_int32_t_3_4
CreateMatrix2D(void);
Array_uint8_t_2_3_4
CreateMatrix3D(void);
main_Node*
CreateNode(intptr_t data);
main_SmallStruct
CreateSmallStruct(int8_t id, _Bool flag);
C_XType
CreateXType(int32_t id, GoString name, double value, _Bool flag);
void
HelloWorld(void);
intptr_t
LinkNodes(main_Node* first, main_Node* second);
GoString
MultipleParams(int8_t a, uint16_t b, int32_t c, uint64_t d, float e, double f, GoString g, _Bool h);
int32_t
NoParamNames(int8_t, int16_t, _Bool);
intptr_t
NoParams(void);
void
NoReturn(GoString message);
intptr_t
OneParam(intptr_t x);
_Bool
ProcessBool(_Bool b);
int32_t
ProcessComplexData(main_ComplexData data);
float
ProcessFloat32(float x);
double
ProcessFloat64(double x);
double
ProcessGrid5x4(double grid[5][4]);
intptr_t
ProcessInt(intptr_t x);
int16_t
ProcessInt16(int16_t x);
int32_t
ProcessInt32(int32_t x);
int64_t
ProcessInt64(int64_t x);
int8_t
ProcessInt8(int8_t x);
intptr_t
ProcessIntArray(intptr_t* arr);
intptr_t
ProcessIntChannel(GoChan ch);
intptr_t
ProcessIntSlice(GoSlice slice);
intptr_t
ProcessInterface(GoInterface i);
int64_t
ProcessLargeStruct(main_LargeStruct ls);
main_LargeStruct*
ProcessLargeStructPtr(main_LargeStruct* ls);
int32_t
ProcessMatrix2D(int32_t matrix[3][4]);
uint32_t
ProcessMatrix3D(uint8_t cube[2][3][4]);
main_MyInt
ProcessMyInt(main_MyInt x);
main_MyString
ProcessMyString(main_MyString s);
main_SmallStruct
ProcessSmallStruct(main_SmallStruct s);
main_SmallStruct*
ProcessSmallStructPtr(main_SmallStruct* s);
GoString
ProcessString(GoString s);
intptr_t
ProcessStringMap(GoMap m);
double
ProcessThreeUnnamedParams(intptr_t a, GoString s, _Bool b);
uintptr_t
ProcessUint(uintptr_t x);
uint16_t
ProcessUint16(uint16_t x);
uint32_t
ProcessUint32(uint32_t x);
uint64_t
ProcessUint64(uint64_t x);
uint8_t
ProcessUint8(uint8_t x);
uintptr_t
ProcessUintptr(uintptr_t x);
void*
ProcessUnsafePointer(void* p);
intptr_t
ProcessWithIntCallback(intptr_t x, main_IntCallback callback);
GoString
ProcessWithStringCallback(GoString s, main_StringCallback callback);
intptr_t
ProcessWithVoidCallback(main_VoidCallback callback);
C_XType
ProcessXType(C_XType x);
C_XType*
ProcessXTypePtr(C_XType* x);
double
ThreeParams(int32_t a, double b, _Bool c);
intptr_t
TraverseNodes(main_Node* head);
GoString
TwoParams(intptr_t a, GoString b);
void
github_com_goplus_llgo__demo_go_export_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/_demo/go/export.init")
void
github_com_goplus_llgo_runtime_abi_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/abi.init")
void
github_com_goplus_llgo_runtime_internal_clite_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite.init")
void
github_com_goplus_llgo_runtime_internal_clite_bdwgc_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/bdwgc.init")
void
github_com_goplus_llgo_runtime_internal_clite_bitcast_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/bitcast.init")
void
github_com_goplus_llgo_runtime_internal_clite_debug_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/debug.init")
void
github_com_goplus_llgo_runtime_internal_clite_pthread_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/pthread.init")
void
github_com_goplus_llgo_runtime_internal_clite_pthread_sync_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/pthread/sync.init")
void
github_com_goplus_llgo_runtime_internal_runtime_goarch_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/runtime/goarch.init")
void
github_com_goplus_llgo_runtime_internal_runtime_math_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/runtime/math.init")
void
github_com_goplus_llgo_runtime_internal_runtime_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/runtime.init")
#ifdef __cplusplus
}
#endif
#endif /* __LIBEXPORT_H_ */

View File

@@ -1,278 +0,0 @@
#!/bin/bash
# Test script for C header generation in different build modes
# This script tests the header generation functionality with various buildmode options
set -e # Exit on any error
# Get script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to check if file exists and is not empty
check_file() {
local file="$1"
local description="$2"
if [[ -f "$file" ]]; then
if [[ -s "$file" ]]; then
print_status "$description exists and is not empty"
return 0
else
print_error "$description exists but is empty"
return 1
fi
else
print_error "$description does not exist"
return 1
fi
}
# Function to compare header with expected content
compare_header() {
local header_file="$1"
local expected_file="$2"
local test_name="$3"
if [[ -f "$expected_file" ]]; then
if diff -q "$header_file" "$expected_file" >/dev/null 2>&1; then
print_status "$test_name: Header content matches expected"
return 0
else
print_warning "$test_name: Header content differs from expected"
print_warning "Run 'diff $header_file $expected_file' to see differences"
return 1
fi
else
print_warning "$test_name: No expected file found at $expected_file"
print_status "Generated header content:"
echo "--- START OF HEADER ---"
cat "$header_file"
echo "--- END OF HEADER ---"
return 0
fi
}
# Function to cleanup generated files
cleanup() {
local files=("$@")
for file in "${files[@]}"; do
if [[ -f "$file" ]]; then
rm -f "$file"
print_status "Cleaned up $file"
fi
done
}
# Check if llgo.sh exists
LLGO_SCRIPT="../../../llgo.sh"
if [[ ! -f "$LLGO_SCRIPT" ]]; then
print_error "llgo.sh not found at $LLGO_SCRIPT"
exit 1
fi
print_status "Starting C header generation tests..."
print_status "Working directory: $SCRIPT_DIR"
echo ""
# Test 1: c-shared mode
print_status "=== Test 2: Building with -buildmode c-shared ==="
if $LLGO_SCRIPT build -buildmode c-shared -o export .; then
print_status "Build succeeded"
# Check generated files (different extensions on different platforms)
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
check_file "libexport.dylib" "Dynamic library (libexport.dylib)"
SHARED_LIB="libexport.dylib"
else
# Linux and others
check_file "libexport.so" "Dynamic library (libexport.so)"
SHARED_LIB="libexport.so"
fi
check_file "libexport.h" "C header (libexport.h)"
# Compare with expected header if it exists
if [[ -f "libexport.h" ]]; then
compare_header "libexport.h" "libexport.h.want" "c-shared"
fi
# Test C demo with shared library
print_status "=== Testing C demo with shared library ==="
if cd use; then
if LINK_TYPE=shared make clean && LINK_TYPE=shared make; then
print_status "C demo build succeeded with shared library"
if LINK_TYPE=shared make run; then
print_status "C demo execution succeeded with shared library"
else
print_warning "C demo execution failed with shared library"
fi
else
print_warning "C demo build failed with shared library"
fi
cd ..
else
print_error "Failed to enter use directory"
fi
# Cleanup
cleanup "$SHARED_LIB" "libexport.h"
else
print_error "Build failed for c-shared mode"
fi
# Test 2: c-archive mode
print_status "=== Test 1: Building with -buildmode c-archive ==="
if $LLGO_SCRIPT build -buildmode c-archive -o export .; then
print_status "Build succeeded"
# Check generated files
check_file "libexport.a" "Static library (libexport.a)"
check_file "libexport.h" "C header (libexport.h)"
# Compare with expected header if it exists
if [[ -f "libexport.h" ]]; then
compare_header "libexport.h" "libexport.h.want" "c-archive"
fi
# Test C demo with static library
print_status "=== Testing C demo with static library ==="
if cd use; then
if make clean && make; then
print_status "C demo build succeeded with static library"
if make run; then
print_status "C demo execution succeeded with static library"
else
print_warning "C demo execution failed with static library"
fi
else
print_warning "C demo build failed with static library"
fi
cd ..
else
print_error "Failed to enter use directory"
fi
# # Cleanup
# cleanup "libexport.a" "libexport.h"
else
print_error "Build failed for c-archive mode"
fi
echo ""
# TODO(lijie): Uncomment if https://github.com/goplus/llgo/pull/1268 merged
# # Test 3: ESP32 target with c-archive mode
# print_status "=== Test 3: Building with -target esp32 -buildmode c-archive ==="
# if $LLGO_SCRIPT build -target esp32 -buildmode c-archive -o export .; then
# print_status "Build succeeded"
# # Check generated files
# check_file "libexport.a" "Static library for ESP32 (libexport.a)"
# check_file "libexport.h" "C header for ESP32 (libexport.h)"
# # Compare with expected header if it exists
# if [[ -f "libexport.h" ]]; then
# compare_header "libexport.h" "libexport.h.want" "esp32-c-archive"
# fi
# # Don't cleanup ESP32 files - keep them for inspection
# print_status "ESP32 build files kept for inspection"
# else
# print_error "Build failed for ESP32 target"
# fi
# echo ""
# Test 3: Go export demo execution
print_status "=== Test 3: Running Go export demo ==="
if go run export.go > /tmp/go_export_output.log 2>&1; then
print_status "Go export demo execution succeeded"
# Check if output contains expected success indicators
if grep -q "✓" /tmp/go_export_output.log; then
SUCCESS_COUNT=$(grep -c "✓" /tmp/go_export_output.log)
print_status "All $SUCCESS_COUNT assertions passed in Go export demo"
else
print_warning "No assertion markers found in Go export demo output"
fi
# Show key output lines
print_status "Go export demo output summary:"
if grep -q "ASSERTION FAILED" /tmp/go_export_output.log; then
print_error "Found assertion failures in Go export demo"
grep "ASSERTION FAILED" /tmp/go_export_output.log
else
print_status " ✅ No assertion failures detected"
echo " 📊 First few lines of output:"
head -5 /tmp/go_export_output.log | sed 's/^/ /'
echo " 📊 Last few lines of output:"
tail -5 /tmp/go_export_output.log | sed 's/^/ /'
fi
else
print_error "Go export demo execution failed"
print_error "Error output:"
cat /tmp/go_export_output.log | sed 's/^/ /'
fi
# Cleanup temporary file
rm -f /tmp/go_export_output.log
echo ""
# Final summary
print_status "=== Test Summary ==="
if [[ -f "libexport.a" ]] && [[ -f "libexport.h" ]]; then
print_status "All tests completed successfully:"
print_status " ✅ Go export demo execution with assertions"
print_status " ✅ C header generation (c-archive and c-shared modes)"
print_status " ✅ C demo compilation and execution"
print_status " ✅ Cross-platform symbol renaming"
print_status " ✅ Init function export and calling"
print_status " ✅ Function callback types with proper typedef syntax"
print_status " ✅ Multidimensional array parameter handling"
print_status ""
print_status "Final files available:"
print_status " - libexport.a (static library)"
print_status " - libexport.h (C header file)"
print_status " - use/main.out (C demo executable)"
echo ""
echo "==================="
else
print_error "Some tests may have failed. Check the output above."
fi
# Show file sizes for reference
if [[ -f "libexport.a" ]]; then
SIZE=$(wc -c < libexport.a)
print_status "Static library size: $SIZE bytes"
fi
if [[ -f "libexport.h" ]]; then
LINES=$(wc -l < libexport.h)
print_status "Header file lines: $LINES"
fi
print_status "C header generation and demo tests completed!"

View File

@@ -1,84 +0,0 @@
# Makefile for C demo using Go exported library
# Use LINK_TYPE environment variable to choose library type:
# LINK_TYPE=static - Link with static library (default)
# LINK_TYPE=shared - Link with shared library
CC = clang
CFLAGS = -Wall -Wextra -std=c99
INCLUDES = -I..
TARGET = main.out
SOURCES = main.c
HEADER = ../libexport.h
# Default to static linking
LINK_TYPE ?= static
# Platform detection
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SHARED_EXT = dylib
PLATFORM_LIBS =
else
SHARED_EXT = so
PLATFORM_LIBS = $(shell pkg-config --libs libunwind 2>/dev/null || echo -lunwind)
endif
# Library and flags based on link type
ifeq ($(LINK_TYPE),shared)
BUILDMODE = c-shared
LIBRARY = ../libexport.$(SHARED_EXT)
LDFLAGS = -L.. -lexport -lpthread -lm $(shell pkg-config --libs bdw-gc || echo -lgc) $(PLATFORM_LIBS)
BUILD_MSG = "Building Go shared library..."
LINK_MSG = "Linking with shared library..."
else
BUILDMODE = c-archive
LIBRARY = ../libexport.a
LDFLAGS = $(LIBRARY) -lpthread -lm $(shell pkg-config --libs bdw-gc || echo -lgc) $(PLATFORM_LIBS)
BUILD_MSG = "Building Go static library..."
LINK_MSG = "Linking with static library..."
endif
.PHONY: all clean run build-go
all: build-go $(TARGET)
# Build the Go library first
build-go:
@echo $(BUILD_MSG)
cd .. && ../../../llgo.sh build -buildmode $(BUILDMODE) -o export .
# Build the C executable
$(TARGET): $(SOURCES) $(LIBRARY) $(HEADER)
@echo $(LINK_MSG)
$(CC) $(CFLAGS) $(INCLUDES) -o $(TARGET) $(SOURCES) $(LDFLAGS)
# Run the executable
run: $(TARGET)
@echo "Running C demo..."
ifeq ($(LINK_TYPE),shared)
@echo "Setting library path for shared library..."
LD_LIBRARY_PATH=.. DYLD_LIBRARY_PATH=.. ./$(TARGET)
else
./$(TARGET)
endif
# Clean build artifacts
clean:
rm -f $(TARGET)
rm -f ../libexport.a ../libexport.h ../libexport.so ../libexport.dylib
# Help target
help:
@echo "Available targets:"
@echo " all - Build Go library and C executable"
@echo " build-go - Build only the Go library"
@echo " run - Build and run the C demo"
@echo " clean - Clean all build artifacts"
@echo " help - Show this help message"
@echo ""
@echo "Environment variables:"
@echo " LINK_TYPE - Library type: 'static' (default) or 'shared'"
@echo ""
@echo "Examples:"
@echo " make run # Use static library"
@echo " LINK_TYPE=shared make run # Use shared library"

View File

@@ -1,237 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
#include "../libexport.h"
int main() {
printf("=== C Export Demo ===\n");
fflush(stdout); // Force output
// Initialize packages - call init functions first
github_com_goplus_llgo__demo_go_export_c_init();
github_com_goplus_llgo__demo_go_export_init();
// Test HelloWorld
HelloWorld();
printf("\n");
// Test small struct
main_SmallStruct small = CreateSmallStruct(5, 1); // 1 for true
printf("Small struct: %d %d\n", small.ID, small.Flag);
main_SmallStruct processed = ProcessSmallStruct(small);
printf("Processed small: %d %d\n", processed.ID, processed.Flag);
main_SmallStruct* ptrSmall = ProcessSmallStructPtr(&small);
if (ptrSmall != NULL) {
printf("Ptr small: %d %d\n", ptrSmall->ID, ptrSmall->Flag);
}
// Test large struct - create GoString for name parameter
GoString name = {"test_large", 10}; // name and length
main_LargeStruct large = CreateLargeStruct(12345, name);
printf("Large struct ID: %" PRId64 "\n", large.ID);
int64_t total = ProcessLargeStruct(large);
printf("Large struct total: %" PRId64 "\n", total);
main_LargeStruct* ptrLarge = ProcessLargeStructPtr(&large);
if (ptrLarge != NULL) {
printf("Ptr large ID: %" PRId64 "\n", ptrLarge->ID);
}
// Test self-referential struct
main_Node* node1 = CreateNode(100);
main_Node* node2 = CreateNode(200);
int link_result = LinkNodes(node1, node2);
assert(link_result == 300); // LinkNodes returns 100 + 200 = 300
printf("LinkNodes result: %d\n", link_result);
int count = TraverseNodes(node1);
assert(count == 2); // Should traverse 2 nodes
printf("Node count: %d\n", count);
// Test basic types with assertions
assert(ProcessBool(1) == 0); // ProcessBool(true) returns !true = false
printf("Bool: %d\n", ProcessBool(1));
assert(ProcessInt8(10) == 11); // ProcessInt8(x) returns x + 1
printf("Int8: %d\n", ProcessInt8(10));
assert(ProcessUint8(10) == 11); // ProcessUint8(x) returns x + 1
printf("Uint8: %d\n", ProcessUint8(10));
assert(ProcessInt16(10) == 20); // ProcessInt16(x) returns x * 2
printf("Int16: %d\n", ProcessInt16(10));
assert(ProcessUint16(10) == 20); // ProcessUint16(x) returns x * 2
printf("Uint16: %d\n", ProcessUint16(10));
assert(ProcessInt32(10) == 30); // ProcessInt32(x) returns x * 3
printf("Int32: %d\n", ProcessInt32(10));
assert(ProcessUint32(10) == 30); // ProcessUint32(x) returns x * 3
printf("Uint32: %u\n", ProcessUint32(10));
assert(ProcessInt64(10) == 40); // ProcessInt64(x) returns x * 4
printf("Int64: %" PRId64 "\n", ProcessInt64(10));
assert(ProcessUint64(10) == 40); // ProcessUint64(x) returns x * 4
printf("Uint64: %" PRIu64 "\n", ProcessUint64(10));
assert(ProcessInt(10) == 110); // ProcessInt(x) returns x * 11
printf("Int: %ld\n", ProcessInt(10));
assert(ProcessUint(10) == 210); // ProcessUint(x) returns x * 21
printf("Uint: %lu\n", ProcessUint(10));
assert(ProcessUintptr(0x1000) == 4396); // ProcessUintptr(x) returns x + 300 = 4096 + 300
printf("Uintptr: %lu\n", ProcessUintptr(0x1000));
// Float comparisons with tolerance
float f32_result = ProcessFloat32(3.14f);
assert(f32_result > 4.7f && f32_result < 4.72f); // ProcessFloat32(x) returns x * 1.5 ≈ 4.71
printf("Float32: %f\n", f32_result);
double f64_result = ProcessFloat64(3.14);
assert(f64_result > 7.84 && f64_result < 7.86); // ProcessFloat64(x) returns x * 2.5 ≈ 7.85
printf("Float64: %f\n", f64_result);
// Test unsafe pointer
int test_val = 42;
void* ptr_result = ProcessUnsafePointer(&test_val);
printf("UnsafePointer: %p\n", ptr_result);
// Test named types
main_MyInt myInt = ProcessMyInt(42);
printf("MyInt: %ld\n", (long)myInt);
// Test arrays
intptr_t arr[5] = {1, 2, 3, 4, 5};
printf("Array sum: %ld\n", ProcessIntArray(arr));
// Test complex data with multidimensional arrays
main_ComplexData complex = CreateComplexData();
printf("Complex data matrix sum: %" PRId32 "\n", ProcessComplexData(complex));
// Test interface - this is more complex in C, we'll skip for now
printf("Interface test skipped (complex in C)\n");
// Test various parameter counts
assert(NoParams() == 42); // NoParams() always returns 42
printf("NoParams: %ld\n", NoParams());
assert(OneParam(5) == 10); // OneParam(x) returns x * 2
printf("OneParam: %ld\n", OneParam(5));
assert(ThreeParams(10, 2.5, 1) == 25.0); // ThreeParams calculates result
printf("ThreeParams: %f\n", ThreeParams(10, 2.5, 1)); // 1 for true
// Test ProcessThreeUnnamedParams - now uses all parameters
GoString test_str = {"hello", 5};
double unnamed_result = ProcessThreeUnnamedParams(10, test_str, 1);
assert(unnamed_result == 22.5); // (10 + 5) * 1.5 = 22.5
printf("ProcessThreeUnnamedParams: %f\n", unnamed_result);
// Test ProcessWithVoidCallback - now returns int
int void_callback_result = ProcessWithVoidCallback(NULL);
assert(void_callback_result == 456); // Returns 456 when callback is nil
printf("ProcessWithVoidCallback(NULL): %d\n", void_callback_result);
// Test NoParamNames - function with unnamed parameters
int32_t no_names_result = NoParamNames(5, 10, 0);
assert(no_names_result == 789); // Returns fixed value 789
printf("NoParamNames: %d\n", no_names_result);
// Test XType from c package - create GoString for name parameter
GoString xname = {"test_x", 6}; // name and length
C_XType xtype = CreateXType(42, xname, 3.14, 1); // 1 for true
printf("XType: %d %f %d\n", xtype.ID, xtype.Value, xtype.Flag);
C_XType processedX = ProcessXType(xtype);
printf("Processed XType: %d %f %d\n", processedX.ID, processedX.Value, processedX.Flag);
C_XType* ptrX = ProcessXTypePtr(&xtype);
if (ptrX != NULL) {
printf("Ptr XType: %d %f %d\n", ptrX->ID, ptrX->Value, ptrX->Flag);
}
// Test multidimensional arrays
printf("\n=== Multidimensional Array Tests ===\n");
// Create and test 2D matrix [3][4]
// Note: CreateMatrix2D returns [3][4]int32, but function returns need special handling in C
printf("Testing 2D matrix functions...\n");
// Create a test 2D matrix [3][4]int32
int32_t test_matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int32_t matrix_sum = ProcessMatrix2D(test_matrix);
assert(matrix_sum == 78); // Sum of 1+2+3+...+12 = 78
printf("Matrix2D sum: %d\n", matrix_sum);
// Create a test 3D cube [2][3][4]uint8
uint8_t test_cube[2][3][4];
uint8_t val = 1;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
test_cube[i][j][k] = val++;
}
}
}
uint32_t cube_sum = ProcessMatrix3D(test_cube);
assert(cube_sum == 300); // Sum of 1+2+3+...+24 = 300
printf("Matrix3D (cube) sum: %u\n", cube_sum);
// Create a test 5x4 grid [5][4]double
double test_grid[5][4];
double grid_val = 1.0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
test_grid[i][j] = grid_val;
grid_val += 0.5;
}
}
double grid_sum = ProcessGrid5x4(test_grid);
assert(grid_sum == 115.0); // Sum of 1.0+1.5+2.0+...+10.5 = 115.0
printf("Grid5x4 sum: %f\n", grid_sum);
// Test functions that return multidimensional arrays (as multi-level pointers)
printf("\n=== Testing Return Value Functions ===\n");
// Test CreateMatrix1D() which returns Array_int32_t_4
printf("About to call CreateMatrix1D()...\n");
fflush(stdout);
Array_int32_t_4 matrix1d = CreateMatrix1D();
printf("CreateMatrix1D() call completed\n");
printf("CreateMatrix1D() returned struct, first element: %d\n", matrix1d.data[0]);
// Test CreateMatrix2D() which returns Array_int32_t_3_4
printf("About to call CreateMatrix2D()...\n");
fflush(stdout);
Array_int32_t_3_4 matrix2d = CreateMatrix2D();
printf("CreateMatrix2D() call completed\n");
printf("CreateMatrix2D() returned struct, first element: %d\n", matrix2d.data[0][0]);
// Test CreateMatrix3D() which returns Array_uint8_t_2_3_4
Array_uint8_t_2_3_4 cube = CreateMatrix3D();
printf("CreateMatrix3D() returned struct, first element: %u\n", cube.data[0][0][0]);
// Test CreateGrid5x4() which returns Array_double_5_4
Array_double_5_4 grid = CreateGrid5x4();
printf("CreateGrid5x4() returned struct, first element: %f\n", grid.data[0][0]);
// Test NoReturn function
// Note: This function takes a string parameter which is complex to pass from C
// We'll skip it for now or pass a simple string if the binding allows
printf("NoReturn test skipped (string parameter)\n");
printf("C demo completed!\n");
return 0;
}

View File

@@ -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]

View File

@@ -1,3 +0,0 @@
module github.com/goplus/llgo/_demo/go
go 1.20

View File

View File

@@ -1,85 +0,0 @@
package main
// Tests of interface conversions and type assertions.
type I0 interface {
}
type I1 interface {
f()
}
type I2 interface {
f()
g()
}
type C0 struct{}
type C1 struct{}
func (C1) f() {}
type C2 struct{}
func (C2) f() {}
func (C2) g() {}
func main() {
var i0 I0
var i1 I1
var i2 I2
// Nil always causes a type assertion to fail, even to the
// same type.
if _, ok := i0.(I0); ok {
panic("nil i0.(I0) succeeded")
}
if _, ok := i1.(I1); ok {
panic("nil i1.(I1) succeeded")
}
if _, ok := i2.(I2); ok {
panic("nil i2.(I2) succeeded")
}
// Conversions can't fail, even with nil.
_ = I0(i0)
_ = I0(i1)
_ = I1(i1)
_ = I0(i2)
_ = I1(i2)
_ = I2(i2)
// Non-nil type assertions pass or fail based on the concrete type.
i1 = C1{}
if _, ok := i1.(I0); !ok {
panic("C1 i1.(I0) failed")
}
if _, ok := i1.(I1); !ok {
panic("C1 i1.(I1) failed")
}
if _, ok := i1.(I2); ok {
panic("C1 i1.(I2) succeeded")
}
i1 = C2{}
if _, ok := i1.(I0); !ok {
panic("C2 i1.(I0) failed")
}
if _, ok := i1.(I1); !ok {
panic("C2 i1.(I1) failed")
}
if _, ok := i1.(I2); !ok {
panic("C2 i1.(I2) failed")
}
// Conversions can't fail.
i1 = C1{}
if I0(i1) == nil {
panic("C1 I0(i1) was nil")
}
if I1(i1) == nil {
panic("C1 I1(i1) was nil")
}
println("pass")
}

View File

@@ -1,124 +0,0 @@
package main
import (
"fmt"
"hash/maphash"
)
func main() {
testHashBasics()
testMakeSeed()
testSetSeed()
testWriteMethods()
testBytes()
testString()
}
func testHashBasics() {
fmt.Println("=== Test Hash Basics ===")
var h maphash.Hash
n, err := h.WriteString("hello")
if err != nil {
panic(fmt.Sprintf("WriteString failed: %v", err))
}
if n != 5 {
panic(fmt.Sprintf("WriteString returned %d, expected 5", n))
}
hash1 := h.Sum64()
fmt.Printf("Hash of 'hello': 0x%x\n", hash1)
h.Reset()
n, err = h.WriteString("world")
if err != nil {
panic(fmt.Sprintf("WriteString failed: %v", err))
}
hash2 := h.Sum64()
fmt.Printf("Hash of 'world': 0x%x\n", hash2)
h.Reset()
n, err = h.WriteString("hello")
if err != nil {
panic(fmt.Sprintf("WriteString failed: %v", err))
}
hash3 := h.Sum64()
if hash1 != hash3 {
panic(fmt.Sprintf("Hash mismatch: 0x%x != 0x%x", hash1, hash3))
}
fmt.Printf("Hash consistency verified: 0x%x == 0x%x\n", hash1, hash3)
}
func testMakeSeed() {
fmt.Println("\n=== Test MakeSeed ===")
seed1 := maphash.MakeSeed()
seed2 := maphash.MakeSeed()
fmt.Printf("Seed 1: %v\n", seed1)
fmt.Printf("Seed 2: %v\n", seed2)
if seed1 == seed2 {
fmt.Println("Warning: Seeds are identical (rare but possible)")
}
}
func testSetSeed() {
fmt.Println("\n=== Test SetSeed ===")
var h1, h2 maphash.Hash
seed := maphash.MakeSeed()
h1.SetSeed(seed)
_, err := h1.WriteString("test")
if err != nil {
panic(fmt.Sprintf("WriteString failed: %v", err))
}
hash1 := h1.Sum64()
h2.SetSeed(seed)
_, err = h2.WriteString("test")
if err != nil {
panic(fmt.Sprintf("WriteString failed: %v", err))
}
hash2 := h2.Sum64()
if hash1 != hash2 {
panic(fmt.Sprintf("Hashes with same seed should match: 0x%x != 0x%x", hash1, hash2))
}
fmt.Printf("Same seed produces same hash: 0x%x == 0x%x\n", hash1, hash2)
}
func testWriteMethods() {
fmt.Println("\n=== Test Write Methods ===")
var h maphash.Hash
data := []byte("hello")
n, err := h.Write(data)
if err != nil {
panic(fmt.Sprintf("Write failed: %v", err))
}
if n != len(data) {
panic(fmt.Sprintf("Write returned %d, expected %d", n, len(data)))
}
hash1 := h.Sum64()
fmt.Printf("Hash after Write: 0x%x\n", hash1)
h.Reset()
err = h.WriteByte('A')
if err != nil {
panic(fmt.Sprintf("WriteByte failed: %v", err))
}
hash2 := h.Sum64()
fmt.Printf("Hash after WriteByte('A'): 0x%x\n", hash2)
}
func testBytes() {
fmt.Println("\n=== Test Bytes Function ===")
seed := maphash.MakeSeed()
data := []byte("test data")
hash := maphash.Bytes(seed, data)
fmt.Printf("Bytes hash: 0x%x\n", hash)
}
func testString() {
fmt.Println("\n=== Test String Function ===")
seed := maphash.MakeSeed()
str := "test string"
hash := maphash.String(seed, str)
fmt.Printf("String hash: 0x%x\n", hash)
}

View File

@@ -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
*/

View File

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

View File

@@ -1,29 +0,0 @@
package main
import (
"fmt"
"os"
)
func main() {
entries, err := os.ReadDir("../")
if err != nil {
panic(err)
}
if len(entries) == 0 {
panic("No files found")
}
var check int
for _, e := range entries {
fmt.Printf("%s isDir[%t]\n", e.Name(), e.IsDir())
if !e.IsDir() {
switch e.Name() {
case "go.sum", "go.mod":
check++
}
}
}
if check != 2 {
panic("Bad readdir entries go.mod/go.sum")
}
}

View File

@@ -1,50 +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))
}
}
v := reflect.ValueOf(T{})
if v.Field(0).Kind() != reflect.Func {
panic("must func")
}
}
type T struct {
fn func(int)
}

View File

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

View File

@@ -1,40 +0,0 @@
//go:build go1.23
package main
import "unique"
func main() {
var h1 = unique.Make(int(42))
var h2 = unique.Make(int(42))
if h1 != h2 {
panic("h1 and h2 should be equal")
}
var v1 = h1.Value()
var v2 = h2.Value()
if v1 != v2 || v1 != 42 {
panic("values should be equal to 42")
}
var h3 = unique.Make("hello")
var h4 = unique.Make("hello")
if h3 != h4 {
panic("h3 and h4 should be equal")
}
var s1 = h3.Value()
var s2 = h4.Value()
if s1 != s2 || s1 != "hello" {
panic("values should be equal to 'hello'")
}
var h5 = unique.Make(int(100))
var h6 = unique.Make(int(200))
if h5 == h6 {
panic("h5 and h6 should not be equal")
}
var n1 = h5.Value()
var n2 = h6.Value()
if n1 != 100 || n2 != 200 {
panic("values should be 100 and 200 respectively")
}
}

Some files were not shown because too many files have changed in this diff Show More