guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 01/01: Replace libltdl with raw dlopen, dlsym


From: Andy Wingo
Subject: [Guile-commits] 01/01: Replace libltdl with raw dlopen, dlsym
Date: Fri, 22 Jan 2021 11:01:17 -0500 (EST)

wingo pushed a commit to branch excise-ltdl
in repository guile.

commit 888bd9255fdddcb51b20a47f35f35eca8075e48f
Author: Andy Wingo <wingo@pobox.com>
AuthorDate: Fri Jan 22 16:39:11 2021 +0100

    Replace libltdl with raw dlopen, dlsym
    
    * am/bootstrap.am (SOURCES):
    * module/Makefile.am (SOURCES): Add ice-9/dynl.scm.
    * configure.ac: Replace ltdl check with -ldl check.
    * libguile/deprecated.c (scm_dynamic_func, scm_dynamic_call):
      Deprecate.
    * libguile/dynl.c: Rewrite to just expose core dlopen / dlsym / etc to a
      helper Scheme module.
    * libguile/extensions.c (load_extension): Avoid scm_dynamic_call.
    * module/ice-9/boot-9.scm: Use (ice-9 dynl).
    * module/ice-9/dynl.scm: New file.
    * module/oop/goops.scm (<dynamic-object>): Hackily export a record type
      instead of a class here.
---
 am/bootstrap.am          |   3 +-
 configure.ac             |   8 +-
 doc/ref/api-foreign.texi |   6 +-
 libguile/deprecated.c    |  26 ++-
 libguile/deprecated.h    |   5 +-
 libguile/dynl.c          | 405 +++++++++++------------------------------------
 libguile/dynl.h          |   4 +-
 libguile/extensions.c    |   7 +-
 libguile/guile.c         |   3 +-
 module/Makefile.am       |   3 +-
 module/ice-9/boot-9.scm  |   8 +
 module/ice-9/dynl.scm    | 182 +++++++++++++++++++++
 module/oop/goops.scm     |   9 +-
 13 files changed, 333 insertions(+), 336 deletions(-)

diff --git a/am/bootstrap.am b/am/bootstrap.am
index 2821304..5f5bae2 100644
--- a/am/bootstrap.am
+++ b/am/bootstrap.am
@@ -1,4 +1,4 @@
-##     Copyright (C) 2009-2020 Free Software Foundation, Inc.
+##     Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ##
 ##   This file is part of GNU Guile.
 ##
@@ -96,6 +96,7 @@ SOURCES =                                     \
   ice-9/binary-ports.scm                       \
   ice-9/command-line.scm                       \
   ice-9/control.scm                            \
+  ice-9/dynl.scm                               \
   ice-9/format.scm                             \
   ice-9/getopt-long.scm                                \
   ice-9/i18n.scm                               \
diff --git a/configure.ac b/configure.ac
index bc7bfc6..8166a56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,12 +105,8 @@ AC_PROG_LIBTOOL
 
 AM_CONDITIONAL([HAVE_SHARED_LIBRARIES], [test "x$enable_shared" = "xyes"])
 
-dnl Check for libltdl.
-AC_LIB_HAVE_LINKFLAGS([ltdl], [], [#include <ltdl.h>],
-  [lt_dlopenext ("foo");])
-if test "x$HAVE_LIBLTDL" != "xyes"; then
-  AC_MSG_ERROR([GNU libltdl (Libtool) not found, see README.])
-fi
+# Some systems provide dlopen via libc; others require -ldl.
+AC_SEARCH_LIBS([dlopen], [dl])
 
 AC_CHECK_PROG(have_makeinfo, makeinfo, yes, no)
 AM_CONDITIONAL(HAVE_MAKEINFO, test "$have_makeinfo" = yes)
diff --git a/doc/ref/api-foreign.texi b/doc/ref/api-foreign.texi
index b0d6c24..4679c56 100644
--- a/doc/ref/api-foreign.texi
+++ b/doc/ref/api-foreign.texi
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000-2004, 2007-2014, 2016-2017
+@c Copyright (C)  1996, 1997, 2000-2004, 2007-2014, 2016-2017, 2021
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -84,9 +84,7 @@ as @file{/usr/lib} and @file{/usr/local/lib}.
 @var{library} should not contain an extension such as @code{.so}, unless
 @var{library} represents the absolute file name to the shared library.  The
 correct file name extension for the host operating system is provided
-automatically, according to libltdl's rules (@pxref{Libltdl interface,
-lt_dlopenext, @code{lt_dlopenext}, libtool, Shared Library Support for
-GNU}).
+automatically.
 
 When @var{library} is omitted, a @dfn{global symbol handle} is returned.  This
 handle provides access to the symbols available to the program at run-time,
diff --git a/libguile/deprecated.c b/libguile/deprecated.c
index fcc4e83..dc6c3b3 100644
--- a/libguile/deprecated.c
+++ b/libguile/deprecated.c
@@ -1,4 +1,4 @@
-/* Copyright 2003-2004,2006,2008-2018,2020
+/* Copyright 2003-2004,2006,2008-2018,2020,2021
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -31,7 +31,9 @@
 #include "boolean.h"
 #include "bitvectors.h"
 #include "deprecation.h"
+#include "dynl.h"
 #include "eval.h"
+#include "foreign.h"
 #include "gc.h"
 #include "gsubr.h"
 #include "modules.h"
@@ -601,6 +603,28 @@ scm_copy_tree (SCM obj)
 
 
 
+SCM
+scm_dynamic_func (SCM name, SCM obj)
+{
+  scm_c_issue_deprecation_warning
+    ("scm_dynamic_func is deprecated.  Use scm_dynamic_pointer instead.");
+  return scm_dynamic_pointer (name, obj);
+}
+
+SCM
+scm_dynamic_call (SCM name, SCM obj)
+{
+  scm_c_issue_deprecation_warning
+    ("scm_dynamic_call is deprecated.  Use the FFI instead.");
+  SCM pointer = scm_dynamic_pointer (name, obj);
+  void (*f)(void) = SCM_POINTER_VALUE (pointer);
+  f ();
+  return SCM_UNSPECIFIED;
+}
+
+
+
+
 void
 scm_i_init_deprecated ()
 {
diff --git a/libguile/deprecated.h b/libguile/deprecated.h
index c95f919..50ee01c 100644
--- a/libguile/deprecated.h
+++ b/libguile/deprecated.h
@@ -1,7 +1,7 @@
 #ifndef SCM_DEPRECATED_H
 #define SCM_DEPRECATED_H
 
-/* Copyright 2003-2007,2009-2018,2020
+/* Copyright 2003-2007,2009-2018,2020,2021
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -140,6 +140,9 @@ SCM_DEPRECATED SCM scm_make_srcprops (long line, int col, 
SCM filename,
 
 SCM_DEPRECATED SCM scm_copy_tree (SCM obj);
 
+SCM_DEPRECATED SCM scm_dynamic_func (SCM symb, SCM dobj);
+SCM_DEPRECATED SCM scm_dynamic_call (SCM symb, SCM dobj);
+
 void scm_i_init_deprecated (void);
 
 #endif
diff --git a/libguile/dynl.c b/libguile/dynl.c
index e9c03e9..a042023 100644
--- a/libguile/dynl.c
+++ b/libguile/dynl.c
@@ -1,6 +1,6 @@
 /* dynl.c - dynamic linking
 
-   Copyright 1990-2003,2008-2011,2017-2018
+   Copyright 1990-2003,2008-2011,2017-2018,2021
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -28,369 +28,148 @@
 # include <config.h>
 #endif
 
-#include <alloca.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <ltdl.h>
+#include <dlfcn.h>
 
+#include "boolean.h"
 #include "deprecation.h"
-#include "dynwind.h"
+#include "eval.h"
+#include "extensions.h"
 #include "foreign.h"
-#include "gc.h"
 #include "gsubr.h"
-#include "keywords.h"
-#include "libpath.h"
 #include "list.h"
-#include "ports.h"
-#include "smob.h"
+#include "modules.h"
+#include "numbers.h"
 #include "strings.h"
 #include "threads.h"
+#include "variable.h"
+#include "version.h"
 
 #include "dynl.h"
 
 
-/* From the libtool manual: "Note that libltdl is not threadsafe,
-   i.e. a multithreaded application has to use a mutex for libltdl.".
-   Note: We initialize it as a recursive mutex below.  */
-static scm_i_pthread_mutex_t ltdl_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
-
-/* LT_PATH_SEP-separated extension library search path, searched last */
-static char *system_extensions_path;
-
-static void *
-sysdep_dynl_link (const char *fname, const char *subr)
+static SCM
+dlerror_string (const char *fallback)
 {
-  lt_dlhandle handle;
-
-  /* Try the literal filename first or, if NULL, the program itself */
-  handle = lt_dlopen (fname);
-  if (handle == NULL)
-    {
-      handle = lt_dlopenext (fname);
-
-      if (handle == NULL
-#ifdef LT_DIRSEP_CHAR
-          && strchr (fname, LT_DIRSEP_CHAR) == NULL
-#endif
-          && strchr (fname, '/') == NULL)
-        {
-          /* FNAME contains no directory separators and was not in the
-             usual library search paths, so now we search for it in
-             SYSTEM_EXTENSIONS_PATH. */
-          char *fname_attempt
-            = scm_gc_malloc_pointerless (strlen (system_extensions_path)
-                                         + strlen (fname) + 2,
-                                         "dynl fname_attempt");
-          char *path;  /* remaining path to search */
-          char *end;   /* end of current path component */
-          char *s;
-
-          /* Iterate over the components of SYSTEM_EXTENSIONS_PATH */
-          for (path = system_extensions_path;
-               *path != '\0';
-               path = (*end == '\0') ? end : (end + 1))
-            {
-              /* Find end of path component */
-              end = strchr (path, LT_PATHSEP_CHAR);
-              if (end == NULL)
-                end = strchr (path, '\0');
-
-              /* Skip empty path components */
-              if (path == end)
-                continue;
-
-              /* Construct FNAME_ATTEMPT, starting with path component */
-              s = fname_attempt;
-              memcpy (s, path, end - path);
-              s += end - path;
-
-              /* Append directory separator, but avoid duplicates */
-              if (s[-1] != '/'
-#ifdef LT_DIRSEP_CHAR
-                  && s[-1] != LT_DIRSEP_CHAR
-#endif
-                  )
-                *s++ = '/';
-
-              /* Finally, append FNAME (including null terminator) */
-              strcpy (s, fname);
-
-              /* Try to load it, and terminate the search if successful */
-              handle = lt_dlopenext (fname_attempt);
-              if (handle != NULL)
-                break;
-            }
-        }
-    }
-
-  if (handle == NULL)
-    {
-      SCM fn;
-      SCM msg;
-
-      fn = fname != NULL ? scm_from_locale_string (fname) : SCM_BOOL_F;
-      msg = scm_from_locale_string (lt_dlerror ());
-      scm_misc_error (subr, "file: ~S, message: ~S", scm_list_2 (fn, msg));
-    }
-
-  return (void *) handle;
+  const char *message = dlerror ();
+  if (message)
+    return scm_from_locale_string (message);
+  return scm_from_utf8_string ("Unknown error");
 }
 
-static void
-sysdep_dynl_unlink (void *handle, const char *subr)
-{
-  if (lt_dlclose ((lt_dlhandle) handle))
-    {
-      scm_misc_error (subr, (char *) lt_dlerror (), SCM_EOL);
-    }
-}
-   
-static void *
-sysdep_dynl_value (const char *symb, void *handle, const char *subr)
-{
-  void *fptr;
-
-  fptr = lt_dlsym ((lt_dlhandle) handle, symb);
-  if (!fptr)
-    scm_misc_error (subr, "Symbol not found: ~a",
-                    scm_list_1 (scm_from_locale_string (symb)));
-  return fptr;
-}
-
-static void
-sysdep_dynl_init ()
-{
-  char *env;
-
-  lt_dlinit ();
-
-  /* Initialize 'system_extensions_path' from
-     $GUILE_SYSTEM_EXTENSIONS_PATH, or if that's not set:
-     <SCM_LIB_DIR> <LT_PATHSEP_CHAR> <SCM_EXTENSIONS_DIR>.
-
-     'lt_dladdsearchdir' can't be used because it is searched before
-     the system-dependent search path, which is the one 'libtool
-     --mode=execute -dlopen' fiddles with (info "(libtool) Libltdl
-     Interface").  See
-     <http://lists.gnu.org/archive/html/guile-devel/2010-11/msg00095.html>.
-
-     The environment variables $LTDL_LIBRARY_PATH and $LD_LIBRARY_PATH
-     can't be used because they would be propagated to subprocesses
-     which may cause problems for other programs.  See
-     <http://lists.gnu.org/archive/html/guile-devel/2012-09/msg00037.html> */
-
-  env = getenv ("GUILE_SYSTEM_EXTENSIONS_PATH");
-  if (env)
-    system_extensions_path = env;
-  else
-    {
-      system_extensions_path
-        = scm_gc_malloc_pointerless (strlen (SCM_LIB_DIR)
-                                     + strlen (SCM_EXTENSIONS_DIR) + 2,
-                                     "system_extensions_path");
-      sprintf (system_extensions_path, "%s%c%s",
-               SCM_LIB_DIR, LT_PATHSEP_CHAR, SCM_EXTENSIONS_DIR);
-    }
-}
-
-scm_t_bits scm_tc16_dynamic_obj;
-
-#define DYNL_FILENAME         SCM_SMOB_OBJECT
-#define DYNL_HANDLE(x)        ((void *) SCM_SMOB_DATA_2 (x))
-#define SET_DYNL_HANDLE(x, v) (SCM_SET_SMOB_DATA_2 ((x), (scm_t_bits) (v)))
-
-
-
-static int
-dynl_obj_print (SCM exp, SCM port, scm_print_state *pstate)
-{
-  scm_puts ("#<dynamic-object ", port);
-  scm_iprin1 (DYNL_FILENAME (exp), port, pstate);
-  if (DYNL_HANDLE (exp) == NULL)
-    scm_puts (" (unlinked)", port);
-  scm_putc ('>', port);
-  return 1;
-}
-
-
-SCM_DEFINE (scm_dynamic_link, "dynamic-link", 0, 1, 0,
-            (SCM filename),
-           "Find the shared object (shared library) denoted by\n"
-           "@var{filename} and link it into the running Guile\n"
-           "application.  The returned\n"
-           "scheme object is a ``handle'' for the library which can\n"
-           "be passed to @code{dynamic-func}, @code{dynamic-call} etc.\n\n"
-           "Searching for object files is system dependent.  Normally,\n"
-           "if @var{filename} does have an explicit directory it will\n"
-           "be searched for in locations\n"
-           "such as @file{/usr/lib} and @file{/usr/local/lib}.\n\n"
-           "When @var{filename} is omitted, a @dfn{global symbol handle} is\n"
-           "returned.  This handle provides access to the symbols\n"
-           "available to the program at run-time, including those exported\n"
-           "by the program itself and the shared libraries already loaded.\n")
-#define FUNC_NAME s_scm_dynamic_link
+SCM_DEFINE_STATIC (scm_dlopen, "dlopen", 2, 0, 0, (SCM name, SCM flags), "")
+#define FUNC_NAME s_scm_dlopen
 {
   void *handle;
-  char *file;
-
-  scm_dynwind_begin (0);
-  scm_i_dynwind_pthread_mutex_lock (&ltdl_lock);
+  int c_flags = scm_to_int (flags);
 
-  if (SCM_UNBNDP (filename))
-    file = NULL;
+  if (scm_is_false (name))
+    handle = dlopen (NULL, c_flags);
   else
     {
-      file = scm_to_locale_string (filename);
-      scm_dynwind_free (file);
+      char *c_name = scm_to_locale_string (name);
+      handle = dlopen (c_name, c_flags);
+      free (c_name);
     }
 
-  handle = sysdep_dynl_link (file, FUNC_NAME);
-  scm_dynwind_end ();
+  if (!handle) {
+    SCM message = dlerror_string ("Unknown error while opening module");
+    SCM_MISC_ERROR ("file ~S, message ~S", scm_list_2 (name, message));
+  }
 
-  SCM_RETURN_NEWSMOB2 (scm_tc16_dynamic_obj,
-                      SCM_UNBNDP (filename)
-                      ? SCM_UNPACK (SCM_BOOL_F) : SCM_UNPACK (filename),
-                      handle);
+  return scm_from_pointer (handle, NULL);
 }
 #undef FUNC_NAME
 
-
-SCM_DEFINE (scm_dynamic_object_p, "dynamic-object?", 1, 0, 0, 
-            (SCM obj),
-           "Return @code{#t} if @var{obj} is a dynamic object handle,\n"
-           "or @code{#f} otherwise.")
-#define FUNC_NAME s_scm_dynamic_object_p
+SCM_DEFINE_STATIC (scm_dlclose, "dlclose", 1, 0, 0, (SCM obj), "")
+#define FUNC_NAME s_scm_dlclose
 {
-  return scm_from_bool (SCM_TYP16_PREDICATE (scm_tc16_dynamic_obj, obj));
-}
-#undef FUNC_NAME
-
+  void *handle = scm_to_pointer (obj);
 
-SCM_DEFINE (scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0, 
-            (SCM dobj),
-           "Unlink a dynamic object from the application, if possible.  The\n"
-           "object must have been linked by @code{dynamic-link}, with \n"
-           "@var{dobj} the corresponding handle.  After this procedure\n"
-           "is called, the handle can no longer be used to access the\n"
-           "object.")
-#define FUNC_NAME s_scm_dynamic_unlink
-{
-  /*fixme* GC-problem */
-  SCM_VALIDATE_SMOB (SCM_ARG1, dobj, dynamic_obj);
-
-  scm_dynwind_begin (0);
-  scm_i_dynwind_pthread_mutex_lock (&ltdl_lock);
-  if (DYNL_HANDLE (dobj) == NULL) {
-    SCM_MISC_ERROR ("Already unlinked: ~S", scm_list_1 (dobj));
-  } else {
-    sysdep_dynl_unlink (DYNL_HANDLE (dobj), FUNC_NAME);
-    SET_DYNL_HANDLE (dobj, NULL);
+  if (dlclose (handle) != 0) {
+    SCM message = dlerror_string ("Unknown error");
+    SCM_MISC_ERROR ("Error closing module: ~S", scm_list_1 (message));
   }
-  scm_dynwind_end ();
 
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
 
-
-SCM_DEFINE (scm_dynamic_pointer, "dynamic-pointer", 2, 0, 0,
-            (SCM name, SCM dobj),
-           "Return a ``wrapped pointer'' to the symbol @var{name}\n"
-           "in the shared object referred to by @var{dobj}.  The returned\n"
-           "pointer points to a C object.\n\n"
-           "Regardless whether your C compiler prepends an underscore\n"
-           "@samp{_} to the global names in a program, you should\n"
-           "@strong{not} include this underscore in @var{name}\n"
-           "since it will be added automatically when necessary.")
-#define FUNC_NAME s_scm_dynamic_pointer
+SCM_DEFINE_STATIC (scm_dlsym, "dlsym", 2, 0, 0, (SCM obj, SCM name), "")
+#define FUNC_NAME s_scm_dlsym
 {
-  void *val;
+  void *handle = scm_to_pointer (obj);
+  char *c_name = scm_to_utf8_string (name);
 
-  SCM_VALIDATE_STRING (1, name);
-  SCM_VALIDATE_SMOB (SCM_ARG2, dobj, dynamic_obj);
+  void *sym = dlsym (handle, c_name);
+  free (c_name);
 
-  if (DYNL_HANDLE (dobj) == NULL)
-    SCM_MISC_ERROR ("Already unlinked: ~S", dobj);
-  else
-    {
-      char *chars;
-
-      scm_dynwind_begin (0);
-      scm_i_dynwind_pthread_mutex_lock (&ltdl_lock);
-      chars = scm_to_locale_string (name);
-      scm_dynwind_free (chars);
-      val = sysdep_dynl_value (chars, DYNL_HANDLE (dobj), FUNC_NAME);
-      scm_dynwind_end ();
+  if (!sym) {
+    SCM message = dlerror_string ("Unknown error");
+    SCM_MISC_ERROR ("Error resolving ~S: ~S", scm_list_2 (name, message));
+  }
 
-      return scm_from_pointer (val, NULL);
-    }
+  return scm_from_pointer (sym, NULL);
 }
 #undef FUNC_NAME
 
+#define DEFINE_LAZY_VAR(c_name, mod_name, sym_name)                     \
+  static SCM c_name##_var;                                              \
+  static void init_##c_name##_var (void)                                \
+  {                                                                     \
+    c_name##_var = scm_c_public_lookup (mod_name, sym_name);            \
+  }                                                                     \
+  static SCM c_name (void)                                              \
+  {                                                                     \
+    static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;         \
+    scm_i_pthread_once (&once, init_##c_name##_var);                    \
+    return scm_variable_ref (c_name##_var);                             \
+  }
+
+DEFINE_LAZY_VAR (dynamic_link,     "ice-9 dynl", "dynamic-link");
+DEFINE_LAZY_VAR (dynamic_unlink,   "ice-9 dynl", "dynamic-unlink");
+DEFINE_LAZY_VAR (dynamic_object_p, "ice-9 dynl", "dynamic-object?");
+DEFINE_LAZY_VAR (dynamic_pointer,  "ice-9 dynl", "dynamic-pointer");
 
-SCM_DEFINE (scm_dynamic_func, "dynamic-func", 2, 0, 0, 
-            (SCM name, SCM dobj),
-           "Return a ``handle'' for the function @var{name} in the\n"
-           "shared object referred to by @var{dobj}.  The handle\n"
-           "can be passed to @code{dynamic-call} to actually\n"
-           "call the function.\n\n"
-           "Regardless whether your C compiler prepends an underscore\n"
-           "@samp{_} to the global names in a program, you should\n"
-           "@strong{not} include this underscore in @var{name}\n"
-           "since it will be added automatically when necessary.")
-#define FUNC_NAME s_scm_dynamic_func
+SCM
+scm_dynamic_link (SCM filename)
 {
-  return scm_dynamic_pointer (name, dobj);
+  return scm_call_1 (dynamic_link (), filename);
 }
-#undef FUNC_NAME
 
+SCM
+scm_dynamic_unlink (SCM obj)
+{
+  return scm_call_1 (dynamic_unlink (), obj);
+}
+
+SCM
+scm_dynamic_object_p (SCM obj)
+{
+  return scm_call_1 (dynamic_object_p (), obj);
+}
 
-SCM_DEFINE (scm_dynamic_call, "dynamic-call", 2, 0, 0, 
-            (SCM func, SCM dobj),
-           "Call a C function in a dynamic object.  Two styles of\n"
-           "invocation are supported:\n\n"
-           "@itemize @bullet\n"
-           "@item @var{func} can be a function handle returned by\n"
-           "@code{dynamic-func}.  In this case @var{dobj} is\n"
-           "ignored\n"
-           "@item @var{func} can be a string with the name of the\n"
-           "function to call, with @var{dobj} the handle of the\n"
-           "dynamic object in which to find the function.\n"
-           "This is equivalent to\n"
-           "@smallexample\n\n"
-           "(dynamic-call (dynamic-func @var{func} @var{dobj}) #f)\n"
-           "@end smallexample\n"
-           "@end itemize\n\n"
-           "In either case, the function is passed no arguments\n"
-           "and its return value is ignored.")
-#define FUNC_NAME s_scm_dynamic_call
+SCM
+scm_dynamic_pointer (SCM name, SCM obj)
 {
-  void (*fptr) (void);
+  return scm_call_2 (dynamic_pointer (), name, obj);
+}
 
-  if (scm_is_string (func))
-    func = scm_dynamic_func (func, dobj);
-  SCM_VALIDATE_POINTER (SCM_ARG1, func);
+static void
+scm_init_ice_9_dynl (void)
+{
+  scm_c_define ("RTLD_LAZY", scm_from_int (RTLD_LAZY));
+  scm_c_define ("RTLD_NOW", scm_from_int (RTLD_NOW));
+  scm_c_define ("RTLD_GLOBAL", scm_from_int (RTLD_GLOBAL));
+  scm_c_define ("RTLD_LOCAL", scm_from_int (RTLD_LOCAL));
 
-  fptr = SCM_POINTER_VALUE (func);
-  fptr ();
-  return SCM_UNSPECIFIED;
+#include "dynl.x"
 }
-#undef FUNC_NAME
 
 void
 scm_init_dynamic_linking ()
 {
-  scm_tc16_dynamic_obj = scm_make_smob_type ("dynamic-object", 0);
-  scm_set_smob_print (scm_tc16_dynamic_obj, dynl_obj_print);
-
-  /* Make LTDL_LOCK recursive so that a pre-unwind handler can still use
-     'dynamic-link', as is the case at the REPL.  See
-     <https://bugs.gnu.org/29275>.  */
-  scm_i_pthread_mutex_init (&ltdl_lock,
-                           scm_i_pthread_mutexattr_recursive);
-
-  sysdep_dynl_init ();
-#include "dynl.x"
+  scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
+                            "scm_init_ice_9_dynl",
+                           (scm_t_extension_init_func) scm_init_ice_9_dynl,
+                           NULL);
 }
diff --git a/libguile/dynl.h b/libguile/dynl.h
index 3178c9a..35f4d9d 100644
--- a/libguile/dynl.h
+++ b/libguile/dynl.h
@@ -1,7 +1,7 @@
 #ifndef SCM_DYNL_H
 #define SCM_DYNL_H
 
-/* Copyright 1996,1998,2000-2001,2006,2008,2010,2018
+/* Copyright 1996,1998,2000-2001,2006,2008,2010,2018,2021
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -30,8 +30,6 @@ SCM_API SCM scm_dynamic_link (SCM fname);
 SCM_API SCM scm_dynamic_unlink (SCM dobj);
 SCM_API SCM scm_dynamic_object_p (SCM obj);
 SCM_API SCM scm_dynamic_pointer (SCM name, SCM dobj);
-SCM_API SCM scm_dynamic_func (SCM symb, SCM dobj);
-SCM_API SCM scm_dynamic_call (SCM symb, SCM dobj);
 
 SCM_INTERNAL void scm_init_dynamic_linking (void);
 
diff --git a/libguile/extensions.c b/libguile/extensions.c
index a094159..61c975e 100644
--- a/libguile/extensions.c
+++ b/libguile/extensions.c
@@ -1,4 +1,4 @@
-/* Copyright 2001,2002,2004,2006,2009-2011,2018-2019
+/* Copyright 2001,2002,2004,2006,2009-2011,2018-2019,2021
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -27,6 +27,7 @@
 #include "dynwind.h"
 #include "gc.h"
 #include "gsubr.h"
+#include "foreign.h"
 #include "strings.h"
 #include "threads.h"
 
@@ -113,7 +114,9 @@ load_extension (SCM lib, SCM init)
 
   /* Dynamically link the library. */
 #if HAVE_MODULES
-  scm_dynamic_call (init, scm_dynamic_link (lib));
+  SCM pointer = scm_dynamic_pointer (init, scm_dynamic_link (lib));
+  void (*f)(void) = scm_to_pointer (pointer);
+  f ();
 #else
   scm_misc_error ("load-extension",
                   "extension ~S:~S not registered and dynamic-link disabled",
diff --git a/libguile/guile.c b/libguile/guile.c
index ae592ed..bafe5d6 100644
--- a/libguile/guile.c
+++ b/libguile/guile.c
@@ -1,4 +1,4 @@
-/* Copyright 1996-1997,2000-2001,2006,2008,2011,2013,2018
+/* Copyright 1996-1997,2000-2001,2006,2008,2011,2013,2018,2021
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -28,7 +28,6 @@
 #  include <config.h>
 #endif
 
-#include <ltdl.h>
 #include <locale.h>
 #include <stdio.h>
 
diff --git a/module/Makefile.am b/module/Makefile.am
index 45113b5..451bbe6 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in.
 ##
-##   Copyright (C) 2009-2020 Free Software Foundation, Inc.
+##   Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ##
 ##   This file is part of GUILE.
 ##
@@ -108,6 +108,7 @@ SOURCES =                                   \
   ice-9/curried-definitions.scm                        \
   ice-9/deprecated.scm                         \
   ice-9/documentation.scm                      \
+  ice-9/dynl.scm                               \
   ice-9/eval-string.scm                                \
   ice-9/exceptions.scm                         \
   ice-9/expect.scm                             \
diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index 89595f3..d682dd5 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -4638,6 +4638,14 @@ R7RS."
 
 
 
+;;; {Dynamic linkins}
+;;;
+
+;; Allow users of (guile) to see dynamic-link et al.
+(module-use! the-scm-module (resolve-interface '(ice-9 dynl)))
+
+
+
 ;;; SRFI-4 in the default environment.  FIXME: we should figure out how
 ;;; to deprecate this.
 ;;;
diff --git a/module/ice-9/dynl.scm b/module/ice-9/dynl.scm
new file mode 100644
index 0000000..f55b272
--- /dev/null
+++ b/module/ice-9/dynl.scm
@@ -0,0 +1,182 @@
+;;; Support for dynamic linking via dlopen and dlsym
+;;; Copyright (C) 2021 Free Software Foundation, Inc.
+;;;
+;;; 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 3 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 program.  If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;;
+;;; Implementation of dynamic-link.
+;;;
+;;; Code:
+
+
+(define-module (ice-9 dynl)
+  #:export (dynamic-link
+            dynamic-unlink
+            dynamic-object?
+            dynamic-pointer))
+
+(load-extension (string-append "libguile-" (effective-version))
+                "scm_init_ice_9_dynl")
+
+(define (system-library-extensions)
+  (cond
+   ((string-contains %host-type "-darwin-")
+    '(".bundle" ".so" ".dylib"))
+   ((or (string-contains %host-type "cygwin")
+        (string-contains %host-type "mingw")
+        (string-contains %host-type "msys"))
+    '(".dll"))
+   (else
+    '(".so"))))
+
+(define (has-extension? head exts)
+  (and (pair? exts)
+       (or (string-suffix? (car exts) head)
+           (has-extension? head (cdr exts)))))
+
+(define (file-exists-with-extension head exts)
+  (if (has-extension? head exts)
+      (and (file-exists? head) head)
+      (let lp ((exts exts))
+        (and (pair? exts)
+             (let ((head (string-append head (car exts))))
+               (if (file-exists? head)
+                   head
+                   (lp (cdr exts))))))))
+
+(define (file-exists-in-path-with-extension basename path exts)
+  (and (pair? path)
+       (or (file-exists-with-extension (in-vicinity (car path) basename) exts)
+           (file-exists-in-path-with-extension basename (cdr path) exts))))
+
+(define path-separator
+  (case (system-file-name-convention)
+    ((posix) #\:)
+    ((windows) #\;)
+    (else (error "unreachable"))))
+
+(define (default-library-path search-ltdl-library-path?)
+  (define (parse-path var default)
+    (let ((val (getenv var)))
+      (if val
+          (string-split val path-separator)
+          (default))))
+  (append
+   (parse-path "GUILE_EXTENSIONS_PATH" (lambda () '()))
+   (if search-ltdl-library-path?
+       (parse-path "LTDL_LIBRARY_PATH" (lambda () '()))
+       '())
+   (parse-path "GUILE_SYSTEM_EXTENSIONS_PATH"
+               (lambda ()
+                 (list (assq-ref %guile-build-info 'libdir)
+                       (assq-ref %guile-build-info 'extensionsdir))))))
+
+(define <dynamic-object>
+  (make-record-type '<dynamic-object> '(filename handle)))
+(define make-dynamic-object
+  (record-constructor <dynamic-object>))
+(define dynamic-object-filename
+  (record-accessor <dynamic-object> 'filename))
+(define dynamic-object-handle
+  (record-accessor <dynamic-object> 'handle))
+(define set-dynamic-object-handle!
+  (record-modifier <dynamic-object> 'handle))
+
+(define* (dynamic-link #:optional filename #:key
+                       (extensions (system-library-extensions))
+                       (search-ltdl-library-path? #t)
+                       (library-path (default-library-path
+                                      search-ltdl-library-path?))
+                       (search-system-paths? #t)
+                       (flags (logior RTLD_LAZY RTLD_LOCAL)))
+  (define (error-not-found)
+    (scm-error 'misc-error "dynamic-link"
+               "file: ~S, message: ~S"
+               (list filename "file not found")
+               #f))
+  (define (dlopen* name) (dlopen name flags))
+  (make-dynamic-object
+   filename
+   (cond
+    ((not filename)
+     ;; The self-open trick.
+     (dlopen* #f))
+    ((or (absolute-file-name? filename)
+         (string-any file-name-separator? filename))
+     (cond
+      ((file-exists-with-extension filename extensions)
+       => dlopen*)
+      (else
+       (error-not-found))))
+    ((file-exists-in-path-with-extension filename library-path extensions)
+     => dlopen*)
+    (search-system-paths?
+     (if (or (null? extensions) (has-extension? filename extensions))
+         (dlopen* filename)
+         (let lp ((extensions extensions))
+           (let ((extension (car extensions))
+                 (extensions (cdr extensions)))
+             (if (null? extensions)
+                 ;; Open in tail position to propagate any exception.
+                 (dlopen* (string-append filename extension))
+                 ;; If there is more than one extension, unfortunately we
+                 ;; swallow any error for previous extensions.  This is
+                 ;; not great because maybe the library was found with
+                 ;; the first extension, failed to load and had an
+                 ;; interesting error, but then we swallowed that
+                 ;; interesting error and proceeded, eventually throwing
+                 ;; a "file not found" exception.  FIXME to use more
+                 ;; structured exceptions and stop if the error that we
+                 ;; get is more specific than just "file not found".
+                 (or (false-if-exception
+                      (dlopen* (string-append filename extension)))
+                     (lp extensions)))))))
+    (else
+     (error-not-found)))))
+
+(define dynamic-object? (record-predicate <dynamic-object>))
+
+(define (dynamic-unlink obj)
+  (let ((handle (dynamic-object-handle obj)))
+    (unless handle
+      (scm-error 'misc-error "dynamic-unlink" "Already unlinked: ~S"
+                 (list obj) #f))
+    (dlclose handle)
+    (set-dynamic-object-handle! obj #f)))
+
+(define (dynamic-pointer name obj)
+  (let ((handle (dynamic-object-handle obj)))
+    (unless handle
+      (scm-error 'misc-error "dynamic-unlink" "Already unlinked: ~S"
+                 (list obj) #f))
+    (dlsym handle name)))
+
+(begin-deprecated
+ (define-public (dynamic-func name obj)
+   (issue-deprecation-warning
+    "dynamic-func is deprecated.  Use dynamic-pointer instead.")
+   (dynamic-pointer name obj))
+
+ (define-public (dynamic-call func obj)
+   (issue-deprecation-warning
+    "dynamic-call is deprecated.  Use the FFI in (system foreign) instead.")
+   (let* ((func (if (string? func)
+                    (dynamic-func func obj)))
+          ;; Use module-ref etc to avoid ffi in boot closure
+          (ffi (resolve-interface '(system foreign)))
+          (void (module-ref ffi 'void))
+          (pointer->procedure (module-ref ffi 'pointer->procedure)))
+     ((pointer->procedure void func '())))))
diff --git a/module/oop/goops.scm b/module/oop/goops.scm
index df6df4f..d88a76b 100644
--- a/module/oop/goops.scm
+++ b/module/oop/goops.scm
@@ -1,6 +1,6 @@
 ;;;; goops.scm -- The Guile Object-Oriented Programming System
 ;;;;
-;;;; Copyright (C) 1998-2003,2006,2009-2011,2013-2015,2017-2018
+;;;; Copyright (C) 1998-2003,2006,2009-2011,2013-2015,2017-2018,2021
 ;;;;   Free Software Foundation, Inc.
 ;;;; Copyright (C) 1993-1998 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
 ;;;;
@@ -3307,10 +3307,15 @@ var{initargs}."
 (define <directory> (find-subclass <top> '<directory>))
 (define <array> (find-subclass <top> '<array>))
 (define <character-set> (find-subclass <top> '<character-set>))
-(define <dynamic-object> (find-subclass <top> '<dynamic-object>))
 (define <guardian> (find-subclass <applicable> '<guardian>))
 (define <macro> (find-subclass <top> '<macro>))
 
+;; <dynamic-object> used to be a SMOB type, albeit not exported even to
+;; C.  However now it's a record type, though still private.  Cross our
+;; fingers that nobody is using it in anger!
+(define <dynamic-object>
+  (module-ref (resolve-module '(ice-9 dynl)) '<dynamic-object>))
+
 (define (define-class-subtree class)
   (define! (class-name class) class)
   (for-each define-class-subtree (class-direct-subclasses class)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]