purego: enable testing of amd64 with Rosseta on arm64 macOS (#122)
With Rosetta on arm64 it was possible to test amd64 just by setting GOARCH=amd64. However, since the shared library tests were added it is no longer possible because the default compiler will build for the host architecture and not the cross-compiled (amd64) architecture. This commit tells the C/C++ compiler to build for amd64 when running an amd64 binary. This only effects macOS.
- commit
- b4a1f66b6b989a222b0f305eebd4ec18649b332b
- author
- TotallyGamerJet · · 2023-04-03 18:44 UTC
- committer
- GitHub · · 2023-04-03 18:44 UTC
- parent
- dd97be5
- signature
- GPG Unverified
4AEE18F83AFDEB23The key is unknown
2 files · +41 -39
M callback_test.go +1 -25
| @@ -6,12 +6,8 @@ | |||
| 6 | 6 | package purego_test | |
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | - | "errors" | |
| 10 | - | "fmt" | |
| 11 | 9 | "os" | |
| 12 | - | "os/exec" | |
| 13 | 10 | "path/filepath" | |
| 14 | - | "strings" | |
| 15 | 11 | "testing" | |
| 16 | 12 | "unsafe" | |
| 17 | 13 | ||
| @@ -24,7 +20,7 @@ func TestCallGoFromSharedLib(t *testing.T) { | |||
| 24 | 20 | libFileName := filepath.Join(t.TempDir(), "libcbtest.so") | |
| 25 | 21 | t.Logf("Build %v", libFileName) | |
| 26 | 22 | ||
| 27 | - | if err := buildSharedLib(libFileName, filepath.Join("libcbtest", "callback.c")); err != nil { | |
| 23 | + | if err := buildSharedLib("CC", libFileName, filepath.Join("libcbtest", "callback.c")); err != nil { | |
| 28 | 24 | t.Fatal(err) | |
| 29 | 25 | } | |
| 30 | 26 | defer os.Remove(libFileName) | |
| @@ -53,26 +49,6 @@ func TestCallGoFromSharedLib(t *testing.T) { | |||
| 53 | 49 | } | |
| 54 | 50 | } | |
| 55 | 51 | ||
| 56 | - | func buildSharedLib(libFile string, sources ...string) error { | |
| 57 | - | out, err := exec.Command("go", "env", "CC").Output() | |
| 58 | - | if err != nil { | |
| 59 | - | return fmt.Errorf("go env error: %w", err) | |
| 60 | - | } | |
| 61 | - | ||
| 62 | - | cc := strings.TrimSpace(string(out)) | |
| 63 | - | if cc == "" { | |
| 64 | - | return errors.New("CC not found") | |
| 65 | - | } | |
| 66 | - | ||
| 67 | - | args := append([]string{"-shared", "-Wall", "-Werror", "-o", libFile}, sources...) | |
| 68 | - | cmd := exec.Command(cc, args...) | |
| 69 | - | if out, err := cmd.CombinedOutput(); err != nil { | |
| 70 | - | return fmt.Errorf("compile lib: %w\n%q\n%s", err, cmd, string(out)) | |
| 71 | - | } | |
| 72 | - | ||
| 73 | - | return nil | |
| 74 | - | } | |
| 75 | - | ||
| 76 | 52 | func TestNewCallbackFloat64(t *testing.T) { | |
| 77 | 53 | // This tests the maximum number of arguments a function to NewCallback can take | |
| 78 | 54 | const ( | |
| @@ -6,12 +6,8 @@ | |||||
| 6 | package purego_test | 6 | package purego_test | ||
| 7 | 7 | ||||
| 8 | import ( | 8 | import ( | ||
| 9 | - | "errors" | |||
| 10 | - | "fmt" | |||
| 11 | "os" | 9 | "os" | ||
| 12 | - | "os/exec" | |||
| 13 | "path/filepath" | 10 | "path/filepath" | ||
| 14 | - | "strings" | |||
| 15 | "testing" | 11 | "testing" | ||
| 16 | "unsafe" | 12 | "unsafe" | ||
| 17 | 13 | ||||
| @@ -24,7 +20,7 @@ func TestCallGoFromSharedLib(t *testing.T) { | |||||
| 24 | libFileName := filepath.Join(t.TempDir(), "libcbtest.so") | 20 | libFileName := filepath.Join(t.TempDir(), "libcbtest.so") | ||
| 25 | t.Logf("Build %v", libFileName) | 21 | t.Logf("Build %v", libFileName) | ||
| 26 | 22 | ||||
| 27 | - | if err := buildSharedLib(libFileName, filepath.Join("libcbtest", "callback.c")); err != nil { | 23 | + | if err := buildSharedLib("CC", libFileName, filepath.Join("libcbtest", "callback.c")); err != nil { |
| 28 | t.Fatal(err) | 24 | t.Fatal(err) | ||
| 29 | } | 25 | } | ||
| 30 | defer os.Remove(libFileName) | 26 | defer os.Remove(libFileName) | ||
| @@ -53,26 +49,6 @@ func TestCallGoFromSharedLib(t *testing.T) { | |||||
| 53 | } | 49 | } | ||
| 54 | } | 50 | } | ||
| 55 | 51 | ||||
| 56 | - | func buildSharedLib(libFile string, sources ...string) error { | |||
| 57 | - | out, err := exec.Command("go", "env", "CC").Output() | |||
| 58 | - | if err != nil { | |||
| 59 | - | return fmt.Errorf("go env error: %w", err) | |||
| 60 | - | } | |||
| 61 | - | ||||
| 62 | - | cc := strings.TrimSpace(string(out)) | |||
| 63 | - | if cc == "" { | |||
| 64 | - | return errors.New("CC not found") | |||
| 65 | - | } | |||
| 66 | - | ||||
| 67 | - | args := append([]string{"-shared", "-Wall", "-Werror", "-o", libFile}, sources...) | |||
| 68 | - | cmd := exec.Command(cc, args...) | |||
| 69 | - | if out, err := cmd.CombinedOutput(); err != nil { | |||
| 70 | - | return fmt.Errorf("compile lib: %w\n%q\n%s", err, cmd, string(out)) | |||
| 71 | - | } | |||
| 72 | - | ||||
| 73 | - | return nil | |||
| 74 | - | } | |||
| 75 | - | ||||
| 76 | func TestNewCallbackFloat64(t *testing.T) { | 52 | func TestNewCallbackFloat64(t *testing.T) { | ||
| 77 | // This tests the maximum number of arguments a function to NewCallback can take | 53 | // This tests the maximum number of arguments a function to NewCallback can take | ||
| 78 | const ( | 54 | const ( | ||
M dlfcn_test.go +40 -14
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | package purego_test | |
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | + | "errors" | |
| 9 | 10 | "fmt" | |
| 10 | 11 | "os" | |
| 11 | 12 | "os/exec" | |
| @@ -99,20 +100,8 @@ func TestNestedDlopenCall(t *testing.T) { | |||
| 99 | 100 | libFileName := filepath.Join(t.TempDir(), "libdlnested.so") | |
| 100 | 101 | t.Logf("Build %v", libFileName) | |
| 101 | 102 | ||
| 102 | - | out, err := exec.Command("go", "env", "CXX").Output() | |
| 103 | - | if err != nil { | |
| 104 | - | t.Fatalf("go env error: %v", err) | |
| 105 | - | } | |
| 106 | - | ||
| 107 | - | cxx := strings.TrimSpace(string(out)) | |
| 108 | - | if cxx == "" { | |
| 109 | - | t.Fatal("CXX not found") | |
| 110 | - | } | |
| 111 | - | ||
| 112 | - | args := []string{"-shared", "-Wall", "-Werror", "-o", libFileName, filepath.Join("libdlnested", "nested.cpp")} | |
| 113 | - | cmd := exec.Command(cxx, args...) | |
| 114 | - | if out, err := cmd.CombinedOutput(); err != nil { | |
| 115 | - | t.Fatalf("compile lib: %v\n%q\n%s", err, cmd, string(out)) | |
| 103 | + | if err := buildSharedLib("CXX", libFileName, filepath.Join("libdlnested", "nested.cpp")); err != nil { | |
| 104 | + | t.Fatal(err) | |
| 116 | 105 | } | |
| 117 | 106 | defer os.Remove(libFileName) | |
| 118 | 107 | ||
| @@ -123,3 +112,40 @@ func TestNestedDlopenCall(t *testing.T) { | |||
| 123 | 112 | ||
| 124 | 113 | purego.Dlclose(lib) | |
| 125 | 114 | } | |
| 115 | + | ||
| 116 | + | func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | |
| 117 | + | out, err := exec.Command("go", "env", compilerEnv).Output() | |
| 118 | + | if err != nil { | |
| 119 | + | return fmt.Errorf("go env %s error: %w", compilerEnv, err) | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | compiler := strings.TrimSpace(string(out)) | |
| 123 | + | if compiler == "" { | |
| 124 | + | return errors.New("compiler not found") | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | args := []string{"-shared", "-Wall", "-Werror", "-o", libFile} | |
| 128 | + | ||
| 129 | + | // macOS arm64 can run amd64 tests through Rossetta. | |
| 130 | + | // Build the shared library based on the GOARCH and not | |
| 131 | + | // the default behavior of the compiler. | |
| 132 | + | var archFlag, arch string | |
| 133 | + | if runtime.GOOS == "darwin" { | |
| 134 | + | archFlag = "-arch" | |
| 135 | + | switch runtime.GOARCH { | |
| 136 | + | case "arm64": | |
| 137 | + | arch = "arm64" | |
| 138 | + | case "amd64": | |
| 139 | + | arch = "x86_64" | |
| 140 | + | default: | |
| 141 | + | return fmt.Errorf("unknown macOS architecture %s", runtime.GOARCH) | |
| 142 | + | } | |
| 143 | + | args = append(args, archFlag, arch) | |
| 144 | + | } | |
| 145 | + | cmd := exec.Command(compiler, append(args, sources...)...) | |
| 146 | + | if out, err := cmd.CombinedOutput(); err != nil { | |
| 147 | + | return fmt.Errorf("compile lib: %w\n%q\n%s", err, cmd, string(out)) | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | return nil | |
| 151 | + | } | |
| @@ -6,6 +6,7 @@ | |||||
| 6 | package purego_test | 6 | package purego_test | ||
| 7 | 7 | ||||
| 8 | import ( | 8 | import ( | ||
| 9 | + | "errors" | |||
| 9 | "fmt" | 10 | "fmt" | ||
| 10 | "os" | 11 | "os" | ||
| 11 | "os/exec" | 12 | "os/exec" | ||
| @@ -99,20 +100,8 @@ func TestNestedDlopenCall(t *testing.T) { | |||||
| 99 | libFileName := filepath.Join(t.TempDir(), "libdlnested.so") | 100 | libFileName := filepath.Join(t.TempDir(), "libdlnested.so") | ||
| 100 | t.Logf("Build %v", libFileName) | 101 | t.Logf("Build %v", libFileName) | ||
| 101 | 102 | ||||
| 102 | - | out, err := exec.Command("go", "env", "CXX").Output() | 103 | + | if err := buildSharedLib("CXX", libFileName, filepath.Join("libdlnested", "nested.cpp")); err != nil { |
| 103 | - | if err != nil { | 104 | + | t.Fatal(err) |
| 104 | - | t.Fatalf("go env error: %v", err) | |||
| 105 | - | } | |||
| 106 | - | ||||
| 107 | - | cxx := strings.TrimSpace(string(out)) | |||
| 108 | - | if cxx == "" { | |||
| 109 | - | t.Fatal("CXX not found") | |||
| 110 | - | } | |||
| 111 | - | ||||
| 112 | - | args := []string{"-shared", "-Wall", "-Werror", "-o", libFileName, filepath.Join("libdlnested", "nested.cpp")} | |||
| 113 | - | cmd := exec.Command(cxx, args...) | |||
| 114 | - | if out, err := cmd.CombinedOutput(); err != nil { | |||
| 115 | - | t.Fatalf("compile lib: %v\n%q\n%s", err, cmd, string(out)) | |||
| 116 | } | 105 | } | ||
| 117 | defer os.Remove(libFileName) | 106 | defer os.Remove(libFileName) | ||
| 118 | 107 | ||||
| @@ -123,3 +112,40 @@ func TestNestedDlopenCall(t *testing.T) { | |||||
| 123 | 112 | ||||
| 124 | purego.Dlclose(lib) | 113 | purego.Dlclose(lib) | ||
| 125 | } | 114 | } | ||
| 115 | + | ||||
| 116 | + | func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | |||
| 117 | + | out, err := exec.Command("go", "env", compilerEnv).Output() | |||
| 118 | + | if err != nil { | |||
| 119 | + | return fmt.Errorf("go env %s error: %w", compilerEnv, err) | |||
| 120 | + | } | |||
| 121 | + | ||||
| 122 | + | compiler := strings.TrimSpace(string(out)) | |||
| 123 | + | if compiler == "" { | |||
| 124 | + | return errors.New("compiler not found") | |||
| 125 | + | } | |||
| 126 | + | ||||
| 127 | + | args := []string{"-shared", "-Wall", "-Werror", "-o", libFile} | |||
| 128 | + | ||||
| 129 | + | // macOS arm64 can run amd64 tests through Rossetta. | |||
| 130 | + | // Build the shared library based on the GOARCH and not | |||
| 131 | + | // the default behavior of the compiler. | |||
| 132 | + | var archFlag, arch string | |||
| 133 | + | if runtime.GOOS == "darwin" { | |||
| 134 | + | archFlag = "-arch" | |||
| 135 | + | switch runtime.GOARCH { | |||
| 136 | + | case "arm64": | |||
| 137 | + | arch = "arm64" | |||
| 138 | + | case "amd64": | |||
| 139 | + | arch = "x86_64" | |||
| 140 | + | default: | |||
| 141 | + | return fmt.Errorf("unknown macOS architecture %s", runtime.GOARCH) | |||
| 142 | + | } | |||
| 143 | + | args = append(args, archFlag, arch) | |||
| 144 | + | } | |||
| 145 | + | cmd := exec.Command(compiler, append(args, sources...)...) | |||
| 146 | + | if out, err := cmd.CombinedOutput(); err != nil { | |||
| 147 | + | return fmt.Errorf("compile lib: %w\n%q\n%s", err, cmd, string(out)) | |||
| 148 | + | } | |||
| 149 | + | ||||
| 150 | + | return nil | |||
| 151 | + | } | |||