Skip to content

Commit 9b61471

Browse files
committed
cmd/pack: treat compiler's -linkobj output as "compiler object"
Treat the compiler's -linkobj output as "compiler object, which means "pack c" will "see through" the file and add individual entry to the new archive, instead of the object as a whole. This is somewhat peculiar. But Go 1.15's cmd/pack does this, although seemingly accidental. We just do the same. FWIW, it does make things more consistent with/without -linkobj flag. Fixes #43271. Change-Id: I6b2d99256db7ebf0fa430f85afa7464e334f6bcb Reviewed-on: https://go-review.googlesource.com/c/go/+/279483 Trust: Cherry Zhang <[email protected]> Run-TryBot: Cherry Zhang <[email protected]> Reviewed-by: Jeremy Faller <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent bc7e4d9 commit 9b61471

File tree

2 files changed

+84
-13
lines changed

2 files changed

+84
-13
lines changed

src/cmd/pack/pack.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -315,20 +315,25 @@ func (ar *Archive) extractContents1(e *archive.Entry, out io.Writer) {
315315
}
316316

317317
// isGoCompilerObjFile reports whether file is an object file created
318-
// by the Go compiler, which is an archive file with exactly two entries:
319-
// __.PKGDEF and _go_.o.
318+
// by the Go compiler, which is an archive file with exactly one entry
319+
// of __.PKGDEF, or _go_.o, or both entries.
320320
func isGoCompilerObjFile(a *archive.Archive) bool {
321-
if len(a.Entries) != 2 {
322-
return false
323-
}
324-
var foundPkgDef, foundGo bool
325-
for _, e := range a.Entries {
326-
if e.Type == archive.EntryPkgDef && e.Name == "__.PKGDEF" {
327-
foundPkgDef = true
328-
}
329-
if e.Type == archive.EntryGoObj && e.Name == "_go_.o" {
330-
foundGo = true
321+
switch len(a.Entries) {
322+
case 1:
323+
return (a.Entries[0].Type == archive.EntryGoObj && a.Entries[0].Name == "_go_.o") ||
324+
(a.Entries[0].Type == archive.EntryPkgDef && a.Entries[0].Name == "__.PKGDEF")
325+
case 2:
326+
var foundPkgDef, foundGo bool
327+
for _, e := range a.Entries {
328+
if e.Type == archive.EntryPkgDef && e.Name == "__.PKGDEF" {
329+
foundPkgDef = true
330+
}
331+
if e.Type == archive.EntryGoObj && e.Name == "_go_.o" {
332+
foundGo = true
333+
}
331334
}
335+
return foundPkgDef && foundGo
336+
default:
337+
return false
332338
}
333-
return foundPkgDef && foundGo
334339
}

src/cmd/pack/pack_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,72 @@ func TestIssue21703(t *testing.T) {
302302
run(goBin, "tool", "compile", "-I", ".", "b.go")
303303
}
304304

305+
// Test the "c" command can "see through" the archive generated by the compiler.
306+
// This is peculiar. (See issue )
307+
func TestCreateWithCompilerObj(t *testing.T) {
308+
testenv.MustHaveGoBuild(t)
309+
310+
dir := tmpDir(t)
311+
defer os.RemoveAll(dir)
312+
src := filepath.Join(dir, "p.go")
313+
prog := "package p; var X = 42\n"
314+
err := os.WriteFile(src, []byte(prog), 0666)
315+
if err != nil {
316+
t.Fatal(err)
317+
}
318+
319+
run := func(args ...string) string {
320+
return doRun(t, dir, args...)
321+
}
322+
323+
goBin := testenv.GoToolPath(t)
324+
run(goBin, "build", "cmd/pack") // writes pack binary to dir
325+
run(goBin, "tool", "compile", "-pack", "-o", "p.a", "p.go")
326+
run("./pack", "c", "packed.a", "p.a")
327+
fi, err := os.Stat(filepath.Join(dir, "p.a"))
328+
if err != nil {
329+
t.Fatalf("stat p.a failed: %v", err)
330+
}
331+
fi2, err := os.Stat(filepath.Join(dir, "packed.a"))
332+
if err != nil {
333+
t.Fatalf("stat packed.a failed: %v", err)
334+
}
335+
// For compiler-generated object file, the "c" command is
336+
// expected to get (essentially) the same file back, instead
337+
// of packing it into a new archive with a single entry.
338+
if want, got := fi.Size(), fi2.Size(); want != got {
339+
t.Errorf("packed file with different size: want %d, got %d", want, got)
340+
}
341+
342+
// Test -linkobj flag as well.
343+
run(goBin, "tool", "compile", "-linkobj", "p2.a", "-o", "p.x", "p.go")
344+
run("./pack", "c", "packed2.a", "p2.a")
345+
fi, err = os.Stat(filepath.Join(dir, "p2.a"))
346+
if err != nil {
347+
t.Fatalf("stat p2.a failed: %v", err)
348+
}
349+
fi2, err = os.Stat(filepath.Join(dir, "packed2.a"))
350+
if err != nil {
351+
t.Fatalf("stat packed2.a failed: %v", err)
352+
}
353+
if want, got := fi.Size(), fi2.Size(); want != got {
354+
t.Errorf("packed file with different size: want %d, got %d", want, got)
355+
}
356+
357+
run("./pack", "c", "packed3.a", "p.x")
358+
fi, err = os.Stat(filepath.Join(dir, "p.x"))
359+
if err != nil {
360+
t.Fatalf("stat p.x failed: %v", err)
361+
}
362+
fi2, err = os.Stat(filepath.Join(dir, "packed3.a"))
363+
if err != nil {
364+
t.Fatalf("stat packed3.a failed: %v", err)
365+
}
366+
if want, got := fi.Size(), fi2.Size(); want != got {
367+
t.Errorf("packed file with different size: want %d, got %d", want, got)
368+
}
369+
}
370+
305371
// doRun runs a program in a directory and returns the output.
306372
func doRun(t *testing.T, dir string, args ...string) string {
307373
cmd := exec.Command(args[0], args[1:]...)

0 commit comments

Comments
 (0)