When you use semantic versioning, a switch from libfoo.so.23 to libfoo.so.24 means that libfoo's API changed in an backwards-incompatible way.
Thus, one must not link against both libfoo.so.23 and libfoo.so.24.
Example:
Status quo:
- Executable
myexelinks againstlibfoo.so.23andlibbar.so.1 libbar.so.1itself also links againstlibfoo.so.23
Erroneous change:
libbar.so.1upgrades tolibfoo.so.24without incrementing its major version number
As a result, when myexe is invoked the dynamic linker now loads libfoo.so.23 and libfoo.so.24 (cf. ldd output) leading to one set of functions using backwards-incompatible symbols from libfoo.
How to protect against such an error?
That means: how do I tell the linker to error out in such a situation (at build-time and runtime)?
On Linux, the linker just warns about this at build time:
/usr/bin/ld: warning: libfoo.so.24, needed by libbar.so.1,
may conflict with libfoo.so.23
Is it possible to turn this into an link error?
(This warning doesn't show up at runtime.)
Other linkers on other Unices don't even warn about this at build-time.
It's possible to detect such a library version mismatch at runtime with a constructor function that is executed during library loading. For example:
#include <stdio.h>
#include <stdlib.h>
#define FOO_VERSION 23
int foo_version() { return FOO_VERSION; }
static void cons() __attribute__((constructor));
static void cons()
{
fprintf(stderr, "constructing foo (%d)\n", foo_version());
if (foo_version() != FOO_VERSION) {
fprintf(stderr, "foo.c: FOO_VERSION %d != foo_version() %d\n",
FOO_VERSION, foo_version());
exit(1);
}
}
But I would prefer a linker error at build-time/runtime. Ideally something that also shows up in ldd (as an error).