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.
24 // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
27 // An environment with GOPATH=$(pwd).
28 var gopathEnv []string
33 var GOOS, GOARCH string
37 bin = []string{"./testp"}
39 GOARCH = goEnv("GOARCH")
40 execScript := "go_" + GOOS + "_" + GOARCH + "_exec"
41 if executor, err := exec.LookPath(execScript); err == nil {
42 bin = []string{executor, "./testp"}
46 cc = []string{string(ccOut)}
48 out := goEnv("GOGCCFLAGS")
55 if quote == '\000' && unicode.IsSpace(c) {
57 cc = append(cc, s[start:i])
65 if quote == '\000' && !backslash && (c == '"' || c == '\'') {
68 } else if !backslash && quote == c {
70 } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
78 cc = append(cc, s[start:])
82 cc = append(cc, "-Wl,-no_pie")
85 // TODO(crawshaw): can we do better?
86 cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
88 libgodir = GOOS + "_" + GOARCH
89 if GOOS == "darwin" && GOARCH == "arm" {
90 libgodir = GOOS + "_" + GOARCH + "_shared"
92 cc = append(cc, "-I", filepath.Join("pkg", libgodir))
94 // Build an environment with GOPATH=$(pwd)
97 for _, e := range env {
98 if !strings.HasPrefix(e, "GOPATH=") {
102 dir, err := os.Getwd()
104 fmt.Fprintln(os.Stderr, err)
107 n = append(n, "GOPATH="+dir)
110 if GOOS == "windows" {
115 func goEnv(key string) string {
116 out, err := exec.Command("go", "env", key).Output()
118 fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err)
119 fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr)
122 return strings.TrimSpace(string(out))
125 func compilemain(t *testing.T, libgo string) {
126 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main.c")
127 if GOOS == "windows" {
128 ccArgs = append(ccArgs, "main_windows.c", libgo, "-lntdll", "-lws2_32", "-lwinmm")
130 ccArgs = append(ccArgs, "main_unix.c", libgo)
134 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
140 func TestInstall(t *testing.T) {
148 cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
150 if out, err := cmd.CombinedOutput(); err != nil {
155 compilemain(t, filepath.Join("pkg", libgodir, "libgo.a"))
157 binArgs := append(bin, "arg1", "arg2")
158 if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
167 // Test building libgo other than installing it.
168 // Header files are now present.
169 cmd = exec.Command("go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
171 if out, err := cmd.CombinedOutput(); err != nil {
176 compilemain(t, "libgo.a")
178 if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
187 cmd = exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
189 if out, err := cmd.CombinedOutput(); err != nil {
194 compilemain(t, "libgo.a")
196 if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
202 func TestEarlySignalHandler(t *testing.T) {
207 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
210 t.Skip("skipping signal test on Windows")
214 os.Remove("libgo2.a")
215 os.Remove("libgo2.h")
220 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
222 if out, err := cmd.CombinedOutput(); err != nil {
227 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
228 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
233 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
239 func TestSignalForwarding(t *testing.T) {
244 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
247 t.Skip("skipping signal test on Windows")
251 os.Remove("libgo2.a")
252 os.Remove("libgo2.h")
257 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
259 if out, err := cmd.CombinedOutput(); err != nil {
264 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
265 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
270 cmd = exec.Command(bin[0], append(bin[1:], "1")...)
272 out, err := cmd.CombinedOutput()
276 t.Error("test program succeeded unexpectedly")
277 } else if ee, ok := err.(*exec.ExitError); !ok {
279 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
280 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
282 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
283 } else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV {
285 t.Errorf("got %v; expected SIGSEGV", ee)
289 func TestSignalForwardingExternal(t *testing.T) {
294 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
297 t.Skip("skipping signal test on Windows")
301 os.Remove("libgo2.a")
302 os.Remove("libgo2.h")
307 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
309 if out, err := cmd.CombinedOutput(); err != nil {
314 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
315 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
320 // We want to send the process a signal and see if it dies.
321 // Normally the signal goes to the C thread, the Go signal
322 // handler picks it up, sees that it is running in a C thread,
323 // and the program dies. Unfortunately, occasionally the
324 // signal is delivered to a Go thread, which winds up
325 // discarding it because it was sent by another program and
326 // there is no Go handler for it. To avoid this, run the
327 // program several times in the hopes that it will eventually
330 for i := 0; i < tries; i++ {
331 cmd = exec.Command(bin[0], append(bin[1:], "2")...)
333 stderr, err := cmd.StderrPipe()
339 r := bufio.NewReader(stderr)
347 // Wait for trigger to ensure that the process is started.
348 ok, err := r.ReadString('\n')
351 if err != nil || ok != "OK\n" {
352 t.Fatalf("Did not receive OK signal")
355 // Give the program a chance to enter the sleep function.
356 time.Sleep(time.Millisecond)
358 cmd.Process.Signal(syscall.SIGSEGV)
366 if ee, ok := err.(*exec.ExitError); !ok {
367 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
368 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
369 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
370 } else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV {
371 t.Errorf("got %v; expected SIGSEGV", ee)
373 // We got the error we expected.
378 t.Errorf("program succeeded unexpectedly %d times", tries)
381 func TestOsSignal(t *testing.T) {
384 t.Skip("skipping signal test on Windows")
388 os.Remove("libgo3.a")
389 os.Remove("libgo3.h")
394 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3")
396 if out, err := cmd.CombinedOutput(); err != nil {
401 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
402 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
407 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
413 func TestSigaltstack(t *testing.T) {
416 t.Skip("skipping signal test on Windows")
420 os.Remove("libgo4.a")
421 os.Remove("libgo4.h")
426 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4")
428 if out, err := cmd.CombinedOutput(); err != nil {
433 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
434 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
439 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
445 const testar = `#!/usr/bin/env bash
446 while expr $1 : '[-]' >/dev/null; do
450 echo "testar" > PWD/testar.ran
453 func TestExtar(t *testing.T) {
456 t.Skip("skipping signal test on Windows")
460 os.Remove("libgo4.a")
461 os.Remove("libgo4.h")
463 os.Remove("testar.ran")
468 dir, err := os.Getwd()
472 s := strings.Replace(testar, "PWD", dir, 1)
473 if err := ioutil.WriteFile("testar", []byte(s), 0777); err != nil {
477 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "libgo4")
479 if out, err := cmd.CombinedOutput(); err != nil {
484 if _, err := os.Stat("testar.ran"); err != nil {
485 if os.IsNotExist(err) {
486 t.Error("testar does not exist after go build")
488 t.Errorf("error checking testar: %v", err)