Pipes in apt-cache Output
Whilst pondering a thought-experiment related to installing Ubuntu packages (more on that in another post), I was
looking to understand the output of the apt-cache depends command. However, while doing a quick Google search, I found
that the top two results were wrong - one subtly (though sort-of right), the other blatently wrong. So, I did a little
digging to figure it out for myself.
Before we get to the right answer, let's start with those top two results. The first search result says:
As you guessed the | indicates "or". The control line normally shows foo | bar, but apt-cache depends appears to reformat it by showing each alternative on its own line and prefixing the first with the |. In other words, the pipe flags the preferred option and the next line is the alternative.
(emphasis mine)
This is actually pretty close, but not quite true, as we'll soon see.
The second search result says:
As for the |(pipe flag), between two packages in the list it denotes an "or" relationship between packages following each other. For example in the second example:
Depends: update-inetd
|Depends: openbsd-inetdupdate-inetd and openbsd-inetd are alternatives to each other yet the first one(update-inetd) is preferred.
This is actually relating the wrong entries. The | before openbsd-inetd indicates an or relationship with the
next line, which is not even shown in their quote. The previous line (update-inetd) is not at all relevant to the
| indicator.
Ok, so the first result was close, so let's see why it's not quite correct. To see it's shortcomings, we need to
consider a package dependency that has more than two alternatives. The first search result above actually includes
one such example in the dependencies for a solr-common package, but as that package is not readily available on my
current Ubuntu, I'll use the xorg package as an example instead.
So, here's an excerpt of the apt-cache depends xorg outout:
xorg
  Depends: xserver-xorg
  ...
  Depends: xorg-docs-core
 |Depends: gnome-terminal
 |Depends: xterm
    xterm:i386
  Depends: <x-terminal-emulator>
  ...
Where this example is interesting, and the existing explanations fall short, is the presence of multple consecutive
lines begining with a pipe (|) - lines 5 and 6. In this case we can see what's happening by looking at Depends line
in the apt show xorg output:
$ apt show xorg | grep '^Depends:'
Depends: xserver-xorg (>= 1:7.7+23ubuntu2), libgl1, libgl1-mesa-dri, libglu1-mesa, xfonts-base (>= 1:1.0.0-1), x11-apps, x11-session-utils, x11-utils, x11-xkb-utils, x11-xserver-utils, xauth, xinit, xfonts-utils, xkb-data, xorg-docs-core, gnome-terminal | xterm | x-terminal-emulator, xinput
Ok, that long line is bit hard to read, so let's split the line on commas (,) for better readbility:
$ apt show xorg | grep '^Depends:' | tr ',' '\n'
Depends: xserver-xorg (>= 1:7.7+23ubuntu2)
 libgl1
 libgl1-mesa-dri
 libglu1-mesa
 xfonts-base (>= 1:1.0.0-1)
 x11-apps
 x11-session-utils
 x11-utils
 x11-xkb-utils
 x11-xserver-utils
 xauth
 xinit
 xfonts-utils
 xkb-data
 xorg-docs-core
 gnome-terminal | xterm | x-terminal-emulator
 xinput
Now we can see that one of the dependencies is a set of three alternatives (on the highlighted line 17 above).
Narrowing the output of both commands (apt show xorg and apt-cache depends xorg) to just that dependency, we see:
gnome-terminal | xterm | x-terminal-emulator
versus:
 |Depends: gnome-terminal
 |Depends: xterm
    xterm:i386
  Depends: <x-terminal-emulator>
To generalise, the package dependency consisting of a list of alternatives A | B | ... | D | E becomes:
|A
|B
|...
|D
 E
So we can say that, for the apt-cache depends output, the pipe (|) indicator tells us that the alternative is
or'd with whatever lines follow it, up to, and including, the first entry without a pipe (|).
Now, how does that make the first linked article subtly wrong? There's two statement in the quote that are not quite right. The first one:
but apt-cache depends appears to reformat it by showing each alternative on its own line and prefixing the first with the |
It's subtle, but it doesn't only prefix the first. It prefixes all but the last. Of course, when there's only two alternatives, then the statements are affectively the same. But even in the example that the quote was discussing, there's more than two alternatives shown, so even in that case, the original statement was incorrect.
And the second statement (well, clause really):
the pipe flags the preferred option
Again, it's subtle, but not quite true. If there are n alternatives, then there will be n-1 alternatives with pipe indicators, but not all (if any) are "preferred". Though generally (not strictly) speaking, the earlier alternatives are sort-of "more preferred" than later ones, this is not strictly true. Indeed the Debian documentation1 never mentions any concept of "preferred" packages in dependency alternatives.
But since this first-one (or earlier ones) being preferred concept has some basis in fact, let's see how these alternatives are handled. There's some official documentation here2, but here's a brief summary of the parts I think are relevant to this "preference" idea.
- If one or more of the alternatives is already installed, then regardless of it's position in the alernatives ordering, the dependency is considered met, and no other alternatives are considered.
- For each alternative, in the order given, if the alternative can be satisfied, then it is considered.
- If the result of #2 being applied to all packages requested to be installed results in a conflict, then the next alternative is considered instead.
An important part of step 2, is not just checking alternative package version ranges, but also architecture. I think this is worth calling out, because a primary use case for dependency alternatives is handling scenarios where different packages are required for different architectures. From the Debian documentation1:
For example:
Depends: foo [i386], bar [amd64]becomes
Depends: foowhen the package is built on thei386architecture,Depends: barwhen the package is built on theamd64architecture, and omitted entirely in binary packages built on all other architectures.
So in this (common) scenario, it would be wrong to claim either alternative as "preferred" per se, and certainly not based on its position.
Well, that's probably enough rambling about pipes in apt-cache output. Hopefully you found it interesting (I did).
