summaryrefslogtreecommitdiffstats
path: root/src/cmd/link/cgo_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/cgo_test.go')
-rw-r--r--src/cmd/link/cgo_test.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/cmd/link/cgo_test.go b/src/cmd/link/cgo_test.go
new file mode 100644
index 0000000..4393c3f
--- /dev/null
+++ b/src/cmd/link/cgo_test.go
@@ -0,0 +1,141 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+// Issues 43830, 46295
+func TestCGOLTO(t *testing.T) {
+ testenv.MustHaveCGO(t)
+ testenv.MustHaveGoBuild(t)
+
+ t.Parallel()
+
+ for _, cc := range []string{"gcc", "clang"} {
+ for test := 0; test < 2; test++ {
+ t.Run(fmt.Sprintf("%s-%d", cc, test), func(t *testing.T) {
+ testCGOLTO(t, cc, test)
+ })
+ }
+ }
+}
+
+const test1_main = `
+package main
+
+/*
+extern int myadd(int, int);
+int c_add(int a, int b) {
+ return myadd(a, b);
+}
+*/
+import "C"
+
+func main() {
+ println(C.c_add(1, 2))
+}
+`
+
+const test1_add = `
+package main
+
+import "C"
+
+/* test */
+
+//export myadd
+func myadd(a C.int, b C.int) C.int {
+ return a + b
+}
+`
+
+const test2_main = `
+package main
+
+import "fmt"
+
+/*
+#include <stdio.h>
+
+void hello(void) {
+ printf("hello\n");
+}
+*/
+import "C"
+
+func main() {
+ hello := C.hello
+ fmt.Printf("%v\n", hello)
+}
+`
+
+func testCGOLTO(t *testing.T, cc string, test int) {
+ t.Parallel()
+
+ if _, err := exec.LookPath(cc); err != nil {
+ t.Skipf("no %s compiler", cc)
+ }
+
+ dir := t.TempDir()
+
+ writeTempFile := func(name, contents string) {
+ if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ writeTempFile("go.mod", "module cgolto\n")
+
+ switch test {
+ case 0:
+ writeTempFile("main.go", test1_main)
+ writeTempFile("add.go", test1_add)
+ case 1:
+ writeTempFile("main.go", test2_main)
+ default:
+ t.Fatalf("bad case %d", test)
+ }
+
+ cmd := testenv.Command(t, testenv.GoToolPath(t), "build")
+ cmd.Dir = dir
+ cmd.Env = append(os.Environ(),
+ "CC="+cc,
+ "CGO_CFLAGS=-flto",
+ )
+
+ t.Log("go build")
+ out, err := cmd.CombinedOutput()
+ t.Logf("%s", out)
+
+ if err != nil {
+ t.Logf("go build failed: %v", err)
+
+ // Error messages we've seen indicating that LTO is not supported.
+ // These errors come from GCC or clang, not Go.
+ var noLTO = []string{
+ `unrecognized command line option "-flto"`,
+ "unable to pass LLVM bit-code files to linker",
+ "file not recognized: File format not recognized",
+ "LTO support has not been enabled",
+ "linker command failed with exit code",
+ "gcc: can't load library",
+ }
+ for _, msg := range noLTO {
+ if bytes.Contains(out, []byte(msg)) {
+ t.Skipf("C compiler %v does not support LTO", cc)
+ }
+ }
+
+ t.Error("failed")
+ }
+}