]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: avoid use of 'go tool pack'
authorRuss Cox <rsc@golang.org>
Wed, 18 Dec 2013 02:44:36 +0000 (21:44 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 18 Dec 2013 02:44:36 +0000 (21:44 -0500)
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

src/cmd/go/build.go

index 0eb055413024853bc4083c346de6f09e232f063f..3ef4d8c9ce0bed6033725d015da9516b031523b3 100644 (file)
@@ -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