On Wed, Feb 15, 2023, at 7:51 PM, Fabian Grünbichler wrote: > Hi, > > I'm writing this mail in order to get further input from knowledgeable, but > not directly involved DDs - mostly those involved with cross-building and > multi-arch matters.
sorry for the noise - now with correct CC of debian-cr...@lists.debian.org, instead of the mis-pasted d-cross@ .. > > Some background for those not familiar with rust packaging in Debian, skip > below for the actual examples and question. > > The debian-rust team uses a rather unified workflow to build a large amount > of rust library crates and a not-quite-as-large amount of binary > crates/applications. Each source package (rust-foo) corresponds to a single > crate (rust package) released on crates.io, building one or more > librust-foo*-dev binary packages that actually contain the crate's (patched) > source code, and in case of a "bin" crate shipping an actual > program/application, a binary package containing the compiled executable + > support files (which can have an arbitrary name - usually just that of the > program in question). The reason that the library packages ship source code > in a binary package is that rust doesn't (properly) support rust->rust > dynamic linking (yet), so each rust executable is statically linking all it's > rust dependencies. This has the side-effect that what are actually > (transitive) build-dependencies are encoded as a mix of build-dependencies > (direct) and regular dependencies (transitive dependencies of direct > build-dependencies). > > E.g., a crate foo that depends on a crate bar which in turn depends on a > crate baz will have the foo->bar relationship encoded as build-dependency > (rust-foo -> librust-bar-dev) and dependency (librust-foo-dev -> > librust-bar-dev, for packages [build-]depending on crate foo), while the > bar->baz dependency will *only* be encoded as regular dependency > (librust-bar-dev -> librust-baz-dev) in rust-foo's dependency tree. > > debcargo, the tool used by the Debian rust team to streamline the work of > transforming upstream crates into Debian source packages generates d/control > entries for librust-* binary packages qualified as arch:any and M-A:same, in > order to support cross compilation. This solution was suggested by dpkg > developers (Guillem?) according to the following comment left in the debcargo > source code: > > // 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 > > Some time ago, Jonas (CCed) started packaging rust crates in the same > "namespace" (src:rust-foo building bin:librust-foo-*) using a slightly > different approach, but in a *mostly* compatible fashion. More recently, > Jonas started switching over his rust packages from arch:any, M-A:same (like > the rust team's) to arch:all, M-A:foreign. There was no agreement between the > Debian rust team and Jonas whether this change is problematic and should be > reverted (or not), after a bit of discussion we agreed on getting feedback > from people more involved with cross-building efforts (hence this mail). > > One example of a working in practice (as in, the build doesn't fail), but > technically wrong (cross-)build (pulls in dependencies from wrong > architecture) can be found here: > > https://paste.debian.net/1270516/ > > 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). > > src:rust-lscolors was taken as minimal example bin crate here - many rust > binary crates are affected by this issue since a few crates which are part of > common dependency chains are maintained by Jonas and recently got switched to > arch:all (serde-fmt and ahash are the two most prominent). Note that much of > the rust ecosystem relies on a crate called bindgen to generate rust bindings > for C libraries, which in turn leverages clang under the hood, which > unfortunately makes those packages currently not cross-compilable because > libclang-common-14-dev is not co-installable on multiple architectures. > Many/most rust-*-sys packages and crates depending on those are practically > not cross-compilable for this reason (in addition to pulling in packages from > the wrong architecture via arch:all, as described above). > > Another example would be src:rust-hashbrown, which directly build-depends on > librust-ahash-0.7-dev which got switched to arch:all, cross building it on an > amd64 machine for i386 with > > DEB_BUILD_OPTIONS='' sbuild -c debian-unstable-amd64-sbuild -d unstable > --host i386 --profiles cross rust-hashbrown_0.12.3-1.dsc > > will pull in all librust-* packages from the wrong architecture (am64 instead > of i386): > > $ grep -E '^Get.*librust-serde' rust-hashbrown_0.12.3-1_i386.build > > Get:144 http://deb.debian.org/debian unstable/main amd64 librust-cfg-if-dev > amd64 1.0.0-1 [10.4 kB] > Get:145 http://deb.debian.org/debian unstable/main amd64 librust-libc-dev > amd64 0.2.139-1 [290 kB] > [ .. snip lots of librust-*-dev amd64 downloads ..] > Get:170 http://deb.debian.org/debian unstable/main amd64 > librust-version-check-dev amd64 0.9.4-1 [15.9 kB] > Get:171 http://deb.debian.org/debian unstable/main amd64 > librust-ahash-0.7-dev all 0.7.6-11 [477 kB] > > Reverting librust-ahash-0.7-dev to arch:any, M-A:same (and injecting both the > resulting amd64 and i386 package into the build env, to override the arch:all > one from the archive) makes the cross-build correctly only pull in > librust-*-dev packages from i386. > > 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? > > 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. > > Thanks for reading and any informed input, > Fabian