Add RegisterFunc on unsupported platforms (#234)
Implement Cgo fallback for RegisterFunc. Add testing for windows and Linux 386 to GitHub actions. Closes #230
- commit
- 1ff8716e2490fb1e191cb96bfffdb0ff64d8b7f5
- author
- TotallyGamerJet · · 2024-04-29 11:49 UTC
- committer
- GitHub · · 2024-04-29 11:49 UTC
- parent
- de702ef
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
38 files · +205 -72
M .github/workflows/test.yml +12 -1
| @@ -100,7 +100,18 @@ jobs: | |||
| 100 | 100 | go env -u CC | |
| 101 | 101 | go env -u CXX | |
| 102 | 102 | ||
| 103 | - | # TODO: add Windows 386 tests | |
| 103 | + | - name: go test (Windows 386) | |
| 104 | + | if: runner.os == 'Windows' | |
| 105 | + | run: | | |
| 106 | + | env CGO_ENABLED=0 GOARCH=386 go test -shuffle=on -v -count=10 ./... | |
| 107 | + | env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./... | |
| 108 | + | ||
| 109 | + | - name: go test (Linux 386) | |
| 110 | + | if: runner.os == 'Linux' | |
| 111 | + | run: | | |
| 112 | + | sudo apt-get install gcc-multilib | |
| 113 | + | sudo apt-get install g++-multilib | |
| 114 | + | env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./... | |
| 104 | 115 | ||
| 105 | 116 | - name: go test race | |
| 106 | 117 | if: ${{ !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }} | |
| @@ -100,7 +100,18 @@ jobs: | |||||
| 100 | go env -u CC | 100 | go env -u CC | ||
| 101 | go env -u CXX | 101 | go env -u CXX | ||
| 102 | 102 | ||||
| 103 | - | # TODO: add Windows 386 tests | 103 | + | - name: go test (Windows 386) |
| 104 | + | if: runner.os == 'Windows' | |||
| 105 | + | run: | | |||
| 106 | + | env CGO_ENABLED=0 GOARCH=386 go test -shuffle=on -v -count=10 ./... | |||
| 107 | + | env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./... | |||
| 108 | + | ||||
| 109 | + | - name: go test (Linux 386) | |||
| 110 | + | if: runner.os == 'Linux' | |||
| 111 | + | run: | | |||
| 112 | + | sudo apt-get install gcc-multilib | |||
| 113 | + | sudo apt-get install g++-multilib | |||
| 114 | + | env CGO_ENABLED=1 GOARCH=386 go test -shuffle=on -v -count=10 ./... | |||
| 104 | 115 | ||||
| 105 | - name: go test race | 116 | - name: go test race | ||
| 106 | if: ${{ !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }} | 117 | if: ${{ !startsWith(matrix.go, '1.18.') && !startsWith(matrix.go, '1.19.') }} | ||
M callback_test.go +28 -1
| @@ -1,11 +1,12 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2023 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || (linux && (!cgo || amd64 || arm64)) | |
| 4 | + | //go:build darwin || (linux && (amd64 || arm64)) | |
| 5 | 5 | ||
| 6 | 6 | package purego_test | |
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | + | "fmt" | |
| 9 | 10 | "os" | |
| 10 | 11 | "path/filepath" | |
| 11 | 12 | "testing" | |
| @@ -146,3 +147,29 @@ func TestNewCallbackFloat32AndFloat64(t *testing.T) { | |||
| 146 | 147 | t.Errorf("cbTotalF64 not correct got %f but wanted %f", cbTotalF64, expectedCbTotalF64) | |
| 147 | 148 | } | |
| 148 | 149 | } | |
| 150 | + | ||
| 151 | + | func ExampleNewCallback() { | |
| 152 | + | cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int { | |
| 153 | + | fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) | |
| 154 | + | return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 | |
| 155 | + | }) | |
| 156 | + | ||
| 157 | + | var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int | |
| 158 | + | purego.RegisterFunc(&fn, cb) | |
| 159 | + | ||
| 160 | + | ret := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) | |
| 161 | + | fmt.Println(ret) | |
| 162 | + | ||
| 163 | + | // Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
| 164 | + | // 120 | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | func ExampleNewCallback_cdecl() { | |
| 168 | + | fn := func(_ purego.CDecl, a int) { | |
| 169 | + | fmt.Println(a) | |
| 170 | + | } | |
| 171 | + | cb := purego.NewCallback(fn) | |
| 172 | + | purego.SyscallN(cb, 83) | |
| 173 | + | ||
| 174 | + | // Output: 83 | |
| 175 | + | } | |
| @@ -1,11 +1,12 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2023 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2023 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || (linux && (!cgo || amd64 || arm64)) | 4 | + | //go:build darwin || (linux && (amd64 || arm64)) |
| 5 | 5 | ||||
| 6 | package purego_test | 6 | package purego_test | ||
| 7 | 7 | ||||
| 8 | import ( | 8 | import ( | ||
| 9 | + | "fmt" | |||
| 9 | "os" | 10 | "os" | ||
| 10 | "path/filepath" | 11 | "path/filepath" | ||
| 11 | "testing" | 12 | "testing" | ||
| @@ -146,3 +147,29 @@ func TestNewCallbackFloat32AndFloat64(t *testing.T) { | |||||
| 146 | t.Errorf("cbTotalF64 not correct got %f but wanted %f", cbTotalF64, expectedCbTotalF64) | 147 | t.Errorf("cbTotalF64 not correct got %f but wanted %f", cbTotalF64, expectedCbTotalF64) | ||
| 147 | } | 148 | } | ||
| 148 | } | 149 | } | ||
| 150 | + | ||||
| 151 | + | func ExampleNewCallback() { | |||
| 152 | + | cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int { | |||
| 153 | + | fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) | |||
| 154 | + | return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 | |||
| 155 | + | }) | |||
| 156 | + | ||||
| 157 | + | var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int | |||
| 158 | + | purego.RegisterFunc(&fn, cb) | |||
| 159 | + | ||||
| 160 | + | ret := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) | |||
| 161 | + | fmt.Println(ret) | |||
| 162 | + | ||||
| 163 | + | // Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |||
| 164 | + | // 120 | |||
| 165 | + | } | |||
| 166 | + | ||||
| 167 | + | func ExampleNewCallback_cdecl() { | |||
| 168 | + | fn := func(_ purego.CDecl, a int) { | |||
| 169 | + | fmt.Println(a) | |||
| 170 | + | } | |||
| 171 | + | cb := purego.NewCallback(fn) | |||
| 172 | + | purego.SyscallN(cb, 83) | |||
| 173 | + | ||||
| 174 | + | // Output: 83 | |||
| 175 | + | } | |||
M dlfcn.go +0 -5
| @@ -63,11 +63,6 @@ func Dlclose(handle uintptr) error { | |||
| 63 | 63 | return nil | |
| 64 | 64 | } | |
| 65 | 65 | ||
| 66 | - | //go:linkname openLibrary openLibrary | |
| 67 | - | func openLibrary(name string) (uintptr, error) { | |
| 68 | - | return Dlopen(name, RTLD_NOW|RTLD_GLOBAL) | |
| 69 | - | } | |
| 70 | - | ||
| 71 | 66 | func loadSymbol(handle uintptr, name string) (uintptr, error) { | |
| 72 | 67 | return Dlsym(handle, name) | |
| 73 | 68 | } | |
| @@ -63,11 +63,6 @@ func Dlclose(handle uintptr) error { | |||||
| 63 | return nil | 63 | return nil | ||
| 64 | } | 64 | } | ||
| 65 | 65 | ||||
| 66 | - | //go:linkname openLibrary openLibrary | |||
| 67 | - | func openLibrary(name string) (uintptr, error) { | |||
| 68 | - | return Dlopen(name, RTLD_NOW|RTLD_GLOBAL) | |||
| 69 | - | } | |||
| 70 | - | ||||
| 71 | func loadSymbol(handle uintptr, name string) (uintptr, error) { | 66 | func loadSymbol(handle uintptr, name string) (uintptr, error) { | ||
| 72 | return Dlsym(handle, name) | 67 | return Dlsym(handle, name) | ||
| 73 | } | 68 | } | ||
M dlfcn_test.go +3 -1
| @@ -59,7 +59,9 @@ func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | |||
| 59 | 59 | } else { | |
| 60 | 60 | args = []string{"-shared", "-Wall", "-Werror", "-o", libFile} | |
| 61 | 61 | } | |
| 62 | - | ||
| 62 | + | if runtime.GOARCH == "386" { | |
| 63 | + | args = append(args, "-m32") | |
| 64 | + | } | |
| 63 | 65 | // macOS arm64 can run amd64 tests through Rossetta. | |
| 64 | 66 | // Build the shared library based on the GOARCH and not | |
| 65 | 67 | // the default behavior of the compiler. | |
| @@ -59,7 +59,9 @@ func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | |||||
| 59 | } else { | 59 | } else { | ||
| 60 | args = []string{"-shared", "-Wall", "-Werror", "-o", libFile} | 60 | args = []string{"-shared", "-Wall", "-Werror", "-o", libFile} | ||
| 61 | } | 61 | } | ||
| 62 | - | 62 | + | if runtime.GOARCH == "386" { | |
| 63 | + | args = append(args, "-m32") | |||
| 64 | + | } | |||
| 63 | // macOS arm64 can run amd64 tests through Rossetta. | 65 | // macOS arm64 can run amd64 tests through Rossetta. | ||
| 64 | // Build the shared library based on the GOARCH and not | 66 | // Build the shared library based on the GOARCH and not | ||
| 65 | // the default behavior of the compiler. | 67 | // the default behavior of the compiler. | ||
M func.go +22 -8
| @@ -117,6 +117,10 @@ func RegisterFunc(fptr interface{}, cfn uintptr) { | |||
| 117 | 117 | if cfn == 0 { | |
| 118 | 118 | panic("purego: cfn is nil") | |
| 119 | 119 | } | |
| 120 | + | if ty.NumOut() == 1 && (ty.Out(0).Kind() == reflect.Float32 || ty.Out(0).Kind() == reflect.Float64) && | |
| 121 | + | runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |
| 122 | + | panic("purego: float returns are not supported") | |
| 123 | + | } | |
| 120 | 124 | { | |
| 121 | 125 | // this code checks how many registers and stack this function will use | |
| 122 | 126 | // to avoid crashing with too many arguments | |
| @@ -126,9 +130,22 @@ func RegisterFunc(fptr interface{}, cfn uintptr) { | |||
| 126 | 130 | for i := 0; i < ty.NumIn(); i++ { | |
| 127 | 131 | arg := ty.In(i) | |
| 128 | 132 | switch arg.Kind() { | |
| 133 | + | case reflect.Func: | |
| 134 | + | // This only does preliminary testing to ensure the CDecl argument | |
| 135 | + | // is the first argument. Full testing is done when the callback is actually | |
| 136 | + | // created in NewCallback. | |
| 137 | + | for j := 0; j < arg.NumIn(); j++ { | |
| 138 | + | in := arg.In(j) | |
| 139 | + | if !in.AssignableTo(reflect.TypeOf(CDecl{})) { | |
| 140 | + | continue | |
| 141 | + | } | |
| 142 | + | if j != 0 { | |
| 143 | + | panic("purego: CDecl must be the first argument") | |
| 144 | + | } | |
| 145 | + | } | |
| 129 | 146 | case reflect.String, reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, | |
| 130 | - | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer, reflect.Slice, | |
| 131 | - | reflect.Func, reflect.Bool: | |
| 147 | + | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer, | |
| 148 | + | reflect.Slice, reflect.Bool: | |
| 132 | 149 | if ints < numOfIntegerRegisters() { | |
| 133 | 150 | ints++ | |
| 134 | 151 | } else { | |
| @@ -413,12 +430,9 @@ func numOfIntegerRegisters() int { | |||
| 413 | 430 | return 8 | |
| 414 | 431 | case "amd64": | |
| 415 | 432 | return 6 | |
| 416 | - | // TODO: figure out why 386 tests are not working | |
| 417 | - | /*case "386": | |
| 418 | - | return 0 | |
| 419 | - | case "arm": | |
| 420 | - | return 4*/ | |
| 421 | 433 | default: | |
| 422 | - | panic("purego: unknown GOARCH (" + runtime.GOARCH + ")") | |
| 434 | + | // since this platform isn't supported and can therefore only access | |
| 435 | + | // integer registers it is fine to return the maxArgs | |
| 436 | + | return maxArgs | |
| 423 | 437 | } | |
| 424 | 438 | } | |
| @@ -117,6 +117,10 @@ func RegisterFunc(fptr interface{}, cfn uintptr) { | |||||
| 117 | if cfn == 0 { | 117 | if cfn == 0 { | ||
| 118 | panic("purego: cfn is nil") | 118 | panic("purego: cfn is nil") | ||
| 119 | } | 119 | } | ||
| 120 | + | if ty.NumOut() == 1 && (ty.Out(0).Kind() == reflect.Float32 || ty.Out(0).Kind() == reflect.Float64) && | |||
| 121 | + | runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |||
| 122 | + | panic("purego: float returns are not supported") | |||
| 123 | + | } | |||
| 120 | { | 124 | { | ||
| 121 | // this code checks how many registers and stack this function will use | 125 | // this code checks how many registers and stack this function will use | ||
| 122 | // to avoid crashing with too many arguments | 126 | // to avoid crashing with too many arguments | ||
| @@ -126,9 +130,22 @@ func RegisterFunc(fptr interface{}, cfn uintptr) { | |||||
| 126 | for i := 0; i < ty.NumIn(); i++ { | 130 | for i := 0; i < ty.NumIn(); i++ { | ||
| 127 | arg := ty.In(i) | 131 | arg := ty.In(i) | ||
| 128 | switch arg.Kind() { | 132 | switch arg.Kind() { | ||
| 133 | + | case reflect.Func: | |||
| 134 | + | // This only does preliminary testing to ensure the CDecl argument | |||
| 135 | + | // is the first argument. Full testing is done when the callback is actually | |||
| 136 | + | // created in NewCallback. | |||
| 137 | + | for j := 0; j < arg.NumIn(); j++ { | |||
| 138 | + | in := arg.In(j) | |||
| 139 | + | if !in.AssignableTo(reflect.TypeOf(CDecl{})) { | |||
| 140 | + | continue | |||
| 141 | + | } | |||
| 142 | + | if j != 0 { | |||
| 143 | + | panic("purego: CDecl must be the first argument") | |||
| 144 | + | } | |||
| 145 | + | } | |||
| 129 | case reflect.String, reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, | 146 | case reflect.String, reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, | ||
| 130 | - | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer, reflect.Slice, | 147 | + | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer, |
| 131 | - | reflect.Func, reflect.Bool: | 148 | + | reflect.Slice, reflect.Bool: |
| 132 | if ints < numOfIntegerRegisters() { | 149 | if ints < numOfIntegerRegisters() { | ||
| 133 | ints++ | 150 | ints++ | ||
| 134 | } else { | 151 | } else { | ||
| @@ -413,12 +430,9 @@ func numOfIntegerRegisters() int { | |||||
| 413 | return 8 | 430 | return 8 | ||
| 414 | case "amd64": | 431 | case "amd64": | ||
| 415 | return 6 | 432 | return 6 | ||
| 416 | - | // TODO: figure out why 386 tests are not working | |||
| 417 | - | /*case "386": | |||
| 418 | - | return 0 | |||
| 419 | - | case "arm": | |||
| 420 | - | return 4*/ | |||
| 421 | default: | 433 | default: | ||
| 422 | - | panic("purego: unknown GOARCH (" + runtime.GOARCH + ")") | 434 | + | // since this platform isn't supported and can therefore only access |
| 435 | + | // integer registers it is fine to return the maxArgs | |||
| 436 | + | return maxArgs | |||
| 423 | } | 437 | } | ||
| 424 | } | 438 | } | ||
M func_test.go +20 -27
| @@ -10,13 +10,9 @@ import ( | |||
| 10 | 10 | "unsafe" | |
| 11 | 11 | ||
| 12 | 12 | "github.com/ebitengine/purego" | |
| 13 | + | "github.com/ebitengine/purego/internal/load" | |
| 13 | 14 | ) | |
| 14 | 15 | ||
| 15 | - | // This is an internal OS-dependent function for getting the handle to a library | |
| 16 | - | // | |
| 17 | - | //go:linkname openLibrary openLibrary | |
| 18 | - | func openLibrary(name string) (uintptr, error) | |
| 19 | - | ||
| 20 | 16 | func getSystemLibrary() (string, error) { | |
| 21 | 17 | switch runtime.GOOS { | |
| 22 | 18 | case "darwin": | |
| @@ -37,7 +33,7 @@ func TestRegisterFunc(t *testing.T) { | |||
| 37 | 33 | if err != nil { | |
| 38 | 34 | t.Fatalf("couldn't get system library: %s", err) | |
| 39 | 35 | } | |
| 40 | - | libc, err := openLibrary(library) | |
| 36 | + | libc, err := load.OpenLibrary(library) | |
| 41 | 37 | if err != nil { | |
| 42 | 38 | t.Fatalf("failed to dlopen: %s", err) | |
| 43 | 39 | } | |
| @@ -46,38 +42,26 @@ func TestRegisterFunc(t *testing.T) { | |||
| 46 | 42 | puts("Calling C from from Go without Cgo!") | |
| 47 | 43 | } | |
| 48 | 44 | ||
| 49 | - | func ExampleNewCallback() { | |
| 50 | - | cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int { | |
| 51 | - | fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) | |
| 52 | - | return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 | |
| 53 | - | }) | |
| 54 | - | ||
| 55 | - | var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int | |
| 56 | - | purego.RegisterFunc(&fn, cb) | |
| 57 | - | ||
| 58 | - | ret := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) | |
| 59 | - | fmt.Println(ret) | |
| 60 | - | ||
| 61 | - | // Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
| 62 | - | // 120 | |
| 63 | - | } | |
| 64 | - | ||
| 65 | 45 | func Test_qsort(t *testing.T) { | |
| 46 | + | if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |
| 47 | + | t.Skip("Platform doesn't support Floats") | |
| 48 | + | return | |
| 49 | + | } | |
| 66 | 50 | library, err := getSystemLibrary() | |
| 67 | 51 | if err != nil { | |
| 68 | 52 | t.Fatalf("couldn't get system library: %s", err) | |
| 69 | 53 | } | |
| 70 | - | libc, err := openLibrary(library) | |
| 54 | + | libc, err := load.OpenLibrary(library) | |
| 71 | 55 | if err != nil { | |
| 72 | 56 | t.Fatalf("failed to dlopen: %s", err) | |
| 73 | 57 | } | |
| 74 | 58 | ||
| 75 | 59 | data := []int{88, 56, 100, 2, 25} | |
| 76 | 60 | sorted := []int{2, 25, 56, 88, 100} | |
| 77 | - | compare := func(a, b *int) int { | |
| 61 | + | compare := func(_ purego.CDecl, a, b *int) int { | |
| 78 | 62 | return *a - *b | |
| 79 | 63 | } | |
| 80 | - | var qsort func(data []int, nitms uintptr, size uintptr, compar func(a, b *int) int) | |
| 64 | + | var qsort func(data []int, nitms uintptr, size uintptr, compar func(_ purego.CDecl, a, b *int) int) | |
| 81 | 65 | purego.RegisterLibFunc(&qsort, libc, "qsort") | |
| 82 | 66 | qsort(data, uintptr(len(data)), unsafe.Sizeof(int(0)), compare) | |
| 83 | 67 | for i := range data { | |
| @@ -88,11 +72,15 @@ func Test_qsort(t *testing.T) { | |||
| 88 | 72 | } | |
| 89 | 73 | ||
| 90 | 74 | func TestRegisterFunc_Floats(t *testing.T) { | |
| 75 | + | if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |
| 76 | + | t.Skip("Platform doesn't support Floats") | |
| 77 | + | return | |
| 78 | + | } | |
| 91 | 79 | library, err := getSystemLibrary() | |
| 92 | 80 | if err != nil { | |
| 93 | 81 | t.Fatalf("couldn't get system library: %s", err) | |
| 94 | 82 | } | |
| 95 | - | libc, err := openLibrary(library) | |
| 83 | + | libc, err := load.OpenLibrary(library) | |
| 96 | 84 | if err != nil { | |
| 97 | 85 | t.Fatalf("failed to dlopen: %s", err) | |
| 98 | 86 | } | |
| @@ -123,10 +111,15 @@ func TestRegisterFunc_Floats(t *testing.T) { | |||
| 123 | 111 | } | |
| 124 | 112 | ||
| 125 | 113 | func TestRegisterLibFunc_Bool(t *testing.T) { | |
| 114 | + | if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |
| 115 | + | t.Skip("Platform doesn't support callbacks") | |
| 116 | + | return | |
| 117 | + | } | |
| 126 | 118 | // this callback recreates the state where the return register | |
| 127 | 119 | // contains other information but the least significant byte is false | |
| 128 | 120 | cbFalse := purego.NewCallback(func() uintptr { | |
| 129 | - | return 0x7F5948AE9A00 | |
| 121 | + | x := uint64(0x7F5948AE9A00) | |
| 122 | + | return uintptr(x) | |
| 130 | 123 | }) | |
| 131 | 124 | var runFalse func() bool | |
| 132 | 125 | purego.RegisterFunc(&runFalse, cbFalse) | |
| @@ -10,13 +10,9 @@ import ( | |||||
| 10 | "unsafe" | 10 | "unsafe" | ||
| 11 | 11 | ||||
| 12 | "github.com/ebitengine/purego" | 12 | "github.com/ebitengine/purego" | ||
| 13 | + | "github.com/ebitengine/purego/internal/load" | |||
| 13 | ) | 14 | ) | ||
| 14 | 15 | ||||
| 15 | - | // This is an internal OS-dependent function for getting the handle to a library | |||
| 16 | - | // | |||
| 17 | - | //go:linkname openLibrary openLibrary | |||
| 18 | - | func openLibrary(name string) (uintptr, error) | |||
| 19 | - | ||||
| 20 | func getSystemLibrary() (string, error) { | 16 | func getSystemLibrary() (string, error) { | ||
| 21 | switch runtime.GOOS { | 17 | switch runtime.GOOS { | ||
| 22 | case "darwin": | 18 | case "darwin": | ||
| @@ -37,7 +33,7 @@ func TestRegisterFunc(t *testing.T) { | |||||
| 37 | if err != nil { | 33 | if err != nil { | ||
| 38 | t.Fatalf("couldn't get system library: %s", err) | 34 | t.Fatalf("couldn't get system library: %s", err) | ||
| 39 | } | 35 | } | ||
| 40 | - | libc, err := openLibrary(library) | 36 | + | libc, err := load.OpenLibrary(library) |
| 41 | if err != nil { | 37 | if err != nil { | ||
| 42 | t.Fatalf("failed to dlopen: %s", err) | 38 | t.Fatalf("failed to dlopen: %s", err) | ||
| 43 | } | 39 | } | ||
| @@ -46,38 +42,26 @@ func TestRegisterFunc(t *testing.T) { | |||||
| 46 | puts("Calling C from from Go without Cgo!") | 42 | puts("Calling C from from Go without Cgo!") | ||
| 47 | } | 43 | } | ||
| 48 | 44 | ||||
| 49 | - | func ExampleNewCallback() { | |||
| 50 | - | cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int { | |||
| 51 | - | fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) | |||
| 52 | - | return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 | |||
| 53 | - | }) | |||
| 54 | - | ||||
| 55 | - | var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int | |||
| 56 | - | purego.RegisterFunc(&fn, cb) | |||
| 57 | - | ||||
| 58 | - | ret := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) | |||
| 59 | - | fmt.Println(ret) | |||
| 60 | - | ||||
| 61 | - | // Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |||
| 62 | - | // 120 | |||
| 63 | - | } | |||
| 64 | - | ||||
| 65 | func Test_qsort(t *testing.T) { | 45 | func Test_qsort(t *testing.T) { | ||
| 46 | + | if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |||
| 47 | + | t.Skip("Platform doesn't support Floats") | |||
| 48 | + | return | |||
| 49 | + | } | |||
| 66 | library, err := getSystemLibrary() | 50 | library, err := getSystemLibrary() | ||
| 67 | if err != nil { | 51 | if err != nil { | ||
| 68 | t.Fatalf("couldn't get system library: %s", err) | 52 | t.Fatalf("couldn't get system library: %s", err) | ||
| 69 | } | 53 | } | ||
| 70 | - | libc, err := openLibrary(library) | 54 | + | libc, err := load.OpenLibrary(library) |
| 71 | if err != nil { | 55 | if err != nil { | ||
| 72 | t.Fatalf("failed to dlopen: %s", err) | 56 | t.Fatalf("failed to dlopen: %s", err) | ||
| 73 | } | 57 | } | ||
| 74 | 58 | ||||
| 75 | data := []int{88, 56, 100, 2, 25} | 59 | data := []int{88, 56, 100, 2, 25} | ||
| 76 | sorted := []int{2, 25, 56, 88, 100} | 60 | sorted := []int{2, 25, 56, 88, 100} | ||
| 77 | - | compare := func(a, b *int) int { | 61 | + | compare := func(_ purego.CDecl, a, b *int) int { |
| 78 | return *a - *b | 62 | return *a - *b | ||
| 79 | } | 63 | } | ||
| 80 | - | var qsort func(data []int, nitms uintptr, size uintptr, compar func(a, b *int) int) | 64 | + | var qsort func(data []int, nitms uintptr, size uintptr, compar func(_ purego.CDecl, a, b *int) int) |
| 81 | purego.RegisterLibFunc(&qsort, libc, "qsort") | 65 | purego.RegisterLibFunc(&qsort, libc, "qsort") | ||
| 82 | qsort(data, uintptr(len(data)), unsafe.Sizeof(int(0)), compare) | 66 | qsort(data, uintptr(len(data)), unsafe.Sizeof(int(0)), compare) | ||
| 83 | for i := range data { | 67 | for i := range data { | ||
| @@ -88,11 +72,15 @@ func Test_qsort(t *testing.T) { | |||||
| 88 | } | 72 | } | ||
| 89 | 73 | ||||
| 90 | func TestRegisterFunc_Floats(t *testing.T) { | 74 | func TestRegisterFunc_Floats(t *testing.T) { | ||
| 75 | + | if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |||
| 76 | + | t.Skip("Platform doesn't support Floats") | |||
| 77 | + | return | |||
| 78 | + | } | |||
| 91 | library, err := getSystemLibrary() | 79 | library, err := getSystemLibrary() | ||
| 92 | if err != nil { | 80 | if err != nil { | ||
| 93 | t.Fatalf("couldn't get system library: %s", err) | 81 | t.Fatalf("couldn't get system library: %s", err) | ||
| 94 | } | 82 | } | ||
| 95 | - | libc, err := openLibrary(library) | 83 | + | libc, err := load.OpenLibrary(library) |
| 96 | if err != nil { | 84 | if err != nil { | ||
| 97 | t.Fatalf("failed to dlopen: %s", err) | 85 | t.Fatalf("failed to dlopen: %s", err) | ||
| 98 | } | 86 | } | ||
| @@ -123,10 +111,15 @@ func TestRegisterFunc_Floats(t *testing.T) { | |||||
| 123 | } | 111 | } | ||
| 124 | 112 | ||||
| 125 | func TestRegisterLibFunc_Bool(t *testing.T) { | 113 | func TestRegisterLibFunc_Bool(t *testing.T) { | ||
| 114 | + | if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { | |||
| 115 | + | t.Skip("Platform doesn't support callbacks") | |||
| 116 | + | return | |||
| 117 | + | } | |||
| 126 | // this callback recreates the state where the return register | 118 | // this callback recreates the state where the return register | ||
| 127 | // contains other information but the least significant byte is false | 119 | // contains other information but the least significant byte is false | ||
| 128 | cbFalse := purego.NewCallback(func() uintptr { | 120 | cbFalse := purego.NewCallback(func() uintptr { | ||
| 129 | - | return 0x7F5948AE9A00 | 121 | + | x := uint64(0x7F5948AE9A00) |
| 122 | + | return uintptr(x) | |||
| 130 | }) | 123 | }) | ||
| 131 | var runFalse func() bool | 124 | var runFalse func() bool | ||
| 132 | purego.RegisterFunc(&runFalse, cbFalse) | 125 | purego.RegisterFunc(&runFalse, cbFalse) | ||
M internal/cgo/syscall_cgo_unix.go +4 -4
| @@ -20,7 +20,7 @@ typedef struct syscall15Args { | |||
| 20 | 20 | uintptr_t fn; | |
| 21 | 21 | uintptr_t a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; | |
| 22 | 22 | uintptr_t f1, f2, f3, f4, f5, f6, f7, f8; | |
| 23 | - | uintptr_t r1, r2, err; | |
| 23 | + | uintptr_t err; | |
| 24 | 24 | } syscall15Args; | |
| 25 | 25 | ||
| 26 | 26 | void syscall15(struct syscall15Args *args) { | |
| @@ -31,7 +31,7 @@ void syscall15(struct syscall15Args *args) { | |||
| 31 | 31 | *(void**)(&func_name) = (void*)(args->fn); | |
| 32 | 32 | uintptr_t r1 = func_name(args->a1,args->a2,args->a3,args->a4,args->a5,args->a6,args->a7,args->a8,args->a9, | |
| 33 | 33 | args->a10,args->a11,args->a12,args->a13,args->a14,args->a15); | |
| 34 | - | args->r1 = r1; | |
| 34 | + | args->a1 = r1; | |
| 35 | 35 | args->err = errno; | |
| 36 | 36 | } | |
| 37 | 37 | ||
| @@ -48,8 +48,8 @@ func Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, | |||
| 48 | 48 | C.uintptr_t(fn), C.uintptr_t(a1), C.uintptr_t(a2), C.uintptr_t(a3), | |
| 49 | 49 | C.uintptr_t(a4), C.uintptr_t(a5), C.uintptr_t(a6), | |
| 50 | 50 | C.uintptr_t(a7), C.uintptr_t(a8), C.uintptr_t(a9), C.uintptr_t(a10), C.uintptr_t(a11), C.uintptr_t(a12), | |
| 51 | - | C.uintptr_t(a13), C.uintptr_t(a14), C.uintptr_t(a15), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 51 | + | C.uintptr_t(a13), C.uintptr_t(a14), C.uintptr_t(a15), 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 52 | 52 | } | |
| 53 | 53 | C.syscall15(&args) | |
| 54 | - | return uintptr(args.r1), uintptr(args.r2), uintptr(args.err) | |
| 54 | + | return uintptr(args.a1), 0, uintptr(args.err) | |
| 55 | 55 | } | |
| @@ -20,7 +20,7 @@ typedef struct syscall15Args { | |||||
| 20 | uintptr_t fn; | 20 | uintptr_t fn; | ||
| 21 | uintptr_t a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; | 21 | uintptr_t a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; | ||
| 22 | uintptr_t f1, f2, f3, f4, f5, f6, f7, f8; | 22 | uintptr_t f1, f2, f3, f4, f5, f6, f7, f8; | ||
| 23 | - | uintptr_t r1, r2, err; | 23 | + | uintptr_t err; |
| 24 | } syscall15Args; | 24 | } syscall15Args; | ||
| 25 | 25 | ||||
| 26 | void syscall15(struct syscall15Args *args) { | 26 | void syscall15(struct syscall15Args *args) { | ||
| @@ -31,7 +31,7 @@ void syscall15(struct syscall15Args *args) { | |||||
| 31 | *(void**)(&func_name) = (void*)(args->fn); | 31 | *(void**)(&func_name) = (void*)(args->fn); | ||
| 32 | uintptr_t r1 = func_name(args->a1,args->a2,args->a3,args->a4,args->a5,args->a6,args->a7,args->a8,args->a9, | 32 | uintptr_t r1 = func_name(args->a1,args->a2,args->a3,args->a4,args->a5,args->a6,args->a7,args->a8,args->a9, | ||
| 33 | args->a10,args->a11,args->a12,args->a13,args->a14,args->a15); | 33 | args->a10,args->a11,args->a12,args->a13,args->a14,args->a15); | ||
| 34 | - | args->r1 = r1; | 34 | + | args->a1 = r1; |
| 35 | args->err = errno; | 35 | args->err = errno; | ||
| 36 | } | 36 | } | ||
| 37 | 37 | ||||
| @@ -48,8 +48,8 @@ func Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, | |||||
| 48 | C.uintptr_t(fn), C.uintptr_t(a1), C.uintptr_t(a2), C.uintptr_t(a3), | 48 | C.uintptr_t(fn), C.uintptr_t(a1), C.uintptr_t(a2), C.uintptr_t(a3), | ||
| 49 | C.uintptr_t(a4), C.uintptr_t(a5), C.uintptr_t(a6), | 49 | C.uintptr_t(a4), C.uintptr_t(a5), C.uintptr_t(a6), | ||
| 50 | C.uintptr_t(a7), C.uintptr_t(a8), C.uintptr_t(a9), C.uintptr_t(a10), C.uintptr_t(a11), C.uintptr_t(a12), | 50 | C.uintptr_t(a7), C.uintptr_t(a8), C.uintptr_t(a9), C.uintptr_t(a10), C.uintptr_t(a11), C.uintptr_t(a12), | ||
| 51 | - | C.uintptr_t(a13), C.uintptr_t(a14), C.uintptr_t(a15), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 51 | + | C.uintptr_t(a13), C.uintptr_t(a14), C.uintptr_t(a15), 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 52 | } | 52 | } | ||
| 53 | C.syscall15(&args) | 53 | C.syscall15(&args) | ||
| 54 | - | return uintptr(args.r1), uintptr(args.r2), uintptr(args.err) | 54 | + | return uintptr(args.a1), 0, uintptr(args.err) |
| 55 | } | 55 | } | ||
M internal/fakecgo/callbacks.go +1 -1
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | - | //go:build darwin || freebsd || linux | |
| 5 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 6 | 6 | ||
| 7 | 7 | package fakecgo | |
| 8 | 8 | ||
| @@ -2,7 +2,7 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | - | //go:build darwin || freebsd || linux | 5 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 6 | 6 | ||||
| 7 | package fakecgo | 7 | package fakecgo | ||
| 8 | 8 | ||||
M internal/fakecgo/doc.go +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || freebsd || linux | |
| 4 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 5 | 5 | ||
| 6 | 6 | // Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go. | |
| 7 | 7 | // This allows code that calls into C to function properly when CGO_ENABLED=0. | |
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || freebsd || linux | 4 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 5 | 5 | ||||
| 6 | // Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go. | 6 | // Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go. | ||
| 7 | // This allows code that calls into C to function properly when CGO_ENABLED=0. | 7 | // This allows code that calls into C to function properly when CGO_ENABLED=0. | ||
M internal/fakecgo/gen.go +4 -2
| @@ -20,7 +20,7 @@ const templateSymbols = `// Code generated by 'go generate' with gen.go. DO NOT | |||
| 20 | 20 | // SPDX-License-Identifier: Apache-2.0 | |
| 21 | 21 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 22 | 22 | ||
| 23 | - | //go:build darwin || freebsd || linux | |
| 23 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 24 | 24 | ||
| 25 | 25 | package fakecgo | |
| 26 | 26 | ||
| @@ -88,7 +88,7 @@ const templateTrampolinesStubs = `// Code generated by 'go generate' with gen.go | |||
| 88 | 88 | // SPDX-License-Identifier: Apache-2.0 | |
| 89 | 89 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 90 | 90 | ||
| 91 | - | //go:build darwin || freebsd || linux | |
| 91 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 92 | 92 | ||
| 93 | 93 | #include "textflag.h" | |
| 94 | 94 | ||
| @@ -105,6 +105,8 @@ const templateSymbolsGoos = `// Code generated by 'go generate' with gen.go. DO | |||
| 105 | 105 | // SPDX-License-Identifier: Apache-2.0 | |
| 106 | 106 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 107 | 107 | ||
| 108 | + | //go:build !cgo | |
| 109 | + | ||
| 108 | 110 | package fakecgo | |
| 109 | 111 | ||
| 110 | 112 | {{- range $location := . }} | |
| @@ -20,7 +20,7 @@ const templateSymbols = `// Code generated by 'go generate' with gen.go. DO NOT | |||||
| 20 | // SPDX-License-Identifier: Apache-2.0 | 20 | // SPDX-License-Identifier: Apache-2.0 | ||
| 21 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 21 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 22 | 22 | ||||
| 23 | - | //go:build darwin || freebsd || linux | 23 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 24 | 24 | ||||
| 25 | package fakecgo | 25 | package fakecgo | ||
| 26 | 26 | ||||
| @@ -88,7 +88,7 @@ const templateTrampolinesStubs = `// Code generated by 'go generate' with gen.go | |||||
| 88 | // SPDX-License-Identifier: Apache-2.0 | 88 | // SPDX-License-Identifier: Apache-2.0 | ||
| 89 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 89 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 90 | 90 | ||||
| 91 | - | //go:build darwin || freebsd || linux | 91 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 92 | 92 | ||||
| 93 | #include "textflag.h" | 93 | #include "textflag.h" | ||
| 94 | 94 | ||||
| @@ -105,6 +105,8 @@ const templateSymbolsGoos = `// Code generated by 'go generate' with gen.go. DO | |||||
| 105 | // SPDX-License-Identifier: Apache-2.0 | 105 | // SPDX-License-Identifier: Apache-2.0 | ||
| 106 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 106 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 107 | 107 | ||||
| 108 | + | //go:build !cgo | |||
| 109 | + | ||||
| 108 | package fakecgo | 110 | package fakecgo | ||
| 109 | 111 | ||||
| 110 | {{- range $location := . }} | 112 | {{- range $location := . }} | ||
M internal/fakecgo/go_darwin_amd64.go +2 -0
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | + | //go:build !cgo | |
| 6 | + | ||
| 5 | 7 | package fakecgo | |
| 6 | 8 | ||
| 7 | 9 | import "unsafe" | |
| @@ -2,6 +2,8 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | + | //go:build !cgo | |||
| 6 | + | ||||
| 5 | package fakecgo | 7 | package fakecgo | ||
| 6 | 8 | ||||
| 7 | import "unsafe" | 9 | import "unsafe" | ||
M internal/fakecgo/go_darwin_arm64.go +2 -0
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | + | //go:build !cgo | |
| 6 | + | ||
| 5 | 7 | package fakecgo | |
| 6 | 8 | ||
| 7 | 9 | import "unsafe" | |
| @@ -2,6 +2,8 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | + | //go:build !cgo | |||
| 6 | + | ||||
| 5 | package fakecgo | 7 | package fakecgo | ||
| 6 | 8 | ||||
| 7 | import "unsafe" | 9 | import "unsafe" | ||
M internal/fakecgo/go_freebsd_amd64.go +2 -0
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | + | //go:build !cgo | |
| 6 | + | ||
| 5 | 7 | package fakecgo | |
| 6 | 8 | ||
| 7 | 9 | import "unsafe" | |
| @@ -2,6 +2,8 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | + | //go:build !cgo | |||
| 6 | + | ||||
| 5 | package fakecgo | 7 | package fakecgo | ||
| 6 | 8 | ||||
| 7 | import "unsafe" | 9 | import "unsafe" | ||
M internal/fakecgo/go_freebsd_arm64.go +3 -1
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | + | //go:build !cgo | |
| 6 | + | ||
| 5 | 7 | package fakecgo | |
| 6 | 8 | ||
| 7 | 9 | import "unsafe" | |
| @@ -14,7 +16,7 @@ func _cgo_sys_thread_start(ts *ThreadStart) { | |||
| 14 | 16 | var size size_t | |
| 15 | 17 | var err int | |
| 16 | 18 | ||
| 17 | - | //fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug | |
| 19 | + | // fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug | |
| 18 | 20 | sigfillset(&ign) | |
| 19 | 21 | pthread_sigmask(SIG_SETMASK, &ign, &oset) | |
| 20 | 22 | ||
| @@ -2,6 +2,8 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | + | //go:build !cgo | |||
| 6 | + | ||||
| 5 | package fakecgo | 7 | package fakecgo | ||
| 6 | 8 | ||||
| 7 | import "unsafe" | 9 | import "unsafe" | ||
| @@ -14,7 +16,7 @@ func _cgo_sys_thread_start(ts *ThreadStart) { | |||||
| 14 | var size size_t | 16 | var size size_t | ||
| 15 | var err int | 17 | var err int | ||
| 16 | 18 | ||||
| 17 | - | //fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug | 19 | + | // fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug |
| 18 | sigfillset(&ign) | 20 | sigfillset(&ign) | ||
| 19 | pthread_sigmask(SIG_SETMASK, &ign, &oset) | 21 | pthread_sigmask(SIG_SETMASK, &ign, &oset) | ||
| 20 | 22 | ||||
M internal/fakecgo/go_libinit.go +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || freebsd || linux | |
| 4 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || freebsd || linux | 4 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | package fakecgo | ||
| 7 | 7 | ||||
M internal/fakecgo/go_linux_amd64.go +2 -0
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | + | //go:build !cgo | |
| 6 | + | ||
| 5 | 7 | package fakecgo | |
| 6 | 8 | ||
| 7 | 9 | import "unsafe" | |
| @@ -2,6 +2,8 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | + | //go:build !cgo | |||
| 6 | + | ||||
| 5 | package fakecgo | 7 | package fakecgo | ||
| 6 | 8 | ||||
| 7 | import "unsafe" | 9 | import "unsafe" | ||
M internal/fakecgo/go_linux_arm64.go +2 -0
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | + | //go:build !cgo | |
| 6 | + | ||
| 5 | 7 | package fakecgo | |
| 6 | 8 | ||
| 7 | 9 | import "unsafe" | |
| @@ -2,6 +2,8 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | + | //go:build !cgo | |||
| 6 | + | ||||
| 5 | package fakecgo | 7 | package fakecgo | ||
| 6 | 8 | ||||
| 7 | import "unsafe" | 9 | import "unsafe" | ||
M internal/fakecgo/go_setenv.go +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || freebsd || linux | |
| 4 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || freebsd || linux | 4 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | package fakecgo | ||
| 7 | 7 | ||||
M internal/fakecgo/go_util.go +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || freebsd || linux | |
| 4 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || freebsd || linux | 4 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | package fakecgo | ||
| 7 | 7 | ||||
M internal/fakecgo/iscgo.go +1 -1
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | - | //go:build darwin || freebsd || linux | |
| 5 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 6 | 6 | ||
| 7 | 7 | // The runtime package contains an uninitialized definition | |
| 8 | 8 | // for runtime·iscgo. Override it to tell the runtime we're here. | |
| @@ -2,7 +2,7 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | - | //go:build darwin || freebsd || linux | 5 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 6 | 6 | ||||
| 7 | // The runtime package contains an uninitialized definition | 7 | // The runtime package contains an uninitialized definition | ||
| 8 | // for runtime·iscgo. Override it to tell the runtime we're here. | 8 | // for runtime·iscgo. Override it to tell the runtime we're here. | ||
M internal/fakecgo/libcgo.go +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || freebsd || linux | |
| 4 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || freebsd || linux | 4 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | package fakecgo | ||
| 7 | 7 | ||||
M internal/fakecgo/libcgo_darwin.go +2 -0
| @@ -1,6 +1,8 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | + | //go:build !cgo | |
| 5 | + | ||
| 4 | 6 | package fakecgo | |
| 5 | 7 | ||
| 6 | 8 | type ( | |
| @@ -1,6 +1,8 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | + | //go:build !cgo | |||
| 5 | + | ||||
| 4 | package fakecgo | 6 | package fakecgo | ||
| 5 | 7 | ||||
| 6 | type ( | 8 | type ( | ||
M internal/fakecgo/libcgo_freebsd.go +2 -0
| @@ -1,6 +1,8 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | + | //go:build !cgo | |
| 5 | + | ||
| 4 | 6 | package fakecgo | |
| 5 | 7 | ||
| 6 | 8 | type ( | |
| @@ -1,6 +1,8 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | + | //go:build !cgo | |||
| 5 | + | ||||
| 4 | package fakecgo | 6 | package fakecgo | ||
| 5 | 7 | ||||
| 6 | type ( | 8 | type ( | ||
M internal/fakecgo/libcgo_linux.go +2 -0
| @@ -1,6 +1,8 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | + | //go:build !cgo | |
| 5 | + | ||
| 4 | 6 | package fakecgo | |
| 5 | 7 | ||
| 6 | 8 | type ( | |
| @@ -1,6 +1,8 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | + | //go:build !cgo | |||
| 5 | + | ||||
| 4 | package fakecgo | 6 | package fakecgo | ||
| 5 | 7 | ||||
| 6 | type ( | 8 | type ( | ||
M internal/fakecgo/setenv.go +1 -1
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | // Use of this source code is governed by a BSD-style | |
| 3 | 3 | // license that can be found in the LICENSE file. | |
| 4 | 4 | ||
| 5 | - | //go:build darwin || freebsd || linux | |
| 5 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 6 | 6 | ||
| 7 | 7 | package fakecgo | |
| 8 | 8 | ||
| @@ -2,7 +2,7 @@ | |||||
| 2 | // Use of this source code is governed by a BSD-style | 2 | // Use of this source code is governed by a BSD-style | ||
| 3 | // license that can be found in the LICENSE file. | 3 | // license that can be found in the LICENSE file. | ||
| 4 | 4 | ||||
| 5 | - | //go:build darwin || freebsd || linux | 5 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 6 | 6 | ||||
| 7 | package fakecgo | 7 | package fakecgo | ||
| 8 | 8 | ||||
M internal/fakecgo/symbols.go +1 -1
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | // SPDX-License-Identifier: Apache-2.0 | |
| 4 | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 5 | 5 | ||
| 6 | - | //go:build darwin || freebsd || linux | |
| 6 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 7 | 7 | ||
| 8 | 8 | package fakecgo | |
| 9 | 9 | ||
| @@ -3,7 +3,7 @@ | |||||
| 3 | // SPDX-License-Identifier: Apache-2.0 | 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 5 | 5 | ||||
| 6 | - | //go:build darwin || freebsd || linux | 6 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 7 | 7 | ||||
| 8 | package fakecgo | 8 | package fakecgo | ||
| 9 | 9 | ||||
M internal/fakecgo/symbols_darwin.go +2 -0
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | // SPDX-License-Identifier: Apache-2.0 | |
| 4 | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 5 | 5 | ||
| 6 | + | //go:build !cgo | |
| 7 | + | ||
| 6 | 8 | package fakecgo | |
| 7 | 9 | ||
| 8 | 10 | //go:cgo_import_dynamic purego_malloc malloc "/usr/lib/libSystem.B.dylib" | |
| @@ -3,6 +3,8 @@ | |||||
| 3 | // SPDX-License-Identifier: Apache-2.0 | 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 5 | 5 | ||||
| 6 | + | //go:build !cgo | |||
| 7 | + | ||||
| 6 | package fakecgo | 8 | package fakecgo | ||
| 7 | 9 | ||||
| 8 | //go:cgo_import_dynamic purego_malloc malloc "/usr/lib/libSystem.B.dylib" | 10 | //go:cgo_import_dynamic purego_malloc malloc "/usr/lib/libSystem.B.dylib" | ||
M internal/fakecgo/symbols_freebsd.go +2 -0
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | // SPDX-License-Identifier: Apache-2.0 | |
| 4 | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 5 | 5 | ||
| 6 | + | //go:build !cgo | |
| 7 | + | ||
| 6 | 8 | package fakecgo | |
| 7 | 9 | ||
| 8 | 10 | //go:cgo_import_dynamic purego_malloc malloc "libc.so.7" | |
| @@ -3,6 +3,8 @@ | |||||
| 3 | // SPDX-License-Identifier: Apache-2.0 | 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 5 | 5 | ||||
| 6 | + | //go:build !cgo | |||
| 7 | + | ||||
| 6 | package fakecgo | 8 | package fakecgo | ||
| 7 | 9 | ||||
| 8 | //go:cgo_import_dynamic purego_malloc malloc "libc.so.7" | 10 | //go:cgo_import_dynamic purego_malloc malloc "libc.so.7" | ||
M internal/fakecgo/symbols_linux.go +2 -0
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | // SPDX-License-Identifier: Apache-2.0 | |
| 4 | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 5 | 5 | ||
| 6 | + | //go:build !cgo | |
| 7 | + | ||
| 6 | 8 | package fakecgo | |
| 7 | 9 | ||
| 8 | 10 | //go:cgo_import_dynamic purego_malloc malloc "libc.so.6" | |
| @@ -3,6 +3,8 @@ | |||||
| 3 | // SPDX-License-Identifier: Apache-2.0 | 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 5 | 5 | ||||
| 6 | + | //go:build !cgo | |||
| 7 | + | ||||
| 6 | package fakecgo | 8 | package fakecgo | ||
| 7 | 9 | ||||
| 8 | //go:cgo_import_dynamic purego_malloc malloc "libc.so.6" | 10 | //go:cgo_import_dynamic purego_malloc malloc "libc.so.6" | ||
M internal/fakecgo/trampolines_amd64.s +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || linux || freebsd | |
| 4 | + | //go:build !cgo && (darwin || linux || freebsd) | |
| 5 | 5 | ||
| 6 | 6 | /* | |
| 7 | 7 | trampoline for emulating required C functions for cgo in go (see cgo.go) | |
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || linux || freebsd | 4 | + | //go:build !cgo && (darwin || linux || freebsd) |
| 5 | 5 | ||||
| 6 | /* | 6 | /* | ||
| 7 | trampoline for emulating required C functions for cgo in go (see cgo.go) | 7 | trampoline for emulating required C functions for cgo in go (see cgo.go) | ||
M internal/fakecgo/trampolines_arm64.s +1 -1
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | - | //go:build darwin || freebsd || linux | |
| 4 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 5 | 5 | ||
| 6 | 6 | #include "textflag.h" | |
| 7 | 7 | #include "go_asm.h" | |
| @@ -1,7 +1,7 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | - | //go:build darwin || freebsd || linux | 4 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 5 | 5 | ||||
| 6 | #include "textflag.h" | 6 | #include "textflag.h" | ||
| 7 | #include "go_asm.h" | 7 | #include "go_asm.h" | ||
M internal/fakecgo/trampolines_stubs.s +1 -1
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | // SPDX-License-Identifier: Apache-2.0 | |
| 4 | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | |
| 5 | 5 | ||
| 6 | - | //go:build darwin || freebsd || linux | |
| 6 | + | //go:build !cgo && (darwin || freebsd || linux) | |
| 7 | 7 | ||
| 8 | 8 | #include "textflag.h" | |
| 9 | 9 | ||
| @@ -3,7 +3,7 @@ | |||||
| 3 | // SPDX-License-Identifier: Apache-2.0 | 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | 4 | // SPDX-FileCopyrightText: 2022 The Ebitengine Authors | ||
| 5 | 5 | ||||
| 6 | - | //go:build darwin || freebsd || linux | 6 | + | //go:build !cgo && (darwin || freebsd || linux) |
| 7 | 7 | ||||
| 8 | #include "textflag.h" | 8 | #include "textflag.h" | ||
| 9 | 9 | ||||
A internal/load/load_unix.go +16 -0
| @@ -0,0 +1,16 @@ | |||
| 1 | + | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | + | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | |
| 3 | + | ||
| 4 | + | //go:build darwin || freebsd || linux | |
| 5 | + | ||
| 6 | + | package load | |
| 7 | + | ||
| 8 | + | import "github.com/ebitengine/purego" | |
| 9 | + | ||
| 10 | + | func OpenLibrary(name string) (uintptr, error) { | |
| 11 | + | return purego.Dlopen(name, purego.RTLD_NOW|purego.RTLD_GLOBAL) | |
| 12 | + | } | |
| 13 | + | ||
| 14 | + | func OpenSymbol(lib uintptr, name string) (uintptr, error) { | |
| 15 | + | return purego.Dlsym(lib, name) | |
| 16 | + | } | |
| @@ -0,0 +1,16 @@ | |||||
| 1 | + | // SPDX-License-Identifier: Apache-2.0 | |||
| 2 | + | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | |||
| 3 | + | ||||
| 4 | + | //go:build darwin || freebsd || linux | |||
| 5 | + | ||||
| 6 | + | package load | |||
| 7 | + | ||||
| 8 | + | import "github.com/ebitengine/purego" | |||
| 9 | + | ||||
| 10 | + | func OpenLibrary(name string) (uintptr, error) { | |||
| 11 | + | return purego.Dlopen(name, purego.RTLD_NOW|purego.RTLD_GLOBAL) | |||
| 12 | + | } | |||
| 13 | + | ||||
| 14 | + | func OpenSymbol(lib uintptr, name string) (uintptr, error) { | |||
| 15 | + | return purego.Dlsym(lib, name) | |||
| 16 | + | } | |||
A internal/load/load_windows.go +15 -0
| @@ -0,0 +1,15 @@ | |||
| 1 | + | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | + | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | |
| 3 | + | ||
| 4 | + | package load | |
| 5 | + | ||
| 6 | + | import "golang.org/x/sys/windows" | |
| 7 | + | ||
| 8 | + | func OpenLibrary(name string) (uintptr, error) { | |
| 9 | + | handle, err := windows.LoadLibrary(name) | |
| 10 | + | return uintptr(handle), err | |
| 11 | + | } | |
| 12 | + | ||
| 13 | + | func OpenSymbol(lib uintptr, name string) (uintptr, error) { | |
| 14 | + | return windows.GetProcAddress(windows.Handle(lib), name) | |
| 15 | + | } | |
| @@ -0,0 +1,15 @@ | |||||
| 1 | + | // SPDX-License-Identifier: Apache-2.0 | |||
| 2 | + | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | |||
| 3 | + | ||||
| 4 | + | package load | |||
| 5 | + | ||||
| 6 | + | import "golang.org/x/sys/windows" | |||
| 7 | + | ||||
| 8 | + | func OpenLibrary(name string) (uintptr, error) { | |||
| 9 | + | handle, err := windows.LoadLibrary(name) | |||
| 10 | + | return uintptr(handle), err | |||
| 11 | + | } | |||
| 12 | + | ||||
| 13 | + | func OpenSymbol(lib uintptr, name string) (uintptr, error) { | |||
| 14 | + | return windows.GetProcAddress(windows.Handle(lib), name) | |||
| 15 | + | } | |||
M syscall.go +7 -0
| @@ -5,6 +5,13 @@ | |||
| 5 | 5 | ||
| 6 | 6 | package purego | |
| 7 | 7 | ||
| 8 | + | // CDecl marks a function as being called using the __cdecl calling convention as defined in | |
| 9 | + | // the [MSDocs] when passed to NewCallback. It must be the first argument to the function. | |
| 10 | + | // This is only useful on 386 Windows, but it is safe to use on other platforms. | |
| 11 | + | // | |
| 12 | + | // [MSDocs]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 | |
| 13 | + | type CDecl struct{} | |
| 14 | + | ||
| 8 | 15 | const ( | |
| 9 | 16 | maxArgs = 15 | |
| 10 | 17 | numOfFloats = 8 // arm64 and amd64 both have 8 float registers | |
| @@ -5,6 +5,13 @@ | |||||
| 5 | 5 | ||||
| 6 | package purego | 6 | package purego | ||
| 7 | 7 | ||||
| 8 | + | // CDecl marks a function as being called using the __cdecl calling convention as defined in | |||
| 9 | + | // the [MSDocs] when passed to NewCallback. It must be the first argument to the function. | |||
| 10 | + | // This is only useful on 386 Windows, but it is safe to use on other platforms. | |||
| 11 | + | // | |||
| 12 | + | // [MSDocs]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 | |||
| 13 | + | type CDecl struct{} | |||
| 14 | + | ||||
| 8 | const ( | 15 | const ( | ||
| 9 | maxArgs = 15 | 16 | maxArgs = 15 | ||
| 10 | numOfFloats = 8 // arm64 and amd64 both have 8 float registers | 17 | numOfFloats = 8 // arm64 and amd64 both have 8 float registers | ||
M syscall_cgo_linux.go +0 -2
| @@ -6,8 +6,6 @@ | |||
| 6 | 6 | package purego | |
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | - | _ "unsafe" // for go:linkname | |
| 10 | - | ||
| 11 | 9 | "github.com/ebitengine/purego/internal/cgo" | |
| 12 | 10 | ) | |
| 13 | 11 | ||
| @@ -6,8 +6,6 @@ | |||||
| 6 | package purego | 6 | package purego | ||
| 7 | 7 | ||||
| 8 | import ( | 8 | import ( | ||
| 9 | - | _ "unsafe" // for go:linkname | |||
| 10 | - | ||||
| 11 | "github.com/ebitengine/purego/internal/cgo" | 9 | "github.com/ebitengine/purego/internal/cgo" | ||
| 12 | ) | 10 | ) | ||
| 13 | 11 | ||||
M syscall_sysv.go +21 -1
| @@ -32,6 +32,16 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a | |||
| 32 | 32 | // for these callbacks is never released. At least 2000 callbacks can always be created. Although this function | |
| 33 | 33 | // provides similar functionality to windows.NewCallback it is distinct. | |
| 34 | 34 | func NewCallback(fn interface{}) uintptr { | |
| 35 | + | ty := reflect.TypeOf(fn) | |
| 36 | + | for i := 0; i < ty.NumIn(); i++ { | |
| 37 | + | in := ty.In(i) | |
| 38 | + | if !in.AssignableTo(reflect.TypeOf(CDecl{})) { | |
| 39 | + | continue | |
| 40 | + | } | |
| 41 | + | if i != 0 { | |
| 42 | + | panic("purego: CDecl must be the first argument") | |
| 43 | + | } | |
| 44 | + | } | |
| 35 | 45 | return compileCallback(fn) | |
| 36 | 46 | } | |
| 37 | 47 | ||
| @@ -73,7 +83,12 @@ func compileCallback(fn interface{}) uintptr { | |||
| 73 | 83 | for i := 0; i < ty.NumIn(); i++ { | |
| 74 | 84 | in := ty.In(i) | |
| 75 | 85 | switch in.Kind() { | |
| 76 | - | case reflect.Struct, reflect.Interface, reflect.Func, reflect.Slice, | |
| 86 | + | case reflect.Struct: | |
| 87 | + | if i == 0 && in.AssignableTo(reflect.TypeOf(CDecl{})) { | |
| 88 | + | continue | |
| 89 | + | } | |
| 90 | + | fallthrough | |
| 91 | + | case reflect.Interface, reflect.Func, reflect.Slice, | |
| 77 | 92 | reflect.Chan, reflect.Complex64, reflect.Complex128, | |
| 78 | 93 | reflect.String, reflect.Map, reflect.Invalid: | |
| 79 | 94 | panic("purego: unsupported argument type: " + in.Kind().String()) | |
| @@ -143,7 +158,12 @@ func callbackWrap(a *callbackArgs) { | |||
| 143 | 158 | pos = floatsN | |
| 144 | 159 | } | |
| 145 | 160 | floatsN++ | |
| 161 | + | case reflect.Struct: | |
| 162 | + | // This is the CDecl field | |
| 163 | + | args[i] = reflect.Zero(fnType.In(i)) | |
| 164 | + | continue | |
| 146 | 165 | default: | |
| 166 | + | ||
| 147 | 167 | if intsN >= numOfIntegerRegisters() { | |
| 148 | 168 | pos = stack | |
| 149 | 169 | stack++ | |
| @@ -32,6 +32,16 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a | |||||
| 32 | // for these callbacks is never released. At least 2000 callbacks can always be created. Although this function | 32 | // for these callbacks is never released. At least 2000 callbacks can always be created. Although this function | ||
| 33 | // provides similar functionality to windows.NewCallback it is distinct. | 33 | // provides similar functionality to windows.NewCallback it is distinct. | ||
| 34 | func NewCallback(fn interface{}) uintptr { | 34 | func NewCallback(fn interface{}) uintptr { | ||
| 35 | + | ty := reflect.TypeOf(fn) | |||
| 36 | + | for i := 0; i < ty.NumIn(); i++ { | |||
| 37 | + | in := ty.In(i) | |||
| 38 | + | if !in.AssignableTo(reflect.TypeOf(CDecl{})) { | |||
| 39 | + | continue | |||
| 40 | + | } | |||
| 41 | + | if i != 0 { | |||
| 42 | + | panic("purego: CDecl must be the first argument") | |||
| 43 | + | } | |||
| 44 | + | } | |||
| 35 | return compileCallback(fn) | 45 | return compileCallback(fn) | ||
| 36 | } | 46 | } | ||
| 37 | 47 | ||||
| @@ -73,7 +83,12 @@ func compileCallback(fn interface{}) uintptr { | |||||
| 73 | for i := 0; i < ty.NumIn(); i++ { | 83 | for i := 0; i < ty.NumIn(); i++ { | ||
| 74 | in := ty.In(i) | 84 | in := ty.In(i) | ||
| 75 | switch in.Kind() { | 85 | switch in.Kind() { | ||
| 76 | - | case reflect.Struct, reflect.Interface, reflect.Func, reflect.Slice, | 86 | + | case reflect.Struct: |
| 87 | + | if i == 0 && in.AssignableTo(reflect.TypeOf(CDecl{})) { | |||
| 88 | + | continue | |||
| 89 | + | } | |||
| 90 | + | fallthrough | |||
| 91 | + | case reflect.Interface, reflect.Func, reflect.Slice, | |||
| 77 | reflect.Chan, reflect.Complex64, reflect.Complex128, | 92 | reflect.Chan, reflect.Complex64, reflect.Complex128, | ||
| 78 | reflect.String, reflect.Map, reflect.Invalid: | 93 | reflect.String, reflect.Map, reflect.Invalid: | ||
| 79 | panic("purego: unsupported argument type: " + in.Kind().String()) | 94 | panic("purego: unsupported argument type: " + in.Kind().String()) | ||
| @@ -143,7 +158,12 @@ func callbackWrap(a *callbackArgs) { | |||||
| 143 | pos = floatsN | 158 | pos = floatsN | ||
| 144 | } | 159 | } | ||
| 145 | floatsN++ | 160 | floatsN++ | ||
| 161 | + | case reflect.Struct: | |||
| 162 | + | // This is the CDecl field | |||
| 163 | + | args[i] = reflect.Zero(fnType.In(i)) | |||
| 164 | + | continue | |||
| 146 | default: | 165 | default: | ||
| 166 | + | ||||
| 147 | if intsN >= numOfIntegerRegisters() { | 167 | if intsN >= numOfIntegerRegisters() { | ||
| 148 | pos = stack | 168 | pos = stack | ||
| 149 | stack++ | 169 | stack++ | ||
M syscall_windows.go +16 -7
| @@ -4,8 +4,8 @@ | |||
| 4 | 4 | package purego | |
| 5 | 5 | ||
| 6 | 6 | import ( | |
| 7 | + | "reflect" | |
| 7 | 8 | "syscall" | |
| 8 | - | _ "unsafe" // only for go:linkname | |
| 9 | 9 | ||
| 10 | 10 | "golang.org/x/sys/windows" | |
| 11 | 11 | ) | |
| @@ -25,15 +25,24 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a | |||
| 25 | 25 | // callbacks can always be created. Although this function is similiar to the darwin version it may act | |
| 26 | 26 | // differently. | |
| 27 | 27 | func NewCallback(fn interface{}) uintptr { | |
| 28 | + | isCDecl := false | |
| 29 | + | ty := reflect.TypeOf(fn) | |
| 30 | + | for i := 0; i < ty.NumIn(); i++ { | |
| 31 | + | in := ty.In(i) | |
| 32 | + | if !in.AssignableTo(reflect.TypeOf(CDecl{})) { | |
| 33 | + | continue | |
| 34 | + | } | |
| 35 | + | if i != 0 { | |
| 36 | + | panic("purego: CDecl must be the first argument") | |
| 37 | + | } | |
| 38 | + | isCDecl = true | |
| 39 | + | } | |
| 40 | + | if isCDecl { | |
| 41 | + | return syscall.NewCallbackCDecl(fn) | |
| 42 | + | } | |
| 28 | 43 | return syscall.NewCallback(fn) | |
| 29 | 44 | } | |
| 30 | 45 | ||
| 31 | - | //go:linkname openLibrary openLibrary | |
| 32 | - | func openLibrary(name string) (uintptr, error) { | |
| 33 | - | handle, err := windows.LoadLibrary(name) | |
| 34 | - | return uintptr(handle), err | |
| 35 | - | } | |
| 36 | - | ||
| 37 | 46 | func loadSymbol(handle uintptr, name string) (uintptr, error) { | |
| 38 | 47 | return windows.GetProcAddress(windows.Handle(handle), name) | |
| 39 | 48 | } | |
| @@ -4,8 +4,8 @@ | |||||
| 4 | package purego | 4 | package purego | ||
| 5 | 5 | ||||
| 6 | import ( | 6 | import ( | ||
| 7 | + | "reflect" | |||
| 7 | "syscall" | 8 | "syscall" | ||
| 8 | - | _ "unsafe" // only for go:linkname | |||
| 9 | 9 | ||||
| 10 | "golang.org/x/sys/windows" | 10 | "golang.org/x/sys/windows" | ||
| 11 | ) | 11 | ) | ||
| @@ -25,15 +25,24 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a | |||||
| 25 | // callbacks can always be created. Although this function is similiar to the darwin version it may act | 25 | // callbacks can always be created. Although this function is similiar to the darwin version it may act | ||
| 26 | // differently. | 26 | // differently. | ||
| 27 | func NewCallback(fn interface{}) uintptr { | 27 | func NewCallback(fn interface{}) uintptr { | ||
| 28 | + | isCDecl := false | |||
| 29 | + | ty := reflect.TypeOf(fn) | |||
| 30 | + | for i := 0; i < ty.NumIn(); i++ { | |||
| 31 | + | in := ty.In(i) | |||
| 32 | + | if !in.AssignableTo(reflect.TypeOf(CDecl{})) { | |||
| 33 | + | continue | |||
| 34 | + | } | |||
| 35 | + | if i != 0 { | |||
| 36 | + | panic("purego: CDecl must be the first argument") | |||
| 37 | + | } | |||
| 38 | + | isCDecl = true | |||
| 39 | + | } | |||
| 40 | + | if isCDecl { | |||
| 41 | + | return syscall.NewCallbackCDecl(fn) | |||
| 42 | + | } | |||
| 28 | return syscall.NewCallback(fn) | 43 | return syscall.NewCallback(fn) | ||
| 29 | } | 44 | } | ||
| 30 | 45 | ||||
| 31 | - | //go:linkname openLibrary openLibrary | |||
| 32 | - | func openLibrary(name string) (uintptr, error) { | |||
| 33 | - | handle, err := windows.LoadLibrary(name) | |||
| 34 | - | return uintptr(handle), err | |||
| 35 | - | } | |||
| 36 | - | ||||
| 37 | func loadSymbol(handle uintptr, name string) (uintptr, error) { | 46 | func loadSymbol(handle uintptr, name string) (uintptr, error) { | ||
| 38 | return windows.GetProcAddress(windows.Handle(handle), name) | 47 | return windows.GetProcAddress(windows.Handle(handle), name) | ||
| 39 | } | 48 | } | ||