blob: 26ab8024541d6cfc66b1b6694e4725779bd0d81a [file] [log] [blame]
// 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 := exec.Command(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")
}
}