Source file
src/cmd/link/cgo_test.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "internal/testenv"
10 "os"
11 "path/filepath"
12 "strconv"
13 "testing"
14 )
15
16
17 func TestCGOLTO(t *testing.T) {
18 testenv.MustHaveCGO(t)
19 testenv.MustHaveGoBuild(t)
20
21 t.Parallel()
22
23 goEnv := func(arg string) string {
24 cmd := testenv.Command(t, testenv.GoToolPath(t), "env", arg)
25 cmd.Stderr = new(bytes.Buffer)
26
27 line, err := cmd.Output()
28 if err != nil {
29 t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr)
30 }
31 out := string(bytes.TrimSpace(line))
32 t.Logf("%v: %q", cmd, out)
33 return out
34 }
35
36 cc := goEnv("CC")
37 cgoCflags := goEnv("CGO_CFLAGS")
38
39 for test := 0; test < 2; test++ {
40 t.Run(strconv.Itoa(test), func(t *testing.T) {
41 testCGOLTO(t, cc, cgoCflags, test)
42 })
43 }
44 }
45
46 const test1_main = `
47 package main
48
49 /*
50 extern int myadd(int, int);
51 int c_add(int a, int b) {
52 return myadd(a, b);
53 }
54 */
55 import "C"
56
57 func main() {
58 println(C.c_add(1, 2))
59 }
60 `
61
62 const test1_add = `
63 package main
64
65 import "C"
66
67 /* test */
68
69 //export myadd
70 func myadd(a C.int, b C.int) C.int {
71 return a + b
72 }
73 `
74
75 const test2_main = `
76 package main
77
78 import "fmt"
79
80 /*
81 #include <stdio.h>
82
83 void hello(void) {
84 printf("hello\n");
85 }
86 */
87 import "C"
88
89 func main() {
90 hello := C.hello
91 fmt.Printf("%v\n", hello)
92 }
93 `
94
95 func testCGOLTO(t *testing.T, cc, cgoCflags string, test int) {
96 t.Parallel()
97
98 dir := t.TempDir()
99
100 writeTempFile := func(name, contents string) {
101 if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
102 t.Fatal(err)
103 }
104 }
105
106 writeTempFile("go.mod", "module cgolto\n")
107
108 switch test {
109 case 0:
110 writeTempFile("main.go", test1_main)
111 writeTempFile("add.go", test1_add)
112 case 1:
113 writeTempFile("main.go", test2_main)
114 default:
115 t.Fatalf("bad case %d", test)
116 }
117
118 cmd := testenv.Command(t, testenv.GoToolPath(t), "build")
119 cmd.Dir = dir
120 cgoCflags += " -flto"
121 cmd.Env = append(cmd.Environ(), "CGO_CFLAGS="+cgoCflags)
122
123 t.Logf("CGO_CFLAGS=%q %v", cgoCflags, cmd)
124 out, err := cmd.CombinedOutput()
125 t.Logf("%s", out)
126
127 if err != nil {
128 t.Logf("go build failed: %v", err)
129
130
131
132 var noLTO = []string{
133 `unrecognized command line option "-flto"`,
134 "unable to pass LLVM bit-code files to linker",
135 "file not recognized: File format not recognized",
136 "LTO support has not been enabled",
137 "linker command failed with exit code",
138 "gcc: can't load library",
139 }
140 for _, msg := range noLTO {
141 if bytes.Contains(out, []byte(msg)) {
142 t.Skipf("C compiler %v does not support LTO", cc)
143 }
144 }
145
146 t.Error("failed")
147 }
148 }
149
View as plain text