The XEmacs module system (emodules)

Dynamically loadable modules for Emacs

While Elisp is a full programming language and capable of extending Emacs in more ways than you can imagine, it does have its short-comings.

Firstly, Elisp is an interpreted language, and this has serious speed implications. Like all other interpreted languages, Elisp is often suitable only for certain types of application or extension. So although Elisp is a general purpose language, and very high level, there are times when it is desirable to descend to a lower level compiled language for speed purposes.

Secondly, Elisp (or Lisp in general) is not a very common language any more, except for certain circles in the computer industry. C is a far more commonly known language, and because it is compiled, more suited to a wider range of applications, especially those that require low level access to a system or need to be as quick as possible.

Having the ability to load such modules during run-time into GNU Emacs would be very useful. This topic has been discussed on GNU Emacs mailing lists several times. Unfortunately, RMS does not want this feature accepted into GNU Emacs. If you want to read up on this topic, I recommend Richards reply in a thread which started with this mail.

The XEmacs Module System

XEmacs provides a way of extending it by using dynamically loadable modules (also known as dynamically loadable libraries (DLLs), dynamic shared objects (DSOs) or just simply shared objects), which can be written in C or C++ and loaded into XEmacs at any time.

XEmacs modules are configured into and installed with XEmacs by default on all systems that support loading of shared objects. From a users perspective, the internals of XEmacs modules are irrelevant. All a user will ever need to know about shared objects is the name of the shared object when they want to load a given module. From a developers perspective though, a lot more is provided.

For more details, read the XEmacs 21.5 emodules documentation.

Internals: lrecords

To: Mario Lang <mlang@delysid.org>
Subject: Re: Special object types when writing emodules?
From: Jerry James <james@xemacs.org>
Date: Mon, 04 Aug 2003 13:19:47 -0500
Message-ID: <psadapffp8.fsf@diannao.ittc.ku.edu>
User-Agent: Gnus/5.1002 (Gnus v5.10.2) XEmacs/21.4 (Rational FORTRAN, linux)

Hi Mario,

Mario Lang <mlang@delysid.org>, on Fri, 01 Aug 2003 at 12:32:51 +0200 you
wrote:
> I got your e-mail from Stephen J. Turnbull, he indicated to me
> that you are knowledgeable regarding the emodule system
> of xemacs21.  I am trying to write a module which
> provides bindings to GNOME AT-SPI.  A long story short:
> This binding has as primary data type a so-called object, which
> is represented by a pointer.  For the bindings being really useful,
> I'd need to be able to encapsulate this pinter in a new
> Emacs data type which can:
> 1. Set a special print representation such that some information about
> the object could be printed for convenience.  Something like:
> #<Accessible 0xsomeaddr name="objects-name" role="objects-role">
>
> 2. Set a free function which would unreference the pointer
> when gc decides to free the object in Lisp.
>
> Is such a thing possible using emodules.  If so, could you give
> me some pointers as to where find information on how to achieve
> this?

Yes, it is possible.  You can find examples of this kind of thing in the
LDAP and PostgreSQL modules that come with the XEmacs sources, as well
as my own ViaVoice module:

<URL:http://www.ittc.ku.edu/~james/xemacs/viavoice.html>

The canonical source of information for modules is the emodules info
file that comes with XEmacs.  Here's a brief rundown on how to do what
you want, though:

1) Make a header file that describes your type.  In there, do something
   along these lines:

struct gnome_at_spi
{
  struct lcrecord_header header;
  void *ptr; /* Or whatever type this pointer actually is */
};

DECLARE_EXTERNAL_LRECORD (gnome_at_spi_, struct gnome_at_spi);
#define XGNOME_AT_SPI(x) XRECORD (x, gnome_at_spi, struct gnome_at_spi)
#define XSETGNOME_AT_SPI(x, p) XSETRECORD (x, p, gnome_at_spi)
#define GNOME_AT_SPIP(x) RECORDP (x, gnome_at_spi)
#define CHECK_GNOME_AT_SPI(x) CHECK_RECORD (x, gnome_at_spi)
#define CONCHECK_GNOME_AT_SPI(x) CONCHECK_RECORD (x, gnome_at_spi)
#define XREALGNOME_AT_SPI(x) XGNOME_AT_SPI(x)->ptr

extern Lisp_Object make_gnome_at_spi (void * /* or whatever it is */);

2) Then in your .c file that contains the actual implementation, do
   something like this:

Lisp_Object Qgnome_at_spip;	/* DEFINE_EXTERNAL should really do this */

Lisp_Object
make_gnome_at_spi (void *ptr)
{
  Lisp_Object the_gnome_at_spi;
  struct gnome_at_spi *gnome_thing =
    alloc_lcrecord_type(struct gnome_at_spi, &lrecord_gnome_at_spi);

  gnome_thing->ptr = ptr;
  XSETGNOME_AT_SPI (the_gnome_at_spi, gnome_thing);
  return the_gnome_at_spi;
}

void
finalize_gnome_at_spi (void *header, int for_disksave)
{
  struct gnome_at_spi *gnome_thing = (struct gnome_at_spi *)header;
  if (!for_disksave)
    call_my_gnome_dereferencing_function (gnome_thing);
}

void
print_gnome_at_spi (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
{
  write_c_string ("#<gnome-at-spi>", printcharfun);
}

DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION ("gnome-at-spi", gnome_at_spi, 0, 0,
					print_gnome_at_spi,
					finalize_gnome_at_spi, 0, 0, 0,
					struct gnome_at_spi);

void
syms_of_gnome_at_spi ()
{
  INIT_EXTERNAL_LRECORD_IMPLEMENTATION (gnome_at_spi);
}


Let me know if you need any more information.  Regards,
--
Jerry James
Email: james@ittc.ku.edu -or- jamesj@acm.org
WWW:   http://www.ittc.ku.edu/~james/
Last Modified: 2006-11-27 00:01:56
You can view the Source Code of this page