|
18.3 Portable Library Design
When partitioning the functionality of your project into libraries, and
particularly loadable modules, it easy to inadvertently rely on modern
shared library features such as back-linking or dependent
library loading. If you do accidentally use any of these features, you
probably won't find out about it until someone first tries to use your
project on an older or less featureful host.
I have already used the `-module' and `-avoid-version'
libtool linking options when compiling the libltdl module in the
last section, the others are useful to know also. All of these are used
with the `link' mode of libtool (`libtool
--mode=link'):
- `-module'
- This option tells
libtool that the target is a dynamically
loadable module (as opposed to a conventional shared library) and as
such need not have the `lib' prefix.
- `-avoid-version'
- When linking a dynamic module, this option can be used instead of the
`-version-info' option, so that the module is not subject to the
usual shared library version number suffixes.
- `-no-undefined'
- This is an extremely important option when you are aiming for maximum
portability. It declares that all of the symbols required by the target
are resolved at link time. Some shared library architectures do not
allow undefined symbols by default (Tru64 Unix), and others do not allow
them at all (AIX). By using this switch, and ensuring that all
symbols really are resolved at link time, your libraries will work on
even these platforms. See section 11.2.1 Creating Libtool Libraries with Automake.
- `-export-dynamic'
- Almost the opposite of `-no-undefined', this option will compile
the target so that the symbols it exports can be used to satisfy
unresolved symbols in subsequently loaded modules. Not all shared
library architectures support this feature, and many that do support it,
do so by default regardless of whether this option is supplied. If you
rely on this feature, then you should use this option, in the knowledge
that you project will not work correctly on architectures that have no
support for the feature. For maximum portability, you should neither
rely on this feature nor use the `-export-dynamic' option -- but,
on the occasions you do need the feature, this option is necessary to
ensure that the linker is called correctly.
When you have the option to do so, I recommend that you design your
project so that each of the libraries and modules is self contained,
except for minimal number of dependent libraries, arranged in a
directional graph shaped like a tree. That is, by relying on
back-linking, or mutual or cyclic dependencies you reduce the
portability of your project.
In the diagrams below, an arrow indicates that the compilation object
relies on symbols from the objects that it points to:
|
main .---> main main
| | | |
.----+----, | .----+----, .----+----,
v v | v v v v
liba libb liba libb liba<-----libb
| | | ^
v v v |
libc libc libc-------'
Tree: good Backlinking: bad Cyclic: bad
|
|