Please don't edit this page. If you have a suggestion use my talk page.
Article: soname
editNotes
edit- No context explaining what soname is used for
- Versioning not explained (varies)
- How does this affect linker (will search for most recent unless file specified) and loader (uses
DT_NEEDED
which is set at link time fromDT_SONAME
) - Difference between filename, soname, and library name and how symlinks are generated to resolve these.
- The rules for soname might change on different systems. Linux uses ELF while OSX uses MACH-O.
Notes on shared object versioning
editI'm getting a little confused about shared object versioning because it seems inconsistant but I think I got it now.
On linux shared objects have a filename name traditionally matching the format lib(NAME).so.(MAJOR).(MINOR).(PATCH)
so that multiple versions can be installed side by side with no issues. It should be obvious that (NAME)
refers to the library name. However what about the ABI version components?
(MAJOR)
refers to the interface version. This increments when backwards incompatible changes are made (and the other two components are zeroed).(MINOR)
is incremented when compatible changes are made to the interface (e.g. adding new functions or structures) (the last component is zeroed when this happens).(PATCH)
is incremented when changes are made to the underlying code (like bug/security fixes) but the interface remains the same.
Now, it's possible to specify a relative or absolute path and filename to load in the ELF header for a binary but in most cases only the soname is specified which traditionally has the form lib(NAME).so.(MAJOR)
and a symlink is created with that name to point to the filename of most recent version of that shared object (I'm not sure what you would do if you needed to rely on the minor version given that a newer minor version would also be acceptable but can't be specified; I believe the loader doesn't parse the version string specifically).
What is confusing is when you hear people talking about a (CURRENT), (REVISION), and (AGE). Turns out this is part of libtool (not to be confused with ld - the GNU Linker which is what makes the shared objects) and you pass it this information so it can generate the shared object filename.
lib(NAME)_la_LDFLAGS=-version-info (CURRENT):(REVISION):(AGE)
Here are the rules:
(CURRENT)
whenever you make any change to the interface, compatible or not, this is incremented (set REVISION back to zero when this happens).(REVISION)
is incremented when changes are made to the underlying code (like bug/security fixes) but the interface remains the same (basically a direct correspondence to PATCH).(AGE)
is incremented when backwards compatible changes are made to the interface and zeroed when they aren't compatible (corresponds to MINOR.
On linux libtool generates the shared object filename using:
lib(NAME).so(CURRENT - AGE).(AGE).(REVISION)
All that's really happening is that instead of having a MAJOR version which only increments when breaking changes are made to the interface, each interface - backward compatible or not - is numbered in sequence so versions 4,5,6 are all compatible but will map to 4.0.0, 4.1.0, 4.2.0.
In other words, shared objects made by libtool still have the MAJOR.MINOR.PATCH scheme. It's just that the interfaces are conceptually numbered by the developers in a platform agnostic way because libtool is cross platform.
Reference links
edit- https://blog.flameeyes.eu/2010/10/linkers-and-names (further explanation)
- http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html (linux documentation)
- https://autotools.io/libtool/version.html (Libtool versioning discussion, libtool is cross platform)
- http://openbooks.sourceforge.net/books/wga/dealing-with-libraries.html
- https://www.usenix.org/legacy/publications/library/proceedings/als00/2000papers/papers/full_papers/browndavid/browndavid_html/ (minor versions use labels inside libraries to indicate compatability)