Subject: bug#10777: closed (Re: bug#10777: 24.0.93; Enhancement: Add support for libxml2 on MS-Windows)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 07 Apr 2012 14:05:02 +0000

Your bug report

#10777: 24.0.93; Enhancement: Add support for libxml2 on MS-Windows

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
10777: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=10777
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#10777: 24.0.93; Enhancement: Add support for libxml2 on MS-Windows
From: Eli Zaretskii <[email-masked]>
To: Eli Zaretskii <[email-masked]>
Cc: [email-masked]
Date: Sat, 07 Apr 2012 17:01:56 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

> Date: Fri, 10 Feb 2012 12:21:55 +0200
> From: Eli Zaretskii <[email-masked]>
> 
> Package: emacs
> Severity: wishlist
> Tags: patch
> 
> See the subject.  The patch below accomplishes that, but in
> 
>   http://lists.gnu.org/archive/html/emacs-devel/2012-02/msg00288.html
> 
> it was decided that it should be applied after Emacs 24.1 is released.

Changes installed as trunk revision 107786.

Subject: 24.0.93; Enhancement: Add support for libxml2 on MS-Windows
From: Eli Zaretskii <[email-masked]>
To: [email-masked]
Date: Fri, 10 Feb 2012 12:21:55 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Package: emacs
Severity: wishlist
Tags: patch

See the subject.  The patch below accomplishes that, but in

  http://lists.gnu.org/archive/html/emacs-devel/2012-02/msg00288.html

it was decided that it should be applied after Emacs 24.1 is released.

=== modified file 'etc/NEWS'
--- etc/NEWS	2012-02-10 08:51:37 +0000
+++ etc/NEWS	2012-02-10 09:27:36 +0000
@@ -1539,6 +1539,10 @@ and also when HOME is set to C:\ by defa
 *** --without-gnutls disables automatic GnuTLS detection.
 
 +++
+*** --without-libxml2 omits support for libxml2, even if its presence
+is detected.
+
++++
 *** --lib for general library linkage, works with the USER_LIBS build variable.
 
 +++

=== modified file 'lib-src/ChangeLog'
--- lib-src/ChangeLog	2012-02-09 07:48:22 +0000
+++ lib-src/ChangeLog	2012-02-10 09:27:36 +0000
@@ -1,3 +1,7 @@
+2012-02-05  Eli Zaretskii  <[email-masked]>
+
+	* makefile.w32-in (obj): Add xml.o.
+
 2012-01-05  Glenn Morris  <[email-masked]>
 
 	* ebrowse.c (version) <emacs_copyright>:

=== modified file 'lib-src/makefile.w32-in'
--- lib-src/makefile.w32-in	2012-02-09 07:48:22 +0000
+++ lib-src/makefile.w32-in	2012-02-10 09:27:36 +0000
@@ -140,7 +140,7 @@ obj =   dosfns.o msdos.o \
 	process.o callproc.o unexw32.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o intervals.o textprop.o composite.o \
-	gnutls.o
+	gnutls.o xml.o
 
 #
 # These are the lisp files that are loaded up in loadup.el

=== modified file 'lisp/ChangeLog'
--- lisp/ChangeLog	2012-02-10 08:23:33 +0000
+++ lisp/ChangeLog	2012-02-10 09:27:36 +0000
@@ -1,3 +1,7 @@
+2012-02-04  Eli Zaretskii  <[email-masked]>
+
+	* term/w32-win.el (dynamic-library-alist): Add libxml2 DLLs.
+
 2012-02-10  Glenn Morris  <[email-masked]>
 
 	* textmodes/bibtex.el:

=== modified file 'lisp/term/w32-win.el'
--- lisp/term/w32-win.el	2012-01-19 07:21:25 +0000
+++ lisp/term/w32-win.el	2012-02-10 09:27:36 +0000
@@ -210,7 +210,8 @@ See the documentation of `create-fontset
        '(gdk-pixbuf "libgdk_pixbuf-2.0-0.dll")
        '(glib "libglib-2.0-0.dll")
        '(gobject "libgobject-2.0-0.dll")
-       '(gnutls "libgnutls-28.dll" "libgnutls-26.dll")))
+       '(gnutls "libgnutls-28.dll" "libgnutls-26.dll")
+       '(libxml2 "libxml2-2.dll" "libxml2.dll")))
 
 ;;; multi-tty support
 (defvar w32-initialized nil

=== modified file 'nt/ChangeLog'
--- nt/ChangeLog	2012-02-09 07:48:22 +0000
+++ nt/ChangeLog	2012-02-10 10:11:05 +0000
@@ -1,3 +1,10 @@
+2012-02-04  Eli Zaretskii  <[email-masked]>
+
+	* configure.bat: Support building with libxml2.
+
+	* INSTALL:
+	* README.W32: Add information about libxml2.
+
 2012-02-06  Christoph Scholtes  <[email-masked]>
 
 	* README.W32: Removed specific version information for libXpm

=== modified file 'nt/INSTALL'
--- nt/INSTALL	2012-02-04 21:34:36 +0000
+++ nt/INSTALL	2012-02-10 09:58:48 +0000
@@ -367,6 +367,40 @@
   You can get pre-built binaries (including any required DLL and the
   header files) at http://sourceforge.net/projects/ezwinports/files/.
 
+* Optional libxml2 support
+
+  If configure.bat finds the libxml/HTMLparser.h file in the include path,
+  Emacs is built with libxml2 support by default; to avoid that you can
+  pass the argument --without-libxml2.
+
+  In order to support libxml2 at runtime, a libxml2-enabled Emacs must
+  be able to find the relevant DLLs during startup; failure to do so
+  is not an error, but libxml2 features won't be available to the
+  running session.
+
+  One place where you can get pre-built Windows binaries of libxml2
+  (including any required DLL and the header files) is here:
+
+     http://sourceforge.net/projects/ezwinports/files/
+
+  To compile Emacs with libxml2 from that site, you will need to pass
+  the "--cflags -I/path/to/include/libxml2" option to configure.bat,
+  because libxml2 header files are installed in the include/libxml2
+  subdirectory of the directory where you unzip the binary
+  distribution.  Other binary distributions might use other
+  directories, although include/libxml2 is the canonical place where
+  libxml2 headers are installed on Posix platforms.
+
+  You will also need to install the libiconv "development" tarball,
+  because the libiconv headers need to be available to the compiler
+  when you compile with libxml2 support.  A MinGW port of libiconv can
+  be found on the MinGW site:
+
+   http://sourceforge.net/projects/mingw/files/MinGW/Base/libiconv/
+
+  You need the libiconv-X.Y.Z-N-mingw32-dev.tar.lzma tarball from that
+  site.
+
 * Experimental SVG support
 
   SVG support is currently experimental, and not built by default.

=== modified file 'nt/README.W32'
--- nt/README.W32	2012-02-09 07:48:22 +0000
+++ nt/README.W32	2012-02-10 09:27:36 +0000
@@ -172,6 +172,16 @@ See the end of the file for license cond
   You can get pre-built binaries (including any required DLL and the
   header files) at http://sourceforge.net/projects/ezwinports/files/.
 
+* libxml2 support
+
+  In order to support libxml2 at runtime, a libxml2-enabled Emacs must
+  be able to find the relevant DLLs during startup; failure to do so
+  is not an error, but libxml2 features won't be available to the
+  running session.
+
+  You can get pre-built binaries (including any required DLL and the
+  header files) at http://sourceforge.net/projects/ezwinports/files/.
+
 * Uninstalling Emacs
 
   If you should need to uninstall Emacs, simply delete all the files

=== modified file 'nt/configure.bat'
--- nt/configure.bat	2012-01-19 07:21:25 +0000
+++ nt/configure.bat	2012-02-10 09:27:36 +0000
@@ -131,6 +131,7 @@ if "%1" == "--without-jpeg" goto without
 if "%1" == "--without-gif" goto withoutgif
 if "%1" == "--without-tiff" goto withouttiff
 if "%1" == "--without-gnutls" goto withoutgnutls
+if "%1" == "--without-libxml2" goto withoutlibxml2
 if "%1" == "--without-xpm" goto withoutxpm
 if "%1" == "--with-svg" goto withsvg
 if "%1" == "--distfiles" goto distfiles
@@ -156,6 +157,7 @@ echo.   --without-gif           do not u
 echo.   --without-tiff          do not use TIFF library even if it is installed
 echo.   --without-xpm           do not use XPM library even if it is installed
 echo.   --without-gnutls        do not use GnuTLS library even if it is installed
+echo.   --without-libxml2       do not use libxml2 library even if it is installed
 echo.   --with-svg              use the RSVG library (experimental)
 echo.   --distfiles             path to files for make dist, e.g. libXpm.dll
 if "%use_extensions%" == "0" goto end
@@ -317,6 +319,14 @@ goto again
 
 rem ----------------------------------------------------------------------
 
+:withoutlibxml2
+set libxml2support=N
+set HAVE_LIBXML2=
+shift
+goto again
+
+rem ----------------------------------------------------------------------
+
 :withouttiff
 set tiffsupport=N
 set HAVE_TIFF=
@@ -569,6 +579,28 @@ set HAVE_GNUTLS=1
 :tlsDone
 rm -f junk.c junk.obj
 
+if (%libxml2support%) == (N) goto xml2Done
+
+echo Checking for libxml2....
+echo #include "libxml/HTMLparser.h" >junk.c
+echo main(){} >>junk.c
+echo %COMPILER% %usercflags% %mingwflag% -c junk.c -o junk.obj >>config.log
+%COMPILER% %usercflags% %mingwflag% -c junk.c -o junk.obj >junk.out 2>>config.log
+if exist junk.obj goto havelibxml2
+
+echo ...libxml/HTMLparser.h not found, building without libxml2 support
+echo The failed program was: >>config.log
+type junk.c >>config.log
+set HAVE_LIBXML2=
+goto xml2Done
+
+:havelibxml2
+echo ...libxml2 header available, building with libxml2 support
+set HAVE_LIBXML2=1
+
+:xml2Done
+rm -f junk.c junk.obj
+
 if (%jpegsupport%) == (N) goto jpegDone
 
 echo Checking for jpeg-6b...
@@ -757,6 +789,7 @@ if (%doldflags%) == (Y) echo #define USE
 if (%profile%) == (Y) echo #define PROFILING 1 >>config.tmp
 if not "(%HAVE_PNG%)" == "()" echo #define HAVE_PNG 1 >>config.tmp
 if not "(%HAVE_GNUTLS%)" == "()" echo #define HAVE_GNUTLS 1 >>config.tmp
+if not "(%HAVE_LIBXML2%)" == "()" echo #define HAVE_LIBXML2 1 >>config.tmp
 if not "(%HAVE_JPEG%)" == "()" echo #define HAVE_JPEG 1 >>config.tmp
 if not "(%HAVE_GIF%)" == "()" echo #define HAVE_GIF 1 >>config.tmp
 if not "(%HAVE_TIFF%)" == "()" echo #define HAVE_TIFF 1 >>config.tmp
@@ -896,6 +929,7 @@ set HAVE_DISTFILES=
 set distFilesOk=
 set pngsupport=
 set tlssupport=
+set libxml2support=
 set jpegsupport=
 set gifsupport=
 set tiffsupport=

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2012-02-10 08:38:22 +0000
+++ src/ChangeLog	2012-02-10 09:34:47 +0000
@@ -1,3 +1,31 @@
+2012-02-10  Eli Zaretskii  <[email-masked]>
+
+	Support building on MS-Windows with libxml2.
+
+	* makefile.w32-in (OBJ2): Add xml.$(O).
+	(GLOBAL_SOURCES): Add xml.c.
+	($(BLD)/xml.$(O)): New dependency list.
+
+	* xml.c (DEF_XML2_FN, LOAD_XML2_FN) [WINDOWSNT]: New macros.
+	(fn_htmlReadMemory, fn_xmlReadMemory, fn_xmlDocGetRootElement)
+	(fn_xmlFreeDoc, fn_xmlCleanupParser, fn_xmlCheckVersion)
+	[!WINDOWSNT]: New macros.
+	(init_libxml2_functions, libxml2_loaded_p): New functions.
+	(parse_region): Call fn_xmlCheckVersion instead of using the macro
+	LIBXML_TEST_VERSION.  Call libxml2 functions via the fn_* macros.
+	(xml_cleanup_parser): New function, export for fn_xmlCleanupParser.
+	Calls xmlCleanupParser only if libxml2 was loaded (or statically
+	linked in).
+	(Flibxml_parse_html_region, Flibxml_parse_xml_region): Call
+	init_libxml2_functions before calling libxml2 functions.
+	(syms_of_xml) <Qlibxml2_dll>: DEFSYM it.
+
+	* emacs.c: Don't include libxml/parser.h.
+	(shut_down_emacs): Call xml_cleanup_parser, instead of calling
+	xmlCleanupParser directly.
+
+	* lisp.h [HAVE_LIBXML2]: Add prototype for xml_cleanup_parser.
+
 2012-02-10  Glenn Morris  <[email-masked]>
 
 	* fns.c (Fsecure_hash): Doc fix.

=== modified file 'src/emacs.c'
--- src/emacs.c	2012-01-19 07:21:25 +0000
+++ src/emacs.c	2012-02-10 09:27:36 +0000
@@ -82,10 +82,6 @@ along with GNU Emacs.  If not, see <http
 #include <sys/personality.h>
 #endif
 
-#ifdef HAVE_LIBXML2
-#include <libxml/parser.h>
-#endif
-
 #ifndef O_RDWR
 #define O_RDWR 2
 #endif
@@ -2124,7 +2120,7 @@ shut_down_emacs (int sig, int no_x, Lisp
 #endif
 
 #ifdef HAVE_LIBXML2
-  xmlCleanupParser ();
+  xml_cleanup_parser ();
 #endif
 }

=== modified file 'src/lisp.h'
--- src/lisp.h	2012-01-19 07:21:25 +0000
+++ src/lisp.h	2012-02-10 09:27:36 +0000
@@ -3542,6 +3542,7 @@ EXFUN (Fmsdos_downcase_filename, 1);
 #ifdef HAVE_LIBXML2
 /* Defined in xml.c */
 extern void syms_of_xml (void);
+extern void xml_cleanup_parser (void);
 #endif
 
 #ifdef HAVE_MENUS

=== modified file 'src/makefile.w32-in'
--- src/makefile.w32-in	2012-01-19 07:21:25 +0000
+++ src/makefile.w32-in	2012-02-10 09:27:36 +0000
@@ -128,6 +128,7 @@ OBJ2 =  $(BLD)/sysdep.$(O)		\
 	$(BLD)/image.$(O)		\
 	$(BLD)/terminal.$(O)            \
 	$(BLD)/menu.$(O)		\
+	$(BLD)/xml.$(O)			\
 	$(BLD)/w32term.$(O)		\
 	$(BLD)/w32xfns.$(O)		\
 	$(BLD)/w32fns.$(O)		\
@@ -225,7 +226,7 @@ GLOBAL_SOURCES =   dosfns.c msdos.c \
 	process.c callproc.c unexw32.c \
 	region-cache.c sound.c atimer.c \
 	doprnt.c intervals.c textprop.c composite.c \
-	gnutls.c
+	gnutls.c xml.c
 SOME_MACHINE_OBJECTS = dosfns.o msdos.o \
 	xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o dbusbind.o
 obj = $(GLOBAL_SOURCES:.c=.o)
@@ -940,6 +941,13 @@ $(BLD)/gnutls.$(O) : \
 	$(LISP_H) \
 	$(PROCESS_H)
 
+$(BLD)/xml.$(O) : \
+	$(SRC)/xml.c \
+	$(SRC)/w32.h \
+	$(CONFIG_H) \
+	$(LISP_H) \
+	$(SRC)/buffer.h
+
 $(BLD)/image.$(O) : \
 	$(SRC)/image.c \
 	$(SRC)/epaths.h \

=== modified file 'src/xml.c'
--- src/xml.c	2012-01-05 09:46:05 +0000
+++ src/xml.c	2012-02-10 09:41:14 +0000
@@ -28,6 +28,99 @@ along with GNU Emacs.  If not, see <http
 #include "lisp.h"
 #include "buffer.h"
 
+
+static Lisp_Object Qlibxml2_dll;
+
+#ifdef WINDOWSNT
+
+#include <windows.h>
+#include "w32.h"
+
+/* Macro for defining functions that will be loaded from the libxml2 DLL.  */
+#define DEF_XML2_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
+
+/* Macro for loading libxml2 functions from the library.  */
+#define LOAD_XML2_FN(lib,func) {					\
+    fn_##func = (void *) GetProcAddress (lib, #func);			\
+    if (!fn_##func) goto bad_library;					\
+  }
+
+DEF_XML2_FN (htmlDocPtr, htmlReadMemory,
+	     (const char *, int, const char *, const char *, int));
+DEF_XML2_FN (xmlDocPtr, xmlReadMemory,
+	     (const char *, int, const char *, const char *, int));
+DEF_XML2_FN (xmlNodePtr, xmlDocGetRootElement, (xmlDocPtr));
+DEF_XML2_FN (void, xmlFreeDoc, (xmlDocPtr));
+DEF_XML2_FN (void, xmlCleanupParser, (void));
+DEF_XML2_FN (void, xmlCheckVersion, (int));
+
+static int
+libxml2_loaded_p (void)
+{
+  Lisp_Object found = Fassq (Qlibxml2_dll, Vlibrary_cache);
+
+  if (CONSP (found))
+    return EQ (XCDR (found), Qt) ? 1 : 0;
+  return 0;
+}
+
+#else  /* !WINDOWSNT */
+
+#define fn_htmlReadMemory       htmlReadMemory
+#define fn_xmlReadMemory        xmlReadMemory
+#define fn_xmlDocGetRootElement xmlDocGetRootElement
+#define fn_xmlFreeDoc           xmlFreeDoc
+#define fn_xmlCleanupParser     xmlCleanupParser
+#define fn_xmlCheckVersion      xmlCheckVersion
+
+static inine int
+libxml2_loaded_p (void)
+{
+  return 1;
+}
+
+#endif	/* !WINDOWSNT */
+
+static int
+init_libxml2_functions (Lisp_Object libraries)
+{
+#ifdef WINDOWSNT
+  Lisp_Object found = Fassq (Qlibxml2_dll, Vlibrary_cache);
+
+  if (libxml2_loaded_p ())
+    return 1;
+  else
+    {
+      HMODULE library;
+
+      if (!(library = w32_delayed_load (libraries, Qlibxml2_dll)))
+	{
+	  message ("%s", "libxml2 library not found");
+	  return 0;
+	}
+
+      /* LOAD_XML2_FN jumps to bad_library if it fails to find the
+	 named function.  */
+      LOAD_XML2_FN (library, htmlReadMemory);
+      LOAD_XML2_FN (library, xmlReadMemory);
+      LOAD_XML2_FN (library, xmlDocGetRootElement);
+      LOAD_XML2_FN (library, xmlFreeDoc);
+      LOAD_XML2_FN (library, xmlCleanupParser);
+      LOAD_XML2_FN (library, xmlCheckVersion);
+
+      Vlibrary_cache = Fcons (Fcons (Qlibxml2_dll, Qt), Vlibrary_cache);
+      return 1;
+    }
+
+ bad_library:
+  Vlibrary_cache = Fcons (Fcons (Qlibxml2_dll, Qnil), Vlibrary_cache);
+
+  return 0;
+#else  /* !WINDOWSNT */
+  return 1;
+#endif	/* !WINDOWSNT */
+}
+
 static Lisp_Object
 make_dom (xmlNode *node)
 {
@@ -92,7 +185,7 @@ parse_region (Lisp_Object start, Lisp_Ob
   EMACS_INT bytes;
   EMACS_INT istart, iend;
 
-  LIBXML_TEST_VERSION;
+  fn_xmlCheckVersion (LIBXML_VERSION);
 
   validate_region (&start, &end);
 
@@ -111,16 +204,16 @@ parse_region (Lisp_Object start, Lisp_Ob
   bytes = CHAR_TO_BYTE (iend) - CHAR_TO_BYTE (istart);
 
   if (htmlp)
-    doc = htmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
-			  bytes, burl, "utf-8",
-			  HTML_PARSE_RECOVER|HTML_PARSE_NONET|
-			  HTML_PARSE_NOWARNING|HTML_PARSE_NOERROR|
-			  HTML_PARSE_NOBLANKS);
+    doc = fn_htmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
+			     bytes, burl, "utf-8",
+			     HTML_PARSE_RECOVER|HTML_PARSE_NONET|
+			     HTML_PARSE_NOWARNING|HTML_PARSE_NOERROR|
+			     HTML_PARSE_NOBLANKS);
   else
-    doc = xmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
-			 bytes, burl, "utf-8",
-			 XML_PARSE_NONET|XML_PARSE_NOWARNING|
-			 XML_PARSE_NOBLANKS |XML_PARSE_NOERROR);
+    doc = fn_xmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
+			    bytes, burl, "utf-8",
+			    XML_PARSE_NONET|XML_PARSE_NOWARNING|
+			    XML_PARSE_NOBLANKS |XML_PARSE_NOERROR);
 
   if (doc != NULL)
     {
@@ -139,19 +232,26 @@ parse_region (Lisp_Object start, Lisp_Ob
       if (NILP (result)) {
 	/* The document isn't just comments, so get the tree the
 	   proper way. */
-	xmlNode *node = xmlDocGetRootElement (doc);
+	xmlNode *node = fn_xmlDocGetRootElement (doc);
 	if (node != NULL)
 	  result = make_dom (node);
       } else
 	result = Fcons (intern ("top"),
 			Fcons (Qnil, Fnreverse (Fcons (r, result))));
 
-      xmlFreeDoc (doc);
+      fn_xmlFreeDoc (doc);
     }
 
   return result;
 }
 
+void
+xml_cleanup_parser (void)
+{
+  if (libxml2_loaded_p ())
+    fn_xmlCleanupParser ();
+}
+
 DEFUN ("libxml-parse-html-region", Flibxml_parse_html_region,
        Slibxml_parse_html_region,
        2, 3, 0,
@@ -159,7 +259,9 @@ DEFUN ("libxml-parse-html-region", Flibx
 If BASE-URL is non-nil, it is used to expand relative URLs.  */)
   (Lisp_Object start, Lisp_Object end, Lisp_Object base_url)
 {
-  return parse_region (start, end, base_url, 1);
+  if (init_libxml2_functions (Vdynamic_library_alist))
+    return parse_region (start, end, base_url, 1);
+  return Qnil;
 }
 
 DEFUN ("libxml-parse-xml-region", Flibxml_parse_xml_region,
@@ -169,7 +271,9 @@ DEFUN ("libxml-parse-xml-region", Flibxm
 If BASE-URL is non-nil, it is used to expand relative URLs.  */)
   (Lisp_Object start, Lisp_Object end, Lisp_Object base_url)
 {
-  return parse_region (start, end, base_url, 0);
+  if (init_libxml2_functions (Vdynamic_library_alist))
+    return parse_region (start, end, base_url, 0);
+  return Qnil;
 }
 
 
@@ -181,6 +285,8 @@ syms_of_xml (void)
 {
   defsubr (&Slibxml_parse_html_region);
   defsubr (&Slibxml_parse_xml_region);
+
+  DEFSYM (Qlibxml2_dll, "libxml2");
 }
 
 #endif /* HAVE_LIBXML2 */