When I create a library on Linux, I use this method:
According to Wheeler, we have the real name
, the soname
and the linker name
:
Real name libfoo.so.1.2.3
Soname libfoo.so.1
Linker name libfoo.so
The real name
is the name of the file containing the actual library code. The soname
is usually a symbolic link to the real name
, and its number is incremented when the interface changes in an incompatible way. Finally, the linker name
is what the linker uses when requesting a library, which is the soname without any version number.
So, to answer your last question first, you should use the soname
, libhelloworld.so.1
, for the linker option when creating the shared library:
g++ ... -Wl,-soname,libhelloworld.so.1 ...
In this document, Kerrisk provides a very brief example on how to create a shared library using standard naming conventions. I think both Kerrisk and Wheeler are well worth a read if you want to know more about Linux libraries.
There is some confusion regarding the intent and purpose of each of the numbers in the real name
of the library. I personally think that the Apache Portable Runtime Project does a good job of explaining the rules for when each number should be incremented.
In short, the versioning numbers can be thought of as libfoo.MAJOR.MINOR.PATCH
.
PATCH
is incremented for changes that are both forwards and backwards compatible with other versions.MINOR
should be incremented if the new version of the library is source and binary compatible with the old version. Different minor versions are backwards compatible, but not necessarily forwards compatible, with each other. MAJOR
is incremented when a change is introduced that breaks the API, or is otherwise incompatible with the previous version. What this means is that PATCH
releases may only differ internally, for example in the way a function is implemented. Changing the API, the signature of public functions, or the interpretation of function parameters is not allowed.
A new MINOR
release may introduce new functions or constants, and deprecate existing functions, but may not remove anything that is externally exposed. This ensures backwards compatibility. In other words, a minor release 1.12.3
may be used to replace any other 1.12.x
or earlier version, such as 1.11.2
or 1.5.0
. It is not a drop in replacement for 1.16.1
though, since different minor versions are not necessarily forward compatible.
Any kind of change can be made with the release of a new MAJOR
version; constants may be removed or changed, (deprecated) functions may be removed, and of course, any changes that would normally increment the MINOR
or PATCH
number (though it might be worth it to backport such changes to the previous MAJOR
version also).
Of course, there are factors that can complicate this further; you might have developed your library so that the same file may hold multiple versions simultaneously, or you might use libtool
's convention of current:revision:age
. But that's a discussion for another time. :)