[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#749826: Documenting `Multi-Arch: foreign`



Hi Sean,

On Fri, Jun 06, 2025 at 02:22:04PM +0100, Sean Whitton wrote:
> Thanks very much.  Here's a review.

Thank you! With quite a bit of delay, here comes my update. I basically 
sat down the entire day processing your feedback and more interactive 
feedback from Nattie, Rhonda and Stuart trying to improve the text. I 
hope the end result eventually is good enough.

> > diff --git a/policy/ch-controlfields.rst b/policy/ch-controlfields.rst
> > index 3151816..0e7d489 100644
> > --- a/policy/ch-controlfields.rst
> > +++ b/policy/ch-controlfields.rst
> > @@ -1307,6 +1307,154 @@ This list is intentionally incomplete. You should consult the
> >  documentation of the tool or package in question for which keywords it
> >  defines and when they are needed.
> >
> > +.. _s-f-Multi-Arch:
> > +
> > +``Multi-Arch``
> > +~~~~~~~~~~~~~~
> > +
> > +A Debian installation may combine packages from multiple architectures.
> > +The ``Multi-Arch`` header enables individual packages to declare their
> > +support for this feature. It may occur only in the control file of a
> > +binary package or in the per-package fields paragraph of a source
> > +package control file.
> 
> I'm not sure what you mean by "per-package fields paragraph of a source
> package control file".

The correct term likely is "binary package sections of source package 
template control files". Does that make more sense to you?

> Also, "may" is a Policy magic word so shouldn't be used in the ways it
> is used in this paragraph.  I suggest "A Debian installation can" and
> "It must not occur in ..." or similar.

Agreed with avoiding "may". I've further extended and reworded this 
based on in-person feedback.

> > The semantics of permitted values are ``no``
> > +(default), ``foreign``, ``same`` and ``allowed`` as described
> > +individually.
> 
> Just
> 
>     The permitted values are ... .
> 
> is enough I think.

Split into two sentences and reworded.

> > +.. _s-f-Multi-Arch-no:
> > +
> > +``Multi-Arch: no``
> > +^^^^^^^^^^^^^^^^^^
> > +
> > +When satisfying a dependency (using ``Depends``, ``Pre-Depends``,
> > +``Provides``, ``Recommends``, or ``Suggests``), the architecture of the
> > +depender and the architecture of the dependee being thus marked are
> > +required to be equal. For negative dependency relations (``Breaks``,
> > +``Conflicts``, and ``Replaces``) the architecture does not have to match
> > +for the relation to take effect.
> 
> Simplify to:
> 
>     This means that a ``Depends``, ``Pre-Depends``, ``Provides``,
>     ``Recommends`` or ``Suggests`` relation between packages is
>     satisfied only by packages of the same architecture.  There is no
>     effect on ``Breaks``, ``Conflicts`` and ``Replaces``.

This is much easier to understand even though it subtly changes the 
connotation. Arguably, "no" has no effect on any of these relations as 
what we describe here is the default. The increased readability trumps.

> > Architecture-independent packages are
> > +treated as if they had the architecture value of the installed `dpkg`
> > +package.  Furthermore, multiple instances of a package with the same
> > +name and different architectures are not considered coinstallable.
> 
> Reorder:
> 
>     Furthermore, multiple instances of a package with the same name but
>     different architectures are not coinstallable.
>     Architecture-independent packages are treated as though they were
>     architecture-dependent with the same architecture as the version of
>     ``dpkg`` that's installed.

I agree with the reordering and partially with the rewording though I've 
partially kept the original wording based on feedback from others.

> > +``Multi-Arch: foreign``
> > +^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +A binary package may be marked ``Multi-Arch: foreign`` if the provided
> > +interfaces are independent of the architecture of the package. Any
> > +provided virtual packages (see :ref:`s-virtual`) inherit this property.
> > +Given this header value, dependencies on this package are considered
> > +satisfied even when the depender's architecture differs from the marked
> > +package.
> 
> Reorder:
> 
>     This means that the interfaces the package provides are independent
>     of its architecture, and that therefore it satisfies dependencies on
>     a package of this name regardless of the architecture of the package
>     declaring the dependency.  Any virtual packages provided ...

Now that's simpler. It also absorbs the "Given this header value, ...", 
so I deleted that part as well.

> > +There are five main areas that can contribute to the interface of a
> > +package and if any of them provides an architecture-dependent interface,
> > +a package must not be marked with ``Multi-Arch: foreign``.
> 
> Is "must" right?  I think it's okay, but just to check, this would
> always be an RC bug?

I argue that yes it would. Effectively issuing foreign where foreign is 
not appropriate is equivalent to a missing dependency and we treat many 
missing dependencies as RC bugs. Now there is some vagueness in that the 
package maintainer determines what interfaces are provided, so there 
still is room for discussion in such an RC bug. Conversely, using a 
private interface of a package (e.g. linking libbinutils is explicitly 
prohibited by its package description) may also be considered an RC bug.

> I think you need to talk about arch:all vs. arch:any here and how it is
> (and is not) the same as having architecture-independent interfaces.

I see how this can be suprirsing and added:

| Note that architecture-independent packages can provide
| architecture-dependent interfaces.

> > +- The installed files of a package: Architecture-dependent packages may
> > +  install different sets of files or files with different content for
> > +  multiple architectures and these differences may contribute to the
> 
> s/multiple/different/

Yes, thanks.

> > +  interface (e.g. an endianess-dependent database file).  For
> > +  architecture-independent binary packages, this aspect does not
> > +  apply.
> 
> See above -- arch:all vs. arch:any kind of comes out of nowhere here,
> and it's difficult to follow.  The reader thinks "wait a minute,
> architecture-independent binary packages would always be m-e:foreign,
> wouldn't they?  Oh, there must be edge cases?" and promptly gets lost.

Point taken. I hope the earlier addition resolves this.

> > +- The behavior of installed files of a package: When interfacing with
> > +  installed files by executing them, their behavior may contribute to
> > +  the provided interface.  For instance, interfacing with shared and
> > +  static libraries necessarily is architecture-dependent.  Whilst binary
> > +  executables generally differ with architectures, the exposed interface
> > +  (for example the command line interface, the content on standard
> > +  input/output, the way they process files) may be independent of the
> > +  architecture used to execute.  In that case, their interface may be
> > +  considered architecture-independent.
> 
> This is dificult to follow.
> I don't know what the first sentence means -- what is interfacing with
> installed files, and whose provided interface is it?

Yeah, we ended up rewriting significantly.

> > +- The dependencies of a package: A package may expose functionality of
> > +  other packages by depending on them. The ABI of a shared library
> > +  linked into an executable does not contribute to the interface, but
> > +  the behavior of library functions used may do so. Development packages
> > +  for shared libraries necessarily expose their own dependencies as
> > +  their interface since they enable others to link such libraries. An
> > +  extreme example is transitional packages, whose main purpose is to
> > +  expose the functionality of their dependency.
> 
> I think I follow you here but it's very dense.  Could you give some very
> simple examples to illustrate?

I sat down quite a bit on this with other DebConf attendees and we 
couldn't come up with sensible improvements here. Is it ok to pull the 
the-perfect-is-the-enemy-of-the-good card here?

> > +- Implicit and foreign dependencies of a package: Essential packages are
> > +  implicitly depended upon and need not show up in ``Depends``. Yet
> > +  their behaviour can be architecture-dependent. For instance, using
> > +  ``dpkg --print-architecture`` can be used to emit the native
> > +  architecture even though ``dpkg`` is marked ``Multi-Arch: foreign``.
> > +  Similarly, calling ``pkgconf`` (without a prefix) will behave
> > +  differently on different architectures as its search path is
> > +  architecture-dependent even though ``pkgconf-bin`` is considered
> > +  ``Multi-Arch: foreign``.
> 
> So why are these packages m-e:foreign?  This paragraph is difficult for
> someone to think about what it would mean for the package they maintain
> (which is our target audience).

I fear the answer is along the lines "in order to be practically 
useful". The whole "interface" part is an unwritten contract between 
package maintainers. In principle, we'd want to have an elaborate 
README.multiarch for these packages.

> > +The interfaces of a package are determined by its maintainer.  However,
> > +some packages might expose architecture-specific dependencies when other
> > +packages use them in a manner not intended by the maintainer.  This can
> > +happen when it is not clear which parts of the package are its
> > +interfaces.
> > +
> > +In such cases, where the package satisfies the criterion for
> > +``Multi-Arch: foreign`` but might expose architecture dependency,
> > +because it is not clear which parts of the package are its interfaces,
> > +the interfaces of the package should be described in the file
> > +``debian/README.multiarch``.
> > +
> > +Conversely, justifying the use of functionality that is not covered by
> > +its offered interface with a dependency on such a package is not
> > +allowed.
> 
> Can you reword this to use "should", "should not" etc. more often?

Where do you seem more opportunity to apply should? The one where I 
really want it, is the README.multiarch part.

> We're imposing requirements, here, so the normative status should be
> clear.  Also, there is a switch here from describing requirements on the
> maintainer of the m-e:foreign package to requirements on the maintainers
> of rdeps.  It would be good to be explicit about that: "Packages
> depending on a package marked m-e:foreign should not ..."

Rephrased in a way that explicitly references `README.multiarch` and 
uses must rather than should.

> > +``Multi-Arch: same``
> > +^^^^^^^^^^^^^^^^^^^^
> > +
> > +Multiple binary packages with the same name and version may be installed
> > +concurrently if all of them carry this header valued ``same``. Any set
> > +of packages with matching name and version being thus marked must
> > +support the following properties.
> >
> > +- All filenames that are present in multiple of these packages must
> > +  contain bit-identical content across architectures. [#]_
> > +
> > +  For files whose name is unique within this set, no such requirement
> > +  exists. Therefore, such packages usually install most of their files
> > +  below ``/usr/lib/${DEB_HOST_MULTIARCH}``.
> 
> For a set of packages which all have the same name and version, do we
> ever want to allow some of them to have m-a:same and some of them not?

For one thing, various tools disagree how to cope with that situation. 
dpkg requires that all packages to be co-installed carry m-a:same. That 
said, having policy require homogenity about the field is a good thing.

> If we disallow that then this can be worded more straightforwardly:
> 
>     This means that other packages with the same name and version, but
>     different architectures, are coinstallable.  All packages with this
>     name and version must be declared ``Multi-Arch: same``.  For a given
>     file name, if the package for one architecture installs a file
>     there, then the packages for every other architecture must either
>     install no file there, or a bit-identical file.  (Given this
>     restriction, such packages usually install most of their files below
>     ``/usr/lib/...``.)

Copied with slight adaptions. Thanks.

> > +- The maintainer scripts must be prepared to be configured or
> > +  deconfigured multiple times.
> 
> Isn't this already implied by the general requirements on maintainer
> scripts to be idempotent?

No. I can easily write an idempotent maitainer script that violates the 
subsequent elaboration about postrm.

> > In particular, ``postrm`` must consider
> > +  that another instance may still be present.
> 
> How about:
> 
>     In particular, any ``postrm`` script must not assume that all
>     instances of the package (i.e., instances for other architectures)
>     are all gone.

I don't see what aspect you are improving here and prefer the existing 
wording, because it is more focused on the key aspect. That said, "may" 
is not the right term there.

> > It may check the
> > +  ``DPKG_MAINTSCRIPT_PACKAGE_REFCOUNT`` environment variable set by
> > +  ``dpkg``.
> 
> What is the meaning of the value of this environment variable?

Please refer to man 1 dpkg.

> > +``Multi-Arch: allowed``
> > +^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +A package marked this way behaves as if it were annotated with the
> > +``no`` value except that a depender may now append ``:any`` to the
> > +package name in a dependency relation field. In that case, the
> > +dependency is considered satisfied even when the architecture of the
> > +depender differs from the dependee's. Dependencies carrying an ``:any``
> > +suffix can only be satisfied by packages marked ``Multi-Arch: allowed``.
> 
> As above, how about reordering it like this:
> 
>     This means the same as ``Multi-Arch: no`` except that a package
>     depending on this package may choose to treat it as though it were
>     marked ``Multi-Arch: foreign``.  This is done by appending ``:any``
>     to the name of the package in the dependency relation field.  For
>     example, where foo is ``Multi-Arch: allowed``, bar might have
>     ``Depends: foo:any (>= 1.0)``.  Then bar's dependency on foo is
>     satisfied even when bar and foo have different architectures.
> 
>     Only a ``Multi-Arch: allowed`` package satisfies a dependency with
>     the ``:any`` suffix.

Thank you. This indeed reads strictly better than the previous version 
to me.

> > +This value should be used rarely for cases where the package can be used
> > +in an architecture-dependent way or in an architecture-independent way
> > +and the decision of which applies is deferred to the depender. The most
> > +common use is with programming language interpreters that enable loading
> > +architecture-dependent plugins.
> 
> Can you avoid "should" here?  I don't think you intend to be normative.

Unless I misunderstand "should", that particular normative is intended 
here. I was even considering that usage of allowed must be discussed 
with d-devel beforehand just like the use of epochs.

> > +.. [#]
> > +   As an exception, the ``libc6`` package is marked ``Multi-Arch: same``
> > +   despite not fully complying with this requirement, because the
> > +   location of the dynamic loader is not universally unique and cannot
> > +   be changed without breakig ABI.
> 
> It would be helpful to scope "universally" I think.  Do you mean across
> architectures, or across GNU/Linux distributions, or what?

Changed.

Version 3 attached.

Helmut
diff --git a/policy/ch-controlfields.rst b/policy/ch-controlfields.rst
index 3151816..efb9aa9 100644
--- a/policy/ch-controlfields.rst
+++ b/policy/ch-controlfields.rst
@@ -1307,6 +1307,164 @@ This list is intentionally incomplete. You should consult the
 documentation of the tool or package in question for which keywords it
 defines and when they are needed.
 
+.. _s-f-Multi-Arch:
+
+``Multi-Arch``
+~~~~~~~~~~~~~~
+
+A Debian installation can combine packages from multiple architectures.
+The ``Multi-Arch`` header enables individual packages to declare their
+support for this feature, and influences the way dependencies are
+handled.  It can be declared in binary package sections of a source
+package template control file and in binary package control files.  The
+permitted header values are ``no`` (default), ``foreign``, ``same`` and
+``allowed``. Their semantics are described in the following sections.
+
+.. _s-f-Multi-Arch-no:
+
+``Multi-Arch: no``
+^^^^^^^^^^^^^^^^^^
+
+This means that a ``Depends``, ``Pre-Depends``, ``Provides``,
+``Recommends`` or ``Suggests`` relation between packages is satisfied
+only by packages of the same architecture.  There is no effect on
+``Breaks``, ``Conflicts`` and ``Replaces``.  Furthermore, multiple
+instances of a package with the same name but different architectures
+cannot be installed at the same time.  Architecture-independent packages
+are treated as though they had the architecture value of the installed
+``dpkg`` package.
+
+Note that, due to limitations in the archive management software, this
+value cannot currently be specified explicitly in binary package control
+files.  Instead, the field needs to be absent in order to imply its
+default value and ``debhelper`` discards it when transforming a source
+package control template.
+
+``Multi-Arch: foreign``
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This means that the interfaces the package provides are independent of
+its architecture, and that it therefore satisfies dependencies on a
+package of this name regardless of the architecture of the package
+declaring the dependency. Any virtual packages provided (see
+:ref:`s-virtual`) inherit this property.
+
+There are five main areas that can contribute to the interface of a
+package. If any of them provides an architecture-dependent interface, a
+package must not be marked with ``Multi-Arch: foreign``. Note that
+architecture-independent packages can reasonably provide
+architecture-dependentinterfaces and therefore architecture-indpenedent
+packages are not implicitly treated as ``Multi-Arch: foreign``.
+
+- The installed files of a package: Architecture-dependent packages may
+  install multiple sets of files or files with different content for
+  multiple architectures. These differences may contribute to the
+  interface (e.g. an endianness-dependent database file).  For
+  architecture-independent binary packages, this aspect does not apply.
+
+- The behavior of package's installed files: packages usually have
+  an expected way of having their files used. They may be executed or
+  interpreted. If the architecture of the package that installed them is
+  exposed in the process of their intended use, their interface is
+  considered architecture-dependent.
+
+  For instance, shared and static libraries are inherently
+  architecture-dependent. They therefore prohibit the use of
+  ``Multi-Arch: foreign`` unless they are not intended to be used by
+  other packages.  Whilst binary executables generally differ across
+  architectures, the exposed interface can be independent of the
+  architecture used to execute. Architecture exposure can happen via the
+  command line arguments, the data exchanged or the way they process
+  files. Last but not least, data files can have architecture-dependent
+  structure.
+
+- Maintainer scripts and triggers: A package can behave in an
+  architecture dependent way, when the behavior of maintainer scripts or
+  invoked triggers depends on the architecture. For instance,
+  byte-compiling source files into architecture-dependent bytecode
+  during ``postinst`` may turn the interface of a package
+  architecture-dependent.
+
+- The dependencies of a package: A package may expose functionality of
+  other packages by depending on them and thereby provide an
+  architecture-dependent interface itself. The ABI of a shared library
+  linked into an executable does not usually contribute to the
+  interface, but the behavior of library functions used may do so.
+  Development packages for shared libraries necessarily expose their own
+  dependencies as their interface since they enable others to link such
+  libraries. An extreme example is transitional packages, whose main
+  purpose is to expose the functionality of their dependency. Therefore,
+  transitional packages should copy the ``Architecture`` and
+  ``Multi-Arch`` field from their target.
+
+- Implicit and foreign dependencies of a package: Essential packages are
+  implicitly depended upon and need not be included in ``Depends``. Yet
+  their behaviour can be architecture-dependent. For instance, using
+  ``dpkg --print-architecture`` can be used to emit the native
+  architecture even though ``dpkg`` is marked ``Multi-Arch: foreign``.
+  Similarly, calling ``pkgconf`` (without a prefix) will behave
+  differently on different architectures as its search path is
+  architecture-dependent even though ``pkgconf-bin`` is considered
+  ``Multi-Arch: foreign``.
+
+The interfaces of a package are determined by its maintainer.  However,
+some packages might expose architecture-specific dependencies when other
+packages use them in a manner not intended by the maintainer.  This can
+happen when it is not clear which parts of the package are its
+interfaces.
+
+In such cases, where the package satisfies the criterion for
+``Multi-Arch: foreign`` but might expose architecture dependency,
+because it is not clear which parts of the package are its interfaces,
+the interfaces of the package should be described in the file
+``debian/README.multiarch``.
+
+Conversely, packages must not use other packages in ways declined by
+their ``debian/README.multiarch``.
+
+``Multi-Arch: same``
+^^^^^^^^^^^^^^^^^^^^
+
+This means that other packages with the exact same name and version, but
+different architectures, can be installed concurrently.  All those
+packages  must be declared ``Multi-Arch: same``.
+
+For a given file name, if the package for one architecture installs a
+file there, then the packages for every other architecture must either
+install no file there, or a bit-identical file.  Given this restriction,
+such packages usually install most of their files below
+``/usr/lib/${DEB_HOST_MULTIARCH}``.
+
+The maintainer scripts must be prepared to be configured or deconfigured
+multiple times. In particular, ``postrm`` must consider that another
+instance can still be present. It may check the
+``DPKG_MAINTSCRIPT_PACKAGE_REFCOUNT`` environment variable set by
+``dpkg``.
+
+``Multi-Arch: allowed``
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This means the same as ``Multi-Arch: no`` except that a package
+depending on this package may choose to treat it as though it were
+marked ``Multi-Arch: foreign``.  This is done by appending ``:any`` to
+the name of the package in the dependency relation field.  For example,
+where foo is ``Multi-Arch: allowed``, bar might have ``Depends: foo:any
+(>= 1.0)``.  Then bar's dependency on foo is satisfied even when bar and
+foo have different architectures.
+
+Only a ``Multi-Arch: allowed`` package satisfies a dependency with the
+``:any`` suffix.
+
+This value should be used rarely for cases where the package can be used
+in an architecture-dependent way or in an architecture-independent way
+and the decision of which applies is deferred to the depender. The most
+common use is with programming language interpreters that enable loading
+architecture-dependent plugins.
+
+Since removing this value tends to break reverse dependencies that
+employ ``:any``, uses of it should be discussed with
+*debian-devel@lists.debian.org* first.
+
 .. _s5.7:
 
 User-defined fields
@@ -1443,3 +1601,9 @@ details.
 
 .. [#]
    That is, the parts which are not the ``.dsc``.
+
+.. [#]
+   As an exception, the ``libc6`` package is marked ``Multi-Arch: same``
+   despite not fully complying with this requirement, because the
+   location of the dynamic loader is not unique across architectures and
+   cannot be changed without breakig ABI.

Reply to: