After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 51583 - reimplemented gmodule as a wrapper for (soon-to-be) libtool-1.4's libltdl
reimplemented gmodule as a wrapper for (soon-to-be) libtool-1.4's libltdl
Status: RESOLVED WONTFIX
Product: glib
Classification: Platform
Component: gmodule
1.3.x
Other All
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2001-03-02 20:26 UTC by Gary V. Vaughan
Modified: 2012-01-16 03:36 UTC
See Also:
GNOME target: ---
GNOME version: Unversioned Enhancement


Attachments
gmodule.h (2.92 KB, patch)
2001-03-02 20:28 UTC, Gary V. Vaughan
none Details | Review
gmodule.c (12.07 KB, patch)
2001-03-02 20:29 UTC, Gary V. Vaughan
none Details | Review

Description Gary V. Vaughan 2001-03-02 20:26:14 UTC
gmodule.h:

/* GMODULE - GLIB wrapper code for dynamic module loading
 * Copyright (C) 1998 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/.
 */

#ifndef __GMODULE_H__
#define __GMODULE_H__

extern const char      *g_log_domain_gmodule;
#include <glib.h>

G_BEGIN_DECLS

/* exporting and importing functions, this is special cased
 * to feature Windows dll stubs.
 */
#define G_MODULE_IMPORT         extern
#if defined (G_OS_WIN32)
#  define       G_MODULE_EXPORT         __declspec(dllexport)
#else /* !G_OS_WIN32 */
#  define       G_MODULE_EXPORT
#endif /* !G_OS_WIN32 */

/* No longer used.  These remain for interface compatibility only.  */
typedef enum
{
  G_MODULE_BIND_LAZY    = 1 << 0,
  G_MODULE_BIND_MASK    = 0x01
} GModuleFlags;
 
typedef gpointer GModule;
typedef const gchar* (*GModuleCheckInit) (GModule       *module);
typedef void         (*GModuleUnload)    (GModule       *module);
 
/* open a module `file_name' and return handle, which is NULL on error */
GModule*        g_module_open              (const gchar         *file_name,
                                            GModuleFlags         flags);
 
/* close a previously opened module, returns TRUE on success */
gboolean        g_module_close             (GModule             *module);
 
/* make a module resident so g_module_close on it will be ignored */
void            g_module_make_resident     (GModule             *module);
 
/* query the last module error as a string */
gchar*          g_module_error             (void);
 
/* retrive a symbol pointer from `module', returns TRUE on success */
gboolean        g_module_symbol            (GModule             *module,
                                            const gchar        
*symbol_name,
                                            gpointer            *symbol);
 
/* retrive the file name from an existing module */
gchar*          g_module_name              (GModule             *module);
 
/* Reset the list of colon separated module search directories. */
gchar*          g_module_set_search_path   (gchar               *path);
 
/* Add a new search directory to the list.  */
gchar*          g_module_add_search_path   (gchar               *path);
 
 
 
 
/* --- deprecated functions --- */
gboolean        g_module_supported         (void) G_GNUC_CONST;
gchar*          g_module_build_path        (const gchar         *directory,
                                            const gchar        
*module_name);
 
G_END_DECLS
 
#endif /* __GMODULE_H__ */  

gmodule.c:
/* GMODULE - GLIB wrapper code for dynamic module loading
 * Copyright (C) 1998 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/.
 */

#include        "gmodule.h"
#include        "gmoduleconf.h"
#include        "ltdl.h"
#include        <errno.h>
#include        <string.h>


#define G_CALLERID_UNDEFINED    ((lt_dlcaller_id) -1)
#define G_MODULE_INI_STRING     "g_module_check_init"
#define G_MODULE_FINI_STRING    "g_module_unload"


/* --- prototypes --- */
static  inline gboolean g_module_init_once      (void);
static  inline void     g_module_set_error      (const gchar *error);
static  const gchar    *g_module_get_error      (void);
static  void            g_module_mutex_lock     (void);
static  void            g_module_mutex_unlock   (void);

/* --- variables --- */
G_LOCK_DEFINE_STATIC (GModule);
const char           *g_log_domain_gmodule = "GModule";
static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;


/* --- inline functions --- */
static inline void
g_module_set_error (const gchar *error)
{
  g_static_private_set (&module_error_private, error, NULL);
  errno = 0;
}

/* For orthogonality only:  g_module_error already does exactly what
   is required, but is named according to the supported API. */
#define g_module_get_error      g_module_error

static inline gboolean
g_module_init_once (void)
{
  static gint initialized = 0;

  /* Clear error message for this thread.  */
  g_module_set_error (NULL);

  G_LOCK (GModule);
  if (++initialized == 1)
    {
      gint errors = 0;          /* Number of errors from libltdl calls.  */

      /* Make sure libltdl is using our memory managment API. */
      lt_dlmalloc = (lt_ptr(*)(size_t)) g_malloc;
      lt_dlfree   = (void  (*)(lt_ptr)) g_free;

      /* Register the callbacks to make all lt_*() functions MT safe.  */
      lt_dlmutex_register (g_module_mutex_lock, g_module_mutex_unlock,
                           g_module_set_error,  g_module_get_error);

      /* Initialise ltdl library.  */
      errors = lt_dlinit ();
      if (!errors)
        {
          gchar *path = g_getenv ("GMODULE_PATH");

          /* Create a gmodule specific key for subsequent access to
             per-module data stored by gmodule functions.  */
          g_module_caller_id = lt_dlcaller_register ();

          /* Initialise libltdl module search directory list.  */
          if (path != NULL)
            errors = lt_dladdsearchdir (path);
        }

      G_UNLOCK (GModule);
      return (errors == 0);
    }

  G_UNLOCK (GModule);
  return TRUE;
}

/* --- static functions --- */
static void
g_module_mutex_lock (void)
{
  G_LOCK (GModule);
}

static void
g_module_mutex_unlock (void)
{
  G_UNLOCK (GModule);
}


/* --- exported functions --- */

/**
 * g_module_supported:
 *
 * This function is deprecated.
 * Check if modules are supported on the current platform.  Now that
 * the gmodule API is a wrapper for libltdl, this function will always
 * return %TRUE.
 *
 * Return value: %TRUE if modules are supported.
 **/
gboolean
g_module_supported (void)
{
#if G_ENABLE_DEBUG
  static gboolean first_call = TRUE;

  if (first_call)
    {
      g_warning ("g_module_supported is deprecated.");
      g_warning ("modules are always supported by the underlying
libltdl.");
      first_call = FALSE;
    }
#endif /* G_ENABLE_DEBUG */

  return TRUE;
}

/**
 * g_module_open:
 * @filename: the name of the file containing the module to be opened.
 * @flags: not used.
 *
 * Opens a module.  If the module has already been opened, its reference
 * count is incremented.
 *
 * First of all g_module_open() tries to open @file_name as a module.  If
 * that fails and @file_name has the ".la"-suffix (and is a libtool
archive)
 * it tries to open the corresponding module.  If that fails and @file_name
 * doesn't have the proper module suffix for the host platform, this suffix
 * will be appended and any corresponding module opened.  If that fails and
 * @file_name doesn't have the ".la"-suffix, it is appended and
 * g_module_open() tries to open the corresponding module.  If ultimately
 * that fails as well, %NULL is returned.
 *
 * Return value: a #GModule on success, or %NULL on failure.
 **/
GModule*
g_module_open (const gchar    *file_name,
               GModuleFlags    flags)
{
  lt_dlhandle  handle = (lt_dlhandle) 0;

  g_module_init_once ();

  /* open the module */
  handle = lt_dlopenext (file_name);

  if (handle)
    {
      gchar *error = NULL;
      GModuleCheckInit check_init;
      GModuleUnload unload;
      const gchar *check_failed_error = NULL;

      /* check initialization */
      if (g_module_symbol ((GModule *) handle, G_MODULE_INI_STRING,
                           (gpointer) &check_init))
        {
          check_failed_error = check_init ((GModule *) handle);
        }

      if (check_failed_error != NULL)
        {
          error = g_strconcat ("GModule initialization check failed: ",
                               check_failed_error, NULL);
        }

      /* Register error diagnostic generated above, if any. */
      if (error)
        {
          g_module_close ((GModule *) handle);
          module = NULL;
          g_module_set_error (error);
          g_free (error);
        }
    }

  return module;
}

/**
 * g_module_close:
 * @module: the module to be closed.
 *
 * Closes an open module.
 *
 * Return value: %TRUE on success.
 **/
gboolean
g_module_close (GModule *module)
{
  lt_dlinfo *info;
  gboolean success = TRUE;

  g_return_val_if_fail (module != NULL, FALSE);

  g_module_init_once ();        /* Is this really neccessary? */

  info = lt_dlgetinfo ((lt_dlhandle) module);

  g_return_val_if_fail (info->ref_count > 1, FALSE);

  if ((info->ref_count == 1) && !lt_dlisresident ((lt_dlhandle) module))
    {
      GModuleUnload unload;
      lt_ptr stale = NULL;

      unload = g_module_symbol (module, G_MODULE_FINI_STRING,
                                (gpointer) &unload);

      if (unload)
        unload (module);

      if (lt_dlclose ((lt_dlhandle) module) != 0)
        success = FALSE;

      g_free (module);
    }

  return success;
}

/**
 * g_module_make_resident:
 * @module: the module to make permenantly resident.
 *
 * Ensures that a module can never be unloaded.  Any future
g_module_close()
 * calls on the module will have no effect.  If you open the entire process
 * as a reflexive module, then it is always made resident by default --
there
 * is no need to call this function manually.
 **/
void
g_module_make_resident (GModule *module)
{
  g_return_if_fail (module != NULL);

  lt_dlmakeresident ((lt_dlhandle) module);
}

/**
 * g_module_error:
 *
 * Get a string describing the last error that occured in the gmodule
 * subsystem.
 *
 * Return value: a string describing the last module error.
 **/
gchar*
g_module_error (void)
{
  return g_static_private_get (&module_error_private);
}

/**
 * g_module_symbol:
 * @module: the module.
 * @symbol_name: the name of the symbol to find.
 * @symbol: returns the pointer to the symbol value.
 *
 * Gets a symbol pointer from a module.
 *
 * Return value: %TRUE on success.
 **/
gboolean
g_module_symbol (GModule        *module,
                 const gchar    *symbol_name,
                 gpointer       *symbol)
{
  if (symbol)
    *symbol = NULL;

  g_return_val_if_fail (module      != NULL, FALSE);
  g_return_val_if_fail (symbol_name != NULL, FALSE);
  g_return_val_if_fail (symbol      != NULL, FALSE);

  *symbol = lt_dlsym ((lt_dlhandle) module, symbol_name);

  if (*symbol == NULL)
    {
      gchar *module_error = lt_dlerror ();
      gchar *error;

      error = g_strconcat ("`", symbol_name, "': ", module_error, NULL);
      g_module_set_error (error);
      g_free (error);

      return FALSE;
    }

  return TRUE;
}

/**
 * g_module_name:
 * @module: the module.
 *
 * Gets the file name from a #GModule.
 *
 * Return value: the file name of the module, or "main" if the module
 * is the main program itself.
 **/
gchar*
g_module_name (GModule *module)
{
  lt_dlinfo  *info;

  g_return_val_if_fail (module != NULL, NULL);

  info   = lt_dlgetinfo ((lt_dlhandle) module);

  return g_strdup (info->filename ? info->filename : "main");
}

/**
 * g_module_set_search_path:
 * @path: a colon delimited list of directories.
 *
 * Set the paths of the directories to be searced when trying to
 * locate a module opened using a relative path.
 *
 * Return value: %TRUE if successful.
 **/
gboolean
g_module_set_search_path (gchar *path)
{
  return (lt_dlsetsearchpath (path) == 0);
}

/**
 * g_module_add_search_path:
 * @path: a colon delimited list of directories.
 *
 * Append to the list of user paths, the additional @path of directories
 * to be searched when trying to locate a module opened using a
 * relative path.
 *
 * Return value: %TRUE if successful.
 **/
gboolean
g_module_add_search_path (gchar *path)
{
  return (lt_dladdsearchdir (path) == 0);
}

/**
 * g_module_build_path:
 * @directory: the directory where the module is.
 * @module_name: the name of the module.
 *
 * This function is deprecated.
 **/
gchar*
g_module_build_path (const gchar *directory,
                     const gchar *module_name)
{
#if G_ENABLE_DEBUG
  static gboolean first_call = TRUE;

  if (first_call)
    {
      g_warning ("g_module_build_path is deprecated.");
      g_warning ("Use g_module_set_search_path or
g_module_add_search_path.");
      first_call = FALSE;
    }
#endif /* G_ENABLE_DEBUG */

#if (G_MODULE_IMPL == G_MODULE_IMPL_DL)

  if (directory && *directory) {
    if (strncmp (module_name, "lib", 3) == 0)
      return g_strconcat (directory, "/", module_name, NULL);
    else
      return g_strconcat (directory, "/lib", module_name, ".so", NULL);
  } else if (strncmp (module_name, "lib", 3) == 0)
    return g_strdup (module_name);
  else
    return g_strconcat ("lib", module_name, ".so", NULL);

#elif (G_MODULE_IMPL == G_MODULE_IMPL_DLD)

  if (directory && *directory)
    if (strncmp (module_name, "lib", 3) == 0)
      return g_strconcat (directory, "/", module_name, NULL);
    else
      return g_strconcat (directory, "/lib", module_name, ".sl", NULL);
  else if (strncmp (module_name, "lib", 3) == 0)
    return g_strdup (module_name);
  else
    return g_strconcat ("lib", module_name, ".sl", NULL);

#elif (G_MODULE_IMPL == G_MODULE_IMPL_BEOS)

  g_warning ("g_module_build_path() untested for BeOS!");

  if (directory && *directory)
    {
      if (strncmp (module_name, "lib", 3) == 0)
        return g_strconcat (directory, "/", module_name, NULL);
      else
        return g_strconcat (directory, "/lib", module_name, ".so", NULL);
    }
  else if (strncmp (module_name, "lib", 3) == 0)
    return g_strdup (module_name);
  else
    return g_strconcat ("lib", module_name, ".so", NULL);
 
#elif (G_MODULE_IMPL == G_MODULE_IMPL_WIN32)
 
  {
    gint k = strlen (module_name);
    if (directory && *directory)
      if (k > 4 && g_strcasecmp (module_name + k - 4, ".dll") == 0)
        return g_strconcat (directory, "\\", module_name, NULL);
      else
        return g_strconcat (directory, "\\", module_name, ".dll", NULL);
    else if (k > 4 && g_strcasecmp (module_name + k - 4, ".dll") == 0)
      return g_strdup (module_name);
    else
      return g_strconcat (module_name, ".dll", NULL);
  }
 
#elif (G_MODULE_IMPL == G_MODULE_IMPL_OS2)
 
  {
    gchar *suffix = strrchr(module_name, '.');
    if (directory && *directory)
      if (suffix && (stricmp (suffix, ".dll") == 0))
        return g_strconcat (directory, "/", module_name, NULL);
      else
        return g_strconcat (directory, "/", module_name, ".dll", NULL);
    else if (suffix && (stricmp (suffix, ".dll") == 0))
      return g_strdup (module_name);
    else
      return g_strconcat (module_name, ".dll", NULL);
  }
 
#endif
 
  return NULL;
}
Comment 1 Gary V. Vaughan 2001-03-02 20:28:27 UTC
Created attachment 354 [details] [review]
gmodule.h
Comment 2 Gary V. Vaughan 2001-03-02 20:29:55 UTC
Created attachment 355 [details] [review]
gmodule.c
Comment 3 Gary V. Vaughan 2001-03-02 20:36:08 UTC
My first bugzilla submission... Please excuse the original long
description, There was no obvious way to submit the files until after
I returned to the bug.  Sorry.

Anyway, I redid the implementation of gmodule as a wrapper for libltdl
to take advantage of the thread locking hooks recently committed to
libtool CVS, so that we can hopefully unify the two code bases.  The
last few months have occupied me with pushing features gmodule had
down into libltdl to make this possible, so the wrapper is actually
very thin.

The purpose of this report is mainly to get some feedback -- I haven't
actually tested this code at all.  In fact, I have never programmed
with threads in C before, so some pointers to a small threaded gmodule
using project would be a huge help!

Let me know what you think and if you approve I will incorporate any 
suggestions you have, clean the whole thing up and resubmit.
Comment 4 Owen Taylor 2001-03-03 17:12:03 UTC
I'm putting this on the 2.0 milestone temporarily, but I suspect 
that we'll have to push it off past that, since I don't think we 
have time at this point to properly evaluate and test this change.

I'm also nervous about adding another run-time /compile-time
dependency to the GTK+ system; we've already upped the 
ante-there quite a bit for GTK+-2.0. For libfribidi we decided
that having an external dependency was too painful, and we just
moved the relevant portion of the code into Pango.

Finally, if gmodule should become just a wrapper for libltdl (and
doesn't have a different implementation on any platform) then
perhaps the right thing to do (long-term) is to simply deprecate
gmodule in favor of using libltdl directly.

That's my abstract thoughts on the issue - I have not looked at the
patch or libltdl yet.
Comment 5 Gary V. Vaughan 2001-03-10 17:31:30 UTC
To address your concerns with another compile time dependency: 
libltdl ships with libtool and the libltdl code is copied into your
project source tree at libtoolize time (much like gettextize adds the
internationalisation source code). 

Deprecation gmodule is a smashing idea, though I'd like to see a
source compatibility wrapper modelled after this patch for the next
stable release or two for the sake of projects that already use the
gmodule API.

I am happy to do the work on integration for this patch if I get an
approval in principle.
Comment 6 Owen Taylor 2002-02-26 20:14:34 UTC
Neither gettextize or libtoolize work in the context of a library
like glib... glib has no business installing a libltdl.so and
certainly can't link to it statically.

I'm putting this on a future milestone for consideration again
later; right now, I don't see this as something that actually
gives tangible benefits for users, but certainly the reduction of 
duplication for users would be good. In any case, it's a too
big change to consider for 2.0.x.
Comment 7 Tim Janik 2004-02-19 22:01:57 UTC
i would really like to see this happen. at this point we actually need
a new patch that targets libtool-1.5. as far as the libltdl functions
are concerned though, those can be renamed and integrated completely
into glib, without interferance of any other installed libraries. at
least last time i looked at libltdl, the code allowed for that.
i don't think full deprecation of the g_module API is a good idea
then, i found the libltdl api crufty to use at best, and don't see a
necessity for applications to port away from a g_module api if it
works correctly.
Comment 8 Tor Lillqvist 2004-12-05 09:04:06 UTC
Does libltdl on Win32 implement the required symbol lookup functionality as 
gmodule-win32 does (using two alternative APIs even, to work also on NT 4)? 
I.e. look for the symbol in all currently loaded DLLs *and* the exe?
Comment 9 Matthias Clasen 2012-01-16 03:36:58 UTC
I think it is clear that this is not going to happen