github.com/ActiveState/go@v0.0.0-20170614201249-0b81c023a722/src/cmd/cgo/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  	err := p.Run()
    63  	if _, ok := err.(*exec.ExitError); err != nil && !ok {
    64  		fatalf("%s", err)
    65  	}
    66  	ok = p.ProcessState.Success()
    67  	stdout, stderr = bout.Bytes(), berr.Bytes()
    68  	return
    69  }
    70  
    71  func find(argv []string, target string) int {
    72  	for i, arg := range argv {
    73  		if arg == target {
    74  			return i
    75  		}
    76  	}
    77  	return -1
    78  }
    79  
    80  func lineno(pos token.Pos) string {
    81  	return fset.Position(pos).String()
    82  }
    83  
    84  // Die with an error message.
    85  func fatalf(msg string, args ...interface{}) {
    86  	// If we've already printed other errors, they might have
    87  	// caused the fatal condition. Assume they're enough.
    88  	if nerrors == 0 {
    89  		fmt.Fprintf(os.Stderr, msg+"\n", args...)
    90  	}
    91  	os.Exit(2)
    92  }
    93  
    94  var nerrors int
    95  
    96  func error_(pos token.Pos, msg string, args ...interface{}) {
    97  	nerrors++
    98  	if pos.IsValid() {
    99  		fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
   100  	}
   101  	fmt.Fprintf(os.Stderr, msg, args...)
   102  	fmt.Fprintf(os.Stderr, "\n")
   103  }
   104  
   105  // isName reports whether s is a valid C identifier
   106  func isName(s string) bool {
   107  	for i, v := range s {
   108  		if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
   109  			return false
   110  		}
   111  		if i == 0 && '0' <= v && v <= '9' {
   112  			return false
   113  		}
   114  	}
   115  	return s != ""
   116  }
   117  
   118  func creat(name string) *os.File {
   119  	f, err := os.Create(name)
   120  	if err != nil {
   121  		fatalf("%s", err)
   122  	}
   123  	return f
   124  }
   125  
   126  func slashToUnderscore(c rune) rune {
   127  	if c == '/' || c == '\\' || c == ':' {
   128  		c = '_'
   129  	}
   130  	return c
   131  }