Merge pull request #133 from anthrotype/py27win

fix compilation on Windows Python 2.7 + support for MINGW32 and Cygwin
diff --git a/python/bro.py b/python/bro.py
index 3d21a77..0f307fb 100755
--- a/python/bro.py
+++ b/python/bro.py
@@ -9,9 +9,6 @@
 import platform
 
 
-__version__ = '1.0'
-
-
 # default values of encoder parameters
 DEFAULT_PARAMS = {
     'mode': brotli.MODE_GENERIC,
@@ -54,7 +51,7 @@
     parser = argparse.ArgumentParser(
         prog='bro.py',
         description="Compression/decompression utility using the Brotli algorithm.")
-    parser.add_argument('--version', action='version', version='%(prog)s 1.0')
+    parser.add_argument('--version', action='version', version=brotli.__version__)
     parser.add_argument('-i', '--input', metavar='FILE', type=str, dest='infile',
                         help='Input file', default=None)
     parser.add_argument('-o', '--output', metavar='FILE', type=str, dest='outfile',
diff --git a/python/brotlimodule.cc b/python/brotlimodule.cc
index c1d669a..4294664 100644
--- a/python/brotlimodule.cc
+++ b/python/brotlimodule.cc
@@ -9,6 +9,8 @@
 #define PyInt_AsLong PyLong_AsLong
 #endif
 
+#define BROTLI_VERSION "0.1.0"
+
 using namespace brotli;
 
 static PyObject *BrotliError;
@@ -110,7 +112,7 @@
   int lgblock = -1;
   int ok;
 
-  static const char *kwlist[] = {"string", "mode", "quality", "lgwin", "lgblock"};
+  static const char *kwlist[] = {"string", "mode", "quality", "lgwin", "lgblock", NULL};
 
   ok = PyArg_ParseTupleAndKeywords(args, keywds, "s#|O&O&O&O&:compress",
                         const_cast<char **>(kwlist),
@@ -243,5 +245,7 @@
   PyModule_AddIntConstant(m, "MODE_TEXT", (int) BrotliParams::Mode::MODE_TEXT);
   PyModule_AddIntConstant(m, "MODE_FONT", (int) BrotliParams::Mode::MODE_FONT);
 
+  PyModule_AddStringConstant(m, "__version__", BROTLI_VERSION);
+
   RETURN_BROTLI;
 }
diff --git a/setup.py b/setup.py
index 3b3419b..9df1135 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,37 @@
+import distutils
 from distutils.core import setup, Extension
 from distutils.command.build_ext import build_ext
 from distutils.cmd import Command
 import platform
+import os
+import re
+
+
+CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
+
+# when compiling for Windows Python 2.7, force distutils to use Visual Studio
+# 2010 instead of 2008, as the latter doesn't support c++0x
+if platform.system() == 'Windows':
+    try:
+        import distutils.msvc9compiler
+    except distutils.errors.DistutilsPlatformError:
+        pass  # importing msvc9compiler raises when running under MinGW
+    else:
+        orig_find_vcvarsall = distutils.msvc9compiler.find_vcvarsall
+        def patched_find_vcvarsall(version):
+            return orig_find_vcvarsall(version if version != 9.0 else 10.0)
+        distutils.msvc9compiler.find_vcvarsall = patched_find_vcvarsall
+
+
+def get_version():
+    """ Return BROTLI_VERSION string as defined in 'brotlimodule.cc' file. """
+    brotlimodule = os.path.join(CURR_DIR, 'python', 'brotlimodule.cc')
+    with open(brotlimodule, 'r') as f:
+        for line in f:
+            m = re.match(r'#define\sBROTLI_VERSION\s"(.*)"', line)
+            if m:
+                return m.group(1)
+    return ""
 
 
 class TestCommand(Command):
@@ -18,10 +48,9 @@
         pass
 
     def run(self):
-        import sys, os, subprocess, glob
+        import sys, subprocess, glob
 
-        curr_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-        test_dir = os.path.join(curr_dir, 'python', 'tests')
+        test_dir = os.path.join(CURR_DIR, 'python', 'tests')
         os.chdir(test_dir)
 
         for test in glob.glob("*_test.py"):
@@ -59,6 +88,11 @@
             macros = ext.define_macros[:]
             if platform.system() == "Darwin":
                 macros.append(("OS_MACOSX", "1"))
+            elif self.compiler.compiler_type == "mingw32":
+                # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot",
+                # This clashes with GCC's cmath, and causes compilation errors when
+                # building under MinGW: http://bugs.python.org/issue11566
+                macros.append(("_hypot", "hypot"))
             for undef in ext.undef_macros:
                 macros.append((undef,))
 
@@ -75,6 +109,10 @@
         if ext.extra_objects:
             objects.extend(ext.extra_objects)
         extra_args = ext.extra_link_args or []
+        # when using GCC on Windows, we statically link libgcc and libstdc++,
+        # so that we don't need to package extra DLLs
+        if self.compiler.compiler_type == "mingw32":
+            extra_args.extend(['-static-libgcc', '-static-libstdc++'])
 
         ext_path = self.get_ext_fullpath(ext.name)
         # Detect target language, if not provided
@@ -153,7 +191,7 @@
 
 setup(
     name="Brotli",
-    version="0.1",
+    version=get_version(),
     url="https://github.com/google/brotli",
     description="Python binding of the Brotli compression library",
     author="Khaled Hosny",