2016-04-10 15:32:26 -06:00
|
|
|
// Copyright 2016 The Go Authors. All rights reserved.
|
2016-03-22 19:17:43 -06:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package carchive_test
|
|
|
|
|
|
|
|
import (
|
2016-03-22 21:11:42 -06:00
|
|
|
"bufio"
|
2017-10-11 14:02:59 -06:00
|
|
|
"bytes"
|
2016-06-16 13:59:09 -06:00
|
|
|
"debug/elf"
|
2016-03-22 19:17:43 -06:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2018-04-19 13:56:29 -06:00
|
|
|
"regexp"
|
2017-02-24 16:46:40 -07:00
|
|
|
"runtime"
|
2016-03-22 19:17:43 -06:00
|
|
|
"strings"
|
2016-03-22 21:11:42 -06:00
|
|
|
"syscall"
|
2016-03-22 19:17:43 -06:00
|
|
|
"testing"
|
2016-03-25 16:57:25 -06:00
|
|
|
"time"
|
2016-03-22 19:17:43 -06:00
|
|
|
"unicode"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Program to run.
|
|
|
|
var bin []string
|
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
|
2016-03-22 19:17:43 -06:00
|
|
|
var cc []string
|
|
|
|
|
|
|
|
// An environment with GOPATH=$(pwd).
|
|
|
|
var gopathEnv []string
|
|
|
|
|
|
|
|
// ".exe" on Windows.
|
|
|
|
var exeSuffix string
|
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
var GOOS, GOARCH string
|
2016-04-27 16:03:49 -06:00
|
|
|
var libgodir string
|
2016-03-24 14:47:02 -06:00
|
|
|
|
2016-03-22 19:17:43 -06:00
|
|
|
func init() {
|
2016-03-24 14:47:02 -06:00
|
|
|
GOOS = goEnv("GOOS")
|
|
|
|
GOARCH = goEnv("GOARCH")
|
2016-10-14 00:03:01 -06:00
|
|
|
bin = cmdToRun("./testp")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
ccOut := goEnv("CC")
|
|
|
|
cc = []string{string(ccOut)}
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
out := goEnv("GOGCCFLAGS")
|
2016-03-22 19:17:43 -06:00
|
|
|
quote := '\000'
|
|
|
|
start := 0
|
|
|
|
lastSpace := true
|
|
|
|
backslash := false
|
|
|
|
s := string(out)
|
|
|
|
for i, c := range s {
|
|
|
|
if quote == '\000' && unicode.IsSpace(c) {
|
|
|
|
if !lastSpace {
|
|
|
|
cc = append(cc, s[start:i])
|
|
|
|
lastSpace = true
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if lastSpace {
|
|
|
|
start = i
|
|
|
|
lastSpace = false
|
|
|
|
}
|
|
|
|
if quote == '\000' && !backslash && (c == '"' || c == '\'') {
|
|
|
|
quote = c
|
|
|
|
backslash = false
|
|
|
|
} else if !backslash && quote == c {
|
|
|
|
quote = '\000'
|
|
|
|
} else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
|
|
|
|
backslash = true
|
|
|
|
} else {
|
|
|
|
backslash = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !lastSpace {
|
|
|
|
cc = append(cc, s[start:])
|
|
|
|
}
|
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
if GOOS == "darwin" {
|
2016-03-22 19:17:43 -06:00
|
|
|
// For Darwin/ARM.
|
|
|
|
// TODO(crawshaw): can we do better?
|
|
|
|
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
|
|
|
|
}
|
2016-04-27 16:03:49 -06:00
|
|
|
libgodir = GOOS + "_" + GOARCH
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
libgodir = "gccgo_" + libgodir + "_fPIC"
|
|
|
|
} else {
|
|
|
|
switch GOOS {
|
|
|
|
case "darwin":
|
|
|
|
if GOARCH == "arm" || GOARCH == "arm64" {
|
|
|
|
libgodir += "_shared"
|
|
|
|
}
|
|
|
|
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
|
2016-06-16 13:59:09 -06:00
|
|
|
libgodir += "_shared"
|
|
|
|
}
|
2016-04-27 16:03:49 -06:00
|
|
|
}
|
|
|
|
cc = append(cc, "-I", filepath.Join("pkg", libgodir))
|
2016-03-22 19:17:43 -06:00
|
|
|
|
|
|
|
// Build an environment with GOPATH=$(pwd)
|
|
|
|
env := os.Environ()
|
|
|
|
var n []string
|
|
|
|
for _, e := range env {
|
|
|
|
if !strings.HasPrefix(e, "GOPATH=") {
|
|
|
|
n = append(n, e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dir, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
n = append(n, "GOPATH="+dir)
|
|
|
|
gopathEnv = n
|
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
if GOOS == "windows" {
|
2016-03-22 19:17:43 -06:00
|
|
|
exeSuffix = ".exe"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 14:47:02 -06:00
|
|
|
func goEnv(key string) string {
|
|
|
|
out, err := exec.Command("go", "env", key).Output()
|
|
|
|
if err != nil {
|
2017-05-24 15:59:22 -06:00
|
|
|
fmt.Fprintf(os.Stderr, "go env %s failed:\n%s\n", key, err)
|
|
|
|
if ee, ok := err.(*exec.ExitError); ok {
|
|
|
|
fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
|
|
|
|
}
|
2016-03-24 14:47:02 -06:00
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(string(out))
|
|
|
|
}
|
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
func cmdToRun(name string) []string {
|
|
|
|
execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
|
|
|
|
executor, err := exec.LookPath(execScript)
|
|
|
|
if err != nil {
|
|
|
|
return []string{name}
|
2016-03-24 15:50:21 -06:00
|
|
|
}
|
2016-10-14 00:03:01 -06:00
|
|
|
return []string{executor, name}
|
2016-03-24 15:50:21 -06:00
|
|
|
}
|
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
|
2017-10-09 19:07:32 -06:00
|
|
|
t.Helper()
|
2016-10-14 00:03:01 -06:00
|
|
|
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
2016-03-22 19:17:43 -06:00
|
|
|
cmd.Env = gopathEnv
|
2017-10-09 19:07:32 -06:00
|
|
|
t.Log(buildcmd)
|
2016-03-22 19:17:43 -06:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-10-14 00:03:01 -06:00
|
|
|
defer func() {
|
|
|
|
os.Remove(libgoa)
|
|
|
|
os.Remove(libgoh)
|
|
|
|
}()
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
ccArgs := append(cc, "-o", exe, "main.c")
|
|
|
|
if GOOS == "windows" {
|
|
|
|
ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
|
|
|
|
} else {
|
|
|
|
ccArgs = append(ccArgs, "main_unix.c", libgoa)
|
2016-03-22 19:17:43 -06:00
|
|
|
}
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-10-14 00:03:01 -06:00
|
|
|
t.Log(ccArgs)
|
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
2016-03-22 19:17:43 -06:00
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-10-14 00:03:01 -06:00
|
|
|
defer os.Remove(exe)
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
binArgs := append(cmdToRun(exe), "arg1", "arg2")
|
2017-02-24 16:46:40 -07:00
|
|
|
cmd = exec.Command(binArgs[0], binArgs[1:]...)
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
cmd.Env = append(os.Environ(), "GCCGO=1")
|
|
|
|
}
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2016-03-22 19:17:43 -06:00
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
|
|
|
|
checkLineComments(t, libgoh)
|
|
|
|
}
|
|
|
|
|
|
|
|
var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
|
|
|
|
|
|
|
|
// checkLineComments checks that the export header generated by
|
|
|
|
// -buildmode=c-archive doesn't have any absolute paths in the #line
|
|
|
|
// comments. We don't want those paths because they are unhelpful for
|
|
|
|
// the user and make the files change based on details of the location
|
|
|
|
// of GOPATH.
|
|
|
|
func checkLineComments(t *testing.T, hdrname string) {
|
|
|
|
hdr, err := ioutil.ReadFile(hdrname)
|
|
|
|
if err != nil {
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if line := badLineRegexp.Find(hdr); line != nil {
|
|
|
|
t.Errorf("bad #line directive with absolute path in %s: %q", hdrname, line)
|
|
|
|
}
|
2016-10-14 00:03:01 -06:00
|
|
|
}
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
func TestInstall(t *testing.T) {
|
|
|
|
defer os.RemoveAll("pkg")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2017-02-24 16:46:40 -07:00
|
|
|
libgoa := "libgo.a"
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
libgoa = "liblibgo.a"
|
|
|
|
}
|
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
testInstall(t, "./testp1"+exeSuffix,
|
2017-02-24 16:46:40 -07:00
|
|
|
filepath.Join("pkg", libgodir, libgoa),
|
2016-10-14 00:03:01 -06:00
|
|
|
filepath.Join("pkg", libgodir, "libgo.h"),
|
cmd/go: do not install dependencies during "go install"
This CL makes "go install" behave the way many users expect:
install only the things named on the command line.
Future builds still run as fast, thanks to the new build cache (CL 75473).
To install dependencies as well (the old behavior), use "go install -i".
Actual definitions aside, what most users know and expect of "go install"
is that (1) it installs what you asked, and (2) it's fast, unlike "go build".
It was fast because it installed dependencies, but installing dependencies
confused users repeatedly (see for example #5065, #6424, #10998, #12329,
"go build" and "go test" so that they could be "fast" too, but that only
created new opportunities for confusion. We also had to add -installsuffix
and then -pkgdir, to allow "fast" even when dependencies could not be
installed in the usual place.
The recent introduction of precise content-based staleness logic means that
the go command detects the need for rebuilding packages more often than it
used to, with the consequence that "go install" rebuilds and reinstalls
dependencies more than it used to. This will create more new opportunities
for confusion and will certainly lead to more issues filed like the ones
listed above.
CL 75743 introduced a build cache, separate from the install locations.
That cache makes all operations equally incremental and fast, whether or
not the operation is "install" or "build", and whether or not "-i" is used.
Installing dependencies is no longer necessary for speed, it has confused
users in the past, and the more accurate rebuilds mean that it will confuse
users even more often in the future. This CL aims to end all that confusion
by not installing dependencies by default.
By analogy with "go build -i" and "go test -i", which still install
dependencies, this CL introduces "go install -i", which installs
dependencies in addition to the things named on the command line.
Fixes #5065.
Fixes #6424.
Fixes #10998.
Fixes #12329.
Fixes #18981.
Fixes #22469.
Another step toward #4719.
Change-Id: I3d7bc145c3a680e2f26416e182fa0dcf1e2a15e5
Reviewed-on: https://go-review.googlesource.com/75850
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-11-02 23:24:19 -06:00
|
|
|
"go", "install", "-i", "-buildmode=c-archive", "libgo")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
// Test building libgo other than installing it.
|
|
|
|
// Header files are now present.
|
|
|
|
testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
|
|
|
|
"go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
|
2016-03-22 19:17:43 -06:00
|
|
|
|
2016-10-14 00:03:01 -06:00
|
|
|
testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
|
|
|
|
"go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
|
2016-03-22 19:17:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestEarlySignalHandler(t *testing.T) {
|
2016-03-24 14:47:02 -06:00
|
|
|
switch GOOS {
|
2016-03-22 19:17:43 -06:00
|
|
|
case "darwin":
|
2016-03-24 14:47:02 -06:00
|
|
|
switch GOARCH {
|
2016-03-22 19:17:43 -06:00
|
|
|
case "arm", "arm64":
|
2016-03-24 14:47:02 -06:00
|
|
|
t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
|
2016-03-22 19:17:43 -06:00
|
|
|
}
|
|
|
|
case "windows":
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo2.a")
|
|
|
|
os.Remove("libgo2.h")
|
|
|
|
os.Remove("testp")
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-03-22 19:17:43 -06:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-22 21:11:42 -06:00
|
|
|
func TestSignalForwarding(t *testing.T) {
|
2017-05-09 15:34:16 -06:00
|
|
|
checkSignalForwardingTest(t)
|
2016-03-22 21:11:42 -06:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo2.a")
|
|
|
|
os.Remove("libgo2.h")
|
|
|
|
os.Remove("testp")
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2016-03-22 21:11:42 -06:00
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-03-22 21:11:42 -06:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = exec.Command(bin[0], append(bin[1:], "1")...)
|
|
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
2017-05-09 15:34:16 -06:00
|
|
|
t.Logf("%s", out)
|
|
|
|
expectSignal(t, err, syscall.SIGSEGV)
|
2017-01-29 07:34:50 -07:00
|
|
|
|
|
|
|
// Test SIGPIPE forwarding
|
|
|
|
cmd = exec.Command(bin[0], append(bin[1:], "3")...)
|
|
|
|
|
|
|
|
out, err = cmd.CombinedOutput()
|
2017-05-09 15:34:16 -06:00
|
|
|
t.Logf("%s", out)
|
|
|
|
expectSignal(t, err, syscall.SIGPIPE)
|
2016-03-22 21:11:42 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSignalForwardingExternal(t *testing.T) {
|
2018-02-13 20:00:17 -07:00
|
|
|
if GOOS == "freebsd" {
|
|
|
|
t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
|
|
|
|
}
|
2017-05-09 15:34:16 -06:00
|
|
|
checkSignalForwardingTest(t)
|
2016-03-22 21:11:42 -06:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo2.a")
|
|
|
|
os.Remove("libgo2.h")
|
|
|
|
os.Remove("testp")
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2016-03-22 21:11:42 -06:00
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-03-22 21:11:42 -06:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
// We want to send the process a signal and see if it dies.
|
|
|
|
// Normally the signal goes to the C thread, the Go signal
|
|
|
|
// handler picks it up, sees that it is running in a C thread,
|
|
|
|
// and the program dies. Unfortunately, occasionally the
|
|
|
|
// signal is delivered to a Go thread, which winds up
|
|
|
|
// discarding it because it was sent by another program and
|
|
|
|
// there is no Go handler for it. To avoid this, run the
|
|
|
|
// program several times in the hopes that it will eventually
|
|
|
|
// fail.
|
|
|
|
const tries = 20
|
|
|
|
for i := 0; i < tries; i++ {
|
|
|
|
cmd = exec.Command(bin[0], append(bin[1:], "2")...)
|
|
|
|
|
|
|
|
stderr, err := cmd.StderrPipe()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer stderr.Close()
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
r := bufio.NewReader(stderr)
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
err = cmd.Start()
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
// Wait for trigger to ensure that the process is started.
|
|
|
|
ok, err := r.ReadString('\n')
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
// Verify trigger.
|
|
|
|
if err != nil || ok != "OK\n" {
|
|
|
|
t.Fatalf("Did not receive OK signal")
|
|
|
|
}
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
// Give the program a chance to enter the sleep function.
|
|
|
|
time.Sleep(time.Millisecond)
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
cmd.Process.Signal(syscall.SIGSEGV)
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
err = cmd.Wait()
|
2016-03-22 21:11:42 -06:00
|
|
|
|
2016-03-25 16:57:25 -06:00
|
|
|
if err == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2017-05-09 15:34:16 -06:00
|
|
|
if expectSignal(t, err, syscall.SIGSEGV) {
|
2016-03-25 16:57:25 -06:00
|
|
|
return
|
|
|
|
}
|
2016-03-22 21:11:42 -06:00
|
|
|
}
|
2016-03-25 16:57:25 -06:00
|
|
|
|
|
|
|
t.Errorf("program succeeded unexpectedly %d times", tries)
|
2016-03-22 21:11:42 -06:00
|
|
|
}
|
|
|
|
|
2017-05-09 15:34:16 -06:00
|
|
|
// checkSignalForwardingTest calls t.Skip if the SignalForwarding test
|
|
|
|
// doesn't work on this platform.
|
|
|
|
func checkSignalForwardingTest(t *testing.T) {
|
|
|
|
switch GOOS {
|
|
|
|
case "darwin":
|
|
|
|
switch GOARCH {
|
|
|
|
case "arm", "arm64":
|
|
|
|
t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
|
|
|
|
}
|
|
|
|
case "windows":
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// expectSignal checks that err, the exit status of a test program,
|
|
|
|
// shows a failure due to a specific signal. Returns whether we found
|
|
|
|
// the expected signal.
|
|
|
|
func expectSignal(t *testing.T, err error, sig syscall.Signal) bool {
|
|
|
|
if err == nil {
|
|
|
|
t.Error("test program succeeded unexpectedly")
|
|
|
|
} else if ee, ok := err.(*exec.ExitError); !ok {
|
|
|
|
t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
|
|
|
|
} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
|
|
|
|
t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
|
|
|
|
} else if !ws.Signaled() || ws.Signal() != sig {
|
|
|
|
t.Errorf("got %v; expected signal %v", ee, sig)
|
|
|
|
} else {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2016-03-22 19:17:43 -06:00
|
|
|
func TestOsSignal(t *testing.T) {
|
2016-03-24 14:47:02 -06:00
|
|
|
switch GOOS {
|
2016-03-22 19:17:43 -06:00
|
|
|
case "windows":
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo3.a")
|
|
|
|
os.Remove("libgo3.h")
|
|
|
|
os.Remove("testp")
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo3.h")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-03-22 19:17:43 -06:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSigaltstack(t *testing.T) {
|
2016-03-24 14:47:02 -06:00
|
|
|
switch GOOS {
|
2016-03-22 19:17:43 -06:00
|
|
|
case "windows":
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo4.a")
|
|
|
|
os.Remove("libgo4.h")
|
|
|
|
os.Remove("testp")
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo4.h")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-03-22 19:17:43 -06:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const testar = `#!/usr/bin/env bash
|
2018-02-13 20:00:17 -07:00
|
|
|
while [[ $1 == -* ]] >/dev/null; do
|
2016-03-22 19:17:43 -06:00
|
|
|
shift
|
|
|
|
done
|
|
|
|
echo "testar" > $1
|
|
|
|
echo "testar" > PWD/testar.ran
|
|
|
|
`
|
|
|
|
|
|
|
|
func TestExtar(t *testing.T) {
|
2016-03-24 14:47:02 -06:00
|
|
|
switch GOOS {
|
2016-03-22 19:17:43 -06:00
|
|
|
case "windows":
|
|
|
|
t.Skip("skipping signal test on Windows")
|
|
|
|
}
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
t.Skip("skipping -extar test when using gccgo")
|
|
|
|
}
|
2016-03-22 19:17:43 -06:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo4.a")
|
|
|
|
os.Remove("libgo4.h")
|
|
|
|
os.Remove("testar")
|
|
|
|
os.Remove("testar.ran")
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
|
|
|
os.Remove("testar")
|
|
|
|
dir, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
s := strings.Replace(testar, "PWD", dir, 1)
|
|
|
|
if err := ioutil.WriteFile("testar", []byte(s), 0777); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "libgo4")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo4.h")
|
2016-03-22 19:17:43 -06:00
|
|
|
|
|
|
|
if _, err := os.Stat("testar.ran"); err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
t.Error("testar does not exist after go build")
|
|
|
|
} else {
|
|
|
|
t.Errorf("error checking testar: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-16 13:59:09 -06:00
|
|
|
|
|
|
|
func TestPIE(t *testing.T) {
|
|
|
|
switch GOOS {
|
|
|
|
case "windows", "darwin", "plan9":
|
|
|
|
t.Skipf("skipping PIE test on %s", GOOS)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("testp" + exeSuffix)
|
|
|
|
os.RemoveAll("pkg")
|
|
|
|
}()
|
|
|
|
|
cmd/go: do not install dependencies during "go install"
This CL makes "go install" behave the way many users expect:
install only the things named on the command line.
Future builds still run as fast, thanks to the new build cache (CL 75473).
To install dependencies as well (the old behavior), use "go install -i".
Actual definitions aside, what most users know and expect of "go install"
is that (1) it installs what you asked, and (2) it's fast, unlike "go build".
It was fast because it installed dependencies, but installing dependencies
confused users repeatedly (see for example #5065, #6424, #10998, #12329,
"go build" and "go test" so that they could be "fast" too, but that only
created new opportunities for confusion. We also had to add -installsuffix
and then -pkgdir, to allow "fast" even when dependencies could not be
installed in the usual place.
The recent introduction of precise content-based staleness logic means that
the go command detects the need for rebuilding packages more often than it
used to, with the consequence that "go install" rebuilds and reinstalls
dependencies more than it used to. This will create more new opportunities
for confusion and will certainly lead to more issues filed like the ones
listed above.
CL 75743 introduced a build cache, separate from the install locations.
That cache makes all operations equally incremental and fast, whether or
not the operation is "install" or "build", and whether or not "-i" is used.
Installing dependencies is no longer necessary for speed, it has confused
users in the past, and the more accurate rebuilds mean that it will confuse
users even more often in the future. This CL aims to end all that confusion
by not installing dependencies by default.
By analogy with "go build -i" and "go test -i", which still install
dependencies, this CL introduces "go install -i", which installs
dependencies in addition to the things named on the command line.
Fixes #5065.
Fixes #6424.
Fixes #10998.
Fixes #12329.
Fixes #18981.
Fixes #22469.
Another step toward #4719.
Change-Id: I3d7bc145c3a680e2f26416e182fa0dcf1e2a15e5
Reviewed-on: https://go-review.googlesource.com/75850
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-11-02 23:24:19 -06:00
|
|
|
cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "libgo")
|
2016-06-16 13:59:09 -06:00
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-02-24 16:46:40 -07:00
|
|
|
libgoa := "libgo.a"
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
libgoa = "liblibgo.a"
|
|
|
|
}
|
|
|
|
|
|
|
|
ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, libgoa))
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-06-16 13:59:09 -06:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
binArgs := append(bin, "arg1", "arg2")
|
2017-02-24 16:46:40 -07:00
|
|
|
cmd = exec.Command(binArgs[0], binArgs[1:]...)
|
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
cmd.Env = append(os.Environ(), "GCCGO=1")
|
|
|
|
}
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2016-06-16 13:59:09 -06:00
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err := elf.Open("testp" + exeSuffix)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("elf.Open failed: ", err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
if hasDynTag(t, f, elf.DT_TEXTREL) {
|
|
|
|
t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
|
|
|
|
ds := f.SectionByType(elf.SHT_DYNAMIC)
|
|
|
|
if ds == nil {
|
|
|
|
t.Error("no SHT_DYNAMIC section")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d, err := ds.Data()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for len(d) > 0 {
|
|
|
|
var t elf.DynTag
|
|
|
|
switch f.Class {
|
|
|
|
case elf.ELFCLASS32:
|
|
|
|
t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
|
|
|
|
d = d[8:]
|
|
|
|
case elf.ELFCLASS64:
|
|
|
|
t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
|
|
|
|
d = d[16:]
|
|
|
|
}
|
|
|
|
if t == tag {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2016-12-06 21:54:41 -07:00
|
|
|
|
|
|
|
func TestSIGPROF(t *testing.T) {
|
|
|
|
switch GOOS {
|
|
|
|
case "windows", "plan9":
|
|
|
|
t.Skipf("skipping SIGPROF test on %s", GOOS)
|
2017-10-08 08:53:18 -06:00
|
|
|
case "darwin":
|
|
|
|
t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS)
|
2016-12-06 21:54:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("testp6" + exeSuffix)
|
|
|
|
os.Remove("libgo6.a")
|
|
|
|
os.Remove("libgo6.h")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "libgo6")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo6.h")
|
2016-12-06 21:54:41 -07:00
|
|
|
|
|
|
|
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2016-12-06 21:54:41 -07:00
|
|
|
if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
argv := cmdToRun("./testp6")
|
|
|
|
cmd = exec.Command(argv[0], argv[1:]...)
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2017-05-09 15:34:16 -06:00
|
|
|
|
|
|
|
// TestCompileWithoutShared tests that if we compile code without the
|
|
|
|
// -shared option, we can put it into an archive. When we use the go
|
|
|
|
// tool with -buildmode=c-archive, it passes -shared to the compiler,
|
|
|
|
// so we override that. The go tool doesn't work this way, but Bazel
|
|
|
|
// will likely do it in the future. And it ought to work. This test
|
|
|
|
// was added because at one time it did not work on PPC GNU/Linux.
|
|
|
|
func TestCompileWithoutShared(t *testing.T) {
|
|
|
|
// For simplicity, reuse the signal forwarding test.
|
|
|
|
checkSignalForwardingTest(t)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
os.Remove("libgo2.a")
|
|
|
|
os.Remove("libgo2.h")
|
|
|
|
}()
|
|
|
|
|
|
|
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "libgo2")
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
t.Log(cmd.Args)
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
t.Logf("%s", out)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 13:56:29 -06:00
|
|
|
checkLineComments(t, "libgo2.h")
|
2017-05-09 15:34:16 -06:00
|
|
|
|
|
|
|
exe := "./testnoshared" + exeSuffix
|
2017-10-11 14:02:59 -06:00
|
|
|
|
|
|
|
// In some cases, -no-pie is needed here, but not accepted everywhere. First try
|
|
|
|
// if -no-pie is accepted. See #22126.
|
|
|
|
ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a")
|
2017-02-24 16:46:40 -07:00
|
|
|
if runtime.Compiler == "gccgo" {
|
|
|
|
ccArgs = append(ccArgs, "-lgo")
|
|
|
|
}
|
2017-05-09 15:34:16 -06:00
|
|
|
t.Log(ccArgs)
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
2017-10-11 14:02:59 -06:00
|
|
|
|
|
|
|
// If -no-pie unrecognized, try -nopie if this is possibly clang
|
|
|
|
if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
|
|
|
|
ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
|
|
|
|
t.Log(ccArgs)
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't use either -no-pie or -nopie
|
|
|
|
if err != nil && bytes.Contains(out, []byte("unrecognized")) {
|
|
|
|
ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
|
|
|
|
t.Log(ccArgs)
|
|
|
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
|
|
}
|
2017-05-09 15:34:16 -06:00
|
|
|
t.Logf("%s", out)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.Remove(exe)
|
|
|
|
|
|
|
|
binArgs := append(cmdToRun(exe), "3")
|
|
|
|
t.Log(binArgs)
|
|
|
|
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
|
|
|
|
t.Logf("%s", out)
|
|
|
|
expectSignal(t, err, syscall.SIGPIPE)
|
|
|
|
}
|
2018-01-10 18:48:37 -07:00
|
|
|
|
|
|
|
// Test that installing a second time recreates the header files.
|
|
|
|
func TestCachedInstall(t *testing.T) {
|
|
|
|
defer os.RemoveAll("pkg")
|
|
|
|
|
|
|
|
h1 := filepath.Join("pkg", libgodir, "libgo.h")
|
|
|
|
h2 := filepath.Join("pkg", libgodir, "p.h")
|
|
|
|
|
|
|
|
buildcmd := []string{"go", "install", "-i", "-buildmode=c-archive", "libgo"}
|
|
|
|
|
|
|
|
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
t.Log(buildcmd)
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := os.Stat(h1); err != nil {
|
|
|
|
t.Errorf("libgo.h not installed: %v", err)
|
|
|
|
}
|
|
|
|
if _, err := os.Stat(h2); err != nil {
|
|
|
|
t.Errorf("p.h not installed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := os.Remove(h1); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := os.Remove(h2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
|
|
|
|
cmd.Env = gopathEnv
|
|
|
|
t.Log(buildcmd)
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
t.Logf("%s", out)
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := os.Stat(h1); err != nil {
|
|
|
|
t.Errorf("libgo.h not installed in second run: %v", err)
|
|
|
|
}
|
|
|
|
if _, err := os.Stat(h2); err != nil {
|
|
|
|
t.Errorf("p.h not installed in second run: %v", err)
|
|
|
|
}
|
|
|
|
}
|