github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/misc/cgo/testcarchive/carchive_test.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package carchive_test
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"debug/elf"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"regexp"
    17  	"runtime"
    18  	"strings"
    19  	"syscall"
    20  	"testing"
    21  	"time"
    22  	"unicode"
    23  )
    24  
    25  // Program to run.
    26  var bin []string
    27  
    28  // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
    29  var cc []string
    30  
    31  // An environment with GOPATH=$(pwd).
    32  var gopathEnv []string
    33  
    34  // ".exe" on Windows.
    35  var exeSuffix string
    36  
    37  var GOOS, GOARCH string
    38  var libgodir string
    39  
    40  func init() {
    41  	GOOS = goEnv("GOOS")
    42  	GOARCH = goEnv("GOARCH")
    43  	bin = cmdToRun("./testp")
    44  
    45  	ccOut := goEnv("CC")
    46  	cc = []string{string(ccOut)}
    47  
    48  	out := goEnv("GOGCCFLAGS")
    49  	quote := '\000'
    50  	start := 0
    51  	lastSpace := true
    52  	backslash := false
    53  	s := string(out)
    54  	for i, c := range s {
    55  		if quote == '\000' && unicode.IsSpace(c) {
    56  			if !lastSpace {
    57  				cc = append(cc, s[start:i])
    58  				lastSpace = true
    59  			}
    60  		} else {
    61  			if lastSpace {
    62  				start = i
    63  				lastSpace = false
    64  			}
    65  			if quote == '\000' && !backslash && (c == '"' || c == '\'') {
    66  				quote = c
    67  				backslash = false
    68  			} else if !backslash && quote == c {
    69  				quote = '\000'
    70  			} else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
    71  				backslash = true
    72  			} else {
    73  				backslash = false
    74  			}
    75  		}
    76  	}
    77  	if !lastSpace {
    78  		cc = append(cc, s[start:])
    79  	}
    80  
    81  	if GOOS == "darwin" {
    82  		// For Darwin/ARM.
    83  		// TODO(crawshaw): can we do better?
    84  		cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
    85  	}
    86  	libgodir = GOOS + "_" + GOARCH
    87  	if runtime.Compiler == "gccgo" {
    88  		libgodir = "gccgo_" + libgodir + "_fPIC"
    89  	} else {
    90  		switch GOOS {
    91  		case "darwin":
    92  			if GOARCH == "arm" || GOARCH == "arm64" {
    93  				libgodir += "_shared"
    94  			}
    95  		case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
    96  			libgodir += "_shared"
    97  		}
    98  	}
    99  	cc = append(cc, "-I", filepath.Join("pkg", libgodir))
   100  
   101  	// Build an environment with GOPATH=$(pwd)
   102  	env := os.Environ()
   103  	var n []string
   104  	for _, e := range env {
   105  		if !strings.HasPrefix(e, "GOPATH=") {
   106  			n = append(n, e)
   107  		}
   108  	}
   109  	dir, err := os.Getwd()
   110  	if err != nil {
   111  		fmt.Fprintln(os.Stderr, err)
   112  		os.Exit(2)
   113  	}
   114  	n = append(n, "GOPATH="+dir)
   115  	gopathEnv = n
   116  
   117  	if GOOS == "windows" {
   118  		exeSuffix = ".exe"
   119  	}
   120  }
   121  
   122  func goEnv(key string) string {
   123  	out, err := exec.Command("go", "env", key).Output()
   124  	if err != nil {
   125  		fmt.Fprintf(os.Stderr, "go env %s failed:\n%s\n", key, err)
   126  		if ee, ok := err.(*exec.ExitError); ok {
   127  			fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
   128  		}
   129  		os.Exit(2)
   130  	}
   131  	return strings.TrimSpace(string(out))
   132  }
   133  
   134  func cmdToRun(name string) []string {
   135  	execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
   136  	executor, err := exec.LookPath(execScript)
   137  	if err != nil {
   138  		return []string{name}
   139  	}
   140  	return []string{executor, name}
   141  }
   142  
   143  func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
   144  	t.Helper()
   145  	cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
   146  	cmd.Env = gopathEnv
   147  	t.Log(buildcmd)
   148  	if out, err := cmd.CombinedOutput(); err != nil {
   149  		t.Logf("%s", out)
   150  		t.Fatal(err)
   151  	}
   152  	defer func() {
   153  		os.Remove(libgoa)
   154  		os.Remove(libgoh)
   155  	}()
   156  
   157  	ccArgs := append(cc, "-o", exe, "main.c")
   158  	if GOOS == "windows" {
   159  		ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
   160  	} else {
   161  		ccArgs = append(ccArgs, "main_unix.c", libgoa)
   162  	}
   163  	if runtime.Compiler == "gccgo" {
   164  		ccArgs = append(ccArgs, "-lgo")
   165  	}
   166  	t.Log(ccArgs)
   167  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   168  		t.Logf("%s", out)
   169  		t.Fatal(err)
   170  	}
   171  	defer os.Remove(exe)
   172  
   173  	binArgs := append(cmdToRun(exe), "arg1", "arg2")
   174  	cmd = exec.Command(binArgs[0], binArgs[1:]...)
   175  	if runtime.Compiler == "gccgo" {
   176  		cmd.Env = append(os.Environ(), "GCCGO=1")
   177  	}
   178  	if out, err := cmd.CombinedOutput(); err != nil {
   179  		t.Logf("%s", out)
   180  		t.Fatal(err)
   181  	}
   182  
   183  	checkLineComments(t, libgoh)
   184  }
   185  
   186  var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
   187  
   188  // checkLineComments checks that the export header generated by
   189  // -buildmode=c-archive doesn't have any absolute paths in the #line
   190  // comments. We don't want those paths because they are unhelpful for
   191  // the user and make the files change based on details of the location
   192  // of GOPATH.
   193  func checkLineComments(t *testing.T, hdrname string) {
   194  	hdr, err := ioutil.ReadFile(hdrname)
   195  	if err != nil {
   196  		if !os.IsNotExist(err) {
   197  			t.Error(err)
   198  		}
   199  		return
   200  	}
   201  	if line := badLineRegexp.Find(hdr); line != nil {
   202  		t.Errorf("bad #line directive with absolute path in %s: %q", hdrname, line)
   203  	}
   204  }
   205  
   206  func TestInstall(t *testing.T) {
   207  	defer os.RemoveAll("pkg")
   208  
   209  	libgoa := "libgo.a"
   210  	if runtime.Compiler == "gccgo" {
   211  		libgoa = "liblibgo.a"
   212  	}
   213  
   214  	testInstall(t, "./testp1"+exeSuffix,
   215  		filepath.Join("pkg", libgodir, libgoa),
   216  		filepath.Join("pkg", libgodir, "libgo.h"),
   217  		"go", "install", "-i", "-buildmode=c-archive", "libgo")
   218  
   219  	// Test building libgo other than installing it.
   220  	// Header files are now present.
   221  	testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
   222  		"go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
   223  
   224  	testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
   225  		"go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
   226  }
   227  
   228  func TestEarlySignalHandler(t *testing.T) {
   229  	switch GOOS {
   230  	case "darwin":
   231  		switch GOARCH {
   232  		case "arm", "arm64":
   233  			t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
   234  		}
   235  	case "windows":
   236  		t.Skip("skipping signal test on Windows")
   237  	}
   238  
   239  	defer func() {
   240  		os.Remove("libgo2.a")
   241  		os.Remove("libgo2.h")
   242  		os.Remove("testp")
   243  		os.RemoveAll("pkg")
   244  	}()
   245  
   246  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
   247  	cmd.Env = gopathEnv
   248  	if out, err := cmd.CombinedOutput(); err != nil {
   249  		t.Logf("%s", out)
   250  		t.Fatal(err)
   251  	}
   252  	checkLineComments(t, "libgo2.h")
   253  
   254  	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
   255  	if runtime.Compiler == "gccgo" {
   256  		ccArgs = append(ccArgs, "-lgo")
   257  	}
   258  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   259  		t.Logf("%s", out)
   260  		t.Fatal(err)
   261  	}
   262  
   263  	if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
   264  		t.Logf("%s", out)
   265  		t.Fatal(err)
   266  	}
   267  }
   268  
   269  func TestSignalForwarding(t *testing.T) {
   270  	checkSignalForwardingTest(t)
   271  
   272  	defer func() {
   273  		os.Remove("libgo2.a")
   274  		os.Remove("libgo2.h")
   275  		os.Remove("testp")
   276  		os.RemoveAll("pkg")
   277  	}()
   278  
   279  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
   280  	cmd.Env = gopathEnv
   281  	if out, err := cmd.CombinedOutput(); err != nil {
   282  		t.Logf("%s", out)
   283  		t.Fatal(err)
   284  	}
   285  	checkLineComments(t, "libgo2.h")
   286  
   287  	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
   288  	if runtime.Compiler == "gccgo" {
   289  		ccArgs = append(ccArgs, "-lgo")
   290  	}
   291  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   292  		t.Logf("%s", out)
   293  		t.Fatal(err)
   294  	}
   295  
   296  	cmd = exec.Command(bin[0], append(bin[1:], "1")...)
   297  
   298  	out, err := cmd.CombinedOutput()
   299  	t.Logf("%s", out)
   300  	expectSignal(t, err, syscall.SIGSEGV)
   301  
   302  	// Test SIGPIPE forwarding
   303  	cmd = exec.Command(bin[0], append(bin[1:], "3")...)
   304  
   305  	out, err = cmd.CombinedOutput()
   306  	t.Logf("%s", out)
   307  	expectSignal(t, err, syscall.SIGPIPE)
   308  }
   309  
   310  func TestSignalForwardingExternal(t *testing.T) {
   311  	if GOOS == "freebsd" {
   312  		t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
   313  	}
   314  	checkSignalForwardingTest(t)
   315  
   316  	defer func() {
   317  		os.Remove("libgo2.a")
   318  		os.Remove("libgo2.h")
   319  		os.Remove("testp")
   320  		os.RemoveAll("pkg")
   321  	}()
   322  
   323  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
   324  	cmd.Env = gopathEnv
   325  	if out, err := cmd.CombinedOutput(); err != nil {
   326  		t.Logf("%s", out)
   327  		t.Fatal(err)
   328  	}
   329  	checkLineComments(t, "libgo2.h")
   330  
   331  	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
   332  	if runtime.Compiler == "gccgo" {
   333  		ccArgs = append(ccArgs, "-lgo")
   334  	}
   335  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   336  		t.Logf("%s", out)
   337  		t.Fatal(err)
   338  	}
   339  
   340  	// We want to send the process a signal and see if it dies.
   341  	// Normally the signal goes to the C thread, the Go signal
   342  	// handler picks it up, sees that it is running in a C thread,
   343  	// and the program dies. Unfortunately, occasionally the
   344  	// signal is delivered to a Go thread, which winds up
   345  	// discarding it because it was sent by another program and
   346  	// there is no Go handler for it. To avoid this, run the
   347  	// program several times in the hopes that it will eventually
   348  	// fail.
   349  	const tries = 20
   350  	for i := 0; i < tries; i++ {
   351  		cmd = exec.Command(bin[0], append(bin[1:], "2")...)
   352  
   353  		stderr, err := cmd.StderrPipe()
   354  		if err != nil {
   355  			t.Fatal(err)
   356  		}
   357  		defer stderr.Close()
   358  
   359  		r := bufio.NewReader(stderr)
   360  
   361  		err = cmd.Start()
   362  
   363  		if err != nil {
   364  			t.Fatal(err)
   365  		}
   366  
   367  		// Wait for trigger to ensure that the process is started.
   368  		ok, err := r.ReadString('\n')
   369  
   370  		// Verify trigger.
   371  		if err != nil || ok != "OK\n" {
   372  			t.Fatalf("Did not receive OK signal")
   373  		}
   374  
   375  		// Give the program a chance to enter the sleep function.
   376  		time.Sleep(time.Millisecond)
   377  
   378  		cmd.Process.Signal(syscall.SIGSEGV)
   379  
   380  		err = cmd.Wait()
   381  
   382  		if err == nil {
   383  			continue
   384  		}
   385  
   386  		if expectSignal(t, err, syscall.SIGSEGV) {
   387  			return
   388  		}
   389  	}
   390  
   391  	t.Errorf("program succeeded unexpectedly %d times", tries)
   392  }
   393  
   394  // checkSignalForwardingTest calls t.Skip if the SignalForwarding test
   395  // doesn't work on this platform.
   396  func checkSignalForwardingTest(t *testing.T) {
   397  	switch GOOS {
   398  	case "darwin":
   399  		switch GOARCH {
   400  		case "arm", "arm64":
   401  			t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
   402  		}
   403  	case "windows":
   404  		t.Skip("skipping signal test on Windows")
   405  	}
   406  }
   407  
   408  // expectSignal checks that err, the exit status of a test program,
   409  // shows a failure due to a specific signal. Returns whether we found
   410  // the expected signal.
   411  func expectSignal(t *testing.T, err error, sig syscall.Signal) bool {
   412  	if err == nil {
   413  		t.Error("test program succeeded unexpectedly")
   414  	} else if ee, ok := err.(*exec.ExitError); !ok {
   415  		t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
   416  	} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
   417  		t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
   418  	} else if !ws.Signaled() || ws.Signal() != sig {
   419  		t.Errorf("got %v; expected signal %v", ee, sig)
   420  	} else {
   421  		return true
   422  	}
   423  	return false
   424  }
   425  
   426  func TestOsSignal(t *testing.T) {
   427  	switch GOOS {
   428  	case "windows":
   429  		t.Skip("skipping signal test on Windows")
   430  	}
   431  
   432  	defer func() {
   433  		os.Remove("libgo3.a")
   434  		os.Remove("libgo3.h")
   435  		os.Remove("testp")
   436  		os.RemoveAll("pkg")
   437  	}()
   438  
   439  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3")
   440  	cmd.Env = gopathEnv
   441  	if out, err := cmd.CombinedOutput(); err != nil {
   442  		t.Logf("%s", out)
   443  		t.Fatal(err)
   444  	}
   445  	checkLineComments(t, "libgo3.h")
   446  
   447  	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
   448  	if runtime.Compiler == "gccgo" {
   449  		ccArgs = append(ccArgs, "-lgo")
   450  	}
   451  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   452  		t.Logf("%s", out)
   453  		t.Fatal(err)
   454  	}
   455  
   456  	if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
   457  		t.Logf("%s", out)
   458  		t.Fatal(err)
   459  	}
   460  }
   461  
   462  func TestSigaltstack(t *testing.T) {
   463  	switch GOOS {
   464  	case "windows":
   465  		t.Skip("skipping signal test on Windows")
   466  	}
   467  
   468  	defer func() {
   469  		os.Remove("libgo4.a")
   470  		os.Remove("libgo4.h")
   471  		os.Remove("testp")
   472  		os.RemoveAll("pkg")
   473  	}()
   474  
   475  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4")
   476  	cmd.Env = gopathEnv
   477  	if out, err := cmd.CombinedOutput(); err != nil {
   478  		t.Logf("%s", out)
   479  		t.Fatal(err)
   480  	}
   481  	checkLineComments(t, "libgo4.h")
   482  
   483  	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
   484  	if runtime.Compiler == "gccgo" {
   485  		ccArgs = append(ccArgs, "-lgo")
   486  	}
   487  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   488  		t.Logf("%s", out)
   489  		t.Fatal(err)
   490  	}
   491  
   492  	if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
   493  		t.Logf("%s", out)
   494  		t.Fatal(err)
   495  	}
   496  }
   497  
   498  const testar = `#!/usr/bin/env bash
   499  while [[ $1 == -* ]] >/dev/null; do
   500    shift
   501  done
   502  echo "testar" > $1
   503  echo "testar" > PWD/testar.ran
   504  `
   505  
   506  func TestExtar(t *testing.T) {
   507  	switch GOOS {
   508  	case "windows":
   509  		t.Skip("skipping signal test on Windows")
   510  	}
   511  	if runtime.Compiler == "gccgo" {
   512  		t.Skip("skipping -extar test when using gccgo")
   513  	}
   514  
   515  	defer func() {
   516  		os.Remove("libgo4.a")
   517  		os.Remove("libgo4.h")
   518  		os.Remove("testar")
   519  		os.Remove("testar.ran")
   520  		os.RemoveAll("pkg")
   521  	}()
   522  
   523  	os.Remove("testar")
   524  	dir, err := os.Getwd()
   525  	if err != nil {
   526  		t.Fatal(err)
   527  	}
   528  	s := strings.Replace(testar, "PWD", dir, 1)
   529  	if err := ioutil.WriteFile("testar", []byte(s), 0777); err != nil {
   530  		t.Fatal(err)
   531  	}
   532  
   533  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "libgo4")
   534  	cmd.Env = gopathEnv
   535  	if out, err := cmd.CombinedOutput(); err != nil {
   536  		t.Logf("%s", out)
   537  		t.Fatal(err)
   538  	}
   539  	checkLineComments(t, "libgo4.h")
   540  
   541  	if _, err := os.Stat("testar.ran"); err != nil {
   542  		if os.IsNotExist(err) {
   543  			t.Error("testar does not exist after go build")
   544  		} else {
   545  			t.Errorf("error checking testar: %v", err)
   546  		}
   547  	}
   548  }
   549  
   550  func TestPIE(t *testing.T) {
   551  	switch GOOS {
   552  	case "windows", "darwin", "plan9":
   553  		t.Skipf("skipping PIE test on %s", GOOS)
   554  	}
   555  
   556  	defer func() {
   557  		os.Remove("testp" + exeSuffix)
   558  		os.RemoveAll("pkg")
   559  	}()
   560  
   561  	cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "libgo")
   562  	cmd.Env = gopathEnv
   563  	if out, err := cmd.CombinedOutput(); err != nil {
   564  		t.Logf("%s", out)
   565  		t.Fatal(err)
   566  	}
   567  
   568  	libgoa := "libgo.a"
   569  	if runtime.Compiler == "gccgo" {
   570  		libgoa = "liblibgo.a"
   571  	}
   572  
   573  	ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, libgoa))
   574  	if runtime.Compiler == "gccgo" {
   575  		ccArgs = append(ccArgs, "-lgo")
   576  	}
   577  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   578  		t.Logf("%s", out)
   579  		t.Fatal(err)
   580  	}
   581  
   582  	binArgs := append(bin, "arg1", "arg2")
   583  	cmd = exec.Command(binArgs[0], binArgs[1:]...)
   584  	if runtime.Compiler == "gccgo" {
   585  		cmd.Env = append(os.Environ(), "GCCGO=1")
   586  	}
   587  	if out, err := cmd.CombinedOutput(); err != nil {
   588  		t.Logf("%s", out)
   589  		t.Fatal(err)
   590  	}
   591  
   592  	f, err := elf.Open("testp" + exeSuffix)
   593  	if err != nil {
   594  		t.Fatal("elf.Open failed: ", err)
   595  	}
   596  	defer f.Close()
   597  	if hasDynTag(t, f, elf.DT_TEXTREL) {
   598  		t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
   599  	}
   600  }
   601  
   602  func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
   603  	ds := f.SectionByType(elf.SHT_DYNAMIC)
   604  	if ds == nil {
   605  		t.Error("no SHT_DYNAMIC section")
   606  		return false
   607  	}
   608  	d, err := ds.Data()
   609  	if err != nil {
   610  		t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
   611  		return false
   612  	}
   613  	for len(d) > 0 {
   614  		var t elf.DynTag
   615  		switch f.Class {
   616  		case elf.ELFCLASS32:
   617  			t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
   618  			d = d[8:]
   619  		case elf.ELFCLASS64:
   620  			t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
   621  			d = d[16:]
   622  		}
   623  		if t == tag {
   624  			return true
   625  		}
   626  	}
   627  	return false
   628  }
   629  
   630  func TestSIGPROF(t *testing.T) {
   631  	switch GOOS {
   632  	case "windows", "plan9":
   633  		t.Skipf("skipping SIGPROF test on %s", GOOS)
   634  	case "darwin":
   635  		t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS)
   636  	}
   637  
   638  	t.Parallel()
   639  
   640  	defer func() {
   641  		os.Remove("testp6" + exeSuffix)
   642  		os.Remove("libgo6.a")
   643  		os.Remove("libgo6.h")
   644  	}()
   645  
   646  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "libgo6")
   647  	cmd.Env = gopathEnv
   648  	if out, err := cmd.CombinedOutput(); err != nil {
   649  		t.Logf("%s", out)
   650  		t.Fatal(err)
   651  	}
   652  	checkLineComments(t, "libgo6.h")
   653  
   654  	ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
   655  	if runtime.Compiler == "gccgo" {
   656  		ccArgs = append(ccArgs, "-lgo")
   657  	}
   658  	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
   659  		t.Logf("%s", out)
   660  		t.Fatal(err)
   661  	}
   662  
   663  	argv := cmdToRun("./testp6")
   664  	cmd = exec.Command(argv[0], argv[1:]...)
   665  	if out, err := cmd.CombinedOutput(); err != nil {
   666  		t.Logf("%s", out)
   667  		t.Fatal(err)
   668  	}
   669  }
   670  
   671  // TestCompileWithoutShared tests that if we compile code without the
   672  // -shared option, we can put it into an archive. When we use the go
   673  // tool with -buildmode=c-archive, it passes -shared to the compiler,
   674  // so we override that. The go tool doesn't work this way, but Bazel
   675  // will likely do it in the future. And it ought to work. This test
   676  // was added because at one time it did not work on PPC GNU/Linux.
   677  func TestCompileWithoutShared(t *testing.T) {
   678  	// For simplicity, reuse the signal forwarding test.
   679  	checkSignalForwardingTest(t)
   680  
   681  	defer func() {
   682  		os.Remove("libgo2.a")
   683  		os.Remove("libgo2.h")
   684  	}()
   685  
   686  	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "libgo2")
   687  	cmd.Env = gopathEnv
   688  	t.Log(cmd.Args)
   689  	out, err := cmd.CombinedOutput()
   690  	t.Logf("%s", out)
   691  	if err != nil {
   692  		t.Fatal(err)
   693  	}
   694  	checkLineComments(t, "libgo2.h")
   695  
   696  	exe := "./testnoshared" + exeSuffix
   697  
   698  	// In some cases, -no-pie is needed here, but not accepted everywhere. First try
   699  	// if -no-pie is accepted. See #22126.
   700  	ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a")
   701  	if runtime.Compiler == "gccgo" {
   702  		ccArgs = append(ccArgs, "-lgo")
   703  	}
   704  	t.Log(ccArgs)
   705  	out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
   706  
   707  	// If -no-pie unrecognized, try -nopie if this is possibly clang
   708  	if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
   709  		ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
   710  		t.Log(ccArgs)
   711  		out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
   712  	}
   713  
   714  	// Don't use either -no-pie or -nopie
   715  	if err != nil && bytes.Contains(out, []byte("unrecognized")) {
   716  		ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
   717  		t.Log(ccArgs)
   718  		out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
   719  	}
   720  	t.Logf("%s", out)
   721  	if err != nil {
   722  		t.Fatal(err)
   723  	}
   724  	defer os.Remove(exe)
   725  
   726  	binArgs := append(cmdToRun(exe), "3")
   727  	t.Log(binArgs)
   728  	out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
   729  	t.Logf("%s", out)
   730  	expectSignal(t, err, syscall.SIGPIPE)
   731  }
   732  
   733  // Test that installing a second time recreates the header files.
   734  func TestCachedInstall(t *testing.T) {
   735  	defer os.RemoveAll("pkg")
   736  
   737  	h1 := filepath.Join("pkg", libgodir, "libgo.h")
   738  	h2 := filepath.Join("pkg", libgodir, "p.h")
   739  
   740  	buildcmd := []string{"go", "install", "-i", "-buildmode=c-archive", "libgo"}
   741  
   742  	cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
   743  	cmd.Env = gopathEnv
   744  	t.Log(buildcmd)
   745  	if out, err := cmd.CombinedOutput(); err != nil {
   746  		t.Logf("%s", out)
   747  		t.Fatal(err)
   748  	}
   749  
   750  	if _, err := os.Stat(h1); err != nil {
   751  		t.Errorf("libgo.h not installed: %v", err)
   752  	}
   753  	if _, err := os.Stat(h2); err != nil {
   754  		t.Errorf("p.h not installed: %v", err)
   755  	}
   756  
   757  	if err := os.Remove(h1); err != nil {
   758  		t.Fatal(err)
   759  	}
   760  	if err := os.Remove(h2); err != nil {
   761  		t.Fatal(err)
   762  	}
   763  
   764  	cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
   765  	cmd.Env = gopathEnv
   766  	t.Log(buildcmd)
   767  	if out, err := cmd.CombinedOutput(); err != nil {
   768  		t.Logf("%s", out)
   769  		t.Fatal(err)
   770  	}
   771  
   772  	if _, err := os.Stat(h1); err != nil {
   773  		t.Errorf("libgo.h not installed in second run: %v", err)
   774  	}
   775  	if _, err := os.Stat(h2); err != nil {
   776  		t.Errorf("p.h not installed in second run: %v", err)
   777  	}
   778  }