Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10d84a6a6b | ||
|
|
a4b4c1574b | ||
|
|
94bc39bdb2 | ||
|
|
7c93b37125 | ||
|
|
4371cc10bd | ||
|
|
eaa2628934 | ||
|
|
30e247186c | ||
|
|
2714da8d98 | ||
|
|
0ef3a7ec25 | ||
|
|
489a0069aa | ||
|
|
a257b7bdfa | ||
|
|
739cc66d0d | ||
|
|
28d944c6af | ||
|
|
19b98393a6 | ||
|
|
5a13e7400e | ||
|
|
a56129d675 | ||
|
|
0d75bbace0 | ||
|
|
29ec4a7a0e | ||
|
|
8b26c48d9b | ||
|
|
ddd0535d30 | ||
|
|
adcd370c27 | ||
|
|
dbead0d725 | ||
|
|
207aea813b | ||
|
|
7a771154a7 | ||
|
|
18c6b9b404 | ||
|
|
3110382d88 | ||
|
|
9ee55896e3 | ||
|
|
ad6f41f312 | ||
|
|
8512395985 | ||
|
|
7284042823 | ||
|
|
0ef683bba9 | ||
|
|
d4bf66936a | ||
|
|
be4737461a | ||
|
|
0d22b3be05 | ||
|
|
7c81d9293b | ||
|
|
d1dce65313 | ||
|
|
641f9bbf7c | ||
|
|
be0e42cf82 | ||
|
|
3a883b8821 | ||
|
|
4bbc58d62d | ||
|
|
5f4b09bede | ||
|
|
f0ade21155 | ||
|
|
f35063ee6e | ||
|
|
e6c7627ee8 | ||
|
|
a85d937482 | ||
|
|
b17632a352 |
4
.github/actions/setup-deps/action.yml
vendored
4
.github/actions/setup-deps/action.yml
vendored
@@ -15,7 +15,7 @@ runs:
|
||||
run: |
|
||||
brew update
|
||||
brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} bdw-gc openssl libffi libuv
|
||||
brew link --overwrite lld@${{inputs.llvm-version}} libffi
|
||||
brew link --overwrite llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} libffi
|
||||
echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH
|
||||
|
||||
# Install optional deps for demos.
|
||||
@@ -35,7 +35,7 @@ runs:
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y llvm-${{inputs.llvm-version}}-dev clang-${{inputs.llvm-version}} libclang-${{inputs.llvm-version}}-dev lld-${{inputs.llvm-version}} pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libunwind-dev libuv1-dev
|
||||
echo "/usr/lib/llvm-${{inputs.llvm-version}}/bin" >> $GITHUB_PATH
|
||||
echo "PATH=/usr/lib/llvm-${{inputs.llvm-version}}/bin:$PATH" >> $GITHUB_ENV
|
||||
|
||||
# Install optional deps for demos.
|
||||
#
|
||||
|
||||
9
.github/workflows/doc.yml
vendored
9
.github/workflows/doc.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
node-version: "20"
|
||||
|
||||
- name: Install embedme
|
||||
run: npm install -g embedme
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: '1.23.6'
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Install dependencies on macOS
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: "1.23"
|
||||
|
||||
- name: Install dependencies on macOS
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
@@ -130,7 +130,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: "1.23"
|
||||
|
||||
- name: Install dependencies on macOS
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
@@ -145,6 +145,7 @@ jobs:
|
||||
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: |
|
||||
|
||||
2
.github/workflows/fmt.yml
vendored
2
.github/workflows/fmt.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: '1.24.0'
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Check formatting
|
||||
run: |
|
||||
|
||||
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: "1.24.0"
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
60
.github/workflows/llgo.yml
vendored
60
.github/workflows/llgo.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- macos-latest
|
||||
- ubuntu-24.04
|
||||
llvm: [19]
|
||||
go: ['1.21.13', '1.22.12', '1.23.6', '1.24.0']
|
||||
go: ["1.21.13", "1.22.12", "1.23.6", "1.24.2"]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
- name: Set up Go for build
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: "1.24.0"
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
- macos-latest
|
||||
- ubuntu-24.04
|
||||
llvm: [19]
|
||||
go: ["1.24.0"]
|
||||
go: ["1.24.2"]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
- name: Set up Go for build
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: "1.24.0"
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, macos-latest]
|
||||
llvm: [19]
|
||||
go: ['1.21.13', '1.22.12', '1.23.6', '1.24.0']
|
||||
go: ["1.21.13", "1.22.12", "1.23.6", "1.24.2"]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -158,7 +158,7 @@ jobs:
|
||||
- name: Set up Go 1.23 for building llgo
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: "1.24.0"
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Install llgo
|
||||
run: |
|
||||
@@ -197,3 +197,51 @@ jobs:
|
||||
with:
|
||||
go-version: ${{matrix.go}}
|
||||
mod-version: "1.24"
|
||||
|
||||
cross-compile:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest]
|
||||
llvm: [19]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/setup-deps
|
||||
with:
|
||||
llvm-version: ${{matrix.llvm}}
|
||||
|
||||
- name: Set up Go for building llgo
|
||||
uses: ./.github/actions/setup-go
|
||||
with:
|
||||
go-version: "1.24.2"
|
||||
|
||||
- name: Install wamr
|
||||
run: |
|
||||
git clone https://github.com/bytecodealliance/wasm-micro-runtime.git
|
||||
mkdir wasm-micro-runtime/product-mini/platforms/darwin/build
|
||||
cd wasm-micro-runtime/product-mini/platforms/darwin/build
|
||||
cmake -D WAMR_BUILD_EXCE_HANDLING=1 -D WAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_SHARED_MEMORY=1 -DWAMR_BUILD_LIB_WASI_THREADS=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_DEBUG_INTERP=1 ..
|
||||
make -j8
|
||||
echo "$PWD" >> $GITHUB_PATH
|
||||
|
||||
- name: Install llgo
|
||||
run: |
|
||||
go install ./...
|
||||
echo "LLGO_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||
|
||||
- name: Test Cross Compilation (wasm)
|
||||
shell: bash
|
||||
working-directory: _demo
|
||||
run: |
|
||||
echo "Testing cross-compilation wasm with Go 1.24.2"
|
||||
|
||||
# Compile for wasm architecture
|
||||
GOOS=wasip1 GOARCH=wasm llgo build -o hello -tags=nogc -v ./helloc
|
||||
|
||||
# Check file type
|
||||
file hello.wasm
|
||||
|
||||
# Run the wasm binary using llgo_wasm
|
||||
iwasm --stack-size=819200000 --heap-size=800000000 hello.wasm
|
||||
|
||||
@@ -361,7 +361,7 @@ Follow these steps to generate the `llgo` command (its usage is the same as the
|
||||
brew update
|
||||
brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config
|
||||
brew install python@3.12 # optional
|
||||
brew link --overwrite lld@19 libffi
|
||||
brew link --overwrite llvm@19 lld@19 libffi
|
||||
# curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash
|
||||
./install.sh
|
||||
```
|
||||
|
||||
@@ -2,4 +2,4 @@ module github.com/goplus/llgo/_demo
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/goplus/lib v0.1.0
|
||||
require github.com/goplus/lib v0.2.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
|
||||
15
_demo/helloc/helloc.go
Normal file
15
_demo/helloc/helloc.go
Normal file
@@ -0,0 +1,15 @@
|
||||
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))
|
||||
}
|
||||
@@ -2,4 +2,4 @@ module github.com/goplus/llgo/_pydemo
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/goplus/lib v0.1.0
|
||||
require github.com/goplus/lib v0.2.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
|
||||
@@ -2,4 +2,4 @@ module github.com/goplus/llgo/_xtool
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/goplus/lib v0.1.0
|
||||
require github.com/goplus/lib v0.2.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
|
||||
@@ -8,7 +8,7 @@ source_filename = "github.com/goplus/llgo/cl/_testdata/vargs"
|
||||
@"github.com/goplus/llgo/cl/_testdata/vargs.init$guard" = global i1 false, align 1
|
||||
@_llgo_int = linkonce global ptr null, align 8
|
||||
@0 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
|
||||
@1 = private unnamed_addr constant [40 x i8] c"type assertion interface{} -> int failed", align 1
|
||||
@1 = private unnamed_addr constant [32 x i8] c"type assertion any -> int failed", align 1
|
||||
@_llgo_string = linkonce global ptr null, align 8
|
||||
|
||||
define void @"github.com/goplus/llgo/cl/_testdata/vargs.init"() {
|
||||
@@ -87,7 +87,7 @@ _llgo_4: ; preds = %_llgo_2
|
||||
_llgo_5: ; preds = %_llgo_2
|
||||
%18 = load ptr, ptr @_llgo_string, align 8
|
||||
%19 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 40 }, ptr %19, align 8
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 32 }, ptr %19, align 8
|
||||
%20 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %18, 0
|
||||
%21 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %20, ptr %19, 1
|
||||
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %21)
|
||||
|
||||
@@ -7,10 +7,10 @@ source_filename = "github.com/goplus/llgo/cl/_testrt/any"
|
||||
@"github.com/goplus/llgo/cl/_testrt/any.init$guard" = global i1 false, align 1
|
||||
@_llgo_int8 = linkonce global ptr null, align 8
|
||||
@"*_llgo_int8" = linkonce global ptr null, align 8
|
||||
@0 = private unnamed_addr constant [42 x i8] c"type assertion interface{} -> *int8 failed", align 1
|
||||
@0 = private unnamed_addr constant [34 x i8] c"type assertion any -> *int8 failed", align 1
|
||||
@_llgo_string = linkonce global ptr null, align 8
|
||||
@_llgo_int = linkonce global ptr null, align 8
|
||||
@1 = private unnamed_addr constant [40 x i8] c"type assertion interface{} -> int failed", align 1
|
||||
@1 = private unnamed_addr constant [32 x i8] c"type assertion any -> int failed", align 1
|
||||
@2 = private unnamed_addr constant [7 x i8] c"%s %d\0A\00", align 1
|
||||
@3 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1
|
||||
|
||||
@@ -29,7 +29,7 @@ _llgo_1: ; preds = %_llgo_0
|
||||
_llgo_2: ; preds = %_llgo_0
|
||||
%6 = load ptr, ptr @_llgo_string, align 8
|
||||
%7 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 42 }, ptr %7, align 8
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 34 }, ptr %7, align 8
|
||||
%8 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %6, 0
|
||||
%9 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %8, ptr %7, 1
|
||||
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %9)
|
||||
@@ -52,7 +52,7 @@ _llgo_1: ; preds = %_llgo_0
|
||||
_llgo_2: ; preds = %_llgo_0
|
||||
%7 = load ptr, ptr @_llgo_string, align 8
|
||||
%8 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 40 }, ptr %8, align 8
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 32 }, ptr %8, align 8
|
||||
%9 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %7, 0
|
||||
%10 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %9, ptr %8, 1
|
||||
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %10)
|
||||
|
||||
@@ -23,7 +23,7 @@ source_filename = "github.com/goplus/llgo/cl/_testrt/tpabi"
|
||||
@5 = private unnamed_addr constant [4 x i8] c"Demo", align 1
|
||||
@"_llgo_func$2_iS07vIlF2_rZqWB5eU0IvP_9HviM4MYZNkXZDvbac" = linkonce global ptr null, align 8
|
||||
@6 = private unnamed_addr constant [4 x i8] c"Info", align 1
|
||||
@7 = private unnamed_addr constant [91 x i8] c"type assertion interface{} -> github.com/goplus/llgo/cl/_testrt/tpabi.T[string, int] failed", align 1
|
||||
@7 = private unnamed_addr constant [83 x i8] c"type assertion any -> github.com/goplus/llgo/cl/_testrt/tpabi.T[string, int] failed", align 1
|
||||
@8 = private unnamed_addr constant [5 x i8] c"hello", align 1
|
||||
@"*_llgo_github.com/goplus/llgo/cl/_testrt/tpabi.T[string,int]" = linkonce global ptr null, align 8
|
||||
@"_llgo_iface$BP0p_lUsEd-IbbtJVukGmgrdQkqzcoYzSiwgUvgFvUs" = linkonce global ptr null, align 8
|
||||
@@ -107,7 +107,7 @@ _llgo_1: ; preds = %_llgo_0
|
||||
_llgo_2: ; preds = %_llgo_0
|
||||
%38 = load ptr, ptr @_llgo_string, align 8
|
||||
%39 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @7, i64 91 }, ptr %39, align 8
|
||||
store %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @7, i64 83 }, ptr %39, align 8
|
||||
%40 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" undef, ptr %38, 0
|
||||
%41 = insertvalue %"github.com/goplus/llgo/runtime/internal/runtime.eface" %40, ptr %39, 1
|
||||
call void @"github.com/goplus/llgo/runtime/internal/runtime.Panic"(%"github.com/goplus/llgo/runtime/internal/runtime.eface" %41)
|
||||
|
||||
19
cl/import.go
19
cl/import.go
@@ -446,17 +446,18 @@ const (
|
||||
llgoAlloca = llgoInstrBase + 2
|
||||
llgoAllocaCStr = llgoInstrBase + 3
|
||||
llgoAllocaCStrs = llgoInstrBase + 4
|
||||
llgoAdvance = llgoInstrBase + 5
|
||||
llgoIndex = llgoInstrBase + 6
|
||||
llgoStringData = llgoInstrBase + 7
|
||||
llgoString = llgoInstrBase + 8
|
||||
llgoDeferData = llgoInstrBase + 9
|
||||
llgoAllocCStr = llgoInstrBase + 5
|
||||
llgoAdvance = llgoInstrBase + 6
|
||||
llgoIndex = llgoInstrBase + 7
|
||||
llgoStringData = llgoInstrBase + 8
|
||||
llgoString = llgoInstrBase + 9
|
||||
llgoDeferData = llgoInstrBase + 0xa
|
||||
|
||||
llgoSigjmpbuf = llgoInstrBase + 0xa
|
||||
llgoSigsetjmp = llgoInstrBase + 0xb
|
||||
llgoSiglongjmp = llgoInstrBase + 0xc
|
||||
llgoSigjmpbuf = llgoInstrBase + 0xb
|
||||
llgoSigsetjmp = llgoInstrBase + 0xc
|
||||
llgoSiglongjmp = llgoInstrBase + 0xd
|
||||
|
||||
llgoFuncAddr = llgoInstrBase + 0xd
|
||||
llgoFuncAddr = llgoInstrBase + 0xe
|
||||
|
||||
llgoPyList = llgoInstrBase + 0x10
|
||||
llgoPyStr = llgoInstrBase + 0x11
|
||||
|
||||
12
cl/instr.go
12
cl/instr.go
@@ -165,6 +165,15 @@ func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr)
|
||||
panic("allocaCStr(s string): invalid arguments")
|
||||
}
|
||||
|
||||
// func allocCStr(s string) *int8
|
||||
func (p *context) allocCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 1 {
|
||||
s := p.compileValue(b, args[0])
|
||||
return b.AllocCStr(s)
|
||||
}
|
||||
panic("allocCStr(s string): invalid arguments")
|
||||
}
|
||||
|
||||
// func allocaCStrs(strs []string, endWithNil bool) **int8
|
||||
func (p *context) allocaCStrs(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 2 {
|
||||
@@ -281,6 +290,7 @@ var llgoInstrs = map[string]int{
|
||||
"advance": llgoAdvance,
|
||||
"index": llgoIndex,
|
||||
"alloca": llgoAlloca,
|
||||
"allocCStr": llgoAllocCStr,
|
||||
"allocaCStr": llgoAllocaCStr,
|
||||
"allocaCStrs": llgoAllocaCStrs,
|
||||
"string": llgoString,
|
||||
@@ -470,6 +480,8 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
|
||||
ret = p.alloca(b, args)
|
||||
case llgoAllocaCStr:
|
||||
ret = p.allocaCStr(b, args)
|
||||
case llgoAllocCStr:
|
||||
ret = p.allocCStr(b, args)
|
||||
case llgoAllocaCStrs:
|
||||
ret = p.allocaCStrs(b, args)
|
||||
case llgoString:
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/cmd/internal/base"
|
||||
"github.com/goplus/llgo/cmd/internal/flags"
|
||||
"github.com/goplus/llgo/internal/build"
|
||||
"github.com/goplus/llgo/internal/mockable"
|
||||
)
|
||||
@@ -34,17 +35,22 @@ var Cmd = &base.Command{
|
||||
|
||||
func init() {
|
||||
Cmd.Run = runCmd
|
||||
flags.AddBuildFlags(&Cmd.Flag)
|
||||
flags.AddOutputFlags(&Cmd.Flag)
|
||||
}
|
||||
|
||||
func runCmd(cmd *base.Command, args []string) {
|
||||
conf := &build.Config{
|
||||
Mode: build.ModeBuild,
|
||||
AppExt: build.DefaultAppExt(),
|
||||
}
|
||||
if len(args) >= 2 && args[0] == "-o" {
|
||||
conf.OutFile = args[1]
|
||||
args = args[2:]
|
||||
if err := cmd.Flag.Parse(args); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conf := build.NewDefaultConf(build.ModeBuild)
|
||||
conf.Tags = flags.Tags
|
||||
conf.Verbose = flags.Verbose
|
||||
conf.OutFile = flags.OutputFile
|
||||
|
||||
args = cmd.Flag.Args()
|
||||
|
||||
_, err := build.Do(args, conf)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
@@ -19,6 +19,7 @@ package clean
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/cmd/internal/base"
|
||||
"github.com/goplus/llgo/cmd/internal/flags"
|
||||
"github.com/goplus/llgo/internal/build"
|
||||
)
|
||||
|
||||
@@ -30,9 +31,18 @@ var Cmd = &base.Command{
|
||||
|
||||
func init() {
|
||||
Cmd.Run = runCmd
|
||||
flags.AddBuildFlags(&Cmd.Flag)
|
||||
}
|
||||
|
||||
func runCmd(cmd *base.Command, args []string) {
|
||||
if err := cmd.Flag.Parse(args); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conf := build.NewDefaultConf(0)
|
||||
conf.Tags = flags.Tags
|
||||
conf.Verbose = flags.Verbose
|
||||
|
||||
args = cmd.Flag.Args()
|
||||
build.Clean(args, conf)
|
||||
}
|
||||
|
||||
27
cmd/internal/flags/flags.go
Normal file
27
cmd/internal/flags/flags.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
)
|
||||
|
||||
var OutputFile string
|
||||
|
||||
func AddOutputFlags(fs *flag.FlagSet) {
|
||||
fs.StringVar(&OutputFile, "o", "", "Output file")
|
||||
}
|
||||
|
||||
var Verbose bool
|
||||
var BuildEnv string
|
||||
var Tags string
|
||||
|
||||
func AddBuildFlags(fs *flag.FlagSet) {
|
||||
fs.BoolVar(&Verbose, "v", false, "Verbose mode")
|
||||
fs.StringVar(&Tags, "tags", "", "Build tags")
|
||||
fs.StringVar(&BuildEnv, "buildenv", "", "Build environment")
|
||||
}
|
||||
|
||||
var Gen bool
|
||||
|
||||
func AddCmpTestFlags(fs *flag.FlagSet) {
|
||||
fs.BoolVar(&Gen, "gen", false, "Generate llgo.expect file")
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/cmd/internal/base"
|
||||
"github.com/goplus/llgo/cmd/internal/flags"
|
||||
"github.com/goplus/llgo/internal/build"
|
||||
"github.com/goplus/llgo/internal/mockable"
|
||||
)
|
||||
@@ -34,10 +35,19 @@ var Cmd = &base.Command{
|
||||
|
||||
func init() {
|
||||
Cmd.Run = runCmd
|
||||
flags.AddBuildFlags(&Cmd.Flag)
|
||||
}
|
||||
|
||||
func runCmd(cmd *base.Command, args []string) {
|
||||
if err := cmd.Flag.Parse(args); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conf := build.NewDefaultConf(build.ModeInstall)
|
||||
conf.Tags = flags.Tags
|
||||
conf.Verbose = flags.Verbose
|
||||
|
||||
args = cmd.Flag.Args()
|
||||
_, err := build.Do(args, conf)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/goplus/llgo/cmd/internal/base"
|
||||
"github.com/goplus/llgo/cmd/internal/flags"
|
||||
"github.com/goplus/llgo/internal/build"
|
||||
"github.com/goplus/llgo/internal/mockable"
|
||||
)
|
||||
@@ -47,6 +47,9 @@ var CmpTestCmd = &base.Command{
|
||||
func init() {
|
||||
Cmd.Run = runCmd
|
||||
CmpTestCmd.Run = runCmpTest
|
||||
flags.AddBuildFlags(&Cmd.Flag)
|
||||
flags.AddBuildFlags(&CmpTestCmd.Flag)
|
||||
flags.AddCmpTestFlags(&CmpTestCmd.Flag)
|
||||
}
|
||||
|
||||
func runCmd(cmd *base.Command, args []string) {
|
||||
@@ -57,12 +60,17 @@ func runCmpTest(cmd *base.Command, args []string) {
|
||||
runCmdEx(cmd, args, build.ModeCmpTest)
|
||||
}
|
||||
|
||||
func runCmdEx(_ *base.Command, args []string, mode build.Mode) {
|
||||
conf := build.NewDefaultConf(mode)
|
||||
if mode == build.ModeCmpTest && len(args) > 0 && args[0] == "-gen" {
|
||||
conf.GenExpect = true
|
||||
args = args[1:]
|
||||
func runCmdEx(cmd *base.Command, args []string, mode build.Mode) {
|
||||
if err := cmd.Flag.Parse(args); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conf := build.NewDefaultConf(mode)
|
||||
conf.Tags = flags.Tags
|
||||
conf.Verbose = flags.Verbose
|
||||
conf.GenExpect = flags.Gen
|
||||
|
||||
args = cmd.Flag.Args()
|
||||
args, runArgs, err := parseRunArgs(args)
|
||||
check(err)
|
||||
conf.RunArgs = runArgs
|
||||
@@ -74,24 +82,11 @@ func runCmdEx(_ *base.Command, args []string, mode build.Mode) {
|
||||
}
|
||||
|
||||
func parseRunArgs(args []string) ([]string, []string, error) {
|
||||
n := build.SkipFlagArgs(args)
|
||||
if n < 0 {
|
||||
if len(args) == 0 {
|
||||
return nil, nil, errNoProj
|
||||
}
|
||||
|
||||
arg := args[n]
|
||||
if isGoFile(arg) {
|
||||
n++
|
||||
for n < len(args) && isGoFile(args[n]) {
|
||||
n++
|
||||
}
|
||||
return args[:n], args[n:], nil
|
||||
}
|
||||
return args[:n+1], args[n+1:], nil
|
||||
}
|
||||
|
||||
func isGoFile(fname string) bool {
|
||||
return filepath.Ext(fname) == ".go"
|
||||
return args[:1], args[1:], nil
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/cmd/internal/base"
|
||||
"github.com/goplus/llgo/cmd/internal/flags"
|
||||
"github.com/goplus/llgo/internal/build"
|
||||
)
|
||||
|
||||
@@ -16,15 +17,19 @@ var Cmd = &base.Command{
|
||||
|
||||
func init() {
|
||||
Cmd.Run = runCmd
|
||||
flags.AddBuildFlags(&Cmd.Flag)
|
||||
}
|
||||
|
||||
func runCmd(cmd *base.Command, args []string) {
|
||||
runCmdEx(cmd, args, build.ModeRun)
|
||||
if err := cmd.Flag.Parse(args); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
func runCmdEx(_ *base.Command, args []string, mode build.Mode) {
|
||||
conf := build.NewDefaultConf(mode)
|
||||
conf.Mode = build.ModeTest
|
||||
conf := build.NewDefaultConf(build.ModeTest)
|
||||
conf.Tags = flags.Tags
|
||||
conf.Verbose = flags.Verbose
|
||||
|
||||
args = cmd.Flag.Args()
|
||||
_, err := build.Do(args, conf)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
@@ -301,7 +301,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func _TestCommandHandling(t *testing.T) {
|
||||
func TestCommandHandling(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
|
||||
@@ -2,4 +2,4 @@ module github.com/goplus/llgo/doc/_readme
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/goplus/lib v0.1.0
|
||||
require github.com/goplus/lib v0.2.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
brew update
|
||||
brew install llvm@19 lld@19 bdw-gc openssl cjson libffi libuv pkg-config
|
||||
brew install python@3.12 # optional
|
||||
brew link --overwrite lld@19 libffi
|
||||
brew link --overwrite llvm@19 lld@19 libffi
|
||||
# curl https://raw.githubusercontent.com/goplus/llgo/refs/heads/main/install.sh | bash
|
||||
./install.sh
|
||||
8
go.mod
8
go.mod
@@ -5,12 +5,12 @@ go 1.22.0
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
github.com/goplus/gogen v1.16.9
|
||||
github.com/goplus/lib v0.1.0
|
||||
github.com/goplus/gogen v1.17.2
|
||||
github.com/goplus/lib v0.2.0
|
||||
github.com/goplus/llgo/runtime v0.0.0-20250403035532-0a8a4eb6a653
|
||||
github.com/goplus/llvm v0.8.3
|
||||
github.com/goplus/mod v0.13.17
|
||||
github.com/qiniu/x v1.13.12
|
||||
github.com/goplus/mod v0.16.0
|
||||
github.com/qiniu/x v1.13.19
|
||||
golang.org/x/tools v0.30.0
|
||||
)
|
||||
|
||||
|
||||
16
go.sum
16
go.sum
@@ -1,15 +1,15 @@
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/goplus/gogen v1.16.9 h1:BRNAsRzdyMcLBOLUe6+suVMmOe+D2HLfF7mAkS4/QW4=
|
||||
github.com/goplus/gogen v1.16.9/go.mod h1:6TQYbabXDF9LCdDkOOzHmfg1R4ENfXQ3XpHa9RhTSD8=
|
||||
github.com/goplus/lib v0.1.0 h1:kqMAC6FmVPfrw0q8E5yF6Y12WC4GOfi2L/MYS4QoxbQ=
|
||||
github.com/goplus/lib v0.1.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
github.com/goplus/gogen v1.17.2 h1:oQDWiVzZmDAdgNieJnrvrWTmxDTqYXGFMBa2rAbwjmA=
|
||||
github.com/goplus/gogen v1.17.2/go.mod h1:owX2e1EyU5WD+Nm6oH2m/GXjLdlBYcwkLO4wN8HHXZI=
|
||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
github.com/goplus/llvm v0.8.3 h1:is1zOwhiQZWtLnOmSMVPO+1sPa2uK/XJ/FjTSfIjGBU=
|
||||
github.com/goplus/llvm v0.8.3/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||
github.com/goplus/mod v0.13.17 h1:aWp14xosENrh7t0/0qcIejDmQEiTgI3ou2+KoLDlSlE=
|
||||
github.com/goplus/mod v0.13.17/go.mod h1:XlHf8mnQ4QkRDX14Of2tpywuHDd+JVpPStvh3egog+0=
|
||||
github.com/qiniu/x v1.13.12 h1:UyAwja6dgKUOYWZMzzc02wLodwnZ7wmK/0XzRd0e78g=
|
||||
github.com/qiniu/x v1.13.12/go.mod h1:INZ2TSWSJVWO/RuELQROERcslBwVgFG7MkTfEdaQz9E=
|
||||
github.com/goplus/mod v0.16.0 h1:5CHXx3no7YaMN5HN2sgZe9MbQnc8118JLjbOeetSTfc=
|
||||
github.com/goplus/mod v0.16.0/go.mod h1:U69PUD2e1MnI2DYhuumj1Z6wvZ1bNbKqHUk1MK8Diqo=
|
||||
github.com/qiniu/x v1.13.19 h1:rZzWpifNjMtaMhhVnYHw9RGUn+84KGtclDZ9HAKtuZQ=
|
||||
github.com/qiniu/x v1.13.19/go.mod h1:AiovSOCaRijaf3fj+0CBOpR1457pn24b0Vdb1JpwhII=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"debug/macho"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
@@ -31,23 +30,25 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
|
||||
"github.com/goplus/llgo/cl"
|
||||
"github.com/goplus/llgo/internal/crosscompile"
|
||||
"github.com/goplus/llgo/internal/env"
|
||||
"github.com/goplus/llgo/internal/mockable"
|
||||
"github.com/goplus/llgo/internal/packages"
|
||||
"github.com/goplus/llgo/internal/typepatch"
|
||||
llvmTarget "github.com/goplus/llgo/internal/xtool/llvm"
|
||||
"github.com/goplus/llgo/ssa/abi"
|
||||
xenv "github.com/goplus/llgo/xtool/env"
|
||||
"github.com/goplus/llgo/xtool/env/llvm"
|
||||
|
||||
llruntime "github.com/goplus/llgo/runtime"
|
||||
llssa "github.com/goplus/llgo/ssa"
|
||||
clangCheck "github.com/goplus/llgo/xtool/clang/check"
|
||||
)
|
||||
|
||||
type Mode int
|
||||
@@ -66,12 +67,16 @@ const (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Goos string
|
||||
Goarch string
|
||||
BinPath string
|
||||
AppExt string // ".exe" on Windows, empty on Unix
|
||||
OutFile string // only valid for ModeBuild when len(pkgs) == 1
|
||||
RunArgs []string // only valid for ModeRun
|
||||
Mode Mode
|
||||
GenExpect bool // only valid for ModeCmpTest
|
||||
Verbose bool
|
||||
Tags string
|
||||
}
|
||||
|
||||
func NewDefaultConf(mode Mode) *Config {
|
||||
@@ -86,10 +91,19 @@ func NewDefaultConf(mode Mode) *Config {
|
||||
if err := os.MkdirAll(bin, 0755); err != nil {
|
||||
panic(fmt.Errorf("cannot create bin directory: %v", err))
|
||||
}
|
||||
goos, goarch := os.Getenv("GOOS"), os.Getenv("GOARCH")
|
||||
if goos == "" {
|
||||
goos = runtime.GOOS
|
||||
}
|
||||
if goarch == "" {
|
||||
goarch = runtime.GOARCH
|
||||
}
|
||||
conf := &Config{
|
||||
Goos: goos,
|
||||
Goarch: goarch,
|
||||
BinPath: bin,
|
||||
Mode: mode,
|
||||
AppExt: DefaultAppExt(),
|
||||
AppExt: DefaultAppExt(goos),
|
||||
}
|
||||
return conf
|
||||
}
|
||||
@@ -105,9 +119,12 @@ func envGOPATH() (string, error) {
|
||||
return filepath.Join(home, "go"), nil
|
||||
}
|
||||
|
||||
func DefaultAppExt() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
func DefaultAppExt(goos string) string {
|
||||
switch goos {
|
||||
case "windows":
|
||||
return ".exe"
|
||||
case "wasi", "wasip1", "js":
|
||||
return ".wasm"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -122,11 +139,21 @@ const (
|
||||
)
|
||||
|
||||
func Do(args []string, conf *Config) ([]Package, error) {
|
||||
flags, patterns, verbose := ParseArgs(args, buildFlags)
|
||||
flags = append(flags, "-tags", "llgo")
|
||||
if conf.Goos == "" {
|
||||
conf.Goos = runtime.GOOS
|
||||
}
|
||||
if conf.Goarch == "" {
|
||||
conf.Goarch = runtime.GOARCH
|
||||
}
|
||||
verbose := conf.Verbose
|
||||
patterns := args
|
||||
tags := "llgo"
|
||||
if conf.Tags != "" {
|
||||
tags += "," + conf.Tags
|
||||
}
|
||||
cfg := &packages.Config{
|
||||
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
|
||||
BuildFlags: flags,
|
||||
BuildFlags: []string{"-tags=" + tags},
|
||||
Fset: token.NewFileSet(),
|
||||
Tests: conf.Mode == ModeTest,
|
||||
}
|
||||
@@ -134,13 +161,12 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
||||
cfg.Mode |= packages.NeedForTest
|
||||
}
|
||||
|
||||
if len(llruntime.OverlayFiles) > 0 {
|
||||
cfg.Overlay = make(map[string][]byte)
|
||||
clearRuntime(cfg.Overlay, filepath.Join(env.GOROOT(), "src", "runtime"))
|
||||
for file, src := range llruntime.OverlayFiles {
|
||||
overlay := unsafe.Slice(unsafe.StringData(src), len(src))
|
||||
cfg.Overlay[filepath.Join(env.GOROOT(), "src", file)] = overlay
|
||||
}
|
||||
}
|
||||
|
||||
cl.EnableDebug(IsDbgEnabled())
|
||||
cl.EnableDbgSyms(IsDbgSymsEnabled())
|
||||
@@ -148,8 +174,8 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
||||
llssa.Initialize(llssa.InitAll)
|
||||
|
||||
target := &llssa.Target{
|
||||
GOOS: build.Default.GOOS,
|
||||
GOARCH: build.Default.GOARCH,
|
||||
GOOS: conf.Goos,
|
||||
GOARCH: conf.Goarch,
|
||||
}
|
||||
|
||||
prog := llssa.NewProgram(target)
|
||||
@@ -221,7 +247,9 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
||||
os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows
|
||||
|
||||
output := conf.OutFile != ""
|
||||
ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool)}
|
||||
export, err := crosscompile.UseCrossCompileSDK(conf.Goos, conf.Goarch, IsWasiThreadsEnabled())
|
||||
check(err)
|
||||
ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), conf, export}
|
||||
pkgs, err := buildAllPkgs(ctx, initial, verbose)
|
||||
check(err)
|
||||
if mode == ModeGen {
|
||||
@@ -235,20 +263,35 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
||||
|
||||
dpkg, err := buildAllPkgs(ctx, altPkgs[noRt:], verbose)
|
||||
check(err)
|
||||
var linkArgs []string
|
||||
for _, pkg := range dpkg {
|
||||
linkArgs = append(linkArgs, pkg.LinkArgs...)
|
||||
}
|
||||
allPkgs := append([]*aPackage{}, pkgs...)
|
||||
allPkgs = append(allPkgs, dpkg...)
|
||||
|
||||
for _, pkg := range initial {
|
||||
if needLink(pkg, mode) {
|
||||
linkMainPkg(ctx, pkg, pkgs, linkArgs, conf, mode, verbose)
|
||||
linkMainPkg(ctx, pkg, allPkgs, conf, mode, verbose)
|
||||
}
|
||||
}
|
||||
|
||||
return dpkg, nil
|
||||
}
|
||||
|
||||
func clearRuntime(overlay map[string][]byte, runtimePath string) {
|
||||
files, err := filepath.Glob(runtimePath + "/*.go")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
overlay[file] = []byte("package runtime\n")
|
||||
}
|
||||
files, err = filepath.Glob(runtimePath + "/*.s")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
overlay[file] = []byte("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func needLink(pkg *packages.Package, mode Mode) bool {
|
||||
if mode == ModeTest {
|
||||
return strings.HasSuffix(pkg.ID, ".test")
|
||||
@@ -286,6 +329,9 @@ type context struct {
|
||||
|
||||
needRt map[*packages.Package]bool
|
||||
needPyInit map[*packages.Package]bool
|
||||
|
||||
buildConf *Config
|
||||
crossCompile crosscompile.Export
|
||||
}
|
||||
|
||||
func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage, err error) {
|
||||
@@ -314,16 +360,10 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs
|
||||
pkg.ExportFile = ""
|
||||
case cl.PkgLinkIR, cl.PkgLinkExtern, cl.PkgPyModule:
|
||||
if len(pkg.GoFiles) > 0 {
|
||||
cgoLdflags, err := buildPkg(ctx, aPkg, verbose)
|
||||
err := buildPkg(ctx, aPkg, verbose)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
linkParts := concatPkgLinkFiles(ctx, pkg, verbose)
|
||||
allParts := append(linkParts, cgoLdflags...)
|
||||
if pkg.ExportFile != "" {
|
||||
allParts = append(allParts, pkg.ExportFile)
|
||||
}
|
||||
aPkg.LinkArgs = allParts
|
||||
} else {
|
||||
// panic("todo")
|
||||
// TODO(xsw): support packages out of llgo
|
||||
@@ -364,22 +404,15 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs
|
||||
ctx.nLibdir++
|
||||
}
|
||||
}
|
||||
if err := clangCheck.CheckLinkArgs(pkgLinkArgs); err != nil {
|
||||
if err := ctx.env.Clang().CheckLinkArgs(pkgLinkArgs); err != nil {
|
||||
panic(fmt.Sprintf("test link args '%s' failed\n\texpanded to: %v\n\tresolved to: %v\n\terror: %v", param, expdArgs, pkgLinkArgs, err))
|
||||
}
|
||||
aPkg.LinkArgs = append(aPkg.LinkArgs, pkgLinkArgs...)
|
||||
}
|
||||
default:
|
||||
cgoLdflags, err := buildPkg(ctx, aPkg, verbose)
|
||||
err := buildPkg(ctx, aPkg, verbose)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if pkg.ExportFile != "" {
|
||||
aPkg.LinkArgs = append(cgoLdflags, pkg.ExportFile)
|
||||
}
|
||||
aPkg.LinkArgs = append(aPkg.LinkArgs, concatPkgLinkFiles(ctx, pkg, verbose)...)
|
||||
if aPkg.AltPkg != nil {
|
||||
aPkg.LinkArgs = append(aPkg.LinkArgs, concatPkgLinkFiles(ctx, aPkg.AltPkg.Package, verbose)...)
|
||||
return nil, err
|
||||
}
|
||||
setNeedRuntimeOrPyInit(ctx, pkg, aPkg.LPkg.NeedRuntime, aPkg.LPkg.NeedPyInit)
|
||||
}
|
||||
@@ -387,7 +420,7 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs
|
||||
return
|
||||
}
|
||||
|
||||
func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs []string, conf *Config, mode Mode, verbose bool) {
|
||||
func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, conf *Config, mode Mode, verbose bool) {
|
||||
pkgPath := pkg.PkgPath
|
||||
name := path.Base(pkgPath)
|
||||
app := conf.OutFile
|
||||
@@ -401,49 +434,25 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs
|
||||
} else {
|
||||
app = filepath.Join(conf.BinPath, name+conf.AppExt)
|
||||
}
|
||||
} else if !strings.HasSuffix(app, conf.AppExt) {
|
||||
app += conf.AppExt
|
||||
}
|
||||
args := make([]string, 0, len(pkg.Imports)+len(linkArgs)+16)
|
||||
args = append(
|
||||
args,
|
||||
"-o", app,
|
||||
"-Wl,--error-limit=0",
|
||||
"-fuse-ld=lld",
|
||||
"-Wno-override-module",
|
||||
// "-O2", // FIXME: This will cause TestFinalizer in _test/bdwgc.go to fail on macOS.
|
||||
)
|
||||
switch runtime.GOOS {
|
||||
case "darwin": // ld64.lld (macOS)
|
||||
args = append(
|
||||
args,
|
||||
"-rpath", "@loader_path",
|
||||
"-rpath", "@loader_path/../lib",
|
||||
"-Xlinker", "-dead_strip",
|
||||
)
|
||||
case "windows": // lld-link (Windows)
|
||||
// TODO: Add options for Windows.
|
||||
default: // ld.lld (Unix), wasm-ld (WebAssembly)
|
||||
args = append(
|
||||
args,
|
||||
"-rpath", "$ORIGIN",
|
||||
"-rpath", "$ORIGIN/../lib",
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
"-Xlinker", "--gc-sections",
|
||||
"-lm",
|
||||
"-latomic",
|
||||
"-lpthread", // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions.
|
||||
)
|
||||
}
|
||||
|
||||
needRuntime := false
|
||||
needPyInit := false
|
||||
pkgsMap := make(map[*packages.Package]*aPackage, len(pkgs))
|
||||
allPkgs := []*packages.Package{pkg}
|
||||
for _, v := range pkgs {
|
||||
pkgsMap[v.Package] = v
|
||||
allPkgs = append(allPkgs, v.Package)
|
||||
}
|
||||
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||
if p.ExportFile != "" { // skip packages that only contain declarations
|
||||
var llFiles []string
|
||||
var linkArgs []string
|
||||
packages.Visit(allPkgs, nil, func(p *packages.Package) {
|
||||
aPkg := pkgsMap[p]
|
||||
args = append(args, aPkg.LinkArgs...)
|
||||
if p.ExportFile != "" && aPkg != nil { // skip packages that only contain declarations
|
||||
linkArgs = append(linkArgs, aPkg.LinkArgs...)
|
||||
llFiles = append(llFiles, aPkg.LLFiles...)
|
||||
need1, need2 := isNeedRuntimeOrPyInit(ctx, p)
|
||||
if !needRuntime {
|
||||
needRuntime = need1
|
||||
@@ -453,51 +462,29 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs
|
||||
}
|
||||
}
|
||||
})
|
||||
entryLLFile, err := genMainModuleFile(llssa.PkgRuntime, pkg.PkgPath, needRuntime, needPyInit)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
entryLLFile, err := genMainModuleFile(conf, llssa.PkgRuntime, pkg.PkgPath, needRuntime, needPyInit)
|
||||
check(err)
|
||||
// defer os.Remove(entryLLFile)
|
||||
args = append(args, entryLLFile)
|
||||
|
||||
var aPkg *aPackage
|
||||
for _, v := range pkgs {
|
||||
if v.Package == pkg { // found this package
|
||||
aPkg = v
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
args = append(args, linkArgs...)
|
||||
|
||||
if ctx.output {
|
||||
lpkg := aPkg.LPkg
|
||||
os.WriteFile(pkg.ExportFile, []byte(lpkg.String()), 0644)
|
||||
}
|
||||
llFiles = append(llFiles, entryLLFile)
|
||||
|
||||
// add rpath and find libs
|
||||
exargs := make([]string, 0, ctx.nLibdir<<1)
|
||||
libs := make([]string, 0, ctx.nLibdir*3)
|
||||
for _, arg := range args {
|
||||
if IsRpathChangeEnabled() {
|
||||
for _, arg := range linkArgs {
|
||||
if strings.HasPrefix(arg, "-L") {
|
||||
exargs = append(exargs, "-rpath", arg[2:])
|
||||
} else if strings.HasPrefix(arg, "-l") {
|
||||
libs = append(libs, arg[2:])
|
||||
}
|
||||
}
|
||||
args = append(args, exargs...)
|
||||
if IsDbgSymsEnabled() {
|
||||
args = append(args, "-gdwarf-4")
|
||||
}
|
||||
linkArgs = append(linkArgs, exargs...)
|
||||
|
||||
// TODO(xsw): show work
|
||||
if verbose {
|
||||
fmt.Fprintln(os.Stderr, "clang", args)
|
||||
}
|
||||
err = ctx.env.Clang().Link(args...)
|
||||
err = compileAndLinkLLFiles(ctx, app, llFiles, linkArgs, verbose)
|
||||
check(err)
|
||||
|
||||
if IsRpathChangeEnabled() && runtime.GOOS == "darwin" {
|
||||
if IsRpathChangeEnabled() && ctx.buildConf.Goos == "darwin" {
|
||||
dylibDeps := make([]string, 0, len(libs))
|
||||
for _, lib := range libs {
|
||||
dylibDep := findDylibDep(app, lib)
|
||||
@@ -519,11 +506,37 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs
|
||||
fmt.Fprintf(os.Stderr, "%s: exit code %d\n", app, s.ExitCode())
|
||||
}
|
||||
case ModeRun:
|
||||
cmd := exec.Command(app, conf.RunArgs...)
|
||||
args := make([]string, 0, len(conf.RunArgs)+1)
|
||||
copy(args, conf.RunArgs)
|
||||
if isWasmTarget(conf.Goos) {
|
||||
wasmer := os.ExpandEnv(WasmRuntime())
|
||||
wasmerArgs := strings.Split(wasmer, " ")
|
||||
wasmerCmd := wasmerArgs[0]
|
||||
wasmerArgs = wasmerArgs[1:]
|
||||
switch wasmer {
|
||||
case "wasmtime":
|
||||
args = append(args, "--wasm", "multi-memory=true", app)
|
||||
args = append(args, conf.RunArgs...)
|
||||
case "iwasm":
|
||||
args = append(args, "--stack-size=819200000", "--heap-size=800000000", app)
|
||||
args = append(args, conf.RunArgs...)
|
||||
default:
|
||||
args = append(args, wasmerArgs...)
|
||||
args = append(args, app)
|
||||
args = append(args, conf.RunArgs...)
|
||||
}
|
||||
app = wasmerCmd
|
||||
} else {
|
||||
args = conf.RunArgs
|
||||
}
|
||||
cmd := exec.Command(app, args...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Run()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if s := cmd.ProcessState; s != nil {
|
||||
mockable.Exit(s.ExitCode())
|
||||
}
|
||||
@@ -532,7 +545,133 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs
|
||||
}
|
||||
}
|
||||
|
||||
func genMainModuleFile(rtPkgPath, mainPkgPath string, needRuntime, needPyInit bool) (path string, err error) {
|
||||
func compileAndLinkLLFiles(ctx *context, app string, llFiles, linkArgs []string, verbose bool) error {
|
||||
buildArgs := []string{"-o", app}
|
||||
buildArgs = append(buildArgs, linkArgs...)
|
||||
|
||||
// Add common linker arguments based on target OS and architecture
|
||||
targetTriple := llvmTarget.GetTargetTriple(ctx.buildConf.Goos, ctx.buildConf.Goarch)
|
||||
buildArgs = append(buildArgs, buildLdflags(ctx.buildConf.Goos, ctx.buildConf.Goarch, targetTriple)...)
|
||||
|
||||
if IsDbgSymsEnabled() {
|
||||
buildArgs = append(buildArgs, "-gdwarf-4")
|
||||
}
|
||||
|
||||
buildArgs = append(buildArgs, ctx.crossCompile.CCFLAGS...)
|
||||
buildArgs = append(buildArgs, ctx.crossCompile.LDFLAGS...)
|
||||
buildArgs = append(buildArgs, llFiles...)
|
||||
if verbose {
|
||||
buildArgs = append(buildArgs, "-v")
|
||||
}
|
||||
|
||||
cmd := ctx.env.Clang()
|
||||
cmd.Verbose = verbose
|
||||
return cmd.Link(buildArgs...)
|
||||
}
|
||||
|
||||
func buildCflags(goos, goarch, targetTriple string) []string {
|
||||
args := []string{}
|
||||
if goarch == "wasm" {
|
||||
args = append(args, "-target", targetTriple)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// buildLdflags builds the common linker arguments based on target OS and architecture
|
||||
func buildLdflags(goos, goarch, targetTriple string) []string {
|
||||
args := []string{
|
||||
"-target", targetTriple,
|
||||
"-Wno-override-module",
|
||||
"-Wl,--error-limit=0",
|
||||
}
|
||||
if goos == runtime.GOOS {
|
||||
// Non-cross-compile
|
||||
args = append(args,
|
||||
"-fuse-ld=lld",
|
||||
"-Wno-override-module",
|
||||
)
|
||||
}
|
||||
|
||||
switch goos {
|
||||
case "darwin": // ld64.lld (macOS)
|
||||
if IsRpathChangeEnabled() {
|
||||
args = append(
|
||||
args,
|
||||
"-rpath", "@loader_path",
|
||||
"-rpath", "@loader_path/../lib",
|
||||
)
|
||||
}
|
||||
args = append(
|
||||
args,
|
||||
"-Xlinker", "-dead_strip",
|
||||
)
|
||||
case "windows": // lld-link (Windows)
|
||||
// TODO(xsw): Add options for Windows.
|
||||
case "wasi", "wasip1", "js": // wasm-ld (WebAssembly)
|
||||
args = append(
|
||||
args,
|
||||
// "-fdata-sections",
|
||||
// "-ffunction-sections",
|
||||
// "-nostdlib",
|
||||
// "-Wl,--no-entry",
|
||||
"-Wl,--export-all",
|
||||
"-Wl,--allow-undefined",
|
||||
"-Wl,--import-memory,", // unknown import: `env::memory` has not been defined
|
||||
"-Wl,--export-memory",
|
||||
"-Wl,--initial-memory=67108864", // 64MB
|
||||
"-mbulk-memory",
|
||||
"-mmultimemory",
|
||||
"-z", "stack-size=10485760", // 10MB
|
||||
"-Wl,--export=malloc", "-Wl,--export=free",
|
||||
"-lc",
|
||||
"-lcrypt",
|
||||
"-lm",
|
||||
"-lrt",
|
||||
"-lutil",
|
||||
// "-lxnet",
|
||||
// "-lresolv",
|
||||
"-lsetjmp",
|
||||
"-lwasi-emulated-mman",
|
||||
"-lwasi-emulated-getpid",
|
||||
"-lwasi-emulated-process-clocks",
|
||||
"-lwasi-emulated-signal",
|
||||
"-fwasm-exceptions",
|
||||
"-mllvm", "-wasm-enable-sjlj",
|
||||
// "-mllvm", "-wasm-enable-eh", // unreachable error if enabled
|
||||
// "-mllvm", "-wasm-disable-explicit-locals", // WASM module load failed: type mismatch: expect data but stack was empty if enabled
|
||||
)
|
||||
if IsWasiThreadsEnabled() {
|
||||
args = append(
|
||||
args,
|
||||
"-lwasi-emulated-pthread",
|
||||
"-lpthread",
|
||||
"-pthread", // global is immutable if -pthread is not specified
|
||||
// "-matomics", // undefined symbol: __atomic_load
|
||||
)
|
||||
}
|
||||
default: // ld.lld (Unix)
|
||||
args = append(
|
||||
args,
|
||||
// "-rpath", "$ORIGIN",
|
||||
// "-rpath", "$ORIGIN/../lib",
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
"-Xlinker",
|
||||
"--gc-sections",
|
||||
"-lm",
|
||||
"-latomic",
|
||||
"-lpthread", // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions.
|
||||
)
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func isWasmTarget(goos string) bool {
|
||||
return slices.Contains([]string{"wasi", "js", "wasip1"}, goos)
|
||||
}
|
||||
|
||||
func genMainModuleFile(conf *Config, rtPkgPath, mainPkgPath string, needRuntime, needPyInit bool) (path string, err error) {
|
||||
var (
|
||||
pyInitDecl string
|
||||
pyInit string
|
||||
@@ -547,12 +686,40 @@ func genMainModuleFile(rtPkgPath, mainPkgPath string, needRuntime, needPyInit bo
|
||||
pyInit = "call void @Py_Initialize()"
|
||||
pyInitDecl = "declare void @Py_Initialize()"
|
||||
}
|
||||
declSizeT := "%size_t = type i64"
|
||||
if is32Bits(conf.Goarch) {
|
||||
declSizeT = "%size_t = type i32"
|
||||
}
|
||||
stdioDecl := ""
|
||||
stdioNobuf := ""
|
||||
if IsStdioNobuf() {
|
||||
stdioDecl = `
|
||||
@stdout = external global ptr
|
||||
@stderr = external global ptr
|
||||
@__stdout = external global ptr
|
||||
@__stderr = external global ptr
|
||||
declare i32 @setvbuf(ptr, ptr, i32, %size_t)
|
||||
`
|
||||
stdioNobuf = `
|
||||
; Set stdout with no buffer
|
||||
%stdout_is_null = icmp eq ptr @stdout, null
|
||||
%stdout_ptr = select i1 %stdout_is_null, ptr @__stdout, ptr @stdout
|
||||
call i32 @setvbuf(ptr %stdout_ptr, ptr null, i32 2, %size_t 0)
|
||||
; Set stderr with no buffer
|
||||
%stderr_ptr = select i1 %stdout_is_null, ptr @__stderr, ptr @stderr
|
||||
call i32 @setvbuf(ptr %stderr_ptr, ptr null, i32 2, %size_t 0)
|
||||
`
|
||||
}
|
||||
mainDefine := "define i32 @main(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr"
|
||||
if isWasmTarget(conf.Goos) {
|
||||
mainDefine = "define hidden noundef i32 @__main_argc_argv(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr"
|
||||
}
|
||||
mainCode := fmt.Sprintf(`; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%s
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
declare void @"%s.init"()
|
||||
@@ -566,18 +733,21 @@ define weak void @"syscall.init"() {
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %%0, ptr %%1) {
|
||||
%s {
|
||||
_llgo_0:
|
||||
%s
|
||||
store i32 %%0, ptr @__llgo_argc, align 4
|
||||
store ptr %%1, ptr @__llgo_argv, align 8
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
call void @runtime.init()
|
||||
call void @"%s.init"()
|
||||
call void @"%s.main"()
|
||||
ret i32 0
|
||||
}
|
||||
`, pyInitDecl, rtInitDecl, mainPkgPath, mainPkgPath,
|
||||
`, declSizeT, stdioDecl,
|
||||
pyInitDecl, rtInitDecl, mainPkgPath, mainPkgPath,
|
||||
mainDefine, stdioNobuf,
|
||||
pyInit, rtInit, mainPkgPath, mainPkgPath)
|
||||
|
||||
f, err := os.CreateTemp("", "main*.ll")
|
||||
@@ -595,7 +765,11 @@ _llgo_0:
|
||||
return f.Name(), nil
|
||||
}
|
||||
|
||||
func buildPkg(ctx *context, aPkg *aPackage, verbose bool) (cgoLdflags []string, err error) {
|
||||
func is32Bits(goarch string) bool {
|
||||
return goarch == "386" || goarch == "arm" || goarch == "mips" || goarch == "wasm"
|
||||
}
|
||||
|
||||
func buildPkg(ctx *context, aPkg *aPackage, verbose bool) error {
|
||||
pkg := aPkg.Package
|
||||
pkgPath := pkg.PkgPath
|
||||
if debugBuild || verbose {
|
||||
@@ -603,7 +777,7 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) (cgoLdflags []string,
|
||||
}
|
||||
if llruntime.SkipToBuild(pkgPath) {
|
||||
pkg.ExportFile = ""
|
||||
return
|
||||
return nil
|
||||
}
|
||||
var syntax = pkg.Syntax
|
||||
if altPkg := aPkg.AltPkg; altPkg != nil {
|
||||
@@ -622,17 +796,26 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) (cgoLdflags []string,
|
||||
}
|
||||
check(err)
|
||||
aPkg.LPkg = ret
|
||||
cgoLdflags, err = buildCgo(ctx, aPkg, aPkg.Package.Syntax, externs, verbose)
|
||||
if aPkg.AltPkg != nil {
|
||||
altLdflags, e := buildCgo(ctx, aPkg, aPkg.AltPkg.Syntax, externs, verbose)
|
||||
if e != nil {
|
||||
return nil, fmt.Errorf("build cgo of %v failed: %v", pkgPath, e)
|
||||
cgoLLFiles, cgoLdflags, err := buildCgo(ctx, aPkg, aPkg.Package.Syntax, externs, verbose)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build cgo of %v failed: %v", pkgPath, err)
|
||||
}
|
||||
cgoLdflags = append(cgoLdflags, altLdflags...)
|
||||
aPkg.LLFiles = append(aPkg.LLFiles, cgoLLFiles...)
|
||||
aPkg.LLFiles = append(aPkg.LLFiles, concatPkgLinkFiles(ctx, pkg, verbose)...)
|
||||
aPkg.LinkArgs = append(aPkg.LinkArgs, cgoLdflags...)
|
||||
if aPkg.AltPkg != nil {
|
||||
altLLFiles, altLdflags, e := buildCgo(ctx, aPkg, aPkg.AltPkg.Syntax, externs, verbose)
|
||||
if e != nil {
|
||||
return fmt.Errorf("build cgo of %v failed: %v", pkgPath, e)
|
||||
}
|
||||
aPkg.LLFiles = append(aPkg.LLFiles, altLLFiles...)
|
||||
aPkg.LLFiles = append(aPkg.LLFiles, concatPkgLinkFiles(ctx, aPkg.AltPkg.Package, verbose)...)
|
||||
aPkg.LinkArgs = append(aPkg.LinkArgs, altLdflags...)
|
||||
}
|
||||
if pkg.ExportFile != "" {
|
||||
pkg.ExportFile += ".ll"
|
||||
os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644)
|
||||
aPkg.LLFiles = append(aPkg.LLFiles, pkg.ExportFile)
|
||||
if debugBuild || verbose {
|
||||
fmt.Fprintf(os.Stderr, "==> Export %s: %s\n", aPkg.PkgPath, pkg.ExportFile)
|
||||
}
|
||||
@@ -642,7 +825,7 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) (cgoLdflags []string,
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
func llcCheck(env *llvm.Env, exportFile string) (err error, msg string) {
|
||||
@@ -697,6 +880,7 @@ type aPackage struct {
|
||||
LPkg llssa.Package
|
||||
|
||||
LinkArgs []string
|
||||
LLFiles []string
|
||||
}
|
||||
|
||||
type Package = *aPackage
|
||||
@@ -717,7 +901,7 @@ func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aP
|
||||
return
|
||||
}
|
||||
}
|
||||
all = append(all, &aPackage{p, ssaPkg, altPkg, nil, nil})
|
||||
all = append(all, &aPackage{p, ssaPkg, altPkg, nil, nil, nil})
|
||||
} else {
|
||||
errs = append(errs, p)
|
||||
}
|
||||
@@ -762,6 +946,19 @@ const llgoTrace = "LLGO_TRACE"
|
||||
const llgoOptimize = "LLGO_OPTIMIZE"
|
||||
const llgoCheck = "LLGO_CHECK"
|
||||
const llgoRpathChange = "LLGO_RPATH_CHANGE"
|
||||
const llgoWasmRuntime = "LLGO_WASM_RUNTIME"
|
||||
const llgoWasiThreads = "LLGO_WASI_THREADS"
|
||||
const llgoStdioNobuf = "LLGO_STDIO_NOBUF"
|
||||
|
||||
const defaultWasmRuntime = "wasmtime"
|
||||
|
||||
func defaultEnv(env string, defVal string) string {
|
||||
envVal := os.Getenv(env)
|
||||
if envVal == "" {
|
||||
return defVal
|
||||
}
|
||||
return envVal
|
||||
}
|
||||
|
||||
func isEnvOn(env string, defVal bool) bool {
|
||||
envVal := strings.ToLower(os.Getenv(env))
|
||||
@@ -775,6 +972,10 @@ func IsTraceEnabled() bool {
|
||||
return isEnvOn(llgoTrace, false)
|
||||
}
|
||||
|
||||
func IsStdioNobuf() bool {
|
||||
return isEnvOn(llgoStdioNobuf, false)
|
||||
}
|
||||
|
||||
func IsDbgEnabled() bool {
|
||||
return isEnvOn(llgoDebug, false) || isEnvOn(llgoDbgSyms, false)
|
||||
}
|
||||
@@ -795,48 +996,12 @@ func IsRpathChangeEnabled() bool {
|
||||
return isEnvOn(llgoRpathChange, false)
|
||||
}
|
||||
|
||||
func ParseArgs(args []string, swflags map[string]bool) (flags, patterns []string, verbose bool) {
|
||||
n := len(args)
|
||||
for i := 0; i < n; i++ {
|
||||
arg := args[i]
|
||||
if strings.HasPrefix(arg, "-") {
|
||||
checkFlag(arg, &i, &verbose, swflags)
|
||||
} else {
|
||||
patterns = append([]string{}, args[i:]...)
|
||||
flags = append([]string{}, args[:i]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
func IsWasiThreadsEnabled() bool {
|
||||
return isEnvOn(llgoWasiThreads, true)
|
||||
}
|
||||
|
||||
func SkipFlagArgs(args []string) int {
|
||||
n := len(args)
|
||||
for i := 0; i < n; i++ {
|
||||
arg := args[i]
|
||||
if strings.HasPrefix(arg, "-") {
|
||||
checkFlag(arg, &i, nil, buildFlags)
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func checkFlag(arg string, i *int, verbose *bool, swflags map[string]bool) {
|
||||
if pos := strings.IndexByte(arg, '='); pos > 0 {
|
||||
if verbose != nil && arg == "-v=true" {
|
||||
*verbose = true
|
||||
}
|
||||
} else if hasarg, ok := swflags[arg]; ok {
|
||||
if hasarg {
|
||||
*i++
|
||||
} else if verbose != nil && arg == "-v" {
|
||||
*verbose = true
|
||||
}
|
||||
} else {
|
||||
panic("unknown flag: " + arg)
|
||||
}
|
||||
func WasmRuntime() string {
|
||||
return defaultEnv(llgoWasmRuntime, defaultWasmRuntime)
|
||||
}
|
||||
|
||||
func concatPkgLinkFiles(ctx *context, pkg *packages.Package, verbose bool) (parts []string) {
|
||||
@@ -877,11 +1042,17 @@ func clFiles(ctx *context, files string, pkg *packages.Package, procFile func(li
|
||||
|
||||
func clFile(ctx *context, args []string, cFile, expFile string, procFile func(linkFile string), verbose bool) {
|
||||
llFile := expFile + filepath.Base(cFile) + ".ll"
|
||||
targetTriple := llvmTarget.GetTargetTriple(ctx.buildConf.Goos, ctx.buildConf.Goarch)
|
||||
cflags := buildCflags(ctx.buildConf.Goos, ctx.buildConf.Goarch, targetTriple)
|
||||
args = append(cflags, args...)
|
||||
args = append(args, "-emit-llvm", "-S", "-o", llFile, "-c", cFile)
|
||||
args = append(args, ctx.crossCompile.CCFLAGS...)
|
||||
args = append(args, ctx.crossCompile.CFLAGS...)
|
||||
if verbose {
|
||||
fmt.Fprintln(os.Stderr, "clang", args)
|
||||
}
|
||||
err := ctx.env.Clang().Compile(args...)
|
||||
cmd := ctx.env.Clang()
|
||||
err := cmd.Compile(args...)
|
||||
check(err)
|
||||
procFile(llFile)
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ func mockRun(args []string, cfg *Config) {
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
mockRun([]string{"-v", "../../cl/_testgo/print"}, &Config{Mode: ModeRun})
|
||||
mockRun([]string{"../../cl/_testgo/print"}, &Config{Mode: ModeRun})
|
||||
}
|
||||
|
||||
func TestTest(t *testing.T) {
|
||||
mockRun([]string{"-v", "../../cl/_testgo/runtest"}, &Config{Mode: ModeTest})
|
||||
mockRun([]string{"../../cl/_testgo/runtest"}, &Config{Mode: ModeTest})
|
||||
}
|
||||
|
||||
func TestCmpTest(t *testing.T) {
|
||||
mockRun([]string{"-v", "../../cl/_testgo/runtest"}, &Config{Mode: ModeCmpTest})
|
||||
mockRun([]string{"../../cl/_testgo/runtest"}, &Config{Mode: ModeCmpTest})
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ static void* _Cmalloc(size_t size) {
|
||||
`
|
||||
)
|
||||
|
||||
func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs []string, verbose bool) (cgoLdflags []string, err error) {
|
||||
func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs []string, verbose bool) (llfiles, cgoLdflags []string, err error) {
|
||||
cfiles, preambles, cdecls, err := parseCgo_(pkg, files)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -87,7 +87,7 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs []string,
|
||||
}
|
||||
for _, cfile := range cfiles {
|
||||
clFile(ctx, cflags, cfile, pkg.ExportFile, func(linkFile string) {
|
||||
cgoLdflags = append(cgoLdflags, linkFile)
|
||||
llfiles = append(llfiles, linkFile)
|
||||
}, verbose)
|
||||
}
|
||||
re := regexp.MustCompile(`^(_cgo_[^_]+_(Cfunc|Cmacro)_)(.*)$`)
|
||||
@@ -117,20 +117,20 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs []string,
|
||||
for _, preamble := range preambles {
|
||||
tmpFile, err := os.CreateTemp("", "-cgo-*.c")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create temp file: %v", err)
|
||||
return nil, nil, fmt.Errorf("failed to create temp file: %v", err)
|
||||
}
|
||||
tmpName := tmpFile.Name()
|
||||
defer os.Remove(tmpName)
|
||||
code := cgoHeader + "\n\n" + preamble.src
|
||||
externDecls, err := genExternDeclsByClang(pkg, code, cflags, cgoSymbols)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate extern decls: %v", err)
|
||||
return nil, nil, fmt.Errorf("failed to generate extern decls: %v", err)
|
||||
}
|
||||
if err = os.WriteFile(tmpName, []byte(code+"\n\n"+externDecls), 0644); err != nil {
|
||||
return nil, fmt.Errorf("failed to write temp file: %v", err)
|
||||
return nil, nil, fmt.Errorf("failed to write temp file: %v", err)
|
||||
}
|
||||
clFile(ctx, cflags, tmpName, pkg.ExportFile, func(linkFile string) {
|
||||
cgoLdflags = append(cgoLdflags, linkFile)
|
||||
llfiles = append(llfiles, linkFile)
|
||||
}, verbose)
|
||||
}
|
||||
for _, ldflag := range ldflags {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/goplus/llgo/internal/packages"
|
||||
)
|
||||
@@ -32,11 +33,20 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func Clean(args []string, conf *Config) {
|
||||
flags, patterns, verbose := ParseArgs(args, cleanFlags)
|
||||
func Clean(patterns []string, conf *Config) {
|
||||
if conf.Goos == "" {
|
||||
conf.Goos = runtime.GOOS
|
||||
}
|
||||
if conf.Goarch == "" {
|
||||
conf.Goarch = runtime.GOARCH
|
||||
}
|
||||
tags := "llgo"
|
||||
if conf.Tags != "" {
|
||||
tags += "," + conf.Tags
|
||||
}
|
||||
cfg := &packages.Config{
|
||||
Mode: loadSyntax | packages.NeedExportFile,
|
||||
BuildFlags: flags,
|
||||
BuildFlags: []string{"-tags=" + tags},
|
||||
}
|
||||
|
||||
if patterns == nil {
|
||||
@@ -45,11 +55,11 @@ func Clean(args []string, conf *Config) {
|
||||
initial, err := packages.LoadEx(nil, nil, cfg, patterns...)
|
||||
check(err)
|
||||
|
||||
cleanPkgs(initial, verbose)
|
||||
cleanPkgs(initial, conf.Verbose)
|
||||
|
||||
for _, pkg := range initial {
|
||||
if pkg.Name == "main" {
|
||||
cleanMainPkg(pkg, conf, verbose)
|
||||
cleanMainPkg(pkg, conf, conf.Verbose)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
internal/crosscompile/cosscompile.go
Normal file
66
internal/crosscompile/cosscompile.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package crosscompile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/goplus/llgo/internal/env"
|
||||
"github.com/goplus/llgo/internal/xtool/llvm"
|
||||
)
|
||||
|
||||
type Export struct {
|
||||
CCFLAGS []string
|
||||
CFLAGS []string
|
||||
LDFLAGS []string
|
||||
}
|
||||
|
||||
const wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz"
|
||||
|
||||
func cacheDir() string {
|
||||
return filepath.Join(env.LLGoCacheDir(), "crosscompile")
|
||||
}
|
||||
|
||||
func UseCrossCompileSDK(goos, goarch string, wasiThreads bool) (export Export, err error) {
|
||||
if runtime.GOOS == goos && runtime.GOARCH == goarch {
|
||||
// not cross compile
|
||||
return
|
||||
}
|
||||
if goarch == "wasm" {
|
||||
sdkDir := filepath.Join(cacheDir(), llvm.GetTargetTriple(goos, goarch))
|
||||
if _, err = os.Stat(sdkDir); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return
|
||||
}
|
||||
if err = downloadAndExtract(wasiSdkUrl, sdkDir); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
triple := "wasm32-wasip1"
|
||||
if wasiThreads {
|
||||
triple = "wasm32-wasip1-threads"
|
||||
}
|
||||
// Set up flags for the SDK
|
||||
wasiSdkRoot := filepath.Join(sdkDir, "wasi-sdk-25.0-x86_64-macos")
|
||||
sysrootDir := filepath.Join(wasiSdkRoot, "share", "wasi-sysroot")
|
||||
libclangDir := filepath.Join(wasiSdkRoot, "lib", "clang", "19")
|
||||
includeDir := filepath.Join(sysrootDir, "include", triple)
|
||||
libDir := filepath.Join(sysrootDir, "lib", triple)
|
||||
|
||||
export.CCFLAGS = []string{
|
||||
"--sysroot=" + sysrootDir,
|
||||
"-resource-dir=" + libclangDir,
|
||||
}
|
||||
export.CFLAGS = []string{
|
||||
"-I" + includeDir,
|
||||
}
|
||||
export.LDFLAGS = []string{
|
||||
"-L" + libDir,
|
||||
}
|
||||
return
|
||||
}
|
||||
// TODO(lijie): supports other platforms
|
||||
return
|
||||
}
|
||||
156
internal/crosscompile/crosscompile_test.go
Normal file
156
internal/crosscompile/crosscompile_test.go
Normal file
@@ -0,0 +1,156 @@
|
||||
//go:build !llgo
|
||||
// +build !llgo
|
||||
|
||||
package crosscompile
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
sysrootPrefix = "--sysroot="
|
||||
resourceDirPrefix = "-resource-dir="
|
||||
includePrefix = "-I"
|
||||
libPrefix = "-L"
|
||||
)
|
||||
|
||||
func TestUseCrossCompileSDK(t *testing.T) {
|
||||
// Skip long-running tests unless explicitly enabled
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode")
|
||||
}
|
||||
|
||||
// Test cases
|
||||
testCases := []struct {
|
||||
name string
|
||||
goos string
|
||||
goarch string
|
||||
expectSDK bool
|
||||
expectCCFlags bool
|
||||
expectCFlags bool
|
||||
expectLDFlags bool
|
||||
}{
|
||||
{
|
||||
name: "Same Platform",
|
||||
goos: runtime.GOOS,
|
||||
goarch: runtime.GOARCH,
|
||||
expectSDK: false,
|
||||
expectCCFlags: false,
|
||||
expectCFlags: false,
|
||||
expectLDFlags: false,
|
||||
},
|
||||
{
|
||||
name: "WASM Target",
|
||||
goos: "wasip1",
|
||||
goarch: "wasm",
|
||||
expectSDK: true,
|
||||
expectCCFlags: true,
|
||||
expectCFlags: true,
|
||||
expectLDFlags: true,
|
||||
},
|
||||
{
|
||||
name: "Unsupported Target",
|
||||
goos: "windows",
|
||||
goarch: "amd64",
|
||||
expectSDK: false,
|
||||
expectCCFlags: false,
|
||||
expectCFlags: false,
|
||||
expectLDFlags: false,
|
||||
},
|
||||
}
|
||||
|
||||
// Create a temporary directory for the cache
|
||||
tempDir, err := os.MkdirTemp("", "crosscompile_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Set environment variable for cache directory
|
||||
oldEnv := os.Getenv("LLGO_CACHE_DIR")
|
||||
os.Setenv("LLGO_CACHE_DIR", tempDir)
|
||||
defer os.Setenv("LLGO_CACHE_DIR", oldEnv)
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
export, err := UseCrossCompileSDK(tc.goos, tc.goarch, false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("export: %+v", export)
|
||||
|
||||
if tc.expectSDK {
|
||||
// Check if flags are set correctly
|
||||
if tc.expectCCFlags && len(export.CCFLAGS) == 0 {
|
||||
t.Error("Expected CCFLAGS to be set, but they are empty")
|
||||
}
|
||||
|
||||
if tc.expectCFlags && len(export.CFLAGS) == 0 {
|
||||
t.Error("Expected CFLAGS to be set, but they are empty")
|
||||
}
|
||||
|
||||
if tc.expectLDFlags && len(export.LDFLAGS) == 0 {
|
||||
t.Error("Expected LDFLAGS to be set, but they are empty")
|
||||
}
|
||||
|
||||
// Check for specific flags
|
||||
if tc.expectCCFlags {
|
||||
hasSysroot := false
|
||||
hasResourceDir := false
|
||||
|
||||
for _, flag := range export.CCFLAGS {
|
||||
if len(flag) >= len(sysrootPrefix) && flag[:len(sysrootPrefix)] == sysrootPrefix {
|
||||
hasSysroot = true
|
||||
}
|
||||
if len(flag) >= len(resourceDirPrefix) && flag[:len(resourceDirPrefix)] == resourceDirPrefix {
|
||||
hasResourceDir = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasSysroot {
|
||||
t.Error("Missing --sysroot flag in CCFLAGS")
|
||||
}
|
||||
if !hasResourceDir {
|
||||
t.Error("Missing -resource-dir flag in CCFLAGS")
|
||||
}
|
||||
}
|
||||
|
||||
if tc.expectCFlags {
|
||||
hasInclude := false
|
||||
|
||||
for _, flag := range export.CFLAGS {
|
||||
if len(flag) >= len(includePrefix) && flag[:len(includePrefix)] == includePrefix {
|
||||
hasInclude = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasInclude {
|
||||
t.Error("Missing -I flag in CFLAGS")
|
||||
}
|
||||
}
|
||||
|
||||
if tc.expectLDFlags {
|
||||
hasLib := false
|
||||
|
||||
for _, flag := range export.LDFLAGS {
|
||||
if len(flag) >= len(libPrefix) && flag[:len(libPrefix)] == libPrefix {
|
||||
hasLib = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasLib {
|
||||
t.Error("Missing -L flag in LDFLAGS")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(export.CCFLAGS) != 0 || len(export.CFLAGS) != 0 || len(export.LDFLAGS) != 0 {
|
||||
t.Errorf("Expected empty export, got CCFLAGS=%v, CFLAGS=%v, LDFLAGS=%v",
|
||||
export.CCFLAGS, export.CFLAGS, export.LDFLAGS)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
109
internal/crosscompile/fetch.go
Normal file
109
internal/crosscompile/fetch.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package crosscompile
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func downloadAndExtract(url, dir string) (err error) {
|
||||
if _, err = os.Stat(dir); err == nil {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
tempDir := dir + ".temp"
|
||||
os.RemoveAll(tempDir)
|
||||
if err = os.MkdirAll(tempDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
}
|
||||
|
||||
urlPath := strings.Split(url, "/")
|
||||
filename := urlPath[len(urlPath)-1]
|
||||
localFile := filepath.Join(tempDir, filename)
|
||||
if err = downloadFile(url, localFile); err != nil {
|
||||
return fmt.Errorf("failed to download file: %w", err)
|
||||
}
|
||||
defer os.Remove(localFile)
|
||||
|
||||
if strings.HasSuffix(filename, ".tar.gz") || strings.HasSuffix(filename, ".tgz") {
|
||||
err = extractTarGz(localFile, tempDir)
|
||||
} else {
|
||||
return fmt.Errorf("unsupported archive format: %s", filename)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to extract archive: %w", err)
|
||||
}
|
||||
if err = os.Rename(tempDir, dir); err != nil {
|
||||
return fmt.Errorf("failed to rename directory: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func downloadFile(url, filepath string) error {
|
||||
out, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("bad status: %s", resp.Status)
|
||||
}
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func extractTarGz(tarGzFile, dest string) error {
|
||||
file, err := os.Open(tarGzFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
gzr, err := gzip.NewReader(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzr.Close()
|
||||
tr := tar.NewReader(gzr)
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target := filepath.Join(dest, header.Name)
|
||||
if !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("%s: illegal file path", target)
|
||||
}
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(target, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeReg:
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(f, tr); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
8
internal/env/env.go
vendored
8
internal/env/env.go
vendored
@@ -32,6 +32,14 @@ func GOROOT() string {
|
||||
panic("cannot get GOROOT: " + err.Error())
|
||||
}
|
||||
|
||||
func LLGoCacheDir() string {
|
||||
userCacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return filepath.Join(userCacheDir, "llgo")
|
||||
}
|
||||
|
||||
func LLGoRuntimeDir() string {
|
||||
root := LLGoROOT()
|
||||
if root != "" {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/goplus/llgo/internal/build"
|
||||
@@ -46,7 +47,7 @@ func genFrom(pkgPath string) (build.Package, error) {
|
||||
|
||||
conf := &build.Config{
|
||||
Mode: build.ModeGen,
|
||||
AppExt: build.DefaultAppExt(),
|
||||
AppExt: build.DefaultAppExt(runtime.GOOS),
|
||||
}
|
||||
pkgs, err := build.Do([]string{pkgPath}, conf)
|
||||
if err != nil {
|
||||
|
||||
55
internal/xtool/llvm/llvm.go
Normal file
55
internal/xtool/llvm/llvm.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package llvm
|
||||
|
||||
import "runtime"
|
||||
|
||||
func GetTargetTriple(goos, goarch string) string {
|
||||
var llvmarch string
|
||||
if goarch == "" {
|
||||
goarch = runtime.GOARCH
|
||||
}
|
||||
if goos == "" {
|
||||
goos = runtime.GOOS
|
||||
}
|
||||
switch goarch {
|
||||
case "386":
|
||||
llvmarch = "i386"
|
||||
case "amd64":
|
||||
llvmarch = "x86_64"
|
||||
case "arm64":
|
||||
llvmarch = "aarch64"
|
||||
case "arm":
|
||||
switch goarch {
|
||||
case "5":
|
||||
llvmarch = "armv5"
|
||||
case "6":
|
||||
llvmarch = "armv6"
|
||||
default:
|
||||
llvmarch = "armv7"
|
||||
}
|
||||
case "wasm":
|
||||
llvmarch = "wasm32"
|
||||
default:
|
||||
llvmarch = goarch
|
||||
}
|
||||
llvmvendor := "unknown"
|
||||
llvmos := goos
|
||||
switch goos {
|
||||
case "darwin":
|
||||
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
|
||||
// to iOS!
|
||||
llvmos = "macosx"
|
||||
if llvmarch == "aarch64" {
|
||||
// Looks like Apple prefers to call this architecture ARM64
|
||||
// instead of AArch64.
|
||||
llvmarch = "arm64"
|
||||
llvmos = "macosx"
|
||||
}
|
||||
llvmvendor = "apple"
|
||||
case "wasip1":
|
||||
llvmos = "wasip1"
|
||||
}
|
||||
// Target triples (which actually have four components, but are called
|
||||
// triples for historical reasons) have the form:
|
||||
// arch-vendor-os-environment
|
||||
return llvmarch + "-" + llvmvendor + "-" + llvmos
|
||||
}
|
||||
150
internal/xtool/llvm/llvm_test.go
Normal file
150
internal/xtool/llvm/llvm_test.go
Normal file
@@ -0,0 +1,150 @@
|
||||
//go:build !llgo
|
||||
// +build !llgo
|
||||
|
||||
package llvm
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetTargetTriple(t *testing.T) {
|
||||
// Get the list of supported architectures from clang
|
||||
cmd := exec.Command("clang", "--print-targets")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to run clang --print-targets: %v", err)
|
||||
}
|
||||
|
||||
// Parse the output to get the list of supported architectures
|
||||
supportedArchs := make(map[string]bool)
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line != "" && !strings.HasPrefix(line, "Registered Targets:") {
|
||||
// Extract the architecture from the line
|
||||
parts := strings.SplitN(line, " - ", 2)
|
||||
if len(parts) > 0 {
|
||||
arch := strings.TrimSpace(parts[0])
|
||||
supportedArchs[arch] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(supportedArchs) == 0 {
|
||||
t.Fatal("No supported architectures found from clang --print-targets")
|
||||
}
|
||||
|
||||
t.Logf("Found %d supported architectures from clang", len(supportedArchs))
|
||||
|
||||
// Map our architecture names to clang's architecture names
|
||||
clangArchMap := map[string][]string{
|
||||
"x86_64": {"x86-64", "x86_64"},
|
||||
"i386": {"x86", "i386"},
|
||||
"aarch64": {"aarch64", "arm64"},
|
||||
"arm64": {"arm64", "aarch64"},
|
||||
"armv7": {"arm", "thumb"},
|
||||
"wasm32": {"wasm32"},
|
||||
}
|
||||
|
||||
// Define a function to check if the architecture is supported by clang
|
||||
isArchSupported := func(archPart string) (bool, string) {
|
||||
if mappedArchs, ok := clangArchMap[archPart]; ok {
|
||||
for _, mappedArch := range mappedArchs {
|
||||
if supportedArchs[mappedArch] {
|
||||
return true, mappedArch
|
||||
}
|
||||
}
|
||||
} else if supportedArchs[archPart] {
|
||||
// Direct match
|
||||
return true, archPart
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// Define a function to verify OS name
|
||||
isOSValid := func(os, goos string) bool {
|
||||
validOSMap := map[string][]string{
|
||||
"linux": {"linux", "linux-gnu"},
|
||||
"darwin": {"macosx", "darwin"},
|
||||
"windows": {"windows", "win32"},
|
||||
"wasip1": {"wasip1", "wasi"},
|
||||
"js": {"js", "javascript"},
|
||||
}
|
||||
|
||||
if validVariants, ok := validOSMap[goos]; ok {
|
||||
for _, validVariant := range validVariants {
|
||||
if strings.HasPrefix(os, validVariant) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Define a function to check if vendor is valid
|
||||
isVendorValid := func(vendor string) bool {
|
||||
validVendors := map[string]bool{
|
||||
"unknown": true,
|
||||
"apple": true,
|
||||
"pc": true,
|
||||
"ibm": true,
|
||||
}
|
||||
return validVendors[vendor]
|
||||
}
|
||||
|
||||
// Define the test function
|
||||
checkTriple := func(t *testing.T, testName, goos, goarch, expected string) {
|
||||
t.Helper()
|
||||
got := GetTargetTriple(goos, goarch)
|
||||
|
||||
// Check if the generated triple matches the expected value
|
||||
if got != expected {
|
||||
t.Errorf("getTargetTriple(%q, %q) = %q, want %q",
|
||||
goos, goarch, got, expected)
|
||||
}
|
||||
|
||||
// Extract the architecture part from the triple (first component)
|
||||
parts := strings.Split(got, "-")
|
||||
if len(parts) < 3 {
|
||||
t.Errorf("Invalid target triple format: %s, should have at least 3 components", got)
|
||||
return
|
||||
}
|
||||
|
||||
archPart := parts[0]
|
||||
vendor := parts[1]
|
||||
os := parts[2]
|
||||
|
||||
// Check if the architecture is supported by clang
|
||||
supported, mappedArch := isArchSupported(archPart)
|
||||
if supported {
|
||||
t.Logf("Architecture %s (mapped to %s) is supported by clang", archPart, mappedArch)
|
||||
} else {
|
||||
t.Logf("WARNING: Architecture %s from triple %q for %s/%s not found in clang's supported architectures",
|
||||
archPart, got, goos, goarch)
|
||||
}
|
||||
|
||||
// Verify vendor
|
||||
if !isVendorValid(vendor) {
|
||||
t.Errorf("Invalid vendor in triple: %s", vendor)
|
||||
}
|
||||
|
||||
// Verify OS
|
||||
if !isOSValid(os, goos) {
|
||||
t.Errorf("OS in triple %q doesn't match expected OS %q", os, goos)
|
||||
}
|
||||
}
|
||||
|
||||
// Run tests for different OS/arch combinations
|
||||
checkTriple(t, "wasip1/wasm", "wasip1", "wasm", "wasm32-unknown-wasip1")
|
||||
checkTriple(t, "linux/amd64", "linux", "amd64", "x86_64-unknown-linux")
|
||||
checkTriple(t, "linux/386", "linux", "386", "i386-unknown-linux")
|
||||
checkTriple(t, "linux/arm64", "linux", "arm64", "aarch64-unknown-linux")
|
||||
checkTriple(t, "linux/arm", "linux", "arm", "armv7-unknown-linux")
|
||||
checkTriple(t, "darwin/amd64", "darwin", "amd64", "x86_64-apple-macosx")
|
||||
checkTriple(t, "darwin/arm64", "darwin", "arm64", "arm64-apple-macosx")
|
||||
checkTriple(t, "windows/amd64", "windows", "amd64", "x86_64-unknown-windows")
|
||||
checkTriple(t, "windows/386", "windows", "386", "i386-unknown-windows")
|
||||
checkTriple(t, "js/wasm", "js", "wasm", "wasm32-unknown-js")
|
||||
}
|
||||
11
llgo_wasm
Executable file
11
llgo_wasm
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
WORKDIR=''
|
||||
WORKDIR=$(pwd)
|
||||
LLGO_ROOT=''
|
||||
LLGO_ROOT=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )
|
||||
export LLGO_ROOT
|
||||
cd $LLGO_ROOT
|
||||
go install ./cmd/llgo
|
||||
cd $WORKDIR
|
||||
GOOS=wasip1 GOARCH=wasm llgo "$@"
|
||||
@@ -24,11 +24,6 @@
|
||||
// with a single network connection.
|
||||
package textproto
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
@@ -97,55 +92,55 @@ const (
|
||||
type SockAddr struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Data [14]C.char
|
||||
Data [14]uint8
|
||||
}
|
||||
|
||||
type AddrInfo struct {
|
||||
Flags C.int
|
||||
Family C.int
|
||||
SockType C.int
|
||||
Protocol C.int
|
||||
AddrLen C.uint
|
||||
CanOnName *C.char
|
||||
Flags int32
|
||||
Family int32
|
||||
SockType int32
|
||||
Protocol int32
|
||||
AddrLen uint32
|
||||
CanOnName *uint8
|
||||
Addr *SockAddr
|
||||
Next *AddrInfo
|
||||
}
|
||||
|
||||
//go:linkname Getaddrinfo C.getaddrinfo
|
||||
func Getaddrinfo(host *C.char, port *C.char, addrInfo *AddrInfo, result **AddrInfo) C.int
|
||||
func Getaddrinfo(host *uint8, port *uint8, addrInfo *AddrInfo, result **AddrInfo) int32
|
||||
|
||||
//go:linkname Freeaddrinfo C.freeaddrinfo
|
||||
func Freeaddrinfo(addrInfo *AddrInfo) C.int
|
||||
func Freeaddrinfo(addrInfo *AddrInfo) int32
|
||||
|
||||
//go:linkname GoString llgo.string
|
||||
func GoString(cstr *C.char, __llgo_va_list /* n */ ...any) string
|
||||
func GoString(cstr *uint8, __llgo_va_list /* n */ ...any) string
|
||||
|
||||
//go:linkname AllocaCStr llgo.allocaCStr
|
||||
func AllocaCStr(s string) *C.char
|
||||
func AllocaCStr(s string) *uint8
|
||||
|
||||
//go:linkname Memset C.memset
|
||||
func Memset(s unsafe.Pointer, c C.int, n uintptr) unsafe.Pointer
|
||||
func Memset(s unsafe.Pointer, c int32, n uintptr) unsafe.Pointer
|
||||
|
||||
//go:linkname Read C.read
|
||||
func Read(fd C.int, buf unsafe.Pointer, count uintptr) int
|
||||
func Read(fd int32, buf unsafe.Pointer, count uintptr) int
|
||||
|
||||
//go:linkname Write C.write
|
||||
func Write(fd C.int, buf unsafe.Pointer, count uintptr) int
|
||||
func Write(fd int32, buf unsafe.Pointer, count uintptr) int
|
||||
|
||||
//go:linkname Close C.close
|
||||
func Close(fd C.int) C.int
|
||||
func Close(fd int32) int32
|
||||
|
||||
//go:linkname Strerror strerror
|
||||
func Strerror(errnum C.int) *C.char
|
||||
func Strerror(errnum int32) *uint8
|
||||
|
||||
//go:linkname Errno C.cliteErrno
|
||||
func Errno() C.int
|
||||
func Errno() int32
|
||||
|
||||
//go:linkname Socket C.socket
|
||||
func Socket(domain C.int, typ C.int, protocol C.int) C.int
|
||||
func Socket(domain int32, typ int32, protocol int32) int32
|
||||
|
||||
//go:linkname Connect C.connect
|
||||
func Connect(sockfd C.int, addr *SockAddr, addrlen C.uint) C.int
|
||||
func Connect(sockfd int32, addr *SockAddr, addrlen uint32) int32
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -204,7 +199,7 @@ func Dial(network, addr string) (*Conn, error) {
|
||||
}
|
||||
|
||||
type cConn struct {
|
||||
socketFd C.int
|
||||
socketFd int32
|
||||
closed bool
|
||||
}
|
||||
|
||||
@@ -218,7 +213,7 @@ func (conn *cConn) Read(p []byte) (n int, err error) {
|
||||
for n < len(p) {
|
||||
result := Read(conn.socketFd, unsafe.Pointer(&p[n:][0]), uintptr(len(p)-n))
|
||||
if result < 0 {
|
||||
if Errno() == C.int(syscall.EINTR) {
|
||||
if Errno() == int32(syscall.EINTR) {
|
||||
continue
|
||||
}
|
||||
return n, errors.New("read error")
|
||||
@@ -238,7 +233,7 @@ func (conn *cConn) Write(p []byte) (n int, err error) {
|
||||
for n < len(p) {
|
||||
result := Write(conn.socketFd, unsafe.Pointer(&p[n:][0]), uintptr(len(p)-n))
|
||||
if result < 0 {
|
||||
if Errno() == C.int(syscall.EINTR) {
|
||||
if Errno() == int32(syscall.EINTR) {
|
||||
continue
|
||||
}
|
||||
return n, errors.New("write error")
|
||||
|
||||
482
runtime/_overlay/runtime/runtime.go
Normal file
482
runtime/_overlay/runtime/runtime.go
Normal file
@@ -0,0 +1,482 @@
|
||||
package runtime
|
||||
|
||||
func Goexit() {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func KeepAlive(x any) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func SetFinalizer(obj any, finalizer any) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
const GOOS = ""
|
||||
const GOARCH = ""
|
||||
|
||||
func GOMAXPROCS(n int) int {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func GC() {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func GOROOT() string {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func Callers(skip int, pc []uintptr) int {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
type Func struct {
|
||||
opaque struct{} // unexported field to disallow conversions
|
||||
}
|
||||
|
||||
func (f *Func) Name() string {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func FuncForPC(pc uintptr) *Func {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
type nih struct{}
|
||||
|
||||
type NotInHeap struct{ _ nih }
|
||||
|
||||
type FuncID uint8
|
||||
|
||||
type FuncFlag uint8
|
||||
|
||||
type _func struct {
|
||||
NotInHeap // Only in static data
|
||||
|
||||
entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
|
||||
nameOff int32 // function name, as index into moduledata.funcnametab.
|
||||
|
||||
args int32 // in/out args size
|
||||
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
|
||||
|
||||
pcsp uint32
|
||||
pcfile uint32
|
||||
pcln uint32
|
||||
npcdata uint32
|
||||
cuOffset uint32 // runtime.cutab offset of this function's CU
|
||||
startLine int32 // line number of start of function (func keyword/TEXT directive)
|
||||
funcID FuncID // set for certain special runtime functions
|
||||
flag FuncFlag
|
||||
_ [1]byte // pad
|
||||
nfuncdata uint8 // must be last, must end on a uint32-aligned boundary
|
||||
}
|
||||
|
||||
type moduledata struct{}
|
||||
|
||||
type funcInfo struct {
|
||||
*_func
|
||||
datap *moduledata
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
PC uintptr
|
||||
Func *Func
|
||||
Function string
|
||||
File string
|
||||
Line int
|
||||
startLine int
|
||||
Entry uintptr
|
||||
funcInfo funcInfo
|
||||
}
|
||||
|
||||
type Frames struct {
|
||||
callers []uintptr
|
||||
nextPC uintptr
|
||||
frames []Frame
|
||||
frameStore [2]Frame
|
||||
}
|
||||
|
||||
func (ci *Frames) Next() (frame Frame, more bool) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func CallersFrames(callers []uintptr) *Frames {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func Stack(buf []byte, all bool) int {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func Version() string {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
type MemStats struct {
|
||||
// General statistics.
|
||||
|
||||
// Alloc is bytes of allocated heap objects.
|
||||
//
|
||||
// This is the same as HeapAlloc (see below).
|
||||
Alloc uint64
|
||||
|
||||
// TotalAlloc is cumulative bytes allocated for heap objects.
|
||||
//
|
||||
// TotalAlloc increases as heap objects are allocated, but
|
||||
// unlike Alloc and HeapAlloc, it does not decrease when
|
||||
// objects are freed.
|
||||
TotalAlloc uint64
|
||||
|
||||
// Sys is the total bytes of memory obtained from the OS.
|
||||
//
|
||||
// Sys is the sum of the XSys fields below. Sys measures the
|
||||
// virtual address space reserved by the Go runtime for the
|
||||
// heap, stacks, and other internal data structures. It's
|
||||
// likely that not all of the virtual address space is backed
|
||||
// by physical memory at any given moment, though in general
|
||||
// it all was at some point.
|
||||
Sys uint64
|
||||
|
||||
// Lookups is the number of pointer lookups performed by the
|
||||
// runtime.
|
||||
//
|
||||
// This is primarily useful for debugging runtime internals.
|
||||
Lookups uint64
|
||||
|
||||
// Mallocs is the cumulative count of heap objects allocated.
|
||||
// The number of live objects is Mallocs - Frees.
|
||||
Mallocs uint64
|
||||
|
||||
// Frees is the cumulative count of heap objects freed.
|
||||
Frees uint64
|
||||
|
||||
// Heap memory statistics.
|
||||
//
|
||||
// Interpreting the heap statistics requires some knowledge of
|
||||
// how Go organizes memory. Go divides the virtual address
|
||||
// space of the heap into "spans", which are contiguous
|
||||
// regions of memory 8K or larger. A span may be in one of
|
||||
// three states:
|
||||
//
|
||||
// An "idle" span contains no objects or other data. The
|
||||
// physical memory backing an idle span can be released back
|
||||
// to the OS (but the virtual address space never is), or it
|
||||
// can be converted into an "in use" or "stack" span.
|
||||
//
|
||||
// An "in use" span contains at least one heap object and may
|
||||
// have free space available to allocate more heap objects.
|
||||
//
|
||||
// A "stack" span is used for goroutine stacks. Stack spans
|
||||
// are not considered part of the heap. A span can change
|
||||
// between heap and stack memory; it is never used for both
|
||||
// simultaneously.
|
||||
|
||||
// HeapAlloc is bytes of allocated heap objects.
|
||||
//
|
||||
// "Allocated" heap objects include all reachable objects, as
|
||||
// well as unreachable objects that the garbage collector has
|
||||
// not yet freed. Specifically, HeapAlloc increases as heap
|
||||
// objects are allocated and decreases as the heap is swept
|
||||
// and unreachable objects are freed. Sweeping occurs
|
||||
// incrementally between GC cycles, so these two processes
|
||||
// occur simultaneously, and as a result HeapAlloc tends to
|
||||
// change smoothly (in contrast with the sawtooth that is
|
||||
// typical of stop-the-world garbage collectors).
|
||||
HeapAlloc uint64
|
||||
|
||||
// HeapSys is bytes of heap memory obtained from the OS.
|
||||
//
|
||||
// HeapSys measures the amount of virtual address space
|
||||
// reserved for the heap. This includes virtual address space
|
||||
// that has been reserved but not yet used, which consumes no
|
||||
// physical memory, but tends to be small, as well as virtual
|
||||
// address space for which the physical memory has been
|
||||
// returned to the OS after it became unused (see HeapReleased
|
||||
// for a measure of the latter).
|
||||
//
|
||||
// HeapSys estimates the largest size the heap has had.
|
||||
HeapSys uint64
|
||||
|
||||
// HeapIdle is bytes in idle (unused) spans.
|
||||
//
|
||||
// Idle spans have no objects in them. These spans could be
|
||||
// (and may already have been) returned to the OS, or they can
|
||||
// be reused for heap allocations, or they can be reused as
|
||||
// stack memory.
|
||||
//
|
||||
// HeapIdle minus HeapReleased estimates the amount of memory
|
||||
// that could be returned to the OS, but is being retained by
|
||||
// the runtime so it can grow the heap without requesting more
|
||||
// memory from the OS. If this difference is significantly
|
||||
// larger than the heap size, it indicates there was a recent
|
||||
// transient spike in live heap size.
|
||||
HeapIdle uint64
|
||||
|
||||
// HeapInuse is bytes in in-use spans.
|
||||
//
|
||||
// In-use spans have at least one object in them. These spans
|
||||
// can only be used for other objects of roughly the same
|
||||
// size.
|
||||
//
|
||||
// HeapInuse minus HeapAlloc estimates the amount of memory
|
||||
// that has been dedicated to particular size classes, but is
|
||||
// not currently being used. This is an upper bound on
|
||||
// fragmentation, but in general this memory can be reused
|
||||
// efficiently.
|
||||
HeapInuse uint64
|
||||
|
||||
// HeapReleased is bytes of physical memory returned to the OS.
|
||||
//
|
||||
// This counts heap memory from idle spans that was returned
|
||||
// to the OS and has not yet been reacquired for the heap.
|
||||
HeapReleased uint64
|
||||
|
||||
// HeapObjects is the number of allocated heap objects.
|
||||
//
|
||||
// Like HeapAlloc, this increases as objects are allocated and
|
||||
// decreases as the heap is swept and unreachable objects are
|
||||
// freed.
|
||||
HeapObjects uint64
|
||||
|
||||
// Stack memory statistics.
|
||||
//
|
||||
// Stacks are not considered part of the heap, but the runtime
|
||||
// can reuse a span of heap memory for stack memory, and
|
||||
// vice-versa.
|
||||
|
||||
// StackInuse is bytes in stack spans.
|
||||
//
|
||||
// In-use stack spans have at least one stack in them. These
|
||||
// spans can only be used for other stacks of the same size.
|
||||
//
|
||||
// There is no StackIdle because unused stack spans are
|
||||
// returned to the heap (and hence counted toward HeapIdle).
|
||||
StackInuse uint64
|
||||
|
||||
// StackSys is bytes of stack memory obtained from the OS.
|
||||
//
|
||||
// StackSys is StackInuse, plus any memory obtained directly
|
||||
// from the OS for OS thread stacks.
|
||||
//
|
||||
// In non-cgo programs this metric is currently equal to StackInuse
|
||||
// (but this should not be relied upon, and the value may change in
|
||||
// the future).
|
||||
//
|
||||
// In cgo programs this metric includes OS thread stacks allocated
|
||||
// directly from the OS. Currently, this only accounts for one stack in
|
||||
// c-shared and c-archive build modes and other sources of stacks from
|
||||
// the OS (notably, any allocated by C code) are not currently measured.
|
||||
// Note this too may change in the future.
|
||||
StackSys uint64
|
||||
|
||||
// Off-heap memory statistics.
|
||||
//
|
||||
// The following statistics measure runtime-internal
|
||||
// structures that are not allocated from heap memory (usually
|
||||
// because they are part of implementing the heap). Unlike
|
||||
// heap or stack memory, any memory allocated to these
|
||||
// structures is dedicated to these structures.
|
||||
//
|
||||
// These are primarily useful for debugging runtime memory
|
||||
// overheads.
|
||||
|
||||
// MSpanInuse is bytes of allocated mspan structures.
|
||||
MSpanInuse uint64
|
||||
|
||||
// MSpanSys is bytes of memory obtained from the OS for mspan
|
||||
// structures.
|
||||
MSpanSys uint64
|
||||
|
||||
// MCacheInuse is bytes of allocated mcache structures.
|
||||
MCacheInuse uint64
|
||||
|
||||
// MCacheSys is bytes of memory obtained from the OS for
|
||||
// mcache structures.
|
||||
MCacheSys uint64
|
||||
|
||||
// BuckHashSys is bytes of memory in profiling bucket hash tables.
|
||||
BuckHashSys uint64
|
||||
|
||||
// GCSys is bytes of memory in garbage collection metadata.
|
||||
GCSys uint64
|
||||
|
||||
// OtherSys is bytes of memory in miscellaneous off-heap
|
||||
// runtime allocations.
|
||||
OtherSys uint64
|
||||
|
||||
// Garbage collector statistics.
|
||||
|
||||
// NextGC is the target heap size of the next GC cycle.
|
||||
//
|
||||
// The garbage collector's goal is to keep HeapAlloc ≤ NextGC.
|
||||
// At the end of each GC cycle, the target for the next cycle
|
||||
// is computed based on the amount of reachable data and the
|
||||
// value of GOGC.
|
||||
NextGC uint64
|
||||
|
||||
// LastGC is the time the last garbage collection finished, as
|
||||
// nanoseconds since 1970 (the UNIX epoch).
|
||||
LastGC uint64
|
||||
|
||||
// PauseTotalNs is the cumulative nanoseconds in GC
|
||||
// stop-the-world pauses since the program started.
|
||||
//
|
||||
// During a stop-the-world pause, all goroutines are paused
|
||||
// and only the garbage collector can run.
|
||||
PauseTotalNs uint64
|
||||
|
||||
// PauseNs is a circular buffer of recent GC stop-the-world
|
||||
// pause times in nanoseconds.
|
||||
//
|
||||
// The most recent pause is at PauseNs[(NumGC+255)%256]. In
|
||||
// general, PauseNs[N%256] records the time paused in the most
|
||||
// recent N%256th GC cycle. There may be multiple pauses per
|
||||
// GC cycle; this is the sum of all pauses during a cycle.
|
||||
PauseNs [256]uint64
|
||||
|
||||
// PauseEnd is a circular buffer of recent GC pause end times,
|
||||
// as nanoseconds since 1970 (the UNIX epoch).
|
||||
//
|
||||
// This buffer is filled the same way as PauseNs. There may be
|
||||
// multiple pauses per GC cycle; this records the end of the
|
||||
// last pause in a cycle.
|
||||
PauseEnd [256]uint64
|
||||
|
||||
// NumGC is the number of completed GC cycles.
|
||||
NumGC uint32
|
||||
|
||||
// NumForcedGC is the number of GC cycles that were forced by
|
||||
// the application calling the GC function.
|
||||
NumForcedGC uint32
|
||||
|
||||
// GCCPUFraction is the fraction of this program's available
|
||||
// CPU time used by the GC since the program started.
|
||||
//
|
||||
// GCCPUFraction is expressed as a number between 0 and 1,
|
||||
// where 0 means GC has consumed none of this program's CPU. A
|
||||
// program's available CPU time is defined as the integral of
|
||||
// GOMAXPROCS since the program started. That is, if
|
||||
// GOMAXPROCS is 2 and a program has been running for 10
|
||||
// seconds, its "available CPU" is 20 seconds. GCCPUFraction
|
||||
// does not include CPU time used for write barrier activity.
|
||||
//
|
||||
// This is the same as the fraction of CPU reported by
|
||||
// GODEBUG=gctrace=1.
|
||||
GCCPUFraction float64
|
||||
|
||||
// EnableGC indicates that GC is enabled. It is always true,
|
||||
// even if GOGC=off.
|
||||
EnableGC bool
|
||||
|
||||
// DebugGC is currently unused.
|
||||
DebugGC bool
|
||||
|
||||
// BySize reports per-size class allocation statistics.
|
||||
//
|
||||
// BySize[N] gives statistics for allocations of size S where
|
||||
// BySize[N-1].Size < S ≤ BySize[N].Size.
|
||||
//
|
||||
// This does not report allocations larger than BySize[60].Size.
|
||||
BySize [61]struct {
|
||||
// Size is the maximum byte size of an object in this
|
||||
// size class.
|
||||
Size uint32
|
||||
|
||||
// Mallocs is the cumulative count of heap objects
|
||||
// allocated in this size class. The cumulative bytes
|
||||
// of allocation is Size*Mallocs. The number of live
|
||||
// objects in this size class is Mallocs - Frees.
|
||||
Mallocs uint64
|
||||
|
||||
// Frees is the cumulative count of heap objects freed
|
||||
// in this size class.
|
||||
Frees uint64
|
||||
}
|
||||
}
|
||||
|
||||
func ReadMemStats(m *MemStats) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
type MemProfileRecord struct {
|
||||
AllocBytes, FreeBytes int64 // number of bytes allocated, freed
|
||||
AllocObjects, FreeObjects int64 // number of objects allocated, freed
|
||||
Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
|
||||
}
|
||||
|
||||
// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
|
||||
func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
|
||||
|
||||
// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
|
||||
func (r *MemProfileRecord) InUseObjects() int64 {
|
||||
return r.AllocObjects - r.FreeObjects
|
||||
}
|
||||
|
||||
var MemProfileRate int = 512 * 1024
|
||||
|
||||
func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func StartTrace() error {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func StopTrace() {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func ReadTrace() []byte {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func SetBlockProfileRate(rate int) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func SetMutexProfileFraction(rate int) int {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func LockOSThread() {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func UnlockOSThread() {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
type StackRecord struct {
|
||||
Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
|
||||
}
|
||||
|
||||
func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func NumGoroutine() int {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func SetCPUProfileRate(hz int) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
type BlockProfileRecord struct {
|
||||
Count int64
|
||||
Cycles int64
|
||||
StackRecord
|
||||
}
|
||||
|
||||
func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func MutexProfile(p []BlockProfileRecord) (n int, ok bool) {
|
||||
panic("todo")
|
||||
}
|
||||
@@ -342,14 +342,28 @@ func (t *UncommonType) Methods() []Method {
|
||||
if t.Mcount == 0 {
|
||||
return nil
|
||||
}
|
||||
return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount]
|
||||
methodsPtr := addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0")
|
||||
methods := make([]Method, t.Mcount)
|
||||
for i := 0; i < int(t.Mcount); i++ {
|
||||
elemPtr := addChecked(methodsPtr, uintptr(i)*unsafe.Sizeof(Method{}), "accessing method element")
|
||||
elem := (*Method)(elemPtr)
|
||||
methods[i] = *elem
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func (t *UncommonType) ExportedMethods() []Method {
|
||||
if t.Xcount == 0 {
|
||||
return nil
|
||||
}
|
||||
return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount]
|
||||
mthdsPtr := addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0")
|
||||
mthds := make([]Method, t.Xcount)
|
||||
for i := 0; i < int(t.Xcount); i++ {
|
||||
elemPtr := addChecked(mthdsPtr, uintptr(i)*unsafe.Sizeof(Method{}), "accessing method element")
|
||||
elem := (*Method)(elemPtr)
|
||||
mthds[i] = *elem
|
||||
}
|
||||
return mthds
|
||||
}
|
||||
|
||||
// Imethod represents a method on an interface type
|
||||
|
||||
@@ -26,12 +26,17 @@ var hasAltPkg = map[string]none{
|
||||
"hash/crc32": {},
|
||||
"internal/abi": {},
|
||||
"internal/bytealg": {},
|
||||
"internal/chacha8rand": {},
|
||||
"internal/cpu": {},
|
||||
"internal/itoa": {},
|
||||
"internal/godebug": {},
|
||||
"internal/oserror": {},
|
||||
"internal/poll": {},
|
||||
"internal/reflectlite": {},
|
||||
"internal/runtime/atomic": {},
|
||||
"internal/runtime/maps": {},
|
||||
"internal/runtime/sys": {},
|
||||
"internal/sync": {},
|
||||
"internal/syscall/execenv": {},
|
||||
"internal/syscall/unix": {},
|
||||
"math": {},
|
||||
@@ -52,4 +57,5 @@ var hasAltPkg = map[string]none{
|
||||
"runtime/trace": {},
|
||||
"runtime/internal/syscall": {},
|
||||
"io": {},
|
||||
"io/fs": {},
|
||||
}
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
typedef union {
|
||||
typedef union
|
||||
{
|
||||
double d;
|
||||
float f;
|
||||
long v;
|
||||
long long ll;
|
||||
} castUnion;
|
||||
|
||||
double llgoToFloat64(long v) {
|
||||
double llgoToFloat64(long long v)
|
||||
{
|
||||
castUnion k;
|
||||
k.v = v;
|
||||
k.ll = v;
|
||||
return k.d;
|
||||
}
|
||||
|
||||
float llgoToFloat32(long v) {
|
||||
float llgoToFloat32(int v)
|
||||
{
|
||||
castUnion k;
|
||||
k.v = v;
|
||||
return k.f;
|
||||
}
|
||||
|
||||
long llgoFromFloat64(double v) {
|
||||
long long llgoFromFloat64(double v)
|
||||
{
|
||||
castUnion k;
|
||||
k.d = v;
|
||||
return k.v;
|
||||
return k.ll;
|
||||
}
|
||||
|
||||
long llgoFromFloat32(float v) {
|
||||
int llgoFromFloat32(float v)
|
||||
{
|
||||
castUnion k;
|
||||
k.f = v;
|
||||
return k.v;
|
||||
|
||||
@@ -24,13 +24,13 @@ const (
|
||||
)
|
||||
|
||||
//go:linkname ToFloat64 C.llgoToFloat64
|
||||
func ToFloat64(v uintptr) float64
|
||||
func ToFloat64(v int64) float64
|
||||
|
||||
//go:linkname ToFloat32 C.llgoToFloat32
|
||||
func ToFloat32(v uintptr) float32
|
||||
func ToFloat32(v int32) float32
|
||||
|
||||
//go:linkname FromFloat64 C.llgoFromFloat64
|
||||
func FromFloat64(v float64) uintptr
|
||||
func FromFloat64(v float64) int64
|
||||
|
||||
//go:linkname FromFloat32 C.llgoFromFloat32
|
||||
func FromFloat32(v float32) uintptr
|
||||
func FromFloat32(v float32) int32
|
||||
|
||||
149
runtime/internal/clite/byteorder/byteorder.go
Normal file
149
runtime/internal/clite/byteorder/byteorder.go
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package byteorder provides functions for decoding and encoding
|
||||
// little and big endian integer types from/to byte slices.
|
||||
package byteorder
|
||||
|
||||
func LEUint16(b []byte) uint16 {
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func LEPutUint16(b []byte, v uint16) {
|
||||
_ = b[1] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
}
|
||||
|
||||
func LEAppendUint16(b []byte, v uint16) []byte {
|
||||
return append(b,
|
||||
byte(v),
|
||||
byte(v>>8),
|
||||
)
|
||||
}
|
||||
|
||||
func LEUint32(b []byte) uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
func LEPutUint32(b []byte, v uint32) {
|
||||
_ = b[3] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
}
|
||||
|
||||
func LEAppendUint32(b []byte, v uint32) []byte {
|
||||
return append(b,
|
||||
byte(v),
|
||||
byte(v>>8),
|
||||
byte(v>>16),
|
||||
byte(v>>24),
|
||||
)
|
||||
}
|
||||
|
||||
func LEUint64(b []byte) uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
}
|
||||
|
||||
func LEPutUint64(b []byte, v uint64) {
|
||||
_ = b[7] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
}
|
||||
|
||||
func LEAppendUint64(b []byte, v uint64) []byte {
|
||||
return append(b,
|
||||
byte(v),
|
||||
byte(v>>8),
|
||||
byte(v>>16),
|
||||
byte(v>>24),
|
||||
byte(v>>32),
|
||||
byte(v>>40),
|
||||
byte(v>>48),
|
||||
byte(v>>56),
|
||||
)
|
||||
}
|
||||
|
||||
func BEUint16(b []byte) uint16 {
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint16(b[1]) | uint16(b[0])<<8
|
||||
}
|
||||
|
||||
func BEPutUint16(b []byte, v uint16) {
|
||||
_ = b[1] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v >> 8)
|
||||
b[1] = byte(v)
|
||||
}
|
||||
|
||||
func BEAppendUint16(b []byte, v uint16) []byte {
|
||||
return append(b,
|
||||
byte(v>>8),
|
||||
byte(v),
|
||||
)
|
||||
}
|
||||
|
||||
func BEUint32(b []byte) uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
|
||||
}
|
||||
|
||||
func BEPutUint32(b []byte, v uint32) {
|
||||
_ = b[3] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v >> 24)
|
||||
b[1] = byte(v >> 16)
|
||||
b[2] = byte(v >> 8)
|
||||
b[3] = byte(v)
|
||||
}
|
||||
|
||||
func BEAppendUint32(b []byte, v uint32) []byte {
|
||||
return append(b,
|
||||
byte(v>>24),
|
||||
byte(v>>16),
|
||||
byte(v>>8),
|
||||
byte(v),
|
||||
)
|
||||
}
|
||||
|
||||
func BEUint64(b []byte) uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
}
|
||||
|
||||
func BEPutUint64(b []byte, v uint64) {
|
||||
_ = b[7] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v >> 56)
|
||||
b[1] = byte(v >> 48)
|
||||
b[2] = byte(v >> 40)
|
||||
b[3] = byte(v >> 32)
|
||||
b[4] = byte(v >> 24)
|
||||
b[5] = byte(v >> 16)
|
||||
b[6] = byte(v >> 8)
|
||||
b[7] = byte(v)
|
||||
}
|
||||
|
||||
func BEAppendUint64(b []byte, v uint64) []byte {
|
||||
return append(b,
|
||||
byte(v>>56),
|
||||
byte(v>>48),
|
||||
byte(v>>40),
|
||||
byte(v>>32),
|
||||
byte(v>>24),
|
||||
byte(v>>16),
|
||||
byte(v>>8),
|
||||
byte(v),
|
||||
)
|
||||
}
|
||||
@@ -14,14 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package clite
|
||||
package c
|
||||
|
||||
// typedef unsigned int uint;
|
||||
// typedef unsigned long ulong;
|
||||
// typedef unsigned long long ulonglong;
|
||||
// typedef long long longlong;
|
||||
import "C"
|
||||
import "unsafe"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
@@ -41,14 +38,16 @@ type FILE struct {
|
||||
}
|
||||
|
||||
type (
|
||||
Int C.int
|
||||
Uint C.uint
|
||||
Int = int32
|
||||
Uint = uint32
|
||||
|
||||
Long C.long
|
||||
Ulong C.ulong
|
||||
// Long and Ulong are defined in platform-specific files
|
||||
// Windows (both 32-bit and 64-bit): int32/uint32
|
||||
// Unix/Linux/macOS 32-bit: int32/uint32
|
||||
// Unix/Linux/macOS 64-bit: int64/uint64
|
||||
|
||||
LongLong C.longlong
|
||||
UlongLong C.ulonglong
|
||||
LongLong = int64
|
||||
UlongLong = uint64
|
||||
)
|
||||
|
||||
type integer interface {
|
||||
@@ -56,6 +55,7 @@ type integer interface {
|
||||
}
|
||||
|
||||
type SizeT = uintptr
|
||||
type SsizeT = Long
|
||||
|
||||
type IntptrT = uintptr
|
||||
type UintptrT = uintptr
|
||||
@@ -72,6 +72,8 @@ type Uint64T = uint64
|
||||
type IntmaxT = LongLong
|
||||
type UintmaxT = UlongLong
|
||||
|
||||
type VaList = Pointer
|
||||
|
||||
//go:linkname Str llgo.cstr
|
||||
func Str(string) *Char
|
||||
|
||||
@@ -90,6 +92,9 @@ func Alloca(size uintptr) Pointer
|
||||
//go:linkname AllocaCStr llgo.allocaCStr
|
||||
func AllocaCStr(s string) *Char
|
||||
|
||||
//go:linkname AllocCStr llgo.allocCStr
|
||||
func AllocCStr(s string) *Char
|
||||
|
||||
//go:linkname AllocaCStrs llgo.allocaCStrs
|
||||
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
||||
|
||||
@@ -257,6 +262,14 @@ func Perror(s *Char)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type IconvT = Pointer
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type LocaleT = Pointer
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Usleep C.usleep
|
||||
func Usleep(useconds Uint) Int
|
||||
|
||||
@@ -297,6 +310,3 @@ func GetoptLong(argc Int, argv **Char, optstring *Char, longopts *Option, longin
|
||||
func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Sysconf C.sysconf
|
||||
func Sysconf(name Int) Long
|
||||
|
||||
27
runtime/internal/clite/ctypes_32bit.go
Normal file
27
runtime/internal/clite/ctypes_32bit.go
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build (linux || darwin || freebsd || netbsd || openbsd || solaris) && (386 || arm || mips || mipsle)
|
||||
// +build linux darwin freebsd netbsd openbsd solaris
|
||||
// +build 386 arm mips mipsle
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package c
|
||||
|
||||
// For 32-bit Unix/Linux/macOS, Long is 32-bit
|
||||
type (
|
||||
Long = int32
|
||||
Ulong = uint32
|
||||
)
|
||||
27
runtime/internal/clite/ctypes_unix64.go
Normal file
27
runtime/internal/clite/ctypes_unix64.go
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build (linux || darwin || freebsd || netbsd || openbsd || solaris) && (amd64 || arm64 || ppc64 || ppc64le || mips64 || mips64le || s390x || riscv64)
|
||||
// +build linux darwin freebsd netbsd openbsd solaris
|
||||
// +build amd64 arm64 ppc64 ppc64le mips64 mips64le s390x riscv64
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package c
|
||||
|
||||
// For 64-bit Unix/Linux/macOS, Long is 64-bit
|
||||
type (
|
||||
Long = int64
|
||||
Ulong = uint64
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
//go:build linux
|
||||
//go:build wasip1 || js
|
||||
// +build wasip1 js
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
@@ -16,14 +17,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package os
|
||||
package c
|
||||
|
||||
import "C"
|
||||
|
||||
const (
|
||||
LLGoFiles = "_os/os.c"
|
||||
LLGoPackage = "link"
|
||||
// For WebAssembly targets, Long is 32-bit per the spec
|
||||
type (
|
||||
Long = int32
|
||||
Ulong = uint32
|
||||
)
|
||||
|
||||
//go:linkname Clearenv C.clearenv
|
||||
func Clearenv()
|
||||
26
runtime/internal/clite/ctypes_windows.go
Normal file
26
runtime/internal/clite/ctypes_windows.go
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package c
|
||||
|
||||
// For Windows (LLP64 model), Long is 32-bit, regardless of architecture
|
||||
type (
|
||||
Long = int32
|
||||
Ulong = uint32
|
||||
)
|
||||
@@ -1,9 +1,7 @@
|
||||
//go:build !wasm
|
||||
|
||||
package debug
|
||||
|
||||
/*
|
||||
#cgo linux LDFLAGS: -lunwind
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
@@ -11,7 +9,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "_wrap/debug.c"
|
||||
)
|
||||
|
||||
|
||||
33
runtime/internal/clite/debug/debug_wasm.go
Normal file
33
runtime/internal/clite/debug/debug_wasm.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
type Info struct {
|
||||
Fname *c.Char
|
||||
Fbase c.Pointer
|
||||
Sname *c.Char
|
||||
Saddr c.Pointer
|
||||
}
|
||||
|
||||
func Address() unsafe.Pointer {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func Addrinfo(addr unsafe.Pointer, info *Info) c.Int {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
PC uintptr
|
||||
Offset uintptr
|
||||
SP unsafe.Pointer
|
||||
Name string
|
||||
}
|
||||
|
||||
func StackTrace(skip int, fn func(fr *Frame) bool) {
|
||||
panic("not implemented")
|
||||
}
|
||||
7
runtime/internal/clite/debug/libunwind.go
Normal file
7
runtime/internal/clite/debug/libunwind.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !linux
|
||||
|
||||
package debug
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
7
runtime/internal/clite/debug/libunwind_linux.go
Normal file
7
runtime/internal/clite/debug/libunwind_linux.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build linux
|
||||
|
||||
package debug
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: -lunwind"
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64))
|
||||
//go:build !amd64
|
||||
|
||||
package ffi
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build freebsd || linux || darwin
|
||||
|
||||
package ffi
|
||||
|
||||
const (
|
||||
|
||||
@@ -6,11 +6,6 @@ import (
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
||||
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
||||
)
|
||||
|
||||
const (
|
||||
Void = iota
|
||||
Int
|
||||
@@ -67,62 +62,9 @@ type Cif struct {
|
||||
//Extra c.Uint
|
||||
}
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_cif(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCif C.ffi_prep_cif
|
||||
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCifVar C.ffi_prep_cif_var
|
||||
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
void ffi_call(ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
void **avalue);
|
||||
*/
|
||||
//go:linkname Call C.ffi_call
|
||||
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer)
|
||||
|
||||
// void *ffi_closure_alloc (size_t size, void **code);
|
||||
//
|
||||
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
||||
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
// void ffi_closure_free (void *);
|
||||
//
|
||||
//go:linkname ClosureFree C.ffi_closure_free
|
||||
func ClosureFree(unsafe.Pointer)
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure*,
|
||||
ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
*/
|
||||
|
||||
//llgo:type C
|
||||
type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer)
|
||||
|
||||
//go:linkname PreClosureLoc C.ffi_prep_closure_loc
|
||||
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint
|
||||
|
||||
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + offset)
|
||||
}
|
||||
|
||||
67
runtime/internal/clite/ffi/ffi_other.go
Normal file
67
runtime/internal/clite/ffi/ffi_other.go
Normal file
@@ -0,0 +1,67 @@
|
||||
//go:build !wasm
|
||||
|
||||
package ffi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
||||
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
||||
)
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_cif(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCif C.ffi_prep_cif
|
||||
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCifVar C.ffi_prep_cif_var
|
||||
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
void ffi_call(ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
void **avalue);
|
||||
*/
|
||||
//go:linkname Call C.ffi_call
|
||||
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer)
|
||||
|
||||
// void *ffi_closure_alloc (size_t size, void **code);
|
||||
//
|
||||
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
||||
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
// void ffi_closure_free (void *);
|
||||
//
|
||||
//go:linkname ClosureFree C.ffi_closure_free
|
||||
func ClosureFree(unsafe.Pointer)
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure*,
|
||||
ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
*/
|
||||
|
||||
//go:linkname PreClosureLoc C.ffi_prep_closure_loc
|
||||
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint
|
||||
31
runtime/internal/clite/ffi/ffi_wasm.go
Normal file
31
runtime/internal/clite/ffi/ffi_wasm.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package ffi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func ClosureFree(unsafe.Pointer) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint {
|
||||
panic("not implemented")
|
||||
}
|
||||
7
runtime/internal/clite/goarch/endian_big.go
Normal file
7
runtime/internal/clite/goarch/endian_big.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build 386 || amd64 || arm || arm64 || ppc64le || mips64le || mipsle || riscv64 || wasm
|
||||
// +build 386 amd64 arm arm64 ppc64le mips64le mipsle riscv64 wasm
|
||||
|
||||
package goarch
|
||||
|
||||
const BigEndian = true
|
||||
const LittleEndian = false
|
||||
9
runtime/internal/clite/goarch/endian_little.go
Normal file
9
runtime/internal/clite/goarch/endian_little.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build ppc64 || s390x || mips || mips64
|
||||
// +build ppc64 s390x mips mips64
|
||||
|
||||
package goarch
|
||||
|
||||
const (
|
||||
BigEndian = false
|
||||
LittleEndian = true
|
||||
)
|
||||
3
runtime/internal/clite/goarch/goarch.go
Normal file
3
runtime/internal/clite/goarch/goarch.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package goarch
|
||||
|
||||
const PtrSize = 4 << (^uintptr(0) >> 63)
|
||||
5
runtime/internal/clite/libuv/_demo/go.mod
Normal file
5
runtime/internal/clite/libuv/_demo/go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module github.com/goplus/llgo/runtime/internal/clite/libuv/_demo
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require github.com/goplus/lib v0.2.0
|
||||
2
runtime/internal/clite/libuv/_demo/go.sum
Normal file
2
runtime/internal/clite/libuv/_demo/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
package os
|
||||
|
||||
// #include <sys/stat.h>
|
||||
// #include <limits.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
@@ -27,10 +23,6 @@ import (
|
||||
"github.com/goplus/llgo/runtime/internal/clite/syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
PATH_MAX = C.PATH_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
/* get file status flags */
|
||||
F_GETFL = 3
|
||||
@@ -58,14 +50,6 @@ const (
|
||||
EAGAIN = 35
|
||||
)
|
||||
|
||||
type (
|
||||
ModeT C.mode_t
|
||||
UidT C.uid_t
|
||||
GidT C.gid_t
|
||||
OffT C.off_t
|
||||
DevT C.dev_t
|
||||
)
|
||||
|
||||
type (
|
||||
StatT = syscall.Stat_t
|
||||
)
|
||||
@@ -115,12 +99,6 @@ func Truncate(path *c.Char, length OffT) c.Int
|
||||
//go:linkname Chmod C.chmod
|
||||
func Chmod(path *c.Char, mode ModeT) c.Int
|
||||
|
||||
//go:linkname Chown C.chown
|
||||
func Chown(path *c.Char, owner UidT, group GidT) c.Int
|
||||
|
||||
//go:linkname Lchown C.lchown
|
||||
func Lchown(path *c.Char, owner UidT, group GidT) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Getcwd C.getcwd
|
||||
@@ -189,16 +167,6 @@ func Dup2(oldfd c.Int, newfd c.Int) c.Int
|
||||
//go:linkname Dup3 C.dup3
|
||||
func Dup3(oldfd c.Int, newfd c.Int, flags c.Int) c.Int
|
||||
|
||||
/* TODO(xsw):
|
||||
On Alpha, IA-64, MIPS, SuperH, and SPARC/SPARC64, pipe() has the following prototype:
|
||||
struct fd_pair {
|
||||
long fd[2];
|
||||
};
|
||||
struct fd_pair pipe(void);
|
||||
*/
|
||||
//go:linkname Pipe C.pipe
|
||||
func Pipe(fds *[2]c.Int) c.Int
|
||||
|
||||
//go:linkname Mkfifo C.mkfifo
|
||||
func Mkfifo(path *c.Char, mode ModeT) c.Int
|
||||
|
||||
@@ -270,9 +238,6 @@ func Execvp(file *c.Char, argv **c.Char) c.Int
|
||||
|
||||
type PidT c.Int
|
||||
|
||||
//go:linkname Fork C.fork
|
||||
func Fork() PidT
|
||||
|
||||
//go:linkname Getpid C.getpid
|
||||
func Getpid() PidT
|
||||
|
||||
@@ -293,9 +258,6 @@ func Getppid() PidT
|
||||
//go:linkname Syscall C.syscall
|
||||
func Syscall(sysno c.Long, __llgo_va_list ...any) c.Long
|
||||
|
||||
//go:linkname Kill C.kill
|
||||
func Kill(pid PidT, sig c.Int) c.Int
|
||||
|
||||
// If wait() returns due to a stopped or terminated child process, the process ID
|
||||
// of the child is returned to the calling process. Otherwise, a value of -1 is
|
||||
// returned and errno is set to indicate the error.
|
||||
@@ -313,9 +275,6 @@ func Wait(statLoc *c.Int) PidT
|
||||
//go:linkname Wait3 C.wait3
|
||||
func Wait3(statLoc *c.Int, options c.Int, rusage *syscall.Rusage) PidT
|
||||
|
||||
//go:linkname Wait4 C.wait4
|
||||
func Wait4(pid PidT, statLoc *c.Int, options c.Int, rusage *syscall.Rusage) PidT
|
||||
|
||||
//go:linkname Waitpid C.waitpid
|
||||
func Waitpid(pid PidT, statLoc *c.Int, options c.Int) PidT
|
||||
|
||||
@@ -324,26 +283,6 @@ func Waitpid(pid PidT, statLoc *c.Int, options c.Int) PidT
|
||||
//go:linkname Exit C.exit
|
||||
func Exit(c.Int)
|
||||
|
||||
//go:linkname Getuid C.getuid
|
||||
func Getuid() UidT
|
||||
|
||||
//go:linkname Geteuid C.geteuid
|
||||
func Geteuid() UidT
|
||||
|
||||
//go:linkname Getgid C.getgid
|
||||
func Getgid() GidT
|
||||
|
||||
//go:linkname Getegid C.getegid
|
||||
func Getegid() GidT
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Getrlimit C.getrlimit
|
||||
func Getrlimit(resource c.Int, rlp *syscall.Rlimit) c.Int
|
||||
|
||||
//go:linkname Setrlimit C.setrlimit
|
||||
func Setrlimit(resource c.Int, rlp *syscall.Rlimit) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Upon successful completion, the value 0 is returned; otherwise the value -1
|
||||
|
||||
43
runtime/internal/clite/os/os_darwin.go
Normal file
43
runtime/internal/clite/os/os_darwin.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "_os/os.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
const (
|
||||
PATH_MAX = 1024
|
||||
)
|
||||
|
||||
type (
|
||||
ModeT uint16
|
||||
UidT uint32
|
||||
GidT uint32
|
||||
OffT int64
|
||||
DevT int32
|
||||
)
|
||||
|
||||
//go:linkname Clearenv C.cliteClearenv
|
||||
func Clearenv() c.Int
|
||||
69
runtime/internal/clite/os/os_nonwasm.go
Normal file
69
runtime/internal/clite/os/os_nonwasm.go
Normal file
@@ -0,0 +1,69 @@
|
||||
//go:build !wasm
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
"github.com/goplus/llgo/runtime/internal/clite/syscall"
|
||||
)
|
||||
|
||||
//go:linkname Getuid C.getuid
|
||||
func Getuid() UidT
|
||||
|
||||
//go:linkname Geteuid C.geteuid
|
||||
func Geteuid() UidT
|
||||
|
||||
//go:linkname Getgid C.getgid
|
||||
func Getgid() GidT
|
||||
|
||||
//go:linkname Getegid C.getegid
|
||||
func Getegid() GidT
|
||||
|
||||
//go:linkname Chown C.chown
|
||||
func Chown(path *c.Char, owner UidT, group GidT) c.Int
|
||||
|
||||
//go:linkname Lchown C.lchown
|
||||
func Lchown(path *c.Char, owner UidT, group GidT) c.Int
|
||||
|
||||
//go:linkname Getrlimit C.getrlimit
|
||||
func Getrlimit(resource c.Int, rlp *syscall.Rlimit) c.Int
|
||||
|
||||
//go:linkname Setrlimit C.setrlimit
|
||||
func Setrlimit(resource c.Int, rlp *syscall.Rlimit) c.Int
|
||||
|
||||
//go:linkname Wait4 C.wait4
|
||||
func Wait4(pid PidT, statLoc *c.Int, options c.Int, rusage *syscall.Rusage) PidT
|
||||
|
||||
/* TODO(xsw):
|
||||
On Alpha, IA-64, MIPS, SuperH, and SPARC/SPARC64, pipe() has the following prototype:
|
||||
struct fd_pair {
|
||||
long fd[2];
|
||||
};
|
||||
struct fd_pair pipe(void);
|
||||
*/
|
||||
//go:linkname Pipe C.pipe
|
||||
func Pipe(fds *[2]c.Int) c.Int
|
||||
|
||||
//go:linkname Fork C.fork
|
||||
func Fork() PidT
|
||||
|
||||
//go:linkname Kill C.kill
|
||||
func Kill(pid PidT, sig c.Int) c.Int
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !linux
|
||||
//go:build !darwin
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
@@ -18,12 +18,28 @@
|
||||
|
||||
package os
|
||||
|
||||
import "C"
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "_os/os.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
//go:linkname Clearenv C.cliteClearenv
|
||||
func Clearenv()
|
||||
const (
|
||||
PATH_MAX = 4096
|
||||
)
|
||||
|
||||
type (
|
||||
ModeT uint32
|
||||
UidT uint32
|
||||
GidT uint32
|
||||
OffT int64
|
||||
DevT uint64
|
||||
)
|
||||
|
||||
//go:linkname Clearenv C.clearenv
|
||||
func Clearenv() c.Int
|
||||
|
||||
1
runtime/internal/clite/os/os_wasm.go
Normal file
1
runtime/internal/clite/os/os_wasm.go
Normal file
@@ -0,0 +1 @@
|
||||
package os
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <pthread.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
pthread_once_t cliteSyncOnceInitVal = PTHREAD_ONCE_INIT;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// wrap return type to void
|
||||
void clite_wrap_pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
// wrap return type to void
|
||||
void clite_wrap_pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package sync
|
||||
|
||||
// #include <pthread.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
@@ -27,16 +24,25 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "_wrap/pthd.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
const (
|
||||
PTHREAD_MUTEX_NORMAL = 0
|
||||
PTHREAD_MUTEX_ERRORCHECK = 1
|
||||
PTHREAD_MUTEX_RECURSIVE = 2
|
||||
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Once is an object that will perform exactly one action.
|
||||
type Once C.pthread_once_t
|
||||
// pthread_once_t
|
||||
type Once struct {
|
||||
Unused [PthreadOnceSize]c.Char
|
||||
}
|
||||
|
||||
//go:linkname OnceInit cliteSyncOnceInitVal
|
||||
//go:linkname OnceInit once_control
|
||||
var OnceInit Once
|
||||
|
||||
// llgo:link (*Once).Do C.pthread_once
|
||||
@@ -47,14 +53,17 @@ func (o *Once) Do(f func()) c.Int { return 0 }
|
||||
type MutexType c.Int
|
||||
|
||||
const (
|
||||
MUTEX_NORMAL MutexType = C.PTHREAD_MUTEX_NORMAL
|
||||
MUTEX_ERRORCHECK MutexType = C.PTHREAD_MUTEX_ERRORCHECK
|
||||
MUTEX_RECURSIVE MutexType = C.PTHREAD_MUTEX_RECURSIVE
|
||||
MUTEX_DEFAULT MutexType = C.PTHREAD_MUTEX_DEFAULT
|
||||
MUTEX_NORMAL MutexType = PTHREAD_MUTEX_NORMAL
|
||||
MUTEX_ERRORCHECK MutexType = PTHREAD_MUTEX_ERRORCHECK
|
||||
MUTEX_RECURSIVE MutexType = PTHREAD_MUTEX_RECURSIVE
|
||||
MUTEX_DEFAULT MutexType = PTHREAD_MUTEX_DEFAULT
|
||||
)
|
||||
|
||||
// MutexAttr is a mutex attribute object.
|
||||
type MutexAttr C.pthread_mutexattr_t
|
||||
// pthread_mutexattr_t
|
||||
type MutexAttr struct {
|
||||
Unused [PthreadMutexAttrSize]c.Char
|
||||
}
|
||||
|
||||
// llgo:link (*MutexAttr).Init C.pthread_mutexattr_init
|
||||
func (a *MutexAttr) Init(attr *MutexAttr) c.Int { return 0 }
|
||||
@@ -67,28 +76,54 @@ func (a *MutexAttr) SetType(typ MutexType) c.Int { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname c_pthread_mutex_init C.pthread_mutex_init
|
||||
func c_pthread_mutex_init(m *Mutex, attr *MutexAttr) c.Int
|
||||
|
||||
//go:linkname c_pthread_mutex_destroy C.pthread_mutex_destroy
|
||||
func c_pthread_mutex_destroy(m *Mutex) c.Int
|
||||
|
||||
//go:linkname c_pthread_mutex_lock C.pthread_mutex_lock
|
||||
func c_pthread_mutex_lock(m *Mutex) c.Int
|
||||
|
||||
//go:linkname c_pthread_mutex_unlock C.pthread_mutex_unlock
|
||||
func c_pthread_mutex_unlock(m *Mutex) c.Int
|
||||
|
||||
//go:linkname c_pthread_mutex_trylock C.pthread_mutex_trylock
|
||||
func c_pthread_mutex_trylock(m *Mutex) c.Int
|
||||
|
||||
// Mutex is a mutual exclusion lock.
|
||||
type Mutex C.pthread_mutex_t
|
||||
// pthread_mutex_t
|
||||
type Mutex struct {
|
||||
Unused [PthreadMutexSize]c.Char
|
||||
}
|
||||
|
||||
// llgo:link (*Mutex).Init C.pthread_mutex_init
|
||||
func (m *Mutex) Init(attr *MutexAttr) c.Int { return 0 }
|
||||
func (m *Mutex) Init(attr *MutexAttr) c.Int {
|
||||
return c_pthread_mutex_init(m, attr)
|
||||
}
|
||||
|
||||
// llgo:link (*Mutex).Destroy C.pthread_mutex_destroy
|
||||
func (m *Mutex) Destroy() {}
|
||||
func (m *Mutex) Destroy() {
|
||||
c_pthread_mutex_destroy(m)
|
||||
}
|
||||
|
||||
// llgo:link (*Mutex).TryLock C.pthread_mutex_trylock
|
||||
func (m *Mutex) TryLock() c.Int { return 0 }
|
||||
func (m *Mutex) TryLock() c.Int {
|
||||
return c_pthread_mutex_trylock(m)
|
||||
}
|
||||
|
||||
// llgo:link (*Mutex).Lock C.clite_wrap_pthread_mutex_lock
|
||||
func (m *Mutex) Lock() {}
|
||||
func (m *Mutex) Lock() {
|
||||
c_pthread_mutex_lock(m)
|
||||
}
|
||||
|
||||
// llgo:link (*Mutex).Unlock C.clite_wrap_pthread_mutex_unlock
|
||||
func (m *Mutex) Unlock() {}
|
||||
func (m *Mutex) Unlock() {
|
||||
c_pthread_mutex_unlock(m)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// RWLockAttr is a read-write lock attribute object.
|
||||
type RWLockAttr C.pthread_rwlockattr_t
|
||||
// pthread_rwlockattr_t
|
||||
type RWLockAttr struct {
|
||||
Unused [PthreadRWLockAttrSize]c.Char
|
||||
}
|
||||
|
||||
// llgo:link (*RWLockAttr).Init C.pthread_rwlockattr_init
|
||||
func (a *RWLockAttr) Init(attr *RWLockAttr) c.Int { return 0 }
|
||||
@@ -104,37 +139,69 @@ func (a *RWLockAttr) GetPShared(pshared *c.Int) c.Int { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname c_pthread_rwlock_init C.pthread_rwlock_init
|
||||
func c_pthread_rwlock_init(rw *RWLock, attr *RWLockAttr) c.Int
|
||||
|
||||
//go:linkname c_pthread_rwlock_destroy C.pthread_rwlock_destroy
|
||||
func c_pthread_rwlock_destroy(rw *RWLock) c.Int
|
||||
|
||||
//go:linkname c_pthread_rwlock_rdlock C.pthread_rwlock_rdlock
|
||||
func c_pthread_rwlock_rdlock(rw *RWLock) c.Int
|
||||
|
||||
//go:linkname c_pthread_rwlock_wrlock C.pthread_rwlock_wrlock
|
||||
func c_pthread_rwlock_wrlock(rw *RWLock) c.Int
|
||||
|
||||
//go:linkname c_pthread_rwlock_unlock C.pthread_rwlock_unlock
|
||||
func c_pthread_rwlock_unlock(rw *RWLock) c.Int
|
||||
|
||||
//go:linkname c_pthread_rwlock_tryrdlock C.pthread_rwlock_tryrdlock
|
||||
func c_pthread_rwlock_tryrdlock(rw *RWLock) c.Int
|
||||
|
||||
//go:linkname c_pthread_rwlock_trywrlock C.pthread_rwlock_trywrlock
|
||||
func c_pthread_rwlock_trywrlock(rw *RWLock) c.Int
|
||||
|
||||
// RWLock is a read-write lock.
|
||||
type RWLock C.pthread_rwlock_t
|
||||
// pthread_rwlock_t
|
||||
type RWLock struct {
|
||||
Unused [PthreadRWLockSize]c.Char
|
||||
}
|
||||
|
||||
// llgo:link (*RWLock).Init C.pthread_rwlock_init
|
||||
func (rw *RWLock) Init(attr *RWLockAttr) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*RWLock).Destroy C.pthread_rwlock_destroy
|
||||
func (rw *RWLock) Destroy() {}
|
||||
func (rw *RWLock) Destroy() {
|
||||
c_pthread_rwlock_destroy(rw)
|
||||
}
|
||||
|
||||
// llgo:link (*RWLock).RLock C.pthread_rwlock_rdlock
|
||||
func (rw *RWLock) RLock() {}
|
||||
func (rw *RWLock) RLock() {
|
||||
c_pthread_rwlock_rdlock(rw)
|
||||
}
|
||||
|
||||
// llgo:link (*RWLock).TryRLock C.pthread_rwlock_tryrdlock
|
||||
func (rw *RWLock) TryRLock() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*RWLock).RUnlock C.pthread_rwlock_unlock
|
||||
func (rw *RWLock) RUnlock() {}
|
||||
func (rw *RWLock) RUnlock() {
|
||||
c_pthread_rwlock_unlock(rw)
|
||||
}
|
||||
|
||||
// llgo:link (*RWLock).Lock C.pthread_rwlock_wrlock
|
||||
func (rw *RWLock) Lock() {}
|
||||
func (rw *RWLock) Lock() {
|
||||
c_pthread_rwlock_wrlock(rw)
|
||||
}
|
||||
|
||||
// llgo:link (*RWLock).TryLock C.pthread_rwlock_trywrlock
|
||||
func (rw *RWLock) TryLock() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*RWLock).Unlock C.pthread_rwlock_unlock
|
||||
func (rw *RWLock) Unlock() {}
|
||||
func (rw *RWLock) Unlock() {
|
||||
c_pthread_rwlock_unlock(rw)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// CondAttr is a condition variable attribute object.
|
||||
type CondAttr C.pthread_condattr_t
|
||||
// pthread_condattr_t
|
||||
type CondAttr struct {
|
||||
Unused [PthreadCondAttrSize]c.Char
|
||||
}
|
||||
|
||||
// llgo:link (*CondAttr).Init C.pthread_condattr_init
|
||||
func (a *CondAttr) Init(attr *CondAttr) c.Int { return 0 }
|
||||
@@ -150,25 +217,52 @@ func (a *CondAttr) Destroy() {}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname c_pthread_cond_init C.pthread_cond_init
|
||||
func c_pthread_cond_init(c *Cond, attr *CondAttr) c.Int
|
||||
|
||||
//go:linkname c_pthread_cond_destroy C.pthread_cond_destroy
|
||||
func c_pthread_cond_destroy(c *Cond) c.Int
|
||||
|
||||
//go:linkname c_pthread_cond_signal C.pthread_cond_signal
|
||||
func c_pthread_cond_signal(c *Cond) c.Int
|
||||
|
||||
//go:linkname c_pthread_cond_broadcast C.pthread_cond_broadcast
|
||||
func c_pthread_cond_broadcast(c *Cond) c.Int
|
||||
|
||||
//go:linkname c_pthread_cond_wait C.pthread_cond_wait
|
||||
func c_pthread_cond_wait(c *Cond, m *Mutex) c.Int
|
||||
|
||||
//go:linkname c_pthread_cond_timedwait C.pthread_cond_timedwait
|
||||
func c_pthread_cond_timedwait(c *Cond, m *Mutex, abstime *time.Timespec) c.Int
|
||||
|
||||
// Cond is a condition variable.
|
||||
type Cond C.pthread_cond_t
|
||||
// pthread_cond_t
|
||||
type Cond struct {
|
||||
Unused [PthreadCondSize]c.Char
|
||||
}
|
||||
|
||||
// llgo:link (*Cond).Init C.pthread_cond_init
|
||||
func (c *Cond) Init(attr *CondAttr) c.Int { return 0 }
|
||||
func (c *Cond) Init(attr *CondAttr) c.Int {
|
||||
return c_pthread_cond_init(c, attr)
|
||||
}
|
||||
|
||||
// llgo:link (*Cond).Destroy C.pthread_cond_destroy
|
||||
func (c *Cond) Destroy() {}
|
||||
func (c *Cond) Destroy() {
|
||||
c_pthread_cond_destroy(c)
|
||||
}
|
||||
|
||||
// llgo:link (*Cond).Signal C.pthread_cond_signal
|
||||
func (c *Cond) Signal() c.Int { return 0 }
|
||||
func (c *Cond) Signal() c.Int {
|
||||
return c_pthread_cond_signal(c)
|
||||
}
|
||||
|
||||
// llgo:link (*Cond).Broadcast C.pthread_cond_broadcast
|
||||
func (c *Cond) Broadcast() c.Int { return 0 }
|
||||
func (c *Cond) Broadcast() c.Int {
|
||||
return c_pthread_cond_broadcast(c)
|
||||
}
|
||||
|
||||
// llgo:link (*Cond).Wait C.pthread_cond_wait
|
||||
func (c *Cond) Wait(m *Mutex) c.Int { return 0 }
|
||||
func (c *Cond) Wait(m *Mutex) c.Int {
|
||||
return c_pthread_cond_wait(c, m)
|
||||
}
|
||||
|
||||
// llgo:link (*Cond).TimedWait C.pthread_cond_timedwait
|
||||
func (c *Cond) TimedWait(m *Mutex, abstime *time.Timespec) c.Int { return 0 }
|
||||
func (c *Cond) TimedWait(m *Mutex, abstime *time.Timespec) c.Int {
|
||||
return c_pthread_cond_timedwait(c, m, abstime)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
11
runtime/internal/clite/pthread/sync/sync_darwin_amd64.go
Normal file
11
runtime/internal/clite/pthread/sync/sync_darwin_amd64.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package sync
|
||||
|
||||
const (
|
||||
PthreadOnceSize = 16
|
||||
PthreadMutexSize = 56
|
||||
PthreadMutexAttrSize = 8
|
||||
PthreadCondSize = 40
|
||||
PthreadCondAttrSize = 8
|
||||
PthreadRWLockSize = 192
|
||||
PthreadRWLockAttrSize = 16
|
||||
)
|
||||
11
runtime/internal/clite/pthread/sync/sync_darwin_arm64.go
Normal file
11
runtime/internal/clite/pthread/sync/sync_darwin_arm64.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package sync
|
||||
|
||||
const (
|
||||
PthreadOnceSize = 16
|
||||
PthreadMutexSize = 64
|
||||
PthreadMutexAttrSize = 16
|
||||
PthreadCondSize = 48
|
||||
PthreadCondAttrSize = 16
|
||||
PthreadRWLockSize = 200
|
||||
PthreadRWLockAttrSize = 24
|
||||
)
|
||||
11
runtime/internal/clite/pthread/sync/sync_linux_amd64.go
Normal file
11
runtime/internal/clite/pthread/sync/sync_linux_amd64.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package sync
|
||||
|
||||
const (
|
||||
PthreadOnceSize = 4
|
||||
PthreadMutexSize = 40
|
||||
PthreadMutexAttrSize = 4
|
||||
PthreadCondSize = 48
|
||||
PthreadCondAttrSize = 4
|
||||
PthreadRWLockSize = 56
|
||||
PthreadRWLockAttrSize = 8
|
||||
)
|
||||
11
runtime/internal/clite/pthread/sync/sync_linux_arm64.go
Normal file
11
runtime/internal/clite/pthread/sync/sync_linux_arm64.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package sync
|
||||
|
||||
const (
|
||||
PthreadOnceSize = 4
|
||||
PthreadMutexSize = 48
|
||||
PthreadMutexAttrSize = 8
|
||||
PthreadCondSize = 48
|
||||
PthreadCondAttrSize = 8
|
||||
PthreadRWLockSize = 56
|
||||
PthreadRWLockAttrSize = 8
|
||||
)
|
||||
13
runtime/internal/clite/pthread/sync/sync_other.go
Normal file
13
runtime/internal/clite/pthread/sync/sync_other.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build !((linux || darwin) && (amd64 || arm64))
|
||||
|
||||
package sync
|
||||
|
||||
const (
|
||||
PthreadOnceSize = 4
|
||||
PthreadMutexSize = 40
|
||||
PthreadMutexAttrSize = 4
|
||||
PthreadCondSize = 48
|
||||
PthreadCondAttrSize = 4
|
||||
PthreadRWLockSize = 56
|
||||
PthreadRWLockAttrSize = 8
|
||||
)
|
||||
6
runtime/internal/clite/setjmp/jmpbuf_darwin_amd64.go
Normal file
6
runtime/internal/clite/setjmp/jmpbuf_darwin_amd64.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package setjmp
|
||||
|
||||
const (
|
||||
SigjmpBufSize = 196
|
||||
JmpBufSize = 192
|
||||
)
|
||||
6
runtime/internal/clite/setjmp/jmpbuf_darwin_arm64.go
Normal file
6
runtime/internal/clite/setjmp/jmpbuf_darwin_arm64.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package setjmp
|
||||
|
||||
const (
|
||||
SigjmpBufSize = 196
|
||||
JmpBufSize = 192
|
||||
)
|
||||
8
runtime/internal/clite/setjmp/jmpbuf_linux_amd64.go
Normal file
8
runtime/internal/clite/setjmp/jmpbuf_linux_amd64.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build !darwin
|
||||
|
||||
package setjmp
|
||||
|
||||
const (
|
||||
SigjmpBufSize = 200
|
||||
JmpBufSize = 200
|
||||
)
|
||||
6
runtime/internal/clite/setjmp/jmpbuf_linux_arm64.go
Normal file
6
runtime/internal/clite/setjmp/jmpbuf_linux_arm64.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package setjmp
|
||||
|
||||
const (
|
||||
SigjmpBufSize = 312
|
||||
JmpBufSize = 312
|
||||
)
|
||||
8
runtime/internal/clite/setjmp/jmpbuf_other.go
Normal file
8
runtime/internal/clite/setjmp/jmpbuf_other.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build !((linux || darwin) && (amd64 || arm64))
|
||||
|
||||
package setjmp
|
||||
|
||||
const (
|
||||
SigjmpBufSize = 200
|
||||
JmpBufSize = 200
|
||||
)
|
||||
47
runtime/internal/clite/setjmp/setjmp.go
Normal file
47
runtime/internal/clite/setjmp/setjmp.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package setjmp
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
|
||||
type (
|
||||
SigjmpBuf [SigjmpBufSize]byte
|
||||
JmpBuf [JmpBufSize]byte
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Setjmp C.setjmp
|
||||
func Setjmp(env *JmpBuf) c.Int
|
||||
|
||||
//go:linkname Longjmp C.longjmp
|
||||
func Longjmp(env *JmpBuf, val c.Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Siglongjmp C.siglongjmp
|
||||
func Siglongjmp(env *SigjmpBuf, val c.Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !wasm
|
||||
|
||||
package signal
|
||||
|
||||
import (
|
||||
@@ -5,7 +7,6 @@ import (
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
import "C"
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
|
||||
1
runtime/internal/clite/signal/signal_wasm.go
Normal file
1
runtime/internal/clite/signal/signal_wasm.go
Normal file
@@ -0,0 +1 @@
|
||||
package signal
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
@@ -17,7 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package clite
|
||||
package c
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
@@ -17,7 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package clite
|
||||
package c
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
47
runtime/internal/clite/syscall/dirent.go
Normal file
47
runtime/internal/clite/syscall/dirent.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/runtime/internal/clite/byteorder"
|
||||
"github.com/goplus/llgo/runtime/internal/clite/goarch"
|
||||
)
|
||||
|
||||
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
|
||||
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
|
||||
if len(b) < int(off+size) {
|
||||
return 0, false
|
||||
}
|
||||
if goarch.BigEndian {
|
||||
return readIntBE(b[off:], size), true
|
||||
}
|
||||
return readIntLE(b[off:], size), true
|
||||
}
|
||||
|
||||
func readIntBE(b []byte, size uintptr) uint64 {
|
||||
switch size {
|
||||
case 1:
|
||||
return uint64(b[0])
|
||||
case 2:
|
||||
return uint64(byteorder.BEUint16(b))
|
||||
case 4:
|
||||
return uint64(byteorder.BEUint32(b))
|
||||
case 8:
|
||||
return uint64(byteorder.BEUint64(b))
|
||||
default:
|
||||
panic("syscall: readInt with unsupported size")
|
||||
}
|
||||
}
|
||||
|
||||
func readIntLE(b []byte, size uintptr) uint64 {
|
||||
switch size {
|
||||
case 1:
|
||||
return uint64(b[0])
|
||||
case 2:
|
||||
return uint64(byteorder.LEUint16(b))
|
||||
case 4:
|
||||
return uint64(byteorder.LEUint32(b))
|
||||
case 8:
|
||||
return uint64(byteorder.LEUint64(b))
|
||||
default:
|
||||
panic("syscall: readInt with unsupported size")
|
||||
}
|
||||
}
|
||||
69
runtime/internal/clite/syscall/env_unix.go
Normal file
69
runtime/internal/clite/syscall/env_unix.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
_ "unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
var (
|
||||
envOnce sync.Once
|
||||
envLock sync.RWMutex
|
||||
env map[string]int
|
||||
envs []string
|
||||
)
|
||||
|
||||
//go:linkname c_environ environ
|
||||
var c_environ **c.Char
|
||||
|
||||
//go:linkname c_getenv C.getenv
|
||||
func c_getenv(name *c.Char) *c.Char
|
||||
|
||||
func copyenv() {
|
||||
env = make(map[string]int)
|
||||
p := c_environ
|
||||
i := 0
|
||||
for p != nil {
|
||||
s := c.GoString(*p)
|
||||
for j := 0; j < len(s); j++ {
|
||||
if s[j] == '=' {
|
||||
key := s[:j]
|
||||
if _, ok := env[key]; !ok {
|
||||
env[key] = i // first mention of key
|
||||
} else {
|
||||
// Clear duplicate keys. This permits Unsetenv to
|
||||
// safely delete only the first item without
|
||||
// worrying about unshadowing a later one,
|
||||
// which might be a security problem.
|
||||
envs[i] = ""
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
p = c.Advance(p, 1)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
envOnce.Do(copyenv)
|
||||
if len(key) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
envLock.RLock()
|
||||
defer envLock.RUnlock()
|
||||
|
||||
i, ok := env[key]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
s := envs[i]
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '=' {
|
||||
return s[i+1:], true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
316
runtime/internal/clite/syscall/fs_wasip1.go
Normal file
316
runtime/internal/clite/syscall/fs_wasip1.go
Normal file
@@ -0,0 +1,316 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build wasip1
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"structs"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Try to set stdio to non-blocking mode before the os package
|
||||
// calls NewFile for each fd. NewFile queries the non-blocking flag
|
||||
// but doesn't change it, even if the runtime supports non-blocking
|
||||
// stdio. Since WebAssembly modules are single-threaded, blocking
|
||||
// system calls temporarily halt execution of the module. If the
|
||||
// runtime supports non-blocking stdio, the Go runtime is able to
|
||||
// use the WASI net poller to poll for read/write readiness and is
|
||||
// able to schedule goroutines while waiting.
|
||||
SetNonblock(0, true)
|
||||
SetNonblock(1, true)
|
||||
SetNonblock(2, true)
|
||||
}
|
||||
|
||||
type uintptr32 = uint32
|
||||
type size = uint32
|
||||
type fdflags = uint32
|
||||
type filesize = uint64
|
||||
type filetype = uint8
|
||||
type lookupflags = uint32
|
||||
type oflags = uint32
|
||||
type rights = uint64
|
||||
type timestamp = uint64
|
||||
type dircookie = uint64
|
||||
type filedelta = int64
|
||||
type fstflags = uint32
|
||||
|
||||
type iovec struct {
|
||||
_ structs.HostLayout
|
||||
buf uintptr32
|
||||
bufLen size
|
||||
}
|
||||
|
||||
const (
|
||||
LOOKUP_SYMLINK_FOLLOW = 0x00000001
|
||||
)
|
||||
|
||||
const (
|
||||
OFLAG_CREATE = 0x0001
|
||||
OFLAG_DIRECTORY = 0x0002
|
||||
OFLAG_EXCL = 0x0004
|
||||
OFLAG_TRUNC = 0x0008
|
||||
)
|
||||
|
||||
const (
|
||||
FDFLAG_APPEND = 0x0001
|
||||
FDFLAG_DSYNC = 0x0002
|
||||
FDFLAG_NONBLOCK = 0x0004
|
||||
FDFLAG_RSYNC = 0x0008
|
||||
FDFLAG_SYNC = 0x0010
|
||||
)
|
||||
|
||||
const (
|
||||
RIGHT_FD_DATASYNC = 1 << iota
|
||||
RIGHT_FD_READ
|
||||
RIGHT_FD_SEEK
|
||||
RIGHT_FDSTAT_SET_FLAGS
|
||||
RIGHT_FD_SYNC
|
||||
RIGHT_FD_TELL
|
||||
RIGHT_FD_WRITE
|
||||
RIGHT_FD_ADVISE
|
||||
RIGHT_FD_ALLOCATE
|
||||
RIGHT_PATH_CREATE_DIRECTORY
|
||||
RIGHT_PATH_CREATE_FILE
|
||||
RIGHT_PATH_LINK_SOURCE
|
||||
RIGHT_PATH_LINK_TARGET
|
||||
RIGHT_PATH_OPEN
|
||||
RIGHT_FD_READDIR
|
||||
RIGHT_PATH_READLINK
|
||||
RIGHT_PATH_RENAME_SOURCE
|
||||
RIGHT_PATH_RENAME_TARGET
|
||||
RIGHT_PATH_FILESTAT_GET
|
||||
RIGHT_PATH_FILESTAT_SET_SIZE
|
||||
RIGHT_PATH_FILESTAT_SET_TIMES
|
||||
RIGHT_FD_FILESTAT_GET
|
||||
RIGHT_FD_FILESTAT_SET_SIZE
|
||||
RIGHT_FD_FILESTAT_SET_TIMES
|
||||
RIGHT_PATH_SYMLINK
|
||||
RIGHT_PATH_REMOVE_DIRECTORY
|
||||
RIGHT_PATH_UNLINK_FILE
|
||||
RIGHT_POLL_FD_READWRITE
|
||||
RIGHT_SOCK_SHUTDOWN
|
||||
RIGHT_SOCK_ACCEPT
|
||||
)
|
||||
|
||||
const (
|
||||
WHENCE_SET = 0
|
||||
WHENCE_CUR = 1
|
||||
WHENCE_END = 2
|
||||
)
|
||||
|
||||
const (
|
||||
FILESTAT_SET_ATIM = 0x0001
|
||||
FILESTAT_SET_ATIM_NOW = 0x0002
|
||||
FILESTAT_SET_MTIM = 0x0004
|
||||
FILESTAT_SET_MTIM_NOW = 0x0008
|
||||
)
|
||||
|
||||
const (
|
||||
// Despite the rights being defined as a 64 bits integer in the spec,
|
||||
// wasmtime crashes the program if we set any of the upper 32 bits.
|
||||
fullRights = rights(^uint32(0))
|
||||
readRights = rights(RIGHT_FD_READ | RIGHT_FD_READDIR)
|
||||
writeRights = rights(RIGHT_FD_DATASYNC | RIGHT_FD_WRITE | RIGHT_FD_ALLOCATE | RIGHT_PATH_FILESTAT_SET_SIZE)
|
||||
|
||||
// Some runtimes have very strict expectations when it comes to which
|
||||
// rights can be enabled on files opened by path_open. The fileRights
|
||||
// constant is used as a mask to retain only bits for operations that
|
||||
// are supported on files.
|
||||
fileRights rights = RIGHT_FD_DATASYNC |
|
||||
RIGHT_FD_READ |
|
||||
RIGHT_FD_SEEK |
|
||||
RIGHT_FDSTAT_SET_FLAGS |
|
||||
RIGHT_FD_SYNC |
|
||||
RIGHT_FD_TELL |
|
||||
RIGHT_FD_WRITE |
|
||||
RIGHT_FD_ADVISE |
|
||||
RIGHT_FD_ALLOCATE |
|
||||
RIGHT_PATH_CREATE_DIRECTORY |
|
||||
RIGHT_PATH_CREATE_FILE |
|
||||
RIGHT_PATH_LINK_SOURCE |
|
||||
RIGHT_PATH_LINK_TARGET |
|
||||
RIGHT_PATH_OPEN |
|
||||
RIGHT_FD_READDIR |
|
||||
RIGHT_PATH_READLINK |
|
||||
RIGHT_PATH_RENAME_SOURCE |
|
||||
RIGHT_PATH_RENAME_TARGET |
|
||||
RIGHT_PATH_FILESTAT_GET |
|
||||
RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||
RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||
RIGHT_FD_FILESTAT_GET |
|
||||
RIGHT_FD_FILESTAT_SET_SIZE |
|
||||
RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
RIGHT_PATH_SYMLINK |
|
||||
RIGHT_PATH_REMOVE_DIRECTORY |
|
||||
RIGHT_PATH_UNLINK_FILE |
|
||||
RIGHT_POLL_FD_READWRITE
|
||||
|
||||
// Runtimes like wasmtime and wasmedge will refuse to open directories
|
||||
// if the rights requested by the application exceed the operations that
|
||||
// can be performed on a directory.
|
||||
dirRights rights = RIGHT_FD_SEEK |
|
||||
RIGHT_FDSTAT_SET_FLAGS |
|
||||
RIGHT_FD_SYNC |
|
||||
RIGHT_PATH_CREATE_DIRECTORY |
|
||||
RIGHT_PATH_CREATE_FILE |
|
||||
RIGHT_PATH_LINK_SOURCE |
|
||||
RIGHT_PATH_LINK_TARGET |
|
||||
RIGHT_PATH_OPEN |
|
||||
RIGHT_FD_READDIR |
|
||||
RIGHT_PATH_READLINK |
|
||||
RIGHT_PATH_RENAME_SOURCE |
|
||||
RIGHT_PATH_RENAME_TARGET |
|
||||
RIGHT_PATH_FILESTAT_GET |
|
||||
RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||
RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||
RIGHT_FD_FILESTAT_GET |
|
||||
RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
RIGHT_PATH_SYMLINK |
|
||||
RIGHT_PATH_REMOVE_DIRECTORY |
|
||||
RIGHT_PATH_UNLINK_FILE
|
||||
)
|
||||
|
||||
// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-fdstat-record
|
||||
// fdflags must be at offset 2, hence the uint16 type rather than the
|
||||
// fdflags (uint32) type.
|
||||
type fdstat struct {
|
||||
_ structs.HostLayout
|
||||
filetype filetype
|
||||
fdflags uint16
|
||||
rightsBase rights
|
||||
rightsInheriting rights
|
||||
}
|
||||
|
||||
type preopentype = uint8
|
||||
|
||||
const (
|
||||
preopentypeDir preopentype = iota
|
||||
)
|
||||
|
||||
type prestatDir struct {
|
||||
_ structs.HostLayout
|
||||
prNameLen size
|
||||
}
|
||||
|
||||
type prestat struct {
|
||||
_ structs.HostLayout
|
||||
typ preopentype
|
||||
dir prestatDir
|
||||
}
|
||||
|
||||
// Current working directory. We maintain this as a string and resolve paths in
|
||||
// the code because wasmtime does not allow relative path lookups outside of the
|
||||
// scope of a directory; a previous approach we tried consisted in maintaining
|
||||
// open a file descriptor to the current directory so we could perform relative
|
||||
// path lookups from that location, but it resulted in breaking path resolution
|
||||
// from the current directory to its parent.
|
||||
var cwd string
|
||||
|
||||
//go:nosplit
|
||||
func appendCleanPath(buf []byte, path string, lookupParent bool) ([]byte, bool) {
|
||||
i := 0
|
||||
for i < len(path) {
|
||||
for i < len(path) && path[i] == '/' {
|
||||
i++
|
||||
}
|
||||
|
||||
j := i
|
||||
for j < len(path) && path[j] != '/' {
|
||||
j++
|
||||
}
|
||||
|
||||
s := path[i:j]
|
||||
i = j
|
||||
|
||||
switch s {
|
||||
case "":
|
||||
continue
|
||||
case ".":
|
||||
continue
|
||||
case "..":
|
||||
if !lookupParent {
|
||||
k := len(buf)
|
||||
for k > 0 && buf[k-1] != '/' {
|
||||
k--
|
||||
}
|
||||
for k > 1 && buf[k-1] == '/' {
|
||||
k--
|
||||
}
|
||||
buf = buf[:k]
|
||||
if k == 0 {
|
||||
lookupParent = true
|
||||
} else {
|
||||
s = ""
|
||||
continue
|
||||
}
|
||||
}
|
||||
default:
|
||||
lookupParent = false
|
||||
}
|
||||
|
||||
if len(buf) > 0 && buf[len(buf)-1] != '/' {
|
||||
buf = append(buf, '/')
|
||||
}
|
||||
buf = append(buf, s...)
|
||||
}
|
||||
return buf, lookupParent
|
||||
}
|
||||
|
||||
// joinPath concatenates dir and file paths, producing a cleaned path where
|
||||
// "." and ".." have been removed, unless dir is relative and the references
|
||||
// to parent directories in file represented a location relative to a parent
|
||||
// of dir.
|
||||
//
|
||||
// This function is used for path resolution of all wasi functions expecting
|
||||
// a path argument; the returned string is heap allocated, which we may want
|
||||
// to optimize in the future. Instead of returning a string, the function
|
||||
// could append the result to an output buffer that the functions in this
|
||||
// file can manage to have allocated on the stack (e.g. initializing to a
|
||||
// fixed capacity). Since it will significantly increase code complexity,
|
||||
// we prefer to optimize for readability and maintainability at this time.
|
||||
func joinPath(dir, file string) string {
|
||||
buf := make([]byte, 0, len(dir)+len(file)+1)
|
||||
if isAbs(dir) {
|
||||
buf = append(buf, '/')
|
||||
}
|
||||
buf, lookupParent := appendCleanPath(buf, dir, false)
|
||||
buf, _ = appendCleanPath(buf, file, lookupParent)
|
||||
// The appendCleanPath function cleans the path so it does not inject
|
||||
// references to the current directory. If both the dir and file args
|
||||
// were ".", this results in the output buffer being empty so we handle
|
||||
// this condition here.
|
||||
if len(buf) == 0 {
|
||||
buf = append(buf, '.')
|
||||
}
|
||||
// If the file ended with a '/' we make sure that the output also ends
|
||||
// with a '/'. This is needed to ensure that programs have a mechanism
|
||||
// to represent dereferencing symbolic links pointing to directories.
|
||||
if buf[len(buf)-1] != '/' && isDir(file) {
|
||||
buf = append(buf, '/')
|
||||
}
|
||||
return unsafe.String(&buf[0], len(buf))
|
||||
}
|
||||
|
||||
func isAbs(path string) bool {
|
||||
return strings.HasPrefix(path, "/")
|
||||
}
|
||||
|
||||
func isDir(path string) bool {
|
||||
return strings.HasSuffix(path, "/")
|
||||
}
|
||||
|
||||
type Stat_t struct {
|
||||
Dev uint64
|
||||
Ino uint64
|
||||
Filetype uint8
|
||||
Nlink uint64
|
||||
Size uint64
|
||||
Atime uint64
|
||||
Mtime uint64
|
||||
Ctime uint64
|
||||
}
|
||||
65
runtime/internal/clite/syscall/net_fake.go
Normal file
65
runtime/internal/clite/syscall/net_fake.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Fake networking for js/wasm and wasip1/wasm.
|
||||
|
||||
//go:build js || wasm
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
AF_UNSPEC = iota
|
||||
AF_UNIX
|
||||
AF_INET
|
||||
AF_INET6
|
||||
)
|
||||
|
||||
const (
|
||||
SOCK_STREAM = 1 + iota
|
||||
SOCK_DGRAM
|
||||
SOCK_RAW
|
||||
SOCK_SEQPACKET
|
||||
)
|
||||
|
||||
const (
|
||||
IPPROTO_IP = 0
|
||||
IPPROTO_IPV4 = 4
|
||||
IPPROTO_IPV6 = 0x29
|
||||
IPPROTO_TCP = 6
|
||||
IPPROTO_UDP = 0x11
|
||||
)
|
||||
|
||||
const (
|
||||
SOMAXCONN = 0x80
|
||||
)
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
IPV6_V6ONLY
|
||||
SO_ERROR
|
||||
)
|
||||
|
||||
// Misc constants expected by package net but not supported.
|
||||
const (
|
||||
_ = iota
|
||||
F_DUPFD_CLOEXEC
|
||||
SYS_FCNTL = 500 // unsupported
|
||||
)
|
||||
|
||||
type Sockaddr any
|
||||
|
||||
type SockaddrInet4 struct {
|
||||
Port int
|
||||
Addr [4]byte
|
||||
}
|
||||
|
||||
type SockaddrInet6 struct {
|
||||
Port int
|
||||
ZoneId uint32
|
||||
Addr [16]byte
|
||||
}
|
||||
|
||||
type SockaddrUnix struct {
|
||||
Name string
|
||||
}
|
||||
5
runtime/internal/clite/syscall/os_wasm.go
Normal file
5
runtime/internal/clite/syscall/os_wasm.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
@@ -16,21 +16,61 @@
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
errorsPkg "errors"
|
||||
_ "unsafe"
|
||||
|
||||
c "github.com/goplus/llgo/runtime/internal/clite"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "noinit"
|
||||
)
|
||||
|
||||
type Errno uintptr
|
||||
var (
|
||||
ErrInvalid = errorsPkg.New("invalid argument")
|
||||
ErrPermission = errorsPkg.New("permission denied")
|
||||
ErrExist = errorsPkg.New("file already exists")
|
||||
ErrNotExist = errorsPkg.New("file does not exist")
|
||||
ErrClosed = errorsPkg.New("file already closed")
|
||||
ErrUnsupported = errorsPkg.New("operation not supported")
|
||||
)
|
||||
|
||||
// A Signal is a number describing a process signal.
|
||||
// It implements the os.Signal interface.
|
||||
type Signal = int
|
||||
// Nano returns the time stored in ts as nanoseconds.
|
||||
func (ts *Timespec) Nano() int64 {
|
||||
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
// Nano returns the time stored in tv as nanoseconds.
|
||||
func (tv *Timeval) Nano() int64 {
|
||||
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||
}
|
||||
|
||||
// Unix returns the time stored in ts as seconds plus nanoseconds.
|
||||
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||
return int64(ts.Sec), int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (iov *Iovec) SetLen(length int) {
|
||||
iov.Len = uint64(length)
|
||||
// Unix returns the time stored in tv as seconds plus nanoseconds.
|
||||
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||
}
|
||||
|
||||
//go:linkname c_getpid C.getpid
|
||||
func c_getpid() c.Int
|
||||
|
||||
func Kill(pid int, signum Signal) error {
|
||||
// WASI does not have the notion of processes nor signal handlers.
|
||||
//
|
||||
// Any signal that the application raises to the process itself will
|
||||
// be interpreted as being cause for termination.
|
||||
if pid > 0 && pid != int(c_getpid()) {
|
||||
return ESRCH
|
||||
}
|
||||
ProcExit(128 + int32(signum))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ProcExit(code int32) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
55
runtime/internal/clite/syscall/syscall_unix.go
Normal file
55
runtime/internal/clite/syscall/syscall_unix.go
Normal file
@@ -0,0 +1,55 @@
|
||||
//go:build !wasm
|
||||
|
||||
package syscall
|
||||
|
||||
import "strconv"
|
||||
|
||||
type Errno uintptr
|
||||
|
||||
func (e Errno) Error() string {
|
||||
if 0 <= int(e) && int(e) < len(errors) {
|
||||
s := errors[e]
|
||||
if s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return "errno " + strconv.Itoa(int(e))
|
||||
}
|
||||
|
||||
func (e Errno) Is(target error) bool {
|
||||
switch target {
|
||||
case ErrPermission:
|
||||
return e == EACCES || e == EPERM
|
||||
case ErrExist:
|
||||
return e == EEXIST || e == ENOTEMPTY
|
||||
case ErrNotExist:
|
||||
return e == ENOENT
|
||||
case ErrUnsupported:
|
||||
return e == ENOSYS || e == ENOTSUP || e == EOPNOTSUPP
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e Errno) Temporary() bool {
|
||||
return e == EINTR || e == EMFILE || e == ENFILE || e.Timeout()
|
||||
}
|
||||
|
||||
func (e Errno) Timeout() bool {
|
||||
return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
|
||||
}
|
||||
|
||||
// A Signal is a number describing a process signal.
|
||||
// It implements the [os.Signal] interface.
|
||||
type Signal int
|
||||
|
||||
func (s Signal) Signal() {}
|
||||
|
||||
func (s Signal) String() string {
|
||||
if 0 <= s && int(s) < len(signals) {
|
||||
str := signals[s]
|
||||
if str != "" {
|
||||
return str
|
||||
}
|
||||
}
|
||||
return "signal " + strconv.Itoa(int(s))
|
||||
}
|
||||
464
runtime/internal/clite/syscall/syscall_wasm.go
Normal file
464
runtime/internal/clite/syscall/syscall_wasm.go
Normal file
@@ -0,0 +1,464 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
DT_UNKNOWN = 0
|
||||
DT_FIFO = 1
|
||||
DT_CHR = 2
|
||||
DT_DIR = 4
|
||||
DT_BLK = 6
|
||||
DT_REG = 8
|
||||
DT_LNK = 10
|
||||
DT_SOCK = 12
|
||||
DT_WHT = 14
|
||||
)
|
||||
|
||||
type Dircookie = uint64
|
||||
|
||||
type Filetype = uint8
|
||||
|
||||
const (
|
||||
FILETYPE_UNKNOWN Filetype = iota
|
||||
FILETYPE_BLOCK_DEVICE
|
||||
FILETYPE_CHARACTER_DEVICE
|
||||
FILETYPE_DIRECTORY
|
||||
FILETYPE_REGULAR_FILE
|
||||
FILETYPE_SOCKET_DGRAM
|
||||
FILETYPE_SOCKET_STREAM
|
||||
FILETYPE_SYMBOLIC_LINK
|
||||
)
|
||||
|
||||
type Dirent struct {
|
||||
// The offset of the next directory entry stored in this directory.
|
||||
Next Dircookie
|
||||
// The serial number of the file referred to by this directory entry.
|
||||
Ino uint64
|
||||
// The length of the name of the directory entry.
|
||||
Namlen uint32
|
||||
// The type of the file referred to by this directory entry.
|
||||
Type Filetype
|
||||
// Name of the directory entry.
|
||||
Name *byte
|
||||
}
|
||||
|
||||
func direntIno(buf []byte) (uint64, bool) {
|
||||
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
|
||||
}
|
||||
|
||||
func direntReclen(buf []byte) (uint64, bool) {
|
||||
namelen, ok := direntNamlen(buf)
|
||||
return 24 + namelen, ok
|
||||
}
|
||||
|
||||
func direntNamlen(buf []byte) (uint64, bool) {
|
||||
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
|
||||
}
|
||||
|
||||
// An Errno is an unsigned number describing an error condition.
|
||||
// It implements the error interface. The zero Errno is by convention
|
||||
// a non-error, so code to convert from Errno to error should use:
|
||||
//
|
||||
// var err = nil
|
||||
// if errno != 0 {
|
||||
// err = errno
|
||||
// }
|
||||
type Errno uint32
|
||||
|
||||
func (e Errno) Error() string {
|
||||
if 0 <= int(e) && int(e) < len(errorstr) {
|
||||
s := errorstr[e]
|
||||
if s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return "errno " + strconv.Itoa(int(e))
|
||||
}
|
||||
|
||||
func (e Errno) Is(target error) bool {
|
||||
switch target {
|
||||
case ErrPermission:
|
||||
return e == EACCES || e == EPERM
|
||||
case ErrExist:
|
||||
return e == EEXIST || e == ENOTEMPTY
|
||||
case ErrNotExist:
|
||||
return e == ENOENT
|
||||
case ErrUnsupported:
|
||||
return e == ENOSYS
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e Errno) Temporary() bool {
|
||||
return e == EINTR || e == EMFILE || e.Timeout()
|
||||
}
|
||||
|
||||
func (e Errno) Timeout() bool {
|
||||
return e == EAGAIN || e == ETIMEDOUT
|
||||
}
|
||||
|
||||
// A Signal is a number describing a process signal.
|
||||
// It implements the [os.Signal] interface.
|
||||
type Signal uint8
|
||||
|
||||
const (
|
||||
SIGNONE Signal = iota
|
||||
SIGHUP
|
||||
SIGINT
|
||||
SIGQUIT
|
||||
SIGILL
|
||||
SIGTRAP
|
||||
SIGABRT
|
||||
SIGBUS
|
||||
SIGFPE
|
||||
SIGKILL
|
||||
SIGUSR1
|
||||
SIGSEGV
|
||||
SIGUSR2
|
||||
SIGPIPE
|
||||
SIGALRM
|
||||
SIGTERM
|
||||
SIGCHLD
|
||||
SIGCONT
|
||||
SIGSTOP
|
||||
SIGTSTP
|
||||
SIGTTIN
|
||||
SIGTTOU
|
||||
SIGURG
|
||||
SIGXCPU
|
||||
SIGXFSZ
|
||||
SIGVTARLM
|
||||
SIGPROF
|
||||
SIGWINCH
|
||||
SIGPOLL
|
||||
SIGPWR
|
||||
SIGSYS
|
||||
)
|
||||
|
||||
func (s Signal) Signal() {}
|
||||
|
||||
func (s Signal) String() string {
|
||||
switch s {
|
||||
case SIGNONE:
|
||||
return "no signal"
|
||||
case SIGHUP:
|
||||
return "hangup"
|
||||
case SIGINT:
|
||||
return "interrupt"
|
||||
case SIGQUIT:
|
||||
return "quit"
|
||||
case SIGILL:
|
||||
return "illegal instruction"
|
||||
case SIGTRAP:
|
||||
return "trace/breakpoint trap"
|
||||
case SIGABRT:
|
||||
return "abort"
|
||||
case SIGBUS:
|
||||
return "bus error"
|
||||
case SIGFPE:
|
||||
return "floating point exception"
|
||||
case SIGKILL:
|
||||
return "killed"
|
||||
case SIGUSR1:
|
||||
return "user defined signal 1"
|
||||
case SIGSEGV:
|
||||
return "segmentation fault"
|
||||
case SIGUSR2:
|
||||
return "user defined signal 2"
|
||||
case SIGPIPE:
|
||||
return "broken pipe"
|
||||
case SIGALRM:
|
||||
return "alarm clock"
|
||||
case SIGTERM:
|
||||
return "terminated"
|
||||
case SIGCHLD:
|
||||
return "child exited"
|
||||
case SIGCONT:
|
||||
return "continued"
|
||||
case SIGSTOP:
|
||||
return "stopped (signal)"
|
||||
case SIGTSTP:
|
||||
return "stopped"
|
||||
case SIGTTIN:
|
||||
return "stopped (tty input)"
|
||||
case SIGTTOU:
|
||||
return "stopped (tty output)"
|
||||
case SIGURG:
|
||||
return "urgent I/O condition"
|
||||
case SIGXCPU:
|
||||
return "CPU time limit exceeded"
|
||||
case SIGXFSZ:
|
||||
return "file size limit exceeded"
|
||||
case SIGVTARLM:
|
||||
return "virtual timer expired"
|
||||
case SIGPROF:
|
||||
return "profiling timer expired"
|
||||
case SIGWINCH:
|
||||
return "window changed"
|
||||
case SIGPOLL:
|
||||
return "I/O possible"
|
||||
case SIGPWR:
|
||||
return "power failure"
|
||||
case SIGSYS:
|
||||
return "bad system call"
|
||||
default:
|
||||
return "signal " + strconv.Itoa(int(s))
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
Stdin = 0
|
||||
Stdout = 1
|
||||
Stderr = 2
|
||||
)
|
||||
|
||||
const (
|
||||
O_RDONLY = 0
|
||||
O_WRONLY = 1
|
||||
O_RDWR = 2
|
||||
|
||||
O_CREAT = 0100
|
||||
O_CREATE = O_CREAT
|
||||
O_TRUNC = 01000
|
||||
O_APPEND = 02000
|
||||
O_EXCL = 0200
|
||||
O_SYNC = 010000
|
||||
O_DIRECTORY = 020000
|
||||
O_NOFOLLOW = 0400
|
||||
|
||||
O_CLOEXEC = 0
|
||||
)
|
||||
|
||||
const (
|
||||
F_DUPFD = 0
|
||||
F_GETFD = 1
|
||||
F_SETFD = 2
|
||||
F_GETFL = 3
|
||||
F_SETFL = 4
|
||||
F_GETOWN = 5
|
||||
F_SETOWN = 6
|
||||
F_GETLK = 7
|
||||
F_SETLK = 8
|
||||
F_SETLKW = 9
|
||||
F_RGETLK = 10
|
||||
F_RSETLK = 11
|
||||
F_CNVT = 12
|
||||
F_RSETLKW = 13
|
||||
|
||||
F_RDLCK = 1
|
||||
F_WRLCK = 2
|
||||
F_UNLCK = 3
|
||||
F_UNLKSYS = 4
|
||||
)
|
||||
|
||||
const (
|
||||
S_IFMT = 0000370000
|
||||
S_IFSHM_SYSV = 0000300000
|
||||
S_IFSEMA = 0000270000
|
||||
S_IFCOND = 0000260000
|
||||
S_IFMUTEX = 0000250000
|
||||
S_IFSHM = 0000240000
|
||||
S_IFBOUNDSOCK = 0000230000
|
||||
S_IFSOCKADDR = 0000220000
|
||||
S_IFDSOCK = 0000210000
|
||||
|
||||
S_IFSOCK = 0000140000
|
||||
S_IFLNK = 0000120000
|
||||
S_IFREG = 0000100000
|
||||
S_IFBLK = 0000060000
|
||||
S_IFDIR = 0000040000
|
||||
S_IFCHR = 0000020000
|
||||
S_IFIFO = 0000010000
|
||||
|
||||
S_UNSUP = 0000370000
|
||||
|
||||
S_ISUID = 0004000
|
||||
S_ISGID = 0002000
|
||||
S_ISVTX = 0001000
|
||||
|
||||
S_IREAD = 0400
|
||||
S_IWRITE = 0200
|
||||
S_IEXEC = 0100
|
||||
|
||||
S_IRWXU = 0700
|
||||
S_IRUSR = 0400
|
||||
S_IWUSR = 0200
|
||||
S_IXUSR = 0100
|
||||
|
||||
S_IRWXG = 070
|
||||
S_IRGRP = 040
|
||||
S_IWGRP = 020
|
||||
S_IXGRP = 010
|
||||
|
||||
S_IRWXO = 07
|
||||
S_IROTH = 04
|
||||
S_IWOTH = 02
|
||||
S_IXOTH = 01
|
||||
)
|
||||
|
||||
type WaitStatus uint32
|
||||
|
||||
func (w WaitStatus) Exited() bool { return false }
|
||||
func (w WaitStatus) ExitStatus() int { return 0 }
|
||||
func (w WaitStatus) Signaled() bool { return false }
|
||||
func (w WaitStatus) Signal() Signal { return 0 }
|
||||
func (w WaitStatus) CoreDump() bool { return false }
|
||||
func (w WaitStatus) Stopped() bool { return false }
|
||||
func (w WaitStatus) Continued() bool { return false }
|
||||
func (w WaitStatus) StopSignal() Signal { return 0 }
|
||||
func (w WaitStatus) TrapCause() int { return 0 }
|
||||
|
||||
// Rusage is a placeholder to allow compilation of the [os/exec] package
|
||||
// because we need Go programs to be portable across platforms. WASI does
|
||||
// not have a mechanism to spawn processes so there is no reason for an
|
||||
// application to take a dependency on this type.
|
||||
type Rusage struct {
|
||||
Utime Timeval
|
||||
Stime Timeval
|
||||
}
|
||||
|
||||
// ProcAttr is a placeholder to allow compilation of the [os/exec] package
|
||||
// because we need Go programs to be portable across platforms. WASI does
|
||||
// not have a mechanism to spawn processes so there is no reason for an
|
||||
// application to take a dependency on this type.
|
||||
type ProcAttr struct {
|
||||
Dir string
|
||||
Env []string
|
||||
Files []uintptr
|
||||
Sys *SysProcAttr
|
||||
}
|
||||
|
||||
type SysProcAttr struct {
|
||||
}
|
||||
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
|
||||
return 0, 0, ENOSYS
|
||||
}
|
||||
|
||||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
|
||||
return 0, 0, ENOSYS
|
||||
}
|
||||
|
||||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
|
||||
return 0, 0, ENOSYS
|
||||
}
|
||||
|
||||
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
|
||||
return 0, 0, ENOSYS
|
||||
}
|
||||
|
||||
func Sysctl(key string) (string, error) {
|
||||
if key == "kern.hostname" {
|
||||
return "wasip1", nil
|
||||
}
|
||||
return "", ENOSYS
|
||||
}
|
||||
|
||||
func Getuid() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func Getgid() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func Geteuid() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func Getegid() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func Getgroups() ([]int, error) {
|
||||
return []int{1}, nil
|
||||
}
|
||||
|
||||
func Getpid() int {
|
||||
return 3
|
||||
}
|
||||
|
||||
func Getppid() int {
|
||||
return 2
|
||||
}
|
||||
|
||||
// func Gettimeofday(tv *Timeval) error {
|
||||
// var time timestamp
|
||||
// if errno := clock_time_get(clockRealtime, 1e3, &time); errno != 0 {
|
||||
// return errno
|
||||
// }
|
||||
// tv.setTimestamp(time)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
return 0, ENOSYS
|
||||
}
|
||||
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
return 0, 0, ENOSYS
|
||||
}
|
||||
|
||||
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
|
||||
return 0, ENOSYS
|
||||
}
|
||||
|
||||
func Umask(mask int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type Timespec struct {
|
||||
Sec int64
|
||||
Nsec int64
|
||||
}
|
||||
|
||||
type Timeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
||||
|
||||
func setTimespec(sec, nsec int64) Timespec {
|
||||
return Timespec{Sec: sec, Nsec: nsec}
|
||||
}
|
||||
|
||||
func setTimeval(sec, usec int64) Timeval {
|
||||
return Timeval{Sec: sec, Usec: usec}
|
||||
}
|
||||
|
||||
type clockid = uint32
|
||||
|
||||
const (
|
||||
clockRealtime clockid = iota
|
||||
clockMonotonic
|
||||
clockProcessCPUTimeID
|
||||
clockThreadCPUTimeID
|
||||
)
|
||||
|
||||
func SetNonblock(fd int, nonblocking bool) error {
|
||||
panic("todo: syscall.SetNonblock")
|
||||
}
|
||||
|
||||
type Rlimit struct {
|
||||
Cur uint64
|
||||
Max uint64
|
||||
}
|
||||
|
||||
const (
|
||||
RLIMIT_NOFILE = iota
|
||||
)
|
||||
|
||||
func Getrlimit(which int, lim *Rlimit) error {
|
||||
return ENOSYS
|
||||
}
|
||||
|
||||
type Iovec struct {
|
||||
Base *byte
|
||||
Len int
|
||||
}
|
||||
205
runtime/internal/clite/syscall/tables_wasm.go
Normal file
205
runtime/internal/clite/syscall/tables_wasm.go
Normal file
@@ -0,0 +1,205 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
import "runtime"
|
||||
|
||||
// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
|
||||
const (
|
||||
E2BIG Errno = 1
|
||||
EACCES Errno = 2
|
||||
EADDRINUSE Errno = 3
|
||||
EADDRNOTAVAIL Errno = 4
|
||||
EAFNOSUPPORT Errno = 5
|
||||
EAGAIN Errno = 6
|
||||
EWOULDBLOCK Errno = EAGAIN
|
||||
EALREADY Errno = 7
|
||||
EBADF Errno = 8
|
||||
EBADMSG Errno = 9
|
||||
EBUSY Errno = 10
|
||||
ECANCELED Errno = 11
|
||||
ECHILD Errno = 12
|
||||
ECONNABORTED Errno = 13
|
||||
ECONNREFUSED Errno = 14
|
||||
ECONNRESET Errno = 15
|
||||
EDEADLK Errno = 16
|
||||
EDESTADDRREQ Errno = 17
|
||||
EDOM Errno = 18
|
||||
EDQUOT Errno = 19
|
||||
EEXIST Errno = 20
|
||||
EFAULT Errno = 21
|
||||
EFBIG Errno = 22
|
||||
EHOSTUNREACH Errno = 23
|
||||
EIDRM Errno = 24
|
||||
EILSEQ Errno = 25
|
||||
EINPROGRESS Errno = 26
|
||||
EINTR Errno = 27
|
||||
EINVAL Errno = 28
|
||||
EIO Errno = 29
|
||||
EISCONN Errno = 30
|
||||
EISDIR Errno = 31
|
||||
ELOOP Errno = 32
|
||||
EMFILE Errno = 33
|
||||
EMLINK Errno = 34
|
||||
EMSGSIZE Errno = 35
|
||||
EMULTIHOP Errno = 36
|
||||
ENAMETOOLONG Errno = 37
|
||||
ENETDOWN Errno = 38
|
||||
ENETRESET Errno = 39
|
||||
ENETUNREACH Errno = 40
|
||||
ENFILE Errno = 41
|
||||
ENOBUFS Errno = 42
|
||||
ENODEV Errno = 43
|
||||
ENOENT Errno = 44
|
||||
ENOEXEC Errno = 45
|
||||
ENOLCK Errno = 46
|
||||
ENOLINK Errno = 47
|
||||
ENOMEM Errno = 48
|
||||
ENOMSG Errno = 49
|
||||
ENOPROTOOPT Errno = 50
|
||||
ENOSPC Errno = 51
|
||||
ENOSYS Errno = 52
|
||||
ENOTCONN Errno = 53
|
||||
ENOTDIR Errno = 54
|
||||
ENOTEMPTY Errno = 55
|
||||
ENOTRECOVERABLE Errno = 56
|
||||
ENOTSOCK Errno = 57
|
||||
ENOTSUP Errno = 58
|
||||
ENOTTY Errno = 59
|
||||
ENXIO Errno = 60
|
||||
EOVERFLOW Errno = 61
|
||||
EOWNERDEAD Errno = 62
|
||||
EPERM Errno = 63
|
||||
EPIPE Errno = 64
|
||||
EPROTO Errno = 65
|
||||
EPROTONOSUPPORT Errno = 66
|
||||
EPROTOTYPE Errno = 67
|
||||
ERANGE Errno = 68
|
||||
EROFS Errno = 69
|
||||
ESPIPE Errno = 70
|
||||
ESRCH Errno = 71
|
||||
ESTALE Errno = 72
|
||||
ETIMEDOUT Errno = 73
|
||||
ETXTBSY Errno = 74
|
||||
EXDEV Errno = 75
|
||||
ENOTCAPABLE Errno = 76
|
||||
EBADFD Errno = 77
|
||||
// needed by src/net/error_unix_test.go
|
||||
EOPNOTSUPP = ENOTSUP
|
||||
)
|
||||
|
||||
// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
|
||||
var errorstr = [...]string{
|
||||
E2BIG: "Argument list too long",
|
||||
EACCES: "Permission denied",
|
||||
EADDRINUSE: "Address already in use",
|
||||
EADDRNOTAVAIL: "Address not available",
|
||||
EAFNOSUPPORT: "Address family not supported by protocol family",
|
||||
EAGAIN: "Try again",
|
||||
EALREADY: "Socket already connected",
|
||||
EBADF: "Bad file number",
|
||||
EBADFD: "file descriptor in bad state",
|
||||
EBADMSG: "Trying to read unreadable message",
|
||||
EBUSY: "Device or resource busy",
|
||||
ECANCELED: "Operation canceled.",
|
||||
ECHILD: "No child processes",
|
||||
ECONNABORTED: "Connection aborted",
|
||||
ECONNREFUSED: "Connection refused",
|
||||
ECONNRESET: "Connection reset by peer",
|
||||
EDEADLK: "Deadlock condition",
|
||||
EDESTADDRREQ: "Destination address required",
|
||||
EDOM: "Math arg out of domain of func",
|
||||
EDQUOT: "Quota exceeded",
|
||||
EEXIST: "File exists",
|
||||
EFAULT: "Bad address",
|
||||
EFBIG: "File too large",
|
||||
EHOSTUNREACH: "Host is unreachable",
|
||||
EIDRM: "Identifier removed",
|
||||
EILSEQ: "EILSEQ",
|
||||
EINPROGRESS: "Connection already in progress",
|
||||
EINTR: "Interrupted system call",
|
||||
EINVAL: "Invalid argument",
|
||||
EIO: "I/O error",
|
||||
EISCONN: "Socket is already connected",
|
||||
EISDIR: "Is a directory",
|
||||
ELOOP: "Too many symbolic links",
|
||||
EMFILE: "Too many open files",
|
||||
EMLINK: "Too many links",
|
||||
EMSGSIZE: "Message too long",
|
||||
EMULTIHOP: "Multihop attempted",
|
||||
ENAMETOOLONG: "File name too long",
|
||||
ENETDOWN: "Network interface is not configured",
|
||||
ENETRESET: "Network dropped connection on reset",
|
||||
ENETUNREACH: "Network is unreachable",
|
||||
ENFILE: "File table overflow",
|
||||
ENOBUFS: "No buffer space available",
|
||||
ENODEV: "No such device",
|
||||
ENOENT: "No such file or directory",
|
||||
ENOEXEC: "Exec format error",
|
||||
ENOLCK: "No record locks available",
|
||||
ENOLINK: "The link has been severed",
|
||||
ENOMEM: "Out of memory",
|
||||
ENOMSG: "No message of desired type",
|
||||
ENOPROTOOPT: "Protocol not available",
|
||||
ENOSPC: "No space left on device",
|
||||
ENOSYS: "Not implemented on " + runtime.GOOS,
|
||||
ENOTCONN: "Socket is not connected",
|
||||
ENOTDIR: "Not a directory",
|
||||
ENOTEMPTY: "Directory not empty",
|
||||
ENOTRECOVERABLE: "State not recoverable",
|
||||
ENOTSOCK: "Socket operation on non-socket",
|
||||
ENOTSUP: "Not supported",
|
||||
ENOTTY: "Not a typewriter",
|
||||
ENXIO: "No such device or address",
|
||||
EOVERFLOW: "Value too large for defined data type",
|
||||
EOWNERDEAD: "Owner died",
|
||||
EPERM: "Operation not permitted",
|
||||
EPIPE: "Broken pipe",
|
||||
EPROTO: "Protocol error",
|
||||
EPROTONOSUPPORT: "Unknown protocol",
|
||||
EPROTOTYPE: "Protocol wrong type for socket",
|
||||
ERANGE: "Math result not representable",
|
||||
EROFS: "Read-only file system",
|
||||
ESPIPE: "Illegal seek",
|
||||
ESRCH: "No such process",
|
||||
ESTALE: "Stale file handle",
|
||||
ETIMEDOUT: "Connection timed out",
|
||||
ETXTBSY: "Text file busy",
|
||||
EXDEV: "Cross-device link",
|
||||
ENOTCAPABLE: "Capabilities insufficient",
|
||||
}
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
var (
|
||||
errEAGAIN error = EAGAIN
|
||||
errEINVAL error = EINVAL
|
||||
errENOENT error = ENOENT
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
//
|
||||
// We set both noinline and nosplit to reduce code size, this function has many
|
||||
// call sites in the syscall package, inlining it causes a significant increase
|
||||
// of the compiled code; the function call ultimately does not make a difference
|
||||
// in the performance of syscall functions since the time is dominated by calls
|
||||
// to the imports and path resolution.
|
||||
//
|
||||
//go:noinline
|
||||
//go:nosplit
|
||||
func errnoErr(e Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case EAGAIN:
|
||||
return errEAGAIN
|
||||
case EINVAL:
|
||||
return errEINVAL
|
||||
case ENOENT:
|
||||
return errENOENT
|
||||
}
|
||||
return e
|
||||
}
|
||||
36
runtime/internal/clite/syscall/timestruct.go
Normal file
36
runtime/internal/clite/syscall/timestruct.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1
|
||||
|
||||
package syscall
|
||||
|
||||
// TimespecToNsec returns the time stored in ts as nanoseconds.
|
||||
func TimespecToNsec(ts Timespec) int64 { return ts.Nano() }
|
||||
|
||||
// NsecToTimespec converts a number of nanoseconds into a [Timespec].
|
||||
// func NsecToTimespec(nsec int64) Timespec {
|
||||
// sec := nsec / 1e9
|
||||
// nsec = nsec % 1e9
|
||||
// if nsec < 0 {
|
||||
// nsec += 1e9
|
||||
// sec--
|
||||
// }
|
||||
// return setTimespec(sec, nsec)
|
||||
// }
|
||||
|
||||
// TimevalToNsec returns the time stored in tv as nanoseconds.
|
||||
func TimevalToNsec(tv Timeval) int64 { return tv.Nano() }
|
||||
|
||||
// // NsecToTimeval converts a number of nanoseconds into a [Timeval].
|
||||
// func NsecToTimeval(nsec int64) Timeval {
|
||||
// nsec += 999 // round up to microsecond
|
||||
// usec := nsec % 1e9 / 1e3
|
||||
// sec := nsec / 1e9
|
||||
// if usec < 0 {
|
||||
// usec += 1e6
|
||||
// sec--
|
||||
// }
|
||||
// return setTimeval(sec, usec)
|
||||
// }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user