1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// Copyright 2009 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 main
import (
"bytes"
"fmt"
"go/token"
exec "internal/execabs"
"io/ioutil"
"os"
)
// run runs the command argv, feeding in stdin on standard input.
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
// Some compilers have trouble with standard input.
// Others have trouble with -xc.
// Avoid both problems by writing a file with a .c extension.
f, err := ioutil.TempFile("", "cgo-gcc-input-")
if err != nil {
fatalf("%s", err)
}
name := f.Name()
f.Close()
if err := ioutil.WriteFile(name+".c", stdin, 0666); err != nil {
os.Remove(name)
fatalf("%s", err)
}
defer os.Remove(name)
defer os.Remove(name + ".c")
// Build new argument list without -xc and trailing -.
new := append(argv[:i:i], argv[i+1:len(argv)-1]...)
// Since we are going to write the file to a temporary directory,
// we will need to add -I . explicitly to the command line:
// any #include "foo" before would have looked in the current
// directory as the directory "holding" standard input, but now
// the temporary directory holds the input.
// We've also run into compilers that reject "-I." but allow "-I", ".",
// so be sure to use two arguments.
// This matters mainly for people invoking cgo -godefs by hand.
new = append(new, "-I", ".")
// Finish argument list with path to C file.
new = append(new, name+".c")
argv = new
stdin = nil
}
p := exec.Command(argv[0], argv[1:]...)
p.Stdin = bytes.NewReader(stdin)
var bout, berr bytes.Buffer
p.Stdout = &bout
p.Stderr = &berr
// Disable escape codes in clang error messages.
p.Env = append(os.Environ(), "TERM=dumb")
err := p.Run()
if _, ok := err.(*exec.ExitError); err != nil && !ok {
fatalf("exec %s: %s", argv[0], err)
}
ok = p.ProcessState.Success()
stdout, stderr = bout.Bytes(), berr.Bytes()
return
}
func find(argv []string, target string) int {
for i, arg := range argv {
if arg == target {
return i
}
}
return -1
}
func lineno(pos token.Pos) string {
return fset.Position(pos).String()
}
// Die with an error message.
func fatalf(msg string, args ...interface{}) {
// If we've already printed other errors, they might have
// caused the fatal condition. Assume they're enough.
if nerrors == 0 {
fmt.Fprintf(os.Stderr, "cgo: "+msg+"\n", args...)
}
os.Exit(2)
}
var nerrors int
func error_(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
} else {
fmt.Fprintf(os.Stderr, "cgo: ")
}
fmt.Fprintf(os.Stderr, msg, args...)
fmt.Fprintf(os.Stderr, "\n")
}
// isName reports whether s is a valid C identifier
func isName(s string) bool {
for i, v := range s {
if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
return false
}
if i == 0 && '0' <= v && v <= '9' {
return false
}
}
return s != ""
}
func creat(name string) *os.File {
f, err := os.Create(name)
if err != nil {
fatalf("%s", err)
}
return f
}
func slashToUnderscore(c rune) rune {
if c == '/' || c == '\\' || c == ':' {
c = '_'
}
return c
}
|