diff --git a/configure.ac b/configure.ac
index de959d58debd6bd5f6d20757965a5f961cd3a3b1_Y29uZmlndXJlLmFj..0d251255bd3273d82aa79fd145141b7b14fa5f89_Y29uZmlndXJlLmFj 100644
--- a/configure.ac
+++ b/configure.ac
@@ -549,6 +549,7 @@
 libexslt/exsltconfig.h
 xsltproc/Makefile
 python/Makefile
+python/setup.py
 python/tests/Makefile
 tests/Makefile
 tests/xmlspec/Makefile
diff --git a/python/Makefile.am b/python/Makefile.am
index de959d58debd6bd5f6d20757965a5f961cd3a3b1_cHl0aG9uL01ha2VmaWxlLmFt..0d251255bd3273d82aa79fd145141b7b14fa5f89_cHl0aG9uL01ha2VmaWxlLmFt 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -13,7 +13,8 @@
 	libxml_wrap.h		\
 	libxslt_wrap.h		\
 	libxsl.py		\
-	libxslt-python-api.xml
+	libxslt-python-api.xml	\
+	setup.py.in
 
 if WITH_PYTHON
 
diff --git a/python/setup.py.in b/python/setup.py.in
new file mode 100644
index 0000000000000000000000000000000000000000..0d251255bd3273d82aa79fd145141b7b14fa5f89_cHl0aG9uL3NldHVwLnB5Lmlu
--- /dev/null
+++ b/python/setup.py.in
@@ -0,0 +1,203 @@
+#!/usr/bin/python -u
+#
+# Setup script for libxml2 and libxslt if found
+#
+import sys, os, subprocess
+
+try:
+    import setuptools
+except ImportError:
+    pass
+
+from distutils.core import setup, Extension
+
+# Below ROOT, we expect to find include, include/libxml2, lib and bin.
+# On *nix, it is not needed (but should not harm),
+# on Windows, it is set by configure.js.
+ROOT = r'@prefix@'
+
+# If this flag is set (windows only),
+# a private copy of the dlls are included in the package.
+# If this flag is not set, the libxml2 and libxslt
+# dlls must be found somewhere in the PATH at runtime.
+WITHDLLS = 1 and sys.platform.startswith('win')
+
+def missing(file):
+    if os.access(file, os.R_OK) == 0:
+        return 1
+    return 0
+
+try:
+    HOME = os.environ['HOME']
+except:
+    HOME="C:"
+
+if sys.platform.startswith('win'):
+    libraryPrefix = 'lib'
+    platformLibs = []
+else:
+    libraryPrefix = ''
+    platformLibs = ["m","z"]
+
+# those are examined to find
+# - libxslt/xsltconfig.h
+includes_dir = [
+"/usr/include",
+"/usr/local/include",
+"/opt/include",
+os.path.join(ROOT,'include'),
+HOME
+];
+
+# those are added in the linker search path for libraries
+libdirs = [
+os.path.join(ROOT,'lib'),
+]
+
+xslt_files = ["libxslt-api.xml", "libxslt-python-api.xml",
+             "libxslt.c", "libxsl.py", "libxslt_wrap.h",
+             "generator.py"]
+
+if WITHDLLS:
+    def altImport(s):
+        s = s.replace("import libxml2mod","from libxmlmods import libxml2mod")
+        s = s.replace("import libxsltmod","from libxsltmods import libxsltmod")
+        return s
+
+if missing("libxslt-py.c") or missing("libxslt.py"):
+    if missing("generator.py") or missing(os.path.join("..", "doc", "libxslt-api.xml")):
+        print("libxslt stub generator not found, libxslt not built")
+    else:
+        try:
+            if hasattr(subprocess, 'run'):
+                subprocess.run([sys.executable,
+                                'generator.py',
+                                os.path.join('..', 'doc', 'libxslt-api.xml'),
+                                'libxslt-python-api.xml'
+                               ], check=True)
+            else:
+                subprocess.check_output([sys.executable,
+                                        'generator.py',
+                                        os.path.join('..', 'doc', 'libxslt-api.xml'),
+                                        'libxslt-python-api.xml'])
+        except:
+            print("failed to generate stubs for libxslt, aborting ...")
+            print(sys.exc_info()[0], sys.exc_info()[1])
+        else:
+            head = open("libxsl.py", "r")
+            generated = open("libxsltclass.py", "r")
+            result = open("libxslt.py", "w")
+            for line in head.readlines():
+                if WITHDLLS:
+                    result.write(altImport(line))
+                else:
+                    result.write(line)
+            for line in generated.readlines():
+                result.write(line)
+            head.close()
+            generated.close()
+            result.close()
+
+xml_includes=""
+for dir in includes_dir:
+    if not missing(dir + "/libxml2/libxml/tree.h"):
+        xml_includes=dir + "/libxml2"
+        break;
+
+if xml_includes == "":
+    print("failed to find headers for libxml2: update includes_dir")
+    sys.exit(1)
+
+xslt_includes=""
+for dir in includes_dir:
+    if not missing(dir + "/libxslt/xsltconfig.h"):
+        xslt_includes=dir + "/libxslt"
+        break;
+
+if xslt_includes == "":
+    print("failed to find headers for libxslt: update includes_dir")
+
+if WITHDLLS:
+    # libxslt dlls (expected in ROOT/bin)
+    dlls = ['libxslt.dll','libexslt.dll']
+
+    packaged_dlls = [os.path.join(ROOT,'bin',dll) for dll in dlls]
+
+    # create __init__.py for the libxsltmods package
+    if not os.path.exists("libxsltmods"):
+        os.mkdir("libxsltmods")
+        open("libxsltmods/__init__.py","w").close()
+
+    packaged_dlls = [os.path.join(ROOT,'bin',dll) for dll in dlls]
+
+descr = "libxslt package"
+modules = [ 'libxslt']
+if WITHDLLS:
+    modules.append('libxsltmods.__init__')
+c_files = []
+includes= [xslt_includes, xml_includes]
+libs    = platformLibs
+macros  = []
+
+descr = "libxslt package"
+if not sys.platform.startswith('win'):
+    #
+    # We are gonna build 2 identical shared libs with merge initializing
+    # both libxml2mod and libxsltmod
+    #
+    c_files = c_files + ['libxslt-py.c', 'libxslt.c']
+    xslt_c_files = c_files
+else:
+    #
+    # On windows the MERGED_MODULE option is not needed
+    # (and does not work)
+    #
+    xslt_c_files = ['libxslt-py.c', 'libxslt.c', 'types.c']
+libs.insert(0, libraryPrefix + 'exslt')
+libs.insert(0, libraryPrefix + 'xslt')
+libs.insert(0, libraryPrefix + 'xml2')
+includes.append(xslt_includes)
+modules.append('libxslt')
+
+
+extens=[Extension('libxsltmod', xslt_c_files, include_dirs=includes,
+                        library_dirs=libdirs,
+                        libraries=libs, define_macros=macros)]
+
+if missing("MANIFEST"):
+
+    manifest = open("MANIFEST", "w")
+    manifest.write("setup.py\n")
+    for file in xslt_files:
+        manifest.write(file + "\n")
+    manifest.close()
+
+if WITHDLLS:
+    ext_package = "libxsltmods"
+    if sys.version >= "2.2":
+        base = "lib/site-packages/"
+    else:
+        base = ""
+    data_files = [(base+ext_package,packaged_dlls)]
+else:
+    ext_package = None
+    data_files = []
+
+setup (name = "libxslt-python",
+       # On *nix, the version number is created from setup.py.in
+       # On windows, it is set by configure.js
+       version = "@VERSION@",
+       description = descr,
+       author = "Daniel Veillard",
+       author_email = "veillard@redhat.com",
+       url = "https://gitlab.gnome.org/GNOME/libxslt",
+       licence="MIT Licence",
+       py_modules=modules,
+       ext_modules=extens,
+       ext_package=ext_package,
+       data_files=data_files,
+       install_requires=['libxml2_python>=@LIBXML_REQUIRED_VERSION@'],
+       )
+
+sys.exit(0)
+
diff --git a/win32/configure.js b/win32/configure.js
index de959d58debd6bd5f6d20757965a5f961cd3a3b1_d2luMzIvY29uZmlndXJlLmpz..0d251255bd3273d82aa79fd145141b7b14fa5f89_d2luMzIvY29uZmlndXJlLmpz 100644
--- a/win32/configure.js
+++ b/win32/configure.js
@@ -36,6 +36,7 @@
 var verMajorExslt;
 var verMinorExslt;
 var verMicroExslt;
+var verLibxmlReq;
 var verCvs;
 var useCvsVer = true;
 /* Libxslt features. */
@@ -48,6 +49,7 @@
 var withCrypto = true;
 var withModules = false;
 var withProfiler = true;
+var withPython = false;
 /* Win32 build options. */
 var dirSep = "\\";
 var compiler = "msvc";
@@ -108,6 +110,7 @@
 	txt += "  crypto:     Enable Crypto support (" + (withCrypto? "yes" : "no") + ")\n";
 	txt += "  modules:    Enable Module support (" + (withModules? "yes" : "no") + ")\n";
 	txt += "  profiler:   Enable Profiler support (" + (withProfiler? "yes" : "no") + ")\n";
+	txt += "  python:     Build Python bindings (" + (withPython? "yes" : "no")  + ")\n";
 	txt += "\nWin32 build options, default value given in parentheses:\n\n";
 	txt += "  compiler:   Compiler to be used [msvc|mingw] (" + compiler + ")\n";
 	txt += "  cruntime:   C-runtime compiler option (only msvc) (" + cruntime + ")\n";
@@ -169,6 +172,9 @@
 		} else if(s.search(/^LIBEXSLT_MICRO_VERSION=/) != -1) {
 			vf.WriteLine(s);
 			verMicroExslt = s.substring(s.indexOf("=") + 1, s.length);
+		} else if(s.search(/^LIBXML_REQUIRED_VERSION=/) != -1) {
+			vf.WriteLine(s);
+			verLibxmlReq = s.substring(s.indexOf("=") + 1, s.length);
 		}
 	}
 	cf.Close();
@@ -181,6 +187,7 @@
 	vf.WriteLine("WITH_CRYPTO=" + (withCrypto? "1" : "0"));
 	vf.WriteLine("WITH_MODULES=" + (withModules? "1" : "0"));
 	vf.WriteLine("WITH_PROFILER=" + (withProfiler? "1" : "0"));
+	vf.WriteLine("WITH_PYTHON=" + (withPython? "1" : "0"));
 	vf.WriteLine("DEBUG=" + (buildDebug? "1" : "0"));
 	vf.WriteLine("STATIC=" + (buildStatic? "1" : "0"));
 	vf.WriteLine("PREFIX=" + buildPrefix);
@@ -251,8 +258,8 @@
 	while (ofi.AtEndOfStream != true) {
 		ln = ofi.ReadLine();
 		s = new String(ln);
-		if (s.search(/\@LIBEXSLT_VERSION\@/) != -1) {
-			of.WriteLine(s.replace(/\@LIBEXSLT_VERSION\@/, 
+		if (s.search(/\@VERSION\@/) != -1) {
+			of.WriteLine(s.replace(/\@VERSION\@/, 
 				verMajorExslt + "." + verMinorExslt + "." + verMicroExslt));
 		} else if (s.search(/\@LIBEXSLT_VERSION_NUMBER\@/) != -1) {
 			of.WriteLine(s.replace(/\@LIBEXSLT_VERSION_NUMBER\@/, 
@@ -270,6 +277,51 @@
 	of.Close();
 }
 
+/* Configures Python bindings. Otherwise identical to the above */
+function configureLibxsltPy()
+{
+	var pyOptsFileIn = baseDir + "\\python\\setup.py.in";
+	var pyOptsFile = baseDir + "\\python\\setup.py";
+	var fso, ofi, of, ln, s;
+	fso = new ActiveXObject("Scripting.FileSystemObject");
+	ofi = fso.OpenTextFile(pyOptsFileIn, 1);
+	of = fso.CreateTextFile(pyOptsFile, true);
+	while (ofi.AtEndOfStream != true) {
+		ln = ofi.ReadLine();
+		s = new String(ln);
+		if (s.search(/\@VERSION\@/) != -1) {
+			of.WriteLine(s.replace(/\@VERSION\@/, 
+				verMajorXslt + "." + verMinorXslt + "." + verMicroXslt));
+		} else if (s.search(/\@prefix\@/) != -1) {
+			of.WriteLine(s.replace(/\@prefix\@/, buildPrefix));
+		} else if (s.search(/\@LIBXSLT_VERSION_NUMBER\@/) != -1) {
+			of.WriteLine(s.replace(/\@LIBXSLT_VERSION_NUMBER\@/, 
+				verMajorXslt*10000 + verMinorXslt*100 + verMicroXslt*1));
+		} else if (s.search(/\@LIBXSLT_VERSION_EXTRA\@/) != -1) {
+			of.WriteLine(s.replace(/\@LIBXSLT_VERSION_EXTRA\@/, verCvs));
+		} else if (s.search(/\@WITH_TRIO\@/) != -1) {
+			of.WriteLine(s.replace(/\@WITH_TRIO\@/, withTrio? "1" : "0"));
+		} else if (s.search(/\@WITH_XSLT_DEBUG\@/) != -1) {
+			of.WriteLine(s.replace(/\@WITH_XSLT_DEBUG\@/, withXsltDebug? "1" : "0"));
+		} else if (s.search(/\@WITH_MEM_DEBUG\@/) != -1) {
+			of.WriteLine(s.replace(/\@WITH_MEM_DEBUG\@/, withMemDebug? "1" : "0"));
+		} else if (s.search(/\@WITH_DEBUGGER\@/) != -1) {
+			of.WriteLine(s.replace(/\@WITH_DEBUGGER\@/, withDebugger? "1" : "0"));
+		} else if (s.search(/\@WITH_MODULES\@/) != -1) {
+			of.WriteLine(s.replace(/\@WITH_MODULES\@/, withModules? "1" : "0"));
+		} else if (s.search(/\@WITH_PROFILER\@/) != -1) {
+			of.WriteLine(s.replace(/\@WITH_PROFILER\@/, withProfiler? "1" : "0"));
+		} else if (s.search(/\@LIBXSLT_DEFAULT_PLUGINS_PATH\@/) != -1) {
+			of.WriteLine(s.replace(/\@LIBXSLT_DEFAULT_PLUGINS_PATH\@/, "NULL"));
+		} else if (s.search(/\@LIBXML_REQUIRED_VERSION\@/) != -1) {
+			of.WriteLine(s.replace(/\@LIBXML_REQUIRED_VERSION\@/, verLibxmlReq));
+		} else
+			of.WriteLine(ln);
+	}
+	ofi.Close();
+	of.Close();
+}
+
 /* Creates the readme file for the binary distribution of 'bname', for the
    version 'ver' in the file 'file'. This one is called from the Makefile when
    generating a binary distribution. The parameters are passed by make. */
@@ -336,6 +388,8 @@
 			withModules = strToBool(arg.substring(opt.length + 1, arg.length));
 		else if (opt == "profiler")
 			withProfiler = strToBool(arg.substring(opt.length + 1, arg.length));
+		else if (opt == "python")
+			withPython = strToBool(arg.substring(opt.length + 1, arg.length));
 		else if (opt == "compiler")
 			compiler = arg.substring(opt.length + 1, arg.length);
  		else if (opt == "cruntime")
@@ -432,6 +486,15 @@
 	WScript.Quit(error);
 }
 
+if (withPython == true) {
+	configureLibxsltPy();
+	if (error != 0) {
+		WScript.Echo("Configuration failed, aborting.");
+		WScript.Quit(error);
+	}
+
+}
+
 // Configure libexslt.
 configureExslt();
 if (error != 0) {
@@ -469,6 +532,7 @@
 txtOut += "            Crypto: " + boolToStr(withCrypto) + "\n";
 txtOut += "           Modules: " + boolToStr(withModules) + "\n";
 txtOut += "          Profiler: " + boolToStr(withProfiler) + "\n";
+txtOut += "   Python bindings: " + boolToStr(withPython) + "\n";
 txtOut += "\n";
 txtOut += "Win32 build configuration\n";
 txtOut += "-------------------------\n";