[OpenBSD]

How to handle shared libraries in the ports tree

Understanding shared libraries number rules

Shared libraries are a bit tricky for a variety of reasons. You must understand the library naming scheme: libfoo.so.major.minor.

When you link a program, the linker ld embeds that information in the created binary. You can see it with ldd. Later, when you run that program, the dynamic linker ld.so uses that information to find the right dynamic library:

So, this means that all libraries with the same major number and an equal or higher minor number must satisfy the binary API that the program expects. If they do not, then your port is broken. Specifically, it will break when users try to update their system.

The rules for shared libraries are quite simple.

Sometimes, it happens that a library is written as several files, and that internal functions happen to be visible to communicate between those files. Those function names traditionally begin with an underscore, and are not part of the API proper.

Note that the library naming scheme is ubiquitous on OpenBSD platforms, whether they be ELF or a.out.

Tweaking ports builds to achieve the right names

Quite a few ports need tweaks to build shared libraries correctly anyways. Remember that building shared libraries should be done with gcc -shared -fpic|-fPIC -o libfoo.so.4.5 obj1 obj2

Trying to rename the library after the fact to adjust the version number does not work: ELF libraries use some extra magic to set the library internal name, so you must link it with the correct version the first time.

On the other hand, remember that you can override Makefile variables from the command line, by using MAKE_FLAGS in the port's Makefile. This is quite valuable in, for instance, libtool-based ports, which provide one such version variable for each library they create.

The best way to handle libtool-based ports is to set USE_LIBTOOL=Yes. This activates the ports tree version of libtool, which handles most details automatically:

Try putting all user visible libraries into /usr/local/lib

As a rule, requesting the user to add directories to their ldconfig path is a very bad idea: all shared libraries that are linked directly to programs should appear in /usr/local/lib. However, it is quite possible to use a symbolic link to the actual library. You should understand the library lookup rules: So, let us assume you have two ports that provide two major versions of a given library, say qt.1.45 and qt.2.31. Since both ports can be installed simultaneously, to make sure a given program will link against qt.1, that library is provided as /usr/local/lib/qt/libqt.so.1.45, and programs will be linked using ld -o program program.o -L/usr/local/lib/qt -lqt. Similarly, a program that links with qt.2 will use the /usr/local/lib/qt2/libqt.so.2.31 file with ld -o program program.o -L/usr/local/lib/qt2 -lqt.

To solve those libraries at run-time, a link called /usr/local/lib/libqt.so.1.45 and a link called /usr/local/lib/libqt.so.2.31 have been provided. This is enough to satisfy ld.so.

It is an error to link a program using qt1 with ld -o program program.o -L/usr/local/lib -lqt. This code assumes the qt.2.31 is not installed, which is a wrong assumption.

Such tricks are only necessary in the rare cases of very pervasive libraries where a transition period between major versions must be provided. In general, it is enough to make sure the library appears in /usr/local/lib.

Writing library dependencies correctly

The new dependency code does need complete library dependencies. You must use make lib-depends-check to verify a port does mention all libraries it requires. You just separate library specs with commas like this: LIB_DEPENDS=gtk.1.2,gdk.1.2::x11/gtk+.

It is not an error to specify static libraries on a LIB_DEPENDS line as well. LIB_DEPENDS are fully evaluated at package build time: the resulting package will have library dependency information embedded as lines for ld.so that hold the actual major.minor number that was used for building, and nothing for static libraries.

You must provide RUN_DEPENDS as well if a port requires anything beyond a library proper. This will allow the port to build correctly on architectures that do not support shared libraries.

In fact, providing LIB_DEPENDS lines for static libraries is a good idea: this will simplify port update if a given dependency goes from a static library to a shared library.

LIB_DEPENDS lines must specify the same paths that are used for ld. For instance, the standard qt2 depends fragment says: LIB_DEPENDS+=lib/qt2/qt.2::x11/qt2, so that the lib depends line will be solved correctly. This allows the dependency checking code to do the right thing when multiple versions of the same library are encountered.

Updating ports correctly

So, when you update or add a port that involves shared libraries, a few details must be done right.
OpenBSD www@openbsd.org
$OpenBSD: libraries.html,v 1.6 2006/11/04 10:53:37 espie Exp $