Systems that desire to have one copy of a library installed in
one place suffer from the obvious problem of needing to expose
the union of functionality expected of all programs that depend
on them, either directly or indirectly.
Quite possibly! It's interesting to note that Linux has also
suffered from similar issues, exacerbated by libraries that
don't handle versioning well. Containers were the solution.
In article <10rao08$jv9$1@reader1.panix.com>,
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
Systems that desire to have one copy of a library installed in
one place suffer from the obvious problem of needing to expose
the union of functionality expected of all programs that depend
on them, either directly or indirectly.
There are at least three related, but different, use cases for shared >libraries on Unix-like systems:
1) Breaking up the operating system functionality into manageable-size
chunks of sensibly related material. This is the case that shared library >system designers are usually dealing with.
In some cases, notably macOS,
there are unspoken assumptions that this is _always_ the case, and shared >libraries have strings embedded in them that are copied into programs
built against them. The purpose of these strings is to tell the loader
where to find them. This works fine for libraries that have a canonical >location in the filesystem, but see below for ones that don't.
2) Breaking up applications into related chunks of functionality. This
can be helpful for organisation of code, for producing commercial >applications with subsets of "full" functionality, and so on. The
important point here is that the shared libraries are used by a single >application, or a suite of related applications. On macOS, this is
tackled by some special values in the embedded strings that tell the
loader to look in a filesystem location relative to the application. That >avoids the need for an application to have a fixed installation directory, >which implies that you can't have two different versions installed.
3) The fairly rare case of shared libraries intended as "software >components," to be used in many different applications, but which are
_not_ extensions to the operating system. Different applications may (and >likely do) have different versions of such libraries. On macOS, this
requires the application developer to modify the embedded strings in the >shared library before linking against it. Apple provide a tool for doing >this, but it's fairly obscure. The stuff I work on is in this category.
In article <10r5eor$b6q$1@reader1.panix.com>,
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
Quite possibly! It's interesting to note that Linux has also
suffered from similar issues, exacerbated by libraries that
don't handle versioning well. Containers were the solution.
Containers were designed to make it easy to run lots of different >applications on the same cloud servers. The companies that offer cloud >services don't want to solve such problems in the applications - it's
hard to blame them - and the SaaS companies have learned that their
customers want cheap, not good, software.
In article <memo.20260415122259.25212A@jgd.cix.co.uk>,
John Dallman <jgd@cix.co.uk> wrote:
In article <10rao08$jv9$1@reader1.panix.com>,
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
Systems that desire to have one copy of a library installed in
one place suffer from the obvious problem of needing to expose
the union of functionality expected of all programs that depend
on them, either directly or indirectly.
There are at least three related, but different, use cases for shared >>libraries on Unix-like systems:
I don't know what this has to do with what I wrote that you
quoted, but I'm afraid it's mostly incorrect.
The usual use cases for shared objects are a) sharing of text
and r/o data between processes linked against the same image,
b) providing fixes to libraries without having to relink
programs, and c) providing extensibility via the ability to
dynamically load shared objects into the address space of a
running process, find e.g. callable functions in those objects
by looking up entries in their symbol tables, and accessing
functionality provided by those objects by calling them (using
a well-defined ABI).
The last bit is a particularly powerful thing, and is how a
language interpreter can so easily take advantage of advanced
functionality that is not built-in or written in that language.
C.f. Python and its use in the data processing ecosystem, which
relies heavily on FFI calls to numerical analysis libraries
written in FORTRAN and C.
2) Breaking up applications into related chunks of functionality. This
can be helpful for organisation of code, for producing commercial >>applications with subsets of "full" functionality, and so on. The
important point here is that the shared libraries are used by a single >>application, or a suite of related applications. On macOS, this is
tackled by some special values in the embedded strings that tell the
loader to look in a filesystem location relative to the application. That >>avoids the need for an application to have a fixed installation directory, >>which implies that you can't have two different versions installed.
Huh. That's an interesting idea, but really it's something that
is facilitated by having shared objects, not something that was
(or is) a primary motivating factor for shared libraries in the
first place.
3) The fairly rare case of shared libraries intended as "software >>components," to be used in many different applications, but which are >>_not_ extensions to the operating system. Different applications may (and >>likely do) have different versions of such libraries. On macOS, this >>requires the application developer to modify the embedded strings in the >>shared library before linking against it. Apple provide a tool for doing >>this, but it's fairly obscure. The stuff I work on is in this category.
Actually, I'd posit that this is very common.
On Sat, 11 Apr 2026 14:49:21 -0700, Chris M. Thomasson wrote:
On 4/11/2026 2:37 PM, Lawrence D’Oliveiro wrote:
Shared library versioning is for dealing with backward-incompatible
changes to the ABI, not (necessarily) the API.
For example, some struct that is passed to a library call might
have some more fields added to it. The setup call sets those fields
to sensible defaults, so existing client code can be recompiled
against the new interface, linked against the new library version,
and continue to work unchanged.
Windows on Alpha, windows on MIPS, ect...
Windows doesn’t do shared library versioning though, does it?
Containers were designed to make it easy to run lots of different applications on the same cloud servers.
There are at least three related, but different, use cases for
shared libraries on Unix-like systems:
3) The fairly rare case of shared libraries intended as "software components," to be used in many different applications, but which
are _not_ extensions to the operating system.
3) The fairly rare case of shared libraries intended as "software >>>components," to be used in many different applications, but which are >>>_not_ extensions to the operating system. Different applications may (and >>>likely do) have different versions of such libraries. On macOS, this >>>requires the application developer to modify the embedded strings in the >>>shared library before linking against it. Apple provide a tool for doing >>>this, but it's fairly obscure. The stuff I work on is in this category.
Actually, I'd posit that this is very common.
Indeed. Thinks like libxml and libxsl, for example. Or openssl.
According to Dan Cross <cross@spitfire.i.gajendra.net>:
Maybe he's thinking of what's known as DLL Hell, which resultedQuite possibly! It's interesting to note that Linux has also
from Microsoft's neglecting to put a version number in DLL filenames. ... >>
suffered from similar issues, exacerbated by libraries that
don't handle versioning well. Containers were the solution.
That's kind of sad.
ELF library names include multi-part version numbers, with the plan being that
if the API changes you bump the major number, while if it's a bug fix or otherwise compatible you just bump the minor number.
Then you symlink the name
with the minor version number back to the name with just the major number so the
lists of imported library names just have the major number. This seems to work
OK on FreeBSD. What happens on linux?
One issue with this kind of version numbering is that adding a
feature is an API change but does not necessarily prevent
compatibility.
On 4/8/26 3:25 PM, John Levine wrote:
According to Dan Cross <cross@spitfire.i.gajendra.net>:
Maybe he's thinking of what's known as DLL Hell, which resultedQuite possibly! It's interesting to note that Linux has also
from Microsoft's neglecting to put a version number in DLL filenames. ... >>>
suffered from similar issues, exacerbated by libraries that
don't handle versioning well. Containers were the solution.
That's kind of sad.
ELF library names include multi-part version numbers, with the plan being that
if the API changes you bump the major number, while if it's a bug fix or
otherwise compatible you just bump the minor number.
One issue with this kind of version numbering is that adding a
feature is an API change but does not necessarily prevent
compatibility. This expression of versioning allows users
dependent on newer features to request the newer major version,
but it does not allow a newer major version to be used when it
is compatible (which might be desirable to reduce library bloat
or just not force installation of a different version).
While one could include a backward compatibility range (e.g.,
14-12 or 14b to indicate implementation of version 14 features
with compatibility back to version (b) to version 12), this
would still not maximize the compatibility support (which may
well not be a desirable goal).
Bug compatibility is also an issue as are leaky abstractions.
For ISAs, if early implementations use a stronger memory model
(or appear to do so), software could be written to exploit that
and be incompatible with future hardware.
One can also have performance (or non-time resource consumption) >incompatibilities, where the abstract architecture is the same
but some uses may be significantly impacted. E.g., an ISA might
initially not define a preferred register zeroing idiom and
software might choose any single cycle instruction that zeros a
register, but later implementations might only optimize one of
those options.
(A library function that moved from a O(nlogn) implementation to--- Synchronet 3.21f-Linux NewsLink 1.2
a O(logn) implementation with larger constant factor might
"break" software that calls the function N times rather than
once with an N-times larger list/array but be broadly considered
an improvement.)
Then you symlink the name
with the minor version number back to the name with just the major number so the
lists of imported library names just have the major number. This seems to work
OK on FreeBSD. What happens on linux?
I guess using minor version is tricky as it depends on the
specific implementation. The fourth bug fix version of Burzatt's >implementation of the 14th version of the libgood API would be
different than the fourth of Blinfoo's implementation. (There
could, in theory, be cooperation in minor versioning when a
common bug is discovered, but that seems unlikely.)
I guess the major version represents the abstract interface and
the minor version represents a "release number". With ISAs,
multiple resource-use targets (power-performance-area tradeoffs,
e.g.) might be pursued with the same abstract interface (the
original goal of Architecture), so specifying the interface
version number is not sufficient.
There may also be desirable for different implementations to
deprecate features (possibly where a feature technically works
but has poor resource use traits) or extend the lifetime of a
feature. E.g., an ISA version might specify that an opcode no
longer needs to be supported and can either generate an illegal
opcode exception or provide the legacy behavior while the
implementation could still claim to be of that version of the
ISA.
[I feel my mind is getting fuzzy, sleep is calling.]
On 4/8/26 3:25 PM, John Levine wrote:
According to Dan Cross <cross@spitfire.i.gajendra.net>:
Maybe he's thinking of what's known as DLL Hell, which resultedQuite possibly! It's interesting to note that Linux has also
from Microsoft's neglecting to put a version number in DLL filenames. ... >>>
suffered from similar issues, exacerbated by libraries that
don't handle versioning well. Containers were the solution.
That's kind of sad.
ELF library names include multi-part version numbers, with the plan being that
if the API changes you bump the major number, while if it's a bug fix or
otherwise compatible you just bump the minor number.
One issue with this kind of version numbering is that adding a
feature is an API change but does not necessarily prevent
compatibility. This expression of versioning allows users
dependent on newer features to request the newer major version,
but it does not allow a newer major version to be used when it
is compatible (which might be desirable to reduce library bloat
or just not force installation of a different version).
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,116 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 85:27:16 |
| Calls: | 14,305 |
| Files: | 186,338 |
| D/L today: |
647 files (184M bytes) |
| Messages: | 2,525,478 |