1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package so_test 6 7import ( 8 "cmd/cgo/internal/cgotest" 9 "internal/testenv" 10 "log" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "runtime" 15 "strings" 16 "testing" 17) 18 19func TestSO(t *testing.T) { 20 testSO(t, "so") 21} 22 23func TestSOVar(t *testing.T) { 24 testSO(t, "sovar") 25} 26 27func testSO(t *testing.T, dir string) { 28 if runtime.GOOS == "ios" { 29 t.Skip("iOS disallows dynamic loading of user libraries") 30 } 31 testenv.MustHaveGoBuild(t) 32 testenv.MustHaveExec(t) 33 testenv.MustHaveCGO(t) 34 35 GOPATH, err := os.MkdirTemp("", "cgosotest") 36 if err != nil { 37 log.Fatal(err) 38 } 39 defer os.RemoveAll(GOPATH) 40 41 modRoot := filepath.Join(GOPATH, "src", "cgosotest") 42 if err := cgotest.OverlayDir(modRoot, filepath.Join("testdata", dir)); err != nil { 43 log.Panic(err) 44 } 45 if err := os.WriteFile(filepath.Join(modRoot, "go.mod"), []byte("module cgosotest\n"), 0666); err != nil { 46 log.Panic(err) 47 } 48 49 cmd := exec.Command("go", "env", "CC", "GOGCCFLAGS") 50 cmd.Dir = modRoot 51 cmd.Stderr = new(strings.Builder) 52 cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) 53 out, err := cmd.Output() 54 if err != nil { 55 t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr) 56 } 57 lines := strings.Split(string(out), "\n") 58 if len(lines) != 3 || lines[2] != "" { 59 t.Fatalf("Unexpected output from %s:\n%s", strings.Join(cmd.Args, " "), lines) 60 } 61 62 cc := lines[0] 63 if cc == "" { 64 t.Fatal("CC environment variable (go env CC) cannot be empty") 65 } 66 gogccflags := strings.Split(lines[1], " ") 67 68 // build shared object 69 ext := "so" 70 args := append(gogccflags, "-shared") 71 switch runtime.GOOS { 72 case "darwin", "ios": 73 ext = "dylib" 74 args = append(args, "-undefined", "suppress", "-flat_namespace") 75 case "windows": 76 ext = "dll" 77 args = append(args, "-DEXPORT_DLL") 78 // At least in mingw-clang it is not permitted to just name a .dll 79 // on the command line. You must name the corresponding import 80 // library instead, even though the dll is used when the executable is run. 81 args = append(args, "-Wl,-out-implib,libcgosotest.a") 82 case "aix": 83 ext = "so.1" 84 } 85 sofname := "libcgosotest." + ext 86 args = append(args, "-o", sofname, "cgoso_c.c") 87 88 cmd = exec.Command(cc, args...) 89 cmd.Dir = modRoot 90 cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) 91 out, err = cmd.CombinedOutput() 92 if err != nil { 93 t.Fatalf("%s: %s\n%s", strings.Join(cmd.Args, " "), err, out) 94 } 95 t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out) 96 97 if runtime.GOOS == "aix" { 98 // Shared object must be wrapped by an archive 99 cmd = exec.Command("ar", "-X64", "-q", "libcgosotest.a", "libcgosotest.so.1") 100 cmd.Dir = modRoot 101 out, err = cmd.CombinedOutput() 102 if err != nil { 103 t.Fatalf("%s: %s\n%s", strings.Join(cmd.Args, " "), err, out) 104 } 105 } 106 107 cmd = exec.Command("go", "build", "-o", "main.exe", "main.go") 108 cmd.Dir = modRoot 109 cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) 110 out, err = cmd.CombinedOutput() 111 if err != nil { 112 t.Fatalf("%s: %s\n%s", strings.Join(cmd.Args, " "), err, out) 113 } 114 t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out) 115 116 cmd = exec.Command("./main.exe") 117 cmd.Dir = modRoot 118 cmd.Env = append(os.Environ(), "GOPATH="+GOPATH) 119 if runtime.GOOS != "windows" { 120 s := "LD_LIBRARY_PATH" 121 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { 122 s = "DYLD_LIBRARY_PATH" 123 } 124 cmd.Env = append(os.Environ(), s+"=.") 125 126 // On FreeBSD 64-bit architectures, the 32-bit linker looks for 127 // different environment variables. 128 if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" { 129 cmd.Env = append(cmd.Env, "LD_32_LIBRARY_PATH=.") 130 } 131 } 132 out, err = cmd.CombinedOutput() 133 if err != nil { 134 t.Fatalf("%s: %s\n%s", strings.Join(cmd.Args, " "), err, out) 135 } 136 t.Logf("%s:\n%s", strings.Join(cmd.Args, " "), out) 137} 138