Go to the first, previous, next, last section, table of contents.
Libtool provides a small library, called `libltdl', that aims at hiding the various difficulties of dlopening libraries from programmers. It consists of a header-file and a small C source file that can be distributed with applications that need dlopening functionality. On some platforms, whose dynamic linkers are too limited for a simple implementation of `libltdl' services, it requires GNU DLD, or it will only emulate dynamic linking with libtool's dlpreopening mechanism.
libltdl supports currently the following dynamic linking mechanisms:
dlopen
(Solaris, Linux and various BSD flavors)
shl_load
(HP-UX)
LoadLibrary
(Win16 and Win32)
load_add_on
(BeOS)
libltdl is licensed under the terms of the GNU Library General Public License, with the following exception:
As a special exception to the GNU Lesser General Public License, if you distribute this file as part of a program or library that is built using GNU libtool, you may include it under the same distribution terms that you use for the rest of that program.
The libltdl API is similar to the dlopen interface of Solaris and Linux, which is very simple but powerful.
To use libltdl in your program you have to include the header file `ltdl.h':
#include <ltdl.h>
The last release of libltdl used some symbols that violated the POSIX namespace conventions. These symbols are now deprecated, and have been replaced by those described here. If you have code that relies on the old deprecated symbol names, defining `LT_NON_POSIX_NAMESPACE' before you include `ltdl.h' provides conversion macros. Whichever set of symbols you use, the new api is not binary compatible with the last, so you will need to recompile your application in order to use this version of libltdl.
Note that libltdl is not threadsafe, i.e. a multithreaded application
has to use a mutex for libltdl. It was reported that GNU/Linux's glibc
2.0's dlopen
with `RTLD_LAZY' (which libltdl uses by
default) is not thread-safe, but this problem is supposed to be fixed in
glibc 2.1. On the other hand, `RTLD_NOW' was reported to introduce
problems in multi-threaded applications on FreeBSD. Working around
these problems is left as an exercise for the reader; contributions are
certainly welcome.
The following types are defined in `ltdl.h':
lt_ptr
is a generic pointer.
lt_dlhandle
is a module "handle".
Every lt_dlopened module has a handle associated with it.
lt_dlsymlist
is a symbol list for dlpreopened modules.
This structure is described in see section Dlpreopening.
libltdl provides the following functions:
lt_dlinit
has been successfully called.
Return 0 on success, otherwise the number of errors.
lt_dlopen
is able to open libtool dynamic
modules, preloaded static modules, the program itself and
native dynamic libraries.
Unresolved symbols in the module are resolved using its dependency
libraries (not implemented yet) and previously dlopened modules. If the
executable using this module was linked with the -export-dynamic
flag, then the global symbols in the executable will also be used to
resolve references in the module.
If filename is NULL
and the program was linked with
-export-dynamic
or -dlopen self
, lt_dlopen
will
return a handle for the program itself, which can be used to access its
symbols.
If libltdl cannot find the library and the file name filename does not have a directory component it will additionally search in the following search paths for the module (in the order as follows):
lt_dlsetsearchpath
and lt_dladdsearchdir
.
Each search path must be a colon-separated list of absolute directories,
for example, "/usr/lib/mypkg:/lib/foo"
.
If the same module is loaded several times, the same handle is returned.
If lt_dlopen
fails for any reason, it returns NULL
.
lt_dlopen
, except that it tries to append
different file name extensions to the file name.
If the file with the file name filename cannot be found
libltdl tries to append the following extensions:
This lookup strategy was designed to allow programs that don't
have knowledge about native dynamic libraries naming conventions
to be able to dlopen
such libraries as well as libtool modules
transparently.
NULL
is returned.
NULL
if no errors have occurred since initialization
or since it was last called.
NULL
, then all previously registered
symbol lists, except the list set by lt_dlpreload_default
,
are deleted. Return 0 on success.
lt_dlpreload
. Note that this function does
not require libltdl to be initialized using lt_dlinit
and
can be used in the program to register the default preloaded modules.
Instead of calling this function directly, most programs will use the
macro LTDL_SET_PRELOADED_SYMBOLS
.
Return 0 on success.
#include <ltdl.h> int main() { /* ... */ LTDL_SET_PRELOADED_SYMBOLS(); /* ... */ }
If you use `lt_dlopen (NULL)' to get a handle for the running binary, that handle will always be marked as resident, and consequently cannot be successfully `lt_dlclose'd.
lt_dlerror
.
malloc
and free
, by default,
but you can set them to any other functions that provides equivalent
functionality. However, you must not modify their values after calling
any libltdl function other than lt_dlpreopen_default
or the macro
LTDL_SET_PRELOADED_SYMBOLS
.
dlopen
edLibtool modules are like normal libtool libraries with a few exceptions:
You have to link the module with libtool's `-module' switch, and you should link any program that is intended to dlopen the module with `-dlopen modulename.la' so that libtool can dlpreopen the module on platforms which don't support dlopening. If the module depends on any other libraries, make sure you specify them either when you link the module or when you link programs that dlopen it. If you want to disable see section Library interface versions for a specific module you should link it with the `-avoid-version' switch. Note that libtool modules don't need to have a "lib" prefix. However, automake 1.4 or higher is required to build such modules.
Usually a set of modules provide the same interface, i.e, exports the same symbols, so that a program can dlopen them without having to know more about their internals. In order to avoid symbol conflicts all exported symbols must be prefixed with "modulename_LTX_" (`modulename' is the name of the module). Internal symbols must be named in such a way that they won't conflict with other modules, for example, by prefixing them with "_modulename_". Although some platforms support having the same symbols defined more than once it is generally not portable and it makes it impossible to dlpreopen such modules. libltdl will automatically cut the prefix off to get the real name of the symbol. Additionally, it supports modules which don't use a prefix so that you can also dlopen non-libtool modules.
`foo1.c' gives an example of a portable libtool module. Exported symbols are prefixed with "foo1_LTX_", internal symbols with "_foo1_". Aliases are defined at the beginning so that the code is more readable.
/* aliases for the exported symbols */ #define foo foo1_LTX_foo #define bar foo1_LTX_bar /* a global variable definition */ int bar = 1; /* a private function */ int _foo1_helper() { return bar; } /* an exported function */ int foo() { return _foo1_helper(); }
The `Makefile.am' contains the necessary rules to build the module `foo1.la':
... lib_LTLIBRARIES = foo1.la foo1_la_SOURCES = foo1.c foo1_la_LDFLAGS = -module ...
Using the lt_dlmutex_register()
function, and by providing some
appropriate callback function definitions, libltdl can be used in a
multi-threaded environment.
Because libltdl is inherantly recursive, it is important that the locking mechanism employed by these callback functions are reentrant, or else strange problems will occur.
lt_dlerror()
.
A function of this type must be registered with the library in order for it to work in a multi-threaded context. The function should store any error message passed in thread local storage.
When regeistered correctly this function will be used by
lt_dlerror())
from all threads to retrieve error messages for the
client.
NULL
function addresses, or else all
NULL
to return to single threaded operation.
Some of the internal information about each loaded module that is maintained by libltdl is available to the user, in the form of this structure:
lt_dlinfo
is used to store information about a module.
The filename attribute is a null-terminated character string of
the real module file name. If the module is a libtool module then
name is its module name (e.g. "libfoo"
for
"dir/libfoo.la"
), otherwise it is set to NULL
. The
ref_count attribute is a reference counter that describes how
often the same module is currently loaded.
The following function will return a pointer to libltdl's internal copy of this structure for the given handle:
NULL
on failure.
Furthermore, in order to save you from having to keep a list of the handles of all the modules you have loaded, these functions allow you to iterate over libltdl's list of loaded modules:
lt_dlforeach
.
As soon as func returns a non-zero value for one of the handles,
lt_dlforeach
will stop calling func and immediately return 1.
Otherwise 0 is returned.
NULL
, and the next one on subsequent calls.
If place is the last element in the list of loaded modules, this
function returns NULL
.
Of course, you would still need to maintain your own list of loaded module handles to parallel the list maintained by libltdl if there are any other data that you need to associate with each handle for the purposes of your application. However, if you use the following API calls to associate your application data with individual module handles as they are loaded there is actually no need to do that. You must first obtain a unique caller id from libltdl which you subsequently use to retrieve the data you stored earlier. This allows for different libraries that each wish to store their own data against loaded modules to do so without interfering with one another's data.
lt_dlerror()
.
For example, to correctly remove some associated data:
lt_ptr stale = lt_dlcaller_set_data (key, handle, 0); if (stale == NULL) { char *error_msg = lt_dlerror (); if (error_msg != NULL) { my_error_handler (error_msg); return STATUS_FAILED; } } else { free (stale); }
NULL
if there is none.
The preceding functions can be combined with lt_dlforeach
to
implement search and apply operations without the need for your
application to track the modules that have been loaded and unloaded:
int my_dlcaller_callback (lt_dlhandle handle, lt_ptr key_ptr) { struct my_module_data *my_data; my_data = lt_dlcaller_get_data (handle, (lt_dlcaller_id) *key_ptr); return process (my_data); } int my_dlcaller_foreach (lt_dlcaller_id key) { lt_dlforeach (my_dlcaller_callback, (lt_ptr) &key); }
Sometimes libltdl's many ways of gaining access to modules are not
sufficient for the purposes of a project. You can write your own
loader, and register it with libltdl so that lt_dlopen
will be
able to use it.
Writing a loader involves writing at least three functions which can be
called by lt_dlopen
, lt_dlsym
and lt_dlclose
.
Optionally, you can provide a finalisation function to perform any
cleanup operations when lt_dlexit
executes, and a symbol prefix
string which will be prepended to any symbols passed to lt_dlsym
.
These functions must match the function pointer types below, after
which they can be allocated to an instance of lt_user_dlloader
and registered.
Registering the loader requires that you choose a name for it, so that it
can be recognised by lt_dlloader_find
and removed with
lt_dlloader_remove
. The name you choose must be unique, and not
already in use by libltdl's builtin loaders:
lt_dlopen
ing of preloaded static modules.
The prefix "dl" is reserved for loaders supplied with future versions of libltdl, so you should not use that for your own loader names.
The following types are defined in `ltdl.h':
lt_module
is a dlloader dependent module.
The dynamic module loader extensions communicate using these low
level types.
lt_dlloader
is a handle for module loader types.
lt_dlloader_data
is used for specifying loader instance data.
lt_dlopen
API use it, you need to instantiate one of these
structures and pass it to lt_dlloader_add
. You can pass whatever
you like in the dlloader_data field, and it will be passed back as
the value of the first parameter to each of the functions specified in
the function pointer fields.
lt_dlloader
module
loader. The value set in the dlloader_data field of the struct
lt_user_dlloader
structure will be passed into this function in the
loader_data parameter. Implementation of such a function should
attempt to load the named module, and return an lt_module
suitable for passing in to the associated lt_module_close
and
lt_sym_find
function pointers. If the function fails it should
return NULL
, and set the error message with lt_dlseterror
.
lt_dlseterror
and return non-zero.
lt_dlseterror
and return NULL
if lookup fails.
dlloader_data
field of the lt_user_dlloader
. If non-NULL
,
the function will be called by lt_dlexit
, and
lt_dlloader_remove
.
For example:
int register_myloader (void) { lt_user_dlloader dlloader; /* User modules are responsible for their own initialisation. */ if (myloader_init () != 0) return MYLOADER_INIT_ERROR; dlloader.sym_prefix = NULL; dlloader.module_open = myloader_open; dlloader.module_close = myloader_close; dlloader.find_sym = myloader_find_sym. dlloader.dlloader_exit = myloader_exit; dlloader.dlloader_data = (lt_user_data)myloader_function; /* Add my loader as the default module loader. */ if (lt_dlloader_add (lt_dlloader_next (NULL), &dlloader, "myloader") != 0) return ERROR; return OK; }
Note that if there is any initialisation required for the loader, it must be performed manually before the loader is registered -- libltdl doesn't handle user loader initialisation.
Finalisation is handled by libltdl however, and it is important
to ensure the dlloader_exit
callback releases any resources claimed
during the initialisation phase.
libltdl provides the following functions for writing your own module loaders:
NULL
), else immediately before the
loader passed as place. loader_name will be returned by
lt_dlloader_name
if it is subsequently passed a newly
registered loader. These loader_names must be unique, or
lt_dlloader_remove
and lt_dlloader_find
cannot
work. Returns 0 for success.
{ /* Make myloader be the last one. */ if (lt_dlloader_add (NULL, myloader) != 0) perror (lt_dlerror ()); }
lt_dlerror
.
{ /* Remove myloader. */ if (lt_dlloader_remove ("myloader") != 0) perror (lt_dlerror ()); }
NULL
, and the next one on subsequent calls. The handle is for use with
lt_dlloader_add
.
{ /* Make myloader be the first one. */ if (lt_dlloader_add (lt_dlloader_next (NULL), myloader) != 0) return ERROR; }
NULL
, if the identifier is not found.
The identifiers which may be used by libltdl itself, if the host architecture supports them are dlopen(9), dld and dlpreload.
{ /* Add a user loader as the next module loader to be tried if the standard dlopen loader were to fail when lt_dlopening. */ if (lt_dlloader_add (lt_dlloader_find ("dlopen"), myloader) != 0) return ERROR; }
lt_dlloader_next
or lt_dlloader_find
. If this function fails,
it will return NULL
and set an error for retrieval with
lt_dlerror
.
dlloader_data
of PLACE, as
obtained from lt_dlloader_next
or lt_dlloader_find
. If
this function fails, it will return NULL
and set an error for
retrieval with lt_dlerror
.
lt_dlerror
. Pass in a suitable diagnostic message for return by
lt_dlerror
, and an error identifier for use with
lt_dlseterror
is returned.
If the allocation of an identifier fails, this function returns -1.
int myerror = lt_dladderror ("Doh!"); if (myerror < 0) perror (lt_dlerror ());
lt_dlerror
interface. All of the standard errors used by libltdl are declared in
`ltdl.h', or you can add more of your own with
lt_dladderror
. This function returns 0 on success.
if (lt_dlseterror (LTDL_ERROR_NO_MEMORY) != 0) perror (lt_dlerror ());
Even though libltdl is installed together with libtool, you may wish to
include libltdl in the distribution of your package, for the convenience
of users of your package that don't have libtool or libltdl installed.
In this case, you must decide whether to manually add the ltdl
objects to your package, or else which flavor of libltdl you want to use:
a convenience library or an installable libtool library.
The most simplistic way to add libltdl
to your package is to copy
the source files, `ltdl.c' and `ltdl.h', to a source directory
withing your package and to build and link them along with the rest of
your sources. To help you do this, the m4 macros for autoconf are
available in `ltdl.m4'. You must ensure that they are available in
`aclocal.m4' before you run autoconf -- by appending the contents
of `ltdl.m4' to `acinclude.m4', if you are using automake, or
to `aclocal.m4' if you are not. Having made the macros available,
you must add a call to the `AC_LIB_LTDL' macro to your package's
`configure.in' to perform the configure time checks required to
build `ltdl.o' correctly. This method has problems if you then try
to link the package binaries with an installed libltdl, or a library
which depends on libltdl: you may have problems with duplicate symbol
definitions.
One advantage of the convenience library is that it is not installed, so the fact that you use libltdl will not be apparent to the user, and it will not overwrite a pre-installed version of libltdl a user might have. On the other hand, if you want to upgrade libltdl for any reason (e.g. a bugfix) you'll have to recompile your package instead of just replacing an installed version of libltdl. However, if your programs or libraries are linked with other libraries that use such a pre-installed version of libltdl, you may get linker errors or run-time crashes. Another problem is that you cannot link the convenience library into more than one libtool library, then link a single program with these libraries, because you may get duplicate symbols. In general you can safely use the convenience library in programs which don't depend on other libraries that might use libltdl too. In order to enable this flavor of libltdl, you should add the line `AC_LIBLTDL_CONVENIENCE' to your `configure.in', before `AC_PROG_LIBTOOL'.
In order to select the installable version of libltdl, you should add a call of the macro `AC_LIBLTDL_INSTALLABLE' to your `configure.in' before `AC_PROG_LIBTOOL'. This macro will check whether libltdl is already installed and, if not, request the libltdl embedded in your package to be built and installed. Note, however, that no version checking is performed. The user may override the test and determine that the libltdl embedded must be installed, regardless of the existence of another version, using the configure switch `--enable-ltdl-install'.
In order to embed libltdl into your package, just add `--ltdl' to
the libtoolize
command line. It will copy the libltdl sources
to a subdirectory `libltdl' in your package.
Both macros accept an optional argument to specify the location
of the `libltdl' directory. By the default both macros assume that it
is `${top_srcdir}/libltdl'.
Whatever macro you use, it is up to you to ensure that your `configure.in' will configure libltdl, using `AC_CONFIG_SUBDIRS', and that your `Makefile's will start sub-makes within libltdl's directory, using automake's SUBDIRS, for example. Both macros define the shell variables LIBLTDL, to the link flag that you should use to link with libltdl, and INCLTDL, to the preprocessor flag that you should use to compile with programs that include `ltdl.h'. It is up to you to use `AC_SUBST' to ensure that this variable will be available in `Makefile's, or add them to variables that are `AC_SUBST'ed by default, such as LIBS and CPPFLAGS.
If you're using the convenience libltdl, LIBLTDL will be the pathname for the convenience version of libltdl and INCLTDL will be `-I' followed by the directory that contains libltdl, both starting with `${top_builddir}/' or `${top_srcdir}/', respectively.
If you request an installed version of libltdl and one is found(10), LIBLTDL will be set to `-lltdl' and INCLTDL will be empty (which is just a blind assumption that `ltdl.h' is somewhere in the include path if libltdl is in the library path). If an installable version of libltdl must be built, its pathname, starting with `${top_builddir}/', will be stored in LIBLTDL, and INCLTDL will be set just like in the case of convenience library.
So, when you want to link a program with libltdl, be it a convenience, installed or installable library, just compile with `$(INCLTDL)' and link it with `$(LIBLTDL)', using libtool.
You should probably also add `AC_LIBTOOL_DLOPEN' to your `configure.in' before `AC_PROG_LIBTOOL', otherwise libtool will assume no dlopening mechanism is supported, and revert to dlpreopening, which is probably not what you want.
Avoid using the -static
or -all-static
switches when
linking programs with libltdl. This will not work on all platforms,
because the dlopening functions may not be available for static linking.
The following example shows you how to embed the convenience libltdl in your package. In order to use the installable variant just replace `AC_LIBLTDL_CONVENIENCE' with `AC_LIBLTDL_INSTALLABLE'. We assume that libltdl was embedded using `libtoolize --ltdl'.
configure.in:
... dnl Enable building of the convenience library dnl and set LIBLTDL accordingly AC_LIBLTDL_CONVENIENCE dnl Substitute INCLTDL and LIBLTDL in the Makefiles AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) dnl Check for dlopen support AC_LIBTOOL_DLOPEN dnl Configure libtool AC_PROG_LIBTOOL dnl Configure libltdl AC_CONFIG_SUBDIRS(libltdl) ...
Makefile.am:
... SUBDIRS = libltdl INCLUDES = $(INCLTDL) myprog_LDFLAGS = -export-dynamic # The quotes around -dlopen below fool automake <= 1.4 into accepting it myprog_LDADD = $(LIBLTDL) "-dlopen" self "-dlopen" foo1.la myprog_DEPENDENCIES = $(LIBLTDL) foo1.la ...
Go to the first, previous, next, last section, table of contents.