[CMake] Mostly O.T. Need advice on Mac OS X compatibility version for libraries

E. Wing ewmailing at gmail.com
Thu Apr 3 18:17:01 EDT 2008


I think I recall reading Brad's notes on the bug report, and I think
they look good. I'm still trying to find time to dig through all my
correspondences on this issue. Below is something I posted to the
OpenSceneGraph mailing list. It talks about versioning at the dylib
level, but also talks about the other versioning mechanisms on OS X:


So I tend not to deal with versioning a lot, but OS X has several
different layers of versioning. At the Unix/Mach-O dylib level, there
is something similar to the soname on ELF. I believe this information
goes directly into the binary itself and not necessarily the file name
(relevant to frameworks), but we could create file versions for dylibs
like: libosg.1.9.2.dylib, which seems to be the common convention from
seeing what's in my /usr/lib. I think the format is fairly flexible,
but in practice, I generally I see the 3 point description. I believe
this is set using the build flag -current_version 1.9.2

However, there is a second flag available called
-compatibility_version which you are supposed to set to mark what
versions this library is backwards compatible. This seems to make
sense since you can use the above to mark the real version of the
library and this one to express what it's compatible with. I am not
completely sure of the usage, but I think it would look like
-compatibility_version 1.9 in this case if we wanted the entire 1.9.x
build to be compatible. Personally, looking at libosg.so.5 strikes me
as really weird because I would not casually associate 5 with 1.9.1.

At the next level (the framework level), frameworks support a notion
of multiple versioning, where the framework can actually hold multiple
versions of the same library. This works with a combination of
symbolic links, in conjunction with dylib versioning stuff above, and
system level understanding of the framework structure.

So for example, a Lua.framework I built myself looks like this
(keeping in mind that 5.0 and 5.1 broke compatibility):

Lua.framework/
  Versions/
      5.0/
          Headers/
              lua.h
              lualib.h
              lauxlib.h
          Lua (the dynamic library binary)
          Resources/
              Info.plist
      5.1/
          Headers/
              lua.h
              lua.hpp
              lualib.h
              lauxlib.h
              luaconf.h
          Lua (the dynamic library binary)
          Resources/
              Info.plist
       Headers (symbolic link to 5.1/Headers)
       Resources (symbolic link to 5.1/Resources)
       Lua (symbolic link to 5.1/Lua)

The idea is you can have one central framework that contains previous
versions for backwards compatibility for runtime. So if you built an
application against 5.0 (and 5.1 didn't exist yet), and then when 5.1
came out, if you deployed a new framework that was based on 5.1, you
could create a framework like the one above so any app that was built
against 5.0 could still run without breakage or recompiling. The
application will auto-magically know which library to pull at launch
time and the user will never know the difference.

Generally compiling a new application against an old version of the
library in the framework is not really supported as Xcode and the gcc
tool chain don't make it easy to specify you want to compile against
the old version. Basically you have to change the symlinks manually to
point to the older version. This is kind of a pain so most people
don't do it. Since developers are encouraged to do application
bundling with their own frameworks, multiple versioning is less of an
issue (though it still can be an annoying and painful issue).

I should also remind everybody that we are still waiting for CMake to
support building frameworks, and I don't expect framework versioning
to be a feature they support initially.


The next layer is the Info.plist. The system follows a lot of
conventions and putting version info into the Info.plist is one of
them. A lot of system tools and services know how to look through
these for data mining. I think these also might be used by the
official Apple package installers (which we don't use).


However, this is all about dynamic libraries, not plugins (bundles)
which are considered to be two entirely different entities in Mach-O.
Since a plugin is loaded at runtime, I'm not sure how versioning at
this level is useful, let alone work, since I would expect that it
would be hard for the OS to enforce anything in a reasonable way. It
would seem that osgDB itself would have to have code to deal with
this. As far as Mach-O is concerned, I believe the -current_version
and -compatibility_version flags are incompatible with plugins. And
since we build the plugins as flat .so files (extension is arbitrary
for bundles) instead of directories of files, there is no opportunity
for other schemes like Info.plist.


More information about the CMake mailing list