aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-12-17 21:44:36 -0500
committerRuss Cox <rsc@golang.org>2013-12-17 21:44:36 -0500
commitc86fc68ac6f95b2a50abe419dce6d1649adf4cd9 (patch)
treeb10d2668512b6130568cbccd02eaffd07cb58aba /src
parentb2d43caa7a1a2697f09187a133ef724d9f822634 (diff)
downloadgo-c86fc68ac6f95b2a50abe419dce6d1649adf4cd9.tar.xz
cmd/go: avoid use of 'go tool pack'
All packages now use the -pack option to the compiler. For a pure Go package, that's enough. For a package with additional C and assembly files, the extra archive entries can be added directly (by concatenation) instead of by invoking go tool pack. These changes make it possible to rewrite cmd/pack in Go. R=iant, r CC=golang-dev https://golang.org/cl/42910043
Diffstat (limited to 'src')
-rw-r--r--src/cmd/go/build.go142
1 files changed, 128 insertions, 14 deletions
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 0eb0554130..3ef4d8c9ce 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -5,6 +5,7 @@
package main
import (
+ "bufio"
"bytes"
"container/heap"
"errors"
@@ -879,7 +880,7 @@ func (b *builder) build(a *action) (err error) {
// Compile Go.
if len(gofiles) > 0 {
- ofile, out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles)
+ ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
if len(out) > 0 {
b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
if err != nil {
@@ -889,7 +890,9 @@ func (b *builder) build(a *action) (err error) {
if err != nil {
return err
}
- objects = append(objects, ofile)
+ if ofile != a.objpkg {
+ objects = append(objects, ofile)
+ }
}
// Copy .h files named for goos or goarch or goos_goarch
@@ -952,9 +955,15 @@ func (b *builder) build(a *action) (err error) {
objects = append(objects, filepath.Join(a.p.Dir, syso))
}
- // Pack into archive in obj directory
- if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
- return err
+ // Pack into archive in obj directory.
+ // If the Go compiler wrote an archive, we only need to add the
+ // object files for non-Go sources to the archive.
+ // If the Go compiler wrote an archive and the package is entirely
+ // Go sources, there is no pack to execute at all.
+ if len(objects) > 0 {
+ if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
+ return err
+ }
}
// Link if needed.
@@ -1016,7 +1025,7 @@ func (b *builder) install(a *action) (err error) {
}
}
- return b.copyFile(a, a.target, a1.target, perm)
+ return b.moveOrCopyFile(a, a.target, a1.target, perm)
}
// includeArgs returns the -I or -L directory list for access
@@ -1062,6 +1071,27 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
return inc
}
+// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
+func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
+ if buildN {
+ b.showcmd("", "mv %s %s", src, dst)
+ return nil
+ }
+
+ // If we can update the mode and rename to the dst, do it.
+ // Otherwise fall back to standard copy.
+ if err := os.Chmod(src, perm); err == nil {
+ if err := os.Rename(src, dst); err == nil {
+ if buildX {
+ b.showcmd("", "mv %s %s", src, dst)
+ }
+ return nil
+ }
+ }
+
+ return b.copyFile(a, dst, src, perm)
+}
+
// copyFile is like 'cp src dst'.
func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
if buildN || buildX {
@@ -1432,7 +1462,7 @@ type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
// The compiler runs in the directory dir.
- gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
+ gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
@@ -1469,7 +1499,7 @@ func (noToolchain) linker() string {
return ""
}
-func (noToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler()
}
@@ -1505,9 +1535,14 @@ func (gcToolchain) linker() string {
return tool(archChar + "l")
}
-func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
- out := "_go_." + archChar
- ofile = obj + out
+func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+ if archive != "" {
+ ofile = archive
+ } else {
+ out := "_go_." + archChar
+ ofile = obj + out
+ }
+
gcargs := []string{"-p", p.ImportPath}
if p.Standard && p.ImportPath == "runtime" {
// runtime compiles with a special 6g flag to emit
@@ -1534,6 +1569,9 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
}
args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ if ofile == archive {
+ args = append(args, "-pack")
+ }
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
@@ -1557,7 +1595,83 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, nil, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
+ cmd := "grcP"
+ absAfile := mkAbs(objDir, afile)
+ appending := false
+ if _, err := os.Stat(absAfile); err == nil {
+ appending = true
+ cmd = "rqP"
+ }
+
+ cmdline := stringList("pack", cmd, b.work, absAfile, absOfiles)
+
+ if appending {
+ if buildN || buildX {
+ b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
+ }
+ if buildN {
+ return nil
+ }
+ if err := packInternal(b, absAfile, absOfiles); err != nil {
+ b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
+ return errPrintedOutput
+ }
+ return nil
+ }
+
+ // Need actual pack.
+ cmdline[0] = tool("pack")
+ return b.run(p.Dir, p.ImportPath, nil, cmdline)
+}
+
+func packInternal(b *builder, afile string, ofiles []string) error {
+ dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
+ if err != nil {
+ return err
+ }
+ defer dst.Close() // only for error returns or panics
+ w := bufio.NewWriter(dst)
+
+ for _, ofile := range ofiles {
+ src, err := os.Open(ofile)
+ if err != nil {
+ return err
+ }
+ fi, err := src.Stat()
+ if err != nil {
+ src.Close()
+ return err
+ }
+ // Note: Not using %-16.16s format because we care
+ // about bytes, not runes.
+ name := fi.Name()
+ if len(name) > 16 {
+ name = name[:16]
+ } else {
+ name += strings.Repeat(" ", 16-len(name))
+ }
+ size := fi.Size()
+ fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
+ name, 0, 0, 0, 0644, size)
+ n, err := io.Copy(w, src)
+ src.Close()
+ if err == nil && n < size {
+ err = io.ErrUnexpectedEOF
+ } else if err == nil && n > size {
+ err = fmt.Errorf("file larger than size reported by stat")
+ }
+ if err != nil {
+ return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
+ }
+ if size&1 != 0 {
+ w.WriteByte(0)
+ }
+ }
+
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return dst.Close()
}
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
@@ -1650,7 +1764,7 @@ func (gccgoToolchain) linker() string {
return gccgoBin
}
-func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := p.Name + ".o"
ofile = obj + out
gcargs := []string{"-g"}
@@ -2220,7 +2334,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
p := goFilesPackage(srcs)
- if _, _, e := buildToolchain.gc(b, p, obj, nil, srcs); e != nil {
+ if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil {
return "32", nil
}
return "64", nil