[xslt] [PATCH] xslt extensions as modules/dso's



The following patch, which builds on my libxml2 module patch, converts
libexslt into a set of modules, which looks something like this:

(%:/opt/src/libxslt)- l /usr/local/lib/libxslt/*.so
/usr/local/lib/libxslt/common.so*
/usr/local/lib/libxslt/crypto.so*
/usr/local/lib/libxslt/dates-and-times.so*
/usr/local/lib/libxslt/dynamic.so*
/usr/local/lib/libxslt/functions.so*
/usr/local/lib/libxslt/math.so*
/usr/local/lib/libxslt/saxon.so*
/usr/local/lib/libxslt/sets.so*
/usr/local/lib/libxslt/strings.so*

The guts of the patch can be found in libxslt/extensions.c.
Basically, if module support has been compiled in, then libxslt
will dynamically load in the appropriate module when first referenced.

The output for "make check" with and without module support 
should be identical - it is on my box, after lots of debugging.
When I timed the standard build versus a build with module support
enabled, the times seem to be identical or slightly faster for
the module enabled option. The primary usefulness of this approach
to exslt extensions in my opinion is the greater flexibility this
allows to base exslt extensions on 3rd party libraries, without
increasing the dependencies for the base libxslt library. Having support
for modules in libxml/libxslt will hopefully make it far easier to
provide exslt extensions, if what seems to happen with most OSS projects
that implement some sort of module support, is replicated here.

The only question i have is about what to do with libexslt. When modules
are enabled there is really no use for libexslt. Part of me feels
like the best approach would be to make this a libxslt2 thing. libexslt
_could_ be ripped out and replaced with a series of exslt modules, with 
some base set and then additional extensions. i'd like to do the regexp
extension based on prce for example, if this patch is eventually
accepted.  

Looking forward to receiving feedback on the implementation,

jr
Index: configure.in
===================================================================
RCS file: /cvs/gnome/libxslt/configure.in,v
retrieving revision 1.163
diff -u -w -b -B -r1.163 configure.in
--- configure.in	29 Oct 2004 15:07:14 -0000	1.163
+++ configure.in	20 Dec 2004 17:04:25 -0000
@@ -435,6 +434,28 @@
 AC_SUBST(CPPFLAGS)
 AC_SUBST(LDFLAGS)
 
+AC_ARG_WITH(dynamic,
+[  --with-dynamic          Add dynamically loaded extension support (off)])
+if test "$with_dynamic" = ""
+then
+    with_dynamic=no
+fi
+
+if test "$with_dynamic" = "yes" ; then
+  AC_MSG_CHECKING([libxml2 module support])
+  WITH_MODULES="`$XML_CONFIG --modules`"
+  if test "${WITH_MODULES}" = "1"; then
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+  fi
+else
+  WITH_MODULES="0"
+fi
+
+AM_CONDITIONAL(AM_WITH_MODULES, test $WITH_MODULES = "1")
+AC_SUBST(WITH_MODULES)
+
 dnl
 dnl In build tree I use a static version with memory debug enabled
 dnl
Index: libexslt/Makefile.am
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/Makefile.am,v
retrieving revision 1.22
diff -u -w -b -B -r1.22 Makefile.am
--- libexslt/Makefile.am	4 Jul 2004 13:53:02 -0000	1.22
+++ libexslt/Makefile.am	20 Dec 2004 17:04:50 -0000
@@ -34,3 +34,46 @@
 man_MANS = libexslt.3
 
 EXTRA_DIST = $(man_MANS)
+
+pkglibdir =  $(libdir)/libxslt
+
+if AM_WITH_MODULES
+pkglib_LTLIBRARIES = \
+	common.la     \
+	crypto.la			\
+	math.la				\
+	sets.la				\
+	functions.la		\
+	strings.la			\
+	dates-and-times.la				\
+	dynamic.la	\
+	saxon.la
+
+common_la_CFLAGS = -DMODULE_COMPILE
+common_la_SOURCES = common.c
+common_la_LDFLAGS = -module -avoid-version
+crypto_la_SOURCES = crypto.c
+crypto_la_CFLAGS =  $(LIBGCRYPT_CFLAGS) -DMODULE_COMPILE
+crypto_la_LDFLAGS = -module -avoid-version $(LIBGCRYPT_LIBS)
+math_la_CFLAGS = -DMODULE_COMPILE
+math_la_SOURCES = math.c
+math_la_LDFLAGS = -module -avoid-version
+sets_la_CFLAGS = -DMODULE_COMPILE
+sets_la_SOURCES = sets.c
+sets_la_LDFLAGS = -module -avoid-version
+functions_la_CFLAGS = -DMODULE_COMPILE
+functions_la_SOURCES = functions.c
+functions_la_LDFLAGS = -module -avoid-version
+saxon_la_CFLAGS = -DMODULE_COMPILE
+saxon_la_SOURCES = saxon.c
+saxon_la_LDFLAGS = -module -avoid-version
+strings_la_CFLAGS = -DMODULE_COMPILE
+strings_la_SOURCES = strings.c
+strings_la_LDFLAGS = -module -avoid-version
+dates_and_times_la_CFLAGS = -DMODULE_COMPILE
+dates_and_times_la_SOURCES = date.c
+dates_and_times_la_LDFLAGS = -module -avoid-version
+dynamic_la_CFLAGS = -DMODULE_COMPILE
+dynamic_la_SOURCES = dynamic.c
+dynamic_la_LDFLAGS = -module -avoid-version
+endif
Index: libexslt/common.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/common.c,v
retrieving revision 1.15
diff -u -w -b -B -r1.15 common.c
--- libexslt/common.c	14 Jan 2004 06:34:42 -0000	1.15
+++ libexslt/common.c	20 Dec 2004 17:04:50 -0000
@@ -102,7 +102,7 @@
  */
 
 void
-exsltCommonRegister (void) {
+EXSLTREGFUN(exsltCommonRegister) (void) {
     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
 				  EXSLT_COMMON_NAMESPACE,
 				  exsltNodeSetFunction);
Index: libexslt/crypto.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/crypto.c,v
retrieving revision 1.5
diff -u -w -b -B -r1.5 crypto.c
--- libexslt/crypto.c	29 Oct 2004 15:07:15 -0000	1.5
+++ libexslt/crypto.c	20 Dec 2004 17:04:50 -0000
@@ -710,7 +710,7 @@
  */
 
 void
-exsltCryptoRegister (void) {
+EXSLTREGFUN(exsltCryptoRegister) (void) {
     xsltRegisterExtModuleFunction ((const xmlChar *) "md4",
 				   EXSLT_CRYPTO_NAMESPACE,
 				   exsltCryptoMd4Function);
@@ -730,7 +730,7 @@
 
 #else
 void
-exsltCryptoRegister (void) {
+EXSLTREGFUN(exsltCryptoRegister) (void) {
 }
 
 #endif /* defined(HAVE_CRYPTO) */
Index: libexslt/date.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/date.c,v
retrieving revision 1.35
diff -u -w -b -B -r1.35 date.c
--- libexslt/date.c	8 Nov 2004 03:41:26 -0000	1.35
+++ libexslt/date.c	20 Dec 2004 17:04:54 -0000
@@ -3678,7 +3678,7 @@
  * Registers the EXSLT - Dates and Times module
  */
 void
-exsltDateRegister (void)
+EXSLTREGFUN(exsltDateRegister) (void)
 {
     xsltRegisterExtModuleFunction ((const xmlChar *) "add",
 				   (const xmlChar *) EXSLT_DATE_NAMESPACE,
Index: libexslt/dynamic.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/dynamic.c,v
retrieving revision 1.3
diff -u -w -b -B -r1.3 dynamic.c
--- libexslt/dynamic.c	18 Aug 2003 22:41:05 -0000	1.3
+++ libexslt/dynamic.c	20 Dec 2004 17:04:54 -0000
@@ -90,7 +90,7 @@
  */
 
 void
-exsltDynRegister (void) {
+EXSLTREGFUN(exsltDynRegister) (void) {
     xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
 				   EXSLT_DYNAMIC_NAMESPACE,
 				   exsltDynEvaluateFunction);
Index: libexslt/exslt.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/exslt.c,v
retrieving revision 1.14
diff -u -w -b -B -r1.14 exslt.c
--- libexslt/exslt.c	18 Aug 2004 21:27:08 -0000	1.14
+++ libexslt/exslt.c	20 Dec 2004 17:04:54 -0000
@@ -32,6 +32,7 @@
  */
 void
 exsltRegisterAll (void) {
+#ifndef EXSLT_MODULES_ENABLED
     exsltCommonRegister();
 #ifdef EXSLT_CRYPTO_ENABLED
     exsltCryptoRegister();
@@ -43,5 +44,6 @@
     exsltDateRegister();
     exsltSaxonRegister();
     exsltDynRegister();
+#endif /* EXSLT_MODULES_ENABLED */
 }
 
Index: libexslt/exslt.h
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/exslt.h,v
retrieving revision 1.15
diff -u -w -b -B -r1.15 exslt.h
--- libexslt/exslt.h	16 Jul 2004 10:17:29 -0000	1.15
+++ libexslt/exslt.h	20 Dec 2004 17:04:54 -0000
@@ -46,6 +46,12 @@
  */
 #define EXSLT_FUNCTIONS_NAMESPACE ((const xmlChar *) "http://exslt.org/functions";)
 /**
+ * EXSLT_REGEXP_NAMESPACE:
+ *
+ * Namespace for EXSLT regexp functions
+ */
+#define EXSLT_REGEXP_NAMESPACE ((const xmlChar *) "http://exslt.org/regular-expressions";)
+/**
  * EXSLT_STRINGS_NAMESPACE:
  *
  * Namespace for EXSLT strings functions
@@ -71,6 +77,8 @@
  */
 #define SAXON_NAMESPACE ((const xmlChar *) "http://icl.com/saxon";)
 
+#ifndef EXSLT_MODULES_ENABLED
+
 EXSLTPUBFUN void EXSLTCALL exsltCommonRegister (void);
 #ifdef EXSLT_CRYPTO_ENABLED
 EXSLTPUBFUN void EXSLTCALL exsltCryptoRegister (void);
@@ -78,12 +86,21 @@
 EXSLTPUBFUN void EXSLTCALL exsltMathRegister (void);
 EXSLTPUBFUN void EXSLTCALL exsltSetsRegister (void);
 EXSLTPUBFUN void EXSLTCALL exsltFuncRegister (void);
+EXSLTPUBFUN void EXSLTCALL exsltRegexpRegister (void);
 EXSLTPUBFUN void EXSLTCALL exsltStrRegister (void);
 EXSLTPUBFUN void EXSLTCALL exsltDateRegister (void);
 EXSLTPUBFUN void EXSLTCALL exsltSaxonRegister (void);
 EXSLTPUBFUN void EXSLTCALL exsltDynRegister(void);
 
+#endif /* EXSLT_MODULES_ENABLED */
+
 EXSLTPUBFUN void EXSLTCALL exsltRegisterAll (void);
+
+#ifdef MODULE_COMPILE
+#define EXSLTREGFUN(a) exsltRegisterModule
+#else
+#define EXSLTREGFUN(a) a
+#endif
 
 #ifdef __cplusplus
 }
Index: libexslt/exsltconfig.h.in
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/exsltconfig.h.in,v
retrieving revision 1.8
diff -u -w -b -B -r1.8 exsltconfig.h.in
--- libexslt/exsltconfig.h.in	18 Aug 2004 21:27:08 -0000	1.8
+++ libexslt/exsltconfig.h.in	20 Dec 2004 17:04:54 -0000
@@ -51,6 +51,15 @@
 #endif
 
 /**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into exslt
+ */
+#if @WITH_MODULES@
+#define EXSLT_MODULES_ENABLED
+#endif
+
+/**
  * ATTRIBUTE_UNUSED:
  *
  * This macro is used to flag unused function parameters to GCC
Index: libexslt/functions.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/functions.c,v
retrieving revision 1.21
diff -u -w -b -B -r1.21 functions.c
--- libexslt/functions.c	23 Oct 2004 16:41:59 -0000	1.21
+++ libexslt/functions.c	20 Dec 2004 17:04:55 -0000
@@ -643,7 +644,7 @@
  * Registers the EXSLT - Functions module
  */
 void
-exsltFuncRegister (void) {
+EXSLTREGFUN(exsltFuncRegister) (void) {
     xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
 		       (xsltExtInitFunction) exsltFuncInit,
 		       (xsltExtShutdownFunction) exsltFuncShutdown,
Index: libexslt/math.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/math.c,v
retrieving revision 1.17
diff -u -w -b -B -r1.17 math.c
--- libexslt/math.c	14 Jan 2004 06:34:42 -0000	1.17
+++ libexslt/math.c	20 Dec 2004 17:04:56 -0000
@@ -1065,7 +1065,7 @@
  */
 
 void
-exsltMathRegister (void) {
+EXSLTREGFUN(exsltMathRegister) (void) {
     xsltRegisterExtModuleFunction ((const xmlChar *) "min",
 				   EXSLT_MATH_NAMESPACE,
 				   exsltMathMinFunction);
Index: libexslt/saxon.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/saxon.c,v
retrieving revision 1.7
diff -u -w -b -B -r1.7 saxon.c
--- libexslt/saxon.c	27 Sep 2003 15:31:09 -0000	1.7
+++ libexslt/saxon.c	20 Dec 2004 17:04:56 -0000
@@ -247,7 +247,7 @@
  * Registers the SAXON extension module
  */
 void
-exsltSaxonRegister (void) {
+EXSLTREGFUN(exsltSaxonRegister) (void) {
      xsltRegisterExtModule (SAXON_NAMESPACE,
 			    (xsltExtInitFunction) exsltSaxonInit,
 			    (xsltExtShutdownFunction) exsltSaxonShutdown);
Index: libexslt/sets.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/sets.c,v
retrieving revision 1.15
diff -u -w -b -B -r1.15 sets.c
--- libexslt/sets.c	18 Aug 2003 22:41:05 -0000	1.15
+++ libexslt/sets.c	20 Dec 2004 17:04:56 -0000
@@ -270,7 +270,7 @@
  */
 
 void
-exsltSetsRegister (void) {
+EXSLTREGFUN(exsltSetsRegister) (void) {
     xsltRegisterExtModuleFunction ((const xmlChar *) "difference",
 				   EXSLT_SETS_NAMESPACE,
 				   exsltSetsDifferenceFunction);
Index: libexslt/strings.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/strings.c,v
retrieving revision 1.20
diff -u -w -b -B -r1.20 strings.c
--- libexslt/strings.c	27 Jul 2004 00:06:37 -0000	1.20
+++ libexslt/strings.c	20 Dec 2004 17:04:57 -0000
@@ -500,7 +500,7 @@
  */
 
 void
-exsltStrRegister (void) {
+EXSLTREGFUN(exsltStrRegister) (void) {
     xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
 				   EXSLT_STRINGS_NAMESPACE,
 				   exsltStrTokenizeFunction);
Index: libxslt/extensions.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/extensions.c,v
retrieving revision 1.35
diff -u -w -b -B -r1.35 extensions.c
--- libxslt/extensions.c	1 Dec 2004 14:44:56 -0000	1.35
+++ libxslt/extensions.c	20 Dec 2004 17:04:58 -0000
@@ -13,6 +13,7 @@
 #include "libxslt.h"
 
 #include <string.h>
+#include <limits.h>
 
 #include <libxml/xmlmemory.h>
 #include <libxml/tree.h>
@@ -20,6 +21,9 @@
 #include <libxml/xmlerror.h>
 #include <libxml/parserInternals.h>
 #include <libxml/xpathInternals.h>
+#include <libxml/xmlmodule.h>
+#include <libxml/list.h>
+#include <libxml/xmlIO.h>
 #include "xslt.h"
 #include "xsltInternals.h"
 #include "xsltutils.h"
@@ -72,6 +76,7 @@
 static xmlHashTablePtr xsltFunctionsHash = NULL;
 static xmlHashTablePtr xsltElementsHash = NULL;
 static xmlHashTablePtr xsltTopLevelsHash = NULL;
+static xmlHashTablePtr xsltModuleHash = NULL;
 
 /************************************************************************
  * 									*
@@ -269,6 +274,75 @@
 }
 
 
+/**
+ * xsltExtModuleRegisterDynamic:
+ * @URI:  the function or element namespace URI
+ *
+ * Looks up an extension module to dynamically load
+ * based on the namespace URI
+ *
+ * Returns 0 if successful, -1 in case of error. 
+ */
+
+#ifdef WITH_MODULES
+typedef void (*exsltRegisterFunction) (void);
+
+int
+static xsltExtModuleRegisterDynamic (const xmlChar *URI) {
+
+ 
+  xmlChar module_filename[PATH_MAX];
+  const xmlChar *extNameBegin = NULL;
+  int i, seen_before;
+
+  /* check for bad inputs */
+  if (URI == NULL)
+    return(-1);
+
+  if (NULL == xsltModuleHash) {
+    xsltModuleHash = xmlHashCreate(5);
+    if (xsltModuleHash == NULL)
+      return(-1);
+  }
+
+  /* have we attempted to register this module already? */
+  seen_before = (int)xmlHashLookup(xsltModuleHash, URI);
+  if (1 == seen_before) {
+    return(-1);
+  }
+
+  /* ok, we haven't seen this registeration request before */
+  xmlHashAddEntry(xsltModuleHash, URI, (void*)1);
+
+  for (i = xmlStrlen(URI); i != 0 && extNameBegin == NULL; --i)
+    {
+      if (URI[i-1] == '/') extNameBegin = URI + i;
+    }
+
+  if (extNameBegin == NULL || *extNameBegin == '\0') 
+    return(-1);
+
+  /* build the module filename, and confirm the module exists */
+  xmlStrPrintf(module_filename, sizeof(module_filename), "%s%s%s", XSLT_EXTENSIONS_PATH, extNameBegin, LIBXML_MODULE_EXTENSION);
+  if (1 != xmlCheckFilename(module_filename))
+    return(-1);
+
+  xmlModulePtr m = xmlModuleOpen(module_filename);
+  if (NULL == m) 
+    return(-1);
+                   
+  exsltRegisterFunction regfunc = (exsltRegisterFunction) xmlModuleSymbol(m, "exsltRegisterModule");
+  if (NULL != regfunc) {
+    (*regfunc)();
+  }
+
+  xmlModuleFree(m);
+  return (NULL == regfunc)? -1 : 0;
+}
+#else
+#define xsltExtModuleRegisterDynamic(b) -1
+#endif
+
 /************************************************************************
  * 									*
  * 		The stylesheet extension prefixes handling		*
@@ -330,6 +404,12 @@
 	xsltExtModulePtr module;
 
 	module = xmlHashLookup(xsltExtensionsHash, URI);
+  if (NULL == module) {
+    if (!xsltExtModuleRegisterDynamic(URI)) {
+      module = xmlHashLookup(xsltExtensionsHash, URI);
+    }
+  }
+
 	if (module != NULL) {
 	    xsltStyleGetExtData(style, URI);
 	}
@@ -959,6 +1039,14 @@
 	return(NULL);
 
     XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
+
+    /* if lookup fails, attempt a dynamic load on supported platforms */
+    if (NULL == ret) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
+      }
+    }
+
     return ret;
 }
 
@@ -1160,6 +1248,14 @@
 
     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
 
+    /* if function lookup fails, attempt a dynamic load on supported platforms */
+    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+    if (NULL == ext) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+      }
+    }
+
     if (ext == NULL)
 	return(NULL);
     return(ext->transform);
@@ -1184,6 +1280,12 @@
 
     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
 
+    if (ext == NULL) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+      }
+    }
+
     if (ext == NULL)
 	return(NULL);
     return(ext->precomp);
@@ -1262,6 +1364,14 @@
 	return(NULL);
 
     XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
+
+    /* if lookup fails, attempt a dynamic load on supported platforms */
+    if (NULL == ret) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
+      }
+    }
+
     return(ret);
 }
 
@@ -1611,6 +1721,13 @@
     xsltUnregisterAllExtModuleFunction();
     xsltUnregisterAllExtModuleElement();
     xsltUnregisterAllExtModuleTopLevel();
+
+    /* cleanup dynamic module hash */
+    if (NULL != xsltModuleHash)
+      {
+        xmlHashFree(xsltModuleHash, NULL);
+        xsltModuleHash = NULL;
+      }
 }
 
 static void
Index: libxslt/xsltconfig.h.in
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xsltconfig.h.in,v
retrieving revision 1.22
diff -u -w -b -B -r1.22 xsltconfig.h.in
--- libxslt/xsltconfig.h.in	18 Aug 2004 21:27:08 -0000	1.22
+++ libxslt/xsltconfig.h.in	20 Dec 2004 17:05:01 -0000
@@ -107,6 +107,18 @@
 #endif
 
 /**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into libxslt
+ */
+#if @WITH_MODULES@
+#ifndef WITH_MODULES
+#define WITH_MODULES
+#endif
+#define XSLT_EXTENSIONS_PATH "@prefix@/lib/libxslt/"
+#endif
+
+/**
  * ATTRIBUTE_UNUSED:
  *
  * This macro is used to flag unused function parameters to GCC


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]