mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			605 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			605 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright 2017 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 (
 | |
| 	"debug/elf"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"testing"
 | |
| 	"unicode"
 | |
| )
 | |
| 
 | |
| // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
 | |
| var cc []string
 | |
| 
 | |
| // An environment with GOPATH=$(pwd).
 | |
| var gopathEnv []string
 | |
| 
 | |
| // ".exe" on Windows.
 | |
| var exeSuffix string
 | |
| 
 | |
| var GOOS, GOARCH, GOROOT string
 | |
| var installdir, androiddir string
 | |
| var libSuffix, libgoname string
 | |
| 
 | |
| func TestMain(m *testing.M) {
 | |
| 	GOOS = goEnv("GOOS")
 | |
| 	GOARCH = goEnv("GOARCH")
 | |
| 	GOROOT = goEnv("GOROOT")
 | |
| 
 | |
| 	if _, err := os.Stat(GOROOT); os.IsNotExist(err) {
 | |
| 		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())
 | |
| 	if GOOS == "android" {
 | |
| 		args := append(adbCmd(), "shell", "mkdir", "-p", androiddir)
 | |
| 		cmd := exec.Command(args[0], args[1:]...)
 | |
| 		out, err := cmd.CombinedOutput()
 | |
| 		if err != nil {
 | |
| 			log.Fatalf("setupAndroid failed: %v\n%s\n", err, out)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	libgoname = "libgo." + libSuffix
 | |
| 
 | |
| 	cc = []string{goEnv("CC")}
 | |
| 
 | |
| 	out := goEnv("GOGCCFLAGS")
 | |
| 	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:])
 | |
| 	}
 | |
| 
 | |
| 	switch GOOS {
 | |
| 	case "darwin":
 | |
| 		// For Darwin/ARM.
 | |
| 		// TODO(crawshaw): can we do better?
 | |
| 		cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
 | |
| 	case "android":
 | |
| 		cc = append(cc, "-pie", "-fuse-ld=gold")
 | |
| 	}
 | |
| 	libgodir := GOOS + "_" + GOARCH
 | |
| 	switch GOOS {
 | |
| 	case "darwin":
 | |
| 		if GOARCH == "arm" || GOARCH == "arm64" {
 | |
| 			libgodir += "_shared"
 | |
| 		}
 | |
| 	case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
 | |
| 		libgodir += "_shared"
 | |
| 	}
 | |
| 	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" {
 | |
| 		exeSuffix = ".exe"
 | |
| 	}
 | |
| 
 | |
| 	st := m.Run()
 | |
| 
 | |
| 	os.Remove(libgoname)
 | |
| 	os.RemoveAll("pkg")
 | |
| 	cleanupHeaders()
 | |
| 	cleanupAndroid()
 | |
| 
 | |
| 	os.Exit(st)
 | |
| }
 | |
| 
 | |
| func goEnv(key string) string {
 | |
| 	out, err := exec.Command("go", "env", key).Output()
 | |
| 	if err != nil {
 | |
| 		fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err)
 | |
| 		fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr)
 | |
| 		os.Exit(2)
 | |
| 	}
 | |
| 	return strings.TrimSpace(string(out))
 | |
| }
 | |
| 
 | |
| func cmdToRun(name string) string {
 | |
| 	return "./" + name + exeSuffix
 | |
| }
 | |
| 
 | |
| func adbCmd() []string {
 | |
| 	cmd := []string{"adb"}
 | |
| 	if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
 | |
| 		cmd = append(cmd, strings.Split(flags, " ")...)
 | |
| 	}
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| func adbPush(t *testing.T, filename string) {
 | |
| 	if GOOS != "android" {
 | |
| 		return
 | |
| 	}
 | |
| 	args := append(adbCmd(), "push", filename, fmt.Sprintf("%s/%s", androiddir, filename))
 | |
| 	cmd := exec.Command(args[0], args[1:]...)
 | |
| 	if out, err := cmd.CombinedOutput(); err != nil {
 | |
| 		t.Fatalf("adb command failed: %v\n%s\n", err, out)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func adbRun(t *testing.T, env []string, adbargs ...string) string {
 | |
| 	if GOOS != "android" {
 | |
| 		t.Fatalf("trying to run adb command when operating system is not android.")
 | |
| 	}
 | |
| 	args := append(adbCmd(), "shell")
 | |
| 	// Propagate LD_LIBRARY_PATH to the adb shell invocation.
 | |
| 	for _, e := range env {
 | |
| 		if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
 | |
| 			adbargs = append([]string{e}, adbargs...)
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 	shellcmd := fmt.Sprintf("cd %s; %s", androiddir, strings.Join(adbargs, " "))
 | |
| 	args = append(args, shellcmd)
 | |
| 	cmd := exec.Command(args[0], args[1:]...)
 | |
| 	out, err := cmd.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("adb command failed: %v\n%s\n", err, out)
 | |
| 	}
 | |
| 	return strings.Replace(string(out), "\r", "", -1)
 | |
| }
 | |
| 
 | |
| func run(t *testing.T, env []string, args ...string) string {
 | |
| 	t.Helper()
 | |
| 	cmd := exec.Command(args[0], args[1:]...)
 | |
| 	cmd.Env = env
 | |
| 
 | |
| 	if GOOS != "windows" {
 | |
| 		// TestUnexportedSymbols relies on file descriptor 30
 | |
| 		// being closed when the program starts, so enforce
 | |
| 		// that in all cases. (The first three descriptors are
 | |
| 		// stdin/stdout/stderr, so we just need to make sure
 | |
| 		// that cmd.ExtraFiles[27] exists and is nil.)
 | |
| 		cmd.ExtraFiles = make([]*os.File, 28)
 | |
| 	}
 | |
| 
 | |
| 	out, err := cmd.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("command failed: %v\n%v\n%s\n", args, err, out)
 | |
| 	} else {
 | |
| 		t.Logf("run: %v", args)
 | |
| 	}
 | |
| 	return string(out)
 | |
| }
 | |
| 
 | |
| func runExe(t *testing.T, env []string, args ...string) string {
 | |
| 	t.Helper()
 | |
| 	if GOOS == "android" {
 | |
| 		return adbRun(t, env, args...)
 | |
| 	}
 | |
| 	return run(t, env, args...)
 | |
| }
 | |
| 
 | |
| func runCC(t *testing.T, args ...string) string {
 | |
| 	t.Helper()
 | |
| 	// This function is run in parallel, so append to a copy of cc
 | |
| 	// rather than cc itself.
 | |
| 	return run(t, nil, append(append([]string(nil), cc...), args...)...)
 | |
| }
 | |
| 
 | |
| func createHeaders() error {
 | |
| 	args := []string{"go", "install", "-i", "-buildmode=c-shared",
 | |
| 		"-installsuffix", "testcshared", "libgo"}
 | |
| 	cmd := exec.Command(args[0], args[1:]...)
 | |
| 	cmd.Env = gopathEnv
 | |
| 	out, err := cmd.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
 | |
| 	}
 | |
| 
 | |
| 	args = []string{"go", "build", "-buildmode=c-shared",
 | |
| 		"-installsuffix", "testcshared",
 | |
| 		"-o", libgoname,
 | |
| 		filepath.Join("src", "libgo", "libgo.go")}
 | |
| 	cmd = exec.Command(args[0], args[1:]...)
 | |
| 	cmd.Env = gopathEnv
 | |
| 	out, err = cmd.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
 | |
| 	}
 | |
| 
 | |
| 	if GOOS == "android" {
 | |
| 		args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname))
 | |
| 		cmd = exec.Command(args[0], args[1:]...)
 | |
| 		out, err = cmd.CombinedOutput()
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("adb command failed: %v\n%s\n", err, out)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	headersOnce sync.Once
 | |
| 	headersErr  error
 | |
| )
 | |
| 
 | |
| func createHeadersOnce(t *testing.T) {
 | |
| 	headersOnce.Do(func() {
 | |
| 		headersErr = createHeaders()
 | |
| 	})
 | |
| 	if headersErr != nil {
 | |
| 		t.Fatal(headersErr)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func cleanupHeaders() {
 | |
| 	os.Remove("libgo.h")
 | |
| }
 | |
| 
 | |
| func cleanupAndroid() {
 | |
| 	if GOOS != "android" {
 | |
| 		return
 | |
| 	}
 | |
| 	args := append(adbCmd(), "shell", "rm", "-rf", androiddir)
 | |
| 	cmd := exec.Command(args[0], args[1:]...)
 | |
| 	out, err := cmd.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		log.Fatalf("cleanupAndroid failed: %v\n%s\n", err, out)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // test0: exported symbols in shared lib are accessible.
 | |
| func TestExportedSymbols(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 
 | |
| 	cmd := "testp0"
 | |
| 	bin := cmdToRun(cmd)
 | |
| 
 | |
| 	createHeadersOnce(t)
 | |
| 
 | |
| 	runCC(t, "-I", installdir, "-o", cmd, "main0.c", libgoname)
 | |
| 	adbPush(t, cmd)
 | |
| 
 | |
| 	defer os.Remove(bin)
 | |
| 
 | |
| 	out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin)
 | |
| 	if strings.TrimSpace(out) != "PASS" {
 | |
| 		t.Error(out)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // test1: shared library can be dynamically loaded and exported symbols are accessible.
 | |
| func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 
 | |
| 	if GOOS == "windows" {
 | |
| 		t.Logf("Skipping on %s", GOOS)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	cmd := "testp1"
 | |
| 	bin := cmdToRun(cmd)
 | |
| 
 | |
| 	createHeadersOnce(t)
 | |
| 
 | |
| 	if GOOS != "freebsd" {
 | |
| 		runCC(t, "-o", cmd, "main1.c", "-ldl")
 | |
| 	} else {
 | |
| 		runCC(t, "-o", cmd, "main1.c")
 | |
| 	}
 | |
| 	adbPush(t, cmd)
 | |
| 
 | |
| 	defer os.Remove(bin)
 | |
| 
 | |
| 	out := runExe(t, nil, bin, "./"+libgoname)
 | |
| 	if strings.TrimSpace(out) != "PASS" {
 | |
| 		t.Error(out)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // test2: tests libgo2 which does not export any functions.
 | |
| func TestUnexportedSymbols(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 
 | |
| 	if GOOS == "windows" {
 | |
| 		t.Logf("Skipping on %s", GOOS)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	cmd := "testp2"
 | |
| 	bin := cmdToRun(cmd)
 | |
| 	libname := "libgo2." + libSuffix
 | |
| 
 | |
| 	run(t,
 | |
| 		gopathEnv,
 | |
| 		"go", "build",
 | |
| 		"-buildmode=c-shared",
 | |
| 		"-installsuffix", "testcshared",
 | |
| 		"-o", libname, "libgo2",
 | |
| 	)
 | |
| 	adbPush(t, libname)
 | |
| 
 | |
| 	linkFlags := "-Wl,--no-as-needed"
 | |
| 	if GOOS == "darwin" {
 | |
| 		linkFlags = ""
 | |
| 	}
 | |
| 
 | |
| 	runCC(t, "-o", cmd, "main2.c", linkFlags, libname)
 | |
| 	adbPush(t, cmd)
 | |
| 
 | |
| 	defer os.Remove(libname)
 | |
| 	defer os.Remove(bin)
 | |
| 
 | |
| 	out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin)
 | |
| 
 | |
| 	if strings.TrimSpace(out) != "PASS" {
 | |
| 		t.Error(out)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // test3: tests main.main is exported on android.
 | |
| func TestMainExportedOnAndroid(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 
 | |
| 	switch GOOS {
 | |
| 	case "android":
 | |
| 		break
 | |
| 	default:
 | |
| 		t.Logf("Skipping on %s", GOOS)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	cmd := "testp3"
 | |
| 	bin := cmdToRun(cmd)
 | |
| 
 | |
| 	createHeadersOnce(t)
 | |
| 
 | |
| 	runCC(t, "-o", cmd, "main3.c", "-ldl")
 | |
| 	adbPush(t, cmd)
 | |
| 
 | |
| 	defer os.Remove(bin)
 | |
| 
 | |
| 	out := runExe(t, nil, bin, "./"+libgoname)
 | |
| 	if strings.TrimSpace(out) != "PASS" {
 | |
| 		t.Error(out)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) {
 | |
| 	libname := pkgname + "." + libSuffix
 | |
| 	run(t,
 | |
| 		gopathEnv,
 | |
| 		"go", "build",
 | |
| 		"-buildmode=c-shared",
 | |
| 		"-installsuffix", "testcshared",
 | |
| 		"-o", libname, pkgname,
 | |
| 	)
 | |
| 	adbPush(t, libname)
 | |
| 	if GOOS != "freebsd" {
 | |
| 		runCC(t, "-pthread", "-o", cmd, cfile, "-ldl")
 | |
| 	} else {
 | |
| 		runCC(t, "-pthread", "-o", cmd, cfile)
 | |
| 	}
 | |
| 	adbPush(t, cmd)
 | |
| 
 | |
| 	bin := cmdToRun(cmd)
 | |
| 
 | |
| 	defer os.Remove(libname)
 | |
| 	defer os.Remove(bin)
 | |
| 	defer os.Remove(pkgname + ".h")
 | |
| 
 | |
| 	out := runExe(t, nil, bin, "./"+libname)
 | |
| 	if strings.TrimSpace(out) != "PASS" {
 | |
| 		t.Error(run(t, nil, bin, libname, "verbose"))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // test4: test signal handlers
 | |
| func TestSignalHandlers(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 	if GOOS == "windows" {
 | |
| 		t.Logf("Skipping on %s", GOOS)
 | |
| 		return
 | |
| 	}
 | |
| 	testSignalHandlers(t, "libgo4", "main4.c", "testp4")
 | |
| }
 | |
| 
 | |
| // test5: test signal handlers with os/signal.Notify
 | |
| func TestSignalHandlersWithNotify(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 	if GOOS == "windows" {
 | |
| 		t.Logf("Skipping on %s", GOOS)
 | |
| 		return
 | |
| 	}
 | |
| 	testSignalHandlers(t, "libgo5", "main5.c", "testp5")
 | |
| }
 | |
| 
 | |
| func TestPIE(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 
 | |
| 	switch GOOS {
 | |
| 	case "linux", "android":
 | |
| 		break
 | |
| 	default:
 | |
| 		t.Logf("Skipping on %s", GOOS)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	createHeadersOnce(t)
 | |
| 
 | |
| 	f, err := elf.Open(libgoname)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("elf.Open failed: %v", err)
 | |
| 	}
 | |
| 	defer f.Close()
 | |
| 
 | |
| 	ds := f.SectionByType(elf.SHT_DYNAMIC)
 | |
| 	if ds == nil {
 | |
| 		t.Fatalf("no SHT_DYNAMIC section")
 | |
| 	}
 | |
| 	d, err := ds.Data()
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("can't read SHT_DYNAMIC contents: %v", err)
 | |
| 	}
 | |
| 	for len(d) > 0 {
 | |
| 		var tag elf.DynTag
 | |
| 		switch f.Class {
 | |
| 		case elf.ELFCLASS32:
 | |
| 			tag = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
 | |
| 			d = d[8:]
 | |
| 		case elf.ELFCLASS64:
 | |
| 			tag = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
 | |
| 			d = d[16:]
 | |
| 		}
 | |
| 		if tag == elf.DT_TEXTREL {
 | |
| 			t.Fatalf("%s has DT_TEXTREL flag", libgoname)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Test that installing a second time recreates the header files.
 | |
| func TestCachedInstall(t *testing.T) {
 | |
| 	tmpdir, err := ioutil.TempDir("", "cshared")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	// 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", "p", "p.go"), filepath.Join("src", "p", "p.go"))
 | |
| 
 | |
| 	env := append(os.Environ(), "GOPATH="+tmpdir)
 | |
| 
 | |
| 	buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "libgo"}
 | |
| 
 | |
| 	cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
 | |
| 	cmd.Env = env
 | |
| 	t.Log(buildcmd)
 | |
| 	out, err := cmd.CombinedOutput()
 | |
| 	t.Logf("%s", out)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	var libgoh, ph string
 | |
| 
 | |
| 	walker := func(path string, info os.FileInfo, err error) error {
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 		var ps *string
 | |
| 		switch filepath.Base(path) {
 | |
| 		case "libgo.h":
 | |
| 			ps = &libgoh
 | |
| 		case "p.h":
 | |
| 			ps = &ph
 | |
| 		}
 | |
| 		if ps != nil {
 | |
| 			if *ps != "" {
 | |
| 				t.Fatalf("%s found again", *ps)
 | |
| 			}
 | |
| 			*ps = path
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if err := filepath.Walk(tmpdir, walker); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if libgoh == "" {
 | |
| 		t.Fatal("libgo.h not installed")
 | |
| 	}
 | |
| 	if ph == "" {
 | |
| 		t.Fatal("p.h not installed")
 | |
| 	}
 | |
| 
 | |
| 	if err := os.Remove(libgoh); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err := os.Remove(ph); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
 | |
| 	cmd.Env = env
 | |
| 	t.Log(buildcmd)
 | |
| 	out, err = cmd.CombinedOutput()
 | |
| 	t.Logf("%s", out)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if _, err := os.Stat(libgoh); err != nil {
 | |
| 		t.Errorf("libgo.h not installed in second run: %v", err)
 | |
| 	}
 | |
| 	if _, err := os.Stat(ph); err != nil {
 | |
| 		t.Errorf("p.h not installed in second run: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // copyFile copies src to dst.
 | |
| func copyFile(t *testing.T, dst, src string) {
 | |
| 	t.Helper()
 | |
| 	data, err := ioutil.ReadFile(src)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err := ioutil.WriteFile(dst, data, 0666); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| }
 |