Multiarch Design

This is a release goal for release 1.0.

There are three high-level design aspects to this multiarch implementation: the filesystem hierarchy that primarily enables package coinstallability, control information documenting package coinstallability and dependency satisfaction, and coinstallability considerations in package management.

For reference, see the specification and other documentation for multiarch in Debian and Ubuntu.

Filesystem Hierarchy

For packages to be coninstallable with themselves (such that a user can have multiple architecture builds of one package installed simultaneously), all architecture-dependent files must be installed in architecture-dependent locations. The most straightforward way to do this is to embed architecture strings into filesystem paths.

Debian and Ubuntu do something similar to this. In a Debian library package that supports multiarch, shared object files are installed in /usr/lib/<triplet>, where <triplet> is a GNU system type.

The scope of Debian's and Ubuntu's multiarch work does not include coinstallable executable programs.

Such work, however, would help enable cross installation of packages. So a goal of this multiarch implementation is to support coinstallation of shared object files, header files, and executable programs.

There are two proposed filesystem hierarchies (see below) to support this.

Parts of the toolchain (especially the dynamic linker) need to be configured and/or patched to use multiarch library paths. Additionally, at least the native-architecture executable program directories have to be added to the PATH environment variable (set in libbb/messages.c and libbb/libbb.h in the BusyBox source as of versions 1.19.3 and 1.20.2).

Proposal 1: /usr Organized Primarily by Architecture

It may be useful to install all architecture-dependent files under /usr/<arch>, where <arch> is a distribution architecture string. The filesystem hierarchy would then look something like this:

/
 +- bin/
 |   +- core-linux-eglibc/
 |   +- cortexa8-linux-eglibc/
 |   \- native -> core-linux-eglibc
 +- lib/
 |   +- core-linux-eglibc/
 |   \- cortexa8-linux-eglibc/
 +- sbin/
 |   +- core-linux-eglibc/
 |   +- cortexa8-linux-eglibc/
 |   \- native -> core-linux-eglibc
 \- usr/
     +- core-linux-eglibc/
     |   +- bin/
     |   +- games/
     |   +- include/
     |   +- lib/
     |   +- sbin/
     +- cortexa8-linux-eglibc/
     |   +- bin/
     |   +- games/
     |   +- include/
     |   +- lib/
     |   +- sbin/
     +- bin/
     +- games/
     +- include/
     +- local/
     +- native -> core-linux-eglibc
     +- sbin/
     +- share/
     \- src/

Note that /usr/lib doesn't exist, as no architecture-independent files should be installed there.

BusyBox needs to be patched to set the PATH environment variable to /sbin:/sbin/native:/usr/sbin:/usr/native/sbin:/bin:/bin/native:/usr/bin:/usr/native/bin.

Proposal 2: /usr Organized Secondarily by Architecture

It may be cleaner and slightly more efficient to install architecture-dependent files within an architecture-dependent directory under otherwise standard paths. This is similar to how Debian and Ubuntu have designed their multiarch filesystem hierarchy. Such an organized filesystem hierarchy would look something like this:

/
 +- bin/
 |   +- core-linux-eglibc/
 |   +- cortexa8-linux-eglibc/
 |   \- native -> core-linux-eglibc
 +- lib/
 |   +- core-linux-eglibc/
 |   \- cortexa8-linux-eglibc/
 +- sbin/
 |   +- core-linux-eglibc/
 |   +- cortexa8-linux-eglibc/
 |   \- native -> core-linux-eglibc
 \- usr/
     +- bin/
     |   +- core-linux-eglibc/
     |   +- cortexa8-linux-eglibc/
     |   \- native -> core-linux-eglibc
     +- games/
     |   +- core-linux-eglibc/
     |   +- cortexa8-linux-eglibc/
     |   \- native -> core-linux-eglibc
     +- include/
     |   +- core-linux-eglibc/
     |   \- cortexa8-linux-eglibc/
     +- lib/
     |   +- core-linux-eglibc/
     |   \- cortexa8-linux-eglibc/
     +- local/
     +- sbin/
     |   +- core-linux-eglibc/
     |   +- cortexa8-linux-eglibc/
     |   \- native -> core-linux-eglibc
     +- share/
     \- src/

Note that this hierarchy is more consistent than is the hierarchy in proposal 1. That is, /bin and /usr/bin, for example, are both laid out the same.

BusyBox needs to be patched to set the PATH environment variable to /sbin:/sbin/native:/usr/sbin:/usr/sbin/native:/bin:/bin/native:/usr/bin:/usr/bin/native.

Control Information

New package control information will be needed to indicate whether a package is coinstallable with itself and to mark its purpose.

During build-time, there are two possible architectures for any dependent package:

During install-time, there are also two possible architectures for any dependent package:

Host-architecture packages should be coinstallable with themselves, and they should satisfy dependencies of the same architecture. For example, the dependency of libexpat.1-dev:cortexa8-linux-eglibc on libexpat.1 should resolve to a dependency on libexpat.1:cortexa8-linux-eglibc.

Build- and install-architecture packages need not be coinstallable with themselves, and they should satisfy dependencies of any architecture. For example, the build dependency of glib (built on core-linux-eglibc for cortexa8-linux-eglibc) on pkg-config should resolve to a build dependency on pkg-config:core-linux-eglibc.

Debian and Ubuntu specify such properties in a Multi-Arch control field. A value of same indicates that a package satisfies dependencies of the same architecture; a value of foreign indicates that a package satisfies dependencies of any architecture. We can implement something similar, perhaps even using the same terminology.

Logic to handle the new control information will need to be added to opkg and opkhelper (specifically oh-checkbuilddeps).

Special design considerations need to be given to install-time dependencies. Specific use case analysis can help here.

Architecture-Independent Files

Many packages provide architecture-independent files (configuration files, documentation, data, etc.). To the extent possible and feasible, these should simply be provided by architecture-independent packages (with names like *-common, *-data, or *-base).

If this is not possible in all cases, then some modifications to opkg will be necessary (reference counting, implicit "Breaks" relationships, etc.).