Project:Base/Alternatives
The packages in app-alternatives category symlink specific implementations of generic tools to their respective generic names. For example, app-alternatives/sh installs /bin/sh symlink. USE flags are used to select a specific implementation.
Users
Migration
Migration to app-alternatives/* providers of common system packages like awk, bzip2, gzip will occur for stable users shortly (bug #886017).
It is important that users do not have FEATURES="collision-protect" enabled during this upgrade to allow the orphaned symlinks to transition to a new owner package (in fact, this setting is discouraged for users in general, and users should instead use FEATURES="protect-owned" which is the same but allows collisions in packages between orphaned files).
A similar recommendation was issued during the libxcrypt migration.
Note that for the reasons described on this page, app-eselect/eselect-sh (bug #886021) and app-eselect/eselect-awk (bug #886019) are both now obsolete.
All of these changes mean that e.g. the popular pigz (bug #868648) & pbzip/lbzip2 (bug #868651) symlink functionality returns, just with a new method.
Preferences
Users may change the provider of an app-alternatives package by setting the appropriate USE flags in /etc/portage/package.use, or roll with the defaults if they prefer.
Why?
- eselect interacts poorly when controlling software a package might depend on as there's no way for ebuilds to correctly express which implementation they need (think e.g. yacc), but also a broken system can result from edge-cases because of its reliance on orphaned files. See bug #829309 for an example.
- Some packages which now use app-alternatives often previously relied on luck, like kbuild (bug #734354) where
virtual/yacc
caused confusing issues. - Controlling a symlink via PATH precedence led to both unpredictable behavior and was often incompatible with Merge-usr (bug #868312, bug #868318).
- It allows up-front configuration of a system via /etc/portage.
Developers
Alternatives vs. eselect
Alternatives are preferred over eselect whenever writing outside /etc is necessary. They guarantee that the installed symlinks are owned by the package manager, and managed using the same process as system upgrades, with all the reliability improvements that brings.
When is an alternative appropriate?
An alternative (app-alternatives/*
) package is the appropriate solution if all candidates providing it are completely compatible and install the same binaries.
eselect is still a valid solution for some problems, but it's important to not rely on it in ebuilds at all. A user should never have to run eselect in order to fix an emerge operation. eselect is for users to customise the system in a way that is adjacent to ebuilds and their environment.
A virtual is more appropriate if the tool is not user-facing or the candidates do not install the same binaries (reverse dependencies might just detect and handle appropriately depending on which provider is installed). The key difference between an alternative is that virtuals simply ensure one of several packages are installed rather than managing a symlink in e.g. /usr/bin.
split-usr support
Whenever the symlink is installed to /bin, yet at least one of the implementations normally resides in /usr/bin, special care needs to be taken to handle both split /usr and merged /usr systems. For this purpose, split-usr flag can be used to alter the installed paths, e.g.:
src_install() {
local usr_prefix=
use split-usr && usr_prefix=../usr/bin/
if use libarchive; then
dosym "${usr_prefix}bsdcpio" /bin/cpio
fi
}
Transition from unowned symlinks
Historically, symlinks such as /bin/sh were installed as part of the initial system and not owned by any package. For the transition period, it is a good idea to ensure that these symlinks remain even if the respective app-alternatives package is unmerged. This e.g. is accomplished in app-alternatives/sh using the following snippet:
pkg_postrm() {
# make sure we don't leave the user without /bin/sh, since it's not
# been owned by any other package
if [[ ! -h ${EROOT}/bin/sh ]]; then
ln -s bash "${EROOT}/bin/sh" || die
fi
}
Moving symlinks from original implementations
Other files such as /bin/cpio were originally installed by the default implementation. The original package needs to start installing the actual executable using a different name, and the symlink-to-be needs to be transitioned to the app-alternatives package.
Unfortunately, it is impossible to perform this transparently within the Gentoo packaging framework. The current solution is to add a pkg_postinst phase to the package installing the original implementation to temporarily restore the symlink being moved. This limits the time when the base executable is not provided to the period between merging the new version and running postinst.
For example, app-arch/cpio does:
pkg_postinst() {
# ensure to preserve the symlink before app-alternatives/cpio
# is installed
if [[ ! -h ${EROOT}/bin/cpio ]]; then
ln -s gcpio "${EROOT}/bin/cpio" || die
fi
}