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.
27 // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
30 // An environment with GOPATH=$(pwd).
31 var gopathEnv
[]string
36 var GOOS
, GOARCH
string
41 GOARCH
= goEnv("GOARCH")
42 bin
= cmdToRun("./testp")
45 cc
= []string{string(ccOut
)}
47 out
:= goEnv("GOGCCFLAGS")
54 if quote
== '\000' && unicode
.IsSpace(c
) {
56 cc
= append(cc
, s
[start
:i
])
64 if quote
== '\000' && !backslash
&& (c
== '"' || c
== '\'') {
67 } else if !backslash
&& quote
== c
{
69 } else if (quote
== '\000' || quote
== '"') && !backslash
&& c
== '\\' {
77 cc
= append(cc
, s
[start
:])
82 // TODO(crawshaw): can we do better?
83 cc
= append(cc
, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
85 libgodir
= GOOS
+ "_" + GOARCH
86 if runtime
.Compiler
== "gccgo" {
87 libgodir
= "gccgo_" + libgodir
+ "_fPIC"
91 if GOARCH
== "arm" || GOARCH
== "arm64" {
94 case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
98 cc
= append(cc
, "-I", filepath
.Join("pkg", libgodir
))
100 // Build an environment with GOPATH=$(pwd)
103 for _
, e
:= range env
{
104 if !strings
.HasPrefix(e
, "GOPATH=") {
108 dir
, err
:= os
.Getwd()
110 fmt
.Fprintln(os
.Stderr
, err
)
113 n
= append(n
, "GOPATH="+dir
)
116 if GOOS
== "windows" {
121 func goEnv(key
string) string {
122 out
, err
:= exec
.Command("go", "env", key
).Output()
124 fmt
.Fprintf(os
.Stderr
, "go env %s failed:\n%s\n", key
, err
)
125 if ee
, ok
:= err
.(*exec
.ExitError
); ok
{
126 fmt
.Fprintf(os
.Stderr
, "%s", ee
.Stderr
)
130 return strings
.TrimSpace(string(out
))
133 func cmdToRun(name
string) []string {
134 execScript
:= "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
135 executor
, err
:= exec
.LookPath(execScript
)
137 return []string{name
}
139 return []string{executor
, name
}
142 func testInstall(t
*testing
.T
, exe
, libgoa
, libgoh
string, buildcmd
...string) {
144 cmd
:= exec
.Command(buildcmd
[0], buildcmd
[1:]...)
147 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
156 ccArgs
:= append(cc
, "-o", exe
, "main.c")
157 if GOOS
== "windows" {
158 ccArgs
= append(ccArgs
, "main_windows.c", libgoa
, "-lntdll", "-lws2_32", "-lwinmm")
160 ccArgs
= append(ccArgs
, "main_unix.c", libgoa
)
162 if runtime
.Compiler
== "gccgo" {
163 ccArgs
= append(ccArgs
, "-lgo")
166 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
172 binArgs
:= append(cmdToRun(exe
), "arg1", "arg2")
173 cmd
= exec
.Command(binArgs
[0], binArgs
[1:]...)
174 if runtime
.Compiler
== "gccgo" {
175 cmd
.Env
= append(os
.Environ(), "GCCGO=1")
177 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
183 func TestInstall(t
*testing
.T
) {
184 defer os
.RemoveAll("pkg")
187 if runtime
.Compiler
== "gccgo" {
188 libgoa
= "liblibgo.a"
191 testInstall(t
, "./testp1"+exeSuffix
,
192 filepath
.Join("pkg", libgodir
, libgoa
),
193 filepath
.Join("pkg", libgodir
, "libgo.h"),
194 "go", "install", "-i", "-buildmode=c-archive", "libgo")
196 // Test building libgo other than installing it.
197 // Header files are now present.
198 testInstall(t
, "./testp2"+exeSuffix
, "libgo.a", "libgo.h",
199 "go", "build", "-buildmode=c-archive", filepath
.Join("src", "libgo", "libgo.go"))
201 testInstall(t
, "./testp3"+exeSuffix
, "libgo.a", "libgo.h",
202 "go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
205 func TestEarlySignalHandler(t
*testing
.T
) {
210 t
.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS
, GOARCH
)
213 t
.Skip("skipping signal test on Windows")
217 os
.Remove("libgo2.a")
218 os
.Remove("libgo2.h")
223 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
225 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
230 ccArgs
:= append(cc
, "-o", "testp"+exeSuffix
, "main2.c", "libgo2.a")
231 if runtime
.Compiler
== "gccgo" {
232 ccArgs
= append(ccArgs
, "-lgo")
234 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
239 if out
, err
:= exec
.Command(bin
[0], bin
[1:]...).CombinedOutput(); err
!= nil {
245 func TestSignalForwarding(t
*testing
.T
) {
246 checkSignalForwardingTest(t
)
249 os
.Remove("libgo2.a")
250 os
.Remove("libgo2.h")
255 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
257 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
262 ccArgs
:= append(cc
, "-o", "testp"+exeSuffix
, "main5.c", "libgo2.a")
263 if runtime
.Compiler
== "gccgo" {
264 ccArgs
= append(ccArgs
, "-lgo")
266 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
271 cmd
= exec
.Command(bin
[0], append(bin
[1:], "1")...)
273 out
, err
:= cmd
.CombinedOutput()
275 expectSignal(t
, err
, syscall
.SIGSEGV
)
277 // Test SIGPIPE forwarding
278 cmd
= exec
.Command(bin
[0], append(bin
[1:], "3")...)
280 out
, err
= cmd
.CombinedOutput()
282 expectSignal(t
, err
, syscall
.SIGPIPE
)
285 func TestSignalForwardingExternal(t
*testing
.T
) {
286 checkSignalForwardingTest(t
)
289 os
.Remove("libgo2.a")
290 os
.Remove("libgo2.h")
295 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
297 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
302 ccArgs
:= append(cc
, "-o", "testp"+exeSuffix
, "main5.c", "libgo2.a")
303 if runtime
.Compiler
== "gccgo" {
304 ccArgs
= append(ccArgs
, "-lgo")
306 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
311 // We want to send the process a signal and see if it dies.
312 // Normally the signal goes to the C thread, the Go signal
313 // handler picks it up, sees that it is running in a C thread,
314 // and the program dies. Unfortunately, occasionally the
315 // signal is delivered to a Go thread, which winds up
316 // discarding it because it was sent by another program and
317 // there is no Go handler for it. To avoid this, run the
318 // program several times in the hopes that it will eventually
321 for i
:= 0; i
< tries
; i
++ {
322 cmd
= exec
.Command(bin
[0], append(bin
[1:], "2")...)
324 stderr
, err
:= cmd
.StderrPipe()
330 r
:= bufio
.NewReader(stderr
)
338 // Wait for trigger to ensure that the process is started.
339 ok
, err
:= r
.ReadString('\n')
342 if err
!= nil || ok
!= "OK\n" {
343 t
.Fatalf("Did not receive OK signal")
346 // Give the program a chance to enter the sleep function.
347 time
.Sleep(time
.Millisecond
)
349 cmd
.Process
.Signal(syscall
.SIGSEGV
)
357 if expectSignal(t
, err
, syscall
.SIGSEGV
) {
362 t
.Errorf("program succeeded unexpectedly %d times", tries
)
365 // checkSignalForwardingTest calls t.Skip if the SignalForwarding test
366 // doesn't work on this platform.
367 func checkSignalForwardingTest(t
*testing
.T
) {
372 t
.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS
, GOARCH
)
375 t
.Skip("skipping signal test on Windows")
379 // expectSignal checks that err, the exit status of a test program,
380 // shows a failure due to a specific signal. Returns whether we found
381 // the expected signal.
382 func expectSignal(t
*testing
.T
, err error
, sig syscall
.Signal
) bool {
384 t
.Error("test program succeeded unexpectedly")
385 } else if ee
, ok
:= err
.(*exec
.ExitError
); !ok
{
386 t
.Errorf("error (%v) has type %T; expected exec.ExitError", err
, err
)
387 } else if ws
, ok
:= ee
.Sys().(syscall
.WaitStatus
); !ok
{
388 t
.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee
.Sys(), ee
.Sys())
389 } else if !ws
.Signaled() || ws
.Signal() != sig
{
390 t
.Errorf("got %v; expected signal %v", ee
, sig
)
397 func TestOsSignal(t
*testing
.T
) {
400 t
.Skip("skipping signal test on Windows")
404 os
.Remove("libgo3.a")
405 os
.Remove("libgo3.h")
410 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3")
412 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
417 ccArgs
:= append(cc
, "-o", "testp"+exeSuffix
, "main3.c", "libgo3.a")
418 if runtime
.Compiler
== "gccgo" {
419 ccArgs
= append(ccArgs
, "-lgo")
421 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
426 if out
, err
:= exec
.Command(bin
[0], bin
[1:]...).CombinedOutput(); err
!= nil {
432 func TestSigaltstack(t
*testing
.T
) {
435 t
.Skip("skipping signal test on Windows")
439 os
.Remove("libgo4.a")
440 os
.Remove("libgo4.h")
445 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4")
447 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
452 ccArgs
:= append(cc
, "-o", "testp"+exeSuffix
, "main4.c", "libgo4.a")
453 if runtime
.Compiler
== "gccgo" {
454 ccArgs
= append(ccArgs
, "-lgo")
456 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
461 if out
, err
:= exec
.Command(bin
[0], bin
[1:]...).CombinedOutput(); err
!= nil {
467 const testar
= `#!/usr/bin/env bash
468 while expr $1 : '[-]' >/dev/null; do
472 echo "testar" > PWD/testar.ran
475 func TestExtar(t
*testing
.T
) {
478 t
.Skip("skipping signal test on Windows")
480 if runtime
.Compiler
== "gccgo" {
481 t
.Skip("skipping -extar test when using gccgo")
485 os
.Remove("libgo4.a")
486 os
.Remove("libgo4.h")
488 os
.Remove("testar.ran")
493 dir
, err
:= os
.Getwd()
497 s
:= strings
.Replace(testar
, "PWD", dir
, 1)
498 if err
:= ioutil
.WriteFile("testar", []byte(s
), 0777); err
!= nil {
502 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath
.Join(dir
, "testar"), "-o", "libgo4.a", "libgo4")
504 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
509 if _
, err
:= os
.Stat("testar.ran"); err
!= nil {
510 if os
.IsNotExist(err
) {
511 t
.Error("testar does not exist after go build")
513 t
.Errorf("error checking testar: %v", err
)
518 func TestPIE(t
*testing
.T
) {
520 case "windows", "darwin", "plan9":
521 t
.Skipf("skipping PIE test on %s", GOOS
)
525 os
.Remove("testp" + exeSuffix
)
529 cmd
:= exec
.Command("go", "install", "-i", "-buildmode=c-archive", "libgo")
531 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
537 if runtime
.Compiler
== "gccgo" {
538 libgoa
= "liblibgo.a"
541 ccArgs
:= append(cc
, "-fPIE", "-pie", "-o", "testp"+exeSuffix
, "main.c", "main_unix.c", filepath
.Join("pkg", libgodir
, libgoa
))
542 if runtime
.Compiler
== "gccgo" {
543 ccArgs
= append(ccArgs
, "-lgo")
545 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
550 binArgs
:= append(bin
, "arg1", "arg2")
551 cmd
= exec
.Command(binArgs
[0], binArgs
[1:]...)
552 if runtime
.Compiler
== "gccgo" {
553 cmd
.Env
= append(os
.Environ(), "GCCGO=1")
555 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
560 f
, err
:= elf
.Open("testp" + exeSuffix
)
562 t
.Fatal("elf.Open failed: ", err
)
565 if hasDynTag(t
, f
, elf
.DT_TEXTREL
) {
566 t
.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix
)
570 func hasDynTag(t
*testing
.T
, f
*elf
.File
, tag elf
.DynTag
) bool {
571 ds
:= f
.SectionByType(elf
.SHT_DYNAMIC
)
573 t
.Error("no SHT_DYNAMIC section")
578 t
.Errorf("can't read SHT_DYNAMIC contents: %v", err
)
585 t
= elf
.DynTag(f
.ByteOrder
.Uint32(d
[:4]))
588 t
= elf
.DynTag(f
.ByteOrder
.Uint64(d
[:8]))
598 func TestSIGPROF(t
*testing
.T
) {
600 case "windows", "plan9":
601 t
.Skipf("skipping SIGPROF test on %s", GOOS
)
603 t
.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS
)
609 os
.Remove("testp6" + exeSuffix
)
610 os
.Remove("libgo6.a")
611 os
.Remove("libgo6.h")
614 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "libgo6")
616 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
621 ccArgs
:= append(cc
, "-o", "testp6"+exeSuffix
, "main6.c", "libgo6.a")
622 if runtime
.Compiler
== "gccgo" {
623 ccArgs
= append(ccArgs
, "-lgo")
625 if out
, err
:= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput(); err
!= nil {
630 argv
:= cmdToRun("./testp6")
631 cmd
= exec
.Command(argv
[0], argv
[1:]...)
632 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
638 // TestCompileWithoutShared tests that if we compile code without the
639 // -shared option, we can put it into an archive. When we use the go
640 // tool with -buildmode=c-archive, it passes -shared to the compiler,
641 // so we override that. The go tool doesn't work this way, but Bazel
642 // will likely do it in the future. And it ought to work. This test
643 // was added because at one time it did not work on PPC GNU/Linux.
644 func TestCompileWithoutShared(t
*testing
.T
) {
645 // For simplicity, reuse the signal forwarding test.
646 checkSignalForwardingTest(t
)
649 os
.Remove("libgo2.a")
650 os
.Remove("libgo2.h")
653 cmd
:= exec
.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "libgo2")
656 out
, err
:= cmd
.CombinedOutput()
662 exe
:= "./testnoshared" + exeSuffix
664 // In some cases, -no-pie is needed here, but not accepted everywhere. First try
665 // if -no-pie is accepted. See #22126.
666 ccArgs
:= append(cc
, "-o", exe
, "-no-pie", "main5.c", "libgo2.a")
667 if runtime
.Compiler
== "gccgo" {
668 ccArgs
= append(ccArgs
, "-lgo")
671 out
, err
= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput()
673 // If -no-pie unrecognized, try -nopie if this is possibly clang
674 if err
!= nil && bytes
.Contains(out
, []byte("unknown")) && !strings
.Contains(cc
[0], "gcc") {
675 ccArgs
= append(cc
, "-o", exe
, "-nopie", "main5.c", "libgo2.a")
677 out
, err
= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput()
680 // Don't use either -no-pie or -nopie
681 if err
!= nil && bytes
.Contains(out
, []byte("unrecognized")) {
682 ccArgs
:= append(cc
, "-o", exe
, "main5.c", "libgo2.a")
684 out
, err
= exec
.Command(ccArgs
[0], ccArgs
[1:]...).CombinedOutput()
692 binArgs
:= append(cmdToRun(exe
), "3")
694 out
, err
= exec
.Command(binArgs
[0], binArgs
[1:]...).CombinedOutput()
696 expectSignal(t
, err
, syscall
.SIGPIPE
)
699 // Test that installing a second time recreates the header files.
700 func TestCachedInstall(t
*testing
.T
) {
701 defer os
.RemoveAll("pkg")
703 h1
:= filepath
.Join("pkg", libgodir
, "libgo.h")
704 h2
:= filepath
.Join("pkg", libgodir
, "p.h")
706 buildcmd
:= []string{"go", "install", "-i", "-buildmode=c-archive", "libgo"}
708 cmd
:= exec
.Command(buildcmd
[0], buildcmd
[1:]...)
711 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
716 if _
, err
:= os
.Stat(h1
); err
!= nil {
717 t
.Errorf("libgo.h not installed: %v", err
)
719 if _
, err
:= os
.Stat(h2
); err
!= nil {
720 t
.Errorf("p.h not installed: %v", err
)
723 if err
:= os
.Remove(h1
); err
!= nil {
726 if err
:= os
.Remove(h2
); err
!= nil {
730 cmd
= exec
.Command(buildcmd
[0], buildcmd
[1:]...)
733 if out
, err
:= cmd
.CombinedOutput(); err
!= nil {
738 if _
, err
:= os
.Stat(h1
); err
!= nil {
739 t
.Errorf("libgo.h not installed in second run: %v", err
)
741 if _
, err
:= os
.Stat(h2
); err
!= nil {
742 t
.Errorf("p.h not installed in second run: %v", err
)