Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7709989603 | ||
|
|
31e67c4f1f | ||
|
|
11bde36627 | ||
|
|
5941ba7daf | ||
|
|
c1df977e11 | ||
|
|
1dbb12daaa | ||
|
|
a005e263fc | ||
|
|
2a1081c5e5 | ||
|
|
9c908daf27 | ||
|
|
054be2eff2 | ||
|
|
20ba988b72 | ||
|
|
190b013c61 | ||
|
|
c966c6d098 | ||
|
|
d2700bc3b4 | ||
|
|
09e72800c6 | ||
|
|
2b62eef9e7 | ||
|
|
85cba9b1eb | ||
|
|
402ec9e4ac | ||
|
|
e9fd9eaead | ||
|
|
0e04fafd3a | ||
|
|
34515b78c6 | ||
|
|
7d99ccfc7b | ||
|
|
dc01231301 | ||
|
|
96a2505e78 | ||
|
|
d3fd087166 | ||
|
|
b3f82d52cc | ||
|
|
7d90a2f16b | ||
|
|
f4318e15b7 | ||
|
|
d3450e84ac | ||
|
|
a3e9b7b8ec | ||
|
|
1a9c6a5f66 | ||
|
|
c44a084a44 | ||
|
|
1e102b9bc5 | ||
|
|
46f1906e2d | ||
|
|
79c480b896 | ||
|
|
734ca6bfbd |
+3
-3
@@ -23,11 +23,11 @@ matrix:
|
||||
- os: windows
|
||||
language: shell
|
||||
before_install:
|
||||
- choco install python3 --version 3.6.8 --no-progress -y
|
||||
- choco install python3 --version 3.5.4 --no-progress -y
|
||||
install:
|
||||
- C:\\Python36\\python -m pip install -r requirements-dev.txt
|
||||
- C:\\Python35\\python -m pip install -r requirements-dev.txt
|
||||
script:
|
||||
- C:\\Python36\\python ./bin/run_tests.py
|
||||
- C:\\Python35\\python ./bin/run_tests.py
|
||||
|
||||
install: $PYTHON -m pip install -r requirements-dev.txt
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cibuildwheel
|
||||
============
|
||||
|
||||
[](https://pypi.python.org/pypi/cibuildwheel) [](https://travis-ci.org/joerick/cibuildwheel) [](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/master) [](https://circleci.com/gh/joerick/cibuildwheel)
|
||||
[](https://pypi.python.org/pypi/cibuildwheel) [](https://cibuildwheel.readthedocs.io/en/stable/?badge=stable) [](https://travis-ci.org/joerick/cibuildwheel) [](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/master) [](https://circleci.com/gh/joerick/cibuildwheel) [](https://dev.azure.com/joerick0429/cibuildwheel/_build/latest?definitionId=2&branchName=master)
|
||||
|
||||
[Documentation](https://cibuildwheel.readthedocs.org)
|
||||
|
||||
@@ -32,13 +32,13 @@ What does it do?
|
||||
Usage
|
||||
-----
|
||||
|
||||
`cibuildwheel` currently works on **Travis CI** and **Azure Pipelines** to build wheels for all three supported platforms (Linux, macOS, Windows). On **CircleCI** Linux and macOS wheels can be built, and on **AppVeyor** Windows is supported.
|
||||
`cibuildwheel` currently works on **Travis CI** and **Azure Pipelines** to build wheels for all three supported platforms (Linux, macOS, Windows). On **CircleCI** Linux and macOS wheels can be built, and on **AppVeyor** Linux and Windows are supported.
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
|-----------------|-------|-------|---------|
|
||||
| Azure Pipelines | ✅ | ✅ | ✅ |
|
||||
| Travis CI | ✅ | ✅ | ✅ |
|
||||
| AppVeyor | | | ✅ |
|
||||
| AppVeyor | ✅ | | ✅ |
|
||||
| CircleCI | ✅ | ✅ | |
|
||||
|
||||
`cibuildwheel` is not intended to run on your development machine. Because it uses system Python from Python.org it will try to install packages globally - not what you expect from a build tool! Instead, isolated CI services like Travis CI, CircleCI, Azure Pipelines and AppVeyor are ideal.
|
||||
@@ -48,43 +48,43 @@ Usage
|
||||
Example setup
|
||||
-------------
|
||||
|
||||
To build manylinux and macOS wheels on Travis CI, and upload them to PyPI whenever you tag a version, you could use this `.travis.yml`:
|
||||
To build manylinux, macOS, and Windows wheels on Travis CI and upload them to PyPI whenever you tag a version, you could use this `.travis.yml`:
|
||||
|
||||
```yaml
|
||||
language: python
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
# perform a linux build
|
||||
- sudo: required
|
||||
services:
|
||||
- docker
|
||||
env: PIP=pip
|
||||
- services: docker
|
||||
# and a mac build
|
||||
- os: osx
|
||||
language: generic
|
||||
env: PIP=pip2
|
||||
language: shell
|
||||
# and a windows build
|
||||
- os: windows
|
||||
language: shell
|
||||
before_install:
|
||||
- choco install python --version 3.8.0
|
||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
||||
|
||||
env:
|
||||
global:
|
||||
- TWINE_USERNAME=joerick
|
||||
# Note: TWINE_PASSWORD is set in Travis settings
|
||||
|
||||
install:
|
||||
- python -m pip install twine cibuildwheel==1.1.0
|
||||
|
||||
script:
|
||||
- $PIP install cibuildwheel==1.0.0
|
||||
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
- python -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
after_success:
|
||||
# if the release was tagged, upload them to PyPI
|
||||
- |
|
||||
if [[ $TRAVIS_TAG ]]; then
|
||||
python -m pip install twine
|
||||
python -m twine upload wheelhouse/*.whl
|
||||
fi
|
||||
- if [[ $TRAVIS_TAG ]]; then python -m twine upload wheelhouse/*.whl; fi
|
||||
```
|
||||
|
||||
For more information, including how to build on Appveyor, Azure, CircleCI, check out the [documentation](https://cibuildwheel.readthedocs.org).
|
||||
For more information, including how to build on Appveyor, Azure, CircleCI, check out the [documentation](https://cibuildwheel.readthedocs.org) and also check out [the examples](https://github.com/joerick/cibuildwheel/tree/master/examples).
|
||||
|
||||
Options
|
||||
-------
|
||||
@@ -95,8 +95,9 @@ Options
|
||||
| | [`CIBW_BUILD`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip) [`CIBW_SKIP`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip) | Choose the Python versions to build |
|
||||
| **Build environment** | [`CIBW_ENVIRONMENT`](https://cibuildwheel.readthedocs.io/en/stable/options/#environment) | Set environment variables needed during the build |
|
||||
| | [`CIBW_BEFORE_BUILD`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-build) | Execute a shell command preparing each wheel's build |
|
||||
| | [`CIBW_REPAIR_WHEEL_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#repair-wheel-command) | Execute a shell command to repair each (non-pure Python) built wheel |
|
||||
| | [`CIBW_MANYLINUX_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) [`CIBW_MANYLINUX_I686_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) | Specify alternative manylinux docker images |
|
||||
| **Testing** | [`CIBW_TEST_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-command) | Execute a shell command to test all built wheels |
|
||||
| **Testing** | [`CIBW_TEST_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-command) | Execute a shell command to test each built wheel |
|
||||
| | [`CIBW_TEST_REQUIRES`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-requires) | Install Python dependencies before running the tests |
|
||||
| | [`CIBW_TEST_EXTRAS`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-extras) | Install your wheel for testing using extras_require |
|
||||
| **Other** | [`CIBW_BUILD_VERBOSITY`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-extras) | Increase/decrease the output of pip wheel |
|
||||
@@ -122,7 +123,7 @@ Here are some repos that use cibuildwheel.
|
||||
Legal note
|
||||
----------
|
||||
|
||||
Since `cibuildwheel` runs the wheel through delocate or auditwheel, it might automatically bundle dynamically linked libraries from the build machine.
|
||||
Since `cibuildwheel` repairs the wheel with `delocate` or `auditwheel`, it might automatically bundle dynamically linked libraries from the build machine.
|
||||
|
||||
It helps ensure that the library can run without any dependencies outside of the pip toolchain.
|
||||
|
||||
@@ -131,6 +132,39 @@ This is similar to static linking, so it might have some licence implications. C
|
||||
Changelog
|
||||
=========
|
||||
|
||||
### 1.1.0
|
||||
|
||||
_7 December 2019_
|
||||
|
||||
- ✨ Add support for building manylinux2014 wheels. To use, set
|
||||
`CIBW_MANYLINUX_X86_64_IMAGE` and CIBW_MANYLINUX_I686_IMAGE to
|
||||
`manylinux2014`.
|
||||
- ✨ Add support for [Linux on Appveyor](https://www.appveyor.com/blog/2018/03/06/appveyor-for-linux/) (#204, #207)
|
||||
- ✨ Add `CIBW_REPAIR_WHEEL_COMMAND` env variable, for changing how
|
||||
`auditwheel` or `delocate` are invoked, or testing an equivalent on
|
||||
Windows. (#211)
|
||||
- 📚 Added some travis example configs - these are available in /examples. (#228)
|
||||
|
||||
### 1.0.0
|
||||
|
||||
_10 November 2019_
|
||||
|
||||
- ✨ Add support for building Python 3.8 wheels! (#180)
|
||||
- ✨ Add support for building manylinux2010 wheels. cibuildwheel will now
|
||||
build using the manylinux2010 images by default. If your project is still
|
||||
manylinux1 compatible, you should get both manylinux1 and manylinux2010
|
||||
wheels - you can upload both to PyPI. If you always require manylinux1 wheels, you can
|
||||
build using the old manylinux1 image using the [manylinux image](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) option.
|
||||
(#155)
|
||||
- 📚 Documentation is now on its [own mini-site](https://cibuildwheel.readthedocs.io),
|
||||
rather than on the README (#169)
|
||||
- ✨ Add support for building Windows wheels on Travis CI. (#160)
|
||||
- 🛠 If you set `CIBW_TEST_COMMAND`, your tests now run in a virtualenv. (#164)
|
||||
- 🛠 Windows now uses Python as installed by nuget, rather than the versions
|
||||
installed by the various CI providers. (#180)
|
||||
- 🛠 Update Python from 2.7.16 to 2.7.17 and 3.7.4 to 3.7.5 on macOS (#171)
|
||||
- ⚠️ Removed support for Python 3.4 (#168)
|
||||
|
||||
### 0.12.0
|
||||
|
||||
_29 September 2019_
|
||||
@@ -312,7 +346,6 @@ Maintainers
|
||||
-----------
|
||||
|
||||
- Joe Rickerby [@joerick](https://github.com/joerick)
|
||||
- Tomas Garcia [@tgarc](https://github.com/tgarc)
|
||||
- Yannick Jadoul [@YannickJadoul](https://github.com/YannickJadoul)
|
||||
- Matthieu Darbois [@mayeut](https://github.com/mayeut)
|
||||
|
||||
|
||||
+8
-7
@@ -1,10 +1,11 @@
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: "C:\\Python27\\python.exe"
|
||||
- PYTHON: "C:\\Python35\\python.exe"
|
||||
image:
|
||||
- Ubuntu
|
||||
- Visual Studio 2015
|
||||
|
||||
build_script:
|
||||
- "%PYTHON% -m pip install -r requirements-dev.txt"
|
||||
# the '-u' flag is required so the output is in the correct order.
|
||||
- cmd: "C:\\Python27\\python.exe -m pip install -r requirements-dev.txt"
|
||||
- sh: "${HOME}/.localpython3.7.4/bin/python3 -m pip install -r requirements-dev.txt"
|
||||
# the '-u' flag is required so the output is in the correct order.
|
||||
# See https://github.com/joerick/cibuildwheel/pull/24 for more info.
|
||||
- "%PYTHON% -u ./bin/run_tests.py"
|
||||
- cmd: "C:\\Python27\\python.exe -u ./bin/run_tests.py"
|
||||
- sh: "${HOME}/.localpython3.7.4/bin/python3 ./bin/run_tests.py"
|
||||
|
||||
+1
-15
@@ -3,27 +3,13 @@
|
||||
from __future__ import print_function
|
||||
import os, sys, subprocess, shutil
|
||||
|
||||
project_root = os.path.dirname(os.path.dirname(__file__))
|
||||
test_utils_dir = os.path.join(project_root, 'test', 'shared')
|
||||
|
||||
def single_run(test_project):
|
||||
# set up an environment that gives access to the test utils
|
||||
env = os.environ.copy()
|
||||
|
||||
if 'PYTHONPATH' in env:
|
||||
env['PYTHONPATH'] += os.pathsep + test_utils_dir
|
||||
else:
|
||||
env['PYTHONPATH'] = test_utils_dir
|
||||
|
||||
# run the test
|
||||
subprocess.check_call(
|
||||
[sys.executable, '-m', 'pytest', '-vv', os.path.join(test_project, 'cibuildwheel_test.py')],
|
||||
env=env,
|
||||
)
|
||||
|
||||
# clean up
|
||||
if os.path.exists('wheelhouse'):
|
||||
shutil.rmtree('wheelhouse')
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
@@ -33,7 +19,7 @@ if __name__ == '__main__':
|
||||
args = parser.parse_args()
|
||||
|
||||
project_path = os.path.abspath(args.test_project_dir)
|
||||
|
||||
|
||||
if not os.path.exists(project_path):
|
||||
print('No test project not found.', file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = '1.0.0'
|
||||
__version__ = '1.1.0'
|
||||
|
||||
+39
-34
@@ -24,6 +24,12 @@ def get_option_from_environment(option_name, platform=None, default=None):
|
||||
return os.environ.get(option_name, default)
|
||||
|
||||
|
||||
def strtobool(val):
|
||||
if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Build wheels for all the platforms.',
|
||||
@@ -38,7 +44,7 @@ def main():
|
||||
'script is going to automatically install MacPython on your system, '
|
||||
'so don\'t run on your development machine. For "windows", you need to '
|
||||
'run in Windows, and it will build and test for all versions of '
|
||||
'Python at C:\\PythonXX[-x64]. Default: auto.'))
|
||||
'Python. Default: auto.'))
|
||||
parser.add_argument('--output-dir',
|
||||
default=os.environ.get('CIBW_OUTPUT_DIR', 'wheelhouse'),
|
||||
help='Destination folder for the wheels.')
|
||||
@@ -55,42 +61,30 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
detect_obsolete_options()
|
||||
|
||||
|
||||
if args.platform != 'auto':
|
||||
platform = args.platform
|
||||
else:
|
||||
platform = None
|
||||
|
||||
if os.environ.get('TRAVIS_OS_NAME') == 'linux':
|
||||
platform = 'linux'
|
||||
elif os.environ.get('TRAVIS_OS_NAME') == 'osx':
|
||||
platform = 'macos'
|
||||
elif os.environ.get('TRAVIS_OS_NAME') == 'windows':
|
||||
platform = 'windows'
|
||||
elif 'APPVEYOR' in os.environ:
|
||||
platform = 'windows'
|
||||
elif 'BITRISE_BUILD_NUMBER' in os.environ:
|
||||
platform = 'macos'
|
||||
elif os.environ.get('CIRCLECI'):
|
||||
if sys.platform.startswith('linux'):
|
||||
platform = 'linux'
|
||||
elif sys.platform.startswith('darwin'):
|
||||
platform = 'macos'
|
||||
elif 'AZURE_HTTP_USER_AGENT' in os.environ:
|
||||
if os.environ['AGENT_OS'] == 'Linux':
|
||||
platform = 'linux'
|
||||
elif os.environ['AGENT_OS'] == 'Darwin':
|
||||
platform = 'macos'
|
||||
elif os.environ['AGENT_OS'] == 'Windows_NT':
|
||||
platform = 'windows'
|
||||
|
||||
if platform is None:
|
||||
ci = strtobool(os.environ.get('CI', 'false')) or 'BITRISE_BUILD_NUMBER' in os.environ or 'AZURE_HTTP_USER_AGENT' in os.environ
|
||||
if not ci:
|
||||
print('cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server, '
|
||||
'Travis CI, AppVeyor, and CircleCI are supported. You can run on your development '
|
||||
'machine using the --platform argument. Check --help output for more '
|
||||
'information.',
|
||||
'Travis CI, AppVeyor, Azure Pipelines and CircleCI are supported. You can run on your '
|
||||
'development machine or other CI providers using the --platform argument. Check --help '
|
||||
'output for more information.',
|
||||
file=sys.stderr)
|
||||
exit(2)
|
||||
if sys.platform.startswith('linux'):
|
||||
platform = 'linux'
|
||||
elif sys.platform == 'darwin':
|
||||
platform = 'macos'
|
||||
elif sys.platform == 'win32':
|
||||
platform = 'windows'
|
||||
else:
|
||||
print('cibuildwheel: Unable to detect platform from "sys.platform" in a CI environment. You can run '
|
||||
'cibuildwheel using the --platform argument. Check --help output for more information.',
|
||||
file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
|
||||
output_dir = args.output_dir
|
||||
test_command = get_option_from_environment('CIBW_TEST_COMMAND', platform=platform)
|
||||
@@ -100,6 +94,13 @@ def main():
|
||||
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
|
||||
build_verbosity = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
|
||||
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
|
||||
if platform == 'linux':
|
||||
repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}'
|
||||
elif platform == 'macos':
|
||||
repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel -w {dest_dir} {wheel}'
|
||||
else:
|
||||
repair_command_default = ''
|
||||
repair_command = get_option_from_environment('CIBW_REPAIR_WHEEL_COMMAND', platform=platform, default=repair_command_default)
|
||||
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
|
||||
|
||||
if test_extras:
|
||||
@@ -141,6 +142,7 @@ def main():
|
||||
before_build=before_build,
|
||||
build_verbosity=build_verbosity,
|
||||
build_selector=build_selector,
|
||||
repair_command=repair_command,
|
||||
environment=environment,
|
||||
)
|
||||
|
||||
@@ -149,9 +151,11 @@ def main():
|
||||
manylinux_i686_image = os.environ.get('CIBW_MANYLINUX_I686_IMAGE', 'manylinux2010')
|
||||
|
||||
default_manylinux_images_x86_64 = {'manylinux1': 'quay.io/pypa/manylinux1_x86_64',
|
||||
'manylinux2010': 'quay.io/pypa/manylinux2010_x86_64'}
|
||||
'manylinux2010': 'quay.io/pypa/manylinux2010_x86_64',
|
||||
'manylinux2014': 'quay.io/pypa/manylinux2014_x86_64'}
|
||||
default_manylinux_images_i686 = {'manylinux1': 'quay.io/pypa/manylinux1_i686',
|
||||
'manylinux2010': 'quay.io/pypa/manylinux2010_i686'}
|
||||
'manylinux2010': 'quay.io/pypa/manylinux2010_i686',
|
||||
'manylinux2014': 'quay.io/pypa/manylinux2014_i686'}
|
||||
|
||||
build_options.update(
|
||||
manylinux_images={'x86_64': default_manylinux_images_x86_64.get(manylinux_x86_64_image) or manylinux_x86_64_image,
|
||||
@@ -177,7 +181,8 @@ def main():
|
||||
elif platform == 'macos':
|
||||
cibuildwheel.macos.build(**build_options)
|
||||
else:
|
||||
raise Exception('Unsupported platform')
|
||||
print('cibuildwheel: Unsupported platform: {}'.format(platform), file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
|
||||
def detect_obsolete_options():
|
||||
|
||||
+18
-17
@@ -30,7 +30,7 @@ def get_python_configurations(build_selector):
|
||||
return [c for c in python_configurations if build_selector(c.identifier)]
|
||||
|
||||
|
||||
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment, manylinux_images):
|
||||
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, manylinux_images):
|
||||
try:
|
||||
subprocess.check_call(['docker', '--version'])
|
||||
except:
|
||||
@@ -60,30 +60,28 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
{environment_exports}
|
||||
|
||||
for PYBIN in {pybin_paths}; do
|
||||
# Setup
|
||||
rm -rf /tmp/built_wheel
|
||||
rm -rf /tmp/delocated_wheels
|
||||
mkdir /tmp/built_wheel
|
||||
mkdir /tmp/delocated_wheels
|
||||
|
||||
if [ ! -z {before_build} ]; then
|
||||
PATH="$PYBIN:$PATH" sh -c {before_build}
|
||||
fi
|
||||
|
||||
# Build that wheel
|
||||
# Build the wheel
|
||||
rm -rf /tmp/built_wheel
|
||||
mkdir /tmp/built_wheel
|
||||
PATH="$PYBIN:$PATH" "$PYBIN/pip" wheel . -w /tmp/built_wheel --no-deps {build_verbosity_flag}
|
||||
built_wheel=(/tmp/built_wheel/*.whl)
|
||||
|
||||
# Delocate the wheel
|
||||
# repair the wheel
|
||||
rm -rf /tmp/repaired_wheels
|
||||
mkdir /tmp/repaired_wheels
|
||||
# NOTE: 'built_wheel' here is a bash array of glob matches; "$built_wheel" returns
|
||||
# the first element
|
||||
if [[ "$built_wheel" == *none-any.whl ]]; then
|
||||
# pure python wheel - just copy
|
||||
mv "$built_wheel" /tmp/delocated_wheels
|
||||
if [[ "$built_wheel" == *none-any.whl ]] || [ -z {repair_command} ]; then
|
||||
# pure Python wheel or empty repair command
|
||||
mv "$built_wheel" /tmp/repaired_wheels
|
||||
else
|
||||
auditwheel repair "$built_wheel" -w /tmp/delocated_wheels
|
||||
sh -c {repair_command} repair_command "$built_wheel"
|
||||
fi
|
||||
delocated_wheels=(/tmp/delocated_wheels/*.whl)
|
||||
repaired_wheels=(/tmp/repaired_wheels/*.whl)
|
||||
|
||||
if [ ! -z {test_command} ]; then
|
||||
# Set up a virtual environment to install and test from, to make sure
|
||||
@@ -105,7 +103,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
# functionally the same, differing only in name, wheel metadata, and possibly include
|
||||
# different external shared libraries. so it doesn't matter which one we run the tests on.
|
||||
# Let's just pick the first one.
|
||||
pip install "${{delocated_wheels[0]}}"{test_extras}
|
||||
pip install "${{repaired_wheels[0]}}"{test_extras}
|
||||
|
||||
# Install any requirements to run the tests
|
||||
if [ ! -z "{test_requires}" ]; then
|
||||
@@ -127,8 +125,8 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
fi
|
||||
|
||||
# we're all done here; move it to output
|
||||
mv "${{delocated_wheels[@]}}" /output
|
||||
for delocated_wheel in "${{delocated_wheels[@]}}"; do chown {uid}:{gid} "/output/$(basename "$delocated_wheel")"; done
|
||||
mv "${{repaired_wheels[@]}}" /output
|
||||
for repaired_wheel in "${{repaired_wheels[@]}}"; do chown {uid}:{gid} "/output/$(basename "$repaired_wheel")"; done
|
||||
done
|
||||
'''.format(
|
||||
pybin_paths=' '.join(c.path+'/bin' for c in platform_configs),
|
||||
@@ -141,6 +139,9 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
prepare_command(before_build, project='/project') if before_build else ''
|
||||
),
|
||||
build_verbosity_flag=' '.join(get_build_verbosity_extra_flags(build_verbosity)),
|
||||
repair_command=shlex_quote(
|
||||
prepare_command(repair_command, wheel='"$1"', dest_dir='/tmp/repaired_wheels') if repair_command else ''
|
||||
),
|
||||
environment_exports='\n'.join(environment.as_shell_commands()),
|
||||
uid=os.getuid(),
|
||||
gid=os.getgid(),
|
||||
|
||||
+28
-28
@@ -25,7 +25,12 @@ def get_python_configurations(build_selector):
|
||||
return [c for c in python_configurations if build_selector(c.identifier)]
|
||||
|
||||
|
||||
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment):
|
||||
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment):
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
|
||||
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
|
||||
repaired_wheel_dir = os.path.join(temp_dir, 'repaired_wheel')
|
||||
|
||||
python_configurations = get_python_configurations(build_selector)
|
||||
get_pip_url = 'https://bootstrap.pypa.io/get-pip.py'
|
||||
get_pip_script = '/tmp/get-pip.py'
|
||||
@@ -44,8 +49,6 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
|
||||
return subprocess.check_call(args, env=env, cwd=cwd, shell=shell)
|
||||
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
|
||||
# get latest pip once and for all
|
||||
call(['curl', '-L', '-o', get_pip_script, get_pip_url])
|
||||
|
||||
@@ -63,6 +66,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
call(['sudo', 'tar', '-C', '/Library/Frameworks/Python.framework/Versions/%s/' % config.version, '-xmf', '/tmp/python-patch.tar.gz'])
|
||||
|
||||
installation_bin_path = '/Library/Frameworks/Python.framework/Versions/{}/bin'.format(config.version)
|
||||
assert os.path.exists(os.path.join(installation_bin_path, 'python3' if config.version[0] == '3' else 'python'))
|
||||
|
||||
# Python bin folders on Mac don't symlink python3 to python, so we do that
|
||||
# so `python` and `pip` always point to the active configuration.
|
||||
@@ -88,19 +92,10 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
call(['python', '--version'], env=env)
|
||||
|
||||
# install pip & wheel
|
||||
call(['python', get_pip_script, '--no-setuptools', '--no-wheel'], env=env)
|
||||
call(['python', get_pip_script, '--no-setuptools', '--no-wheel'], env=env, cwd="/tmp")
|
||||
assert os.path.exists(os.path.join(installation_bin_path, 'pip'))
|
||||
call(['pip', '--version'], env=env)
|
||||
call(['pip', 'install', '--upgrade', 'setuptools'], env=env)
|
||||
call(['pip', 'install', 'wheel'], env=env)
|
||||
call(['pip', 'install', 'delocate'], env=env)
|
||||
|
||||
# setup dirs
|
||||
if os.path.exists('/tmp/built_wheel'):
|
||||
shutil.rmtree('/tmp/built_wheel')
|
||||
os.makedirs('/tmp/built_wheel')
|
||||
if os.path.exists('/tmp/delocated_wheel'):
|
||||
shutil.rmtree('/tmp/delocated_wheel')
|
||||
os.makedirs('/tmp/delocated_wheel')
|
||||
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', 'delocate'], env=env)
|
||||
|
||||
# run the before_build command
|
||||
if before_build:
|
||||
@@ -108,18 +103,23 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
call(before_build_prepared, env=env, shell=True)
|
||||
|
||||
# build the wheel
|
||||
call(['pip', 'wheel', abs_project_dir, '-w', '/tmp/built_wheel', '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
|
||||
built_wheel = glob('/tmp/built_wheel/*.whl')[0]
|
||||
if os.path.exists(built_wheel_dir):
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
os.makedirs(built_wheel_dir)
|
||||
call(['pip', 'wheel', abs_project_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
|
||||
built_wheel = glob(os.path.join(built_wheel_dir, '*.whl'))[0]
|
||||
|
||||
if built_wheel.endswith('none-any.whl'):
|
||||
# pure python wheel - just move
|
||||
shutil.move(built_wheel, '/tmp/delocated_wheel')
|
||||
# repair the wheel
|
||||
if os.path.exists(repaired_wheel_dir):
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
os.makedirs(repaired_wheel_dir)
|
||||
if built_wheel.endswith('none-any.whl') or not repair_command:
|
||||
# pure Python wheel or empty repair command
|
||||
shutil.move(built_wheel, repaired_wheel_dir)
|
||||
else:
|
||||
# list the dependencies
|
||||
call(['delocate-listdeps', built_wheel], env=env)
|
||||
# rebuild the wheel with shared libraries included and place in output dir
|
||||
call(['delocate-wheel', '-w', '/tmp/delocated_wheel', built_wheel], env=env)
|
||||
delocated_wheel = glob('/tmp/delocated_wheel/*.whl')[0]
|
||||
repair_command_prepared = prepare_command(repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
call(repair_command_prepared, env=env, shell=True)
|
||||
repaired_wheel = glob(os.path.join(repaired_wheel_dir, '*.whl'))[0]
|
||||
|
||||
if test_command:
|
||||
# set up a virtual environment to install and test from, to make sure
|
||||
@@ -141,7 +141,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
call(['which', 'python'], env=virtualenv_env)
|
||||
|
||||
# install the wheel
|
||||
call(['pip', 'install', delocated_wheel + test_extras], env=virtualenv_env)
|
||||
call(['pip', 'install', repaired_wheel + test_extras], env=virtualenv_env)
|
||||
|
||||
# test the wheel
|
||||
if test_requires:
|
||||
@@ -157,5 +157,5 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# we're all done here; move it to output (overwrite existing)
|
||||
dst = os.path.join(output_dir, os.path.basename(delocated_wheel))
|
||||
shutil.move(delocated_wheel, dst)
|
||||
dst = os.path.join(output_dir, os.path.basename(repaired_wheel))
|
||||
shutil.move(repaired_wheel, dst)
|
||||
|
||||
@@ -2,14 +2,14 @@ from fnmatch import fnmatch
|
||||
import warnings
|
||||
|
||||
|
||||
def prepare_command(command, project):
|
||||
def prepare_command(command, **kwargs):
|
||||
'''
|
||||
Preprocesses a command by expanding variables like {project}.
|
||||
Preprocesses a command by expanding variables like {python}.
|
||||
|
||||
For example, used in the test_command option, to specify the path to the
|
||||
tests directory.
|
||||
For example, used in the test_command option to specify the path to the
|
||||
project's root.
|
||||
'''
|
||||
return command.format(python='python', pip='pip', project=project)
|
||||
return command.format(python='python', pip='pip', **kwargs)
|
||||
|
||||
|
||||
def get_build_verbosity_extra_flags(level):
|
||||
|
||||
+35
-22
@@ -57,8 +57,7 @@ def get_python_configurations(build_selector):
|
||||
return python_configurations
|
||||
|
||||
|
||||
|
||||
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment):
|
||||
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment):
|
||||
def simple_shell(args, env=None, cwd=None):
|
||||
print('+ ' + ' '.join(args))
|
||||
args = ['cmd', '/E:ON', '/V:ON', '/C'] + args
|
||||
@@ -90,6 +89,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
|
||||
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
|
||||
repaired_wheel_dir = os.path.join(temp_dir, 'repaired_wheel')
|
||||
|
||||
# install nuget as best way to provide python
|
||||
nuget = 'C:\\cibw\\nuget.exe'
|
||||
@@ -100,22 +100,13 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
|
||||
python_configurations = get_python_configurations(build_selector)
|
||||
for config in python_configurations:
|
||||
# install Python
|
||||
config_python_path = get_python_path(config)
|
||||
simple_shell([nuget, "install"] + get_nuget_args(config))
|
||||
if not os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe')):
|
||||
simple_shell([os.path.join(config_python_path, 'python.exe'), get_pip_script ])
|
||||
|
||||
# check python & pip exist for this configuration
|
||||
assert os.path.exists(os.path.join(config_python_path, 'python.exe'))
|
||||
assert os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe'))
|
||||
|
||||
# setup dirs
|
||||
if os.path.exists(built_wheel_dir):
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
os.makedirs(built_wheel_dir)
|
||||
|
||||
# set up PATH and environment variables for run_with_env
|
||||
env = os.environ.copy()
|
||||
# set up environment variables for run_with_env
|
||||
env['PYTHON_VERSION'] = config.version
|
||||
env['PYTHON_ARCH'] = config.arch
|
||||
env['PATH'] = os.pathsep.join([
|
||||
@@ -123,16 +114,23 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
os.path.join(config_python_path, 'Scripts'),
|
||||
env['PATH']
|
||||
])
|
||||
# update env with results from CIBW_ENVIRONMENT
|
||||
env = environment.as_dictionary(prev_environment=env)
|
||||
|
||||
# for the logs - check we're running the right version of python
|
||||
shell(['python', '--version'], env=env)
|
||||
shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env)
|
||||
simple_shell(['where', 'python'], env=env)
|
||||
simple_shell(['python', '--version'], env=env)
|
||||
simple_shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env)
|
||||
|
||||
# make sure pip is installed
|
||||
if not os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe')):
|
||||
simple_shell(['python', get_pip_script], env=env, cwd="C:\\cibw")
|
||||
assert os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe'))
|
||||
|
||||
# prepare the Python environment
|
||||
shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], env=env)
|
||||
shell(['pip', 'install', '--upgrade', 'setuptools'], env=env)
|
||||
shell(['pip', 'install', 'wheel'], env=env)
|
||||
simple_shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], env=env)
|
||||
simple_shell(['pip', '--version'], env=env)
|
||||
simple_shell(['pip', 'install', '--upgrade', 'setuptools', 'wheel'], env=env)
|
||||
|
||||
# run the before_build command
|
||||
if before_build:
|
||||
@@ -140,8 +138,23 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
shell([before_build_prepared], env=env)
|
||||
|
||||
# build the wheel
|
||||
if os.path.exists(built_wheel_dir):
|
||||
shutil.rmtree(built_wheel_dir)
|
||||
os.makedirs(built_wheel_dir)
|
||||
shell(['pip', 'wheel', abs_project_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
|
||||
built_wheel = glob(built_wheel_dir+'/*.whl')[0]
|
||||
built_wheel = glob(os.path.join(built_wheel_dir, '*.whl'))[0]
|
||||
|
||||
# repair the wheel
|
||||
if os.path.exists(repaired_wheel_dir):
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
os.makedirs(repaired_wheel_dir)
|
||||
if built_wheel.endswith('none-any.whl') or not repair_command:
|
||||
# pure Python wheel or empty repair command
|
||||
shutil.move(built_wheel, repaired_wheel_dir)
|
||||
else:
|
||||
repair_command_prepared = prepare_command(repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
shell([repair_command_prepared], env=env)
|
||||
repaired_wheel = glob(os.path.join(repaired_wheel_dir, '*.whl'))[0]
|
||||
|
||||
if test_command:
|
||||
# set up a virtual environment to install and test from, to make sure
|
||||
@@ -160,7 +173,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
shell(['which', 'python'], env=virtualenv_env)
|
||||
|
||||
# install the wheel
|
||||
shell(['pip', 'install', built_wheel + test_extras], env=virtualenv_env)
|
||||
shell(['pip', 'install', repaired_wheel + test_extras], env=virtualenv_env)
|
||||
|
||||
# test the wheel
|
||||
if test_requires:
|
||||
@@ -176,7 +189,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# we're all done here; move it to output (remove if already exists)
|
||||
dst = os.path.join(output_dir, os.path.basename(built_wheel))
|
||||
dst = os.path.join(output_dir, os.path.basename(repaired_wheel))
|
||||
if os.path.isfile(dst):
|
||||
os.remove(dst)
|
||||
shutil.move(built_wheel, dst)
|
||||
shutil.move(repaired_wheel, dst)
|
||||
|
||||
+76
-26
@@ -4,7 +4,7 @@
|
||||
|
||||
## Setting options
|
||||
|
||||
cibuildwheel is configured using environment variables, that can be set using
|
||||
cibuildwheel is configured using environment variables, that can be set using
|
||||
your CI config.
|
||||
|
||||
For example, to configure cibuildwheel to run tests, add the following YAML to
|
||||
@@ -120,7 +120,7 @@ CIBW_SKIP: "*-win32 *-manylinux_i686"
|
||||
font-size: 90%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rst-content .build-id-table-marker + table td,
|
||||
.rst-content .build-id-table-marker + table td,
|
||||
.rst-content .build-id-table-marker + table th {
|
||||
padding: 4px 4px;
|
||||
}
|
||||
@@ -148,6 +148,11 @@ You must set this variable to pass variables to Linux builds (since they execute
|
||||
|
||||
You can use `$PATH` syntax to insert other variables, or the `$(pwd)` syntax to insert the output of other shell commands.
|
||||
|
||||
To specify more than one environment variable separate it by space.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_ENVIRONMENT_MACOS` | `CIBW_ENVIRONMENT_WINDOWS` | `CIBW_ENVIRONMENT_LINUX`
|
||||
|
||||
#### Examples
|
||||
```yaml
|
||||
# Set some compiler flags
|
||||
@@ -161,10 +166,10 @@ CIBW_ENVIRONMENT: "BUILD_TIME=$(date)"
|
||||
|
||||
# Supply options to `pip` to affect how it downloads dependencies
|
||||
CIBW_ENVIRONMENT: "PIP_EXTRA_INDEX_URL=https://pypi.myorg.com/simple"
|
||||
```
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_ENVIRONMENT_MACOS` | `CIBW_ENVIRONMENT_WINDOWS` | `CIBW_ENVIRONMENT_LINUX`
|
||||
# Set two flags
|
||||
CIBW_ENVIRONMENT: "BUILD_TIME=$(date) SAMPLE_TEXT=\"sample text\""
|
||||
```
|
||||
|
||||
!!! note
|
||||
`cibuildwheel` always defines the environment variable `CIBUILDWHEEL=1`. This can be useful for [building wheels with optional extensions](faq.md#building-packages-with-optional-c-extensions).
|
||||
@@ -177,7 +182,12 @@ A shell command to run before building the wheel. This option allows you to run
|
||||
|
||||
If dependencies are required to build your wheel (for example if you include a header from a Python module), set this to `pip install .`, and the dependencies will be installed automatically by pip. However, this means your package will be built twice - if your package takes a long time to build, you might wish to manually list the dependencies here instead.
|
||||
|
||||
The active Python binary can be accessed using `python`, and pip with `pip`; `cibuildwheel` makes sure the right version of Python and pip will be executed. `{project}` can be used as a placeholder for the absolute path to the project's root.
|
||||
The active Python binary can be accessed using `python`, and pip with `pip`; `cibuildwheel` makes sure the right version of Python and pip will be executed. `{project}` can be used as a placeholder for the absolute path to the project's root and will be replaced by `cibuildwheel`.
|
||||
|
||||
On Linux and macOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX`
|
||||
|
||||
#### Examples
|
||||
```yaml
|
||||
@@ -191,21 +201,53 @@ CIBW_BEFORE_BUILD: pip install pybind11
|
||||
CIBW_BEFORE_BUILD: yum install -y libffi-dev && pip install .
|
||||
```
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX`
|
||||
|
||||
### `CIBW_REPAIR_WHEEL_COMMAND` {: #repair-wheel-command}
|
||||
> Execute a shell command to repair each (non-pure Python) built wheel
|
||||
|
||||
Default:
|
||||
|
||||
- on Linux: `'auditwheel repair -w {dest_dir} {wheel}'`
|
||||
- on macOS: `'delocate-listdeps {wheel} && delocate-wheel -w {dest_dir} {wheel}'`
|
||||
- on Windows: `''`
|
||||
|
||||
A shell command to repair a built wheel by copying external library dependencies into the wheel tree and relinking them.
|
||||
The command is run on each built wheel (except for pure Python ones) before testing it.
|
||||
|
||||
The following placeholders must be used inside the command and will be replaced by `cibuildwheel`:
|
||||
|
||||
- `{wheel}` for the absolute path to the built wheel
|
||||
- `{dest_dir}` for the absolute path of the directory where to create the repaired wheel.
|
||||
|
||||
On Linux and macOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_REPAIR_WHEEL_COMMAND_MACOS` | `CIBW_REPAIR_WHEEL_COMMAND_WINDOWS` | `CIBW_REPAIR_WHEEL_COMMAND_LINUX`
|
||||
|
||||
#### Examples
|
||||
|
||||
```yaml
|
||||
# don't repair macOS wheels
|
||||
CIBW_REPAIR_WHEEL_COMMAND_MACOS: ""
|
||||
|
||||
# pass the `--lib-sdir .` flag to auditwheel on Linux
|
||||
CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"
|
||||
```
|
||||
|
||||
|
||||
### `CIBW_MANYLINUX_X86_64_IMAGE`, `CIBW_MANYLINUX_I686_IMAGE` {: #manylinux-image}
|
||||
> Specify alternative manylinux docker images
|
||||
> Specify alternative manylinux docker images
|
||||
|
||||
An alternative Docker image to be used for building [`manylinux`](https://github.com/pypa/manylinux) wheels. `cibuildwheel` will then pull these instead of the default images, [`quay.io/pypa/manylinux2010_x86_64`](https://quay.io/pypa/manylinux2010_x86_64) and [`quay.io/pypa/manylinux2010_i686`](https://quay.io/pypa/manylinux2010_i686).
|
||||
|
||||
The value of this option can either be set to `manylinux1` or `manylinux2010` to use the [official `manylinux` images](https://github.com/pypa/manylinux), or any other valid Docker image name.
|
||||
The value of this option can either be set to `manylinux1`, `manylinux2010` or `manylinux2014` to use the [official `manylinux` images](https://github.com/pypa/manylinux), or any other valid Docker image name.
|
||||
|
||||
Beware to specify a valid Docker image that can be used in the same way as the official, default Docker images: all necessary Python and pip versions need to be present in `/opt/python/`, and the `auditwheel` tool needs to be present for `cibuildwheel` to work. Apart from that, the architecture and relevant shared system libraries need to be manylinux1- or manylinux2010-compatible in order to produce valid `manylinux1`/`manylinux2010` wheels (see https://github.com/pypa/manylinux, [PEP 513](https://www.python.org/dev/peps/pep-0513/), and [PEP 571](https://www.python.org/dev/peps/pep-0571/) for more details).
|
||||
Beware to specify a valid Docker image that can be used in the same way as the official, default Docker images: all necessary Python and pip versions need to be present in `/opt/python/`, and the `auditwheel` tool needs to be present for `cibuildwheel` to work. Apart from that, the architecture and relevant shared system libraries need to be manylinux1-, manylinux2010- or manylinux2014-compatible in order to produce valid `manylinux1`/`manylinux2010`/`manylinux2014` wheels (see https://github.com/pypa/manylinux, [PEP 513](https://www.python.org/dev/peps/pep-0513/), [PEP 571](https://www.python.org/dev/peps/pep-0571/ and [PEP 599](https://www.python.org/dev/peps/pep-0599/) for more details).
|
||||
|
||||
Note that `auditwheel` detects the version of the `manylinux` standard in the Docker image through the `AUDITWHEEL_PLAT` environment variable, as `cibuildwheel` has no way of detecting the correct `--plat` command line argument to pass to `auditwheel` for a custom image. If a Docker image does not correctly set this `AUDITWHEEL_PLAT` environment variable, the `CIBW_ENVIRONMENT` option can be used to do so (e.g., `CIBW_ENVIRONMENT="manylinux2010_$(uname -m)"`).
|
||||
|
||||
Note that `manylinux2014` doesn't support builds with Python 2.7 - when building with `manylinux2014`, skip Python 2.7 using `CIBW_SKIP` (see example below).
|
||||
|
||||
#### Examples
|
||||
|
||||
```yaml
|
||||
@@ -213,6 +255,11 @@ Note that `auditwheel` detects the version of the `manylinux` standard in the Do
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: manylinux1
|
||||
CIBW_MANYLINUX_I686_IMAGE: manylinux1
|
||||
|
||||
# build using the manylinux2014 image
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
|
||||
CIBW_MANYLINUX_I686_IMAGE: manylinux2014
|
||||
CIBW_SKIP: cp27-manylinux*
|
||||
|
||||
# build using a different image from the docker registry
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: dockcross/manylinux-x64
|
||||
CIBW_MANYLINUX_I686_IMAGE: dockcross/manylinux-x86
|
||||
@@ -221,11 +268,14 @@ CIBW_MANYLINUX_I686_IMAGE: dockcross/manylinux-x86
|
||||
## Testing
|
||||
|
||||
### `CIBW_TEST_COMMAND` {: #test-command}
|
||||
> Execute a shell command to test all built wheels
|
||||
> Execute a shell command to test each built wheel
|
||||
|
||||
Shell command to run tests after the build. The wheel will be installed automatically and available for import from the tests. `{project}` can be used as a placeholder for the absolute path to the project's root and will be replaced by `cibuildwheel`.
|
||||
|
||||
On Linux and Mac, the command runs in a shell, so you can write things like `cmd1 && cmd2`.
|
||||
On Linux and macOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX`
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -237,27 +287,25 @@ CIBW_TEST_COMMAND: nosetests {project}/tests
|
||||
CIBW_TEST_COMMAND: nosetests {project}/tests
|
||||
```
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX`
|
||||
|
||||
|
||||
### `CIBW_TEST_REQUIRES` {: #test-requires}
|
||||
> Install Python dependencies before running the tests
|
||||
|
||||
Space-separated list of dependencies required for running the tests.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_TEST_REQUIRES_MACOS` | `CIBW_TEST_REQUIRES_WINDOWS` | `CIBW_TEST_REQUIRES_LINUX`
|
||||
|
||||
#### Examples
|
||||
|
||||
```yaml
|
||||
# install pytest before running CIBW_TEST_COMMAND
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
|
||||
# install specific versions of test dependencies
|
||||
CIBW_TEST_REQUIRES: nose==1.3.7 moto==0.4.31
|
||||
```
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_TEST_REQUIRES_MACOS` | `CIBW_TEST_REQUIRES_WINDOWS` | `CIBW_TEST_REQUIRES_LINUX`
|
||||
|
||||
### `CIBW_TEST_EXTRAS` {: #test-extras}
|
||||
> Install your wheel for testing using `extras_require`
|
||||
@@ -269,15 +317,16 @@ tests. This can be used to avoid having to redefine test dependencies in
|
||||
`CIBW_TEST_REQUIRES` if they are already defined in `setup.py` or
|
||||
`setup.cfg`.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_TEST_EXTRAS_MACOS` | `CIBW_TEST_EXTRAS_WINDOWS` | `CIBW_TEST_EXTRAS_LINUX`
|
||||
|
||||
#### Examples
|
||||
|
||||
```yaml
|
||||
# will cause the wheel to be installed with `pip install <wheel_file>[test,qt]`
|
||||
CIBW_TEST_EXTRAS: test,qt
|
||||
CIBW_TEST_EXTRAS: test,qt
|
||||
```
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_TEST_EXTRAS_MACOS` | `CIBW_TEST_EXTRAS_WINDOWS` | `CIBW_TEST_EXTRAS_LINUX`
|
||||
|
||||
## Other
|
||||
|
||||
@@ -286,6 +335,9 @@ Platform-specific variants also available:
|
||||
|
||||
An number from 1 to 3 to increase the level of verbosity (corresponding to invoking pip with `-v`, `-vv`, and `-vvv`), between -1 and -3 (`-q`, `-qq`, and `-qqq`), or just 0 (default verbosity). These flags are useful while debugging a build when the output of the actual build invoked by `pip wheel` is required.
|
||||
|
||||
Platform-specific variants also available:<br/>
|
||||
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX`
|
||||
|
||||
#### Examples
|
||||
|
||||
```yaml
|
||||
@@ -293,8 +345,6 @@ An number from 1 to 3 to increase the level of verbosity (corresponding to invok
|
||||
CIBW_BUILD_VERBOSITY: 1
|
||||
```
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX`
|
||||
|
||||
## Command line options
|
||||
|
||||
@@ -302,7 +352,7 @@ Platform-specific variants also available:
|
||||
usage: cibuildwheel [-h] [--platform {auto,linux,macos,windows}]
|
||||
[--output-dir OUTPUT_DIR] [--print-build-identifiers]
|
||||
[project_dir]
|
||||
|
||||
|
||||
Build wheels for all the platforms.
|
||||
|
||||
positional arguments:
|
||||
@@ -381,7 +431,7 @@ optional arguments:
|
||||
|
||||
options[header].push({name: optionName, description, id});
|
||||
});
|
||||
|
||||
|
||||
// write the table of contents
|
||||
|
||||
var tocTable = $('.options-toc');
|
||||
|
||||
+44
-35
@@ -11,33 +11,33 @@ Using Azure pipelines, you can build all three platforms on the same service. Cr
|
||||
jobs:
|
||||
- job: linux
|
||||
pool: {vmImage: 'Ubuntu-16.04'}
|
||||
steps:
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
- bash: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel==1.0.0
|
||||
pip install cibuildwheel==1.1.0
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
- job: macos
|
||||
pool: {vmImage: 'macOS-10.13'}
|
||||
steps:
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
- bash: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel==1.0.0
|
||||
pip install cibuildwheel==1.1.0
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
- job: windows
|
||||
pool: {vmImage: 'vs2017-win2016'}
|
||||
steps:
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
- script: choco install vcpython27 -f -y
|
||||
displayName: Install Visual C++ for Python 2.7
|
||||
- bash: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel==1.0.0
|
||||
pip install cibuildwheel==1.1.0
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
@@ -47,37 +47,39 @@ Commit this file, enable building of your repo on Azure Pipelines, and push.
|
||||
|
||||
Wheels will be stored for you and available through the Pipelines interface. For more info on this file, check out the [docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema).
|
||||
|
||||
# Travis CI [linux/mac] {: #travis-ci}
|
||||
# Travis CI [linux/mac/windows] {: #travis-ci}
|
||||
|
||||
To build Linux and Mac wheels on Travis CI, create a `.travis.yml` file in your repo.
|
||||
To build Linux, Mac, and Windows wheels on Travis CI, create a `.travis.yml` file in your repo.
|
||||
|
||||
> .travis.yml
|
||||
```yaml
|
||||
language: python
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
- sudo: required
|
||||
services:
|
||||
- docker
|
||||
env: PIP=pip
|
||||
# perform a linux build
|
||||
- services: docker
|
||||
# and a mac build
|
||||
- os: osx
|
||||
language: generic
|
||||
env: PIP=pip2
|
||||
|
||||
script:
|
||||
- $PIP install cibuildwheel==1.0.0
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
```
|
||||
|
||||
To build on Windows too, add this matrix entry:
|
||||
```yaml
|
||||
language: shell
|
||||
# and a windows build
|
||||
- os: windows
|
||||
language: shell
|
||||
before_install:
|
||||
- choco install python3 --version 3.6.8 --no-progress -y
|
||||
env:
|
||||
- PATH=/c/Python36:/c/Python36/Scripts:$PATH
|
||||
- choco install python --version 3.8.0
|
||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
||||
|
||||
env:
|
||||
global:
|
||||
- TWINE_USERNAME=joerick
|
||||
# Note: TWINE_PASSWORD is set in Travis settings
|
||||
|
||||
install:
|
||||
- python -m pip install twine cibuildwheel==1.1.0
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
- python -m cibuildwheel --output-dir wheelhouse
|
||||
```
|
||||
|
||||
Note that building Windows Python 2.7 wheels on Travis is unsupported.
|
||||
@@ -105,11 +107,11 @@ jobs:
|
||||
- run:
|
||||
name: Build the Linux wheels.
|
||||
command: |
|
||||
pip install --user cibuildwheel==1.0.0
|
||||
pip install --user cibuildwheel==1.1.0
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
|
||||
|
||||
osx-wheels:
|
||||
working_directory: ~/osx-wheels
|
||||
macos:
|
||||
@@ -119,7 +121,7 @@ jobs:
|
||||
- run:
|
||||
name: Build the OS X wheels.
|
||||
command: |
|
||||
pip install --user cibuildwheel==1.0.0
|
||||
pip install --user cibuildwheel==1.1.0
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
@@ -139,16 +141,23 @@ Commit this file, enable building of your repo on CircleCI, and push.
|
||||
|
||||
CircleCI will store the built wheels for you - you can access them from the project console. Check out the CircleCI [docs](https://circleci.com/docs/2.0/configuration-reference/#section=configuration) for more info on this config file.
|
||||
|
||||
# AppVeyor [windows] {: #appveyor}
|
||||
# AppVeyor [linux/windows] {: #appveyor}
|
||||
|
||||
To build Windows wheels on AppVeyor, create an `appveyor.yml` file in your repo.
|
||||
To build Linux and Windows wheels on AppVeyor, create an `appveyor.yml` file in your repo.
|
||||
|
||||
> appveyor.yml
|
||||
|
||||
```yaml
|
||||
image:
|
||||
- Ubuntu
|
||||
- Visual Studio 2015
|
||||
build_script:
|
||||
- pip install cibuildwheel==1.0.0
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
# windows
|
||||
- cmd: pip install cibuildwheel==1.1.0
|
||||
- cmd: cibuildwheel --output-dir wheelhouse
|
||||
# linux
|
||||
- sh: "${HOME}/.localpython3.7.4/bin/python3 -m pip install cibuildwheel==1.1.0"
|
||||
- sh: "${HOME}/.localpython3.7.4/bin/python3 -m cibuildwheel --output-dir wheelhouse"
|
||||
artifacts:
|
||||
- path: "wheelhouse\\*.whl"
|
||||
name: Wheels
|
||||
@@ -162,7 +171,7 @@ For more info on this config file, check out the [docs](https://www.appveyor.com
|
||||
|
||||
> ⚠️ Got an error? Check the [FAQ](faq.md).
|
||||
|
||||
<script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$('.toctree-l2 a, .rst-content h1').each(function(i, el) {
|
||||
var text = $(el).text()
|
||||
@@ -191,4 +200,4 @@ For more info on this config file, check out the [docs](https://www.appveyor.com
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# As written, this configuration will build your wheels on every
|
||||
# commit, but will only push to PyPI on tagged commits.
|
||||
|
||||
language: python
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# perform a linux build
|
||||
- services: docker
|
||||
# and a mac build
|
||||
- os: osx
|
||||
language: shell
|
||||
# and a windows build
|
||||
- os: windows
|
||||
language: shell
|
||||
before_install:
|
||||
- choco install python --version 3.8.0
|
||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
||||
|
||||
env:
|
||||
global:
|
||||
- TWINE_USERNAME=joerick
|
||||
# Note: TWINE_PASSWORD is set in Travis settings
|
||||
|
||||
install:
|
||||
- python -m pip install twine cibuildwheel==1.0.0
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
- python -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
after_success:
|
||||
# if the release was tagged, upload them to PyPI
|
||||
- if [[ $TRAVIS_TAG ]]; then python -m twine upload wheelhouse/*.whl; fi
|
||||
@@ -0,0 +1,77 @@
|
||||
# In this configuration, the package is tested against multiple versions of python
|
||||
# on Linux and on one version of Python on Windows. If and only if all tests pass
|
||||
# will the wheels be built and deployed. Further, deployment is only initiated if
|
||||
# the current branch is "master", the current commit is tagged, and the current
|
||||
# repo is yours (e.g. it won't run on a Pull Request). For convenience, a source
|
||||
# distribution is also created.
|
||||
|
||||
language: python
|
||||
python:
|
||||
- 3.5
|
||||
- 3.6
|
||||
- 3.7
|
||||
- 3.8
|
||||
|
||||
before_install:
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" = windows ]]; then
|
||||
choco install python --version 3.8.0
|
||||
export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
||||
fi
|
||||
|
||||
install:
|
||||
- python -m pip install pytest
|
||||
|
||||
script:
|
||||
- python setup.py install
|
||||
- pytest
|
||||
|
||||
stages:
|
||||
- test
|
||||
# Only execute deployment stage on master branch, tagged commits,
|
||||
# and from your repository (e.g. not PRs). Replace with your repo name.
|
||||
- name: deploy
|
||||
if: branch = master AND tag IS PRESENT AND repo = joerick/cibuildwheel
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# Optional: run a test on Windows
|
||||
- os: windows
|
||||
language: shell
|
||||
name: Test on Windows
|
||||
|
||||
# Deploy source distribution
|
||||
- stage: deploy
|
||||
name: Deploy source distribution
|
||||
install: skip
|
||||
script: python setup.py sdist --formats=gztar
|
||||
after_success: python -m twine upload --skip-existing dist/*.tar.gz
|
||||
# Deploy on linux
|
||||
- stage: deploy
|
||||
name: Build and deploy Linux wheels
|
||||
services: docker
|
||||
install: python -m pip install twine cibuildwheel==1.0.0
|
||||
script: python -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: python -m twine upload --skip-existing wheelhouse/*.whl
|
||||
# Deploy on mac
|
||||
- stage: deploy
|
||||
name: Build and deploy macOS wheels
|
||||
os: osx
|
||||
language: shell
|
||||
install: python -m pip install twine cibuildwheel==1.0.0
|
||||
script: python -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: python -m twine upload --skip-existing wheelhouse/*.whl
|
||||
# Deploy on windows
|
||||
- stage: deploy
|
||||
name: Build and deploy Windows wheels
|
||||
os: windows
|
||||
language: shell
|
||||
install: python -m pip install twine cibuildwheel==1.0.0
|
||||
script: python -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: python -m twine upload --skip-existing wheelhouse/*.whl
|
||||
|
||||
env:
|
||||
global:
|
||||
- TWINE_USERNAME=joerick
|
||||
# Note: TWINE_PASSWORD is set in Travis settings
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 1.0.0
|
||||
current_version = 1.1.0
|
||||
commit = True
|
||||
tag = True
|
||||
message = Bump version
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import os, io
|
||||
|
||||
try:
|
||||
from setuptools import setup
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
|
||||
this_directory = os.path.dirname(__file__)
|
||||
with io.open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
|
||||
long_description = f.read()
|
||||
|
||||
setup(
|
||||
name='cibuildwheel',
|
||||
version='1.0.0',
|
||||
version='1.1.0',
|
||||
install_requires=['bashlex!=0.13'],
|
||||
description="Build Python wheels on CI with minimal configuration.",
|
||||
long_description='For readme please see http://github.com/joerick/cibuildwheel',
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/markdown',
|
||||
author="Joe Rickerby",
|
||||
author_email='joerick@mac.com',
|
||||
url='https://github.com/joerick/cibuildwheel',
|
||||
@@ -29,7 +35,7 @@ setup(
|
||||
'Natural Language :: English',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Development Status :: 4 - Beta',
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Topic :: Software Development :: Build Tools',
|
||||
|
||||
@@ -6,11 +6,10 @@ project_dir = os.path.dirname(__file__)
|
||||
|
||||
def test():
|
||||
# build the wheels
|
||||
utils.cibuildwheel_run(project_dir)
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ def test():
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
# build and test the wheels
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_TEST_REQUIRES': 'nose',
|
||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||
# mac/linux.
|
||||
@@ -16,7 +16,6 @@ def test():
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@@ -24,7 +23,7 @@ def test_extras_require():
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
# build and test the wheels
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_TEST_EXTRAS': 'test',
|
||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||
# mac/linux.
|
||||
@@ -34,22 +33,19 @@ def test_extras_require():
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_failing_test():
|
||||
def test_failing_test(tmp_path):
|
||||
'''Ensure a failing test causes cibuildwheel to error out and exit'''
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
utils.cibuildwheel_run(project_dir, output_dir=tmp_path, add_env={
|
||||
'CIBW_TEST_COMMAND': 'false',
|
||||
# manylinux1 has a version of bash that's been shown to have
|
||||
# manylinux1 has a version of bash that's been shown to have
|
||||
# problems with this, so let's check that.
|
||||
'CIBW_MANYLINUX_I686_IMAGE': 'manylinux1',
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': 'manylinux1',
|
||||
})
|
||||
|
||||
assert len(os.listdir('wheelhouse'))
|
||||
|
||||
assert len(os.listdir(str(tmp_path))) == 0
|
||||
|
||||
@@ -5,14 +5,13 @@ def test():
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
# build the wheels
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
# write python version information to a temporary file, this is
|
||||
# checked in setup.py
|
||||
'CIBW_BEFORE_BUILD': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonexecutable.txt', 'w').write(sys.executable)"''',
|
||||
'CIBW_BEFORE_BUILD_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonexecutable.txt', 'w').write(sys.executable)"''',
|
||||
})
|
||||
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -5,7 +5,7 @@ def test():
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
# build the wheels
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_BUILD': 'cp3?-*',
|
||||
'CIBW_SKIP': 'cp37-*',
|
||||
})
|
||||
@@ -13,5 +13,4 @@ def test():
|
||||
# check that we got the right wheels. There should be no 2.7 or 3.7.
|
||||
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if ('-cp3' in w) and ('-cp37' not in w)]
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -7,12 +7,11 @@ def test():
|
||||
# write some information into the CIBW_ENVIRONMENT, for expansion and
|
||||
# insertion into the environment by cibuildwheel. This is checked
|
||||
# in setup.py
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_ENVIRONMENT': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path''',
|
||||
'CIBW_ENVIRONMENT_WINDOWS': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''',
|
||||
})
|
||||
|
||||
# also check that we got the right wheels built
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -7,7 +7,7 @@ def test():
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('the test is only relevant to the linux build')
|
||||
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': 'dockcross/manylinux2010-x64',
|
||||
'CIBW_MANYLINUX_I686_IMAGE': 'dockcross/manylinux1-x86',
|
||||
'CIBW_BEFORE_BUILD': '/opt/python/cp36-cp36m/bin/pip install -U auditwheel', # Currently necessary on dockcross images to get auditwheel 2.1 supporting AUDITWHEEL_PLAT
|
||||
@@ -17,5 +17,4 @@ def test():
|
||||
# also check that we got the right wheels built
|
||||
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if '-manylinux2010_i686' not in w]
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import os, pytest
|
||||
import utils
|
||||
|
||||
def test():
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('the docker test is only relevant to the linux build')
|
||||
|
||||
# build the wheels
|
||||
# CFLAGS environment veriable is ecessary to fail on 'malloc_info' (on manylinux1) during compilation/linking,
|
||||
# rather than when dynamically loading the Python
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_ENVIRONMENT': 'CFLAGS="$CFLAGS -Werror=implicit-function-declaration"',
|
||||
})
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if not '-manylinux' in w or '-manylinux2010' in w]
|
||||
actual_wheels = os.listdir('wheelhouse')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
@@ -0,0 +1,27 @@
|
||||
import os, pytest
|
||||
import utils
|
||||
|
||||
|
||||
@pytest.mark.parametrize('manylinux_image', ['manylinux1', 'manylinux2010', 'manylinux2014'])
|
||||
def test(manylinux_image):
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('the docker test is only relevant to the linux build')
|
||||
|
||||
# build the wheels
|
||||
# CFLAGS environment variable is necessary to fail on 'malloc_info' (on manylinux1) during compilation/linking,
|
||||
# rather than when dynamically loading the Python
|
||||
add_env = {
|
||||
'CIBW_ENVIRONMENT': 'CFLAGS="$CFLAGS -Werror=implicit-function-declaration"',
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': manylinux_image,
|
||||
'CIBW_MANYLINUX_I686_IMAGE': manylinux_image,
|
||||
}
|
||||
if manylinux_image == 'manylinux2014':
|
||||
add_env['CIBW_SKIP'] = 'cp27*' # not available on manylinux2014
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
||||
|
||||
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0', manylinux_versions=[manylinux_image])]
|
||||
if manylinux_image == 'manylinux2014':
|
||||
expected_wheels = [w for w in expected_wheels if '-cp27' not in w]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <Python.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#if !defined(__GLIBC_PREREQ)
|
||||
#error "Must run on a glibc linux environment"
|
||||
#endif
|
||||
|
||||
#if !__GLIBC_PREREQ(2, 5) /* manylinux1 is glibc 2.5 */
|
||||
#error "Must run on a glibc >= 2.5 linux environment"
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *command;
|
||||
int sts = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
|
||||
#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 17) /* manylinux2014 is glibc 2.17 */
|
||||
// secure_getenv is only available in manylinux2014, ensuring
|
||||
// that only a manylinux2014 wheel is produced
|
||||
sts = (int)secure_getenv("NON_EXISTING_ENV_VARIABLE");
|
||||
#elif defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) /* manylinux2010 is glibc 2.12 */
|
||||
// malloc_info is only available on manylinux2010+
|
||||
sts = malloc_info(0, stdout);
|
||||
#endif
|
||||
if (sts == 0) {
|
||||
sts = system(command);
|
||||
}
|
||||
return PyLong_FromLong(sts);
|
||||
}
|
||||
|
||||
/* Module initialization */
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
static struct PyModuleDef moduledef = { \
|
||||
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
|
||||
m = PyModule_Create(&moduledef);
|
||||
#define MOD_RETURN(m) return m;
|
||||
#else
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
m = Py_InitModule3(name, methods, doc);
|
||||
#define MOD_RETURN(m) return;
|
||||
#endif
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"system", (PyCFunction)spam_system, METH_VARARGS,
|
||||
"Execute a shell command."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
MOD_INIT(spam)
|
||||
{
|
||||
PyObject* m;
|
||||
|
||||
MOD_DEF(m,
|
||||
"spam",
|
||||
"Example module",
|
||||
module_methods,
|
||||
-1)
|
||||
|
||||
MOD_RETURN(m)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import os
|
||||
import utils
|
||||
|
||||
|
||||
project_dir = os.path.dirname(__file__)
|
||||
|
||||
def test():
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
@@ -0,0 +1,6 @@
|
||||
[metadata]
|
||||
name = spam
|
||||
version = attr: spam.__version__
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
@@ -0,0 +1,8 @@
|
||||
import os
|
||||
|
||||
from setuptools import setup, Extension
|
||||
|
||||
|
||||
setup(
|
||||
ext_modules=[Extension('spam.spam', sources=['spam/spam.c'])],
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
__version__ = "0.1.0"
|
||||
@@ -1,23 +1,14 @@
|
||||
#include <Python.h>
|
||||
#if defined(__linux__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *command;
|
||||
int sts = 0;
|
||||
int sts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
|
||||
#if defined(__linux__)
|
||||
sts = malloc_info(0, stdout);
|
||||
#endif
|
||||
if (sts == 0) {
|
||||
sts = system(command);
|
||||
}
|
||||
sts = system(command);
|
||||
return PyLong_FromLong(sts);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'shared'))
|
||||
+62
-55
@@ -4,12 +4,26 @@ Utility functions used by the cibuildwheel tests.
|
||||
This file is added to the PYTHONPATH in the test runner at bin/run_test.py.
|
||||
'''
|
||||
|
||||
import subprocess, sys, os
|
||||
import subprocess, sys, os, shutil
|
||||
from tempfile import mkdtemp
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
IS_WINDOWS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache')
|
||||
IS_WINDOWS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows'
|
||||
|
||||
|
||||
# Python 2 does not have a tempfile.TemporaryDirectory context manager
|
||||
@contextmanager
|
||||
def TemporaryDirectoryIfNone(path):
|
||||
_path = path or mkdtemp()
|
||||
try:
|
||||
yield _path
|
||||
finally:
|
||||
if path is None:
|
||||
shutil.rmtree(_path)
|
||||
|
||||
|
||||
def cibuildwheel_get_build_identifiers(project_path, env=None):
|
||||
'''
|
||||
Returns the list of build identifiers that cibuildwheel will try to build
|
||||
@@ -24,12 +38,18 @@ def cibuildwheel_get_build_identifiers(project_path, env=None):
|
||||
return cmd_output.strip().split('\n')
|
||||
|
||||
|
||||
def cibuildwheel_run(project_path, env=None, add_env=None):
|
||||
def cibuildwheel_run(project_path, env=None, add_env=None, output_dir=None):
|
||||
'''
|
||||
Runs cibuildwheel as a subprocess, building the project at project_path.
|
||||
|
||||
Uses the current Python interpreter.
|
||||
Configure settings using env.
|
||||
|
||||
:param project_path: path of the project to be built.
|
||||
:param env: full environment to be used, os.environ if None
|
||||
:param add_env: environment used to update env
|
||||
:param output_dir: directory where wheels are saved. If None, a temporary
|
||||
directory will be used for the duration of the command.
|
||||
:return: list of built wheels (file names).
|
||||
'''
|
||||
if env is None:
|
||||
env = os.environ.copy()
|
||||
@@ -37,73 +57,60 @@ def cibuildwheel_run(project_path, env=None, add_env=None):
|
||||
if add_env is not None:
|
||||
env.update(add_env)
|
||||
|
||||
subprocess.check_call(
|
||||
[sys.executable, '-m', 'cibuildwheel', project_path],
|
||||
env=env,
|
||||
)
|
||||
with TemporaryDirectoryIfNone(output_dir) as _output_dir:
|
||||
subprocess.check_call(
|
||||
[sys.executable, '-m', 'cibuildwheel', '--output-dir', str(_output_dir), project_path],
|
||||
env=env,
|
||||
)
|
||||
wheels = os.listdir(_output_dir)
|
||||
return wheels
|
||||
|
||||
|
||||
def expected_wheels(package_name, package_version):
|
||||
def expected_wheels(package_name, package_version, manylinux_versions=['manylinux1', 'manylinux2010']):
|
||||
'''
|
||||
Returns a list of expected wheels from a run of cibuildwheel.
|
||||
'''
|
||||
# per PEP 425 (https://www.python.org/dev/peps/pep-0425/), wheel files shall have name of the form
|
||||
# {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
|
||||
# {python tag} and {abi tag} are closely related to the python interpreter used to build the wheel
|
||||
# so we'll merge them below as python_abi_tag
|
||||
python_abi_tags = ['cp27-cp27m', 'cp35-cp35m', 'cp36-cp36m', 'cp37-cp37m', 'cp38-cp38']
|
||||
if platform == 'linux':
|
||||
templates = [
|
||||
'{package_name}-{package_version}-cp27-cp27m-manylinux1_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27mu-manylinux1_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-manylinux1_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-manylinux1_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-manylinux1_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-manylinux1_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27m-manylinux2010_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27mu-manylinux2010_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-manylinux2010_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-manylinux2010_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-manylinux2010_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-manylinux2010_x86_64.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27m-manylinux1_i686.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27mu-manylinux1_i686.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-manylinux1_i686.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-manylinux1_i686.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-manylinux1_i686.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-manylinux1_i686.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27m-manylinux2010_i686.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27mu-manylinux2010_i686.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-manylinux2010_i686.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-manylinux2010_i686.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-manylinux2010_i686.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-manylinux2010_i686.whl',
|
||||
]
|
||||
python_abi_tags.append('cp27-cp27mu') # python 2.7 has 2 different ABI on manylinux
|
||||
platform_tags = []
|
||||
for architecture in ['x86_64', 'i686']:
|
||||
for manylinux_version in manylinux_versions:
|
||||
platform_tags.append('{manylinux_version}_{architecture}'.format(
|
||||
manylinux_version=manylinux_version, architecture=architecture
|
||||
))
|
||||
def get_platform_tags(python_abi_tag):
|
||||
return platform_tags
|
||||
elif platform == 'windows':
|
||||
templates = [
|
||||
'{package_name}-{package_version}-cp27-cp27m-win32.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-win32.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-win32.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-win32.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-win32.whl',
|
||||
'{package_name}-{package_version}-cp27-cp27m-win_amd64.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-win_amd64.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-win_amd64.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-win_amd64.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-win_amd64.whl',
|
||||
]
|
||||
def get_platform_tags(python_abi_tag):
|
||||
return ['win32', 'win_amd64']
|
||||
elif platform == 'macos':
|
||||
templates = [
|
||||
'{package_name}-{package_version}-cp27-cp27m-macosx_10_6_intel.whl',
|
||||
'{package_name}-{package_version}-cp35-cp35m-macosx_10_6_intel.whl',
|
||||
'{package_name}-{package_version}-cp36-cp36m-macosx_10_6_intel.whl',
|
||||
'{package_name}-{package_version}-cp37-cp37m-macosx_10_6_intel.whl',
|
||||
'{package_name}-{package_version}-cp38-cp38-macosx_10_9_x86_64.whl',
|
||||
]
|
||||
def get_platform_tags(python_abi_tag):
|
||||
if python_abi_tag == 'cp38-cp38':
|
||||
return ['macosx_10_9_x86_64']
|
||||
else:
|
||||
return ['macosx_10_6_intel']
|
||||
else:
|
||||
raise Exception('unsupported platform')
|
||||
|
||||
templates = []
|
||||
for python_abi_tag in python_abi_tags:
|
||||
for platform_tag in get_platform_tags(python_abi_tag):
|
||||
templates.append('{package_name}-{package_version}-{python_abi_tag}-{platform_tag}.whl'.format(
|
||||
package_name=package_name, package_version=package_version,
|
||||
python_abi_tag=python_abi_tag, platform_tag=platform_tag
|
||||
))
|
||||
|
||||
if IS_WINDOWS_RUNNING_ON_TRAVIS:
|
||||
# Python 2.7 isn't supported on Travis.
|
||||
templates = [t for t in templates if '-cp27-' not in t]
|
||||
|
||||
return [filename.format(package_name=package_name, package_version=package_version)
|
||||
for filename in templates]
|
||||
return templates
|
||||
|
||||
|
||||
platform = None
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from cibuildwheel.__main__ import main
|
||||
from cibuildwheel import windows, linux, macos
|
||||
|
||||
|
||||
def not_call_mock(*args, **kwargs):
|
||||
raise RuntimeError("This should never be called")
|
||||
|
||||
|
||||
def apply_mock_protection(monkeypatch):
|
||||
monkeypatch.setattr(subprocess, "Popen", not_call_mock)
|
||||
monkeypatch.setattr(windows, "urlopen", not_call_mock)
|
||||
monkeypatch.setattr(windows, "build", not_call_mock)
|
||||
monkeypatch.setattr(linux, "build", not_call_mock)
|
||||
monkeypatch.setattr(macos, "build", not_call_mock)
|
||||
|
||||
|
||||
def test_unknown_platform_non_ci(monkeypatch, capsys, tmp_path):
|
||||
monkeypatch.setattr(os, 'environ', {})
|
||||
monkeypatch.setattr(sys, "argv", ["python", str(tmp_path)])
|
||||
apply_mock_protection(monkeypatch)
|
||||
with pytest.raises(SystemExit) as exit:
|
||||
main()
|
||||
assert exit.value.code == 2
|
||||
_, err = capsys.readouterr()
|
||||
assert 'cibuildwheel: Unable to detect platform.' in err
|
||||
assert "cibuildwheel should run on your CI server" in err
|
||||
|
||||
|
||||
def test_unknown_platform_on_ci(monkeypatch, capsys, tmp_path):
|
||||
monkeypatch.setattr(os, 'environ', {"CI": "true"})
|
||||
monkeypatch.setattr(sys, "argv", ["python", str(tmp_path)])
|
||||
apply_mock_protection(monkeypatch)
|
||||
monkeypatch.setattr(sys, "platform", "Something")
|
||||
|
||||
with pytest.raises(SystemExit) as exit:
|
||||
main()
|
||||
_, err = capsys.readouterr()
|
||||
assert exit.value.code == 2
|
||||
assert 'cibuildwheel: Unable to detect platform from "sys.platform"' in err
|
||||
|
||||
|
||||
def test_unknown_platform(monkeypatch, capsys, tmp_path):
|
||||
monkeypatch.setattr(os, 'environ', {"CIBW_PLATFORM": "Something"})
|
||||
monkeypatch.setattr(sys, "argv", ["python", str(tmp_path)])
|
||||
apply_mock_protection(monkeypatch)
|
||||
with open(str(tmp_path / "setup.py"), "w") as f:
|
||||
f.write('from setuptools import setup\nsetup(name="spam", version="0.1.0",)')
|
||||
|
||||
with pytest.raises(SystemExit) as exit:
|
||||
main()
|
||||
_, err = capsys.readouterr()
|
||||
assert exit.value.code == 2
|
||||
assert 'cibuildwheel: Unsupported platform: Something' in err
|
||||
Reference in New Issue
Block a user