Re: rust-*/librust-* arch:any vs. arch:all and cross-compilation support
On Wed, Feb 15, 2023 at 08:14:17PM +0100, Fabian Grünbichler wrote:
> > // This is the best but not ideal option for us.
> > //
> > // Currently Debian M-A spec has a deficiency where a package X that
> > // build-depends on a (M-A:foreign+arch:all) package that itself
> > // depends on an arch:any package Z, will pick up the BUILD_ARCH of
> > // package Z instead of the HOST_ARCH. This is because we currently
> > // have no way of telling dpkg to use HOST_ARCH when checking that the
> > // dependencies of Y are satisfied, which is done at install-time
> > // without any knowledge that we're about to do a cross-compile. It
> > // is also problematic to tell dpkg to "accept any arch" because of
> > // the presence of non-M-A:same packages in the archive, that are not
> > // co-installable - different arches of Z might be depended-upon by
> > // two conflicting chains. (dpkg has so far chosen not to add an
> > // exception for the case where package Z is M-A:same co-installable).
> > //
> > // The recommended work-around for now from the dpkg developers is to
> > // make our packages arch:any M-A:same even though this results in
> > // duplicate packages in the Debian archive. For very large crates we
> > // will eventually want to make debcargo generate -data packages that
> > // are arch:all and have the arch:any -dev packages depend on it.
> > https://salsa.debian.org/rust-team/debcargo/-/blob/master/src/debian/control.rs#L342
I guess that I was the one giving the advice that was recorded here
although I agree with Guillem that it is not recorded in a very
> > The chain is
> > rust-lscolors (arch:any) --BD--> librust-tempfile-dev (arch:any)
> > librust-tempfile-dev (arch:any) --D--> librust-remove-dir-all-0.7+default-dev (arch:any) --D--> librust-log-0.4+default-dev (arch:any) --D--> librust-value-bag-1.0.0+serde-dev (arch:any) --D--> librust-serde-fmt-1+default-dev (arch:all) --D--> librust-serde-dev (arch:any, but wrongly resolved!)
> > with librust-serde-fmt-dev being switched to arch:all, it will resolve to :amd64 instead of :i386 and in turn pull in its own dependencies librust-serde-1+std-dev & librust-serde-1-dev (both provided by librust-serde-dev) from amd64 (in addition to librust-serde-dev:i386, which is also part of the arch:any (build-)dependency tree of rust-lscolors itself, without the "hop" over librust-serde-fmt-dev).
The analysis is well done. Thank you. This is a real example of why we
do this annoying arch:any+m-a:same dance.
> > TL;DR: Is the switch to arch:all one that should be reverted in the face of it apparently breaking cross builds? Or is there another alternative (nowadays) that makes the "workaround" employed by debcargo no longer needed?
Yes, the switch to arch:all needs to be reverted at least partially.
No, there is no better way to achieve this. We extensively discussed
alternatives in Vaumarcus and reached the conclusion that no possible
interface was acceptable to dpkg. In essence, dpkg could automatically
track the architectures of packages (which would incur a recursive
dependency resolver onto dpkg) or architecture tracking could be a
manual thing, which would be far too annoying to end users. Therefore,
there is no sane alternative to the workaround.
> > Depending on feedback, the rust team would either ask Jonas to switch back his packages to arch:any, M-A:same (probably after bookworm, to prevent further fallout/need for RMs/.. during the freeze), or will evaluate whether switching to arch:all is an option for debcargo-managed packages as well, and which changes on the team tooling side are needed to avoid losing test coverage or increasing friction.
Technically, not all packages need to become arch:any+m-a:same. As you
correctly observed, the problem arises from non-rust dependencies in the
dependency tree. For instance, librust-typenum-dev has no dependencies.
As such, it could be changed to arch:all+m-a:foreign without incurring
problems to cross compilation. Likewise, librust-bitmaps-dev only
depends on librust-typenum-1+default-dev, which is provided by
librust-typenum-dev. Consequently, it could be converted to
arch:all+m-a:foreign as well. However, as soon as you reach C bindings,
such as librust-typenum-dev, the workaround to use arch:any+m-a:same is
needed. Then any library that transitively depends on any C binding also
needs the workaround. The problem here is that lower layers can
introduce bindings at a later time and thus break cross compilation
involving a higher level library. Whether a library can safely use
arch:all+m-a:foreign is dependent on its entire dependency tree. For
that reason, using arch:all+m-a:foreign is quite a good way to shoot
yourself in the foot.
Let me try to distill a rule of thumb from this: Whenever you require a
package to transfer an architecture constraint to downstream
dependencies (i.e. one of them likely is a C binding), arch:all package
cannot be used.
This actually is one of the m-a hinter rules. It suggests a conversion
from arch:any to arch:all+m-a:foreign whenever three conditions are met:
* The contents are equal on all release architectures.
* There are no maintainer scripts.
* All of the dependencies are marked m-a:foreign or annotated :any.
Could it be that Jonas picked up such hints and thus added m-a:foreign?
Then later a C binding was added to the mix, which broke the hint, but
the conversion wasn't reverted.
This suggests that the hinter should gain another condition to never
issue arch:all+m-a:foreign conversion hints for librust-*-dev packages.
Do you agree?