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