I have a project that compiles with C extensions on Linux, but without
them on Windows. When I first generated the wheel files on Windows with python setup.py bdist_wh
I've just run into this issue myself with Python v2.7 and wheel v0.29.0 on Windows 7 x64, where I build a Python package with some pre-compiled extensions (complicated VisualStudio setup with SWIG and external DLLs).
After examining the source code I have found that overriding Distribution.has_ext_modules
works (automatically includes platform name and ABI tag):
from setuptools import setup
from setuptools.dist import Distribution
DISTNAME = "packagename"
DESCRIPTION = ""
MAINTAINER = ""
MAINTAINER_EMAIL = ""
URL = ""
LICENSE = ""
DOWNLOAD_URL = ""
VERSION = '1.2'
PYTHON_VERSION = (2, 7)
# Tested with wheel v0.29.0
class BinaryDistribution(Distribution):
"""Distribution which always forces a binary package with platform name"""
def has_ext_modules(foo):
return True
setup(name=DISTNAME,
description=DESCRIPTION,
maintainer=MAINTAINER,
maintainer_email=MAINTAINER_EMAIL,
url=URL,
license=LICENSE,
download_url=DOWNLOAD_URL,
version=VERSION,
packages=["packagename"],
# Include pre-compiled extension
package_data={"packagename": ["_precompiled_extension.pyd"]},
distclass=BinaryDistribution)
The difference, of course, is in the environment, on the correctly working Win XP there is an older version of the wheel
package installed (0.24.0) whereas on Appveyor the latest and greatest (and broken) version 0.26 of wheel gets installed (0.25 is broken as well).
Changing the install stanza in the YAML file to fix the wheel version:
install:
- |
%PYTHON%\python.exe -m pip install --upgrade pip
%PYTHON%\python.exe -m pip install wheel==0.24
is enough to get this to work quickly.
You should however upgrade your the wheel package on your Linux box to version 0.28 and then use the new commandline option --plat-name
:
python setup.py sdist
python2 setup.py bdist_wheel --plat-name win32
python2 setup.py bdist_wheel --plat-name win_amd64
python3 setup.py bdist_wheel --plat-name win32
python3 setup.py bdist_wheel --plat-name win_amd64
that will generate:
pkg-1.1.tar.gz
dist/pkg-1.1-py2-none-win32.whl
dist/pkg-1.1-py2-none-win32.whl
dist/pkg-1.1-py3-none-win_amd64.whl
dist/pkg-1.1-py3-none-win32.whl
dist/pkg-1.0-cp34-none-win_amd64.whl
which you can upload to PyPI and results in the correct (.tar.gz
) file downloading on Linux and the appropriate wheel on Windows. By just making
sure that if the --plat-name win...
is specified setup()
is called with ext_modules=None
. The resulting wheel files have minor (line endings in 3 files and their SHA256SUM), but install normally on Windows.
That way you no longer need to build these packages, that are essentially pure packages, on a Windows machine
For me this change by Nate Coraor brings my total build time down from 15+ minutes to about 7 seconds
An alternative that seems to do the same as the accepted answer but more concisely is this:
from setuptools import setup
DISTNAME = "packagename"
DESCRIPTION = ""
MAINTAINER = ""
MAINTAINER_EMAIL = ""
URL = ""
LICENSE = ""
DOWNLOAD_URL = ""
VERSION = '1.2'
PYTHON_VERSION = (2, 7)
setup(name=DISTNAME,
description=DESCRIPTION,
maintainer=MAINTAINER,
maintainer_email=MAINTAINER_EMAIL,
url=URL,
license=LICENSE,
download_url=DOWNLOAD_URL,
version=VERSION,
packages=["packagename"],
# Include pre-compiled extension
package_data={"packagename": ["_precompiled_extension.pyd"]},
has_ext_modules=lambda: True)