Compare commits

..

81 Commits

Author SHA1 Message Date
xushiwei
8882c31eb4 Merge pull request #1090 from xushiwei/cppkg
xtool/cppkg: support latest version
2025-05-04 17:40:07 +08:00
xushiwei
8455ee8226 xtool/cppkg: support latest version 2025-05-04 17:34:02 +08:00
xushiwei
3f74aded8a Merge pull request #1089 from xushiwei/cppkg
llgo cppkg: remove unused import
2025-05-04 16:44:38 +08:00
xushiwei
2e19c2013c llgo cppkg: remove unused import 2025-05-04 16:43:07 +08:00
xushiwei
1edaa2d09b Merge pull request #1088 from xushiwei/cppkg
cmd: llgo cppkg install
2025-05-04 16:06:20 +08:00
xushiwei
beee018287 cmd: llgo cppkg install 2025-05-04 16:01:58 +08:00
xushiwei
34266ea59d Merge pull request #1087 from xushiwei/cppkg
llgo.next => llgo
2025-05-04 15:39:50 +08:00
xushiwei
f26127ce98 llgo.next => llgo 2025-05-04 15:34:32 +08:00
xushiwei
ccf321d178 Merge pull request #1086 from xushiwei/cppkg
llgo.next: support build, run, cmptest
2025-05-04 15:23:40 +08:00
xushiwei
355721c47a llgo.next: support build, run, cmptest 2025-05-04 15:18:49 +08:00
xushiwei
d400663e5d Merge pull request #1085 from xushiwei/cppkg
cmd: llgo.next
2025-05-04 14:14:10 +08:00
xushiwei
2203be945a codecov: ignore llgo.next 2025-05-04 14:10:43 +08:00
xushiwei
b9a2bf4b42 fmt: ignore gop_autogen.go 2025-05-04 14:08:43 +08:00
xushiwei
cc08195cf2 cmd: llgo.next 2025-05-04 14:04:43 +08:00
xushiwei
50c40a7828 Merge pull request #1084 from xushiwei/cppkg
go mod tidy
2025-05-04 10:41:57 +08:00
xushiwei
158be3f949 go mod tidy 2025-05-04 10:28:24 +08:00
xushiwei
0f87c322ca Merge pull request #1082 from xushiwei/cppkg
xtool/cppkg: Main => Install
2025-05-04 00:15:26 +08:00
xushiwei
d5dd19b64c xtool/cppkg: Main => Install 2025-05-04 00:08:20 +08:00
xushiwei
3032d730b7 Merge pull request #1079 from xushiwei/q
package: xtool/cppkg
2025-05-03 23:22:55 +08:00
xushiwei
e93e7126b6 package: xtool/cppkg 2025-05-03 23:13:10 +08:00
xushiwei
9bcf41d28f Merge pull request #1078 from xushiwei/q
github api: release, tag, commit
2025-05-03 22:58:01 +08:00
xushiwei
604ce47d5e github api: release, tag, commit 2025-05-03 22:50:04 +08:00
xushiwei
e1ebe150d4 Merge pull request #1077 from goplus/dependabot/go_modules/github.com/goplus/gogen-1.17.3
build(deps): bump github.com/goplus/gogen from 1.17.2 to 1.17.3
2025-04-28 08:28:56 +08:00
dependabot[bot]
ae992737e8 build(deps): bump github.com/goplus/gogen from 1.17.2 to 1.17.3
Bumps [github.com/goplus/gogen](https://github.com/goplus/gogen) from 1.17.2 to 1.17.3.
- [Release notes](https://github.com/goplus/gogen/releases)
- [Commits](https://github.com/goplus/gogen/compare/v1.17.2...v1.17.3)

---
updated-dependencies:
- dependency-name: github.com/goplus/gogen
  dependency-version: 1.17.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 00:15:49 +00:00
xushiwei
c59d609eb8 Merge pull request #1076 from xushiwei/t
_cmptest: mathbigdemo
2025-04-28 01:18:10 +08:00
xushiwei
9f26d12a3e _cmptest: mathbigdemo 2025-04-28 01:03:13 +08:00
xushiwei
9102577eba Merge pull request #1075 from xushiwei/t
go/parser demo
2025-04-28 00:46:00 +08:00
xushiwei
f0fcfde22b README: go/parser 2025-04-28 00:37:11 +08:00
xushiwei
d9d813db56 go/parser demo 2025-04-28 00:35:45 +08:00
xushiwei
a8808855ae Merge pull request #1074 from visualfc/fix_amd64
runtime/internal/clite/pthread/sync/sync_darwin_amd64: PthreadMutexSize = 64
2025-04-27 16:20:35 +08:00
visualfc
5583f9418a runtime/internal/clite/pthread/sync/sync_darwin_amd64: PthreadMutexSize = 64 2025-04-27 12:40:32 +08:00
xushiwei
7369ffd2aa Merge pull request #1073 from xushiwei/t
_demo: hello
2025-04-26 23:04:06 +08:00
xushiwei
ab15f30b13 _demo: hello 2025-04-26 22:55:46 +08:00
xushiwei
8bff07d66b Merge pull request #1072 from xushiwei/t
fix #965 Dead loop in cl/blocks.Infos
2025-04-26 22:38:45 +08:00
xushiwei
e2e2cb38be fix #965 2025-04-26 22:23:36 +08:00
xushiwei
10d84a6a6b Merge pull request #1070 from goplus/dependabot/go_modules/github.com/goplus/mod-0.16.0
build(deps): bump github.com/goplus/mod from 0.15.1 to 0.16.0
2025-04-26 06:40:51 +08:00
dependabot[bot]
a4b4c1574b build(deps): bump github.com/goplus/mod from 0.15.1 to 0.16.0
Bumps [github.com/goplus/mod](https://github.com/goplus/mod) from 0.15.1 to 0.16.0.
- [Release notes](https://github.com/goplus/mod/releases)
- [Commits](https://github.com/goplus/mod/compare/v0.15.1...v0.16.0)

---
updated-dependencies:
- dependency-name: github.com/goplus/mod
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-25 22:33:17 +00:00
xushiwei
94bc39bdb2 Merge pull request #1071 from goplus/dependabot/go_modules/github.com/qiniu/x-1.13.19
build(deps): bump github.com/qiniu/x from 1.13.18 to 1.13.19
2025-04-26 06:32:13 +08:00
dependabot[bot]
7c93b37125 build(deps): bump github.com/qiniu/x from 1.13.18 to 1.13.19
Bumps [github.com/qiniu/x](https://github.com/qiniu/x) from 1.13.18 to 1.13.19.
- [Release notes](https://github.com/qiniu/x/releases)
- [Commits](https://github.com/qiniu/x/compare/v1.13.18...v1.13.19)

---
updated-dependencies:
- dependency-name: github.com/qiniu/x
  dependency-version: 1.13.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-22 00:11:24 +00:00
xushiwei
4371cc10bd Merge pull request #1068 from goplus/dependabot/go_modules/github.com/qiniu/x-1.13.18
build(deps): bump github.com/qiniu/x from 1.13.17 to 1.13.18
2025-04-22 00:55:37 +08:00
xushiwei
eaa2628934 Merge pull request #1069 from goplus/dependabot/go_modules/github.com/goplus/gogen-1.17.2
build(deps): bump github.com/goplus/gogen from 1.17.1 to 1.17.2
2025-04-21 22:21:09 +08:00
dependabot[bot]
30e247186c build(deps): bump github.com/goplus/gogen from 1.17.1 to 1.17.2
Bumps [github.com/goplus/gogen](https://github.com/goplus/gogen) from 1.17.1 to 1.17.2.
- [Release notes](https://github.com/goplus/gogen/releases)
- [Commits](https://github.com/goplus/gogen/compare/v1.17.1...v1.17.2)

---
updated-dependencies:
- dependency-name: github.com/goplus/gogen
  dependency-version: 1.17.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-21 00:49:42 +00:00
dependabot[bot]
2714da8d98 build(deps): bump github.com/qiniu/x from 1.13.17 to 1.13.18
Bumps [github.com/qiniu/x](https://github.com/qiniu/x) from 1.13.17 to 1.13.18.
- [Release notes](https://github.com/qiniu/x/releases)
- [Commits](https://github.com/qiniu/x/compare/v1.13.17...v1.13.18)

---
updated-dependencies:
- dependency-name: github.com/qiniu/x
  dependency-version: 1.13.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-21 00:48:47 +00:00
xushiwei
0ef3a7ec25 Merge pull request #1067 from cpunion/llgo-env
Fix args parsing
2025-04-18 19:42:14 +08:00
Li Jie
489a0069aa extract common cmd flags 2025-04-18 13:12:05 +08:00
xushiwei
a257b7bdfa Merge pull request #1059 from cpunion/wasm-dev
Wasm dev
2025-04-18 08:55:20 +08:00
Li Jie
739cc66d0d test wasm with _demo/hello 2025-04-18 00:37:02 +08:00
Li Jie
28d944c6af remove unused wasm_import 2025-04-17 22:59:34 +08:00
Li Jie
19b98393a6 TODO: defer workaround, should remove after fix 2025-04-17 10:06:59 +08:00
Li Jie
5a13e7400e update outdated github.com/goplus/llgo/c references 2025-04-17 10:06:56 +08:00
Li Jie
a56129d675 blank syscall.SetNonblock on wasm 2025-04-17 09:58:52 +08:00
Li Jie
0d75bbace0 fix itab on 32bit 2025-04-17 09:58:52 +08:00
Li Jie
29ec4a7a0e allow config LLGO_WASM_RUNTIME with args 2025-04-17 09:58:52 +08:00
Li Jie
8b26c48d9b execute clang -v in verbose mode 2025-04-17 09:58:52 +08:00
Li Jie
ddd0535d30 split llfiles and ldflags and extract compileAndLinkLLFiles to prepare multi-phase build 2025-04-17 09:58:52 +08:00
xushiwei
adcd370c27 Merge pull request #1066 from goplus/dependabot/go_modules/github.com/goplus/mod-0.15.1
build(deps): bump github.com/goplus/mod from 0.13.17 to 0.15.1
2025-04-16 01:50:01 +08:00
dependabot[bot]
dbead0d725 build(deps): bump github.com/goplus/mod from 0.13.17 to 0.15.1
Bumps [github.com/goplus/mod](https://github.com/goplus/mod) from 0.13.17 to 0.15.1.
- [Release notes](https://github.com/goplus/mod/releases)
- [Commits](https://github.com/goplus/mod/compare/v0.13.17...v0.15.1)

---
updated-dependencies:
- dependency-name: github.com/goplus/mod
  dependency-version: 0.15.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 04:26:37 +00:00
xushiwei
207aea813b Merge pull request #1065 from goplus/dependabot/go_modules/github.com/goplus/gogen-1.17.1
build(deps): bump github.com/goplus/gogen from 1.16.9 to 1.17.1
2025-04-14 12:25:03 +08:00
xushiwei
7a771154a7 Merge pull request #1063 from goplus/dependabot/go_modules/github.com/qiniu/x-1.13.17
build(deps): bump github.com/qiniu/x from 1.13.12 to 1.13.17
2025-04-14 12:24:38 +08:00
dependabot[bot]
18c6b9b404 build(deps): bump github.com/goplus/gogen from 1.16.9 to 1.17.1
Bumps [github.com/goplus/gogen](https://github.com/goplus/gogen) from 1.16.9 to 1.17.1.
- [Release notes](https://github.com/goplus/gogen/releases)
- [Commits](https://github.com/goplus/gogen/compare/v1.16.9...v1.17.1)

---
updated-dependencies:
- dependency-name: github.com/goplus/gogen
  dependency-version: 1.17.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 00:40:41 +00:00
Li Jie
3110382d88 fix abi methods crash on wasm 2025-04-11 17:16:02 +08:00
Li Jie
9ee55896e3 update link args for wasm target 2025-04-11 16:28:48 +08:00
Li Jie
ad6f41f312 add LLGO_STDIO_NOBUF to toggle stdout/stderr buffer 2025-04-11 16:28:48 +08:00
Li Jie
8512395985 AllocCStr allocates on heap 2025-04-11 16:28:48 +08:00
Li Jie
7284042823 run wasm with iwasm 2025-04-11 16:28:47 +08:00
Li Jie
0ef683bba9 add LLGO_WASI_THREADS to toggle wasi threads support 2025-04-11 16:28:47 +08:00
Li Jie
d4bf66936a specify setjmp/longjmp function names on wasm 2025-04-11 16:28:47 +08:00
Li Jie
be4737461a make runtime compatible with wasm 2025-04-11 16:28:44 +08:00
dependabot[bot]
0d22b3be05 build(deps): bump github.com/qiniu/x from 1.13.12 to 1.13.17
Bumps [github.com/qiniu/x](https://github.com/qiniu/x) from 1.13.12 to 1.13.17.
- [Release notes](https://github.com/qiniu/x/releases)
- [Commits](https://github.com/qiniu/x/compare/v1.13.12...v1.13.17)

---
updated-dependencies:
- dependency-name: github.com/qiniu/x
  dependency-version: 1.13.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-11 00:33:04 +00:00
Li Jie
7c81d9293b blank ffi for wasm 2025-04-09 14:57:33 +08:00
Li Jie
d1dce65313 update link flags 2025-04-09 14:57:33 +08:00
Li Jie
641f9bbf7c select WASM runtime by LLGO_WASM_RUNTIME 2025-04-09 14:57:32 +08:00
xushiwei
be0e42cf82 Merge pull request #1057 from cpunion/cross-compiling
Cross compiling
2025-04-09 14:26:09 +08:00
Li Jie
3a883b8821 upgrade to github.com/goplus/lib v0.2.0 2025-04-08 19:32:26 +08:00
Li Jie
4bbc58d62d test cross compile on macos 2025-04-08 11:53:21 +08:00
Li Jie
5f4b09bede regenerate snapshot tests 2025-04-08 11:13:00 +08:00
Li Jie
f0ade21155 update docs and CI 2025-04-08 11:12:59 +08:00
Li Jie
f35063ee6e build: download and compile with wasi-sdk 2025-04-08 11:12:57 +08:00
Li Jie
e6c7627ee8 cross compilation 2025-04-08 10:46:14 +08:00
Li Jie
a85d937482 enable command tests 2025-04-08 09:38:00 +08:00
Li Jie
b17632a352 xtool: clang.Cmd supports Env/Verbose/Stdio, add CCFLAGS support 2025-04-08 09:25:49 +08:00
270 changed files with 18206 additions and 1052 deletions

View File

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

4
.github/codecov.yml vendored
View File

@@ -1,9 +1,11 @@
coverage:
ignore:
- "chore"
- "cmd/internal"
- "cmd"
- "internal/build"
- "internal/llgen"
- "internal/mockable"
- "internal/packages"
- "internal/typepatch"
- "internal/github"
- "xtool/cppkg"

View File

@@ -2,9 +2,9 @@ name: Docs
on:
push:
branches: [ "**" ]
branches: ["**"]
pull_request:
branches: [ "**" ]
branches: ["**"]
jobs:
doc_verify:
@@ -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: |

View File

@@ -2,9 +2,9 @@ name: Format Check
on:
push:
branches: [ "**" ]
branches: ["**"]
pull_request:
branches: [ "**" ]
branches: ["**"]
jobs:
fmt:
@@ -15,13 +15,13 @@ 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: |
for dir in . runtime; do
pushd $dir
if [ -n "$(go fmt ./...)" ]; then
if [ -n "$(go fmt ./... | grep -v gop_autogen.go)" ]; then
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
exit 1
fi

View File

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

View File

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

View File

@@ -335,6 +335,7 @@ Here are the Go packages that can be imported correctly:
* [regexp/syntax](https://pkg.go.dev/regexp/syntax)
* [go/token](https://pkg.go.dev/go/token)
* [go/scanner](https://pkg.go.dev/go/scanner)
* [go/parser](https://pkg.go.dev/go/parser)
## Dependencies
@@ -361,7 +362,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
```

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,3 @@ func main() {
fmt.Println("hello world by fmt.Println")
c.Printf(c.Str("Hello world by c.Printf\n"))
}
/* Expected output:
Hello world
*/

15
_demo/helloc/helloc.go Normal file
View 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))
}

View File

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

View File

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

View File

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

View File

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

View File

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

737
cl/_testdefer/gobuild/in.go Normal file
View File

@@ -0,0 +1,737 @@
package main
import (
"errors"
"fmt"
"go/ast"
"go/doc"
"go/token"
"io/fs"
"os"
pathpkg "path"
"runtime"
"slices"
"strconv"
"strings"
)
func IsLocalImport(path string) bool {
return true
}
func isAbsPath(path string) bool {
return strings.HasPrefix(path, "/")
}
func isDir(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}
return fi.IsDir()
}
func isFile(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}
return fi.Mode().IsRegular()
}
func joinPath(a string, b ...string) string {
if isAbsPath(b[0]) {
return b[0]
}
return pathpkg.Join(append([]string{a}, b...)...)
}
func nameExt(path string) string {
return ""
}
func gopath() []string {
all := make([]string, 0, 10)
for _, p := range strings.Split(os.Getenv("GOPATH"), ":") {
if p != "" {
all = append(all, p)
}
}
return all
}
type Context struct {
InstallSuffix string
Compiler string
GOOS string
GOARCH string
GOROOT string
CgoEnabled bool
}
type Package struct {
ImportPath string
Dir string
Goroot bool
Root string
ConflictDir string
SrcRoot string
PkgRoot string
BinDir string
PkgTargetRoot string
PkgObj string
InvalidGoFiles []string
IgnoredGoFiles []string
IgnoredOtherFiles []string
CgoFiles []string
XTestGoFiles []string
TestGoFiles []string
GoFiles []string
Directives []Directive
TestDirectives []Directive
XTestDirectives []Directive
BinaryOnly bool
Name string
Doc string
ImportComment string
AllTags []string
EmbedPatterns []string
TestEmbedPatterns []string
XTestEmbedPatterns []string
Imports []string
TestImports []string
XTestImports []string
EmbedPatternPos map[string][]token.Position
TestEmbedPatternPos map[string][]token.Position
XTestEmbedPatternPos map[string][]token.Position
ImportPos map[string][]token.Position
TestImportPos map[string][]token.Position
XTestImportPos map[string][]token.Position
SFiles []string
}
type Directive struct {
}
type MultiplePackageError struct {
Dir string
Packages []string
Files []string
}
func (e *MultiplePackageError) Error() string {
return fmt.Sprintf("multiple packages in single directory: %s\n\t%s\n\t%s", e.Dir, strings.Join(e.Packages, "\n\t"), strings.Join(e.Files, "\n\t"))
}
type ImportMode = uint
const (
IgnoreVendor ImportMode = 1 << iota
AllowBinary
FindOnly
ImportComment
)
func importGo(ctx *Context, p *Package, path, srcDir string, mode ImportMode) error {
return nil
}
func hasSubdir(root, sub string) (string, bool) {
return sub, true
}
func hasGoFiles(ctxt *Context, file string) bool {
return true
}
func isStandardImportPath(path string) bool {
return true
}
func readDir(name string) ([]os.DirEntry, error) {
return nil, nil
}
func findImportComment(data []byte) (s string, line int) {
return "", 0
}
func saveCgo(ctxt *Context, filename string, p *Package, doc *ast.CommentGroup) error {
return nil
}
func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
return nil, nil
}
func fileListForExt(p *Package, ext string) *[]string {
return nil
}
type fileInfo struct {
name string // full name including dir
header []byte
fset *token.FileSet
parsed *ast.File
parseErr error
imports []fileImport
embeds []fileEmbed
directives []Directive
}
type fileImport struct {
path string
pos token.Pos
doc *ast.CommentGroup
}
type fileEmbed struct {
pattern string
pos token.Position
}
func matchFile(ctxt *Context, dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
return nil, nil
}
var errNoModules = errors.New("no modules")
type godebug struct {
name string
}
func NewGodebug(name string) *godebug {
return &godebug{
name: name,
}
}
func (g *godebug) IncNonDefault() {
}
func (g *godebug) Value() string {
return g.name
}
var installgoroot = NewGodebug("installgoroot")
func IsStandardPackage(a, b, c string) bool {
return true
}
type NoGoError struct {
Dir string
}
func (e *NoGoError) Error() string {
return "no Go files in " + e.Dir
}
func Import(ctxt *Context, path string, srcDir string, mode ImportMode) (*Package, error) {
p := &Package{
ImportPath: path,
}
if path == "" {
return p, fmt.Errorf("import %q: invalid import path", path)
}
var pkgtargetroot string
var pkga string
var pkgerr error
suffix := ""
if ctxt.InstallSuffix != "" {
suffix = "_" + ctxt.InstallSuffix
}
switch ctxt.Compiler {
case "gccgo":
pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
case "gc":
pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
default:
// Save error for end of function.
pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
}
setPkga := func() {
switch ctxt.Compiler {
case "gccgo":
dir, elem := pathpkg.Split(p.ImportPath)
pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
case "gc":
pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
}
}
setPkga()
binaryOnly := false
if IsLocalImport(path) {
pkga = "" // local imports have no installed path
if srcDir == "" {
return p, fmt.Errorf("import %q: import relative to unknown directory", path)
}
if !isAbsPath(path) {
p.Dir = joinPath(srcDir, path)
}
// p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
// Determine canonical import path, if any.
// Exclude results where the import path would include /testdata/.
inTestdata := func(sub string) bool {
return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
}
if ctxt.GOROOT != "" {
root := joinPath(runtime.GOROOT(), "src")
if sub, ok := hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
p.Goroot = true
p.ImportPath = sub
p.Root = ctxt.GOROOT
setPkga() // p.ImportPath changed
goto Found
}
}
all := gopath()
for i, root := range all {
rootsrc := joinPath(root, "src")
if sub, ok := hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
// We found a potential import path for dir,
// but check that using it wouldn't find something
// else first.
if runtime.GOROOT() != "" && ctxt.Compiler != "gccgo" {
if dir := joinPath(runtime.GOROOT(), "src", sub); isDir(dir) {
p.ConflictDir = dir
goto Found
}
}
for _, earlyRoot := range all[:i] {
if dir := joinPath(earlyRoot, "src", sub); isDir(dir) {
p.ConflictDir = dir
goto Found
}
}
// sub would not name some other directory instead of this one.
// Record it.
p.ImportPath = sub
p.Root = root
setPkga() // p.ImportPath changed
goto Found
}
}
// It's okay that we didn't find a root containing dir.
// Keep going with the information we have.
} else {
if strings.HasPrefix(path, "/") {
return p, fmt.Errorf("import %q: cannot import absolute path", path)
}
if err := importGo(ctxt, p, path, srcDir, mode); err == nil {
goto Found
} else if err != errNoModules {
return p, err
}
gopath := gopath() // needed twice below; avoid computing many times
// tried records the location of unsuccessful package lookups
var tried struct {
vendor []string
goroot string
gopath []string
}
// Vendor directories get first chance to satisfy import.
if mode&IgnoreVendor == 0 && srcDir != "" {
searchVendor := func(root string, isGoroot bool) bool {
sub, ok := hasSubdir(root, srcDir)
if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
return false
}
for {
vendor := joinPath(root, sub, "vendor")
if isDir(vendor) {
dir := joinPath(vendor, path)
if isDir(dir) && hasGoFiles(ctxt, dir) {
p.Dir = dir
p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
p.Goroot = isGoroot
p.Root = root
setPkga() // p.ImportPath changed
return true
}
tried.vendor = append(tried.vendor, dir)
}
i := strings.LastIndex(sub, "/")
if i < 0 {
break
}
sub = sub[:i]
}
return false
}
if ctxt.Compiler != "gccgo" && ctxt.GOROOT != "" && searchVendor(ctxt.GOROOT, true) {
goto Found
}
for _, root := range gopath {
if searchVendor(root, false) {
goto Found
}
}
}
// Determine directory from import path.
if ctxt.GOROOT != "" {
// If the package path starts with "vendor/", only search GOROOT before
// GOPATH if the importer is also within GOROOT. That way, if the user has
// vendored in a package that is subsequently included in the standard
// distribution, they'll continue to pick up their own vendored copy.
gorootFirst := srcDir == "" || !strings.HasPrefix(path, "vendor/")
if !gorootFirst {
_, gorootFirst = hasSubdir(runtime.GOROOT(), srcDir)
}
if gorootFirst {
dir := joinPath(runtime.GOROOT(), "src", path)
if ctxt.Compiler != "gccgo" {
isDir := isDir(dir)
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(runtime.GOROOT(), pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Goroot = true
p.Root = runtime.GOROOT()
goto Found
}
}
tried.goroot = dir
}
if ctxt.Compiler == "gccgo" && IsStandardPackage(runtime.GOROOT(), ctxt.Compiler, path) {
// TODO(bcmills): Setting p.Dir here is misleading, because gccgo
// doesn't actually load its standard-library packages from this
// directory. See if we can leave it unset.
p.Dir = joinPath(runtime.GOROOT(), "src", path)
p.Goroot = true
p.Root = runtime.GOROOT()
goto Found
}
}
for _, root := range gopath {
dir := joinPath(root, "src", path)
isDir := isDir(dir)
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(root, pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Root = root
goto Found
}
tried.gopath = append(tried.gopath, dir)
}
// If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH.
// That way, the user can still get useful results from 'go list' for
// standard-vendored paths passed on the command line.
if runtime.GOROOT() != "" && tried.goroot == "" {
dir := joinPath(runtime.GOROOT(), "src", path)
if ctxt.Compiler != "gccgo" {
isDir := isDir(dir)
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(runtime.GOROOT(), pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Goroot = true
p.Root = runtime.GOROOT()
goto Found
}
}
tried.goroot = dir
}
// package was not found
var paths []string
format := "\t%s (vendor tree)"
for _, dir := range tried.vendor {
paths = append(paths, fmt.Sprintf(format, dir))
format = "\t%s"
}
if tried.goroot != "" {
paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
} else {
paths = append(paths, "\t($GOROOT not set)")
}
format = "\t%s (from $GOPATH)"
for _, dir := range tried.gopath {
paths = append(paths, fmt.Sprintf(format, dir))
format = "\t%s"
}
if len(tried.gopath) == 0 {
paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
}
return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
}
Found:
if p.Root != "" {
p.SrcRoot = joinPath(p.Root, "src")
p.PkgRoot = joinPath(p.Root, "pkg")
p.BinDir = joinPath(p.Root, "bin")
if pkga != "" {
// Always set PkgTargetRoot. It might be used when building in shared
// mode.
p.PkgTargetRoot = joinPath(p.Root, pkgtargetroot)
// Set the install target if applicable.
if !p.Goroot || (installgoroot.Value() == "all" && p.ImportPath != "unsafe" && p.ImportPath != "builtin") {
if p.Goroot {
installgoroot.IncNonDefault()
}
p.PkgObj = joinPath(p.Root, pkga)
}
}
}
// If it's a local import path, by the time we get here, we still haven't checked
// that p.Dir directory exists. This is the right time to do that check.
// We can't do it earlier, because we want to gather partial information for the
// non-nil *Package returned when an error occurs.
// We need to do this before we return early on FindOnly flag.
if IsLocalImport(path) && !isDir(p.Dir) {
if ctxt.Compiler == "gccgo" && p.Goroot {
// gccgo has no sources for GOROOT packages.
return p, nil
}
// package was not found
return p, fmt.Errorf("cannot find package %q in:\n\t%s", p.ImportPath, p.Dir)
}
if mode&FindOnly != 0 {
return p, pkgerr
}
if binaryOnly && (mode&AllowBinary) != 0 {
return p, pkgerr
}
if ctxt.Compiler == "gccgo" && p.Goroot {
// gccgo has no sources for GOROOT packages.
return p, nil
}
dirs, err := readDir(p.Dir)
if err != nil {
return p, err
}
var badGoError error
badGoFiles := make(map[string]bool)
badGoFile := func(name string, err error) {
if badGoError == nil {
badGoError = err
}
if !badGoFiles[name] {
p.InvalidGoFiles = append(p.InvalidGoFiles, name)
badGoFiles[name] = true
}
}
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
var firstFile, firstCommentFile string
embedPos := make(map[string][]token.Position)
testEmbedPos := make(map[string][]token.Position)
xTestEmbedPos := make(map[string][]token.Position)
importPos := make(map[string][]token.Position)
testImportPos := make(map[string][]token.Position)
xTestImportPos := make(map[string][]token.Position)
allTags := make(map[string]bool)
fset := token.NewFileSet()
for _, d := range dirs {
if d.IsDir() {
continue
}
if d.Type() == fs.ModeSymlink {
if isDir(joinPath(p.Dir, d.Name())) {
// Symlinks to directories are not source files.
continue
}
}
name := d.Name()
ext := nameExt(name)
info, err := matchFile(ctxt, p.Dir, name, allTags, &p.BinaryOnly, fset)
if err != nil && strings.HasSuffix(name, ".go") {
badGoFile(name, err)
continue
}
if info == nil {
if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
// not due to build constraints - don't report
} else if ext == ".go" {
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
} else if fileListForExt(p, ext) != nil {
p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, name)
}
continue
}
// Going to save the file. For non-Go files, can stop here.
switch ext {
case ".go":
// keep going
case ".S", ".sx":
// special case for cgo, handled at end
Sfiles = append(Sfiles, name)
continue
default:
if list := fileListForExt(p, ext); list != nil {
*list = append(*list, name)
}
continue
}
data, filename := info.header, info.name
if info.parseErr != nil {
badGoFile(name, info.parseErr)
// Fall through: we might still have a partial AST in info.parsed,
// and we want to list files with parse errors anyway.
}
var pkg string
if info.parsed != nil {
pkg = info.parsed.Name.Name
if pkg == "documentation" {
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
continue
}
}
isTest := strings.HasSuffix(name, "_test.go")
isXTest := false
if isTest && strings.HasSuffix(pkg, "_test") && p.Name != pkg {
isXTest = true
pkg = pkg[:len(pkg)-len("_test")]
}
if p.Name == "" {
p.Name = pkg
firstFile = name
} else if pkg != p.Name {
// TODO(#45999): The choice of p.Name is arbitrary based on file iteration
// order. Instead of resolving p.Name arbitrarily, we should clear out the
// existing name and mark the existing files as also invalid.
badGoFile(name, &MultiplePackageError{
Dir: p.Dir,
Packages: []string{p.Name, pkg},
Files: []string{firstFile, name},
})
}
// Grab the first package comment as docs, provided it is not from a test file.
if info.parsed != nil && info.parsed.Doc != nil && p.Doc == "" && !isTest && !isXTest {
p.Doc = doc.Synopsis(info.parsed.Doc.Text())
}
if mode&ImportComment != 0 {
qcom, line := findImportComment(data)
if line != 0 {
com, err := strconv.Unquote(qcom)
if err != nil {
badGoFile(name, fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
} else if p.ImportComment == "" {
p.ImportComment = com
firstCommentFile = name
} else if p.ImportComment != com {
badGoFile(name, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
}
}
}
// Record imports and information about cgo.
isCgo := false
for _, imp := range info.imports {
if imp.path == "C" {
if isTest {
badGoFile(name, fmt.Errorf("use of cgo in test %s not supported", filename))
continue
}
isCgo = true
if imp.doc != nil {
if err := saveCgo(ctxt, filename, p, imp.doc); err != nil {
badGoFile(name, err)
}
}
}
}
var fileList *[]string
var importMap, embedMap map[string][]token.Position
var directives *[]Directive
switch {
case isCgo:
allTags["cgo"] = true
if ctxt.CgoEnabled {
fileList = &p.CgoFiles
importMap = importPos
embedMap = embedPos
directives = &p.Directives
} else {
// Ignore imports and embeds from cgo files if cgo is disabled.
fileList = &p.IgnoredGoFiles
}
case isXTest:
fileList = &p.XTestGoFiles
importMap = xTestImportPos
embedMap = xTestEmbedPos
directives = &p.XTestDirectives
case isTest:
fileList = &p.TestGoFiles
importMap = testImportPos
embedMap = testEmbedPos
directives = &p.TestDirectives
default:
fileList = &p.GoFiles
importMap = importPos
embedMap = embedPos
directives = &p.Directives
}
*fileList = append(*fileList, name)
if importMap != nil {
for _, imp := range info.imports {
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
}
}
if embedMap != nil {
for _, emb := range info.embeds {
embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
}
}
if directives != nil {
*directives = append(*directives, info.directives...)
}
}
for tag := range allTags {
p.AllTags = append(p.AllTags, tag)
}
slices.Sort(p.AllTags)
p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
p.Imports, p.ImportPos = cleanDecls(importPos)
p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
// add the .S/.sx files only if we are using cgo
// (which means gcc will compile them).
// The standard assemblers expect .s files.
if len(p.CgoFiles) > 0 {
p.SFiles = append(p.SFiles, Sfiles...)
slices.Sort(p.SFiles)
} else {
p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, Sfiles...)
slices.Sort(p.IgnoredOtherFiles)
}
if badGoError != nil {
return p, badGoError
}
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
return p, &NoGoError{p.Dir}
}
return p, pkgerr
}

View File

@@ -0,0 +1,206 @@
0: always
1: cond
2: cond
3: cond
4: cond
6: cond
8: cond
7: cond
9: cond
5: cond
10: cond
11: cond
12: cond
13: cond
33: cond
34: cond
14: cond
35: cond
15: cond
36: cond
37: cond
16: cond
40: cond
19: cond
38: cond
17: cond
18: cond
43: cond
42: cond
41: cond
21: loop
22: loop
24: loop
23: cond
27: cond
25: cond
28: cond
26: cond
29: loop
30: loop
31: cond
32: cond
44: loop
45: loop
39: cond
46: cond
48: cond
49: cond
50: cond
51: cond
52: cond
54: cond
59: cond
58: cond
56: cond
57: cond
61: cond
60: cond
55: cond
53: cond
63: cond
62: cond
47: cond
64: loop
65: loop
68: loop
73: loop
72: loop
66: cond
70: cond
71: cond
76: cond
69: cond
74: cond
67: cond
77: cond
82: cond
81: cond
79: cond
80: cond
84: cond
83: cond
78: cond
20: cond
75: cond
96: cond
98: cond
100: cond
102: cond
101: cond
99: cond
103: cond
104: cond
97: cond
107: cond
106: cond
105: cond
111: cond
112: cond
110: cond
115: cond
108: cond
109: cond
113: cond
114: cond
118: cond
116: cond
117: cond
119: cond
120: cond
85: loop
86: loop
87: cond
88: cond
90: cond
89: cond
91: loop
92: loop
93: cond
94: cond
95: cond
121: loop
122: loop
123: cond
124: cond
125: cond
126: cond
129: cond
127: cond
128: cond
130: cond
131: cond
133: cond
137: cond
139: cond
132: cond
143: cond
140: cond
134: cond
135: cond
144: cond
138: cond
141: cond
136: cond
145: cond
142: cond
147: cond
146: cond
151: cond
150: cond
148: cond
149: cond
152: cond
154: cond
155: cond
153: cond
161: cond
160: cond
159: cond
158: cond
156: cond
157: cond
162: cond
164: cond
165: cond
166: cond
167: cond
168: cond
169: cond
163: cond
170: loop
171: loop
173: loop
174: loop
172: cond
175: cond
179: cond
181: cond
176: cond
182: cond
183: cond
180: cond
185: cond
177: cond
184: cond
186: cond
178: cond
187: cond
189: loop
190: loop
188: cond
191: cond
193: loop
194: loop
192: cond
195: cond
196: loop
197: loop
198: cond
199: cond
201: cond
200: cond
202: cond
203: cond
204: cond
205: cond

View File

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

View File

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

View File

@@ -60,11 +60,14 @@ func findLoop(states []*blockState, path []int, from, iblk int) []int {
path = append(path, iblk)
self := states[iblk]
for _, succ := range self.succs {
if states[succ].fdel {
if s := states[succ]; s.fdel || s.loop {
continue
}
if pos := find(path, succ); pos >= 0 {
if pos > 0 {
for _, i := range path[pos:] { // mark inner loop
states[i].loop = true
}
continue
}
for _, i := range path {
@@ -72,6 +75,11 @@ func findLoop(states []*blockState, path []int, from, iblk int) []int {
s.loop = true
s.fdel = true
}
for _, s := range states { // clear inner loop mark
if !s.fdel {
s.loop = false
}
}
return path
}
if ret := findLoop(states, path, from, succ); len(ret) > 0 {

View File

@@ -44,6 +44,9 @@ func TestTestdefer(t *testing.T) {
if strings.HasPrefix(name, "firstloop") {
return "Loop"
}
if strings.HasPrefix(name, "gobuild") {
return "Import"
}
return "main"
})
}

View File

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

View File

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

View 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,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)

View File

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

View 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")
}

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

View File

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

View File

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

View File

@@ -301,7 +301,7 @@ func main() {
}
}
func _TestCommandHandling(t *testing.T) {
func TestCommandHandling(t *testing.T) {
tests := []struct {
name string
args []string

26
cmd/llgo/build_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/cmd/internal/build"
)
short "Compile packages and dependencies"
flagOff
run args => {
self.Cmd.Run self.Cmd, args
}

26
cmd/llgo/clean_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/cmd/internal/clean"
)
short "Remove object files and cached files"
flagOff
run args => {
self.Cmd.Run self.Cmd, args
}

26
cmd/llgo/cmptest_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/cmd/internal/run"
)
short "Compile and run with llgo, compare result (stdout/stderr/exitcode) with go or llgo.expect; generate llgo.expect file if -gen is specified"
flagOff
run args => {
self.CmpTestCmd.Run self.CmpTestCmd, args
}

20
cmd/llgo/cppkg_cmd.gox Normal file
View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2025 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.
*/
short "Manage C/C++ packages"
run => {
help
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/xtool/cppkg"
)
short "Install a C/C++ package from github.com/goplus/cppkg"
long `Installs a C/C++ package with the given name and version. For example:
llgo cppkg install davegamble/cjson@1.7.18
llgo cppkg install davegamble/cjson@latest
llgo cppkg install davegamble/cjson
`
run args => {
if args.len < 1 {
help
return
}
self.install args[0], self.DefaultFlags
}

20
cmd/llgo/get_cmd.gox Normal file
View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2025 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.
*/
short "Add dependencies to current module and install them"
run args => {
panic "todo"
}

247
cmd/llgo/gop_autogen.go Normal file
View File

@@ -0,0 +1,247 @@
// Code generated by gop (Go+); DO NOT EDIT.
package main
import (
"fmt"
"github.com/goplus/cobra/xcmd"
build1 "github.com/goplus/llgo/cmd/internal/build"
clean1 "github.com/goplus/llgo/cmd/internal/clean"
install1 "github.com/goplus/llgo/cmd/internal/install"
run1 "github.com/goplus/llgo/cmd/internal/run"
test1 "github.com/goplus/llgo/cmd/internal/test"
"github.com/goplus/llgo/internal/env"
cppkg1 "github.com/goplus/llgo/xtool/cppkg"
"github.com/qiniu/x/stringutil"
"runtime"
)
const _ = true
type build struct {
xcmd.Command
*App
}
type clean struct {
xcmd.Command
*App
}
type cmptest struct {
xcmd.Command
*App
}
type cppkg struct {
xcmd.Command
*App
}
type cppkg_install struct {
xcmd.Command
*App
}
type get struct {
xcmd.Command
*App
}
type install struct {
xcmd.Command
*App
}
type run struct {
xcmd.Command
*App
}
type test struct {
xcmd.Command
*App
}
type version struct {
xcmd.Command
*App
}
type App struct {
xcmd.App
}
func (this *App) Main() {
_gop_obj0 := &build{App: this}
_gop_obj1 := &clean{App: this}
_gop_obj2 := &cmptest{App: this}
_gop_obj3 := &cppkg{App: this}
_gop_obj4 := &cppkg_install{App: this}
_gop_obj5 := &get{App: this}
_gop_obj6 := &install{App: this}
_gop_obj7 := &run{App: this}
_gop_obj8 := &test{App: this}
_gop_obj9 := &version{App: this}
xcmd.Gopt_App_Main(this, _gop_obj0, _gop_obj1, _gop_obj2, _gop_obj3, _gop_obj4, _gop_obj5, _gop_obj6, _gop_obj7, _gop_obj8, _gop_obj9)
}
//line cmd/llgo/build_cmd.gox:20
func (this *build) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/build_cmd.gox:20:1
this.Short("Compile packages and dependencies")
//line cmd/llgo/build_cmd.gox:22:1
this.FlagOff()
//line cmd/llgo/build_cmd.gox:24:1
this.Run__1(func(args []string) {
//line cmd/llgo/build_cmd.gox:25:1
build1.Cmd.Run(build1.Cmd, args)
})
}
func (this *build) Classfname() string {
return "build"
}
//line cmd/llgo/clean_cmd.gox:20
func (this *clean) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/clean_cmd.gox:20:1
this.Short("Remove object files and cached files")
//line cmd/llgo/clean_cmd.gox:22:1
this.FlagOff()
//line cmd/llgo/clean_cmd.gox:24:1
this.Run__1(func(args []string) {
//line cmd/llgo/clean_cmd.gox:25:1
clean1.Cmd.Run(clean1.Cmd, args)
})
}
func (this *clean) Classfname() string {
return "clean"
}
//line cmd/llgo/cmptest_cmd.gox:20
func (this *cmptest) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/cmptest_cmd.gox:20:1
this.Short("Compile and run with llgo, compare result (stdout/stderr/exitcode) with go or llgo.expect; generate llgo.expect file if -gen is specified")
//line cmd/llgo/cmptest_cmd.gox:22:1
this.FlagOff()
//line cmd/llgo/cmptest_cmd.gox:24:1
this.Run__1(func(args []string) {
//line cmd/llgo/cmptest_cmd.gox:25:1
run1.CmpTestCmd.Run(run1.CmpTestCmd, args)
})
}
func (this *cmptest) Classfname() string {
return "cmptest"
}
//line cmd/llgo/cppkg_cmd.gox:16
func (this *cppkg) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/cppkg_cmd.gox:16:1
this.Short("Manage C/C++ packages")
//line cmd/llgo/cppkg_cmd.gox:18:1
this.Run__0(func() {
//line cmd/llgo/cppkg_cmd.gox:19:1
this.Help()
})
}
func (this *cppkg) Classfname() string {
return "cppkg"
}
//line cmd/llgo/cppkg_install_cmd.gox:20
func (this *cppkg_install) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/cppkg_install_cmd.gox:20:1
this.Short("Install a C/C++ package from github.com/goplus/cppkg")
//line cmd/llgo/cppkg_install_cmd.gox:22:1
this.Long(`Installs a C/C++ package with the given name and version. For example:
llgo cppkg install davegamble/cjson@1.7.18
llgo cppkg install davegamble/cjson@latest
llgo cppkg install davegamble/cjson
`)
//line cmd/llgo/cppkg_install_cmd.gox:29:1
this.Run__1(func(args []string) {
//line cmd/llgo/cppkg_install_cmd.gox:30:1
if len(args) < 1 {
//line cmd/llgo/cppkg_install_cmd.gox:31:1
this.Help()
//line cmd/llgo/cppkg_install_cmd.gox:32:1
return
}
//line cmd/llgo/cppkg_install_cmd.gox:35:1
cppkg1.Install(args[0], cppkg1.DefaultFlags)
})
}
func (this *cppkg_install) Classfname() string {
return "cppkg_install"
}
//line cmd/llgo/get_cmd.gox:16
func (this *get) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/get_cmd.gox:16:1
this.Short("Add dependencies to current module and install them")
//line cmd/llgo/get_cmd.gox:18:1
this.Run__1(func(args []string) {
//line cmd/llgo/get_cmd.gox:19:1
panic("todo")
})
}
func (this *get) Classfname() string {
return "get"
}
//line cmd/llgo/install_cmd.gox:20
func (this *install) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/install_cmd.gox:20:1
this.Short("Compile and install packages and dependencies")
//line cmd/llgo/install_cmd.gox:22:1
this.FlagOff()
//line cmd/llgo/install_cmd.gox:24:1
this.Run__1(func(args []string) {
//line cmd/llgo/install_cmd.gox:25:1
install1.Cmd.Run(install1.Cmd, args)
})
}
func (this *install) Classfname() string {
return "install"
}
//line cmd/llgo/run_cmd.gox:20
func (this *run) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/run_cmd.gox:20:1
this.Short("Compile and run Go program")
//line cmd/llgo/run_cmd.gox:22:1
this.FlagOff()
//line cmd/llgo/run_cmd.gox:24:1
this.Run__1(func(args []string) {
//line cmd/llgo/run_cmd.gox:25:1
run1.Cmd.Run(run1.Cmd, args)
})
}
func (this *run) Classfname() string {
return "run"
}
//line cmd/llgo/test_cmd.gox:20
func (this *test) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/test_cmd.gox:20:1
this.Short("Compile and run Go test")
//line cmd/llgo/test_cmd.gox:22:1
this.FlagOff()
//line cmd/llgo/test_cmd.gox:24:1
this.Run__1(func(args []string) {
//line cmd/llgo/test_cmd.gox:25:1
test1.Cmd.Run(test1.Cmd, args)
})
}
func (this *test) Classfname() string {
return "test"
}
//line cmd/llgo/version_cmd.gox:22
func (this *version) Main(_gop_arg0 string) {
this.Command.Main(_gop_arg0)
//line cmd/llgo/version_cmd.gox:22:1
this.Short("Print LLGo version")
//line cmd/llgo/version_cmd.gox:24:1
this.Run__0(func() {
//line cmd/llgo/version_cmd.gox:25:1
fmt.Println(stringutil.Concat("llgo ", env.Version(), " ", runtime.GOOS, "/", runtime.GOARCH))
})
}
func (this *version) Classfname() string {
return "version"
}
func main() {
//line cmd/llgo/version_cmd.gox:24:1
new(App).Main()
}

26
cmd/llgo/install_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/cmd/internal/install"
)
short "Compile and install packages and dependencies"
flagOff
run args => {
self.Cmd.Run self.Cmd, args
}

26
cmd/llgo/run_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/cmd/internal/run"
)
short "Compile and run Go program"
flagOff
run args => {
self.Cmd.Run self.Cmd, args
}

26
cmd/llgo/test_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
self "github.com/goplus/llgo/cmd/internal/test"
)
short "Compile and run Go test"
flagOff
run args => {
self.Cmd.Run self.Cmd, args
}

26
cmd/llgo/version_cmd.gox Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 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.
*/
import (
"runtime"
"github.com/goplus/llgo/internal/env"
)
short "Print LLGo version"
run => {
echo "llgo ${env.version} ${runtime.GOOS}/${runtime.GOARCH}"
}

View File

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

View File

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

View File

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

18
go.mod
View File

@@ -5,18 +5,18 @@ 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/llgo/runtime v0.0.0-20250403035532-0a8a4eb6a653
github.com/goccy/go-yaml v1.17.1
github.com/goplus/cobra v1.9.8 //gop:class
github.com/goplus/gogen v1.17.3
github.com/goplus/lib v0.2.0
github.com/goplus/llgo/runtime v0.0.0-00010101000000-000000000000
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/mod v0.23.0
golang.org/x/tools v0.30.0
)
require (
golang.org/x/mod v0.23.0 // indirect
golang.org/x/sync v0.11.0 // indirect
)
require golang.org/x/sync v0.11.0 // indirect
replace github.com/goplus/llgo/runtime => ./runtime

20
go.sum
View File

@@ -1,15 +1,19 @@
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
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/cobra v1.9.8 h1:4ZvhxUepT35vreZdxjl/bwnJdwhWyWCGnc60+v22x14=
github.com/goplus/cobra v1.9.8/go.mod h1:p4LhfNJDKEpiGjGiNn0crUXL5dUPA5DX2ztYpEJR34E=
github.com/goplus/gogen v1.17.3 h1:Xhoj2KQw4feRdPEtOYjTUe9lSvNIoxBG4urhdjf+fUg=
github.com/goplus/gogen v1.17.3/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=

View File

@@ -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,12 +161,11 @@ func Do(args []string, conf *Config) ([]Package, error) {
cfg.Mode |= packages.NeedForTest
}
if len(llruntime.OverlayFiles) > 0 {
cfg.Overlay = make(map[string][]byte)
for file, src := range llruntime.OverlayFiles {
overlay := unsafe.Slice(unsafe.StringData(src), len(src))
cfg.Overlay[filepath.Join(env.GOROOT(), "src", file)] = overlay
}
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())
@@ -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
aPkg := pkgsMap[p]
args = append(args, aPkg.LinkArgs...)
var llFiles []string
var linkArgs []string
packages.Visit(allPkgs, nil, func(p *packages.Package) {
aPkg := pkgsMap[p]
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 strings.HasPrefix(arg, "-L") {
exargs = append(exargs, "-rpath", arg[2:])
} else if strings.HasPrefix(arg, "-l") {
libs = append(libs, arg[2:])
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)
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)
}
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 {
altLdflags, e := buildCgo(ctx, aPkg, aPkg.AltPkg.Syntax, externs, verbose)
altLLFiles, 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)
return fmt.Errorf("build cgo of %v failed: %v", pkgPath, e)
}
cgoLdflags = append(cgoLdflags, altLdflags...)
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)
}

View File

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

View File

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

View File

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

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

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

View 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
View File

@@ -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 != "" {

76
internal/github/commit.go Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2025 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 github
import (
"encoding/json"
"net/http"
"strings"
)
// Author represents a github user or bot.
type Author struct {
Login string `json:"login"` // github-actions[bot]
ID int `json:"id"` // 41898282
NodeID string `json:"node_id"` // MDM6Qm90NDE4OTgyODI=
AvatarURL string `json:"avatar_url"` // https://avatars.githubusercontent.com/in/15368?v=4
URL string `json:"url"` // https://api.github.com/users/github-actions%5Bbot%5D
HtmlURL string `json:"html_url"` // https://github.com/apps/github-actions
Type string `json:"type"` // Bot
SiteAdmin bool `json:"site_admin"` // false
}
// CommitAuthor represents the author of a GitHub commit.
type CommitAuthor struct {
Name string `json:"name"` // xushiwei
Email string `json:"email"` // x@goplus.org
Date string `json:"date"` // 2025-04-21T14:13:29Z
}
// CommitSummary represents the summary of a GitHub commit.
type CommitSummary struct {
Author CommitAuthor `json:"author"`
Message string `json:"message"` // Merge pull request #2296 from goplus/main\n\nv1.4.0
}
// CommitDetail represents the details of a GitHub commit.
type CommitDetail struct {
NodeID string `json:"node_id"` // C_kwDOAtpGOtoAKDE2OGEwODlmOWY5ZTNhNDdhMTliMTRjZDczODQ4N2M2ZTJkMTMxYmE
Commit CommitSummary `json:"commit"`
Author Author `json:"author"`
}
func commitURL(pkgPath, sha string) string {
return "https://api.github.com/repos/" + pkgPath + "/commits/" + sha
}
// GetCommit retrieves the details of a specific commit from a GitHub repository.
func GetCommit(pkgPath, shaOrURL string) (ret *CommitDetail, err error) {
url := shaOrURL
if !strings.HasPrefix(shaOrURL, "https://") {
url = commitURL(pkgPath, shaOrURL)
}
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
ret = new(CommitDetail)
err = json.NewDecoder(resp.Body).Decode(ret)
return
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2025 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 github
import (
"encoding/json"
"net/http"
)
// ReleaseAsset represents a GitHub release asset.
type ReleaseAsset struct {
URL string `json:"url"` // https://api.github.com/repos/flintlib/flint/releases/assets/242245930
ID int `json:"id"` // 242245930
NodeID string `json:"node_id"` // RA_kwDOAC8YHs4OcGEq
Name string `json:"name"` // flint-3.2.2.tar.gz
ContentType string `json:"content_type"` // application/x-gtar
State string `json:"state"` // uploaded
Size int64 `json:"size"` // 123456
DownloadCount int `json:"download_count"` // 176
UpdatedAt string `json:"updated_at"` // 2025-03-31T08:54:16Z
BrowserDownloadURL string `json:"browser_download_url"` // https://github.com/flintlib/flint/releases/download/v3.2.2/flint-3.2.2.tar.gz
}
// Release represents a GitHub release.
type Release struct {
URL string `json:"url"` // https://api.github.com/repos/flintlib/flint/releases/209285187
ID int `json:"id"` // 209285187
NodeID string `json:"node_id"` // RE_kwDOAC8YHs4MeXBD
TagName string `json:"tag_name"` // v3.2.2
TargetCommitish string `json:"target_commitish"` // b8223680e38ad048355a421bf7f617bb6c5d5e12
Name string `json:"name"` // FLINT v3.2.2
PublishedAt string `json:"published_at"` // 2025-03-31T08:54:16Z
Body string `json:"body"` // Release Notes
TarballURL string `json:"tarball_url"` // https://api.github.com/repos/flintlib/flint/tarball/v3.2.2
ZipballURL string `json:"zipball_url"` // https://api.github.com/repos/flintlib/flint/zipball/v3.2.2
Author Author `json:"author"`
Assets []*ReleaseAsset `json:"assets"`
Prerelease bool `json:"prerelease"`
}
// releaseURL constructs the URL for a GitHub release.
func releaseURL(pkgPath, ver string) string {
if ver == "" || ver == "latest" {
return "https://api.github.com/repos/" + pkgPath + "/releases/latest"
}
return "https://api.github.com/repos/" + pkgPath + "/releases/tags/" + ver
}
// GetRelease fetches the release information from GitHub.
func GetRelease(pkgPath, ver string) (ret *Release, err error) {
url := releaseURL(pkgPath, ver)
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
ret = new(Release)
err = json.NewDecoder(resp.Body).Decode(ret)
return
}

125
internal/github/tag.go Normal file
View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 2025 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 github
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"strconv"
"strings"
)
var (
ErrBreak = errors.New("break")
ErrNotFound = errors.New("not found")
)
// Commit represents a commit in a GitHub repository.
type Commit struct {
SHA string `json:"sha"`
URL string `json:"url"`
}
// Tag represents a GitHub tag.
type Tag struct {
Name string `json:"name"`
ZipballURL string `json:"zipball_url"`
TarballURL string `json:"tarball_url"`
Commit Commit `json:"commit"`
NodeID string `json:"node_id"`
}
// tagsURL constructs the URL for fetching tags from a GitHub repository.
func tagsURL(pkgPath string) string {
return "https://api.github.com/repos/" + pkgPath + "/tags"
}
// GetTag retrieves a specific tag from a GitHub repository.
func GetTag(pkgPath, ver string) (tag *Tag, err error) {
err = ErrNotFound
EnumTags(pkgPath, 0, func(tags []*Tag, page, total int) error {
for _, t := range tags {
if t.Name == ver {
tag = t
err = nil
return ErrBreak
}
}
return nil
})
return
}
// EnumTags enumerates the tags of a GitHub repository.
func EnumTags(pkgPath string, page int, pager func(tags []*Tag, page, total int) error) (err error) {
total := 0
ubase := tagsURL(pkgPath)
loop:
u := ubase
if page > 0 {
vals := url.Values{"page": []string{strconv.Itoa(page + 1)}}
u += "?" + vals.Encode()
}
resp, err := http.Get(u)
if err != nil {
return
}
defer resp.Body.Close()
var tags []*Tag
err = json.NewDecoder(resp.Body).Decode(&tags)
if err != nil {
return
}
// Link: <https://api.github.com/repositories/47859258/tags?page=2>; rel="next",
// <https://api.github.com/repositories/47859258/tags?page=5>; rel="last"
if total == 0 {
const relLast = `rel="last"`
total = page + 1
link := resp.Header.Get("Link")
for _, part := range strings.Split(link, ",") {
if strings.HasSuffix(part, relLast) {
left := strings.TrimSpace(part[:len(part)-len(relLast)])
lastUrl := strings.TrimSuffix(strings.TrimPrefix(left, "<"), ">;")
if pos := strings.LastIndexByte(lastUrl, '?'); pos >= 0 {
if vals, e := url.ParseQuery(lastUrl[pos+1:]); e == nil {
if n, e := strconv.Atoi(vals.Get("page")); e == nil {
total = n
}
}
}
break
}
}
}
err = pager(tags, page, total)
if err != nil {
if err == ErrBreak {
err = nil
}
return
}
page++
if page < total {
goto loop
}
return
}

View File

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

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

View 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
View 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 "$@"

View File

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

View 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")
}

View File

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

View File

@@ -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": {},
}

View File

@@ -1,28 +1,34 @@
typedef union {
typedef union
{
double d;
float f;
long v;
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;

View File

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

View 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),
)
}

View File

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

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

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

View File

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

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

View File

@@ -1,9 +1,7 @@
//go:build !wasm
package debug
/*
#cgo linux LDFLAGS: -lunwind
*/
import "C"
import (
"unsafe"
@@ -11,8 +9,7 @@ import (
)
const (
LLGoPackage = "link"
LLGoFiles = "_wrap/debug.c"
LLGoFiles = "_wrap/debug.c"
)
type Info struct {

View 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")
}

View File

@@ -0,0 +1,7 @@
//go:build !linux
package debug
const (
LLGoPackage = "link"
)

View File

@@ -0,0 +1,7 @@
//go:build linux
package debug
const (
LLGoPackage = "link: -lunwind"
)

View File

@@ -1,4 +1,4 @@
//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64))
//go:build !amd64
package ffi

View File

@@ -1,5 +1,3 @@
//go:build freebsd || linux || darwin
package ffi
const (

View File

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

View 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

View 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")
}

View 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

View File

@@ -0,0 +1,9 @@
//go:build ppc64 || s390x || mips || mips64
// +build ppc64 s390x mips mips64
package goarch
const (
BigEndian = false
LittleEndian = true
)

View File

@@ -0,0 +1,3 @@
package goarch
const PtrSize = 4 << (^uintptr(0) >> 63)

View 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

View 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=

View File

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

View 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

View 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

View File

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

View File

@@ -0,0 +1 @@
package os

View File

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

View File

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

View File

@@ -0,0 +1,11 @@
package sync
const (
PthreadOnceSize = 16
PthreadMutexSize = 64
PthreadMutexAttrSize = 8
PthreadCondSize = 40
PthreadCondAttrSize = 8
PthreadRWLockSize = 192
PthreadRWLockAttrSize = 16
)

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