This patch by Tony Reix adds buildid support to the go tool for AIX.
This supports caching of build results.  Bootstrapped and ran Go
testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 256877)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-87525458bcd5ab4beb5b95e7d58e3dfdbc1bd478
+3488a401e50835de5de5c4f153772ac2798d0e71
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/go/cmd/go/internal/work/buildid.go
===================================================================
--- libgo/go/cmd/go/internal/work/buildid.go    (revision 256794)
+++ libgo/go/cmd/go/internal/work/buildid.go    (working copy)
@@ -330,6 +330,43 @@ func (b *Builder) gccgoBuildIDELFFile(a
        return sfile, nil
 }
 
+// gccgoBuildIDXCOFFFile creates an assembler file that records the
+// action's build ID in a CSECT (AIX linker deletes CSECTs that are
+// not referenced in the output file).
+func (b *Builder) gccgoBuildIDXCOFFFile(a *Action) (string, error) {
+       sfile := a.Objdir + "_buildid.s"
+
+       var buf bytes.Buffer
+       fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n")
+       fmt.Fprintf(&buf, "\t.byte ")
+       for i := 0; i < len(a.buildID); i++ {
+               if i > 0 {
+                       if i%8 == 0 {
+                               fmt.Fprintf(&buf, "\n\t.byte ")
+                       } else {
+                               fmt.Fprintf(&buf, ",")
+                       }
+               }
+               fmt.Fprintf(&buf, "%#02x", a.buildID[i])
+       }
+       fmt.Fprintf(&buf, "\n")
+
+       if cfg.BuildN || cfg.BuildX {
+               for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) {
+                       b.Showcmd("", "echo '%s' >> %s", line, sfile)
+               }
+               if cfg.BuildN {
+                       return sfile, nil
+               }
+       }
+
+       if err := ioutil.WriteFile(sfile, buf.Bytes(), 0666); err != nil {
+               return "", err
+       }
+
+       return sfile, nil
+}
+
 // buildID returns the build ID found in the given file.
 // If no build ID is found, buildID returns the content hash of the file.
 func (b *Builder) buildID(file string) string {
Index: libgo/go/cmd/go/internal/work/exec.go
===================================================================
--- libgo/go/cmd/go/internal/work/exec.go       (revision 256873)
+++ libgo/go/cmd/go/internal/work/exec.go       (working copy)
@@ -637,6 +637,16 @@ func (b *Builder) build(a *Action) (err
                                return err
                        }
                        objects = append(objects, ofiles...)
+               case "aix":
+                       asmfile, err := b.gccgoBuildIDXCOFFFile(a)
+                       if err != nil {
+                               return err
+                       }
+                       ofiles, err := BuildToolchain.asm(b, a, 
[]string{asmfile})
+                       if err != nil {
+                               return err
+                       }
+                       objects = append(objects, ofiles...)
                }
        }
 
Index: libgo/go/cmd/internal/buildid/buildid.go
===================================================================
--- libgo/go/cmd/internal/buildid/buildid.go    (revision 256593)
+++ libgo/go/cmd/internal/buildid/buildid.go    (working copy)
@@ -7,6 +7,7 @@ package buildid
 import (
        "bytes"
        "debug/elf"
+       "debug/xcoff"
        "fmt"
        "io"
        "os"
@@ -40,6 +41,9 @@ func ReadFile(name string) (id string, e
                return "", err
        }
        if string(buf) != "!<arch>\n" {
+               if string(buf) == "<bigaf>\n" {
+                       return readGccgoBigArchive(name, f)
+               }
                return readBinary(name, f)
        }
 
@@ -156,6 +160,85 @@ func readGccgoArchive(name string, f *os
                }
        }
 }
+
+// readGccgoBigArchive tries to parse the archive as an AIX big
+// archive file, and fetch the build ID from the _buildid.o entry.
+// The _buildid.o entry is written by (*Builder).gccgoBuildIDXCOFFFile
+// in cmd/go/internal/work/exec.go.
+func readGccgoBigArchive(name string, f *os.File) (string, error) {
+       bad := func() (string, error) {
+               return "", &os.PathError{Op: "parse", Path: name, Err: 
errBuildIDMalformed}
+       }
+
+       // Read fixed-length header.
+       if _, err := f.Seek(0, io.SeekStart); err != nil {
+               return "", err
+       }
+       var flhdr [128]byte
+       if _, err := io.ReadFull(f, flhdr[:]); err != nil {
+               return "", err
+       }
+       // Read first member offset.
+       offStr := strings.TrimSpace(string(flhdr[68:88]))
+       off, err := strconv.ParseInt(offStr, 10, 64)
+       if err != nil {
+               return bad()
+       }
+       for {
+               if off == 0 {
+                       // No more entries, no build ID.
+                       return "", nil
+               }
+               if _, err := f.Seek(off, io.SeekStart); err != nil {
+                       return "", err
+               }
+               // Read member header.
+               var hdr [112]byte
+               if _, err := io.ReadFull(f, hdr[:]); err != nil {
+                       return "", err
+               }
+               // Read member name length.
+               namLenStr := strings.TrimSpace(string(hdr[108:112]))
+               namLen, err := strconv.ParseInt(namLenStr, 10, 32)
+               if err != nil {
+                       return bad()
+               }
+               if namLen == 10 {
+                       var nam [10]byte
+                       if _, err := io.ReadFull(f, nam[:]); err != nil {
+                               return "", err
+                       }
+                       if string(nam[:]) == "_buildid.o" {
+                               sizeStr := strings.TrimSpace(string(hdr[0:20]))
+                               size, err := strconv.ParseInt(sizeStr, 10, 64)
+                               if err != nil {
+                                       return bad()
+                               }
+                               off += int64(len(hdr)) + namLen + 2
+                               if off&1 != 0 {
+                                       off++
+                               }
+                               sr := io.NewSectionReader(f, off, size)
+                               x, err := xcoff.NewFile(sr)
+                               if err != nil {
+                                       return bad()
+                               }
+                               data := x.CSect(".go.buildid")
+                               if data == nil {
+                                       return bad()
+                               }
+                               return string(data), nil
+                       }
+               }
+
+               // Read next member offset.
+               offStr = strings.TrimSpace(string(hdr[20:40]))
+               off, err = strconv.ParseInt(offStr, 10, 64)
+               if err != nil {
+                       return bad()
+               }
+       }
+}
 
 var (
        goBuildPrefix = []byte("\xff Go build ID: \"")

Reply via email to