Packaging/Shared Libraries
From openSUSE
Contents |
Definitions
-
lib$NAME.so.*- a shared library, programs can depend on them, usually two files exist:
lib$NAME.so.$MAJOR lib$NAME.so.$MAJOR.$MINOR.$MICRO
where lib$NAME.so.$MAJOR is a symlink to lib$NAME.so.$MAJOR.$MINOR.$MICRO
-
SONAME- the name (query for it usingobjdump -x libfoo.so.1 | grep SONAME) a shared library is referred as by the dynamic loader. This matches the name of the shorter symlinklib$NAME.so.$MAJOR
-
lib$NAME.so- file used by the link editor (ld) to link executables, usually a softlink to the shared library file
-
lib$NAME.a- a static library, used by the link editor (ld) to statically link executables
-
lib$NAME.la- a libtool config file used for static linking with lib$NAME and dynamic loading with the libtool dynamic loader ltdl
Shared Library Naming and Packaging Policy
This policy is to provide naming conventions for packages containing shared libraries in /%_lib or /usr/%_lib. The main rationale is to allow for two (incompatible) versions of a shared library packaged as libfoo1 and libfoo2 installed at the same time without causing RPM conflicts.
Package Naming
- Shared libraries in
/%_libor/usr/%_libshall be packaged into RPMs whose name is"lib" + $NAME + $NUM
-
$NAMEis formed by cutting off the prefix "lib" and suffix ".so.*" from the SONAME - if
$NAMEends in a digit, a dash is inserted between$NAMEand$NUM. So it islibfoo1-0, notlibfoo10.
- Shared libraries may reside in
/%_libor/usr/%_libonly if there are development files packaged separately in a-develpackage to link against those libraries. The only exception to this is if the library is only used by one package, see (1) for details.
- Packages named
lib$NAME$NUMcontain only files namedlib*.so.*(no headers, no*.sofiles, no config files, nothing else). See below (3) for how to make exceptions work.
-
$NUMcontains only decimal digits and underscores.
-
$NUMis equal to the shared librarySONAMEnumber with dots replaced by underscores. Usually theSONAMEnumber is equal to the SO versionMAJOR. For example, if theSONAMEislibssl.so.0.9.7then theSONAMEnumber is0.9.7,$NUMwould be0_9_7in this case.
- All unsuffixed packages named
lib*end with$NUM
- Common suffixes include e.g.
-develor-debuginfo
- Packages with suffix
-develshould in general omit$NUMas-develpackages for different library versions usually conflict due to common header file names. See (4a) and (4b) for how it works otherwise.
Package Contents
-
lib$NAME$NUM.rpmeither contains exactly one shared library namedlib$NAME.so.*or it contains multiple shared libraries
-
lib$NAME$NUM.rpmmay only contain multiple shared libraries if the SO versions of all of them change at the same time always, in lockstep
- If depending on one of the contained libraries doesn't create a dependency on all or most other contained libraries, then it's preferred to not merge those libraries into one rpm, but leave them in their own rpm. Consider installation size. Exceptions are allowed here.
- Example:
libfoo.so.1is packaged inlibfoo1.rpm. Orlibbar.so.3, a part of the program suite PLONK 4.1, would be packaged intolibplonk41.rpm. The latter only makes sense if that rpm contains more than one shared library, which should be the exception, and can be done only if all shared libs therein will update their SO version in lockstep.
- Files needed to develop programs using shared libraries contained in
lib$NAME$NUM.rpmare packaged in a-develpackage (see (4a) and (4b) for cases that need to version this package). Those files includelib*.so,lib*.laand all headers. Optionally those files can also be placed in$NAME.rpm, in the case that it also comes with other tools or documentation. But _if_ there is a*-devel.rpmpackage then it contains alllib*.so,lib*.laand headers.
Best Practices
The following are guidelines for library packaging in general:
- Avoid packaging static libraries. You should use
--disable-staticconfigure option or, as a last resort, remove static libraries after%makeinstall. If in doubt, ask.
- If you package a static library in addition to a shared library, the static library should not be built with
-fPIC.
- If you package a static library without a corresponding shared library, the static library must be built with
-fPICusing--with-picconfigure option if available.
- Avoid packaging libtool config files (
.lafiles). In general they are not needed if you do not package a static library. If in doubt, ask.
- Shared libraries are not executable.
Exceptions
- (1) Shared libraries which are used solely and only by programs from the containing main package must be packaged into the main rpm, without a separate
lib$NAME$NUMrpm. The following must be true:- the shared libs are placed in a subdirectory of
/usr/%{_lib}, that subdirectory is named like the main package - no devel files for those shared libs are packaged anywhere, no
*.a, no*.so, no headers, no files which normally would belong into thelib$NAME-develpackage
- the shared libs are placed in a subdirectory of
- (2) A list of packages that are exempt from this policy is: (to be extended with explicit approval only)
-
glibc -
pam
-
- (3) If a shared library package
lib$NAME$NUMmust contain other files than shared libraries for whatever (approved!) reason, their names must be made unambiguous by putting them in a versioned directory or by versioning their names to not conflict with the rationale of this policy.
- (4a) If more than one version of a library is available from a single source repository even conflicting
-develpackages need to be suffixed to avoid multiple packages with the same rpm name. Proper conflicts need to be added in this case as well.
- (4b) If more than one version of a
-develpackage can be installed at the same time (for example because includes are packaged in a versioned directory and shared libraries have a versioned name likelibgtk1.so.1) the-develpackages should be suffixed with a number that allows identifying the version of the library (usually this is the same number as the shared library package suffix$NUM). So such a-develpackage would be namedlib$NAME$NUM-devel.
Rationale
That scheme makes it possible to install and use multiple shared libraries of the same base name, but different so-version (e.g. of older distribution in case there are programs requiring them). A discriminator needs to be part of the rpm name, as otherwise the update stack will be confused, and using some monotonically increasing number as that makes sense. A strict structure on rpm names will also help those writing quick&dirty tools.
From that follows that only files should be included therein, which aren't generating file conflicts later if installed together with another libbla*.rpm. Hence only lib*.so.* files are allowed in them. To ensure that no shared libraries creep in which aren't handled that way we disallow them to be in any package not named via these rules.
Effectively that creates a partition of all files into shared libs and others, and makes sure that no rpm contains files from both partitions.
Hints
You should remember the following while trying to conform to this policy:
- There is no reason why a -devel package cannot provide development files for multiple shared library packages.
- There is no need to have a binary package that matches the source package name. In fact, you should avoid renaming the source package for different versions as we prefer to only have a single package version in the source repository.
- Dependencies on the shared library package result either from automatic dependencies created by rpm on the shared libraries if they are used, or from the single other case, the library -devel package, which should require the shared library package with a properly versioned requires.
- This policy and its enforcement only is about shared library packages and shared libraries placed in
/%_libor/usr/%_lib. Rules that apply to other parts are only best practices and policies for them may exist elsewhere.
Examples
The simplest example is a source package which builds a single shared library and development files (the zlib package matches this example). The resulting binary packages should be named libz1 and libz-devel with the following contents (file list shortened),
libz1:
/lib/libz.so.1 /lib/libz.so.1.2.3
libz-devel:
/usr/lib/libz.so /usr/lib/libz.a /usr/include/zlib.h /usr/share/man/man3/zlib.3.gz /usr/share/doc/packages/zlib/algorithm.txt
A more complicated example is if apart from the library and the development files there are also executables and documentation (the bzip2 package matches this example). There should be four packages (file list shortened),
libbz2-1:
/lib/libbz2.so.1 /lib/libbz2.so.1.0.0
libbz2-devel:
/usr/include/bzlib.h /usr/lib/libbz2.so /usr/lib/libbz2.a
bzip2:
/usr/bin/bzip2 /usr/share/man/man1/bzip2.1.gz
bzip2-doc:
/usr/share/doc/packages/bzip2-doc/manual.ps.gz
where documentation may be either merged into the binary package bzip2 or the development package libbz2-devel if it is sufficiently small and related.
curl package matches this example). In this case the config or data files should be split into a separate package and the shared library package should require that. For example curl has the four packages libcurl4, libcurl-devel, curl and curl-ca-bundle (CA certificates required by libcurl4).
