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.
31 // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
37 var GOOS, GOARCH, GOPATH string
40 var testWork bool // If true, preserve temporary directories.
42 func TestMain(m *testing.M) {
43 flag.BoolVar(&testWork, "testwork", false, "if true, log and preserve the test's temporary working directory")
45 if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
46 fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
49 if runtime.GOOS == "linux" {
50 if _, err := os.Stat("/etc/alpine-release"); err == nil {
51 fmt.Printf("SKIP - skipping failing test on alpine - go.dev/issue/19938\n")
56 log.SetFlags(log.Lshortfile)
60 func testMain(m *testing.M) int {
61 // We need a writable GOPATH in which to run the tests.
62 // Construct one in a temporary directory.
64 GOPATH, err = os.MkdirTemp("", "carchive_test")
71 defer os.RemoveAll(GOPATH)
73 os.Setenv("GOPATH", GOPATH)
75 // Copy testdata into GOPATH/src/testarchive, along with a go.mod file
76 // declaring the same path.
77 modRoot := filepath.Join(GOPATH, "src", "testcarchive")
78 if err := overlayDir(modRoot, "testdata"); err != nil {
81 if err := os.Chdir(modRoot); err != nil {
84 os.Setenv("PWD", modRoot)
85 if err := os.WriteFile("go.mod", []byte("module testcarchive\n"), 0666); err != nil {
90 GOARCH = goEnv("GOARCH")
91 bin = cmdToRun("./testp")
94 cc = []string{string(ccOut)}
96 out := goEnv("GOGCCFLAGS")
102 for i, c := range s {
103 if quote == '\000' && unicode.IsSpace(c) {
105 cc = append(cc, s[start:i])
113 if quote == '\000' && !backslash && (c == '"' || c == '\'') {
116 } else if !backslash && quote == c {
118 } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
126 cc = append(cc, s[start:])
130 // -Wl,-bnoobjreorder is mandatory to keep the same layout
132 cc = append(cc, "-Wl,-bnoobjreorder")
134 libbase := GOOS + "_" + GOARCH
135 if runtime.Compiler == "gccgo" {
136 libbase = "gccgo_" + libgodir + "_fPIC"
139 case "darwin", "ios":
140 if GOARCH == "arm64" {
143 case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris", "illumos":
147 libgodir = filepath.Join(GOPATH, "pkg", libbase, "testcarchive")
148 cc = append(cc, "-I", libgodir)
150 // Force reallocation (and avoid aliasing bugs) for parallel tests that append to cc.
151 cc = cc[:len(cc):len(cc)]
153 if GOOS == "windows" {
160 func goEnv(key string) string {
161 out, err := exec.Command("go", "env", key).Output()
163 if ee, ok := err.(*exec.ExitError); ok {
164 fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
166 log.Panicf("go env %s failed:\n%s\n", key, err)
168 return strings.TrimSpace(string(out))
171 func cmdToRun(name string) []string {
172 execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
173 executor, err := exec.LookPath(execScript)
175 return []string{name}
177 return []string{executor, name}
180 // genHeader writes a C header file for the C-exported declarations found in .go
181 // source files in dir.
183 // TODO(golang.org/issue/35715): This should be simpler.
184 func genHeader(t *testing.T, header, dir string) {
187 // The 'cgo' command generates a number of additional artifacts,
188 // but we're only interested in the header.
189 // Shunt the rest of the outputs to a temporary directory.
190 objDir, err := os.MkdirTemp(GOPATH, "_obj")
194 defer os.RemoveAll(objDir)
196 files, err := filepath.Glob(filepath.Join(dir, "*.go"))
201 cmd := exec.Command("go", "tool", "cgo",
203 "-exportheader", header)
204 cmd.Args = append(cmd.Args, files...)
206 if out, err := cmd.CombinedOutput(); err != nil {
212 func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
214 cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
215 cmd.Env = append(cmd.Environ(), "GO111MODULE=off") // 'go install' only works in GOPATH mode
217 if out, err := cmd.CombinedOutput(); err != nil {
228 ccArgs := append(cc, "-o", exe, "main.c")
229 if GOOS == "windows" {
230 ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
232 ccArgs = append(ccArgs, "main_unix.c", libgoa)
234 if runtime.Compiler == "gccgo" {
235 ccArgs = append(ccArgs, "-lgo")
238 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
246 binArgs := append(cmdToRun(exe), "arg1", "arg2")
247 cmd = exec.Command(binArgs[0], binArgs[1:]...)
248 if runtime.Compiler == "gccgo" {
249 cmd.Env = append(cmd.Environ(), "GCCGO=1")
251 if out, err := cmd.CombinedOutput(); err != nil {
256 checkLineComments(t, libgoh)
259 var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
261 // checkLineComments checks that the export header generated by
262 // -buildmode=c-archive doesn't have any absolute paths in the #line
263 // comments. We don't want those paths because they are unhelpful for
264 // the user and make the files change based on details of the location
266 func checkLineComments(t *testing.T, hdrname string) {
267 hdr, err := os.ReadFile(hdrname)
269 if !os.IsNotExist(err) {
274 if line := badLineRegexp.Find(hdr); line != nil {
275 t.Errorf("bad #line directive with absolute path in %s: %q", hdrname, line)
279 // checkArchive verifies that the created library looks OK.
280 // We just check a couple of things now, we can add more checks as needed.
281 func checkArchive(t *testing.T, arname string) {
285 case "aix", "darwin", "ios", "windows":
286 // We don't have any checks for non-ELF libraries yet.
287 if _, err := os.Stat(arname); err != nil {
288 t.Errorf("archive %s does not exist: %v", arname, err)
291 checkELFArchive(t, arname)
295 // checkELFArchive checks an ELF archive.
296 func checkELFArchive(t *testing.T, arname string) {
299 f, err := os.Open(arname)
301 t.Errorf("archive %s does not exist: %v", arname, err)
306 // TODO(iant): put these in a shared package? But where?
318 hdrlen = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
331 var magbuf [len(magic)]byte
332 if _, err := io.ReadFull(f, magbuf[:]); err != nil {
333 t.Errorf("%s: archive too short", arname)
336 if string(magbuf[:]) != magic {
337 t.Errorf("%s: incorrect archive magic string %q", arname, magbuf)
340 off := int64(len(magic))
344 if _, err := f.Read(b[:]); err != nil {
348 t.Errorf("%s: error skipping alignment byte at %d: %v", arname, off, err)
353 var hdrbuf [hdrlen]byte
354 if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
358 t.Errorf("%s: error reading archive header at %d: %v", arname, off, err)
363 hdrslice := hdrbuf[:]
364 set := func(len int, ps *string) {
365 *ps = string(bytes.TrimSpace(hdrslice[:len]))
366 hdrslice = hdrslice[len:]
368 set(namelen, &hdr.name)
369 set(datelen, &hdr.date)
370 set(uidlen, &hdr.uid)
371 set(gidlen, &hdr.gid)
372 set(modelen, &hdr.mode)
373 set(sizelen, &hdr.size)
374 hdr.fmag = string(hdrslice[:fmaglen])
375 hdrslice = hdrslice[fmaglen:]
376 if len(hdrslice) != 0 {
377 t.Fatalf("internal error: len(hdrslice) == %d", len(hdrslice))
380 if hdr.fmag != fmag {
381 t.Errorf("%s: invalid fmagic value %q at %d", arname, hdr.fmag, off)
385 size, err := strconv.ParseInt(hdr.size, 10, 64)
387 t.Errorf("%s: error parsing size %q at %d: %v", arname, hdr.size, off, err)
394 case "__.SYMDEF", "/", "/SYM64/":
395 // The archive symbol map.
396 case "//", "ARFILENAMES/":
397 // The extended name table.
399 // This should be an ELF object.
400 checkELFArchiveObject(t, arname, off, io.NewSectionReader(f, off, size))
404 if _, err := f.Seek(off, os.SEEK_SET); err != nil {
405 t.Errorf("%s: failed to seek to %d: %v", arname, off, err)
410 // checkELFArchiveObject checks an object in an ELF archive.
411 func checkELFArchiveObject(t *testing.T, arname string, off int64, obj io.ReaderAt) {
414 ef, err := elf.NewFile(obj)
416 t.Errorf("%s: failed to open ELF file at %d: %v", arname, off, err)
421 // Verify section types.
422 for _, sec := range ef.Sections {
425 case ".text", ".data":
426 want = elf.SHT_PROGBITS
428 want = elf.SHT_NOBITS
430 want = elf.SHT_SYMTAB
432 want = elf.SHT_STRTAB
434 want = elf.SHT_INIT_ARRAY
436 want = elf.SHT_FINI_ARRAY
437 case ".preinit_array":
438 want = elf.SHT_PREINIT_ARRAY
440 if want != elf.SHT_NULL && sec.Type != want {
441 t.Errorf("%s: incorrect section type in elf file at %d for section %q: got %v want %v", arname, off, sec.Name, sec.Type, want)
446 func TestInstall(t *testing.T) {
448 defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
452 if runtime.Compiler == "gccgo" {
453 libgoa = "liblibgo.a"
456 // Generate the p.h header file.
458 // 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
459 // would also attempt to install transitive standard-library dependencies to
460 // GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
461 // be running this test in a GOROOT owned by root.)
462 genHeader(t, "p.h", "./p")
464 testInstall(t, "./testp1"+exeSuffix,
465 filepath.Join(libgodir, libgoa),
466 filepath.Join(libgodir, "libgo.h"),
467 "go", "install", "-buildmode=c-archive", "./libgo")
469 // Test building libgo other than installing it.
470 // Header files are now present.
471 testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
472 "go", "build", "-buildmode=c-archive", filepath.Join(".", "libgo", "libgo.go"))
474 testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
475 "go", "build", "-buildmode=c-archive", "-o", "libgo.a", "./libgo")
478 func TestEarlySignalHandler(t *testing.T) {
480 case "darwin", "ios":
483 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
486 t.Skip("skipping signal test on Windows")
491 os.Remove("libgo2.a")
492 os.Remove("libgo2.h")
493 os.Remove("testp" + exeSuffix)
494 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
498 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
499 if out, err := cmd.CombinedOutput(); err != nil {
503 checkLineComments(t, "libgo2.h")
504 checkArchive(t, "libgo2.a")
506 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
507 if runtime.Compiler == "gccgo" {
508 ccArgs = append(ccArgs, "-lgo")
510 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
516 if runtime.GOOS == "darwin" {
519 cmd = exec.Command(bin[0], append(bin[1:], darwin)...)
521 if out, err := cmd.CombinedOutput(); err != nil {
527 func TestSignalForwarding(t *testing.T) {
528 checkSignalForwardingTest(t)
532 os.Remove("libgo2.a")
533 os.Remove("libgo2.h")
534 os.Remove("testp" + exeSuffix)
535 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
539 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
540 if out, err := cmd.CombinedOutput(); err != nil {
544 checkLineComments(t, "libgo2.h")
545 checkArchive(t, "libgo2.a")
547 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
548 if runtime.Compiler == "gccgo" {
549 ccArgs = append(ccArgs, "-lgo")
551 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
556 cmd = exec.Command(bin[0], append(bin[1:], "1")...)
558 out, err := cmd.CombinedOutput()
559 t.Logf("%v\n%s", cmd.Args, out)
560 expectSignal(t, err, syscall.SIGSEGV)
562 // SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
563 if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
564 // Test SIGPIPE forwarding
565 cmd = exec.Command(bin[0], append(bin[1:], "3")...)
567 out, err = cmd.CombinedOutput()
571 expectSignal(t, err, syscall.SIGPIPE)
575 func TestSignalForwardingExternal(t *testing.T) {
576 if GOOS == "freebsd" || GOOS == "aix" {
577 t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
578 } else if GOOS == "darwin" && GOARCH == "amd64" {
579 t.Skipf("skipping on %s/%s: runtime does not permit SI_USER SIGSEGV", GOOS, GOARCH)
581 checkSignalForwardingTest(t)
585 os.Remove("libgo2.a")
586 os.Remove("libgo2.h")
587 os.Remove("testp" + exeSuffix)
588 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
592 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
593 if out, err := cmd.CombinedOutput(); err != nil {
597 checkLineComments(t, "libgo2.h")
598 checkArchive(t, "libgo2.a")
600 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
601 if runtime.Compiler == "gccgo" {
602 ccArgs = append(ccArgs, "-lgo")
604 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
609 // We want to send the process a signal and see if it dies.
610 // Normally the signal goes to the C thread, the Go signal
611 // handler picks it up, sees that it is running in a C thread,
612 // and the program dies. Unfortunately, occasionally the
613 // signal is delivered to a Go thread, which winds up
614 // discarding it because it was sent by another program and
615 // there is no Go handler for it. To avoid this, run the
616 // program several times in the hopes that it will eventually
619 for i := 0; i < tries; i++ {
620 cmd = exec.Command(bin[0], append(bin[1:], "2")...)
622 stderr, err := cmd.StderrPipe()
628 r := bufio.NewReader(stderr)
636 // Wait for trigger to ensure that the process is started.
637 ok, err := r.ReadString('\n')
640 if err != nil || ok != "OK\n" {
641 t.Fatalf("Did not receive OK signal")
644 // Give the program a chance to enter the sleep function.
645 time.Sleep(time.Millisecond)
647 cmd.Process.Signal(syscall.SIGSEGV)
655 if expectSignal(t, err, syscall.SIGSEGV) {
660 t.Errorf("program succeeded unexpectedly %d times", tries)
663 // checkSignalForwardingTest calls t.Skip if the SignalForwarding test
664 // doesn't work on this platform.
665 func checkSignalForwardingTest(t *testing.T) {
667 case "darwin", "ios":
670 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
673 t.Skip("skipping signal test on Windows")
677 // expectSignal checks that err, the exit status of a test program,
678 // shows a failure due to a specific signal. Returns whether we found
679 // the expected signal.
680 func expectSignal(t *testing.T, err error, sig syscall.Signal) bool {
682 t.Error("test program succeeded unexpectedly")
683 } else if ee, ok := err.(*exec.ExitError); !ok {
684 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
685 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
686 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
687 } else if !ws.Signaled() || ws.Signal() != sig {
688 t.Errorf("got %v; expected signal %v", ee, sig)
695 func TestOsSignal(t *testing.T) {
698 t.Skip("skipping signal test on Windows")
703 os.Remove("libgo3.a")
704 os.Remove("libgo3.h")
705 os.Remove("testp" + exeSuffix)
706 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
710 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "./libgo3")
711 if out, err := cmd.CombinedOutput(); err != nil {
715 checkLineComments(t, "libgo3.h")
716 checkArchive(t, "libgo3.a")
718 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
719 if runtime.Compiler == "gccgo" {
720 ccArgs = append(ccArgs, "-lgo")
722 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
727 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
733 func TestSigaltstack(t *testing.T) {
736 t.Skip("skipping signal test on Windows")
741 os.Remove("libgo4.a")
742 os.Remove("libgo4.h")
743 os.Remove("testp" + exeSuffix)
744 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
748 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "./libgo4")
749 if out, err := cmd.CombinedOutput(); err != nil {
753 checkLineComments(t, "libgo4.h")
754 checkArchive(t, "libgo4.a")
756 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
757 if runtime.Compiler == "gccgo" {
758 ccArgs = append(ccArgs, "-lgo")
760 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
765 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
771 const testar = `#!/usr/bin/env bash
772 while [[ $1 == -* ]] >/dev/null; do
776 echo "testar" > PWD/testar.ran
779 func TestExtar(t *testing.T) {
782 t.Skip("skipping signal test on Windows")
784 if runtime.Compiler == "gccgo" {
785 t.Skip("skipping -extar test when using gccgo")
787 if runtime.GOOS == "ios" {
788 t.Skip("shell scripts are not executable on iOS hosts")
793 os.Remove("libgo4.a")
794 os.Remove("libgo4.h")
796 os.Remove("testar.ran")
797 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
802 dir, err := os.Getwd()
806 s := strings.Replace(testar, "PWD", dir, 1)
807 if err := os.WriteFile("testar", []byte(s), 0777); err != nil {
811 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "./libgo4")
812 if out, err := cmd.CombinedOutput(); err != nil {
816 checkLineComments(t, "libgo4.h")
818 if _, err := os.Stat("testar.ran"); err != nil {
819 if os.IsNotExist(err) {
820 t.Error("testar does not exist after go build")
822 t.Errorf("error checking testar: %v", err)
827 func TestPIE(t *testing.T) {
829 case "windows", "darwin", "ios", "plan9":
830 t.Skipf("skipping PIE test on %s", GOOS)
834 if runtime.Compiler == "gccgo" {
835 libgoa = "liblibgo.a"
840 os.Remove("testp" + exeSuffix)
842 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
846 // Generate the p.h header file.
848 // 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
849 // would also attempt to install transitive standard-library dependencies to
850 // GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
851 // be running this test in a GOROOT owned by root.)
852 genHeader(t, "p.h", "./p")
854 cmd := exec.Command("go", "build", "-buildmode=c-archive", "./libgo")
855 if out, err := cmd.CombinedOutput(); err != nil {
860 ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", libgoa)
861 if runtime.Compiler == "gccgo" {
862 ccArgs = append(ccArgs, "-lgo")
864 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
869 binArgs := append(bin, "arg1", "arg2")
870 cmd = exec.Command(binArgs[0], binArgs[1:]...)
871 if runtime.Compiler == "gccgo" {
872 cmd.Env = append(os.Environ(), "GCCGO=1")
874 if out, err := cmd.CombinedOutput(); err != nil {
880 f, err := elf.Open("testp" + exeSuffix)
882 t.Fatal("elf.Open failed: ", err)
885 if hasDynTag(t, f, elf.DT_TEXTREL) {
886 t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
891 func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
892 ds := f.SectionByType(elf.SHT_DYNAMIC)
894 t.Error("no SHT_DYNAMIC section")
899 t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
906 t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
909 t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
919 func TestSIGPROF(t *testing.T) {
921 case "windows", "plan9":
922 t.Skipf("skipping SIGPROF test on %s", GOOS)
923 case "darwin", "ios":
924 t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS)
931 os.Remove("testp6" + exeSuffix)
932 os.Remove("libgo6.a")
933 os.Remove("libgo6.h")
937 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
938 out, err := cmd.CombinedOutput()
939 t.Logf("%v\n%s", cmd.Args, out)
943 checkLineComments(t, "libgo6.h")
944 checkArchive(t, "libgo6.a")
946 ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
947 if runtime.Compiler == "gccgo" {
948 ccArgs = append(ccArgs, "-lgo")
950 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
951 t.Logf("%v\n%s", ccArgs, out)
956 argv := cmdToRun("./testp6")
957 cmd = exec.Command(argv[0], argv[1:]...)
958 out, err = cmd.CombinedOutput()
959 t.Logf("%v\n%s", argv, out)
965 // TestCompileWithoutShared tests that if we compile code without the
966 // -shared option, we can put it into an archive. When we use the go
967 // tool with -buildmode=c-archive, it passes -shared to the compiler,
968 // so we override that. The go tool doesn't work this way, but Bazel
969 // will likely do it in the future. And it ought to work. This test
970 // was added because at one time it did not work on PPC Linux.
971 func TestCompileWithoutShared(t *testing.T) {
972 // For simplicity, reuse the signal forwarding test.
973 checkSignalForwardingTest(t)
977 os.Remove("libgo2.a")
978 os.Remove("libgo2.h")
982 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
983 out, err := cmd.CombinedOutput()
984 t.Logf("%v\n%s", cmd.Args, out)
988 checkLineComments(t, "libgo2.h")
989 checkArchive(t, "libgo2.a")
991 exe := "./testnoshared" + exeSuffix
993 // In some cases, -no-pie is needed here, but not accepted everywhere. First try
994 // if -no-pie is accepted. See #22126.
995 ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a")
996 if runtime.Compiler == "gccgo" {
997 ccArgs = append(ccArgs, "-lgo")
999 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1000 t.Logf("%v\n%s", ccArgs, out)
1002 // If -no-pie unrecognized, try -nopie if this is possibly clang
1003 if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
1004 ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
1005 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1006 t.Logf("%v\n%s", ccArgs, out)
1009 // Don't use either -no-pie or -nopie
1010 if err != nil && bytes.Contains(out, []byte("unrecognized")) {
1011 ccArgs = append(cc, "-o", exe, "main5.c", "libgo2.a")
1012 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1013 t.Logf("%v\n%s", ccArgs, out)
1019 defer os.Remove(exe)
1022 binArgs := append(cmdToRun(exe), "1")
1023 out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
1024 t.Logf("%v\n%s", binArgs, out)
1025 expectSignal(t, err, syscall.SIGSEGV)
1027 // SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
1028 if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
1029 binArgs := append(cmdToRun(exe), "3")
1030 out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
1031 t.Logf("%v\n%s", binArgs, out)
1032 expectSignal(t, err, syscall.SIGPIPE)
1036 // Test that installing a second time recreates the header file.
1037 func TestCachedInstall(t *testing.T) {
1039 defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
1042 h := filepath.Join(libgodir, "libgo.h")
1044 buildcmd := []string{"go", "install", "-buildmode=c-archive", "./libgo"}
1046 cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
1047 cmd.Env = append(cmd.Environ(), "GO111MODULE=off") // 'go install' only works in GOPATH mode
1049 if out, err := cmd.CombinedOutput(); err != nil {
1054 if _, err := os.Stat(h); err != nil {
1055 t.Errorf("libgo.h not installed: %v", err)
1058 if err := os.Remove(h); err != nil {
1062 cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
1063 cmd.Env = append(cmd.Environ(), "GO111MODULE=off")
1065 if out, err := cmd.CombinedOutput(); err != nil {
1070 if _, err := os.Stat(h); err != nil {
1071 t.Errorf("libgo.h not installed in second run: %v", err)
1076 func TestManyCalls(t *testing.T) {
1081 os.Remove("testp7" + exeSuffix)
1082 os.Remove("libgo7.a")
1083 os.Remove("libgo7.h")
1087 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
1088 out, err := cmd.CombinedOutput()
1089 t.Logf("%v\n%s", cmd.Args, out)
1093 checkLineComments(t, "libgo7.h")
1094 checkArchive(t, "libgo7.a")
1096 ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
1097 if runtime.Compiler == "gccgo" {
1098 ccArgs = append(ccArgs, "-lgo")
1100 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1101 t.Logf("%v\n%s", ccArgs, out)
1106 argv := cmdToRun("./testp7")
1107 cmd = exec.Command(argv[0], argv[1:]...)
1108 sb := new(strings.Builder)
1111 if err := cmd.Start(); err != nil {
1115 timer := time.AfterFunc(time.Minute,
1117 t.Error("test program timed out")
1124 t.Logf("%v\n%s", cmd.Args, sb)
1131 func TestPreemption(t *testing.T) {
1132 if runtime.Compiler == "gccgo" {
1133 t.Skip("skipping asynchronous preemption test with gccgo")
1140 os.Remove("testp8" + exeSuffix)
1141 os.Remove("libgo8.a")
1142 os.Remove("libgo8.h")
1146 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
1147 out, err := cmd.CombinedOutput()
1148 t.Logf("%v\n%s", cmd.Args, out)
1152 checkLineComments(t, "libgo8.h")
1153 checkArchive(t, "libgo8.a")
1155 ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
1156 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1157 t.Logf("%v\n%s", ccArgs, out)
1162 argv := cmdToRun("./testp8")
1163 cmd = exec.Command(argv[0], argv[1:]...)
1164 sb := new(strings.Builder)
1167 if err := cmd.Start(); err != nil {
1171 timer := time.AfterFunc(time.Minute,
1173 t.Error("test program timed out")
1180 t.Logf("%v\n%s", cmd.Args, sb)