Autoconf, Automake, and Libtool: Introducing libltdl

| ## 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.

This document was generated by Gary V. Vaughan on February, 8 2006 using texi2html