#1084908 arch:all linux-libc-dev causes problems to architecture bootstrap

Package:
linux-libc-dev
Source:
linux-libc-dev
Description:
Linux support headers for userspace development
Submitter:
Helmut Grohne
Date:
2025-03-15 10:30:03 UTC
Severity:
normal
#1084908#5
Date:
2024-10-10 16:03:24 UTC
From:
To:
Hi,

Ben asked me to file a bug report with the linux package describing the
issues I see with linux-libc-dev being Arch:all.

A. Multi-Arch: foreign is a lie

linux-libc-dev declares being Multi-Arch: foreign, but it does not live
up to the involved promise and cannot. Earlier, a dependency on
linux-libc-dev:hurd-i386 would be considered unsatisfiable. With the
current setup, it is trivially satisfied even though that doesn't make
sense in any way. In a similar way, linux-libc-dev:sparc is now
considered satisfied. While that makes some sense, the actual package
does not ship any sparc files as 32bit sparc is dead. As such,
linux-libc-dev now makes dependencies look satisfied when they should
not be.

B. Inability to figure out what architectures linux-libc-dev supports

When linux-libc-dev was arch:any, architecture bootstrap would have to
cross build it. Now that it is arch:all, architecture bootstrap can use
the existing package. Sometimes. For release architectures and a few
more, it is good, but fore exotic and dead architectures (e.g. sparc),
one has to rebuild it with a modified configuration. In order to support
figuring out when a rebuild was required, Bastian added provides for
linux-libc-dev-$arch-cross due to my request. Neither of us saw how that
would break cross toolchains and these provides are now reverted as a
result. In any case, we're now back to the state where one cannot figure
out whether a rebuild is needed.

Ben asked me whether linux-libc-dev could simply support all relevant
architectures, but there often is a check&egg problem. The linux package
can only support architectures that dpkg knows about, but we want to
perform test bootstraps way before adding a triplet to dpkg and one of
the first things a test bootstrap does is building linux-libc-dev. So I
generally expect that linux-libc-dev can never provide support for all
architectures of interest and it shouldn't have to. Only once the
bootstrap is tested and the parameters are known do we want to file the
patches for a new architecture.

C. Inability to produce a linux-libc-dev-$arch-cross package

Now that linux-libc-dev-$arch-cross is no longer provided, dependencies
on it are no longer considered satisfied, but the toolchain packages
express dependencies on such packages. The architecture bootstrap
tooling does not use cross-toolchain-base and instead creates such
packages using dpkg-cross, but dpkg-cross cannot operate on arch:all
packages. Therefore, we can no longer turn linux-libc-dev:$arch into
linux-libc-dev-$arch-cross as is required by the cross toolchain.

I note that I do not have a good understanding why the change from
arch:any to arch:all was done. It does seem to reduce the cumulative
size consumed by binary .debs on mirrors and note that a similar effect
can be achieved by having a linux-libc-dev-common for the architecture
generic headers and a per-arch symlink farm in linux-libc-dev.

Ben, can you give some feedback on whether this report is useful for you
in moving things forward? I'm not sure how actionable this actually is
and welcome ideas on how architecture bootstrap should be adapted to
cope with the changed packages.

Helmut

#1084908#10
Date:
2024-10-19 13:35:21 UTC
From:
To:
Hi

What you describe here is a headers only library.  It is consensus
within Debian that those exist and are shipped as arch:all.  They don't
provide further architecture clues in the dependencies, but you need to
know or convey this information by failing to build.

Sparc is dead, so any Debian using Linux that does not support it any
longer will not provide the basic support to use it.  Sure, you could
hold on to an ancient linux-libc-dev, but this is then not longer
Debian.  Heck, we even consider running a mix of stable and unstable as
unsupported.  Why would we consider running a mix of
Debian-supporting-sparc and Debian-not-supporting-sparc a supportable
configuration?  Technically all of this can work, but still not
considered supported.

All the examples of yours will immediatelly fail to build anything with
it.  So what harm is done?

I have no idea what you are talking about.  I added the provides to
replace the existing cross packages with the functional identical
linux-libc-dev.  You where not involved in this at all.

I have to disagree.  With this setup, we can support architectures that
are neither known by dpkg nor dak.  This was not possible before and
required patching, aka making a derivative of the package.  You can
still patch and rebuild it how you want and inject that modified package
into your workflow.

But now you can have a port without hand patched linux that is built in
a non-standard way and relying on internal and unstable package API,
just be talking and getting it added to the package first.

This sounds like a bug in dpkg-cross, as it uses a not agreed on
interface to do it's work.

No, it can not.  We can not have arch:any -> arch:all dependencies
within the same source package this deep in the toolchain, especially as
those require = dependencies.

If we talk about size, please go to gcc, which ships unstripped
binaries parts of the time.  We don't need to talk about a highly
compressible 10 MB installed (up from 7 or so before) package.

Bastian

#1084908#15
Date:
2024-10-19 16:15:57 UTC
From:
To:
Hi Bastian,
...

This is practically untrue. Even with current unstable packages, the
sparc (32) bootstrap still succeeds. But then the use of sparc here was
an example rather than a concrete issue. linux-libc-dev claims to
support an architecture that it technically does not. That problem works
the same way for obsolete architectures (such as sparc) as it does for
new ones. The harm is being done. Quite simply, linux-libc-dev should
ensure that dependencies on it are not considered satisfied when the
architecture of the dependency is not practically supported.
...

Ok, you may see it that way (except for the "functional identical" part
that evidently doesn't hold). I don't think it matters much who caused
the mess we find ourselves in now. Let's skip the history bit.

Fair enough. Please add arc, cksy, mipsr6el, sh3, sparc, and
musl-linux-any. Thanks in advance.
...

I stand corrected. dpkg-cross actually can convert arch:all packages in
a reasonable way. Please consider item C a non-issue.

I read this as you saying that size was not a motivation to change
linux-libc-dev from Arch:any to Arch:all. But then, I do not understand
the benefits of the change and why it was done in the first place.
Obviously, we are still dealing with the fallout of an Arch:all
linux-libc-dev after more than half a year. This bug is evidence of that
dealing and demonstrates the significance of the downsides. Please
enlighten me about the benefits.

Helmut

#1084908#20
Date:
2024-10-23 23:29:31 UTC
From:
To:
[...]
[...]

Currently gencontrol.py runs dpkg-architecture to find the multiarch
triplet for each Debian architecture.  So it's not possible to add any
architecture that's unknown to dpkg in unstable.

Are you proposing to extend our config schema so we can define those
triplets within src:linux?

Do we really want to be on the critical path for the early stages of
defining a new architecture, including any renaming that might happen
before it's added to dpkg upstream?


Ben.

#1084908#25
Date:
2024-10-23 23:31:32 UTC
From:
To:
[...]
[...]

We would need to know the multiarch triplet for csky.

Ben.

#1084908#30
Date:
2024-11-29 06:48:12 UTC
From:
To:
Hi,

I skipped replying here earlier, because I felt like I would not add any
content. Stefano indicated that my impression was wrong. Hence replying
now.

In retrospect, the use of irony was not the best of moves here as it did
not add clarity to a discussion that was already heated. I'm sorry about
that.

Yes, exactly. Let me reiterate the reasons for why I prefer a different
solution here.

  * In general terms, the multiarch triplet is something that
    can change (and has changed) during the early phase of an
    architecture bootstrap.
  * When an architecture becomes available in toolchain packages, it is
    not clear whether it takes off. or1k very much looked like the next
    thing and now it is deleted. The story for tilegx is similar.
    Initially, riscv64 looked a lot like or1k. In not adding these to
    src:linux (and removing them later), we avoid a pile of unnecessary
    interaction. The excessive addition of architectures also interacts
    with #1081826.
  * It is very useful to locally add a new architecture and try a
    bootstrap to give feedback to upstreams as to what piece is missing.
    Not requiring src:linux to cooperate significantly speeds up this
    evaluation process.

I generally see src:linux as one of the later pieces relevant to
architecture cross bootstrap in the sense that while it is one of the
earliest packages needed for its headers, adding real support is often
delayed, because too many out-of-tree patches are required during the
initial bootstrap phase and thus everyone uses a self-built vendor
kernel there.

Automatically modifying src:linux is quite feasible. It has changed a
couple of times and now roughly looks like this:

    cat >debian/config.local/defines.toml >/dev/null <<EOF
    [[kernelarch]]
    name = '$kernel_arch'
      [[kernelarch.debianarch]]
      name = '$deb_arch'
    EOF
    ./debian/rules debian/rules.gen

This is quite mechanical and therein lies value. The difficulty now has
become that src:linux is the only package in the entire architecture
cross bootstrap that builds an architecture-dependent Arch:all package.
I have not yet found a good way to deal with this oxymoron.

Helmut

#1084908#35
Date:
2024-11-29 13:15:24 UTC
From:
To:
Hi Bastian (2024.10.19_09:35:21_-0400)

I think in most (all?) cases, they don't have architecture-specific
headers.  So that applying that consensus here may be not be that useful
to this case.

In general arch:all packages are preferable to arch:any, for the sake of
the size of the archive. But sometimes violating that is necessary.

It sounds like changing linux-libc-dev to arch:any could be helpful to
the cross-bootstrappers. That's something that happens outside the
archive, but is also part of the lifeblood of the project. Architectures
come and go, and we've been trying to make this process easier. It's one
of our strengths as a distribution.

I see a concern on a -common package: There are risks of arch:all and
arch:any packages building at different times on the buildds, and
possibly being published in separate mirror pushes. Leaving
build-essential uninstallable if the builds don't all succeed before the
arch-all package publishes.

If so, avoiding a -common package and having linux-libc-dev be pure
arch:any could be a reasonable solution? (At a cost of size)

Stefano

#1084908#40
Date:
2024-12-04 21:33:28 UTC
From:
To:
I don't understand what succeeds.  Because missing asm/* headers pretty
much makes it impossible to use anything from linux/*.  So the bootstrap
either have it's own headers or it will bail out if it tries to include
any kernel interface.

Can you please share the log for it?

Please make proper requests that are actionable.

- arc: in dpkg. bootstrap plan is where?
- cksy: not in dpkg, so not actionable, as triplet is not known.
  bootstrap plan is where?
- mipsr6el: which one do you mean?
  /usr/include/mipsisa64r6el-linux-gnuabi64?
- sh3: was never in debian. bootstrap plan?
- sparc: was removed years ago. bootstrap plan?
- musl-linux-any: how is that supposed to work?

Bastian

#1084908#45
Date:
2024-12-04 21:40:59 UTC
From:
To:
I did add that support first.
- Before the arch reaches anything related to Debian.  In this stage, it
  does not matter if the package it all or any, it can be patched.
- While it lives on -ports, but dak does not know about it.  In this
  stage, the package needs to be managed manually.
- While it lived on -ports and dak knows about.  In this stage, support
  can be added as arch:any.

Bastian

#1084908#50
Date:
2024-12-05 07:38:35 UTC
From:
To:
Hi Bastian,

This is the stage I am concerned about. You claim that it would not
matter whether the package is all or any, but my experience is
otherwise. With the exception of linux, the cross bootstrap tooling does
not build any Arch:all packages at all. Adding that support has not been
trivial and the way it is implemented still is violating internal
principles making its code fragile. In particular, for each combination
of package name and architecture, there would only be one binary package
- with the exception of linux where the would now be two (the unpatched
one from the archive and the patched one). I'd have to somehow remove
linux-libc-dev from an unstable amd64 mirror.

The all versus any also poses the problem that it becomes unclear
whether it has to be rebuilt. When it was :any, it always had to be
built, but given that its M-A:foreign is a lie and that we had to remove
the Provides, it is difficult to tell whether a rebuild is needed.

In now find it all surprising that we (at least Ben, Bastian and me)
agree on patching linux at this stage being the right approach. My
earlier impression was that Bastian preferred src:linux to participate
in this early stage of the bootstrap and I have expended mails to argue
otherwise, but that seems unnecessary now.

Instead, the question becomes how we can make that patching easy and the
disagreement becomes whether Arch:all makes that sufficiently easy. Even
though I cite building Arch:all as difficult in the bootstrap context,
the more pressing issue from my side is the inability to tell whether a
rebuild is needed by looking at package relations. Dealing with
unsatisfiable dependencies is something, I've developed ways to deal
with. Dealing with wrongly satisfied dependencies is a totally different
thing to me. As it stands, linux currently is the only package involved
in architecture cross bootstrap that produces false positives in
dependency satisfiability tests used for scheduling builds.

As an architecture enters -ports for the first time, it must have its
triplet included in dpkg. At that time, I think it is reasonable to ask
src:linux to include its headers. linux also is uploaded so frequently
that it will not be practically blocking any port progress. The step
that usually takes much time and convincing is getting an architecture
into dpkg. I do not see an Arch:all linux-libc-dev as being a hindrance
to these later stages.

Helmut

#1084908#55
Date:
2024-12-05 07:13:12 UTC
From:
To:
Hi Bastian,

I think much of what you are asking here is already answered in my reply
to Ben's followup.

You may find all the logs at
https://jenkins.debian.net/view/rebootstrap. Indeed, I missed the fact
that sparc is being patched in. And with patching it in, the complete
sparc bootstrap is still successful at this time. So yeah, sparc
immediately fails, but the main reason for that is linux and not some
other component.

I'm not gonna argue about sparc in particular. I'll just keep it alive
in rebootstrap as long as it is low effort. Once actual porting work
becomes necessary, I'll poke John Paul Adrian Glaubitz and if nothing
happens, discard sparc from my bootstrapping efforts.

So these architectures only served as examples here. mipsel and armel
look like they could be the next sparc.
actionable. The architectures referenced are work in progress to
different extents. You'll find more detail in my other mail.

Helmut

#1084908#60
Date:
2024-12-05 14:30:53 UTC
From:
To:
So this tooling does
- patch the source,
- _not_ change the version,
- build non-all?

This sounds broken, as it already relies on those packages producing
compatible all/non-all packages from two different sources.  Yes, in
practice this will work.

To make the double package problem easier, just change the version with
a sufficiently high epoch?

What kind of information can this dependency satisfiability test use?

Something like this?

| Provides:
|   linux-libc-dev-supports (= amd64-0),
|   linux-libc-dev-supports (= arm64-0),
|   linux-libc-dev-supports-multiarch (= aarch64-linux-gnu-0),
|   linux-libc-dev-supports-multiarch (= x86-64-linux-gnu-0),

Bastian

#1084908#65
Date:
2024-12-05 20:33:54 UTC
From:
To:
Hi Bastian,
into the version may technically work, but it feels really strange.
Earlier, I proposed encoding it into the provided package name like
linux-libc-dev-arm64-cross, but we all know how that went and I would
not have proposed it if I had seen how it broke other pieces. Still if
we were to just drop the "-cross" suffix and go for a very similar
version.

Provides: linux-libc-dev-amd64, linux-libc-dev-arm64, ...

In any of these cases, I can inject extra dependencies and have
dose-builddebcheck correctly determine whether the existing
linux-libc-dev satisfies what is needed.

As stated elsewhere, I still don't understand what we gained by
switching from Arch:any to Arch:all, but maybe I don't have to. A
solution that adds any of these Provides is what I'd call good enough in
practical terms for the purpose of bootstrapping.

Helmut

#1084908#70
Date:
2025-01-27 23:36:21 UTC
From:
To:
Hi Bastian:

We have two proposed provides schemes here, can we select one and add
it?

It would be helpful if this question could be answered. I think Matthias
was asking the same question in #1081826.

#1084908#75
Date:
2025-02-04 14:05:07 UTC
From:
To:
Hi

Something like simple providers is the easiest to do.

And I currently have no idea what to say, except to repeat myself.
Just a: this is wrong.  Not, what is broken by it, which makes it wrong.

Bastian

#1084908#80
Date:
2025-02-04 17:25:08 UTC
From:
To:
Hi Bastian (2025.02.04_14:05:07_+0000)
toolchain can determine which architectures are supported, and have a
target to Depend on.

The resolution of the issue brought to the tech-ctte requires figuring
out whether linux-libc-dev will take over providing these headers for
cross toolchain building, or whether cross-toolchain-base continues to
own the linux-libc-dev-${arch}-cross virtual package names (and provides
symlinks or duplicates of headers).

Thanks again for temporarily releasing the -cross virtual package names
while this is being discussed.

Before we can come to a conclusion on that, the elephant in the room
seems to be the question of the motivation for the migration to an
architecture all linux-libc-dev package. Let me try to distil this
question:

What is being gained by the transition to an architecture independent
package?

I see several pros and cons:

1. Advantage: Reduced overall disk usage on mirrors. 1x 2MiB
   package replaces per-architecture 2MiB packages. For context, the
   linux source produces ~1GiB of binaries per arch.
2. Advantage: This allows taking over linux-libc-dev-{arch}-cross, as
   virtual packages, reducing the need for cross-toolchain-base to
   duplicate linux source. And avoiding the need for cross-building to
   create this architecture: all binary packages in bootstrap.
3. Disadvantage: Users get ~40 extra files (totalling 100kiB) per
   architecture in Debian installed when they install linux-libc-dev.
   (bug #1081826)
4. Disadvantage: linux-libc-dev is installable on architectures that it
   doesn't actually support. No other package involved in
   cross-bootstrapping exhibits this. This only applies to architectures
   that aren't supported in the linux source package (helmut's A)
5. Disadvantage: cross-build tooling needs special heuristics to
   determine which architectures linux-libc-dev actually supports.
   (helmut's B) The Provides scheme above supports that.
6. Disadvantage: cross-build tooling doesn't currently support building
   architecture independent packages. And that's quite understandable,
   they should never need to be built unless we hit a situation like
   this.

Is there anything that we're missing here?

Item 6 leads to more complex questions like how do we handle versions of
such packages? That's the fundamental issue here and it's where it gets
gnarly. It begs the question of whether it reasonable to patch sources
and build a binary package without a bumped source version.

When I get to this point, my feeling is: Yes, cross-building is breaking
assumptions that the rest of the archive is making. But it's (until now)
been working fairly successfully while keeping the approach as simple as
possible. That sounds like on balance a good thing.

Should some of those assumptions be codified into policy, if we want
them? Probably.

The change of linux-libc-dev to architecture: all has the effect of
causing a lot of non-trivial work for people doing cross-bootstrapping.

The balance of advantages vs disadvantages does depend a bit on how
valuable you see item 2 being. I imagine Matthias doesn't see any value
there.

With the pros and cons that I've seen, the weight of balance seems to go
against the arch all package. This is why people keep asking what the
motivation for the change was. If you have other motivations, please
share them.

Obviously, undoing the change would be a lot of work for you and the
kernel team, and we wouldn't want to put that on you. I'm not pushing
you to reverse the decision.

It would help if everyone saw the impact that they were having on each
other, and was able to weigh the costs of each option. Once we have some
common ground, we can come to conclusions on the questions raised.

Thanks for taking the time to understand people's questions and answer
them.

Stefano

#1084908#85
Date:
2025-02-04 19:36:52 UTC
From:
To:
Hi
talking about.  It uses dpkg-cross, so is already using undefined
behavior of linux-libc-dev to do it's work.

My current version of it does this now:
| Provides: linux-libc-dev+support-debian+alpha (= ${binary:Version})

Yes.  It only supports architectures that are defined as Debian.

You mean "bootstrap tooling".  And yes, that part I missed in my initial
assessment,
arch:all linux-libc-dev.  But it might have failed with any change of
linux-libc-dev, because it relies of undefined behaviour.  So not a
disadvantage, but inherent instability of the dpkg-cross approach.

Or actually an advantage, because we can remove this instability and
reduce the complexity.

- It can provide headers for multiple architectures at the same time.
- It could even handle debian architectures mapping to multiple
  multiarch identifier and kernel arches (like hppa did kind of).
- debian-ports can import it without going through the manually handled
  "unreleased" part of their archive, even before ftp-master knows about
  an architecture.
- Reduces the part of the package API that is used in an undocumented
  way via dpkg-cross.

I don't know.  Right now the whole cross-building stuff violates the
policy, how would we clean this up?

I'm not even sure about arch:all.  We currently have no problems with
such packages only working on some architectures, if by dependency or
actually failing to work.

The impact was rather small.  Only two other parts where actually
affected, and none of them was our endusers.

The bootstrap stuff was affected, which I missed at first.  But is all
contained within two scripts that control everything.  And the rest of
that script is patching other packages quite havily already.

The other is cross-toolchain-base.  But here the impact is still
completelly unknown or at least does not show up within Debian.

Bastian

#1084908#90
Date:
2025-02-04 22:56:23 UTC
From:
To:
Hi,

In addition to all listed points, it also temporarily breaks
creating chroots for archs when the src:linux build for a given arch
and for arch:all end up in different dinstall windows. In this time
linux-libc-dev will not be visible to debootstrap. This behaviour
was observed f.e. on 2025-02-03.

Chris

#1084908#95
Date:
2025-03-04 16:47:37 UTC
From:
To:
Hi Bastian (2025.02.04_13:25:08_-0400)

I've had a few IRC conversations with both Bastian and Matthias about
what comes next. No conclusions yet, but the ground we've covered is:

Matthias is asserting that the -cross package namespace and
/usr/<triplet> sysroot directories belong to cross-toolchain-base. He'd
like to keep control of those packages.

Bastian is concerned that if both linux-libc-dev and
linux-libc-dev-*-cross provide linux headers in different paths they
should conflict with each other to avoid compilers accidentally sourcing
the wrong headers. linux-libc-dev installs in the usual multiarch
include directory (/usr/include/$ARCH/linux/). linux-libc-dev-*-cross
installs in the sysroot directory (/usr/$ARCH/include/linux/)

I would imagine that any conflicts like that would make
linux-libc-dev-*-cross practically uninstallable in any situation where
you'd need them (libc6-dev depends on linux-libc-dev).

So, we're back to trying to unpick this knot. The Techncial Committee is
not supposed to do design work, but I can see some possible ways out of
this.

I could see a scenario where linux-libc-dev-*-cross are tiny wrapper
packages, depending on linux-libc-dev and including symlinks from one
include directory to the other. I assume that wouldn't need the
Conflicts?

Or if the Conflicts were more version-targetted and allow linux-libc-dev
and linux-libc-dev-*-cross to co-install if they were built from the
same linux source version, would that be acceptable?

Do either of you have any thoughts on how we should figure this out?

Stefano

#1084908#100
Date:
2025-03-13 06:34:44 UTC
From:
To:
Yes.  An unversioned conflict would make the whole cross stuff
effectively uninstallable.

This is what I implemented as well, a symlink farm.  But those symlinks
needs to be belong to the same source package, as the set of required
symlinks change over time.  Or we are back at: requires conflicts.

I only consider symlinks to files acceptable.  With symlinks to
directories we are back in aliased directories land, with all the same
problems as merged-/usr.

Only if the *-cross maintainer is fine with updating it within a day,
every week or so for unstable, but even for stable or security.  So, not
possible, given that the existing conflict for the same reason against
glibc was only solved by NMU after a week or so.

Bastian

#1084908#105
Date:
2025-03-15 10:26:28 UTC
From:
To:
This conflict is currently escalating with the glibc side, see #1100544.
The glibc maintainers decided to not longer take up with it after the
release of trixie.

Bastian