Hi Tianon,

On Fri, Sep 12, 2025 at 04:21:58PM -0700, Tianon Gravi wrote:
> Looking at this again, and I'm kind of concerned by how similar this
> new script is to
> https://salsa.debian.org/go-team/compiler/golang/-/blob/0b1574525525719281c84cfa55ec7ca7719be8d9/debian/helpers/goenv.sh
> which we already maintain in the compiler packages -- I bet there's
> some way we could make either the new script work for the
> bootstrapping use case or better would be the other way around?  That
> raises the question of which source package the script should live in.

There is another angle here. The proposed wrappers need to work without
using DEB_HOST_* environment variables as those are Debian-isms, but the
wrappers are supposed to be outside package building.

Effectively, we may avoid a dependency on dpkg-architecture at runtime
by calling it at build time and recording the output. So instead of
having one goenv.sh for all architectures, the script could be
interpolated per architecture and included in an Arch:any package. The
existing goenv.sh entry point may be kept for compatibility and may then
forward to the appropriately interpolated script selecting it via its
DEB_HOST_GNU_TYPE. So it's shuffling things around rather than
increasing maintenance cost.

But then when I talked to Mathias Gibbens in Brest, we basically agreed
that compatibility with gccgo was a minor concern given that it is
horribly outdated and that we might forget about those wrappers and have
dh-golang handle the environment setup. Then turn things upside down and
turn gccgo into a wrapper that reverses the process and turns
GOARCH/GOOS/GO386/GOARM back into a GNU triplet to call the right gccgo
executable when such a need arises (if ever).

> I think it would be pretty reasonable/easy to split that script into
> "things we need to set for bootstrapping" and "things we need to set
> for cross-building with Go", especially given I just removed a bunch
> of bootstrap-specific logic from it in my latest touching of it (while
> making src:golang-X.Y itself cross-buildable).

That gets us back to the question of where that script should live.
Basically any go package (including the compiler itself), would have to
transitively build-depend on this, so building this script should not
require a go compiler (to avoid a cycle). golang-defaults might be a
good fit here even though adding a binary package just for shipping a
script may feel odd.

> Maybe it does make sense to have a variant of that script that lives
> in every src:golang-X.Y?  I don't know, because there's very little in
> it right now that's specific to a particular version of Go (although
> it *has* had to have complicated logic that in the past, like when the
> value for GO386 had to change, and getting it right across the
> bootstrapping boundary was extra complicated).

That is a good alternative to golang-defaults, because it avoids the
aforementioned cycle and the duplication is limited to a few versions
all maintained by the same people (making it feasible to keep the copies
in sync).

> Personally, I'm not very convinced by any gccgo compatibility,
> especially since I don't think gccgo has kept/reasonably can keep up
> with modern Go versions very well (and in the meantime, Go has gotten

Seems like that's a consensus item then.

> I also need to admit that I don't actually understand the need for so
> many explicit package names -- is there some existing convention that
> will automatically install the correct package based on existing
> Build-Depends or something that warrants all this extra complexity?

Over the years, we have introduced a convention to handle "cross
toolchain dependency translation". Given a compiler supporting the
convention (e.g. gcc or gfortran), you may annotate your Build-Depends
as either COMPILER-for-build or COMPILER-for-host (both lacking :native
and :any). In the latter case, you are expected to prefix all compiler
invocations (even when building natively) with the GNU triplet (e.g.
x86_64-linux-gnu-gcc) and then you get object files for the explicitly
selected architecture. In the former case, you are expected to call the
compiler without a prefix and then you get object files for some
architecture that your CPU can actually execute without emulation. This
typically is the architecture of the dpkg package, but it may change
e.g. when cross grading.

The big question now becomes what the Multi-Arch field of golang-VER-go
should be. It presently is implicitly "no", but that means that you
cannot depend on a runnable go compiler. Keep in mind that :native is
not applicable to Depends. We may argue that it should be Multi-Arch:
foreign. Doing is a quite lax interpretation of the proposed policy
text, because it effectively means that invoking the go compiler without
exporting GOARCH/GOOS and so on would not be a supported interface, but
that's what is happening a lot presently. On the flip side, I see little
use cases for actually requiring the Go compiler executable to have a
particular architecture. Possibly, some packages cannot work with CGO,
which is practically required for any kind of cross compilation and
there we would want to force the Go compiler executable to be a host
architecture one (thus requiring CPU emulation to run it). If that is a
sensible use case, it should likely be Multi-Arch: allowed, but then we
got to update every single source package changing golang-go to
golang-go:native or golang-go:any (their effect is the same, but the
former is more explicit in Build-Depends).

Do you have an opinion here? I think the main two questions are:
 * Do we want to support selecting a Go compiler executable of a
   particular architecture?
   + If yes, it cannot be M-A:foreign.
 * Do we want to update the Build-Depends of every Go thing to enable
   cross compilation?
   + If no, it must be M-A:foreign.

There is a slightly more complex scheme that may be easier on the
consumer side:
 * Rename golang-VER-go to golang-VER-go-compiler (name TBD).
 * Mark the renamed golang-VER-go-compiler M-A:allowed.
 * Introduce a new, empyt Arch:any M-A:same package using the freed name
   golang-VER-go. It depends on golang-VER-go-compiler:any.
 * Move the golang-1.24-src dependency from golang-VER-go-compiler to
   golang-VER-go.
 * Do a similar thing in golang-defaults for golang-go.

Then the many packages that presently depend on golang-go would get the
native Go compiler. Many of them would cross build, because dh-golang
already exports the right environment variables. Those that really do
need a Go compiler executable for the host architecture (expected to be
rare and incompatible with cross compilation) could additionally depend
on golang-go-compiler (without :any or :native) to express this. This
scheme would thus allow answering the two questions above as yes and no
respectively.

If going that more complex route, we may add the interpolated goenv.sh
to the golang-VER-go package in an architecture-dependent path.

Whether to incur this additional complexity depends on whether we
anticipate any dependencies on a Go compiler executable of a particular
architecture. We may also go for M-A:foreign without the shuffling now
and do the shuffling later if such a need arises practically.

Helmut

Reply via email to