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:
struct
lt_dlinfo { char *filename
; char *name
; int ref_count
; int is_resident
; int is_symglobal
; int is_symlocal
;}
¶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 remaining fields can
be compared to any hints that were passed to lt_dlopenadvise
to determine whether the underlying loader was able to follow them.
The following function will return a pointer to libltdl’s internal copy of this structure for the given handle:
const lt_dlinfo *
lt_dlgetinfo (lt_dlhandle handle)
¶Return a pointer to a struct that contains some information about
the module handle. The contents of the struct must not be modified.
Return NULL
on failure.
Furthermore, 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:
The opaque type used to hold the module interface details for each registered libltdl client.
int
lt_dlhandle_interface (lt_dlhandle handle, const char *id_string)
¶Functions of this type are called to check that a handle conforms to a
library’s expected module interface when iterating over the global
handle list. You should be careful to write a callback function of
this type that can correctly identify modules that belong to this
client, both to prevent other clients from accidentally finding your
loaded modules with the iterator functions below, and vice versa. The
best way to do this is to check that module handle conforms
to the interface specification of your loader using lt_dlsym
.
The callback may be given every module loaded by all the libltdl module clients in the current address space, including any modules loaded by other libraries such as libltdl itself, and should return non-zero if that module does not fulfill the interface requirements of your loader.
int
my_interface_cb (lt_dlhandle handle, const char *id_string)
{
char *(*module_id) (void) = NULL;
/* A valid my_module must provide all of these symbols. */
if (!((module_id = (char*(*)(void)) lt_dlsym ("module_version"))
&& lt_dlsym ("my_module_entrypoint")))
return 1;
if (strcmp (id_string, module_id()) != 0)
return 1;
return 0;
}
lt_dlinterface_id
lt_dlinterface_register (const char *id_string, lt_dlhandle_interface *iface)
¶Use this function to register your interface validator with libltdl,
and in return obtain a unique key to store and retrieve per-module data.
You supply an id_string and iface so that the resulting
lt_dlinterface_id
can be used to filter the module handles
returned by the iteration functions below. If iface is NULL
,
all modules will be matched.
void
lt_dlinterface_free (lt_dlinterface_id iface)
¶Release the data associated with iface.
int
lt_dlhandle_map (lt_dlinterface_id iface, int (*func) (lt_dlhandle handle, void * data), void * data)
¶For each module that matches iface, call the function
func. When writing the func callback function, the
argument handle is the handle of a loaded module, and
data is the last argument passed to lt_dlhandle_map
. As
soon as func returns a non-zero value for one of the handles,
lt_dlhandle_map
will stop calling func and immediately
return that non-zero value. Otherwise 0 is eventually returned when
func has been successfully called for all matching modules.
lt_dlhandle
lt_dlhandle_iterate (lt_dlinterface_id iface, lt_dlhandle place)
¶Iterate over the module handles loaded by iface, returning the
first matching handle in the list if place is NULL
, and
the next one on subsequent calls. If place is the last element
in the list of eligible modules, this function returns NULL
.
lt_dlhandle handle = 0; lt_dlinterface_id iface = my_interface_id; while ((handle = lt_dlhandle_iterate (iface, handle))) { ... }
lt_dlhandle
lt_dlhandle_fetch (lt_dlinterface_id iface, const char *module_name)
¶Search through the module handles loaded by iface for a module named
module_name, returning its handle if found or else NULL
if no such named module has been loaded by iface.
However, you might still need to maintain your own list of loaded module handles (in parallel with the list maintained inside libltdl) if there were any other data that your application wanted to associate with each open module. Instead, you can use the following API calls to do that for you. You must first obtain a unique interface id from libltdl as described above, and subsequently always use it to retrieve the data you stored earlier. This allows different libraries to each store their own data against loaded modules, without interfering with one another.
void *
lt_dlcaller_set_data (lt_dlinterface_id key, lt_dlhandle handle, void * data)
¶Set data as the set of data uniquely associated with key and
handle for later retrieval. This function returns the data
previously associated with key and handle if any. A result of
0, may indicate that a diagnostic for the last error (if any) is available
from lt_dlerror()
.
For example, to correctly remove some associated data:
void *stale = lt_dlcaller_set_data (key, handle, 0); if (stale != NULL) { free (stale); } else { char *error_msg = lt_dlerror (); if (error_msg != NULL) { my_error_handler (error_msg); return STATUS_FAILED; } }
void *
lt_dlcaller_get_data (lt_dlinterface_id key, lt_dlhandle handle)
¶Return the address of the data associated with key and
handle, or else NULL
if there is none.
Old versions of libltdl also provided a simpler, but similar, API
based around lt_dlcaller_id
. Unfortunately, it had no
provision for detecting whether a module belonged to a particular
interface as libltdl didn’t support multiple loaders in the same
address space at that time. Those APIs are no longer supported
as there would be no way to stop clients of the old APIs from
seeing (and accidentally altering) modules loaded by other libraries.