|
18.1 Introducing libltdl
Probably the best known and supported Unix run time linking API is
the `dlopen' interface, used by Solaris and GNU/Linux amongst
others, and discussed earlier in 17. Dynamic Loading. libltdl
is based on the `dlopen' API, with a few small differences and
several enhancements.
The following libltdl API functions are declared in
`ltdl.h':
- Function: lt_dlhandle lt_dlopen (const char *filename)
- This function brings the code from a named module into the address space
of the running program that calls it, and returns a handle which is used
by the other API functions. If filename is not an absolute
path, libltdl will search for it in directories named in the
`LTDL_LIBRARY_PATH' environment variable, and then in the standard
library directories before giving up. It is safe to call this
function many times, libltdl will keep track of the number of calls
made, but will require the same number of calls to `lt_dlclose'
to actually unload the module.
- Function: lt_ptr_t lt_dlsym (lt_dlhandle handle, const char *name)
- Returns the address of the named symbol in the module which returned
handle when it was
lt_dlopen ed. You must cast the returned
address to a known type before using it.
- Function: int lt_dlclose (lt_dlhandle handle)
- When you are finished with a particular module, it can be removed from
memory using this function.
- Function: const char * lt_dlerror (void)
- If any of the libltdl API calls fail, this function returns
a string which describes the last error that occurred.
In order to use these functions, you must #include <ltdl.h> for
the function prototypes, and link with `-lltdl' to provide the
API implementation. Assuming you link your application with
libtool , and that you call the necessary macros from your
`configure.in' (see section 18.2 Using libltdl), then any host specific
dependent libraries (for example, `libdl' on GNU/Linux) will
automatically be added to the final link line by libtool .
You don't limit yourself to using only Libtool compiled modules when you
use libltdl. By writing the module loader carefully, it will be able to
load native modules too--although you will not be able to preload
non-Libtool modules (see section 18.4 dlpreopen Loading. The loader in
Module Loader is written in this way. It
is useful to be able to load modules flexibly like this, because you
don't tie your users into using Libtool for any modules they write.
Compare the descriptions of the functions above with the API
described in 17.2 Module Access Functions. You will notice that they
are very similar.
Back-linking is the process of resolving any remaining symbols by
referencing back into the application that loads the library at runtime
-- a mechanism implemented on almost all modern Unices.
For instance, your main application may provide some utility function,
`my_function', which you want a module to have access to. There are
two ways to do that:
-
You could use Libtool to link your application, using the
`-export-dynamic' option to ensure that the global application
symbols are available to modules. When libltdl loads a module into an
application compiled like this, it will back-link symbols from the
application to resolve any otherwise undefined symbols in a module.
When the module is `ltdlopen'ed, libltdl will arrange for
calls to `my_function' in the module, to execute the
`my_function' implementation in the application.
If you have need of this functionality, relying on back-linking is the
simplest way to achieve it. Unfortunately, this simplicity is at the
expense of portability: some platforms have no support for
back-linking at all, and others will not allow a module to be created
with unresolved symbols. Never-the-less, libltdl allows you to do this
if you want to.
-
You could split the code that implements the symbols you need to share
with modules into a separate library. This library would then be used
to resolve the symbols you wish to share, by linking it into modules and
application alike. The definition of `my_function' would be
compiled separately into a library, `libmy_function.la'.
References to `my_function' from the application would be resolved
by linking it with `libmy_function.la', and the library would be
installed so that modules which need to call `my_function' would be
able to resolve the symbol by linking with `-lmy_function'.
This method requires support for neither back-linking nor unresolved
link time symbols from the host platform. The disadvantage is that when
you realise you need this functionality, it may be quite complicated to
extract the shared functionality from the application to be compiled in
a stand alone library.
On those platforms which support back-linking, libltdl can
be configured to resolve external symbol references in a dynamic module
with any global symbols already present in the main application.
This has two implications for the libltdl API:
-
There is no need to pass `RTLD_GLOBAL' (or equivalent) to
lt_dlopen as might be necessary with the native module loading
API.
-
You should be aware that your application will not work on some
platforms--most notably, Windows and AIX---if you rely on
a back-linking.
Similarly, there is no need to specify whether the module should be
integrated into the application core before lt_dlopen returns, or
else when the symbols it provides are first referenced. libltdl
will use lazy loading if it is supported, since this is a slight
performance enhancement, or else fall back to loading everything
immediately. Between this feature and the support of back-linking,
there is no need to pass flags into lt_dlopen as there is with
most native dlopen APIs.
There are a couple of other important API functions which you will
need when using libltdl:
- Function: int lt_dlinit (void)
- You must call this function to initialise libltdl before calling
any of the other libltdl API functions. It is safe to call this
function many times, libltdl will keep track of the number of calls
made, but will require the same number of calls to `lt_dlexit'
to actually recycle the library resources. If you don't call
`lt_dlinit' before any other API call, the other calls,
including `lt_dlerror', will return their respective failure codes
(`NULL' or `1', as appropriate).
- Function: int lt_dlexit (void)
- When you are done with libltdl and all dynamic modules have been
unloaded you can call this function to finalise the library, and recycle
its resources. If you forget to unload any modules, the call to
`lt_dlexit' will `lt_dlclose' them for you.
Another useful departure that the libltdl API makes from a
vanilla dlopen implementation is that it also will work correctly
with old K&R C compilers, by virtue of not relying on `void *'
pointers. libltdl uses lt_dlhandle s to pass references to
loaded modules, and this also improves ANSI C compiler's type
checking compared to the untyped addresses typically used by native
dlopen APIs.
|