github.com/ebitengine/purego@v0.8.0-alpha.2.0.20240512170805-6cd12240d332/dlfcn_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: 2023 The Ebitengine Authors 3 4 //go:build darwin || freebsd || linux 5 6 package purego_test 7 8 import ( 9 "errors" 10 "fmt" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "runtime" 15 "strings" 16 "testing" 17 "unsafe" 18 19 "github.com/ebitengine/purego" 20 ) 21 22 func TestSimpleDlsym(t *testing.T) { 23 if _, err := purego.Dlsym(purego.RTLD_DEFAULT, "dlsym"); err != nil { 24 t.Errorf("Dlsym with RTLD_DEFAULT failed: %v", err) 25 } 26 } 27 28 func TestNestedDlopenCall(t *testing.T) { 29 libFileName := filepath.Join(t.TempDir(), "libdlnested.so") 30 t.Logf("Build %v", libFileName) 31 32 if err := buildSharedLib("CXX", libFileName, filepath.Join("testdata", "libdlnested", "nested_test.cpp")); err != nil { 33 t.Fatal(err) 34 } 35 defer os.Remove(libFileName) 36 37 lib, err := purego.Dlopen(libFileName, purego.RTLD_NOW|purego.RTLD_GLOBAL) 38 if err != nil { 39 t.Fatalf("Dlopen(%q) failed: %v", libFileName, err) 40 } 41 42 purego.Dlclose(lib) 43 } 44 45 func buildSharedLib(compilerEnv, libFile string, sources ...string) error { 46 out, err := exec.Command("go", "env", compilerEnv).Output() 47 if err != nil { 48 return fmt.Errorf("go env %s error: %w", compilerEnv, err) 49 } 50 51 compiler := strings.TrimSpace(string(out)) 52 if compiler == "" { 53 return errors.New("compiler not found") 54 } 55 56 var args []string 57 if runtime.GOOS == "freebsd" { 58 args = []string{"-shared", "-Wall", "-Werror", "-fPIC", "-o", libFile} 59 } else { 60 args = []string{"-shared", "-Wall", "-Werror", "-o", libFile} 61 } 62 if runtime.GOARCH == "386" { 63 args = append(args, "-m32") 64 } 65 // macOS arm64 can run amd64 tests through Rossetta. 66 // Build the shared library based on the GOARCH and not 67 // the default behavior of the compiler. 68 if runtime.GOOS == "darwin" { 69 var arch string 70 switch runtime.GOARCH { 71 case "arm64": 72 arch = "arm64" 73 case "amd64": 74 arch = "x86_64" 75 default: 76 return fmt.Errorf("unknown macOS architecture %s", runtime.GOARCH) 77 } 78 args = append(args, "-arch", arch) 79 } 80 cmd := exec.Command(compiler, append(args, sources...)...) 81 if out, err := cmd.CombinedOutput(); err != nil { 82 return fmt.Errorf("compile lib: %w\n%q\n%s", err, cmd, string(out)) 83 } 84 85 return nil 86 } 87 88 func TestSyscallN(t *testing.T) { 89 var dlsym uintptr 90 var err error 91 if dlsym, err = purego.Dlsym(purego.RTLD_DEFAULT, "dlsym"); err != nil { 92 t.Errorf("Dlsym with RTLD_DEFAULT failed: %v", err) 93 } 94 r1, _, err2 := purego.SyscallN(dlsym, purego.RTLD_DEFAULT, uintptr(unsafe.Pointer(&[]byte("dlsym\x00")[0]))) 95 if dlsym != r1 { 96 t.Fatalf("SyscallN didn't return the same result as purego.Dlsym: %d", err2) 97 } 98 }