libtool: Module loaders for libltdl
1
1 11.5 How to create and register new module loaders
1 ==================================================
1
1 Sometimes libltdl's many ways of gaining access to modules are not
1 sufficient for the purposes of a project. You can write your own
1 loader, and register it with libltdl so that 'lt_dlopen' will be able to
1 use it.
1
1 Writing a loader involves writing at least three functions that can
1 be called by 'lt_dlopen', 'lt_dlsym' and 'lt_dlclose'. Optionally, you
1 can provide a finalisation function to perform any cleanup operations
1 when 'lt_dlexit' executes, and a symbol prefix string that will be
1 prepended to any symbols passed to 'lt_dlsym'. These functions must
1 match the function pointer types below, after which they can be
1 allocated to an instance of 'lt_user_dlloader' and registered.
1
1 Registering the loader requires that you choose a name for it, so
1 that it can be recognised by 'lt_dlloader_find' and removed with
1 'lt_dlloader_remove'. The name you choose must be unique, and not
1 already in use by libltdl's builtin loaders:
1
1 "dlopen"
1 The system dynamic library loader, if one exists.
1 "dld"
1 The GNU dld loader, if 'libdld' was installed when libltdl was
1 built.
1 "dlpreload"
1 The loader for 'lt_dlopen'ing of preloaded static modules.
1
1 The prefix "dl" is reserved for loaders supplied with future versions
1 of libltdl, so you should not use that for your own loader names.
1
1 The following types are defined in 'ltdl.h':
1
1 -- Type: lt_module
1 'lt_module' is a dlloader dependent module. The dynamic module
1 loader extensions communicate using these low level types.
1
1 -- Type: lt_dlloader
1 'lt_dlloader' is a handle for module loader types.
1
1 -- Type: lt_user_data
1 'lt_user_data' is used for specifying loader instance data.
1
1 -- Type: struct lt_user_dlloader {const char *SYM_PREFIX; lt_module_open *MODULE_OPEN;
1 lt_module_close *MODULE_CLOSE; lt_find_sym *FIND_SYM; lt_dlloader_exit *DLLOADER_EXIT;
1 }
1 If you want to define a new way to open dynamic modules, and have
1 the 'lt_dlopen' API use it, you need to instantiate one of these
1 structures and pass it to 'lt_dlloader_add'. You can pass whatever
1 you like in the DLLOADER_DATA field, and it will be passed back as
1 the value of the first parameter to each of the functions specified
1 in the function pointer fields.
1
1 -- Type: lt_module lt_module_open (const char *FILENAME)
1 The type of the loader function for an 'lt_dlloader' module loader.
1 The value set in the dlloader_data field of the 'struct
1 lt_user_dlloader' structure will be passed into this function in
1 the LOADER_DATA parameter. Implementation of such a function
1 should attempt to load the named module, and return an 'lt_module'
1 suitable for passing in to the associated 'lt_module_close' and
1 'lt_sym_find' function pointers. If the function fails it should
1 return 'NULL', and set the error message with 'lt_dlseterror'.
1
1 -- Type: int lt_module_close (lt_user_data LOADER_DATA,
1 lt_module MODULE)
1 The type of the unloader function for a user defined module loader.
1 Implementation of such a function should attempt to release any
1 resources tied up by the MODULE module, and then unload it from
1 memory. If the function fails for some reason, set the error
1 message with 'lt_dlseterror' and return non-zero.
1
1 -- Type: void * lt_find_sym (lt_module MODULE, const char *SYMBOL)
1 The type of the symbol lookup function for a user defined module
1 loader. Implementation of such a function should return the
1 address of the named SYMBOL in the module MODULE, or else set the
1 error message with 'lt_dlseterror' and return 'NULL' if lookup
1 fails.
1
1 -- Type: int lt_dlloader_exit (lt_user_data LOADER_DATA)
1 The type of the finalisation function for a user defined module
1 loader. Implementation of such a function should free any
1 resources associated with the loader, including any user specified
1 data in the 'dlloader_data' field of the 'lt_user_dlloader'. If
1 non-'NULL', the function will be called by 'lt_dlexit', and
1 'lt_dlloader_remove'.
1
1 For example:
1
1 int
1 register_myloader (void)
1 {
1 lt_user_dlloader dlloader;
1
1 /* User modules are responsible for their own initialisation. */
1 if (myloader_init () != 0)
1 return MYLOADER_INIT_ERROR;
1
1 dlloader.sym_prefix = NULL;
1 dlloader.module_open = myloader_open;
1 dlloader.module_close = myloader_close;
1 dlloader.find_sym = myloader_find_sym;
1 dlloader.dlloader_exit = myloader_exit;
1 dlloader.dlloader_data = (lt_user_data)myloader_function;
1
1 /* Add my loader as the default module loader. */
1 if (lt_dlloader_add (lt_dlloader_next (NULL), &dlloader,
1 "myloader") != 0)
1 return ERROR;
1
1 return OK;
1 }
1
1 Note that if there is any initialisation required for the loader, it
1 must be performed manually before the loader is registered - libltdl
1 doesn't handle user loader initialisation.
1
1 Finalisation _is_ handled by libltdl however, and it is important to
1 ensure the 'dlloader_exit' callback releases any resources claimed
1 during the initialisation phase.
1
1 libltdl provides the following functions for writing your own module
1 loaders:
1
1 -- Function: int lt_dlloader_add (lt_dlloader *PLACE, lt_user_dlloader *DLLOADER,
1 const char *LOADER_NAME)
1 Add a new module loader to the list of all loaders, either as the
1 last loader (if PLACE is 'NULL'), else immediately before the
1 loader passed as PLACE. LOADER_NAME will be returned by
1 'lt_dlloader_name' if it is subsequently passed a newly registered
1 loader. These LOADER_NAMEs must be unique, or 'lt_dlloader_remove'
1 and 'lt_dlloader_find' cannot work. Returns 0 for success.
1
1 /* Make myloader be the last one. */
1 if (lt_dlloader_add (NULL, myloader) != 0)
1 perror (lt_dlerror ());
1
1 -- Function: int lt_dlloader_remove (const char *LOADER_NAME)
1 Remove the loader identified by the unique name, LOADER_NAME.
1 Before this can succeed, all modules opened by the named loader
1 must have been closed. Returns 0 for success, otherwise an error
1 message can be obtained from 'lt_dlerror'.
1
1 /* Remove myloader. */
1 if (lt_dlloader_remove ("myloader") != 0)
1 perror (lt_dlerror ());
1
1 -- Function: lt_dlloader * lt_dlloader_next (lt_dlloader *PLACE)
1 Iterate over the module loaders, returning the first loader if
1 PLACE is 'NULL', and the next one on subsequent calls. The handle
1 is for use with 'lt_dlloader_add'.
1
1 /* Make myloader be the first one. */
1 if (lt_dlloader_add (lt_dlloader_next (NULL), myloader) != 0)
1 return ERROR;
1
1 -- Function: lt_dlloader * lt_dlloader_find (const char *LOADER_NAME)
1 Return the first loader with a matching LOADER_NAME identifier, or
1 else 'NULL', if the identifier is not found.
1
1 The identifiers that may be used by libltdl itself, if the host
1 architecture supports them are "dlopen"(1), "dld" and "dlpreload".
1
1 /* Add a user loader as the next module loader to be tried if
1 the standard dlopen loader were to fail when lt_dlopening. */
1 if (lt_dlloader_add (lt_dlloader_find ("dlopen"), myloader) != 0)
1 return ERROR;
1
1 -- Function: const char * lt_dlloader_name (lt_dlloader *PLACE)
1 Return the identifying name of PLACE, as obtained from
1 'lt_dlloader_next' or 'lt_dlloader_find'. If this function fails,
1 it will return 'NULL' and set an error for retrieval with
1 'lt_dlerror'.
1
1 -- Function: lt_user_data * lt_dlloader_data (lt_dlloader *PLACE)
1 Return the address of the 'dlloader_data' of PLACE, as obtained
1 from 'lt_dlloader_next' or 'lt_dlloader_find'. If this function
1 fails, it will return 'NULL' and set an error for retrieval with
1 'lt_dlerror'.
1
1 11.5.1 Error handling within user module loaders
1 ------------------------------------------------
1
1 -- Function: int lt_dladderror (const char *DIAGNOSTIC)
1 This function allows you to integrate your own error messages into
1 'lt_dlerror'. Pass in a suitable diagnostic message for return by
1 'lt_dlerror', and an error identifier for use with 'lt_dlseterror'
1 is returned.
1
1 If the allocation of an identifier fails, this function returns -1.
1
1 int myerror = lt_dladderror ("doh!");
1 if (myerror < 0)
1 perror (lt_dlerror ());
1
1 -- Function: int lt_dlseterror (int ERRORCODE)
1 When writing your own module loaders, you should use this function
1 to raise errors so that they are propagated through the
1 'lt_dlerror' interface. All of the standard errors used by libltdl
1 are declared in 'ltdl.h', or you can add more of your own with
1 'lt_dladderror'. This function returns 0 on success.
1
1 if (lt_dlseterror (LTDL_ERROR_NO_MEMORY) != 0)
1 perror (lt_dlerror ());
1
1 ---------- Footnotes ----------
1
1 (1) This is used for the host dependent module loading API -
1 'shl_load' and 'LoadLibrary' for example
1