diff options
author | Russ Cox <rsc@golang.org> | 2009-04-16 00:18:11 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-04-16 00:18:11 -0700 |
commit | 5a1a92a0559e505bf7a8b50a56d9f28d4b3da765 (patch) | |
tree | 6c0830724548ef4a33f0aff8bd2262bd3abc5d79 /src/cmd/gobuild/util.go | |
parent | 5eda790c67ef577f56e3347bb3589f4de21c7c0a (diff) | |
download | golang-5a1a92a0559e505bf7a8b50a56d9f28d4b3da765.tar.gz |
rewrite gobuild in go.
R=r
DELTA=1305 (704 added, 590 deleted, 11 changed)
OCL=27546
CL=27548
Diffstat (limited to 'src/cmd/gobuild/util.go')
-rw-r--r-- | src/cmd/gobuild/util.go | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/src/cmd/gobuild/util.go b/src/cmd/gobuild/util.go new file mode 100644 index 000000000..022417289 --- /dev/null +++ b/src/cmd/gobuild/util.go @@ -0,0 +1,244 @@ +// 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 gobuild + +import ( + "ast"; + "exec"; + "fmt"; + "os"; + "parser"; + "path"; + "sort"; + "strconv"; + "strings"; +) + +var ( + theChar string; + goarch string; + goos string; + bin = make(map[string] string); +) + +var theChars = map[string] string { + "amd64": "6", + "386": "8", + "arm": "5" +} + +func fatal(args ...) { + fmt.Fprintf(os.Stderr, "gobuild: %s\n", fmt.Sprint(args)); + sys.Exit(1); +} + +func init() { + var err *os.Error; + goarch, err = os.Getenv("GOARCH"); + goos, err = os.Getenv("GOOS"); + + var ok bool; + theChar, ok = theChars[goarch]; + if !ok { + fatal("unknown $GOARCH: ", goarch); + } + + var binaries = []string{ + theChar + "g", + theChar + "c", + theChar + "a", + "6ar", // sic + }; + + for i, v := range binaries { + var s string; + if s, err = exec.LookPath(v); err != nil { + fatal("cannot find binary ", v); + } + bin[v] = s; + } +} + +func PushString(v *[]string, p string) { + n := len(v); + if n >= cap(v) { + m := 2*n + 10; + a := make([]string, n, m); + for i := range *v { + a[i] = v[i]; + } + *v = a; + } + *v = v[0:n+1]; + v[n] = p; +} + + +func run(argv []string, display bool) (ok bool) { + argv0 := bin[argv[0]]; + output := exec.DevNull; + if display { + output = exec.PassThrough; + } + p, err1 := exec.Run(argv0, argv, os.Environ(), exec.DevNull, output, output); + if err1 != nil { + return false; + } + w, err2 := p.Wait(0); + if err2 != nil { + return false; + } + return w.Exited() && w.ExitStatus() == 0; +} + +func Build(cmd []string, file string, display bool) (ok bool) { + if display { + fmt.Fprint(os.Stderr, "$ "); + for i, s := range cmd { + fmt.Fprint(os.Stderr, s[i], " "); + } + fmt.Fprint(os.Stderr, file, "\n"); + } + + var argv []string; + for i, c := range cmd { + PushString(&argv, c); + } + PushString(&argv, file); + return run(argv, display); +} + +func Archive(pkg string, files []string) { + argv := []string{ "6ar", "grc", pkg }; + for i, file := range files { + PushString(&argv, file); + } + if !run(argv, true) { + fatal("archive failed"); + } +} + +func Compiler(file string) []string { + switch { + case strings.HasSuffix(file, ".go"): + return []string{ theChar + "g" }; + case strings.HasSuffix(file, ".c"): + return []string{ theChar + "c", "-FVw" }; + case strings.HasSuffix(file, ".s"): + return []string{ theChar + "a" }; + } + fatal("don't know how to compile ", file); + return nil; +} + +func Object(file, suffix string) string { + ext := path.Ext(file); + return file[0:len(file)-len(ext)] + "." + suffix; +} + +// Dollarstring returns s with literal goarch/goos values +// replaced by $lGOARCHr where l and r are the specified delimeters. +func dollarString(s, l, r string) string { + out := ""; + j := 0; // index of last byte in s copied to out. + for i := 0; i < len(s); { + switch { + case i+len(goarch) <= len(s) && s[i:i+len(goarch)] == goarch: + out += s[j:i]; + out += "$" + l + "GOARCH" + r; + i += len(goarch); + j = i; + case i+len(goos) <= len(s) && s[i:i+len(goos)] == goos: + out += s[j:i]; + out += "$" + l + "GOOS" + r; + i += len(goos); + j = i; + default: + i++; + } + } + out += s[j:len(s)]; + return out; +} + +// dollarString wrappers. +// Print ShellString(s) or MakeString(s) depending on +// the context in which the result will be interpreted. +type ShellString string; +func (s ShellString) String() string { + return dollarString(s, "{", "}"); +} + +type MakeString string; +func (s MakeString) String() string { + return dollarString(s, "(", ")"); +} + +// TODO(rsc): parse.Parse should return an os.Error. +var ParseError = os.NewError("parse errors"); + +// TODO(rsc): Should this be in the AST library? +func LitString(p []*ast.StringLit) (string, *os.Error) { + s := ""; + for i, lit := range p { + t, err := strconv.Unquote(string(lit.Value)); + if err != nil { + return "", err; + } + s += t; + } + return s, nil; +} + +func PackageImports(file string) (pkg string, imports []string, err1 *os.Error) { + f, err := os.Open(file, os.O_RDONLY, 0); + if err != nil { + return "", nil, err + } + + prog, ok := parser.Parse(f, nil, parser.ImportsOnly); + if !ok { + return "", nil, ParseError; + } + + // Normally one must consult the types of decl and spec, + // but we told the parser to return imports only, + // so assume it did. + var imp []string; + for _, decl := range prog.Decls { + for _, spec := range decl.(*ast.GenDecl).Specs { + str, err := LitString(spec.(*ast.ImportSpec).Path); + if err != nil { + return "", nil, ParseError; // ParseError is better than os.EINVAL + } + PushString(&imp, str); + } + } + + // TODO(rsc): should be prog.Package.Value + return prog.Name.Value, imp, nil; +} + +func SourceFiles(dir string) ([]string, *os.Error) { + f, err := os.Open(dir, os.O_RDONLY, 0); + if err != nil { + return nil, err; + } + names, err1 := f.Readdirnames(-1); + f.Close(); + out := make([]string, 0, len(names)); + for i, name := range names { + if strings.HasSuffix(name, ".go") + || strings.HasSuffix(name, ".c") + || strings.HasSuffix(name, ".s") { + n := len(out); + out = out[0:n+1]; + out[n] = name; + } + } + sort.SortStrings(out); + return out, nil; +} |