1
0
mirror of https://github.com/golang/go synced 2024-11-12 08:20:22 -07:00

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
This commit is contained in:
Russ Cox 2013-12-17 21:44:36 -05:00
parent b2d43caa7a
commit c86fc68ac6

View 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