[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As you saw in Using GNU libltdl, I need to put an invocation of
the macro ‘AC_LIBTOOL_DLOPEN’ just before ‘AC_PROG_LIBTOOL’,
in the file ‘configure.in’. But, as well as being able to use
libtoolize --ltdl
, which adds libltdl in a subdirectory
with its own subconfigure, you can also manually copy just the ltdl
source files into your project(45), and use AC_LIB_LTDL
in your existing
‘configure.in’. At the time of writing, this is still a very new
and (as yet) undocumented feature, with a few kinks that need to be
ironed out. In any case you probably shouldn’t use this method to add
‘ltdl.lo’ to a C++ library, since ‘ltdl.c’ is written in C.
If you do want to use libltdl with a C++ library, things will
work much better if you build it in a subdirectory generated with
libtoolize --ltdl
.
For this project, lets:
$ cp /usr/share/libtool/libltdl/ltdl.[ch] sic/ |
The Sic module loader is probably as complicated as any you will ever need to write, since it must support two kinds of modules: modules which contain additional built-in commands for the interpreter; and modules which extend the Sic syntax table. A single module can also provide both syntax extensions and additional built-in commands.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Before using this code (or any other libltdl based module loader for that matter), a certain amount of initialisation is required:
LTDL_SET_PRELOADED_SYMBOLS()
.
ltdl_init()
must be called.
Here is the start of the module loader, ‘sic/module.c’, including the initialisation code for libltdl:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The error handling is a very simplistic wrapper for the libltdl error functions, with the addition of a few extra errors specific to this module loader code(46). Here are the error messages from ‘module.c’:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Individual modules are managed by finding specified entry points (prescribed exported symbols) in the module:
An array of names of built-in commands implemented by a module, with associated handler functions.
If present, this function will be called when the module is loaded.
If supplied, this function will be called just before the module is unloaded.
An array of syntactically significant symbols, and associated handler functions.
If specified, this function will be called by Sic before the syntax of each input line is analysed.
Similarly, this function will be call after the syntax analysis of each line has completed.
All of the hard work in locating and loading the module, and extracting
addresses for the symbols described above is performed by
libltdl. The module_load
function below simply registers
these symbols with the Sic interpreter so that they are called at the
appropriate times – or diagnoses any errors if things don’t go
according to plan:
Notice that the generalised List
data type introduced earlier
(see section A Small GNU Autotools Project) is reused to keep a list of
accumulated module initialisation and finalisation functions.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When unloading a module, several things must be done:
syntax_init
and syntax_finish
functions.
My first cut implementation of a module subsystem kept a list of the
entry points associated with each module so that they could be looked up
and removed when the module was subsequently unloaded. It also kept
track of multiply loaded modules so that a module wasn’t unloaded
prematurely. libltdl already does all of this though, and it is
wasteful to duplicate all of that work. This system uses
lt_dlforeach
and lt_dlgetinfo
to access libltdls records
of loaded modules, and save on duplication. These two functions are
described fully in(Libtool)Libltdl interface section ‘Libltdl interface’ in The Libtool Manual.
This function asks libltdl to call the function
unload_ltmodule
for each of the modules it has loaded, along with
some details of the module it wants to unload. The tricky part of the
callback function below is recalculating the entry point addresses for
the module to be unloaded and then removing all matching addresses from
the appropriate internal structures. Otherwise, the balance of this
callback is involved in informing the calling lt_dlforeach
loop
of whether a matching module has been found and handled:
The userdata_address_compare
helper function at the end is used
to compare the address of recalculated entry points against the already
registered functions and handlers to find which items need to be
unregistered.
There is also a matching header file to export the module interface, so that the code for loadable modules can make use of it:
This header also includes some of the other Sic headers, so that in most cases, the source code for a module need only ‘#include <sic/module.h>’.
To make the module loading interface useful, I have added built-ins for
‘load’ and ‘unload’. Naturally, these must be compiled into
the bare sic
executable, so that it is able to load additional
modules:
These new built-in commands are simply wrappers around the module loading code in ‘module.c’.
As with ‘dlopen’, you can use libltdl to ‘lt_dlopen’ the
main executable, and then lookup its symbols. I have simplified
the initialisation of Sic by replacing the sic_init
function in
‘src/sic.c’ by ‘loading’ the executable itself as a module. This
works because I was careful to use the same format in
‘sic_builtin.c’ and ‘sic_syntax.c’ as would be required for a
genuine loadable module, like so:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by Ben Elliston on July 10, 2015 using texi2html 1.82.