Commit a00611f5 authored by Bryan C. Mills's avatar Bryan C. Mills

misc/cgo/testcshared: fix tests in module mode

Updates #30228

Change-Id: Ie9dca7c64be8dff729be98cb6190236287afd23e
Reviewed-on: https://go-review.googlesource.com/c/163213
Run-TryBot: Bryan C. Mills <bcmills@google.com>
Reviewed-by: default avatarJay Conrod <jayconrod@google.com>
parent ffde2ddb
...@@ -5,13 +5,13 @@ ...@@ -5,13 +5,13 @@
package cshared_test package cshared_test
import ( import (
"bytes"
"debug/elf" "debug/elf"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
...@@ -22,9 +22,6 @@ import ( ...@@ -22,9 +22,6 @@ import (
// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)). // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
var cc []string var cc []string
// An environment with GOPATH=$(pwd).
var gopathEnv []string
// ".exe" on Windows. // ".exe" on Windows.
var exeSuffix string var exeSuffix string
...@@ -33,6 +30,12 @@ var installdir, androiddir string ...@@ -33,6 +30,12 @@ var installdir, androiddir string
var libSuffix, libgoname string var libSuffix, libgoname string
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
os.Exit(testMain(m))
}
func testMain(m *testing.M) int {
log.SetFlags(log.Lshortfile)
GOOS = goEnv("GOOS") GOOS = goEnv("GOOS")
GOARCH = goEnv("GOARCH") GOARCH = goEnv("GOARCH")
GOROOT = goEnv("GOROOT") GOROOT = goEnv("GOROOT")
...@@ -41,19 +44,6 @@ func TestMain(m *testing.M) { ...@@ -41,19 +44,6 @@ func TestMain(m *testing.M) {
log.Fatalf("Unable able to find GOROOT at '%s'", GOROOT) log.Fatalf("Unable able to find GOROOT at '%s'", GOROOT)
} }
// Directory where cgo headers and outputs will be installed.
// The installation directory format varies depending on the platform.
installdir = path.Join("pkg", fmt.Sprintf("%s_%s_testcshared", GOOS, GOARCH))
switch GOOS {
case "darwin":
libSuffix = "dylib"
case "windows":
libSuffix = "dll"
default:
libSuffix = "so"
installdir = path.Join("pkg", fmt.Sprintf("%s_%s_testcshared_shared", GOOS, GOARCH))
}
androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid()) androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid())
if GOOS == "android" { if GOOS == "android" {
args := append(adbCmd(), "shell", "mkdir", "-p", androiddir) args := append(adbCmd(), "shell", "mkdir", "-p", androiddir)
...@@ -62,10 +52,9 @@ func TestMain(m *testing.M) { ...@@ -62,10 +52,9 @@ func TestMain(m *testing.M) {
if err != nil { if err != nil {
log.Fatalf("setupAndroid failed: %v\n%s\n", err, out) log.Fatalf("setupAndroid failed: %v\n%s\n", err, out)
} }
defer cleanupAndroid()
} }
libgoname = "libgo." + libSuffix
cc = []string{goEnv("CC")} cc = []string{goEnv("CC")}
out := goEnv("GOGCCFLAGS") out := goEnv("GOGCCFLAGS")
...@@ -120,34 +109,56 @@ func TestMain(m *testing.M) { ...@@ -120,34 +109,56 @@ func TestMain(m *testing.M) {
} }
cc = append(cc, "-I", filepath.Join("pkg", libgodir)) cc = append(cc, "-I", filepath.Join("pkg", libgodir))
// Build an environment with GOPATH=$(pwd)
dir, err := os.Getwd()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
gopathEnv = append(os.Environ(), "GOPATH="+dir)
if GOOS == "windows" { if GOOS == "windows" {
exeSuffix = ".exe" exeSuffix = ".exe"
} }
st := m.Run() // Copy testdata into GOPATH/src/testcshared, along with a go.mod file
// declaring the same path.
GOPATH, err := ioutil.TempDir("", "cshared_test")
if err != nil {
log.Panic(err)
}
defer os.RemoveAll(GOPATH)
os.Setenv("GOPATH", GOPATH)
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file
// declaring the same path.
modRoot := filepath.Join(GOPATH, "src", "testcshared")
if err := overlayDir(modRoot, "testdata"); err != nil {
log.Panic(err)
}
if err := os.Chdir(modRoot); err != nil {
log.Panic(err)
}
if err := ioutil.WriteFile("go.mod", []byte("module testcshared\n"), 0666); err != nil {
log.Panic(err)
}
os.Remove(libgoname) // Directory where cgo headers and outputs will be installed.
os.RemoveAll("pkg") // The installation directory format varies depending on the platform.
cleanupHeaders() output, err := exec.Command("go", "list",
cleanupAndroid() "-buildmode=c-shared",
"-installsuffix", "testcshared",
"-f", "{{.Target}}",
"./libgo").CombinedOutput()
if err != nil {
log.Panicf("go list failed: %v\n%s", err, output)
}
target := string(bytes.TrimSpace(output))
libgoname = filepath.Base(target)
installdir = filepath.Dir(target)
libSuffix = strings.TrimPrefix(filepath.Ext(target), ".")
os.Exit(st) return m.Run()
} }
func goEnv(key string) string { func goEnv(key string) string {
out, err := exec.Command("go", "env", key).Output() out, err := exec.Command("go", "env", key).Output()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err) log.Printf("go env %s failed:\n%s", key, err)
fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr) log.Panicf("%s", err.(*exec.ExitError).Stderr)
os.Exit(2)
} }
return strings.TrimSpace(string(out)) return strings.TrimSpace(string(out))
} }
...@@ -197,10 +208,12 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string { ...@@ -197,10 +208,12 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
return strings.Replace(string(out), "\r", "", -1) return strings.Replace(string(out), "\r", "", -1)
} }
func run(t *testing.T, env []string, args ...string) string { func run(t *testing.T, extraEnv []string, args ...string) string {
t.Helper() t.Helper()
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
cmd.Env = env if len(extraEnv) > 0 {
cmd.Env = append(os.Environ(), extraEnv...)
}
if GOOS != "windows" { if GOOS != "windows" {
// TestUnexportedSymbols relies on file descriptor 30 // TestUnexportedSymbols relies on file descriptor 30
...@@ -220,12 +233,12 @@ func run(t *testing.T, env []string, args ...string) string { ...@@ -220,12 +233,12 @@ func run(t *testing.T, env []string, args ...string) string {
return string(out) return string(out)
} }
func runExe(t *testing.T, env []string, args ...string) string { func runExe(t *testing.T, extraEnv []string, args ...string) string {
t.Helper() t.Helper()
if GOOS == "android" { if GOOS == "android" {
return adbRun(t, env, args...) return adbRun(t, append(os.Environ(), extraEnv...), args...)
} }
return run(t, env, args...) return run(t, extraEnv, args...)
} }
func runCC(t *testing.T, args ...string) string { func runCC(t *testing.T, args ...string) string {
...@@ -237,9 +250,8 @@ func runCC(t *testing.T, args ...string) string { ...@@ -237,9 +250,8 @@ func runCC(t *testing.T, args ...string) string {
func createHeaders() error { func createHeaders() error {
args := []string{"go", "install", "-i", "-buildmode=c-shared", args := []string{"go", "install", "-i", "-buildmode=c-shared",
"-installsuffix", "testcshared", "libgo"} "-installsuffix", "testcshared", "./libgo"}
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
cmd.Env = gopathEnv
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out) return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
...@@ -248,9 +260,8 @@ func createHeaders() error { ...@@ -248,9 +260,8 @@ func createHeaders() error {
args = []string{"go", "build", "-buildmode=c-shared", args = []string{"go", "build", "-buildmode=c-shared",
"-installsuffix", "testcshared", "-installsuffix", "testcshared",
"-o", libgoname, "-o", libgoname,
filepath.Join("src", "libgo", "libgo.go")} filepath.Join(".", "libgo", "libgo.go")}
cmd = exec.Command(args[0], args[1:]...) cmd = exec.Command(args[0], args[1:]...)
cmd.Env = gopathEnv
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out) return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
...@@ -282,10 +293,6 @@ func createHeadersOnce(t *testing.T) { ...@@ -282,10 +293,6 @@ func createHeadersOnce(t *testing.T) {
} }
} }
func cleanupHeaders() {
os.Remove("libgo.h")
}
func cleanupAndroid() { func cleanupAndroid() {
if GOOS != "android" { if GOOS != "android" {
return return
...@@ -294,7 +301,7 @@ func cleanupAndroid() { ...@@ -294,7 +301,7 @@ func cleanupAndroid() {
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
log.Fatalf("cleanupAndroid failed: %v\n%s\n", err, out) log.Panicf("cleanupAndroid failed: %v\n%s\n", err, out)
} }
} }
...@@ -312,7 +319,7 @@ func TestExportedSymbols(t *testing.T) { ...@@ -312,7 +319,7 @@ func TestExportedSymbols(t *testing.T) {
defer os.Remove(bin) defer os.Remove(bin)
out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin) out := runExe(t, []string{"LD_LIBRARY_PATH=."}, bin)
if strings.TrimSpace(out) != "PASS" { if strings.TrimSpace(out) != "PASS" {
t.Error(out) t.Error(out)
} }
...@@ -361,11 +368,11 @@ func TestUnexportedSymbols(t *testing.T) { ...@@ -361,11 +368,11 @@ func TestUnexportedSymbols(t *testing.T) {
libname := "libgo2." + libSuffix libname := "libgo2." + libSuffix
run(t, run(t,
gopathEnv, nil,
"go", "build", "go", "build",
"-buildmode=c-shared", "-buildmode=c-shared",
"-installsuffix", "testcshared", "-installsuffix", "testcshared",
"-o", libname, "libgo2", "-o", libname, "./libgo2",
) )
adbPush(t, libname) adbPush(t, libname)
...@@ -380,7 +387,7 @@ func TestUnexportedSymbols(t *testing.T) { ...@@ -380,7 +387,7 @@ func TestUnexportedSymbols(t *testing.T) {
defer os.Remove(libname) defer os.Remove(libname)
defer os.Remove(bin) defer os.Remove(bin)
out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin) out := runExe(t, []string{"LD_LIBRARY_PATH=."}, bin)
if strings.TrimSpace(out) != "PASS" { if strings.TrimSpace(out) != "PASS" {
t.Error(out) t.Error(out)
...@@ -418,7 +425,7 @@ func TestMainExportedOnAndroid(t *testing.T) { ...@@ -418,7 +425,7 @@ func TestMainExportedOnAndroid(t *testing.T) {
func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) { func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) {
libname := pkgname + "." + libSuffix libname := pkgname + "." + libSuffix
run(t, run(t,
gopathEnv, nil,
"go", "build", "go", "build",
"-buildmode=c-shared", "-buildmode=c-shared",
"-installsuffix", "testcshared", "-installsuffix", "testcshared",
...@@ -451,7 +458,7 @@ func TestSignalHandlers(t *testing.T) { ...@@ -451,7 +458,7 @@ func TestSignalHandlers(t *testing.T) {
t.Logf("Skipping on %s", GOOS) t.Logf("Skipping on %s", GOOS)
return return
} }
testSignalHandlers(t, "libgo4", "main4.c", "testp4") testSignalHandlers(t, "./libgo4", "main4.c", "testp4")
} }
// test5: test signal handlers with os/signal.Notify // test5: test signal handlers with os/signal.Notify
...@@ -461,7 +468,7 @@ func TestSignalHandlersWithNotify(t *testing.T) { ...@@ -461,7 +468,7 @@ func TestSignalHandlersWithNotify(t *testing.T) {
t.Logf("Skipping on %s", GOOS) t.Logf("Skipping on %s", GOOS)
return return
} }
testSignalHandlers(t, "libgo5", "main5.c", "testp5") testSignalHandlers(t, "./libgo5", "main5.c", "testp5")
} }
func TestPIE(t *testing.T) { func TestPIE(t *testing.T) {
...@@ -515,14 +522,16 @@ func TestCachedInstall(t *testing.T) { ...@@ -515,14 +522,16 @@ func TestCachedInstall(t *testing.T) {
} }
// defer os.RemoveAll(tmpdir) // defer os.RemoveAll(tmpdir)
copyFile(t, filepath.Join(tmpdir, "src", "libgo", "libgo.go"), filepath.Join("src", "libgo", "libgo.go")) copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "go.mod"), "go.mod")
copyFile(t, filepath.Join(tmpdir, "src", "p", "p.go"), filepath.Join("src", "p", "p.go")) copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "libgo", "libgo.go"), filepath.Join("libgo", "libgo.go"))
copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "p", "p.go"), filepath.Join("p", "p.go"))
env := append(os.Environ(), "GOPATH="+tmpdir) env := append(os.Environ(), "GOPATH="+tmpdir, "GOBIN="+filepath.Join(tmpdir, "bin"))
buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "libgo"} buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "./libgo"}
cmd := exec.Command(buildcmd[0], buildcmd[1:]...) cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
cmd.Env = env cmd.Env = env
t.Log(buildcmd) t.Log(buildcmd)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
...@@ -572,6 +581,7 @@ func TestCachedInstall(t *testing.T) { ...@@ -572,6 +581,7 @@ func TestCachedInstall(t *testing.T) {
} }
cmd = exec.Command(buildcmd[0], buildcmd[1:]...) cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
cmd.Env = env cmd.Env = env
t.Log(buildcmd) t.Log(buildcmd)
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
...@@ -621,8 +631,8 @@ func TestGo2C2Go(t *testing.T) { ...@@ -621,8 +631,8 @@ func TestGo2C2Go(t *testing.T) {
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
shlib := filepath.Join(tmpdir, "libtestgo2c2go."+libSuffix) lib := filepath.Join(tmpdir, "libtestgo2c2go."+libSuffix)
run(t, gopathEnv, "go", "build", "-buildmode=c-shared", "-o", shlib, "go2c2go/go") run(t, nil, "go", "build", "-buildmode=c-shared", "-o", lib, "./go2c2go/go")
cgoCflags := os.Getenv("CGO_CFLAGS") cgoCflags := os.Getenv("CGO_CFLAGS")
if cgoCflags != "" { if cgoCflags != "" {
...@@ -636,7 +646,7 @@ func TestGo2C2Go(t *testing.T) { ...@@ -636,7 +646,7 @@ func TestGo2C2Go(t *testing.T) {
} }
cgoLdflags += "-L" + tmpdir + " -ltestgo2c2go" cgoLdflags += "-L" + tmpdir + " -ltestgo2c2go"
goenv := append(gopathEnv[:len(gopathEnv):len(gopathEnv)], "CGO_CFLAGS="+cgoCflags, "CGO_LDFLAGS="+cgoLdflags) goenv := []string{"CGO_CFLAGS=" + cgoCflags, "CGO_LDFLAGS=" + cgoLdflags}
ldLibPath := os.Getenv("LD_LIBRARY_PATH") ldLibPath := os.Getenv("LD_LIBRARY_PATH")
if ldLibPath != "" { if ldLibPath != "" {
...@@ -644,13 +654,13 @@ func TestGo2C2Go(t *testing.T) { ...@@ -644,13 +654,13 @@ func TestGo2C2Go(t *testing.T) {
} }
ldLibPath += tmpdir ldLibPath += tmpdir
runenv := append(gopathEnv[:len(gopathEnv):len(gopathEnv)], "LD_LIBRARY_PATH="+ldLibPath) runenv := []string{"LD_LIBRARY_PATH=" + ldLibPath}
bin := filepath.Join(tmpdir, "m1") + exeSuffix bin := filepath.Join(tmpdir, "m1") + exeSuffix
run(t, goenv, "go", "build", "-o", bin, "go2c2go/m1") run(t, goenv, "go", "build", "-o", bin, "./go2c2go/m1")
runExe(t, runenv, bin) runExe(t, runenv, bin)
bin = filepath.Join(tmpdir, "m2") + exeSuffix bin = filepath.Join(tmpdir, "m2") + exeSuffix
run(t, goenv, "go", "build", "-o", bin, "go2c2go/m2") run(t, goenv, "go", "build", "-o", bin, "./go2c2go/m2")
runExe(t, runenv, bin) runExe(t, runenv, bin)
} }
// Copyright 2019 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 cshared_test
import (
"io"
"os"
"path/filepath"
"strings"
)
// overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added.
//
// TODO: Once we no longer need to support the misc module in GOPATH mode,
// factor this function out into a package to reduce duplication.
func overlayDir(dstRoot, srcRoot string) error {
dstRoot = filepath.Clean(dstRoot)
if err := os.MkdirAll(dstRoot, 0777); err != nil {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
if err != nil || srcPath == srcRoot {
return err
}
suffix := strings.TrimPrefix(srcPath, srcRoot)
for len(suffix) > 0 && suffix[0] == filepath.Separator {
suffix = suffix[1:]
}
dstPath := filepath.Join(dstRoot, suffix)
perm := info.Mode() & os.ModePerm
if info.Mode()&os.ModeSymlink != 0 {
info, err = os.Stat(srcPath)
if err != nil {
return err
}
perm = info.Mode() & os.ModePerm
}
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
return nil
}
// Otherwise, copy the bytes.
src, err := os.Open(srcPath)
if err != nil {
return err
}
defer src.Close()
dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
if err != nil {
return err
}
_, err = io.Copy(dst, src)
if closeErr := dst.Close(); err == nil {
err = closeErr
}
return err
})
}
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
package main package main
import ( import (
_ "p"
"syscall" "syscall"
_ "testcshared/p"
"time" "time"
) )
......
...@@ -695,7 +695,7 @@ func (t *tester) registerTests() { ...@@ -695,7 +695,7 @@ func (t *tester) registerTests() {
t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".") t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".")
} }
if t.supportedBuildmode("c-shared") { if t.supportedBuildmode("c-shared") {
t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", "cshared_test.go") t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
} }
if t.supportedBuildmode("shared") { if t.supportedBuildmode("shared") {
t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600)) t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment