How RPM compares packages
The following is used by RPM to compare two packages (with the same name and comparable architectures) to see which is newer. Please note that this is not the exact algorithm, it is a human-readable simplification.
- The packages are compared to see if they have their Epoch field set. If a package doesn't have an Epoch field, it may be considered to have an Epoch equal to 0 or -1 (based on the version of RPM and the operation happening [some more details here ). The Epoch fields are then compared numerically, and the package with the larger number is considered newer. If the numbers are equal, it goes to step 2. Note: avoid negative epochs at all costs, and don't use Epochs equal to zero if possible. If you use 0 Epochs, know that it may be considered equal to no Epochs in some cases and different in others. Be prepared for the surprise!
- The packages' Version field is compared according to the following algorithm, called
rpmvercmp. The larger Version wins. If the Versions are decided equal, it goes to step 3.
- The packages' Release field is compared according to the
rpmvercmpalgorithm. The larger Release wins. If the Releases are decided equal, the packages are considered equal.
The rpmvercmp algorithm
rpmvercmp algorithm compares two labels (like the Version or the Release tag) to see which is newer.
In this algorithm, "digits" and "letters" are defined as ASCII digits ('0'-'9') and ASCII letters ('a'-'z' and 'A'-'Z'). Other Unicode digits and letters (like accented Latin letters) are not considered letters. ASCII letters and digits are called "alphanumeric" characters.
Please note that the algorithm's actions is undefined in some cases, in a ways may make the resulting comparisons stop working sanely (see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=178798 for an example where the order of the comparison is more important than the operands). To avoid these, make sure that all your labels start and end with alphanumeric characters. So while things like "1.", "+a", or "_" are allowed as labels, the result of such comparisons are undefined. For the exact (non-symmetric) algorithm, see
lib/vercmp.c in the RPM source code. The following algorithm is a simplification based on the version available in FC4, and is considered to be stable, as the last time it changed in any way was in January 2003.
- Each label is separated into a list of maximal alphabetic or numeric sections, with separators (non-alphanumeric characters) ignored. If there is any extra non-alphanumeric character at the end, that. So, '2.0.1' becomes ('2', '0', '1'), while ('2xFg33.+f.5') becomes ('2', 'xFg', '33', 'f', '5').
- All numbers are converted to their numeric value. So '10' becomes 10, '000230' becomes 230, and '00000' becomes 0.
- The elements in the list are compared one by one using the following algorithm. If two elements are decided to be different, the label with the newer element wins as the newer label. If the elements are decided to be equal, the next elements are compared until we either reach different elements or one of the lists runs out. In case one of the lists run out, the other label wins as the newer label. So, for example, (1, 2) is newer than (1, 1), and (1, 2, 0) is newer than (1, 2).
The algorithm for comparing list elements is as follows:
- If one of the elements is a number, while the other is alphabetic, the numeric elements is considered newer. So 10 is newer than 'abc', and 0 is newer than 'Z'.
- If both the elements are numbers, the larger number is considered newer. So 5 is newer than 4 and 10 is newer than 2. If the numbers are equal, the elements are decided equal.
- If both the elements are alphabetic, they are compared using the Unix
strcmpfunction, with the greater string resulting in a newer element. So 'b' is newer than 'a', 'add' is newer than 'ZULU' (because lowercase characters win in
strcmpcomparisons), and 'aba' is newer than 'ab'. If the strings are identical, the elements are decided equal.
Some random examples, to make sure you understand the
- '1.0010' is newer than '1.9' because 10 is more than 9.
- '1.05' is equal to '1.5', because both '05' and '5' are treated as the number 5.
- '1.0' is newer than '1', because it has one more element in the list, while previous elements are equal.
- '2.50' is newer than '2.5', because 50 is more than 5.
- 'fc4' is equal to 'fc.4', because the alphabetic and numeric sections will always get separated into different elements anyway.
- 'FC5' is older than 'fc4', because it uses uppercase letters.
- '2a' is older than '2.0', because numbers are considered newer than letters.
- '1.0' is newer than '1.fc4' because numbers are considered newer than letters.
- '3.0.0_fc' is the same as '3.0.0.fc', because the separators themselves are not important.