Compare commits
29 Commits
xgopilot/c
...
async
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee0e0a5c51 | ||
|
|
7b2747ce0c | ||
|
|
578bc165c4 | ||
|
|
a1d46e905b | ||
|
|
9102ca6b1e | ||
|
|
835d6fee1e | ||
|
|
294abb5126 | ||
|
|
5fca8ebd4e | ||
|
|
d3df782fca | ||
|
|
b04ac8df30 | ||
|
|
bb03df7059 | ||
|
|
98072f3f4b | ||
|
|
3bf0780a67 | ||
|
|
a1fdc05e26 | ||
|
|
93bff83e3d | ||
|
|
e470bc2069 | ||
|
|
efa771f3ff | ||
|
|
806193fc6e | ||
|
|
cdfa0166bd | ||
|
|
0687efaec6 | ||
|
|
0d3e78ad94 | ||
|
|
375b2b579e | ||
|
|
a578155dcb | ||
|
|
df5f1afb74 | ||
|
|
b2a2b2f29d | ||
|
|
91df9957f5 | ||
|
|
08e0ace9a2 | ||
|
|
a4286dbd4b | ||
|
|
f2e15a6846 |
72
.github/actions/setup-deps/action.yml
vendored
72
.github/actions/setup-deps/action.yml
vendored
@@ -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[@]}"
|
|
||||||
|
|
||||||
51
.github/actions/setup-go/action.yml
vendored
51
.github/actions/setup-go/action.yml
vendored
@@ -1,51 +0,0 @@
|
|||||||
name: "Setup Go"
|
|
||||||
description: "Setup Go environment by downloading and extracting from go.dev"
|
|
||||||
inputs:
|
|
||||||
go-version:
|
|
||||||
description: "The Go version to download and use"
|
|
||||||
required: true
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Download and setup Go
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -e
|
|
||||||
GO_VERSION="${{ inputs.go-version }}"
|
|
||||||
GO_VERSION="${GO_VERSION#go}" # Remove 'go' prefix if present
|
|
||||||
|
|
||||||
# Determine OS and architecture
|
|
||||||
if [[ "$RUNNER_OS" == "macOS" ]]; then
|
|
||||||
OS="darwin"
|
|
||||||
ARCH="arm64"
|
|
||||||
else
|
|
||||||
OS="linux"
|
|
||||||
ARCH="amd64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
DOWNLOAD_URL="https://go.dev/dl/go${GO_VERSION}.${OS}-${ARCH}.tar.gz"
|
|
||||||
echo "Downloading Go from: ${DOWNLOAD_URL}"
|
|
||||||
|
|
||||||
# Create temporary directory for download
|
|
||||||
TMP_DIR=$(mktemp -d)
|
|
||||||
curl -L "${DOWNLOAD_URL}" -o "${TMP_DIR}/go.tar.gz"
|
|
||||||
|
|
||||||
# Remove existing Go installation if any
|
|
||||||
sudo rm -rf /usr/local/go
|
|
||||||
|
|
||||||
# Extract to /usr/local
|
|
||||||
sudo tar -C /usr/local -xzf "${TMP_DIR}/go.tar.gz"
|
|
||||||
|
|
||||||
# Clean up
|
|
||||||
rm -rf "${TMP_DIR}"
|
|
||||||
|
|
||||||
# Add to PATH
|
|
||||||
echo "/usr/local/go/bin" >> $GITHUB_PATH
|
|
||||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Verify Go installation
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Verify installation
|
|
||||||
echo "Verifying Go installation..."
|
|
||||||
go version
|
|
||||||
28
.github/actions/setup-goreleaser/action.yml
vendored
28
.github/actions/setup-goreleaser/action.yml
vendored
@@ -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
|
|
||||||
63
.github/actions/test-helloworld/action.yml
vendored
63
.github/actions/test-helloworld/action.yml
vendored
@@ -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
15
.github/codecov.yml
vendored
@@ -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"
|
|
||||||
180
.github/workflows/doc.yml
vendored
180
.github/workflows/doc.yml
vendored
@@ -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
|
|
||||||
67
.github/workflows/download_esp_clang.sh
vendored
67
.github/workflows/download_esp_clang.sh
vendored
@@ -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!"
|
|
||||||
38
.github/workflows/fmt.yml
vendored
38
.github/workflows/fmt.yml
vendored
@@ -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."
|
|
||||||
101
.github/workflows/go.yml
vendored
101
.github/workflows/go.yml
vendored
@@ -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
|
||||||
|
|||||||
300
.github/workflows/llgo.yml
vendored
300
.github/workflows/llgo.yml
vendored
@@ -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
40
.github/workflows/populate_darwin_sysroot.sh
vendored
Executable 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
|
||||||
18
.github/workflows/populate_linux_sysroot.sh
vendored
18
.github/workflows/populate_linux_sysroot.sh
vendored
@@ -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 $?
|
|
||||||
|
|||||||
213
.github/workflows/release-build.yml
vendored
213
.github/workflows/release-build.yml
vendored
@@ -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
|
||||||
|
|||||||
48
.github/workflows/targets.yml
vendored
48
.github/workflows/targets.yml
vendored
@@ -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
|
|
||||||
8
.github/workflows/test_demo.sh
vendored
8
.github/workflows/test_demo.sh
vendored
@@ -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
36
.github/workflows/test_llgo.sh
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
testcmd=/tmp/test
|
||||||
|
llgo build -o $testcmd ./c/bdwgc/_test
|
||||||
|
cases=$($testcmd)
|
||||||
|
total=$(echo "$cases" | wc -l | tr -d ' ')
|
||||||
|
failed=0
|
||||||
|
failed_cases=""
|
||||||
|
|
||||||
|
for idx in $(seq 1 $((total))); do
|
||||||
|
case=$(echo "$cases" | sed -n "${idx}p")
|
||||||
|
case_name=$(echo "$case" | cut -d',' -f2)
|
||||||
|
echo "=== Test case: $case_name"
|
||||||
|
set +e
|
||||||
|
out=$("$testcmd" "$((idx-1))" 2>&1)
|
||||||
|
exit_code=$?
|
||||||
|
set -e
|
||||||
|
if [ "${exit_code:-0}" -ne 0 ]; then
|
||||||
|
echo "failed: $out"
|
||||||
|
failed=$((failed+1))
|
||||||
|
failed_cases="$failed_cases\n* :x: $case_name"
|
||||||
|
else
|
||||||
|
echo "passed"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "=== Done"
|
||||||
|
echo "$((total-failed))/$total tests passed"
|
||||||
|
|
||||||
|
if [ "$failed" -ne 0 ]; then
|
||||||
|
echo ":bangbang: Failed llgo cases:" | tee -a result.md
|
||||||
|
echo -e "$failed_cases" | tee -a result.md
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo ":white_check_mark: All llgo tests passed" | tee -a result.md
|
||||||
|
fi
|
||||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -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
3
.gitmodules
vendored
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "c/llama2/llama2.c"]
|
||||||
|
path = c/llama2/llama2.c
|
||||||
|
url = https://github.com/karpathy/llama2.c.git
|
||||||
|
|||||||
@@ -17,69 +17,65 @@ before:
|
|||||||
builds:
|
builds:
|
||||||
- id: llgo-darwin-amd64
|
- id: llgo-darwin-amd64
|
||||||
main: ./cmd/llgo
|
main: ./cmd/llgo
|
||||||
binary: bin/llgo
|
|
||||||
flags:
|
flags:
|
||||||
- -tags=darwin,amd64,byollvm
|
- -tags=darwin,amd64,byollvm
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}}
|
- -X github.com/goplus/llgo/x/env.buildVersion=v{{.Version}}
|
||||||
- -X github.com/goplus/llgo/internal/env.buildTime={{.Date}}
|
- -X github.com/goplus/llgo/x/env.buildTime={{.Date}}
|
||||||
|
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@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
132
CLAUDE.md
@@ -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
235
README.md
@@ -6,11 +6,11 @@ llgo - A Go compiler based on LLVM
|
|||||||
[](https://github.com/goplus/llgo/releases)
|
[](https://github.com/goplus/llgo/releases)
|
||||||
[](https://codecov.io/gh/goplus/llgo)
|
[](https://codecov.io/gh/goplus/llgo)
|
||||||
[](https://pkg.go.dev/github.com/goplus/llgo)
|
[](https://pkg.go.dev/github.com/goplus/llgo)
|
||||||
[](https://github.com/goplus/gop)
|
[](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`.
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fib() {
|
func main() {
|
||||||
// Initialize two big ints with the first two numbers in the sequence.
|
// Initialize two big ints with the first two numbers in the sequence.
|
||||||
a := big.NewInt(0)
|
a := big.NewInt(0)
|
||||||
b := big.NewInt(1)
|
b := big.NewInt(1)
|
||||||
@@ -23,41 +23,3 @@ func fib() {
|
|||||||
}
|
}
|
||||||
fmt.Println(a) // 100-digit Fibonacci number
|
fmt.Println(a) // 100-digit Fibonacci number
|
||||||
}
|
}
|
||||||
|
|
||||||
func abs() {
|
|
||||||
a := big.NewInt(64)
|
|
||||||
b := big.NewInt(-52)
|
|
||||||
a.Set(b)
|
|
||||||
a.Abs(a)
|
|
||||||
a.Set(big.NewInt(-164))
|
|
||||||
a.Abs(a)
|
|
||||||
fmt.Println("value: ", a.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func neg() {
|
|
||||||
fmt.Println("value: ", big.NewInt(-64).Neg(big.NewInt(-64)))
|
|
||||||
fmt.Println("value: ", big.NewInt(64).Neg(big.NewInt(64)))
|
|
||||||
fmt.Println("value: ", big.NewInt(0).Neg(big.NewInt(0)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func calc() {
|
|
||||||
a := big.NewInt(64)
|
|
||||||
b := big.NewInt(-52)
|
|
||||||
c := big.NewInt(54)
|
|
||||||
fmt.Println("value:", a.Add(a, b))
|
|
||||||
fmt.Println("value:", a.Sub(b, c))
|
|
||||||
d := big.NewInt(10)
|
|
||||||
e := big.NewInt(4)
|
|
||||||
fmt.Println("value:", d.Mul(d, e))
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitop() {
|
|
||||||
a := big.NewInt(4)
|
|
||||||
fmt.Println("value:", a.Lsh(a, 1))
|
|
||||||
b := big.NewInt(16)
|
|
||||||
fmt.Println("value:", b.Rsh(b, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
bitop()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha1"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
h := hmac.New(sha1.New, []byte("<key>"))
|
|
||||||
io.WriteString(h, "The fog is getting thicker!")
|
|
||||||
io.WriteString(h, "And Leon's getting laaarger!")
|
|
||||||
fmt.Printf("%x", h.Sum(nil))
|
|
||||||
}
|
|
||||||
@@ -1,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
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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))
|
|
||||||
}
|
|
||||||
@@ -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))
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -DBAR
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "foo.h"
|
|
||||||
static void foo(Foo* f) {
|
|
||||||
printf("foo in bar: %d\n", f->a);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Bar(f *C.Foo) {
|
|
||||||
C.print_foo(f)
|
|
||||||
C.foo(f)
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo windows,!amd64 CFLAGS: -D_WIN32
|
|
||||||
#cgo !windows CFLAGS: -D_POSIX
|
|
||||||
#cgo windows,amd64 CFLAGS: -D_WIN64
|
|
||||||
#cgo linux,amd64 CFLAGS: -D_LINUX64
|
|
||||||
#cgo !windows,amd64 CFLAGS: -D_UNIX64
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <Python.h>
|
|
||||||
#include "foo.h"
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
} s4;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
} s8;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
} s12;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
int d;
|
|
||||||
} s16;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
int d;
|
|
||||||
int e;
|
|
||||||
} s20;
|
|
||||||
|
|
||||||
static int test_structs(s4* s4, s8* s8, s12* s12, s16* s16, s20* s20) {
|
|
||||||
printf("s4.a: %d\n", s4->a);
|
|
||||||
printf("s8.a: %d, s8.b: %d\n", s8->a, s8->b);
|
|
||||||
printf("s12.a: %d, s12.b: %d, s12.c: %d\n", s12->a, s12->b, s12->c);
|
|
||||||
printf("s16.a: %d, s16.b: %d, s16.c: %d, s16.d: %d\n", s16->a, s16->b, s16->c, s16->d);
|
|
||||||
printf("s20.a: %d, s20.b: %d, s20.c: %d, s20.d: %d, s20.e: %d\n", s20->a, s20->b, s20->c, s20->d, s20->e);
|
|
||||||
|
|
||||||
return s4->a + s8->a + s8->b + s12->a + s12->b + s12->c + s16->a + s16->b + s16->c + s16->d + s20->a + s20->b + s20->c + s20->d + s20->e;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_macros() {
|
|
||||||
#ifdef FOO
|
|
||||||
printf("FOO is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef BAR
|
|
||||||
printf("BAR is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
printf("WIN32 is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _POSIX
|
|
||||||
printf("POSIX is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN64
|
|
||||||
printf("WIN64 is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _LINUX64
|
|
||||||
printf("LINUX64 is defined\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _UNIX64
|
|
||||||
printf("UNIX64 is defined\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MY_VERSION "1.0.0"
|
|
||||||
#define MY_CODE 0x12345678
|
|
||||||
|
|
||||||
static void test_void() {
|
|
||||||
printf("test_void\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int (*Cb)(int);
|
|
||||||
|
|
||||||
extern int go_callback(int);
|
|
||||||
|
|
||||||
extern int c_callback(int i);
|
|
||||||
|
|
||||||
static void test_callback(Cb cb) {
|
|
||||||
printf("test_callback, cb: %p, go_callback: %p, c_callback: %p\n", cb, go_callback, c_callback);
|
|
||||||
printf("test_callback, *cb: %p, *go_callback: %p, *c_callback: %p\n", *(void**)cb, *(void**)(go_callback), *(void**)(c_callback));
|
|
||||||
printf("cb result: %d\n", cb(123));
|
|
||||||
printf("done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int go_callback_not_use_in_go(int);
|
|
||||||
|
|
||||||
static void run_callback() {
|
|
||||||
test_callback(c_callback);
|
|
||||||
test_callback(go_callback_not_use_in_go);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/_demo/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)
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "foo.h"
|
|
||||||
|
|
||||||
void print_foo(Foo *f)
|
|
||||||
{
|
|
||||||
printf("print_foo: %d\n", f->a);
|
|
||||||
}
|
|
||||||
|
|
||||||
int c_callback(int i)
|
|
||||||
{
|
|
||||||
return i + 1;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -DFOO
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "foo.h"
|
|
||||||
static void foo(Foo* f) {
|
|
||||||
printf("foo in bar: %d\n", f->a);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Foo(f *C.Foo) {
|
|
||||||
C.print_foo(f)
|
|
||||||
C.foo(f)
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a;
|
|
||||||
} Foo;
|
|
||||||
|
|
||||||
extern void print_foo(Foo* f);
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <Python.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func Initialize() {
|
|
||||||
C.Py_Initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Finalize() {
|
|
||||||
C.Py_Finalize()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run(code string) error {
|
|
||||||
if C.PyRun_SimpleString(C.CString(code)) != 0 {
|
|
||||||
C.PyErr_Print()
|
|
||||||
return fmt.Errorf("failed to run code")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package pymod1
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <Python.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Float(f float64) *C.PyObject {
|
|
||||||
return C.PyFloat_FromDouble(C.double(f))
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package pymod2
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: python3-embed
|
|
||||||
#include <Python.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func Long(l int64) *C.PyObject {
|
|
||||||
return C.PyLong_FromLongLong(C.longlong(l))
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module github.com/goplus/llgo/_demo/c
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require github.com/goplus/lib v0.3.0
|
|
||||||
@@ -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=
|
|
||||||
@@ -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"))
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
c.Printf(c.Str("Hello world by c.Printf\n"))
|
|
||||||
c.Printf(c.Str("%ld\n"), unsafe.Sizeof(int(0)))
|
|
||||||
c.Printf(c.Str("%ld\n"), unsafe.Sizeof(uintptr(0)))
|
|
||||||
// var v any = int(0)
|
|
||||||
// c.Printf(c.Str("%ld\n"), unsafe.Sizeof(v))
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
llsync "github.com/goplus/lib/c/pthread/sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type L struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
s string
|
|
||||||
i int
|
|
||||||
w io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
l := &L{s: "hello", i: 123, w: os.Stdout}
|
|
||||||
println("sizeof(L):", unsafe.Sizeof(L{}))
|
|
||||||
println("sizeof(sync.Mutex):", unsafe.Sizeof(sync.Mutex{}))
|
|
||||||
println("sizeof(llsync.Mutex):", unsafe.Sizeof(llsync.Mutex{}))
|
|
||||||
println("l:", l, "l.s:", l.s, "l.i:", l.i, "l.w:", l.w)
|
|
||||||
l.mu.Lock()
|
|
||||||
println("locked")
|
|
||||||
println("l:", l, "l.s:", l.s, "l.i:", l.i, "l.w:", l.w)
|
|
||||||
l.w.Write([]byte(l.s))
|
|
||||||
l.w.Write([]byte("\n"))
|
|
||||||
l.mu.Unlock()
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c/sync/atomic"
|
"github.com/goplus/llgo/c/sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/runtime/internal/runtime"
|
"github.com/goplus/llgo/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/runtime/internal/runtime"
|
"github.com/goplus/llgo/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/os"
|
"github.com/goplus/llgo/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
func concat(args ...string) (ret string) {
|
func concat(args ...string) (ret string) {
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/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 {
|
||||||
@@ -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 {
|
||||||
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/math/rand"
|
"github.com/goplus/llgo/c/math/rand"
|
||||||
"github.com/goplus/lib/c/time"
|
"github.com/goplus/llgo/c/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fastrand64() uint64 {
|
func fastrand64() uint64 {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/goplus/lib/c/time"
|
import "github.com/goplus/llgo/c/time"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var tv time.Timespec
|
var tv time.Timespec
|
||||||
@@ -1,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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
@@ -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!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module github.com/goplus/llgo/_demo/embed
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require github.com/goplus/lib v0.3.0
|
|
||||||
@@ -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=
|
|
||||||
@@ -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) {
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import _ "github.com/goplus/llgo/_demo/embed/targetsbuild/C"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/c/os"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/lib/c"
|
|
||||||
"github.com/goplus/lib/c/os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -46,6 +45,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
c.Printf(c.Str("set file status successfully\n"))
|
c.Printf(c.Str("set file status successfully\n"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
c.Printf(c.Str("111"))
|
c.Printf(c.Str("111"))
|
||||||
// Close file
|
// Close file
|
||||||
os.Close(fd)
|
os.Close(fd)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
type generator struct {
|
type generator struct {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/lib/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/lib/c/os"
|
"github.com/goplus/llgo/c/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package async
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Void = [0]byte
|
|
||||||
|
|
||||||
type Future[T any] interface {
|
|
||||||
Then(cb func(T))
|
|
||||||
}
|
|
||||||
|
|
||||||
type future[T any] struct {
|
|
||||||
cb func(func(T))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *future[T]) Then(cb func(T)) {
|
|
||||||
f.cb(cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Async[T any](fn func(func(T))) Future[T] {
|
|
||||||
return &future[T]{fn}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run[T any](future Future[T]) T {
|
|
||||||
var ret T
|
|
||||||
future.Then(func(v T) {
|
|
||||||
ret = v
|
|
||||||
})
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/_demo/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{})
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -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{})
|
|
||||||
}()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tempDir := os.TempDir()
|
|
||||||
noexist := filepath.Join(tempDir, "noexist.txt")
|
|
||||||
|
|
||||||
if _, err := os.Stat(noexist); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
fmt.Println("noexist:", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println("exist,other err:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Open(noexist); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
fmt.Println("noexist:", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println("exist,other err:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,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())
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var a int = 5
|
|
||||||
defer println(a)
|
|
||||||
defer func() {
|
|
||||||
println(a)
|
|
||||||
}()
|
|
||||||
defer func() {
|
|
||||||
println(recover().(string))
|
|
||||||
}()
|
|
||||||
a = 10
|
|
||||||
panic("error")
|
|
||||||
//Output:
|
|
||||||
// error
|
|
||||||
// 10
|
|
||||||
// 5
|
|
||||||
}
|
|
||||||
1
_demo/go/export/.gitignore
vendored
1
_demo/go/export/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
libexport.h
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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")
|
|
||||||
}
|
|
||||||
@@ -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_ */
|
|
||||||
@@ -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!"
|
|
||||||
@@ -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"
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MyStruct[T any] struct {
|
|
||||||
value T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MyStruct[T]) Method() {
|
|
||||||
fmt.Println("In generic method")
|
|
||||||
genericFunc[T](m.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func genericFunc[T any](v T) {
|
|
||||||
fmt.Println("In generic function")
|
|
||||||
normalFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalFunc() {
|
|
||||||
fmt.Println("In normal function")
|
|
||||||
panic("panic occurs here")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
m := &MyStruct[string]{value: "hello"}
|
|
||||||
m.Method()
|
|
||||||
}
|
|
||||||
|
|
||||||
//Expected:
|
|
||||||
// In generic method
|
|
||||||
// In generic function
|
|
||||||
// In normal function
|
|
||||||
// panic: panic occurs here
|
|
||||||
|
|
||||||
// [0x00C6D310 github.com/goplus/llgo/internal/runtime.Rethrow+0x2f, SP = 0x60]
|
|
||||||
// [0x00C6CF44 github.com/goplus/llgo/internal/runtime.Panic+0x2d, SP = 0x50]
|
|
||||||
// [0x00C69420 main.normalFunc+0xf, SP = 0xa8]
|
|
||||||
// [0x00C69564 main.genericFunc[string]+0x18, SP = 0x74]
|
|
||||||
// [0x00C694A8 main.(*MyStruct[string]).Method+0x1f, SP = 0x84]
|
|
||||||
// [0x00C6936C main+0x4, SP = 0x40]
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module github.com/goplus/llgo/_demo/go
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
@@ -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")
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "net/textproto"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
h := make(textproto.MIMEHeader)
|
|
||||||
h.Set("host", "www.example.com")
|
|
||||||
println(h.Get("Host"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expected output:
|
|
||||||
www.example.com
|
|
||||||
*/
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tempDir, err := os.MkdirTemp("", "example*")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to create temp directory:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(tempDir)
|
|
||||||
fmt.Println("Temp directory:", tempDir)
|
|
||||||
|
|
||||||
tempFile, err := os.CreateTemp("", "example*.txt")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to create temp file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer tempFile.Close()
|
|
||||||
defer os.Remove(tempFile.Name())
|
|
||||||
fmt.Println("Temp file:", tempFile.Name())
|
|
||||||
|
|
||||||
nestedDir := filepath.Join("nested", "directory")
|
|
||||||
err = os.MkdirAll(nestedDir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to create nested directory:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("Nest directory:", nestedDir)
|
|
||||||
}
|
|
||||||
@@ -1,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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Counter represents a thread-safe counter
|
|
||||||
type Counter struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
value int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment increases the counter value by 1
|
|
||||||
func (c *Counter) Increment() {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValue returns the current value of the counter
|
|
||||||
func (c *Counter) GetValue() int64 {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
return c.value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constant values for the test
|
|
||||||
const (
|
|
||||||
numGoroutines = 64
|
|
||||||
numIterations = 10000
|
|
||||||
expectedTotal = numGoroutines * numIterations
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Create a new counter instance
|
|
||||||
counter := &Counter{}
|
|
||||||
|
|
||||||
// Create a wait group to wait for all goroutines to finish
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
// Track active goroutines for monitoring
|
|
||||||
var activeGoroutines int32
|
|
||||||
|
|
||||||
// Start time
|
|
||||||
startTime := time.Now()
|
|
||||||
|
|
||||||
// Launch goroutines
|
|
||||||
for i := 0; i < numGoroutines; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
atomic.AddInt32(&activeGoroutines, 1)
|
|
||||||
|
|
||||||
go func(id int) {
|
|
||||||
defer func() {
|
|
||||||
wg.Done()
|
|
||||||
atomic.AddInt32(&activeGoroutines, -1)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Each goroutine increments the counter numIterations times
|
|
||||||
for j := 0; j < numIterations; j++ {
|
|
||||||
counter.Increment()
|
|
||||||
|
|
||||||
// Simulate varying workload with random sleeps
|
|
||||||
if j%100 == 0 {
|
|
||||||
time.Sleep(time.Microsecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Printf("Goroutine %d finished\n", id)
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor progress in a separate goroutine
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
active := atomic.LoadInt32(&activeGoroutines)
|
|
||||||
if active == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fmt.Printf("Active goroutines: %d\n", active)
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Wait for all goroutines to complete
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
// Calculate execution time
|
|
||||||
duration := time.Since(startTime)
|
|
||||||
|
|
||||||
// Get and verify the final result
|
|
||||||
finalValue := counter.GetValue()
|
|
||||||
fmt.Printf("\nExecution completed in: %v\n", duration)
|
|
||||||
fmt.Printf("Final counter value: %d\n", finalValue)
|
|
||||||
fmt.Printf("Expected value: %d\n", expectedTotal)
|
|
||||||
|
|
||||||
// Assert the result
|
|
||||||
if finalValue != expectedTotal {
|
|
||||||
panic(fmt.Sprintf("ERROR: Counter value mismatch! Expected %d, got %d\n",
|
|
||||||
expectedTotal, finalValue))
|
|
||||||
} else {
|
|
||||||
fmt.Printf("SUCCESS: Counter value matches expected total\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print some statistics
|
|
||||||
opsPerSecond := float64(expectedTotal) / duration.Seconds()
|
|
||||||
fmt.Printf("\nStatistics:\n")
|
|
||||||
fmt.Printf("Operations per second: %.2f\n", opsPerSecond)
|
|
||||||
fmt.Printf("Average time per operation: %.2f ns\n",
|
|
||||||
float64(duration.Nanoseconds())/float64(expectedTotal))
|
|
||||||
}
|
|
||||||
@@ -1,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
Reference in New Issue
Block a user