diff setup.py @ 575:9ce13f753c04

Allow execution of setup.py by packaging a cross-built Windows _speedups.pyd. BUGS: ABI tag must be fixed afterwards.
author Franz Glasner <fzglas.hg@dom66.de>
date Sat, 08 Jan 2022 23:00:36 +0100
parents 1bdf88437555
children 3ad416265652
line wrap: on
line diff
--- a/setup.py	Sat Jan 08 21:46:04 2022 +0100
+++ b/setup.py	Sat Jan 08 23:00:36 2022 +0100
@@ -46,44 +46,97 @@
 
 
 cmdclass = {}
-ext_modules = []
+ext_modules = None
 setup_extra_kwds = {}
 
-#
-# Handle the optinal C-extension for Python3.7+ and CPython only.
-# PyPy does not need this.
-#
+windows_cross_pack = False
+
+try:
+    wcp_idx = sys.argv.index("--windows-cross-pack")
+except ValueError:
+    wcp_idx = None
+else:
+    del sys.argv[wcp_idx]
+
+
+if wcp_idx is None:
+
+    #
+    # Otherwise some cached package_data would be used.
+    # But our package data differs between "standard" builds and
+    # builds with "--windows-cross-pack".
+    #
+
+    if os.path.isdir("ConfigMix.egg-info"):
+        raise RuntimeError("please remove ConfigMix.egg-info before")
 
-# The C-extension uses multi-phase module initialization (PEP 489, PY 3.5+)
-if (platform.python_implementation() == "CPython"
-    and (sys.version_info[0] > 3
-         or (sys.version_info[0] == 3 and sys.version_info[1] >= 5))):
+    #
+    # Handle the optinal C-extension for Python3.7+ and CPython only.
+    # PyPy does not need this.
+    #
+
+    # The C-extension uses multi-phase module initialization (PEP 489, PY 3.5+)
+    if (platform.python_implementation() == "CPython"
+        and (sys.version_info[0] > 3
+             or (sys.version_info[0] == 3 and sys.version_info[1] >= 5))):
 
-    # The stable API for Python 3.7+ is used
-    if sys.version_info[0] == 3 and sys.version_info[1] < 7:
-        py_limited_api = False
-    else:
-        py_limited_api = True
+        # The stable API for Python 3.7+ is used
+        if sys.version_info[0] == 3 and sys.version_info[1] < 7:
+            py_limited_api = False
+        else:
+            py_limited_api = True
+
+        if py_limited_api:
+            define_macros = [("Py_LIMITED_API", "0x03070000")]
+        else:
+            define_macros = []
 
-    if py_limited_api:
-        define_macros = [("Py_LIMITED_API", "0x03070000")]
-    else:
-        define_macros = []
+        try:
+            from setuptools import Extension
+        except ImportError:
+            from distutils.core import Extension
 
-    try:
-        from setuptools import Extension
-    except ImportError:
-        from distutils.core import Extension
+        ext_modules = [
+            Extension(
+                name="configmix._speedups",
+                sources=["configmix/_speedups.c"],
+                define_macros=define_macros,
+                py_limited_api=py_limited_api,
+                optional=True
+            ),
+        ]
 
-    ext_modules = [
-        Extension(
-            name="configmix._speedups",
-            sources=["configmix/_speedups.c"],
-            define_macros=define_macros,
-            py_limited_api=py_limited_api,
-            optional=True
-        ),
-    ]
+        if py_limited_api:
+            #
+            # Build a wheel that is properly named using the stable API
+            #
+            try:
+                import wheel.bdist_wheel
+            except ImportError:
+                pass
+            else:
+                class BDistWheel(wheel.bdist_wheel.bdist_wheel):
+                    def finalize_options(self):
+                        # Synchronize this with Py_LIMITED_API
+                        self.py_limited_api = 'cp37'
+                        super().finalize_options()
+
+                cmdclass["bdist_wheel"] = BDistWheel
+else:
+
+    if not os.path.isfile("configmix/_speedups.pyd"):
+        raise RuntimeError("no _speedups.pyd found")
+
+    if os.path.isdir("ConfigMix.egg-info"):
+        raise RuntimeError("please remove ConfigMix.egg-info before")
+
+    setup_extra_kwds["package_data"] = {
+        "configmix": ["*.pyd"]
+    }
+
+    ext_modules = []
+
+    py_limited_api = True
 
     if py_limited_api:
         #
@@ -92,7 +145,7 @@
         try:
             import wheel.bdist_wheel
         except ImportError:
-            cmdclass = {}
+            pass
         else:
             class BDistWheel(wheel.bdist_wheel.bdist_wheel):
                 def finalize_options(self):
@@ -100,9 +153,27 @@
                     self.py_limited_api = 'cp37'
                     super().finalize_options()
 
-            cmdclass = {'bdist_wheel': BDistWheel}
+            cmdclass["bdist_wheel"] = BDistWheel
+
+    from setuptools.dist import Distribution
+
+    #
+    # Force a binary package. An empty ext_modules does not do this always.
+    # Tested with wheel v0.29.0
+    #
+    class BinaryDistribution(Distribution):
+        """Distribution which always forces a binary package with
 
-if ext_modules:
+        platform name
+
+        """
+        def has_ext_modules(foo):
+            return True
+
+    setup_extra_kwds["distclass"] = BinaryDistribution
+
+
+if ext_modules is not None:
     setup_extra_kwds["ext_modules"] = ext_modules
     setup_extra_kwds["zip_safe"] = False
 else:
@@ -121,6 +192,10 @@
     long_description_content_type="text/x-rst",
     packages=["configmix",
               "configmix.extras"],
+    #
+    # Use non-automatic explicit package_data instead
+    # (or MANIFEST.in for sdist)
+    #
     include_package_data=False,
     platforms="any",
     classifiers=[
@@ -137,10 +212,10 @@
     ],
     python_requires=">=2.6",
     extras_require={
-        "aws" : aws_requirements,
+        "aws":  aws_requirements,    # noqa: E241
         "toml": toml_requirements,
         "yaml": yaml_requirements,
-        "all" : all_requirements,
+        "all":  all_requirements,    # noqa: E241
     },
     tests_require=all_requirements,
     **setup_extra_kwds