diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index cd18a81a..95dd8c98 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -12,18 +12,27 @@ on: jobs: test-macos: - runs-on: macos-latest strategy: matrix: + os: [macos-latest, macos-12, macos-13] llvm: [17] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Update Homebrew if: matrix.llvm == 17 # needed as long as LLVM 17 is still fresh run: brew update - - name: Install LLVM ${{ matrix.llvm }} - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} + - name: Install LLVM ${{ matrix.llvm }} and bdw-gc + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} bdw-gc + echo `brew --prefix llvm@${{ matrix.llvm }}`/bin >> $GITHUB_PATH + + - name: Clang information + run: | + echo $PATH + which clang + clang --version - name: Set up Go uses: actions/setup-go@v5 @@ -35,6 +44,14 @@ jobs: - name: Test run: go test -v ./... + + - name: Install + run: go install ./... + + - name: LLGO tests + run: | + export LLGOROOT=$PWD + bash _test/run.sh test-linux: runs-on: ubuntu-20.04 @@ -44,12 +61,19 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install LLVM ${{ matrix.llvm }} + - name: Install LLVM ${{ matrix.llvm }} and libgc-dev run: | echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.llvm }} main' | sudo tee /etc/apt/sources.list.d/llvm.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update - sudo apt-get install --no-install-recommends llvm-${{ matrix.llvm }}-dev + sudo apt-get install --no-install-recommends clang-${{ matrix.llvm }} llvm-${{ matrix.llvm }}-dev libgc-dev + echo /usr/lib/llvm-${{ matrix.llvm }}/bin >> $GITHUB_PATH + + - name: Clang information + run: | + echo $PATH + which clang + clang --version - name: Set up Go uses: actions/setup-go@v5 @@ -61,6 +85,14 @@ jobs: - name: Test run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./... + + - name: Install + run: go install ./... + + - name: LLGO tests + run: | + export LLGOROOT=$PWD + bash _test/run.sh - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 diff --git a/_test/bdwgc.go b/_test/bdwgc.go new file mode 100644 index 00000000..01bdcb2f --- /dev/null +++ b/_test/bdwgc.go @@ -0,0 +1,101 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/_test/testing" + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/internal/runtime/bdwgc" +) + +// ------ Test malloc ------ + +func TestMalloc(t *testing.T) { + pn := (*int)(bdwgc.Malloc(unsafe.Sizeof(int(0)))) + *pn = 1 << 30 + c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn) + + pl := (*int64)(bdwgc.Realloc(c.Pointer(pn), unsafe.Sizeof(int64(0)))) + *pl = 1 << 60 + c.Printf(c.Str("value: %lld, %llx, %p, %p\n"), *pl, *pl, pl, &pl) + + bdwgc.Free(c.Pointer(pl)) +} + +// ------ Test finalizer ------ + +const ( + RETURN_VALUE_FREED = 1 << 31 +) + +var called uint = 0 + +func setReturnValueFreed(pobj c.Pointer, clientData c.Pointer) { + called |= RETURN_VALUE_FREED + c.Printf(c.Str("called: %x\n"), called) +} + +func setLoopValueFreed(pobj c.Pointer, clientData c.Pointer) { + pmask := (*uint)(clientData) + called |= *pmask + c.Printf(c.Str("called: %x\n"), called) +} + +func isCalled(mask uint) bool { + return called&mask != 0 +} + +func returnValue() *int { + pn := bdwgc.Malloc(unsafe.Sizeof(int(0))) + bdwgc.RegisterFinalizer(pn, setReturnValueFreed, nil, nil, nil) + return (*int)(pn) +} + +func callFunc() { + pn := returnValue() + *pn = 1 << 30 + c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn) + bdwgc.Gcollect() + check(!isCalled(RETURN_VALUE_FREED), c.Str("finalizer should not be called")) +} + +func loop() { + for i := 0; i < 5; i++ { + p := bdwgc.Malloc(unsafe.Sizeof(int(0))) + pn := (*int)(p) + *pn = i + c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn) + pflag := (*uint)(c.Malloc(unsafe.Sizeof(uint(0)))) + *pflag = 1 << i + bdwgc.RegisterFinalizer(p, setLoopValueFreed, c.Pointer(pflag), nil, nil) + bdwgc.Gcollect() + check(!isCalled(1<= len(tests) { + c.Printf(c.Str("invalid test index %d"), idx) + panic("invalid test index") + } + tests[idx].F(nil) +} diff --git a/_test/run.sh b/_test/run.sh new file mode 100644 index 00000000..407453d8 --- /dev/null +++ b/_test/run.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e +testcmd=/tmp/test +llgo build -o $testcmd ./_test +cases=$($testcmd) +total=$(echo "$cases" | wc -l | tr -d ' ') +succ=0 +for idx in $(seq 1 $((total))); do + case=$(echo "$cases" | sed -n "${idx}p") + case_id=$(echo "$case" | cut -d',' -f1) + case_name=$(echo "$case" | cut -d',' -f2) + echo "=== Test case: $case_name" + set +e + out=$("$testcmd" "$((idx-1))" 2>&1) + exit_code=$? + set -e + if [ "${exit_code:-0}" -ne 0 ]; then + echo "failed: $out" + else + succ=$((succ+1)) + echo "passed" + fi +done +echo "=== Done" +echo "$succ/$total tests passed" +if [ "$total" -ne "$succ" ]; then + exit 1 +fi diff --git a/_test/testing/testing.go b/_test/testing/testing.go new file mode 100644 index 00000000..d4b6029b --- /dev/null +++ b/_test/testing/testing.go @@ -0,0 +1,4 @@ +package testing + +type T struct { +} diff --git a/c/c.go b/c/c.go index cfa9a77c..e1071eee 100644 --- a/c/c.go +++ b/c/c.go @@ -160,3 +160,6 @@ 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 Atoi C.atoi +func Atoi(s *Char) Int