Shared library (DLL) version numbering on Cygwin

based on
msg id 3D3A042BDOT3070107ATeceDOTgatechDOTedu
sent to png-implementATccrcDOTwustlDOTedu
on Sat, 20 Jul 2002 20:45:31 -0400

From: Charles Wilson cwilsonATeceDOTgatechDOTedu

A couple of definitions:

entry points are *externally accessible* functions or variables exported by the DLL. The interface is the set of all these exported functions and variables in a given version of the library.

Regarding the libPNG version macros in makefile.cygwin:

You ONLY need to bump PNGDLL if the new dll REMOVES an entry point that the old dll provided. If you ADD a new entry point, then the new dll is a drop in replacement for the old one, since the new one provides everything the old one did.

Of course, an app compiled against the new version, which uses the additional entry points, won't work with the old dll -- but nobody ever promised FORWARD compatibility, only BACKWARD compatibility.

This is the way cygwin DLL versioning works:

   1) follow the libtool versioning scheme
From http://www.gnu.org/software/libtool/manual.html#Versioning:
So, libtool library versions are described by three integers:
current
The most recent interface number that this library implements.
revision
The implementation number of the current interface.
age
The difference between the newest and oldest interfaces that this library implements. In other words, the library implements all the interface numbers in the range from number current - age to current.

Updating libtool versioning:
        
  1. Start with version information of 0:0:0 for each libtool library.
        
  2. Update the version information only immediately before a public
    release of your software. More frequent updates are unnecessary, and
    only guarantee that the current interface number gets larger faster.
        
  3. If the library source code has changed at all since the last
    update, then increment revision (c:r:a becomes c:r+1:a).
        
  4. If any interfaces have been added, removed, or changed since the
    last update, increment current, and set revision to 0.
        
  5. If any interfaces have been added since the last public release,
    then increment age.
        
  6. If any interfaces have been removed since the last public
    release, then set age to 0.

Never try to set the interface numbers so that they correspond to the
release number of your package. This is an abuse that only fosters
misunderstanding of the purpose of library versions. Instead, use the
-release flag (see Release numbers), but be warned that every release of
your package will not be binary compatible with any other release.


    2) On windows/cygwin, the DLLVER is 'c - a' (trust me, this is
correct, but it's easier to explain by example).

So, here's an example: the libtool version is 5:4:3, which indicates revision 4 of the implementation of interface 5, which happens to be backwards compatible with the three previous interface definitions. (ie. it is safe for applications linked against interfaces 5, 4, 3 and 2 to load the 5:4:3 dll at runtime).

So, let's look at the likely history of the mystery dll. I am following the c:r:a update rules described above.

oldest: interface definition 0, initial release:
0:0:0 (DLLVER = 0)
removed an entry point:
1:0:0 (DLLVER = 1) NOT backwards compatible!
but DLLVER does the right thing.
source code changed, but no added or removed entry points:
1:1:0 (DLLVER = 1)
more source code changes:
1:2:0 (DLLVER = 1)
 

In all of the previous three releases, 'c' - 'a' = DLLVER = 1.

removed an entry point (or renamed it):
2:0:0 (DLLVER = 2) This is INCOMPATIBLE.
(But look: 'c' - 'a' = 2, so the DLLVER does the right thing)
added a new function:
3:0:1 (DLLVER = 2) (this is BACKWARDS but not FORWARDS compatible.
However, the DLLVER 'c' - 'a' still is 2, so that is good.)
add eight more exported functions all at once
4:0:2 (DLLVER = 2)
add another function:
5:0:3 (DLLVER = 2)
source code changes, but no new interfaces:
5:1:3 (DLLVER = 2)
again:
5:2:3 (DLLVER = 2)
again:
5:3:3 (DLLVER = 2)
again:
5:4:3 (DLLVER = 2)

All of these DLLs with DLLVER = 2 (2:0:0, 3:0:1, 4:0:2, 5:0:3, 5:1:3, 5:2:3, 5:3:3, and 5:4:3) are all strictly backwards compatible: it is guaranteed that any newer DLL in the series can be loaded by an exe that was compiled against an older DLL in the series.

In 1.2.3, the DLLVER was 12. Let's pretend that was a 'c' - 'a' of 12, and that 'c' = 12 and 'a' = 0.

In [libpng] 1.2.4, you simply added some new functions -- but did NOT remove any. So, the new libtool number is 13:0:1 -- and DLLVER remains 12.

As a brief note about how this impacts on the makefile.cygwin in libpng (1.2.4 and higher), I'll mention that the makefile macro PNGDLL was changed to CYGDLL. Confusion over the reasons for the Cygwin library versioning style were the occasion for the posting by Chuck Wilson of the above message, and it was thought that "de-coupling" the versioning scheme of the MSVC build from that of Cygwin builds would be a good idea, since it appears that the two schemes are not the same.

-- Soren Andersen