This is a version of the dynamic loading patch which was made against
the Emacs 22 codebase rather than the Emacs 21 one.

Index: configure.in
===================================================================
RCS file: /cvsroot/emacs/emacs/configure.in,v
retrieving revision 1.404
diff -u -p -r1.404 configure.in
--- configure.in	12 Jan 2006 22:41:38 -0000	1.404
+++ configure.in	21 Jan 2006 21:34:50 -0000
@@ -2688,6 +2691,45 @@ if test $emacs_cv_langinfo_codeset = yes
     [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
 fi
 
+dnl Note that we need to build libltdl even if a development version of
+dnl it is installed since we need to define LT_LAZY_OR_NOW.
+AC_LIBLTDL_CONVENIENCE
+AC_SUBST(INCLTDL)
+AC_SUBST(LIBLTDL)
+AC_LIBTOOL_DLOPEN
+dnl AC_LIBLTDL_INSTALLABLE
+AM_PROG_LIBTOOL
+case `./libtool --config | grep ^dlopen_support=` in
+dlopen_support=yes)
+   CAN_DLOPEN=yes;
+   AC_DEFINE(CAN_DLOPEN, 1, [Define if you have loadable module support])
+   build_emacs_module=build-emacs-module ;;
+dlopen_support=no) ;;
+*)
+   AC_MSG_ERROR([Bad output from libtool --config.  Probably inappropriate version.]) ;;
+esac
+AC_SUBST(LIBTOOL_DEPS)
+AC_SUBST(EXPORT_DYNAMIC)
+if test "$CAN_DLOPEN" = yes; then
+  EXPORT_DYNAMIC=-export-dynamic
+  AC_CONFIG_SUBDIRS(libltdl)
+  dnl Fixme: can we do anything sensible without gcc and without the deps
+  dnl support from automake, for instance?
+  if test "$GCC" = yes; then
+    cat >conftest.c <<+
+#include "$machfile"
+#include "$opsysfile"
++
+dnl Sample gcc o/p:
+dnl conftest.o: conftest.c s/irix6-5.h s/irix5-0.h s/usg5-4.h s/usg5-3.h \
+dnl  m/mips.h
+    cwd=`pwd`; export cwd
+    config_includes=`( cd "$srcdir/src"
+                       $CC -E -MM -I. "$cwd"/conftest.c 2>/dev/null |
+  		     sed -e 's/^.*conftest.c //' | tr '\\\\\n' '  ' )`
+  fi
+fi
+
 AC_CHECK_TYPES(size_t)
 
 AC_TYPE_MBSTATE_T
@@ -2778,6 +2820,8 @@ AC_SUBST(machfile)
 AC_SUBST(opsysfile)
 AC_SUBST(GETLOADAVG_LIBS)
 AC_SUBST(carbon_appdir)
+AC_SUBST(build_emacs_module)
+AC_SUBST(config_includes)
 
 AC_DEFINE_UNQUOTED(EMACS_CONFIGURATION,  "${canonical}",
 		   [Define to the canonical Emacs configuration name.])
@@ -3163,6 +3214,7 @@ echo "  Does Emacs use -ltiff?          
 echo "  Does Emacs use -lungif?                                 ${HAVE_GIF}"
 echo "  Does Emacs use -lpng?                                   ${HAVE_PNG}"
 echo "  Does Emacs use X toolkit scroll bars?                   ${USE_TOOLKIT_SCROLL_BARS}"
+echo "  Does Emacs support dynamic modules?                     ${CAN_DLOPEN:-no}"
 echo
 
 if test $USE_XASSERTS = yes; then
@@ -3189,12 +3241,18 @@ AC_EGREP_CPP(yes..yes,
 	CPP_NEED_TRADITIONAL=no,
 	CPP_NEED_TRADITIONAL=yes)
 
-AC_OUTPUT(Makefile lib-src/Makefile.c:lib-src/Makefile.in oldXMenu/Makefile \
-	man/Makefile lwlib/Makefile src/Makefile.c:src/Makefile.in \
-	lisp/Makefile lispref/Makefile lispintro/Makefile leim/Makefile, [
-
+AC_CONFIG_FILES(Makefile lib-src/Makefile.c:lib-src/Makefile.in \
+		oldXMenu/Makefile man/Makefile lwlib/Makefile \
+		src/Makefile.c:src/Makefile.in lisp/Makefile \
+		lispref/Makefile lispintro/Makefile leim/Makefile \
+		lib-src/build-emacs-module)
+
+m4_pattern_allow([AH_VERBATIM])
+m4_pattern_allow([AC_LIBTOOL_CXX])
+m4_pattern_allow([AC_DEFUN])
+AC_CONFIG_COMMANDS([default], [
 ### Make the necessary directories, if they don't exist.
-for dir in etc lisp ; do
+for dir in etc lisp libltdl; do
   test -d ${dir} || mkdir ${dir}
 done
 
@@ -3255,6 +3313,29 @@ echo creating src/Makefile
   mv -f Makefile.new Makefile
 )
 
+chmod +x lib-src/build-emacs-module
+
+# This is messy, but we need to fix up config-h.in
+if test -d "$srcdir/libltdl" && test ! -f "$srcdir/libltdl/acinclude.m4"; then
+  cat <<+ > "$srcdir/libltdl/acinclude.m4"
+[AH_VERBATIM]([[LT_LAZY]],
+[[#ifndef LT_LAZY_OR_NOW
+#  ifdef RTLD_NOW
+#    define LT_LAZY_OR_NOW RTLD_NOW
+#  else
+#    ifdef DL_NOW
+#      define LT_LAZY_OR_NOW DL_NOW
+#    endif
+#  endif
+#endif
+]])
++
+  # Rebuild config-h.in.  (We cond't need to rebuild configure.)
+  (cd "$srcdir/libltdl" &&
+      echo '[AC_DEFUN([AC_LIBTOOL_CXX],)]' >>aclocal.m4 && aclocal &&
+      autoheader)
+fi
+
 if test ! -f src/.gdbinit && test -f $srcdir/src/.gdbinit; then
   echo creating src/.gdbinit
   echo source $srcdir/src/.gdbinit > src/.gdbinit
@@ -3264,6 +3345,7 @@ fi
 touch src/config.stamp
 
 ], [GCC="$GCC" NON_GNU_CPP="$NON_GNU_CPP" CPP="$CPP" CPP_NEED_TRADITIONAL="$CPP_NEED_TRADITIONAL" CPPFLAGS="$CPPFLAGS"])
+AC_OUTPUT
 
 m4_if(dnl	Do not change this comment
    arch-tag: 156a4dd5-bddc-4d18-96ac-f37742cf6a5e
Index: Makefile.in
===================================================================
RCS file: /cvsroot/emacs/emacs/Makefile.in,v
retrieving revision 1.308
diff -u -p -r1.308 Makefile.in
--- Makefile.in	3 Nov 2005 17:00:25 -0000	1.308
+++ Makefile.in	21 Jan 2006 21:34:50 -0000
@@ -77,6 +77,8 @@ CPP=@CPP@
 C_SWITCH_SYSTEM=@c_switch_system@
 ALLOCA=@ALLOCA@
 LN_S=@LN_S@
+# The LTDL flags are only relevant in src, but the flags are explicitly
+# set for the sub-make for some reason.
 CFLAGS=@CFLAGS@
 LDFLAGS=@LDFLAGS@
 CPPFLAGS=@CPPFLAGS@
@@ -152,6 +154,8 @@ srcdir=@srcdir@
 # Tell make where to find source files; this is needed for the makefiles.
 VPATH=@srcdir@
 
+top_srcdir=@top_srcdir@
+
 # Where to find the application default.
 x_default_search_path=@x_default_search_path@
 
@@ -238,7 +242,7 @@ EMACSFULL = `echo emacs-${version}${EXEE
 # Subdirectories to make recursively.  `lisp' is not included
 # because the compiled lisp files are part of the distribution.
 # leim is not included because it needs special handling.
-SUBDIR = lib-src src
+SUBDIR = lib-src libltdl src
 
 # The makefiles of the directories in $SUBDIR.
 SUBDIR_MAKEFILES = lib-src/Makefile man/Makefile lispref/Makefile lispintro/Makefile src/Makefile oldXMenu/Makefile lwlib/Makefile leim/Makefile
@@ -345,6 +349,9 @@ lwlib/Makefile: $(srcdir)/lwlib/Makefile
 leim/Makefile: $(srcdir)/leim/Makefile.in config.status
 	./config.status
 
+libltdl/Makefile: $(srcdir)/libltdl/Makefile.in config.status
+	./config.status
+
 # ==================== Installation ====================
 
 ## If we let lib-src do its own installation, that means we
@@ -354,7 +361,7 @@ leim/Makefile: $(srcdir)/leim/Makefile.i
 ## On AIX, use tar xBf.
 ## On Xenix, use tar xpf.
 
-.PHONY: install mkdir
+.PHONY: install mkdir install-module-stuff
 
 ## We delete each directory in ${COPYDESTS} before we copy into it;
 ## that way, we can reinstall over directories that have been put in
@@ -363,7 +370,8 @@ leim/Makefile: $(srcdir)/leim/Makefile.i
 ## source exists and is distinct from the destination.
 ### We do install-arch-indep first because
 ### the executable needs the Lisp files and DOC file to work properly.
-install: all install-arch-indep install-arch-dep install-leim blessmail
+install: all install-arch-indep install-arch-dep install-leim blessmail \
+	install-module-stuff
 	@true
 
 ### Install the executables that were compiled specifically for this machine.
@@ -532,6 +542,29 @@ install-leim: leim/Makefile mkdir
 install-strip:
 	$(MAKE) INSTALL_STRIP=-s install
 
+install-module-stuff: mkdir
+#ifdef CAN_DLOPEN
+# lisp.h actually isn't architecture-dependent, but we might as well
+# keep it with config.h, which is, so we only need one include directory
+# for building modules.
+	${INSTALL_DATA} ${srcdir}/src/lisp.h ${archlibdir}/lisp.h
+	${INSTALL_DATA} src/config.h ${archlibdir}/config.h
+	if test "@config_includes@"; then \
+	  for i in @config_includes@; do \
+	    case $$i in \
+	    /*) ;; \
+	    *) ${INSTALL_DATA} ${srcdir}/src/$$i ${archlibdir}/$$i;; \
+	    esac; \
+	  done; \
+	else \
+	  echo "*** Not using GCC, so can't check all dependents of config.h."; \
+	  echo "*** Check headers installed in $archlibdir."; \
+	  ${INSTALL_DATA} ${srcdir}/src/@machfile@ ${archlibdir}/@machfile@; \
+	  ${INSTALL_DATA} ${srcdir}/src/@opsysfile@ ${archlibdir}/@opsysfile@; \
+	fi
+	${INSTALL_PROGRAM} ${INSTALL_STRIP} libtool ${archlibdir}/libtool
+#endif
+
 ### Build all the directories we're going to install Emacs in.	Since
 ### we may be creating several layers of directories (for example,
 ### /usr/local/lib/emacs/19.0/mips-dec-ultrix4.2), we use mkinstalldirs
@@ -546,6 +579,7 @@ mkdir: FRC
 	  ${datadir}/emacs/site-lisp \
 	  ${datadir}/emacs/${version}/site-lisp \
 	  `echo ${locallisppath} | sed 's/:/ /g'`
+	  $(srcdir)/mkinstalldirs ${archlibdir}/m ${archlibdir}/s
 
 ### Delete all the installed files that the `install' target would
 ### create (but not the noninstalled files such as `make all' would
@@ -598,6 +632,7 @@ mostlyclean: FRC
 	-(cd lispref &&   $(MAKE) $(MFLAGS) mostlyclean)
 	-(cd lispintro &&   $(MAKE) $(MFLAGS) mostlyclean)
 	(cd leim;     $(MAKE) $(MFLAGS) mostlyclean)
+	(cd libltdl;  $(MAKE) $(MFLAGS) mostlyclean)
 
 ### `clean'
 ###      Delete all files from the current directory that are normally
@@ -616,6 +651,8 @@ clean: FRC
 	-(cd lispref &&   $(MAKE) $(MFLAGS) clean)
 	-(cd lispintro &&   $(MAKE) $(MFLAGS) clean)
 	(cd leim;     $(MAKE) $(MFLAGS) clean)
+	(cd libltdl;  $(MAKE) $(MFLAGS) clean)
+	rm -f libtool ltmain.sh ltconfig
 
 ### `distclean'
 ###      Delete all files from the current directory that are created by
@@ -624,7 +661,7 @@ clean: FRC
 ###      `make distclean' should leave only the files that were in the
 ###      distribution.
 top_distclean=\
-	rm -f config.status config.cache config.log ; \
+	rm -f config.status config.cache config.log libtool ; \
 	rm -f Makefile ${SUBDIR_MAKEFILES} ; \
 	if [ -d lock ] ; then (cd lock && (rm -f * || true)); else true; fi
 distclean: FRC
@@ -637,6 +674,7 @@ distclean: FRC
 	(cd lispintro &&    $(MAKE) $(MFLAGS) distclean)
 	(cd leim;     $(MAKE) $(MFLAGS) distclean)
 	(cd lisp;     $(MAKE) $(MFLAGS) distclean)
+	(cd libltdl;  $(MAKE) $(MFLAGS) distclean)
 	${top_distclean}
 
 ### `maintainer-clean'
@@ -790,3 +828,7 @@ bootstrap-clean-before-fast: FRC
 	-(cd lispref &&   $(MAKE) $(MFLAGS) clean)
 	-(cd lispintro &&   $(MAKE) $(MFLAGS) clean)
 	(cd leim;     $(MAKE) $(MFLAGS) clean)
+
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
Index: lib-src/Makefile.in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/Makefile.in,v
retrieving revision 1.146
diff -u -p -r1.146 Makefile.in
--- lib-src/Makefile.in	22 Dec 2005 16:18:39 -0000	1.146
+++ lib-src/Makefile.in	21 Jan 2006 21:34:50 -0000
@@ -101,15 +100,17 @@ INSTALL_STRIP =
 
 # Things that a user might actually run,
 # which should be installed in bindir.
-INSTALLABLES = etags${EXEEXT} ctags${EXEEXT} emacsclient${EXEEXT} b2m${EXEEXT} ebrowse${EXEEXT}
+INSTALLABLES = etags${EXEEXT} ctags${EXEEXT} emacsclient${EXEEXT} b2m${EXEEXT} ebrowse${EXEEXT} @build_emacs_module@
 INSTALLABLE_SCRIPTS = rcs-checkin grep-changelog
 
 # Things that Emacs runs internally, or during the build process,
 #  which should not be installed in bindir.
-UTILITIES=  profile${EXEEXT} digest-doc${EXEEXT} sorted-doc${EXEEXT} movemail${EXEEXT} cvtmail${EXEEXT} fakemail${EXEEXT} \
-            yow${EXEEXT} hexl${EXEEXT} update-game-score${EXEEXT}
+UTILITIES=  profile${EXEEXT} digest-doc${EXEEXT} sorted-doc${EXEEXT} \
+            movemail${EXEEXT} cvtmail${EXEEXT} fakemail${EXEEXT} \
+            yow${EXEEXT} hexl${EXEEXT} update-game-score${EXEEXT} \
+            make-docfile${EXEEXT}
 
-DONT_INSTALL= test-distrib${EXEEXT} make-docfile${EXEEXT}
+DONT_INSTALL= test-distrib${EXEEXT}
 
 # Like UTILITIES, but they're not system-dependent, and should not be
 #  deleted by the distclean target.
Index: src/Makefile.in
===================================================================
RCS file: /cvsroot/emacs/emacs/src/Makefile.in,v
retrieving revision 1.323
diff -u -p -r1.323 Makefile.in
--- src/Makefile.in	12 Jan 2006 21:17:37 -0000	1.323
+++ src/Makefile.in	21 Jan 2006 21:34:50 -0000
@@ -55,6 +55,11 @@ etc = $(dot)$(dot)/etc/
 oldXMenudir = $(dot)$(dot)/oldXMenu/
 lwlibdir = $(dot)$(dot)/lwlib/
 lispdir = $(dot)$(dot)/lisp/
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+INCLTDL = @INCLTDL@
+LIBLTDL = @LIBLTDL@
+LIBTOOL = @LIBTOOL@
 
 # Configuration files for .o files to depend on.
 M_FILE = ${srcdir}/@machfile@
@@ -514,16 +519,21 @@ GNULIB_VAR =
 STARTFLAGS = -T LD_TEXT_START_ADDR -e __start
 #endif
 
+#ifdef CAN_DLOPEN
+#define LT_PREFIX $(LIBTOOL) --mode=link
+#else
+#define LT_PREFIX
+#endif
 #ifdef ORDINARY_LINK
-LD = $(CC)
+LD = LT_PREFIX $(CC)
 #else
 #ifdef COFF_ENCAPSULATE
-LD=$(CC) -nostdlib
+LD = LT_PREFIX $(CC) -nostdlib
 #else /* not ORDINARY_LINK */
 #ifdef LINKER
-LD=LINKER
+LD=LT_PREFIX LINKER
 #else /* not LINKER */
-LD=ld
+LD=LT_PREFIX ld
 #endif /* not LINKER */
 #endif /* not COFF_ENCAPSULATE */
 #endif /* not ORDINARY_LINK */
@@ -531,7 +541,7 @@ LD=ld
 /* Flags to pass to LD only for temacs.  */
 /* Don't split this line with a backslash.  That can cause trouble with
    some cpps.  */
-TEMACS_LDFLAGS = LD_SWITCH_SYSTEM LD_SWITCH_SYSTEM_TEMACS LD_SWITCH_MACHINE LD_SWITCH_MACHINE_TEMACS LD_SWITCH_SITE
+TEMACS_LDFLAGS = LD_SWITCH_SYSTEM LD_SWITCH_SYSTEM_TEMACS LD_SWITCH_MACHINE LD_SWITCH_MACHINE_TEMACS LD_SWITCH_SITE @EXPORT_DYNAMIC@
 
 /* A macro which other sections of Makefile can redefine to munge the
    flags before they're passed to LD.  This is helpful if you have
@@ -930,7 +938,7 @@ SOME_MACHINE_LISP = ${dotdot}/lisp/mouse
 LIBES = $(LOADLIBES) $(LIBS) $(LIBX) $(LIBSOUND) \
    LIBS_SYSTEM LIBS_MACHINE LIBS_TERMCAP \
    LIBS_DEBUG $(GETLOADAVG_LIBS) $(GNULIB_VAR) LIB_MATH LIB_STANDARD \
-   $(GNULIB_VAR)
+   $(GNULIB_VAR) $(LIBLTDL)
 
 /* Enable recompilation of certain other files depending on system type.  */
 
@@ -1242,6 +1250,7 @@ print.o: print.c process.h frame.h windo
    $(config_h) dispextern.h termchar.h $(INTERVAL_SRC) msdos.h composite.h
 lread.o: lread.c commands.h keyboard.h buffer.h epaths.h charset.h \
  $(config_h) $(INTERVAL_SRC) termhooks.h coding.h msdos.h
+	$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(INCLTDL) $<
 
 /* Text properties support */
 textprop.o: textprop.c buffer.h window.h dispextern.h $(INTERVAL_SRC) \
Index: src/doc.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/doc.c,v
retrieving revision 1.116
diff -u -p -r1.116 doc.c
--- src/doc.c	11 Nov 2005 15:36:36 -0000	1.116
+++ src/doc.c	21 Jan 2006 21:34:50 -0000
@@ -51,6 +51,7 @@ extern char *index P_ ((const char *, in
 Lisp_Object Vdoc_file_name;
 
 Lisp_Object Qfunction_documentation;
+extern Lisp_Object Vfile_name_coding_system;
 
 /* A list of files used to build this Emacs binary.  */
 static Lisp_Object Vbuild_files;
@@ -258,28 +259,37 @@ get_doc_string (filepos, unibyte, defini
   emacs_close (fd);
 
   /* Sanity checking.  */
-  if (CONSP (filepos))
-    {
-      int test = 1;
-      if (get_doc_string_buffer[offset - test++] != ' ')
-	return Qnil;
-      while (get_doc_string_buffer[offset - test] >= '0'
-	     && get_doc_string_buffer[offset - test] <= '9')
-	test++;
-      if (get_doc_string_buffer[offset - test++] != '@'
-	  || get_doc_string_buffer[offset - test] != '#')
-	return Qnil;
-    }
-  else
-    {
-      int test = 1;
-      if (get_doc_string_buffer[offset - test++] != '\n')
-	return Qnil;
-      while (get_doc_string_buffer[offset - test] > ' ')
-	test++;
-      if (get_doc_string_buffer[offset - test] != '\037')
-	return Qnil;
-    }
+  {
+    int l = strlen (name);
+    if (CONSP (filepos)
+#ifdef CAN_DLOPEN
+	&&
+	/* check for doc file for dynamic module */
+	! (strcmp (name + l - 4, ".doc") || strcmp (name + l - 4, ".DOC"))
+#endif
+	)
+      {
+	int test = 1;
+	if (get_doc_string_buffer[offset - test++] != ' ')
+	  return Qnil;
+	while (get_doc_string_buffer[offset - test] >= '0'
+	       && get_doc_string_buffer[offset - test] <= '9')
+	  test++;
+	if (get_doc_string_buffer[offset - test++] != '@'
+	    || get_doc_string_buffer[offset - test] != '#')
+	  return Qnil;
+      }
+    else
+      {
+	int test = 1;
+	if (get_doc_string_buffer[offset - test++] != '\n')
+	  return Qnil;
+	while (get_doc_string_buffer[offset - test] > ' ')
+	  test++;
+	if (get_doc_string_buffer[offset - test] != '\037')
+	  return Qnil;
+      }
+  }
 
   /* Scan the text and perform quoting with ^A (char code 1).
      ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_.  */
@@ -344,6 +353,10 @@ static int
 reread_doc_file (file)
      Lisp_Object file;
 {
+#ifdef CAN_DLOPEN
+  int l;
+  char *s;
+#endif
 #if 0
   Lisp_Object reply, prompt[3];
   struct gcpro gcpro1;
@@ -359,6 +372,13 @@ reread_doc_file (file)
 
   if (NILP (file))
     Fsnarf_documentation (Vdoc_file_name);
+#if CAN_DLOPEN
+  /* Reloading isn't relevant for dynamic modules, though we shouldn't
+     actually get here.  */
+  else if (s = SDATA (file), l = strlen (s),
+	   (strcmp (s + l - 4, ".doc") || strcmp (s + l - 4, ".DOC")))
+    return 0;
+#endif
   else
     Fload (file, Qt, Qt, Qt, Qnil);
 
@@ -731,6 +751,97 @@ the same file name is found in the `doc-
   emacs_close (fd);
   return Qnil;
 }
+
+/* Used for dynamic modules to snarf from FILENAME (module.doc).  */
+void
+snarf_documentation (filename)
+     Lisp_Object filename;
+{
+  int fd;
+  char buf[1024 + 1];
+  register int filled;
+  register int pos;
+  register char *p, *end;
+  Lisp_Object sym, encoded_name;
+  char *name;
+  int skip_file = 0;
+
+  CHECK_STRING (filename);
+
+  encoded_name = Fencode_coding_string (filename,
+                                        Vfile_name_coding_system, Qt);
+  name = XSTRING (encoded_name)->data;
+
+  fd = emacs_open (name, O_RDONLY, 0);
+  if (fd < 0)
+    report_file_error ("Opening doc string file",
+		       Fcons (build_string (name), Qnil));
+  filled = 0;
+  pos = 0;
+  while (1)
+    {
+      if (filled < 512)
+	filled += emacs_read (fd, &buf[filled], sizeof buf - 1 - filled);
+      if (!filled)
+	break;
+
+      buf[filled] = 0;
+      p = buf;
+      end = buf + (filled < 512 ? filled : filled - 128);
+      while (p != end && *p != '\037') p++;
+      /* p points to ^_Ffunctionname\n or ^_Vvarname\n.  */
+      if (p != end)
+	{
+	  end = (char *) index (p, '\n');
+
+          /* See if this is a file name, and if it is a file in build-files.  */
+          if (p[1] == 'S' && end - p > 4 && end[-2] == '.'
+              && (end[-1] == 'o' || end[-1] == 'c'))
+            {
+              int len = end - p - 2;
+              char *fromfile = alloca (len + 1);
+              strncpy (fromfile, &p[2], len);
+              fromfile[len] = 0;
+              if (fromfile[len-1] == 'c')
+                fromfile[len-1] = 'o';
+            }
+
+	  sym = oblookup (Vobarray, p + 2,
+			  multibyte_chars_in_text (p + 2, end - p - 2),
+			  end - p - 2);
+	  if (SYMBOLP (sym))
+	    {
+	      /* Attach a docstring to a variable?  */
+	      if (p[1] == 'V')
+		{
+		  /* Install file-position as variable-documentation property
+		     and make it negative for a user-variable
+		     (doc starts with a `*').  */
+		  Fput (sym, Qvariable_documentation,
+			Fcons (filename,
+			       make_number ((pos + end + 1 - buf)
+					    * (end[1] == '*' ? -1 : 1))));
+		}
+
+	      /* Attach a docstring to a function?  */
+	      else if (p[1] == 'F')
+		Fput (sym, Qfunction_documentation,
+		      Fcons (filename, make_number ((pos + end + 1 - buf))));
+
+	      else if (p[1] == 'S')
+		; /* Just a source file name boundary marker.  Ignore it.  */
+
+	      else
+		error ("DOC file invalid at position %d", pos);
+	    }
+	}
+      pos += end - buf;
+      filled -= end - buf;
+      bcopy (end, buf, filled);
+    }
+  emacs_close (fd);
+  return;
+}
 
 DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
        Ssubstitute_command_keys, 1, 1, 0,
Index: src/lread.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/lread.c,v
retrieving revision 1.347
diff -u -p -r1.347 lread.c
--- src/lread.c	20 Jan 2006 19:53:36 -0000	1.347
+++ src/lread.c	21 Jan 2006 21:34:51 -0000
@@ -27,6 +27,9 @@ Boston, MA 02110-1301, USA.  */
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <errno.h>
+#if CAN_DLOPEN
+#include <ltdl.h>
+#endif
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
@@ -91,6 +94,9 @@ Lisp_Object Qeval_buffer_list, Veval_buf
 extern Lisp_Object Qevent_symbol_element_mask;
 extern Lisp_Object Qfile_exists_p;
 
+extern int command_loop_level;	/* keyboard.c */
+extern void snarf_documentation P_ ((Lisp_Object)); /* doc.c */
+
 /* non-zero iff inside `load' */
 int load_in_progress;
 
@@ -205,6 +211,9 @@ int load_dangerous_libraries;
 
 static Lisp_Object Vbytecomp_version_regexp;
 
+/* List of dynamically loaded module names.  */
+static Lisp_Object modules_list;
+
 static void to_multibyte P_ ((char **, char **, int *));
 static void readevalloop P_ ((Lisp_Object, FILE*, Lisp_Object,
 			      Lisp_Object (*) (), int,
@@ -741,6 +750,11 @@ Return t if file exists.  */)
 	  else if (size > 4
 		   && !strcmp (SDATA (file) + size - 4, ".elc"))
 	    must_suffix = Qnil;
+#ifdef CAN_DLOPEN
+	  else if (size > 3
+		   && !strcmp (XSTRING (file)->data + size - 3, ".la"))
+	    must_suffix = Qnil;
+#endif
 	  /* Don't insist on adding a suffix
 	     if the argument includes a directory name.  */
 	  else if (! NILP (Ffile_name_directory (file)))
@@ -866,6 +880,78 @@ Return t if file exists.  */)
 	  UNGCPRO;
 	}
     }
+#if CAN_DLOPEN
+  else if (!bcmp (&(XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 3]),
+		  ".la", 3))
+    /* Load dynamic modules, but not when they are remote and have no
+       handler!  */
+    /* Fixme: what about fd == 2?  */
+    {
+      /* Fixme: will it actually work when dumping?  */
+      if (!NILP (Vpurify_flag))
+	error ("Can't dynamic-load modules when dumping");
+      if (fd != -2)
+	{
+	  lt_dlhandle handle;
+	  void (*init) () = 0;
+	  Lisp_Object module_name;
+	  Lisp_Object init_name;
+	  Lisp_Object args[2];
+	  struct gcpro gcpro2;
+	  int i;
+
+	  emacs_close (fd);
+	  if (NILP (nomessage))
+	    message_with_string ("Loading %s (module; subject to the GPL)...",
+				 file, 1);
+	  /* In case file-name-nondirectory GCs.  */
+	  GCPRO1 (found);
+	  module_name = Fsubstring (Ffile_name_nondirectory (found),
+				    make_number (0), make_number (-3));
+	  UNGCPRO;
+	  /* Fixme: Is it reasonable to dlopen twice?  */
+	  if (!NILP (Fmember (module_name, modules_list)))
+	    error ("Module %s already loaded", XSTRING (module_name)->data);
+	  handle = lt_dlopen (XSTRING (found)->data);
+	  if (!handle)
+	    error ("Can't load module %s: %s", XSTRING (module_name)->data,
+		   lt_dlerror ());
+	  modules_list = Fcons (module_name, modules_list);
+	  args[0] = build_string ("init_");
+	  args[1] = module_name;
+	  /* Convention: To form init function name, replace hyphens
+	     in module name with underscores. */
+	  for (i = 0; i < XINT (Flength (module_name)); i++)
+	    if (!NILP (Feq (Faref (args[1], make_number (i)),
+			    make_number ('-'))))
+	      Faset (args[1], make_number (i), make_number ('_'));
+	  init_name = Fconcat (2, args);
+	  init = (void (*) ()) lt_dlsym (handle, XSTRING (init_name)->data);
+	  if (!init)
+	    error ("Init function not found in module %s",
+		   XSTRING (module_name)->data);
+	  GCPRO2 (found, file);
+	  (*init) ();
+	  UNGCPRO;
+	  {
+	    Lisp_Object doc_name;
+
+	    args[0] = Fsubstring (found, make_number (0), make_number (-3));
+	    args[1] = build_string (".doc");
+	    doc_name = Fconcat (2, args);
+	    snarf_documentation (doc_name);
+	  }
+	  /* Run any load-hooks for this file.  */
+	  temp = Fassoc (file, Vafter_load_alist);
+	  if (!NILP (temp))
+	    Fprogn (Fcdr (temp));
+	  if (!noninteractive && NILP (nomessage))
+	    message_with_string ("Loading %s (module subject to the GPL)...done",
+				 file, 1);
+	  return unbind_to (count, Qt);
+	}
+    }
+#endif
   else
     {
       /* We are loading a source file (*.el).  */
@@ -3832,6 +3931,17 @@ dir_warning (format, dirname)
     message_dolog (buffer, strlen (buffer), 0, STRING_MULTIBYTE (dirname));
 }
 
+DEFUN ("dynamic-modules-p", Fdynamic_modules_p, Sdynamic_modules_p, 0, 0, 0,
+       "Return non-nil if this Emacs supports dynamic modules.")
+     ()
+{
+#if CAN_DLOPEN
+  return Qt;
+#else
+  return Qnil;
+#endif
+}
+
 void
 syms_of_lread ()
 {
@@ -3849,6 +3959,7 @@ syms_of_lread ()
   defsubr (&Sget_file_char);
   defsubr (&Smapatoms);
   defsubr (&Slocate_file_internal);
+  defsubr (&Sdynamic_modules_p);
 
   DEFVAR_LISP ("obarray", &Vobarray,
 	       doc: /* Symbol table for use by `intern' and `read'.
@@ -3905,6 +4016,9 @@ otherwise to default specified by file `
 This list should not include the empty string.  */);
   Vload_suffixes = Fcons (build_string (".elc"),
 			  Fcons (build_string (".el"), Qnil));
+#ifdef CAN_DLOPEN
+  Vload_suffixes = Fcons (build_string (".la"), Vload_suffixes);
+#endif
   /* We don't use empty_string because it's not initialized yet.  */
   default_suffixes = Fcons (build_string (""), Qnil);
   staticpro (&default_suffixes);
@@ -4070,7 +4184,13 @@ to load.  See also `load-dangerous-libra
 
   Vloads_in_progress = Qnil;
   staticpro (&Vloads_in_progress);
+
+#ifdef CAN_DLOPEN
+  staticpro (&modules_list);
+  modules_list = Qnil;
+  lt_dlinit ();
+#endif
 }
 
 /* arch-tag: a0d02733-0f96-4844-a659-9fd53c4f414d
--- /dev/null	Thu Nov 30 15:25:58 2000
+++ lib-src/build-emacs-module.in	Tue Mar 19 23:54:53 2002
@@ -0,1 +1,107 @@
+#! /bin/sh
+
+# Build dynamically-loadable modules from source.
+
+# Copyright (C) 2002 Free Software Foundation Inc.
+
+# Author: Dave Love <fx@gnu.org>
+
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GNU Emacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+version=@version@
+configuration=@configuration@
+libexecdir="@libexecdir@"
+dest=`pwd`
+# Could set this in the environment to use uninstalled, assuming lisp.h,
+# cofig.h and make-docfile are all in the same place.
+archlibdir=${archlibdir:-@archlibdir@}
+
+while test $# -gt 0
+do
+  case "$1" in
+      --help)
+          echo "\
+Usage: build-emacs-module [--cflags CFLAGS] [--ldflags LDFLAGS] \\
+           [--dest DIRECTORY] FILE...
+
+Compile C module source FILEs into files for dynamically loading the
+module into Emacs.  CFLAGS and LDFLAGS (both single arguments) specify
+flags respectively for compiling and linking in addition to those used
+to build Emacs.  if the module needs to link against extra libraries,
+put the relevant -L and -l flags in LDFLAGS.  DEST is a directory into
+which to install the module (default current directory).  This must be
+in the Emacs load-path list when the module is loaded.  E.g.:
+  build-emacs-module --ldflags '-lfoo -L/usr/local/lib/foodir' foo.c
+
+Two module files are installed for each FILE with the same base name
+as FILE, one with extension .la and the other with extension
+appropriate for a shared library, e.g. .so on an ELF system.  A file
+of documentation strings with extension .doc is installed too.
+
+Dynamically-linked modules must comply ith the Emacs licence (the GNU GPL)
+just as if they were statically linked."
+          exit;;
+      --version)
+          echo "build-emacs-module Emacs @version@
+Copyright (C) Free Software Foundation, Inc.
+This program is distributed under the same terms as Emacs."
+          exit ;;
+      --cflags)
+          shift
+          cflags="$1"
+          shift ;;
+      --cflags=*)
+          cflags=`echo $1 | sed 's/--cflags=//'`
+          shift ;;
+      --ldflags)
+          shift
+          ldflags="$1"
+          shift ;;
+      --ldflags=*)
+          ldflags=`echo $1 | sed 's/--ldflags=//'`
+          shift ;;
+      --dest)
+          shift
+          dest="$1"
+          shift ;;
+      --dest=*)
+          dest=`echo $1 | sed 's/--dest=//'`
+          shift ;;
+      --)
+          shift
+          break ;;
+      *)
+          break ;;
+  esac
+done
+
+for file
+do
+  basename=`basename $file .c`
+  "$archlibdir/libtool" --mode=compile @CC@ @CFLAGS@ $cflags -I"$archlibdir" -c "$file" &&
+  "$archlibdir/libtool" --mode=link @CC@ @LDFLAGS@ $ldflags -module -avoid-version -rpath `pwd` -o "$basename.la" "$basename.lo" &&
+  echo "Installing in $dest" &&
+# Sink confusing output from this step (not suppressed by --quiet).
+  "$archlibdir/libtool" --quiet --mode=install @INSTALL@ "$basename.la" "$dest/$basename.la" 2>/dev/null >/dev/null &&
+  "$archlibdir/make-docfile" "$file" >"$dest/$basename.doc" &&
+# The archive isn't wanted.
+  rm -f "$dest/$basename.a" || exit 1
+  test "$dest" != `pwd` &&
+  "$archlibdir/libtool" --mode=clean rm -f "$basename.la" "$basename.lo" || exit 1
+done
--- /dev/null	Thu Nov 30 15:25:58 2000
+++ src/mod-test.c	Tue Mar 19 23:54:46 2002
@@ -0,0 +1,61 @@
+/* mod-test.c --- trivial test/demo of dynamic loading C modules
+
+   Copyright (C) 2002 Free Software Foundation Inc.
+
+   Author: Dave Love <fx@gnu.org>
+   
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Emacs; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "config.h"
+#include "lisp.h"
+#include <math.h>
+#include <errno.h>
+
+Lisp_Object Vtest_var;		/* exported variable */
+int test_int = 69;		/* forwarded to Lisp */
+
+/* A function missing from the Emacs core (commented-out in
+   floatfns.c).  It needs -lm, which is automatically included by the
+   module builder.  */
+DEFUN ("Y1", Fy1, Sy1, 1, 1, 0,
+  "Return the order 1 Bessel function of the second kind of ARG.")
+  (arg)
+     Lisp_Object arg;
+{
+  double d = extract_float (arg);
+  errno = 0;
+  d = y1 (d);
+  switch (errno) {
+  case 0: break;
+  case EDOM:
+    Fsignal (Qdomain_error, Fcons (build_string ("Y1"), Fcons (arg, Qnil)));
+  case ERANGE:
+    Fsignal (Qrange_error, Fcons (build_string ("Y1"), Fcons (arg, Qnil)));
+  default:
+    Fsignal (Qarith_error, Fcons (build_string ("Y1"), Fcons (arg, Qnil)));
+  }  
+  return make_float (d);
+}
+
+/* Initialization for the module.  Must be called init_MODULE.  */
+void
+init_mod_test ()
+{
+  defsubr (&Sy1);
+  DEFVAR_LISP ("test-var", &Vtest_var, "A module variable.");
+  Vtest_var = make_number (69);
+  DEFVAR_INT ("test-int", &test_int, "A module defvar_int.");
+  Fprovide (intern ("mod-test"));
+}
