@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.
@cindex foreign function interface
@cindex ffi
-The more one hacks in Scheme, the more one realizes that there are
-actually two computational worlds: one which is warm and alive, that
-land of parentheses, and one cold and dead, the land of C and its ilk.
-
-But yet we as programmers live in both worlds, and Guile itself is half
-implemented in C. So it is that Guile's living half pays respect to its
-dead counterpart, via a spectrum of interfaces to C ranging from dynamic
-loading of Scheme primitives to dynamic binding of stock C library
-procedures.
+Sometimes you need to use libraries written in C or Rust or some other
+non-Scheme language. More rarely, you might need to write some C to
+extend Guile. This section describes how to load these ``foreign
+libraries'', look up data and functions inside them, and so on.
@menu
-* Foreign Libraries:: Dynamically linking to libraries.
-* Foreign Functions:: Simple calls to C procedures.
-* C Extensions:: Extending Guile in C with loadable modules.
-* Modules and Extensions:: Loading C extensions into modules.
-* Foreign Pointers:: Accessing global variables.
-* Dynamic FFI:: Calling arbitrary C functions.
+* Foreign Libraries:: Dynamically linking to libraries.
+* Foreign Extensions:: Extending Guile in C with loadable modules.
+* Foreign Pointers:: Pointers to C data or functions.
+* Foreign Types:: Expressing C types in Scheme.
+* Foreign Functions:: Simple calls to C procedures.
+* Void Pointers and Byte Access:: Pointers into the ether.
+* Foreign Structs:: Packing and unpacking structs.
+* More Foreign Functions:: Advanced examples.
@end menu
@node Foreign Libraries
@subsection Foreign Libraries
-Most modern Unices have something called @dfn{shared libraries}. This
-ordinarily means that they have the capability to share the executable
-image of a library between several running programs to save memory and
-disk space. But generally, shared libraries give a lot of additional
-flexibility compared to the traditional static libraries. In fact,
-calling them `dynamic' libraries is as correct as calling them `shared'.
-
-Shared libraries really give you a lot of flexibility in addition to the
-memory and disk space savings. When you link a program against a shared
-library, that library is not closely incorporated into the final
-executable. Instead, the executable of your program only contains
-enough information to find the needed shared libraries when the program
-is actually run. Only then, when the program is starting, is the final
-step of the linking process performed. This means that you need not
-recompile all programs when you install a new, only slightly modified
-version of a shared library. The programs will pick up the changes
-automatically the next time they are run.
-
-Now, when all the necessary machinery is there to perform part of the
-linking at run-time, why not take the next step and allow the programmer
-to explicitly take advantage of it from within their program? Of course,
-many operating systems that support shared libraries do just that, and
-chances are that Guile will allow you to access this feature from within
-your Scheme programs. As you might have guessed already, this feature
-is called @dfn{dynamic linking}.@footnote{Some people also refer to the
-final linking stage at program startup as `dynamic linking', so if you
-want to make yourself perfectly clear, it is probably best to use the
-more technical term @dfn{dlopening}, as suggested by Gordon Matzigkeit
-in his libtool documentation.}
-
-We titled this section ``foreign libraries'' because although the name
-``foreign'' doesn't leak into the API, the world of C really is foreign
-to Scheme -- and that estrangement extends to components of foreign
-libraries as well, as we see in future sections.
-
-@deffn {Scheme Procedure} dynamic-link [library]
-@deffnx {C Function} scm_dynamic_link (library)
-Find the shared library denoted by @var{library} (a string) and link it
-into the running Guile application. When everything works out, return a
-Scheme object suitable for representing the linked object file.
-Otherwise an error is thrown. How object files are searched is system
-dependent.
-
-Guile first tries to load @var{library} as the absolute file name of a shared
-library. If that fails, it then falls back to interpret
-@var{library} as just the name of some shared library that will be
-searched for in the places where shared libraries usually reside, such
-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}).
-
-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,
-including those exported by the program itself and the shared libraries already
-loaded.
-
-Note that on hosts that use dynamic-link libraries (DLLs), the global
-symbol handle may not be able to provide access to symbols from
-recursively-loaded DLLs. Only exported symbols from those DLLs directly
-loaded by the program may be available.
-@end deffn
+Just as Guile can load up Scheme libraries at run-time, Guile can also
+load some system libraries written in C or other low-level languages.
+We refer to these as dynamically-loadable modules as @dfn{foreign
+libraries}, to distinguish them from native libraries written in Scheme
+or other languages implemented by Guile.
+@cindex foreign libraries
+@cindex libraries, foreign
+
+Foreign libraries usually come in two forms. Some foreign libraries are
+part of the operating system, such as the compression library
+@code{libz}. These shared libraries are built in such a way that many
+programs can use their functionality without duplicating their code.
+When a program written in C is built, it can declare that it uses a
+specific set of shared libraries.
+@cindex shared libraries
+@cindex libraries, shared
+When the program is run, the operating system takes care of locating and
+loading the shared libraries.
+
+The operating system components that can dynamically load and link
+shared libraries when a program is run are also available
+programmatically during a program's execution. This is the interface
+that's most useful for Guile, and this is what we mean in Guile when we
+refer to @dfn{dynamic linking}. Dynamic linking at run-time is
+sometimes called @dfn{dlopening}, to distinguish it from the dynamic
+linking that happens at program start-up.
+@cindex dynamic linking
+@cindex dlopening
+
+The other kind of foreign library is sometimes known as a module,
+plug-in, bundle, or an extension. These foreign libraries aren't meant
+to be linked to by C programs, but rather only to be dynamically loaded
+at run-time -- they extend some main program with functionality, but
+don't stand on their own. Sometimes a Guile library will implement some
+of its functionality in a loadable module.
+
+In either case, the interface on the Guile side is the same. You load
+the interface using @code{load-foreign-library}. The resulting foreign
+library object implements a simple lookup interface whereby the user can
+get addresses of data or code exported by the library. There is no
+facility to inspect foreign libraries; you have to know what's in there
+already before you look.
+
+Routines for loading foreign libraries and accessing their contents are
+implemented in the @code{(system foreign-library)} module.
-@deffn {Scheme Procedure} dynamic-object? obj
-@deffnx {C Function} scm_dynamic_object_p (obj)
-Return @code{#t} if @var{obj} is a dynamic library handle, or @code{#f}
-otherwise.
-@end deffn
-
-@deffn {Scheme Procedure} dynamic-unlink dobj
-@deffnx {C Function} scm_dynamic_unlink (dobj)
-Unlink the indicated object file from the application. The
-argument @var{dobj} must have been obtained by a call to
-@code{dynamic-link}. After @code{dynamic-unlink} has been
-called on @var{dobj}, its content is no longer accessible.
-@end deffn
-
-@smallexample
-(define libgl-obj (dynamic-link "libGL"))
-libgl-obj
-@result{} #<dynamic-object "libGL">
-(dynamic-unlink libGL-obj)
-libGL-obj
-@result{} #<dynamic-object "libGL" (unlinked)>
-@end smallexample
-
-As you can see, after calling @code{dynamic-unlink} on a dynamically
-linked library, it is marked as @samp{(unlinked)} and you are no longer
-able to use it with @code{dynamic-call}, etc. Whether the library is
-really removed from you program is system-dependent and will generally
-not happen when some other parts of your program still use it.
-
-When dynamic linking is disabled or not supported on your system,
-the above functions throw errors, but they are still available.
-
-
-@node Foreign Functions
-@subsection Foreign Functions
+@example
+(use-modules (system foreign-library))
+@end example
-The most natural thing to do with a dynamic library is to grovel around
-in it for a function pointer: a @dfn{foreign function}.
-@code{dynamic-func} exists for that purpose.
-
-@deffn {Scheme Procedure} dynamic-func name dobj
-@deffnx {C Function} scm_dynamic_func (name, dobj)
-Return a ``handle'' for the func @var{name} in the shared object referred to
-by @var{dobj}. The handle can be passed to @code{dynamic-call} to
-actually call the function.
-
-Regardless whether your C compiler prepends an underscore @samp{_} to the global
-names in a program, you should @strong{not} include this underscore in
-@var{name} since it will be added automatically when necessary.
+@deffn {Scheme Procedure} load-foreign-library [library] @
+ [#:extensions=system-library-extensions] @
+ [#:search-ltdl-library-path?=#t] @
+ [#:search-path=search-path] @
+ [#:search-system-paths?=#t] [#:lazy?=#t] [#:global=#f]
+Find the shared library denoted by @var{library} (a string or @code{#f})
+and link it into the running Guile application. When everything works
+out, return a Scheme object suitable for representing the linked object
+file. Otherwise an error is thrown.
+
+If @var{library} argument is omitted, it defaults to @code{#f}. If
+@code{library} is false, the resulting foreign library gives access to
+all symbols available for dynamic linking in the main binary.
+
+It is not necessary to include any extension such as @code{.so} in
+@var{library}. For each system, Guile has a default set of extensions
+that it will try. On GNU systems, the default extension set is just
+@code{.so}; on Windows, just @code{.dll}; and on Darwin (Mac OS), it is
+@code{.bundle}, @code{.so}, and @code{.dylib}. Pass @code{#:extensions
+@var{extensions}} to override the default extensions list. If
+@var{library} contains one of the extensions, no extensions are tried,
+so it is possible to specify the extension if you know exactly what file
+to load.
+
+Unless @var{library} denotes an absolute file name or otherwise contains
+a directory separator (@code{/}, and also @code{\} on Windows), Guile
+will search for the library in the directories listed in
+@var{search-paths}. The default search path has three components, which
+can all be overriden by colon-delimited (semicolon on Windows)
+environment variables:
+
+@table @env
+@item GUILE_EXTENSIONS_PATH
+This is the main environment variable for users to add directories
+containing Guile extensions. The default value has no entries. This
+environment variable was added in Guile 3.0.6.
+@item LTDL_LIBRARY_PATH
+Before Guile 3.0.6, Guile loaded foreign libraries using @code{libltdl},
+the dynamic library loader provided by libtool. This loader used
+@env{LTDL_LIBRARY_PATH}, and for backwards compatibility we still
+support that path.
+
+However, @code{libltdl} would not only open @code{.so} (or @code{.dll}
+and so on) files, but also the @code{.la} files created by libtool. In
+installed libraries -- libraries that are in the target directories of
+@code{make install} -- @code{.la} files are never needed, to the extent
+that most GNU/Linux distributions remove them entirely. It is
+sufficient to just load the @code{.so} (or @code{.dll} and so on) files,
+which are always located in the same directory as the @code{.la} files.
+
+But for uninstalled dynamic libraries, like those in a build tree, the
+situation is a bit of a mess. If you have a project that uses libtool
+to build libraries -- which is the case for Guile, and for most projects
+using autotools -- and you build @file{foo.so} in directory @file{D},
+libtool will put @file{foo.la} in @file{D}, but @file{foo.so} gets put
+into @file{D/.libs}.
+
+Users were mostly oblivious to this situation, as @code{libltdl} had
+special logic to be able to read the @code{.la} file to know where to
+find the @code{.so}, even from an uninstalled build tree, preventing the
+existence of @file{.libs} from leaking out to the user.
+
+We don't use libltdl now, essentially for flexibility and
+error-reporting reasons. But, to keep this old use-case working, if
+@var{search-ltdl-library-path?} is true, we add each entry of
+@code{LTDL_LIBRARY_PATH} to the default extensions load path,
+additionally adding the @file{.libs} subdirextories for each entry, in
+case there are @file{.so} files there instead of alongside the
+@file{.la} files.
+@item GUILE_SYSTEM_EXTENSIONS_PATH
+The last path in Guile's search path belongs to Guile itself, and
+defaults to the libdir and the extensiondir, in that order. For
+example, if you install to @file{/opt/guile}, these would probably be
+@file{/opt/guile/lib} and
+@code{/opt/guile/lib/guile/@value{EFFECTIVE-VERSION}/extensions},
+respectively. @xref{Parallel Installations}, for more details on
+@code{extensionsdir}.
+@end table
+
+Finally, if no library is found in the search path, and if @var{library}
+is not absolute and does not include directory separators, and if
+@var{search-system-paths?} is true, the operating system may have its
+own logic for where to locate @var{library}. For example, on GNU, there
+will be a default set of paths (often @file{/usr/lib} and @file{/lib},
+though it depends on the system), and the @code{LD_LIBRARY_PATH}
+environment variable can add additional paths. Other operating systems
+have other conventions.
+
+Falling back to the operating system for search is usually not a great
+thing; it is a recipe for making programs that work on one machine but
+not on others. Still, when wrapping system libraries, it can be the
+only way to get things working at all.
+
+If @var{lazy?} is true (the default), Guile will request the operating
+system to resolve symbols used by the loaded library as they are first
+used. If @var{global?} is true, symbols defined by the loaded library
+will be available when other modules need to resolve symbols; the
+default is @code{#f}, which keeps symbols local.
@end deffn
-Guile has static support for calling functions with no arguments,
-@code{dynamic-call}.
-
-@deffn {Scheme Procedure} dynamic-call func dobj
-@deffnx {C Function} scm_dynamic_call (func, dobj)
-Call the C function indicated by @var{func} and @var{dobj}.
-The function is passed no arguments and its return value is
-ignored. When @var{function} is something returned by
-@code{dynamic-func}, call that function and ignore @var{dobj}.
-When @var{func} is a string , look it up in @var{dynobj}; this
-is equivalent to
-@smallexample
-(dynamic-call (dynamic-func @var{func} @var{dobj}) #f)
-@end smallexample
+The environment variables mentioned above are parsed when the
+foreign-library module is first loaded and bound to parameters. Null
+path components, for example the three components of
+@env{GUILE_SYSTEM_EXTENSIONS_PATH="::"}, are ignored.
+
+@deffn {Scheme Parameter} guile-extensions-path
+@deffnx {Scheme Parameter} ltdl-library-path
+@deffnx {Scheme Parameter} guile-system-extensions-path
+Parameters whose initial values are taken from
+@env{GUILE_EXTENSIONS_PATH}, @env{LTDL_LIBRARY_PATH}, and
+@env{GUILE_SYSTEM_EXTENSIONS_PATH}, respectively. @xref{Parameters}.
+The current values of these parameters are used when building the search
+path when @code{load-foreign-library} is called, unless the caller
+explicitly passes a @code{#:search-path} argument.
@end deffn
-@code{dynamic-call} is not very powerful. It is mostly intended to be
-used for calling specially written initialization functions that will
-then add new primitives to Guile. For example, we do not expect that you
-will dynamically link @file{libX11} with @code{dynamic-link} and then
-construct a beautiful graphical user interface just by using
-@code{dynamic-call}. Instead, the usual way would be to write a special
-Guile-to-X11 glue library that has intimate knowledge about both Guile
-and X11 and does whatever is necessary to make them inter-operate
-smoothly. This glue library could then be dynamically linked into a
-vanilla Guile interpreter and activated by calling its initialization
-function. That function would add all the new types and primitives to
-the Guile interpreter that it has to offer.
-
-(There is actually another, better option: simply to create a
-@file{libX11} wrapper in Scheme via the dynamic FFI. @xref{Dynamic FFI},
-for more information.)
-
-Given some set of C extensions to Guile, the next logical step is to
-integrate these glue libraries into the module system of Guile so that
-you can load new primitives into a running system just as you can load
-new Scheme code.
-
-@deffn {Scheme Procedure} load-extension lib init
-@deffnx {C Function} scm_load_extension (lib, init)
-Load and initialize the extension designated by LIB and INIT.
-When there is no pre-registered function for LIB/INIT, this is
-equivalent to
-
-@lisp
-(dynamic-call INIT (dynamic-link LIB))
-@end lisp
-
-When there is a pre-registered function, that function is called
-instead.
-
-Normally, there is no pre-registered function. This option exists
-only for situations where dynamic linking is unavailable or unwanted.
-In that case, you would statically link your program with the desired
-library, and register its init function right after Guile has been
-initialized.
-
-As for @code{dynamic-link}, @var{lib} should not contain any suffix such
-as @code{.so} (@pxref{Foreign Libraries, dynamic-link}). It
-should also not contain any directory components. Libraries that
-implement Guile Extensions should be put into the normal locations for
-shared libraries. We recommend to use the naming convention
-@file{libguile-bla-blum} for a extension related to a module @code{(bla
-blum)}.
-
-The normal way for a extension to be used is to write a small Scheme
-file that defines a module, and to load the extension into this
-module. When the module is auto-loaded, the extension is loaded as
-well. For example,
-
-@lisp
-(define-module (bla blum))
-
-(load-extension "libguile-bla-blum" "bla_init_blum")
-@end lisp
+@deffn {Scheme Procedure} foreign-library? obj
+Return @code{#t} if @var{obj} is a foreign library, or @code{#f}
+otherwise.
@end deffn
-@node C Extensions
-@subsection C Extensions
-The most interesting application of dynamically linked libraries is
-probably to use them for providing @emph{compiled code modules} to
-Scheme programs. As much fun as programming in Scheme is, every now and
-then comes the need to write some low-level C stuff to make Scheme even
-more fun.
+@node Foreign Extensions
+@subsection Foreign Extensions
-Not only can you put these new primitives into their own module (see the
-previous section), you can even put them into a shared library that is
-only then linked to your running Guile image when it is actually
-needed.
+One way to use shared libraries is to extend Guile. Such loadable
+modules generally define one distinguished initialization function that,
+when called, will use the @code{libguile} API to define procedures in
+the current module.
-An example will hopefully make everything clear. Suppose we want to
-make the Bessel functions of the C library available to Scheme in the
-module @samp{(math bessel)}. First we need to write the appropriate
-glue code to convert the arguments and return values of the functions
-from Scheme to C and back. Additionally, we need a function that will
-add them to the set of Guile primitives. Because this is just an
-example, we will only implement this for the @code{j0} function.
+Concretely, you might extend Guile with an implementation of the Bessel
+function, @code{j0}:
@smallexample
#include <math.h>
@}
void
-init_math_bessel ()
+init_math_bessel (void)
@{
scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);
@}
@end smallexample
-We can already try to bring this into action by manually calling the low
-level functions for performing dynamic linking. The C source file needs
-to be compiled into a shared library. Here is how to do it on
-GNU/Linux, please refer to the @code{libtool} documentation for how to
-create dynamically linkable libraries portably.
+The C source file would then need to be compiled into a shared library.
+On GNU/Linux, the compiler invocation might look like this:
@smallexample
-gcc -shared -o libbessel.so -fPIC bessel.c
+gcc -shared -o bessel.so -fPIC bessel.c
@end smallexample
-Now fire up Guile:
+A good default place to put shared libraries that extend Guile is into
+the extensions dir. From the command line or a build script, invoke
+@code{pkg-config --variable=extensionsdir
+guile-@value{EFFECTIVE-VERSION}} to print the extensions dir.
+@xref{Parallel Installations}, for more details.
+
+Guile can load up @code{bessel.so} via @code{load-extension}.
+
+@deffn {Scheme Procedure} load-extension lib init
+@deffnx {C Function} scm_load_extension (lib, init)
+Load and initialize the extension designated by LIB and INIT.
+@end deffn
+
+The normal way for a extension to be used is to write a small Scheme
+file that defines a module, and to load the extension into this
+module. When the module is auto-loaded, the extension is loaded as
+well. For example:
@lisp
-(define bessel-lib (dynamic-link "./libbessel.so"))
-(dynamic-call "init_math_bessel" bessel-lib)
-(j0 2)
-@result{} 0.223890779141236
+(define-module (math bessel)
+ #:export (j0))
+
+(load-extension "bessel" "init_math_bessel")
@end lisp
-The filename @file{./libbessel.so} should be pointing to the shared
-library produced with the @code{gcc} command above, of course. The
-second line of the Guile interaction will call the
-@code{init_math_bessel} function which in turn will register the C
-function @code{j0_wrapper} with the Guile interpreter under the name
-@code{j0}. This function becomes immediately available and we can call
-it from Scheme.
+This @code{load-extension} invocation loads the @code{bessel} library
+via @code{(load-foreign-library "bessel")}, then looks up the
+@code{init_math_bessel} symbol in the library, treating it as a function
+of no arguments, and calls that function.
-Fun, isn't it? But we are only half way there. This is what
-@code{apropos} has to say about @code{j0}:
+If you decide to put your extension outside the default search path for
+@code{load-foreign-library}, probably you should adapt the Scheme module
+to specify its absolute path. For example, if you use @code{automake}
+to build your extension and place it in @code{$(pkglibdir)}, you might
+define a build-parameters module that gets created by the build system:
-@smallexample
-(apropos "j0")
-@print{} (guile-user): j0 #<primitive-procedure j0>
-@end smallexample
+@example
+(define-module (math config)
+ #:export (extensiondir))
+(define extensiondir "PKGLIBDIR")
+@end example
+
+This file would be @code{config.scm.in}. You would define a @code{make}
+rule to substitute in the absolute installed file name:
+
+@example
+config.scm: config.scm.in
+ sed 's|PKGLIBDIR|$(pkglibdir)|' <$< >$@
+@end example
+
+Then your @code{(math bessel)} would import @code{(math config)}, then
+@code{(load-extension (in-vicinity extensiondir "bessel")
+"init_math_bessel")}.
-As you can see, @code{j0} is contained in the root module, where all
-the other Guile primitives like @code{display}, etc live. In general,
-a primitive is put into whatever module is the @dfn{current module} at
-the time @code{scm_c_define_gsubr} is called.
+An alternate approach would be to rebind the
+@code{guile-extensions-path} parameter, or its corresponding environment
+variable, but note that changing those parameters applies to other users
+of @code{load-foreign-library} as well.
-A compiled module should have a specially named @dfn{module init
-function}. Guile knows about this special name and will call that
-function automatically after having linked in the shared library. For
-our example, we replace @code{init_math_bessel} with the following code in
-@file{bessel.c}:
+Note that the new primitives that the extension adds to Guile with
+@code{scm_c_define_gsubr} (@pxref{Primitive Procedures}) or with any of
+the other mechanisms are placed into the module that is current when the
+@code{scm_c_define_gsubr} is executed, so to be clear about what goes
+vwhere it's best to include the @code{load-extension} in a module, as
+above. Alternately, the C code can use @code{scm_c_define_module} to
+specify which module is being created:
@smallexample
-void
-init_math_bessel (void *unused)
+static void
+do_init (void *unused)
@{
scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);
scm_c_export ("j0", NULL);
@}
void
-scm_init_math_bessel_module ()
+init_math_bessel ()
@{
- scm_c_define_module ("math bessel", init_math_bessel, NULL);
+ scm_c_define_module ("math bessel", do_init, NULL);
@}
@end smallexample
-The general pattern for the name of a module init function is:
-@samp{scm_init_}, followed by the name of the module where the
-individual hierarchical components are concatenated with underscores,
-followed by @samp{_module}.
+And yet... if what we want is just the @code{j0} function, it seems like
+a lot of ceremony to have to compile a Guile-specific wrapper library
+complete with an initialization function and wraper module to allow
+Guile users to call it. There is another way, but to get there, we have
+to talk about function pointers and function types first. @xref{Foreign
+Functions}, to skip to the good parts.
-After @file{libbessel.so} has been rebuilt, we need to place the shared
-library into the right place.
-Once the module has been correctly installed, it should be possible to
-use it like this:
-
-@smallexample
-guile> (load-extension "./libbessel.so" "scm_init_math_bessel_module")
-guile> (use-modules (math bessel))
-guile> (j0 2)
-0.223890779141236
-guile> (apropos "j0")
-@print{} (math bessel): j0 #<primitive-procedure j0>
-@end smallexample
-
-That's it!
+@node Foreign Pointers
+@subsection Foreign Pointers
+Foreign libraries are essentially key-value mappings, where the keys are
+names of definitions and the values are the addresses of those
+definitions. To look up the address of a definition, use
+@code{foreign-library-pointer} from the @code{(system foreign-library)}
+module.
-@node Modules and Extensions
-@subsection Modules and Extensions
+@deffn {Scheme Procedure} foreign-library-pointer lib name
+Return a ``wrapped pointer'' for the symbol @var{name} in the shared
+object referred to by @var{lib}. The returned pointer points to a C
+object.
-The new primitives that you add to Guile with @code{scm_c_define_gsubr}
-(@pxref{Primitive Procedures}) or with any of the other mechanisms are
-placed into the module that is current when the
-@code{scm_c_define_gsubr} is executed. Extensions loaded from the REPL,
-for example, will be placed into the @code{(guile-user)} module, if the
-REPL module was not changed.
+As a convenience, if @var{lib} is not a foreign library, it will be
+passed to @code{load-foreign-library}.
+@end deffn
-To define C primitives within a specific module, the simplest way is:
+If we continue with the @code{bessel.so} example from before, we can get
+the address of the @code{init_math_bessel} function via:
@example
-(define-module (foo bar))
-(load-extension "foobar-c-code" "foo_bar_init")
+(use-modules (system foreign-library))
+(define init (foreign-library-pointer "bessel" "init_math_bessel"))
+init
+@result{} #<pointer 0x7fb35b1b4688>
@end example
-@cindex extensiondir
-When loaded with @code{(use-modules (foo bar))}, the
-@code{load-extension} call looks for the @file{foobar-c-code.so} (etc)
-object file in Guile's @code{extensiondir}, which is usually a
-subdirectory of the @code{libdir}. For example, if your libdir is
-@file{/usr/lib}, the @code{extensiondir} for the Guile @value{EFFECTIVE-VERSION}.@var{x}
-series will be @file{/usr/lib/guile/@value{EFFECTIVE-VERSION}/}.
-
-The extension path includes the major and minor version of Guile (the
-``effective version''), because Guile guarantees compatibility within a
-given effective version. This allows you to install different versions
-of the same extension for different versions of Guile.
-
-If the extension is not found in the @code{extensiondir}, Guile will
-also search the standard system locations, such as @file{/usr/lib} or
-@file{/usr/local/lib}. It is preferable, however, to keep your extension
-out of the system library path, to prevent unintended interference with
-other dynamically-linked C libraries.
-
-If someone installs your module to a non-standard location then the
-object file won't be found. You can address this by inserting the
-install location in the @file{foo/bar.scm} file. This is convenient
-for the user and also guarantees the intended object is read, even if
-stray older or newer versions are in the loader's path.
-
-The usual way to specify an install location is with a @code{prefix}
-at the configure stage, for instance @samp{./configure prefix=/opt}
-results in library files as say @file{/opt/lib/foobar-c-code.so}.
-When using Autoconf (@pxref{Top, , Introduction, autoconf, The GNU
-Autoconf Manual}), the library location is in a @code{libdir}
-variable. Its value is intended to be expanded by @command{make}, and
-can by substituted into a source file like @file{foo.scm.in}
+A value returned by @code{foreign-library-pointer} is a Scheme wrapper
+for a C pointer. Pointers are a data type in Guile that is disjoint
+from all other types. The next section discusses ways to dereference
+pointers, but before then we describe the usual type predicates and so
+on.
+
+Note that the rest of the interfaces in this section are part of the
+@code{(system foreign)} library:
@example
-(define-module (foo bar))
-(load-extension "XXextensiondirXX/foobar-c-code" "foo_bar_init")
+(use-modules (system foreign))
@end example
-@noindent
-with the following in a @file{Makefile}, using @command{sed}
-(@pxref{Top, , Introduction, sed, SED, A Stream Editor}),
+@deffn {Scheme Procedure} pointer-address pointer
+@deffnx {C Function} scm_pointer_address (pointer)
+Return the numerical value of @var{pointer}.
@example
-foo.scm: foo.scm.in
- sed 's|XXextensiondirXX|$(libdir)/guile/@value{EFFECTIVE-VERSION}|' <foo.scm.in >foo.scm
+(pointer-address init)
+@result{} 139984413364296 ; YMMV
@end example
+@end deffn
-The actual pattern @code{XXextensiondirXX} is arbitrary, it's only something
-which doesn't otherwise occur. If several modules need the value, it
-can be easier to create one @file{foo/config.scm} with a define of the
-@code{extensiondir} location, and use that as required.
+@deffn {Scheme Procedure} make-pointer address [finalizer]
+Return a foreign pointer object pointing to @var{address}. If
+@var{finalizer} is passed, it should be a pointer to a one-argument C
+function that will be called when the pointer object becomes
+unreachable.
+@end deffn
-@example
-(define-module (foo config))
-(define-public foo-config-extensiondir "XXextensiondirXX"")
-@end example
+@deffn {Scheme Procedure} pointer? obj
+Return @code{#t} if @var{obj} is a pointer object, or @code{#f}
+otherwise.
+@end deffn
-Such a file might have other locations too, for instance a data
-directory for auxiliary files, or @code{localedir} if the module has
-its own @code{gettext} message catalogue
-(@pxref{Internationalization}).
+@defvr {Scheme Variable} %null-pointer
+A foreign pointer whose value is 0.
+@end defvr
-It will be noted all of the above requires that the Scheme code to be
-found in @code{%load-path} (@pxref{Load Paths}). Presently it's left up
-to the system administrator or each user to augment that path when
-installing Guile modules in non-default locations. But having reached
-the Scheme code, that code should take care of hitting any of its own
-private files etc.
+@deffn {Scheme Procedure} null-pointer? pointer
+Return @code{#t} if @var{pointer} is the null pointer, @code{#f} otherwise.
+@end deffn
+For the purpose of passing SCM values directly to foreign functions, and
+allowing them to return SCM values, Guile also supports some unsafe
+casting operators.
-@node Foreign Pointers
-@subsection Foreign Pointers
+@deffn {Scheme Procedure} scm->pointer scm
+Return a foreign pointer object with the @code{object-address}
+of @var{scm}.
+@end deffn
-The previous sections have shown how Guile can be extended at runtime by
-loading compiled C extensions. This approach is all well and good, but
-wouldn't it be nice if we didn't have to write any C at all? This
-section takes up the problem of accessing C values from Scheme, and the
-next discusses C functions.
+@deffn {Scheme Procedure} pointer->scm pointer
+Unsafely cast @var{pointer} to a Scheme object.
+Cross your fingers!
+@end deffn
-@menu
-* Foreign Types:: Expressing C types in Scheme.
-* Foreign Variables:: Pointers to C symbols.
-* Void Pointers and Byte Access:: Pointers into the ether.
-* Foreign Structs:: Packing and unpacking structs.
-@end menu
+Sometimes you want to give C extensions access to the dynamic FFI. At
+that point, the names get confusing, because ``pointer'' can refer to a
+@code{SCM} object that wraps a pointer, or to a @code{void*} value. We
+will try to use ``pointer object'' to refer to Scheme objects, and
+``pointer value'' to refer to @code{void *} values.
-@node Foreign Types
-@subsubsection Foreign Types
+@deftypefn {C Function} SCM scm_from_pointer (void *ptr, void (*finalizer) (void*))
+Create a pointer object from a pointer value.
-The first impedance mismatch that one sees between C and Scheme is that
-in C, the storage locations (variables) are typed, but in Scheme types
-are associated with values, not variables. @xref{Values and Variables}.
+If @var{finalizer} is non-null, Guile arranges to call it on the pointer
+value at some point after the pointer object becomes collectable.
+@end deftypefn
-So when describing a C function or a C structure so that it can be
-accessed from Scheme, the data types of the parameters or fields must be
-passed explicitly.
+@deftypefn {C Function} void* scm_to_pointer (SCM obj)
+Unpack the pointer value from a pointer object.
+@end deftypefn
-These ``C type values'' may be constructed using the constants and
+@node Foreign Types
+@subsection Foreign Types
+
+From Scheme's perspective, foreign pointers are shards of chaos. The
+user can create a foreign pointer for any address, and do with it what
+they will. The only thing that lends a sense of order to the whole is a
+shared hallucination that certain storage locations have certain types.
+When making Scheme wrappers for foreign interfaces, we hide the madness
+by explicitly representing the the data types of parameters and fields.
+
+These ``foreign type values'' may be constructed using the constants and
procedures from the @code{(system foreign)} module, which may be loaded
like this:
@end example
@code{(system foreign)} exports a number of values expressing the basic
-C types:
+C types.
@defvr {Scheme Variable} int8
@defvrx {Scheme Variable} uint8
@end defvr
In addition there are some convenience bindings for indicating types of
-platform-dependent size:
+platform-dependent size.
@defvr {Scheme Variable} int
@defvrx {Scheme Variable} unsigned-int
types. Procedures detailed in the following sections, such as
@code{pointer->procedure}, accept it as a type descriptor.
-@node Foreign Variables
-@subsubsection Foreign Variables
-
-Pointers to variables in the current address space may be looked up
-dynamically using @code{dynamic-pointer}.
-
-@deffn {Scheme Procedure} dynamic-pointer name dobj
-@deffnx {C Function} scm_dynamic_pointer (name, dobj)
-Return a ``wrapped pointer'' for the symbol @var{name} in the shared
-object referred to by @var{dobj}. The returned pointer points to a C
-object.
-
-Regardless whether your C compiler prepends an underscore @samp{_} to the global
-names in a program, you should @strong{not} include this underscore in
-@var{name} since it will be added automatically when necessary.
-@end deffn
+@node Foreign Functions
+@subsection Foreign Functions
-For example, currently Guile has a variable, @code{scm_numptob}, as part
-of its API. It is declared as a C @code{long}. So, to create a handle
-pointing to that foreign value, we do:
+The most natural thing to do with a dynamic library is to grovel around
+in it for a function pointer: a @dfn{foreign function}. Load the
+@code{(system foreign)} module to use these Scheme interfaces.
@example
(use-modules (system foreign))
-(define numptob (dynamic-pointer "scm_numptob" (dynamic-link)))
-numptob
-@result{} #<pointer 0x7fb35b1b4688>
@end example
-(The next section discusses ways to dereference pointers.)
-
-A value returned by @code{dynamic-pointer} is a Scheme wrapper for a C
-pointer.
+@deffn {Scheme Procedure} pointer->procedure return_type func_ptr arg_types @
+ [#:return-errno?=#f]
+@deffnx {C Function} scm_pointer_to_procedure (return_type, func_ptr, arg_types)
+@deffnx {C Function} scm_pointer_to_procedure_with_errno (return_type, func_ptr, arg_types)
-@deffn {Scheme Procedure} pointer-address pointer
-@deffnx {C Function} scm_pointer_address (pointer)
-Return the numerical value of @var{pointer}.
+Make a foreign function.
-@example
-(pointer-address numptob)
-@result{} 139984413364296 ; YMMV
-@end example
-@end deffn
+Given the foreign void pointer @var{func_ptr}, its argument and
+return types @var{arg_types} and @var{return_type}, return a
+procedure that will pass arguments to the foreign function
+and return appropriate values.
-@deffn {Scheme Procedure} make-pointer address [finalizer]
-Return a foreign pointer object pointing to @var{address}. If
-@var{finalizer} is passed, it should be a pointer to a one-argument C
-function that will be called when the pointer object becomes
-unreachable.
-@end deffn
+@var{arg_types} should be a list of foreign types.
+@code{return_type} should be a foreign type. @xref{Foreign Types}, for
+more information on foreign types.
-@deffn {Scheme Procedure} pointer? obj
-Return @code{#t} if @var{obj} is a pointer object, @code{#f} otherwise.
+If @var{return-errno?} is true, or when calling
+@code{scm_pointer_to_procedure_with_errno}, the returned procedure will
+return two values, with @code{errno} as the second value.
@end deffn
-@defvr {Scheme Variable} %null-pointer
-A foreign pointer whose value is 0.
-@end defvr
+Finally, in @code{(system foreign-library)} there is a convenient
+wrapper function, joining together @code{foreign-libary-pointer} and
+@code{procedure->pointer}:
-@deffn {Scheme Procedure} null-pointer? pointer
-Return @code{#t} if @var{pointer} is the null pointer, @code{#f} otherwise.
-@end deffn
+@deffn {Scheme Procedure} foreign-library-function lib name @
+ [#:return-type=void] [#:arg-types='()] [#:return-errno?=#f]
+Load the address of @var{name} from @var{lib}, and treat it as a
+function taking arguments @var{arg-types} and returning
+@var{return-type}, optionally also with errno.
-For the purpose of passing SCM values directly to foreign functions, and
-allowing them to return SCM values, Guile also supports some unsafe
-casting operators.
-
-@deffn {Scheme Procedure} scm->pointer scm
-Return a foreign pointer object with the @code{object-address}
-of @var{scm}.
+An invocation of @code{foreign-library-function} is entirely equivalent
+to:
+@example
+(pointer->procedure @var{return-type}
+ (foreign-library-pointer @var{lib} @var{name})
+ @var{arg-types}
+ #:return-errno? @var{return-errno?}).
+@end example
@end deffn
-@deffn {Scheme Procedure} pointer->scm pointer
-Unsafely cast @var{pointer} to a Scheme object.
-Cross your fingers!
-@end deffn
+Pulling all this together, here is a better definition of @code{(math
+bessel)}:
-Sometimes you want to give C extensions access to the dynamic FFI. At
-that point, the names get confusing, because ``pointer'' can refer to a
-@code{SCM} object that wraps a pointer, or to a @code{void*} value. We
-will try to use ``pointer object'' to refer to Scheme objects, and
-``pointer value'' to refer to @code{void *} values.
+@example
+(define-module (math bessel)
+ #:use-module (system foreign)
+ #:use-module (system foreign-library)
+ #:export (j0))
-@deftypefn {C Function} SCM scm_from_pointer (void *ptr, void (*finalizer) (void*))
-Create a pointer object from a pointer value.
+(define j0
+ (foreign-library-function "libm" "j0"
+ #:return-type double
+ #:arg-types (list double)))
+@end example
-If @var{finalizer} is non-null, Guile arranges to call it on the pointer
-value at some point after the pointer object becomes collectable.
-@end deftypefn
+That's it! No C at all.
-@deftypefn {C Function} void* scm_to_pointer (SCM obj)
-Unpack the pointer value from a pointer object.
-@end deftypefn
+Before going on to more detailed examples, the next two sections discuss
+how to deal with data that is more complex than, say, @code{int8}.
+@xref{More Foreign Functions}, to continue with foreign function examples.
@node Void Pointers and Byte Access
-@subsubsection Void Pointers and Byte Access
+@subsection Void Pointers and Byte Access
Wrapped pointers are untyped, so they are essentially equivalent to C
@code{void} pointers. As in C, the memory region pointed to by a
module contains procedures that can be used to convert byte sequences to
Scheme objects such as strings, floating point numbers, or integers.
+Load the @code{(system foreign)} module to use these Scheme interfaces.
+
+@example
+(use-modules (system foreign))
+@end example
+
@deffn {Scheme Procedure} pointer->bytevector pointer len [offset [uvec_type]]
@deffnx {C Function} scm_pointer_to_bytevector (pointer, len, offset, uvec_type)
Return a bytevector aliasing the @var{len} bytes pointed to by
(define grab-bottle
;; Wrapper for `bottle_t *grab (void)'.
- (let ((grab (pointer->procedure '*
- (dynamic-func "grab_bottle" libbottle)
- '())))
+ (let ((grab (foreign-library-function libbottle "grab_bottle"
+ #:return-type '*)))
(lambda ()
"Return a new bottle."
(wrap-bottle (grab)))))
(define bottle-contents
;; Wrapper for `const char *bottle_contents (bottle_t *)'.
- (let ((contents (pointer->procedure '*
- (dynamic-func "bottle_contents"
- libbottle)
- '(*))))
+ (let ((contents (foreign-library-function libbottle "bottle_contents"
+ #:return-type '*
+ #:arg-types '(*))))
(lambda (b)
"Return the contents of B."
(pointer->string (contents (unwrap-bottle b))))))
@code{bottle} object.
@end deffn
-Going back to the @code{scm_numptob} example above, here is how we can
-read its value as a C @code{long} integer:
+As another example, currently Guile has a variable, @code{scm_numptob},
+as part of its API. It is declared as a C @code{long}. So, to read its
+value, we can do:
@example
+(use-modules (system foreign))
(use-modules (rnrs bytevectors))
-
+(define numptob
+ (foreign-library-pointer #f "scm_numptob"))
+numptob
(bytevector-uint-ref (pointer->bytevector numptob (sizeof long))
0 (native-endianness)
(sizeof long))
pointer or similar can prove equally disastrous.
@node Foreign Structs
-@subsubsection Foreign Structs
+@subsection Foreign Structs
Finally, one last note on foreign values before moving on to actually
calling foreign functions. Sometimes you need to deal with C structs,
which requires interpreting each element of the struct according to the
-its type, offset, and alignment. Guile has some primitives to support
-this.
+its type, offset, and alignment. The @code{(system foreign)} module has
+some primitives to support this.
+
+@example
+(use-modules (system foreign))
+@end example
@deffn {Scheme Procedure} sizeof type
@deffnx {C Function} scm_sizeof (type)
tightly packed structs and unions by hand. See the code for
@code{(system foreign)} for details.
+@node More Foreign Functions
+@subsection More Foreign Functions
-@node Dynamic FFI
-@subsection Dynamic FFI
-
-Of course, the land of C is not all nouns and no verbs: there are
-functions too, and Guile allows you to call them.
-
-@deffn {Scheme Procedure} pointer->procedure return_type func_ptr arg_types @
- [#:return-errno?=#f]
-@deffnx {C Function} scm_pointer_to_procedure (return_type, func_ptr, arg_types)
-@deffnx {C Function} scm_pointer_to_procedure_with_errno (return_type, func_ptr, arg_types)
-
-Make a foreign function.
-
-Given the foreign void pointer @var{func_ptr}, its argument and
-return types @var{arg_types} and @var{return_type}, return a
-procedure that will pass arguments to the foreign function
-and return appropriate values.
-
-@var{arg_types} should be a list of foreign types.
-@code{return_type} should be a foreign type. @xref{Foreign Types}, for
-more information on foreign types.
-
-If @var{return-errno?} is true, or when calling
-@code{scm_pointer_to_procedure_with_errno}, the returned procedure will
-return two values, with @code{errno} as the second value.
-@end deffn
-
-Here is a better definition of @code{(math bessel)}:
-
-@example
-(define-module (math bessel)
- #:use-module (system foreign)
- #:export (j0))
-
-(define libm (dynamic-link "libm"))
-
-(define j0
- (pointer->procedure double
- (dynamic-func "j0" libm)
- (list double)))
-@end example
-
-That's it! No C at all.
-
-Numeric arguments and return values from foreign functions are
-represented as Scheme values. For example, @code{j0} in the above
-example takes a Scheme number as its argument, and returns a Scheme
-number.
-
-Pointers may be passed to and returned from foreign functions as well.
-In that case the type of the argument or return value should be the
-symbol @code{*}, indicating a pointer. For example, the following
+It is possible to pass pointers to foreign functions, and to return them
+as well. In that case the type of the argument or return value should
+be the symbol @code{*}, indicating a pointer. For example, the following
code makes @code{memcpy} available to Scheme:
@example
+(use-modules (system foreign))
(define memcpy
- (let ((this (dynamic-link)))
- (pointer->procedure '*
- (dynamic-func "memcpy" this)
- (list '* '* size_t))))
+ (foreign-library-function #f "memcpy"
+ #:return-type '*
+ #:arg-types (list '* '* size_t)))
@end example
To invoke @code{memcpy}, one must pass it foreign pointers:
;; assuming fields are of type "long"
(define gettimeofday
- (let ((f (pointer->procedure
- int
- (dynamic-func "gettimeofday" (dynamic-link))
- (list '* '*)))
+ (let ((f (foreign-library-function #f "gettimeofday"
+ #:return-type int
+ #:arg-types (list '* '*)))
(tv-type (list long long)))
(lambda ()
(let* ((timeval (make-c-struct tv-type (list 0 0)))
@example
(define qsort!
- (let ((qsort (pointer->procedure void
- (dynamic-func "qsort"
- (dynamic-link))
- (list '* size_t size_t '*))))
+ (let ((qsort (foreign-library-function
+ #f "qsort" #:arg-types (list '* size_t size_t '*))))
(lambda (bv compare)
;; Sort bytevector BV in-place according to comparison
;; procedure COMPARE.
/* 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.
# 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)
-{
- 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;
-}
-
-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)
+static SCM
+dlerror_string (const char *fallback)
{
- 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;
+ const char *message = dlerror ();
+ if (message)
+ return scm_from_locale_string (message);
+ return scm_from_utf8_string ("Unknown error");
}
-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;
+ int c_flags = scm_to_int (flags);
- scm_dynwind_begin (0);
- scm_i_dynwind_pthread_mutex_lock (<dl_lock);
-
- 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 (<dl_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 (<dl_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); \
+ }
-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
+DEFINE_LAZY_VAR (load_foreign_library,
+ "system foreign-library", "load-foreign-library");
+DEFINE_LAZY_VAR (foreign_library_p,
+ "system foreign-library", "foreign-library?");
+DEFINE_LAZY_VAR (foreign_library_pointer,
+ "system foreign-library", "foreign-library-pointer");
+
+SCM
+scm_dynamic_link (SCM filename)
{
- return scm_dynamic_pointer (name, dobj);
+ return scm_call_1 (load_foreign_library (), filename);
}
-#undef FUNC_NAME
+SCM
+scm_dynamic_object_p (SCM obj)
+{
+ return scm_call_1 (foreign_library_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 (foreign_library_pointer (), obj, name);
+}
- if (scm_is_string (func))
- func = scm_dynamic_func (func, dobj);
- SCM_VALIDATE_POINTER (SCM_ARG1, func);
+SCM
+scm_dynamic_func (SCM name, SCM obj)
+{
+ return scm_dynamic_pointer (name, obj);
+}
- fptr = SCM_POINTER_VALUE (func);
- fptr ();
+SCM
+scm_dynamic_call (SCM name, SCM obj)
+{
+ SCM pointer = scm_dynamic_pointer (name, obj);
+ void (*f)(void) = SCM_POINTER_VALUE (pointer);
+ f();
return SCM_UNSPECIFIED;
}
-#undef FUNC_NAME
-void
-scm_init_dynamic_linking ()
+static void
+scm_init_system_foreign_library (void *unused)
{
- scm_tc16_dynamic_obj = scm_make_smob_type ("dynamic-object", 0);
- scm_set_smob_print (scm_tc16_dynamic_obj, dynl_obj_print);
+ 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));
- /* 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 (<dl_lock,
- scm_i_pthread_mutexattr_recursive);
-
- sysdep_dynl_init ();
#include "dynl.x"
}
+
+void
+scm_init_dynamic_linking ()
+{
+ scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
+ "scm_init_system_foreign_library",
+ scm_init_system_foreign_library,
+ NULL);
+
+ // FIXME: Deprecate all of these, once (system foreign-library) has
+ // had enough time in the world.
+ scm_c_define_gsubr
+ ("dynamic-link", 0, 1, 0, (scm_t_subr) scm_dynamic_link);
+ scm_c_define_gsubr
+ ("dynamic-object?", 1, 0, 0, (scm_t_subr) scm_dynamic_object_p);
+ scm_c_define_gsubr
+ ("dynamic-func", 2, 0, 0, (scm_t_subr) scm_dynamic_func);
+ scm_c_define_gsubr
+ ("dynamic-pointer", 2, 0, 0, (scm_t_subr) scm_dynamic_pointer);
+ scm_c_define_gsubr
+ ("dynamic-call", 2, 0, 0, (scm_t_subr) scm_dynamic_call);
+}