cmd/link: quote PE .def library name For Windows c-shared builds, peCreateExportFile writes a .def file containing a LIBRARY directive. When the output name has a trailing dot, as can happen for c-shared builds without an explicit -o, the directive was emitted as: LIBRARY mypackage. Some GNU ld versions reject that as invalid .def syntax. Emit the library name as a quoted .def string instead: LIBRARY "mypackage." This keeps ordinary output names working while allowing names with a trailing dot. Fixes #78238. Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest,gotip-windows-arm64 Change-Id: I45ddc09856016a0df233f73b8ec33ac7069a2aec Reviewed-on: https://go-review.googlesource.com/c/go/+/793280 Reviewed-by: Carlos Amedee <carlos@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go index a2a3d18..3cddcf7 100644 --- a/src/cmd/link/internal/ld/ld_test.go +++ b/src/cmd/link/internal/ld/ld_test.go
@@ -199,6 +199,49 @@ }) } +func TestWindowsBuildmodeCSharedTrailingDotOutput(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skip("skipping windows only test") + } + + t.Parallel() + testenv.MustHaveGoBuild(t) + testenv.MustHaveCGO(t) + testenv.MustHaveBuildMode(t, "c-shared") + + dir := t.TempDir() + srcfile := filepath.Join(dir, "test.go") + objfile := filepath.Join(dir, "mypackage.") + linktmp := filepath.Join(dir, "linktmp") + if err := os.Mkdir(linktmp, 0777); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(srcfile, []byte(`package main +import "C" + +//export Hello +func Hello() {} + +func main() {} +`), 0666); err != nil { + t.Fatal(err) + } + + argv := []string{"build", "-buildmode=c-shared", "-o", objfile, "-ldflags", "-tmpdir=" + linktmp, srcfile} + out, err := testenv.Command(t, testenv.GoToolPath(t), argv...).CombinedOutput() + if err != nil { + t.Fatalf("build failure: %s\n%s\n", err, string(out)) + } + + def, err := os.ReadFile(filepath.Join(linktmp, "export_file.def")) + if err != nil { + t.Fatal(err) + } + if want := []byte("LIBRARY \"mypackage.\"\n"); !bytes.HasPrefix(def, want) { + t.Fatalf("export_file.def begins with %q, want %q", def, want) + } +} + func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) { t.Parallel() testenv.MustHaveGoBuild(t)
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 8a01d1f..8376dde 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go
@@ -1920,7 +1920,7 @@ var buf bytes.Buffer if ctxt.BuildMode == BuildModeCShared { - fmt.Fprintf(&buf, "LIBRARY %s\n", libName) + fmt.Fprintf(&buf, "LIBRARY %q\n", libName) } buf.WriteString("EXPORTS\n")