Libtool has its own formal versioning system. It is not as flexible as some, but it is definitely the simplest of the more powerful versioning systems.
Think of a library as exporting several sets of interfaces, arbitrarily represented by integers. When a program is linked against a library, it may use any subset of those interfaces.
Libtool's description of the interfaces that a program uses is simple: it encodes the least and the greatest interface numbers in the resulting binary (first-interface, last-interface).
The dynamic linker is guaranteed that if a library supports every interface number between first-interface and last-interface, then the program can be relinked against that library.
Note that this can cause problems because libtool's compatibility requirements are actually stricter than is necessary.
Say libhello supports interfaces 5, 16, 17, 18, and 19, and that libtool is used to link test against libhello.
Libtool encodes the numbers 5 and 19 in test, and the dynamic linker will only link test against libraries that support every interface between 5 and 19. So, the dynamic linker refuses to link test against libhello!
In order to eliminate this problem, libtool only allows libraries to declare consecutive interface numbers. So, libhello can declare at most that it supports interfaces 16 through 19. Then, the dynamic linker will link test against libhello.
So, libtool library versions are described by three integers:
-age to current.
If two libraries have identical current and age numbers, then the dynamic linker chooses the library with the greater revision number.