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