From 1f0547c4ec4fe18d46192d8c670190111b1d3d79 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 27 Apr 2022 09:02:52 -0400 Subject: [dev.boringcrypto] cmd/go: pass dependency syso to cgo too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proposal #42477 asked for a way to apply conditional build tags to syso files (which have no source code to hold //go:build lines). We ended up suggesting that the standard answer should be to put the syso in its own package and then import that package from a source file that is itself conditionally compiled. A followup comment on that issue pointed out a problem that I did not understand until I tried to use this approach myself: the cgo build fails by default, because the link step only uses syso files from the current package. You have to override this explicitly by arranging to pass a “ignore unresolved symbols” flag to the host linker. Many users will not know how to do this. (I don't know how to do this off the top of my head.) If we want users to use this approach, we should make it work better. This CL does that, by including the syso files from dependencies of the current package in the link step. For #51940. Change-Id: I53a0371b2df17e39a000a645b7686daa6a98722d Reviewed-on: https://go-review.googlesource.com/c/go/+/402596 Reviewed-by: Ian Lance Taylor Run-TryBot: Russ Cox TryBot-Result: Gopher Robot --- src/cmd/go/internal/work/exec.go | 22 ++++++++++- src/cmd/go/testdata/script/link_syso_deps.txt | 54 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/link_syso_deps.txt diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 0b8e5d2330..6ecd4dcf2c 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -22,6 +22,7 @@ import ( "path/filepath" "regexp" "runtime" + "sort" "strconv" "strings" "sync" @@ -2991,7 +2992,26 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe return err } - linkobj := str.StringList(ofile, outObj, mkAbsFiles(p.Dir, p.SysoFiles)) + // Gather .syso files from this package and all (transitive) dependencies. + var syso []string + seen := make(map[*Action]bool) + var gatherSyso func(*Action) + gatherSyso = func(a1 *Action) { + if seen[a1] { + return + } + seen[a1] = true + if p1 := a1.Package; p1 != nil { + syso = append(syso, mkAbsFiles(p1.Dir, p1.SysoFiles)...) + } + for _, a2 := range a1.Deps { + gatherSyso(a2) + } + } + gatherSyso(a) + sort.Strings(syso) + str.Uniq(&syso) + linkobj := str.StringList(ofile, outObj, syso) dynobj := objdir + "_cgo_.o" ldflags := cgoLDFLAGS diff --git a/src/cmd/go/testdata/script/link_syso_deps.txt b/src/cmd/go/testdata/script/link_syso_deps.txt new file mode 100644 index 0000000000..7b458b0826 --- /dev/null +++ b/src/cmd/go/testdata/script/link_syso_deps.txt @@ -0,0 +1,54 @@ +# Test that syso in deps is available to cgo. + +[!gc] skip +[!cgo] skip + +# External linking is not supported on linux/ppc64. +# See: https://github.com/golang/go/issues/8912 +[linux] [ppc64] skip + +cc -c -o syso/x.syso syso/x.c +cc -c -o syso2/x.syso syso2/x.c +go build m/cgo + +-- go.mod -- +module m + +go 1.18 +-- cgo/x.go -- +package cgo + +// extern void f(void); +// extern void g(void); +import "C" + +func F() { + C.f() +} + +func G() { + C.g() +} + +-- cgo/x2.go -- +package cgo + +import _ "m/syso" + +-- syso/x.c -- +//go:build ignore + +void f() {} + +-- syso/x.go -- +package syso + +import _ "m/syso2" + +-- syso2/x.c -- +//go:build ignore + +void g() {} + +-- syso2/x.go -- +package syso2 -- cgit v1.2.3-54-g00ecf