Compare commits

..
36 Commits
Author SHA1 Message Date
Joe Rickerby 7709989603 Bump version 2019-12-07 14:58:10 +00:00
Joe Rickerby 31e67c4f1f Update changelog 2019-12-07 14:58:00 +00:00
Joe Rickerby 11bde36627 Merge pull request #234 from Czaki/fix_setup_cfg
change directory to not conflict with setup.cfg of package
2019-12-07 14:35:38 +00:00
Grzegorz Bokota 5941ba7daf add tests 2019-12-05 21:13:11 +01:00
Grzegorz Bokota c1df977e11 change directory to not conflict with setup.cfg of package 2019-12-03 22:07:47 +01:00
Matthieu Darbois 1dbb12daaa Add manylinux2014 x86_64/i686 (#215) 2019-12-02 11:07:56 +01:00
Joe Rickerby a005e263fc Merge pull request #233 from Czaki/fix_doc_environment
Add example of usage more than one environment variable
2019-12-02 08:54:26 +00:00
Grzegorz Bokota 2a1081c5e5 update docs with information about more than one environment variable. 2019-12-01 21:45:08 +01:00
Joe Rickerby 9c908daf27 Merge pull request #226 from Czaki/fix_platform_bug
Add better protection to unittest to be shure that it will create no changes on developer machine
2019-11-29 09:34:52 +00:00
Joe Rickerby 054be2eff2 Merge pull request #228 from SethMMorton/update-travis-examples
Update travis examples
2019-11-28 22:45:09 +00:00
Seth Morton 20ba988b72 Add an example folder with Travis-CI examples
I have placed two example Travis-CI configurations in an examples/
folder. The first is the same as in the README, and the second shows how
to both test and deploy in two stages.

I am hoping that examples might be added for other CI providers as well,
so that users can see different approaches to building and deploying
wheels.
2019-11-25 18:59:07 -08:00
Seth Morton 190b013c61 Update Travis CI examples
For a more granular view of why each of these changes were made, please
see https://github.com/joerick/cibuildwheel-autopypi-example/pull/5.

High-level overview:
 - Adding Windows support
 - Remove "sudo: required" for linux
 - Use "python -m pip" instead of using an environment variable
 - Add "install:" and "after_success:" steps so that errors get handled
   and reported properly
 - Rename "matrix:" to "jobs:" as this is the now preferred keyword
2019-11-25 15:08:18 -08:00
Grzegorz Bokota c966c6d098 Add mock for better protection of unit tests launch.
change behavior of main function to always end with exit.
2019-11-24 12:17:08 +01:00
Grzegorz Bokota d2700bc3b4 fix UnboundLocalError instead of proper error message (#221)
* fix UnboundLocalError: local variable 'platform' referenced before assignment
* add test to protect against regression
2019-11-21 22:45:33 +01:00
Matthieu Darbois 09e72800c6 Run each test using a temporary directory (#217) 2019-11-20 22:20:53 +01:00
Joe Rickerby 2b62eef9e7 Merge pull request #211 from nsoranzo/delocate_command
Add `CIBW_REPAIR_WHEEL_COMMAND` env variable
2019-11-20 19:58:19 +00:00
Nicola Soranzo 85cba9b1eb Move Platform-specific variants before Examples 2019-11-17 19:08:22 +00:00
Nicola Soranzo 402ec9e4ac Address one more review comment 2019-11-15 02:56:30 +00:00
Nicola Soranzo e9fd9eaead Address @joerick's comments 2019-11-15 02:27:39 +00:00
Nicola Soranzo 0e04fafd3a Add CIBW_REPAIR_COMMAND env variable
to allow different options for auditwheel/delocate, alternative
commands and a future Windows equivalent.

Fix https://github.com/joerick/cibuildwheel/issues/191 .
2019-11-14 12:10:55 +00:00
Yannick Jadoul 34515b78c6 Merge pull request #209 from YannickJadoul/silence-script-not-on-path-warnings
Avoid script location warnings on Windows
2019-11-14 11:59:40 +01:00
Yannick Jadoul 7d99ccfc7b Collapse multiple 'pip install's into one in windows.py and macos.py, and replace full path by 'python' in windows.py 2019-11-12 23:47:06 +01:00
Yannick Jadoul dc01231301 Replace a few shell invocations by simple_shell in windows.py 2019-11-12 22:25:54 +01:00
Matthieu Darbois 96a2505e78 Merge pull request #207 from mayeut/doc-appveyor-linux
Update doc for AppVeyor on linux
2019-11-12 22:11:27 +01:00
Yannick Jadoul d3fd087166 Run python get-pip.py with Scripts directory in PATH to avoid warnings, and reorder steps to match macOS 2019-11-12 17:05:37 +01:00
mayeut b3f82d52cc Update doc for AppVeyor on linux 2019-11-12 01:20:06 +01:00
Matthieu Darbois 7d90a2f16b Merge pull request #204 from mayeut/appveyor-linux
Rework platform detection to ignore CI provider to determine windows/linux/macos.
A check is still present to check if CI is running or not.
2019-11-11 22:24:52 +01:00
mayeut f4318e15b7 Keep CI check for platform auto 2019-11-11 21:49:16 +01:00
mayeut d3450e84ac Rework platform detection to ignore CI provider.
CI provider is now mostly irrelevant, rework platform detection with that in mind.
Run linux test in AppVeyor
2019-11-10 23:40:20 +01:00
Joe Rickerby a3e9b7b8ec Embed readme in project for PyPI 2019-11-10 19:13:49 +00:00
Joe Rickerby 1a9c6a5f66 Add azure pipelines status badge 2019-11-10 19:02:06 +00:00
Joe Rickerby c44a084a44 Really fix link 2019-11-10 19:01:58 +00:00
Joe Rickerby 1e102b9bc5 Fix link 2019-11-10 15:54:17 +00:00
Joe Rickerby 46f1906e2d Add docs badge 2019-11-10 15:52:01 +00:00
Joe Rickerby 79c480b896 Update changelog 2019-11-10 15:47:33 +00:00
Joe Rickerby 734ca6bfbd Remove @tgarc from maintainers 2019-11-10 15:45:34 +00:00
34 changed files with 697 additions and 328 deletions
+3 -3
View File
@@ -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
+56 -23
View File
@@ -1,7 +1,7 @@
cibuildwheel
============
[![PyPI](https://img.shields.io/pypi/v/cibuildwheel.svg)](https://pypi.python.org/pypi/cibuildwheel) [![Build Status](https://travis-ci.org/joerick/cibuildwheel.svg?branch=master)](https://travis-ci.org/joerick/cibuildwheel) [![Build status](https://ci.appveyor.com/api/projects/status/wbsgxshp05tt1tif/branch/master?svg=true)](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/master) [![CircleCI](https://circleci.com/gh/joerick/cibuildwheel.svg?style=svg)](https://circleci.com/gh/joerick/cibuildwheel)
[![PyPI](https://img.shields.io/pypi/v/cibuildwheel.svg)](https://pypi.python.org/pypi/cibuildwheel) [![Documentation Status](https://readthedocs.org/projects/cibuildwheel/badge/?version=stable)](https://cibuildwheel.readthedocs.io/en/stable/?badge=stable) [![Build Status](https://travis-ci.org/joerick/cibuildwheel.svg?branch=master)](https://travis-ci.org/joerick/cibuildwheel) [![Build status](https://ci.appveyor.com/api/projects/status/wbsgxshp05tt1tif/branch/master?svg=true)](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/master) [![CircleCI](https://circleci.com/gh/joerick/cibuildwheel.svg?style=svg)](https://circleci.com/gh/joerick/cibuildwheel) [![Build Status](https://dev.azure.com/joerick0429/cibuildwheel/_apis/build/status/joerick.cibuildwheel?branchName=master)](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
View File
@@ -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
View File
@@ -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
View File
@@ -1 +1 @@
__version__ = '1.0.0'
__version__ = '1.1.0'
+39 -34
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+34
View File
@@ -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
+77
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.0.0
current_version = 1.1.0
commit = True
tag = True
message = Bump version
+9 -3
View File
@@ -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',
+1 -2
View File
@@ -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 -10
View File
@@ -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
+2 -3
View File
@@ -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)
+1 -2
View File
@@ -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)
+1 -2
View File
@@ -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)
+1 -2
View File
@@ -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)
+68
View File
@@ -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)
}
+13
View File
@@ -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)
+6
View File
@@ -0,0 +1,6 @@
[metadata]
name = spam
version = attr: spam.__version__
[options]
packages = find:
+8
View File
@@ -0,0 +1,8 @@
import os
from setuptools import setup, Extension
setup(
ext_modules=[Extension('spam.spam', sources=['spam/spam.c'])],
)
+1
View File
@@ -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);
}
+4
View File
@@ -0,0 +1,4 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), 'shared'))
+62 -55
View File
@@ -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
+59
View File
@@ -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