github.com/jwijenbergh/purego@v0.0.0-20240126093400-70ff3a61df13/func_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: 2023 The Ebitengine Authors 3 4 package purego_test 5 6 import ( 7 "fmt" 8 "runtime" 9 "testing" 10 "unsafe" 11 12 "github.com/jwijenbergh/purego" 13 ) 14 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) { 21 switch runtime.GOOS { 22 case "darwin": 23 return "/usr/lib/libSystem.B.dylib", nil 24 case "linux": 25 return "libc.so.6", nil 26 case "freebsd": 27 return "libc.so.7", nil 28 case "windows": 29 return "ucrtbase.dll", nil 30 default: 31 return "", fmt.Errorf("GOOS=%s is not supported", runtime.GOOS) 32 } 33 } 34 35 func TestRegisterFunc(t *testing.T) { 36 library, err := getSystemLibrary() 37 if err != nil { 38 t.Fatalf("couldn't get system library: %s", err) 39 } 40 libc, err := openLibrary(library) 41 if err != nil { 42 t.Fatalf("failed to dlopen: %s", err) 43 } 44 var puts func(string) 45 purego.RegisterLibFunc(&puts, libc, "puts") 46 puts("Calling C from from Go without Cgo!") 47 } 48 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) { 66 library, err := getSystemLibrary() 67 if err != nil { 68 t.Fatalf("couldn't get system library: %s", err) 69 } 70 libc, err := openLibrary(library) 71 if err != nil { 72 t.Fatalf("failed to dlopen: %s", err) 73 } 74 75 data := []int{88, 56, 100, 2, 25} 76 sorted := []int{2, 25, 56, 88, 100} 77 compare := func(a, b *int) int { 78 return *a - *b 79 } 80 var qsort func(data []int, nitms uintptr, size uintptr, compar func(a, b *int) int) 81 purego.RegisterLibFunc(&qsort, libc, "qsort") 82 qsort(data, uintptr(len(data)), unsafe.Sizeof(int(0)), compare) 83 for i := range data { 84 if data[i] != sorted[i] { 85 t.Errorf("got %d wanted %d at %d", data[i], sorted[i], i) 86 } 87 } 88 } 89 90 func TestRegisterFunc_Floats(t *testing.T) { 91 library, err := getSystemLibrary() 92 if err != nil { 93 t.Fatalf("couldn't get system library: %s", err) 94 } 95 libc, err := openLibrary(library) 96 if err != nil { 97 t.Fatalf("failed to dlopen: %s", err) 98 } 99 { 100 var strtof func(arg string) float32 101 purego.RegisterLibFunc(&strtof, libc, "strtof") 102 const ( 103 arg = "2" 104 ) 105 got := strtof(arg) 106 expected := float32(2) 107 if got != expected { 108 t.Errorf("strtof failed. got %f but wanted %f", got, expected) 109 } 110 } 111 { 112 var strtod func(arg string, ptr **byte) float64 113 purego.RegisterLibFunc(&strtod, libc, "strtod") 114 const ( 115 arg = "1" 116 ) 117 got := strtod(arg, nil) 118 expected := float64(1) 119 if got != expected { 120 t.Errorf("strtod failed. got %f but wanted %f", got, expected) 121 } 122 } 123 } 124 125 func TestRegisterLibFunc_Bool(t *testing.T) { 126 // this callback recreates the state where the return register 127 // contains other information but the least significant byte is false 128 cbFalse := purego.NewCallback(func() uintptr { 129 return 0x7F5948AE9A00 130 }) 131 var runFalse func() bool 132 purego.RegisterFunc(&runFalse, cbFalse) 133 expected := false 134 if got := runFalse(); got != expected { 135 t.Errorf("runFalse failed. got %t but wanted %t", got, expected) 136 } 137 } 138 139 func TestCallbackFnPtrDedup(t *testing.T) { 140 imp := func() uintptr { 141 return 0 142 } 143 144 ref1 := purego.NewCallbackFnPtr(&imp) 145 ref2 := purego.NewCallbackFnPtr(&imp) 146 147 if ref1 != ref2 { 148 t.Errorf("deduplicate expected %d to equal %d", ref1, ref2) 149 } 150 }