123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- @c -*-texinfo-*-
- @c This is part of the GNU Guile Reference Manual.
- @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.
- @node Foreign Function Interface
- @section Foreign Function Interface
- @cindex foreign function interface
- @cindex ffi
- 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 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
- 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.
- @example
- (use-modules (system foreign-library))
- @end example
- @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]
- [#:rename-on-cygwin?=#t]
- 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.
- If @var{rename-on-cygwin?} is true (the default) -- on Cygwin hosts only
- -- the search behavior is modified such that a filename that starts with
- ``lib'' will be searched for under the name ``cyg'', as is customary for
- Cygwin.
- @end deffn
- 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
- @deffn {Scheme Procedure} foreign-library? obj
- Return @code{#t} if @var{obj} is a foreign library, or @code{#f}
- otherwise.
- @end deffn
- @node Foreign Extensions
- @subsection Foreign Extensions
- 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.
- Concretely, you might extend Guile with an implementation of the Bessel
- function, @code{j0}:
- @smallexample
- #include <math.h>
- #include <libguile.h>
- SCM
- j0_wrapper (SCM x)
- @{
- return scm_from_double (j0 (scm_to_double (x, "j0")));
- @}
- void
- init_math_bessel (void)
- @{
- scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);
- @}
- @end smallexample
- 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 bessel.so -fPIC bessel.c
- @end smallexample
- 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-module (math bessel)
- #:export (j0))
- (load-extension "bessel" "init_math_bessel")
- @end lisp
- 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.
- 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:
- @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")}.
- 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.
- 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
- static void
- do_init (void *unused)
- @{
- scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);
- scm_c_export ("j0", NULL);
- @}
- void
- init_math_bessel ()
- @{
- scm_c_define_module ("math bessel", do_init, NULL);
- @}
- @end smallexample
- 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.
- @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.
- @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.
- As a convenience, if @var{lib} is not a foreign library, it will be
- passed to @code{load-foreign-library}.
- @end deffn
- 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
- (use-modules (system foreign-library))
- (define init (foreign-library-pointer "bessel" "init_math_bessel"))
- init
- @result{} #<pointer 0x7fb35b1b4688>
- @end example
- 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
- (use-modules (system foreign))
- @end example
- @deffn {Scheme Procedure} pointer-address pointer
- @deffnx {C Function} scm_pointer_address (pointer)
- Return the numerical value of @var{pointer}.
- @example
- (pointer-address init)
- @result{} 139984413364296 ; YMMV
- @end example
- @end deffn
- @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
- @deffn {Scheme Procedure} pointer? obj
- Return @code{#t} if @var{obj} is a pointer object, or @code{#f}
- otherwise.
- @end deffn
- @defvr {Scheme Variable} %null-pointer
- A foreign pointer whose value is 0.
- @end defvr
- @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.
- @deffn {Scheme Procedure} scm->pointer scm
- Return a foreign pointer object with the @code{object-address}
- of @var{scm}.
- @end deffn
- @deffn {Scheme Procedure} pointer->scm pointer
- Unsafely cast @var{pointer} to a Scheme object.
- Cross your fingers!
- @end deffn
- 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.
- @deftypefn {C Function} SCM scm_from_pointer (void *ptr, void (*finalizer) (void*))
- Create a pointer object from a pointer value.
- 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
- @deftypefn {C Function} void* scm_to_pointer (SCM obj)
- Unpack the pointer value from a pointer object.
- @end deftypefn
- @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:
- @example
- (use-modules (system foreign))
- @end example
- @code{(system foreign)} exports a number of values expressing the basic
- C types.
- @defvr {Scheme Variable} int8
- @defvrx {Scheme Variable} uint8
- @defvrx {Scheme Variable} uint16
- @defvrx {Scheme Variable} int16
- @defvrx {Scheme Variable} uint32
- @defvrx {Scheme Variable} int32
- @defvrx {Scheme Variable} uint64
- @defvrx {Scheme Variable} int64
- @defvrx {Scheme Variable} float
- @defvrx {Scheme Variable} double
- @defvrx {Scheme Variable} complex-double
- @defvrx {Scheme Variable} complex-float
- These values represent the C numeric types of the specified sizes and
- signednesses. @code{complex-float} and @code{complex-double} stand for
- C99 @code{float _Complex} and @code{double _Complex} respecively.
- @end defvr
- In addition there are some convenience bindings for indicating types of
- platform-dependent size.
- @defvr {Scheme Variable} int
- @defvrx {Scheme Variable} unsigned-int
- @defvrx {Scheme Variable} long
- @defvrx {Scheme Variable} unsigned-long
- @defvrx {Scheme Variable} short
- @defvrx {Scheme Variable} unsigned-short
- @defvrx {Scheme Variable} size_t
- @defvrx {Scheme Variable} ssize_t
- @defvrx {Scheme Variable} ptrdiff_t
- @defvrx {Scheme Variable} intptr_t
- @defvrx {Scheme Variable} uintptr_t
- Values exported by the @code{(system foreign)} module, representing C
- numeric types. For example, @code{long} may be @code{equal?} to
- @code{int64} on a 64-bit platform.
- @end defvr
- @defvr {Scheme Variable} void
- The @code{void} type. It can be used as the first argument to
- @code{pointer->procedure} to wrap a C function that returns nothing.
- @end defvr
- In addition, the symbol @code{*} is used by convention to denote pointer
- types. Procedures detailed in the following sections, such as
- @code{pointer->procedure}, accept it as a type descriptor.
- @node Foreign Functions
- @subsection Foreign Functions
- 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))
- @end example
- @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
- 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} 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.
- 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
- Pulling all this together, here is a better definition of @code{(math
- bessel)}:
- @example
- (define-module (math bessel)
- #:use-module (system foreign)
- #:use-module (system foreign-library)
- #:export (j0))
- (define j0
- (foreign-library-function "libm" "j0"
- #:return-type double
- #:arg-types (list double)))
- @end example
- That's it! No C at all.
- 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
- @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
- pointer can be accessed at the byte level. This is achieved using
- @emph{bytevectors} (@pxref{Bytevectors}). The @code{(rnrs bytevectors)}
- 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
- @var{pointer}.
- The user may specify an alternate default interpretation for the memory
- by passing the @var{uvec_type} argument, to indicate that the memory is
- an array of elements of that type. @var{uvec_type} should be something
- that @code{array-type} would return, like @code{f32} or @code{s16}.
- When @var{offset} is passed, it specifies the offset in bytes relative
- to @var{pointer} of the memory region aliased by the returned
- bytevector.
- Mutating the returned bytevector mutates the memory pointed to by
- @var{pointer}, so buckle your seatbelts.
- @end deffn
- @deffn {Scheme Procedure} bytevector->pointer bv [offset]
- @deffnx {C Function} scm_bytevector_to_pointer (bv, offset)
- Return a pointer aliasing the memory pointed to by @var{bv} or
- @var{offset} bytes after @var{bv} when @var{offset} is passed.
- @end deffn
- In addition to these primitives, convenience procedures are available:
- @deffn {Scheme Procedure} dereference-pointer pointer
- Assuming @var{pointer} points to a memory region that holds a pointer,
- return this pointer.
- @end deffn
- @deffn {Scheme Procedure} string->pointer string [encoding]
- Return a foreign pointer to a nul-terminated copy of @var{string} in the
- given @var{encoding}, defaulting to the current locale encoding. The C
- string is freed when the returned foreign pointer becomes unreachable.
- This is the Scheme equivalent of @code{scm_to_stringn}.
- @end deffn
- @deffn {Scheme Procedure} pointer->string pointer [length] [encoding]
- Return the string representing the C string pointed to by @var{pointer}.
- If @var{length} is omitted or @code{-1}, the string is assumed to be
- nul-terminated. Otherwise @var{length} is the number of bytes in memory
- pointed to by @var{pointer}. The C string is assumed to be in the given
- @var{encoding}, defaulting to the current locale encoding.
- This is the Scheme equivalent of @code{scm_from_stringn}.
- @end deffn
- @cindex wrapped pointer types
- Most object-oriented C libraries use pointers to specific data
- structures to identify objects. It is useful in such cases to reify the
- different pointer types as disjoint Scheme types. The
- @code{define-wrapped-pointer-type} macro simplifies this.
- @deffn {Scheme Syntax} define-wrapped-pointer-type type-name pred wrap unwrap print
- Define helper procedures to wrap pointer objects into Scheme objects
- with a disjoint type. Specifically, this macro defines:
- @itemize
- @item @var{pred}, a predicate for the new Scheme type;
- @item @var{wrap}, a procedure that takes a pointer object and returns an
- object that satisfies @var{pred};
- @item @var{unwrap}, which does the reverse.
- @end itemize
- @var{wrap} preserves pointer identity, for two pointer objects @var{p1}
- and @var{p2} that are @code{equal?}, @code{(eq? (@var{wrap} @var{p1})
- (@var{wrap} @var{p2})) @result{} #t}.
- Finally, @var{print} should name a user-defined procedure to print such
- objects. The procedure is passed the wrapped object and a port to write
- to.
- For example, assume we are wrapping a C library that defines a type,
- @code{bottle_t}, and functions that can be passed @code{bottle_t *}
- pointers to manipulate them. We could write:
- @example
- (define-wrapped-pointer-type bottle
- bottle?
- wrap-bottle unwrap-bottle
- (lambda (b p)
- (format p "#<bottle of ~a ~x>"
- (bottle-contents b)
- (pointer-address (unwrap-bottle b)))))
- (define grab-bottle
- ;; Wrapper for `bottle_t *grab (void)'.
- (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 (foreign-library-function libbottle "bottle_contents"
- #:return-type '*
- #:arg-types '(*))))
- (lambda (b)
- "Return the contents of B."
- (pointer->string (contents (unwrap-bottle b))))))
- (write (grab-bottle))
- @result{} #<bottle of Ch@^ateau Haut-Brion 803d36>
- @end example
- In this example, @code{grab-bottle} is guaranteed to return a genuine
- @code{bottle} object satisfying @code{bottle?}. Likewise,
- @code{bottle-contents} errors out when its argument is not a genuine
- @code{bottle} object.
- @end deffn
- 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))
- @result{} 8
- @end example
- If we wanted to corrupt Guile's internal state, we could set
- @code{scm_numptob} to another value; but we shouldn't, because that
- variable is not meant to be set. Indeed this point applies more widely:
- the C API is a dangerous place to be. Not only might setting a value
- crash your program, simply accessing the data pointed to by a dangling
- pointer or similar can prove equally disastrous.
- @node 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. 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)
- Return the size of @var{type}, in bytes.
- @var{type} should be a valid C type, like @code{int}.
- Alternately @var{type} may be the symbol @code{*}, in which
- case the size of a pointer is returned. @var{type} may
- also be a list of types, in which case the size of a
- @code{struct} with ABI-conventional packing is returned.
- @end deffn
- @deffn {Scheme Procedure} alignof type
- @deffnx {C Function} scm_alignof (type)
- Return the alignment of @var{type}, in bytes.
- @var{type} should be a valid C type, like @code{int}.
- Alternately @var{type} may be the symbol @code{*}, in which
- case the alignment of a pointer is returned. @var{type} may
- also be a list of types, in which case the alignment of a
- @code{struct} with ABI-conventional packing is returned.
- @end deffn
- Guile also provides some convenience methods to pack and unpack foreign
- pointers wrapping C structs.
- @deffn {Scheme Procedure} make-c-struct types vals
- Create a foreign pointer to a C struct containing @var{vals} with types
- @code{types}.
- @var{vals} and @code{types} should be lists of the same length.
- @end deffn
- @deffn {Scheme Procedure} parse-c-struct foreign types
- Parse a foreign pointer to a C struct, returning a list of values.
- @code{types} should be a list of C types.
- @end deffn
- For example, to create and parse the equivalent of a @code{struct @{
- int64_t a; uint8_t b; @}}:
- @example
- (parse-c-struct (make-c-struct (list int64 uint8)
- (list 300 43))
- (list int64 uint8))
- @result{} (300 43)
- @end example
- As yet, Guile only has convenience routines to support
- conventionally-packed structs. But given the @code{bytevector->pointer}
- and @code{pointer->bytevector} routines, one can create and parse
- tightly packed structs and unions by hand. See the code for
- @code{(system foreign)} for details.
- @node More Foreign Functions
- @subsection More Foreign Functions
- 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
- (foreign-library-function #f "memcpy"
- #:return-type '*
- #:arg-types (list '* '* size_t)))
- @end example
- To invoke @code{memcpy}, one must pass it foreign pointers:
- @example
- (use-modules (rnrs bytevectors))
- (define src-bits
- (u8-list->bytevector '(0 1 2 3 4 5 6 7)))
- (define src
- (bytevector->pointer src-bits))
- (define dest
- (bytevector->pointer (make-bytevector 16 0)))
- (memcpy dest src (bytevector-length src-bits))
- (bytevector->u8-list (pointer->bytevector dest 16))
- @result{} (0 1 2 3 4 5 6 7 0 0 0 0 0 0 0 0)
- @end example
- One may also pass structs as values, passing structs as foreign
- pointers. @xref{Foreign Structs}, for more information on how to express
- struct types and struct values.
- ``Out'' arguments are passed as foreign pointers. The memory pointed to
- by the foreign pointer is mutated in place.
- @example
- ;; struct timeval @{
- ;; time_t tv_sec; /* seconds */
- ;; suseconds_t tv_usec; /* microseconds */
- ;; @};
- ;; assuming fields are of type "long"
- (define gettimeofday
- (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)))
- (ret (f timeval %null-pointer)))
- (if (zero? ret)
- (apply values (parse-c-struct timeval tv-type))
- (error "gettimeofday returned an error" ret))))))
- (gettimeofday)
- @result{} 1270587589
- @result{} 499553
- @end example
- As you can see, this interface to foreign functions is at a very low,
- somewhat dangerous level@footnote{A contribution to Guile in the form of
- a high-level FFI would be most welcome.}.
- @cindex callbacks
- The FFI can also work in the opposite direction: making Scheme
- procedures callable from C. This makes it possible to use Scheme
- procedures as ``callbacks'' expected by C function.
- @deffn {Scheme Procedure} procedure->pointer return-type proc arg-types
- @deffnx {C Function} scm_procedure_to_pointer (return_type, proc, arg_types)
- Return a pointer to a C function of type @var{return-type}
- taking arguments of types @var{arg-types} (a list) and
- behaving as a proxy to procedure @var{proc}. Thus
- @var{proc}'s arity, supported argument types, and return
- type should match @var{return-type} and @var{arg-types}.
- @end deffn
- As an example, here's how the C library's @code{qsort} array sorting
- function can be made accessible to Scheme (@pxref{Array Sort Function,
- @code{qsort},, libc, The GNU C Library Reference Manual}):
- @example
- (define qsort!
- (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.
- (let ((ptr (procedure->pointer int
- (lambda (x y)
- ;; X and Y are pointers so,
- ;; for convenience, dereference
- ;; them before calling COMPARE.
- (compare (dereference-uint8* x)
- (dereference-uint8* y)))
- (list '* '*))))
- (qsort (bytevector->pointer bv)
- (bytevector-length bv) 1 ;; we're sorting bytes
- ptr)))))
- (define (dereference-uint8* ptr)
- ;; Helper function: dereference the byte pointed to by PTR.
- (let ((b (pointer->bytevector ptr 1)))
- (bytevector-u8-ref b 0)))
- (define bv
- ;; An unsorted array of bytes.
- (u8-list->bytevector '(7 1 127 3 5 4 77 2 9 0)))
- ;; Sort BV.
- (qsort! bv (lambda (x y) (- x y)))
- ;; Let's see what the sorted array looks like:
- (bytevector->u8-list bv)
- @result{} (0 1 2 3 4 5 7 9 77 127)
- @end example
- And voil@`a!
- Note that @code{procedure->pointer} is not supported (and not defined)
- on a few exotic architectures. Thus, user code may need to check
- @code{(defined? 'procedure->pointer)}. Nevertheless, it is available on
- many architectures, including (as of libffi 3.0.9) x86, ia64, SPARC,
- PowerPC, ARM, and MIPS, to name a few.
- @c Local Variables:
- @c TeX-master: "guile.texi"
- @c End:
|