diff --git a/.travis.yml b/.travis.yml index a38e2362..8ddfbf0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ matrix: # Linux Python 3 - sudo: required language: python - python: 3.4 + python: 3.5 services: docker env: PYTHON=python @@ -23,9 +23,15 @@ matrix: # macOS Python 3 - os: osx env: PYTHON=python3 + + - os: windows + language: shell before_install: - - brew update - - brew outdated python || brew upgrade python + - choco install python3 --version 3.6.8 --no-progress -y + install: + - C:\\Python36\\python -m pip install -r requirements-dev.txt + script: + - C:\\Python36\\python ./bin/run_tests.py install: $PYTHON -m pip install -r requirements-dev.txt diff --git a/README.md b/README.md index cec3816e..4b31c086 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,15 @@ Python wheels are great. Building them across **Mac, Linux, Windows**, on **mult What does it do? ---------------- -| | macOS 10.6+ | manylinux i686 | manylinux x86_64 | Windows 32bit | Windows 64bit | -|---|---|---|---|---|---| -| Python 2.7 | ✅ | ✅ | ✅ | ✅ | ✅ | -| Python 3.4 | ✅ | ✅ | ✅ | ✅* | ✅* | -| Python 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ | -| Python 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | -| Python 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | +| | macOS 10.6+ intel | macOS 10.9+ x86_64 | manylinux i686 | manylinux x86_64 | Windows 32bit | Windows 64bit | +|---|---|---|---|---|---|---| +| Python 2.7 | ✅ | | ✅ | ✅ | ✅¹ | ✅¹ | +| Python 3.5 | ✅ | | ✅ | ✅ | ✅ | ✅ | +| Python 3.6 | ✅ | | ✅ | ✅ | ✅ | ✅ | +| Python 3.7 | ✅ | | ✅ | ✅ | ✅ | ✅ | +| Python 3.8 | | ✅ | ✅ | ✅ | ✅ | ✅ | -> \* Not supported on Azure Pipelines +> ¹ Not supported on Travis - Builds manylinux, macOS and Windows (32 and 64bit) wheels using Azure Pipelines, Travis CI, AppVeyor, and CircleCI - Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate) @@ -29,12 +29,12 @@ What does it do? Usage ----- -`cibuildwheel` currently works **Travis CI** and **CircleCI** to build Linux and Mac wheels, and **AppVeyor** to build Windows wheels. **Azure Pipelines** supports all three. +`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. | | Linux | macOS | Windows | |-----------------|-------|-------|---------| | Azure Pipelines | ✅ | ✅ | ✅ | -| Travis CI | ✅ | ✅ | | +| Travis CI | ✅ | ✅ | ✅ | | AppVeyor | | | ✅ | | CircleCI | ✅ | ✅ | | @@ -56,7 +56,7 @@ Usage jobs: - job: linux pool: {vmImage: 'Ubuntu-16.04'} - steps: + steps: - task: UsePythonVersion@0 - bash: | python -m pip install --upgrade pip @@ -66,7 +66,7 @@ jobs: inputs: {pathtoPublish: 'wheelhouse'} - job: macos pool: {vmImage: 'macOS-10.13'} - steps: + steps: - task: UsePythonVersion@0 - bash: | python -m pip install --upgrade pip @@ -76,15 +76,8 @@ jobs: inputs: {pathtoPublish: 'wheelhouse'} - job: windows pool: {vmImage: 'vs2017-win2016'} - steps: - - {task: UsePythonVersion@0, inputs: {versionSpec: '2.7', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '2.7', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.5', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.5', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.6', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.6', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.7', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.7', architecture: x64}} + steps: + - task: UsePythonVersion@0 - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | @@ -101,13 +94,14 @@ jobs: Travis CI + - To build Linux and Mac wheels on Travis CI, create a `.travis.yml` file in your repo. - ``` + ```yaml language: python - + matrix: include: - sudo: required @@ -123,6 +117,18 @@ jobs: - cibuildwheel --output-dir wheelhouse ``` + To build on Windows too, add this matrix entry: + ```yaml + - os: windows + language: shell + before_install: + - choco install python3 --version 3.6.8 --no-progress -y + env: + - PATH=/c/Python36:/c/Python36/Scripts:$PATH + ``` + + Note that building Windows Python 2.7 wheels on Travis is unsupported. + Then setup a deployment method by following the [Travis CI deployment docs](https://docs.travis-ci.com/user/deployment/), or see [Delivering to PyPI](#delivering-to-pypi) below. @@ -132,7 +138,7 @@ jobs: - + - To build Linux and Mac wheels on CircleCI, create a `.circleci/config.yml` file in your repo, ``` @@ -198,14 +204,14 @@ jobs: - path: "wheelhouse\\*.whl" name: Wheels ``` - + AppVeyor will store the built wheels for you - you can access them from the project console. Alternatively, you may want to store them in the same place as the Travis CI build. See [AppVeyor deployment docs](https://www.appveyor.com/docs/deployment/) for more info, or see [Delivering to PyPI](#delivering-to-pypi) below. - + - Commit those files, enable building of your repo on Travis CI and AppVeyor, and push. -All being well, you should get wheels delivered to you in a few minutes. +All being well, you should get wheels delivered to you in a few minutes. > ⚠️ Got an error? Check the [checklist](#it-didnt-work) below. @@ -221,8 +227,8 @@ All being well, you should get wheels delivered to you in a few minutes. | **Build parameters** | `CIBW_BUILD_VERBOSITY` | Increase or decrease the output of `pip wheel` | | **Build environment** | `CIBW_ENVIRONMENT` | Set environment variables needed during the build | | | `CIBW_BEFORE_BUILD` | Execute a shell command preparing each wheel's build | -| | `CIBW_MANYLINUX1_X86_64_IMAGE` | Specify an alternative manylinx1 x86_64 docker image | -| | `CIBW_MANYLINUX1_I686_IMAGE` | Specify an alternative manylinux1 i686 docker image | +| | `CIBW_MANYLINUX_X86_64_IMAGE` | Specify an alternative manylinux x86_64 docker image | +| | `CIBW_MANYLINUX_I686_IMAGE` | Specify an alternative manylinux i686 docker image | | **Tests** | `CIBW_TEST_COMMAND` | Execute a shell command to test all built wheels | | | `CIBW_TEST_REQUIRES` | Install Python dependencies before running the tests | | | `CIBW_TEST_EXTRAS` | Install Python dependencies before running the tests using ``extras_require``| @@ -231,10 +237,10 @@ A more detailed description of the options, the allowed values, and some example ### Linux builds on Docker -Linux wheels are built in the [`manylinux1` docker images](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 513](https://www.python.org/dev/peps/pep-0513/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account: +Linux wheels are built in the [`manylinux` docker images](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 571](https://www.python.org/dev/peps/pep-0571/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account: - Programs and libraries cannot be installed on the Travis CI Ubuntu host with `apt-get`, but can be installed inside of the Docker image using `yum` or manually. The same goes for environment variables that are potentially needed to customize the wheel building. `cibuildwheel` supports this by providing the `CIBW_ENVIRONMENT` and `CIBW_BEFORE_BUILD` options to setup the build environment inside the running Docker image. See [below](#options) for details on these options. - The project directory is mounted in the running Docker instance as `/project`, the output directory for the wheels as `/output`. In general, this is handled transparently by `cibuildwheel`. For a more finegrained level of control however, the root of the host file system is mounted as `/host`, allowing for example to access shared files, caches, etc. on the host file system. Note that this is not available on CircleCI due to their Docker policies. -- Alternative dockers images can be specified with the `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [below](#options) for more details. +- Alternative dockers images can be specified with the `CIBW_MANYLINUX_X86_64_IMAGE` and `CIBW_MANYLINUX_I686_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [below](#options) for more details. Options @@ -244,7 +250,7 @@ Options 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: @@ -291,27 +297,30 @@ For `linux` you need Docker running, on Mac or Linux. For `macos`, you need a Ma Optional. -Space-separated list of builds to build and skip. Each build has an identifier like `cp27-manylinux1_x86_64` or `cp34-macosx_10_6_intel` - you can list specific ones to build and `cibuildwheel` will only build those, and/or list ones to skip and `cibuildwheel` won't try to build them. +Space-separated list of builds to build and skip. Each build has an identifier like `cp27-manylinux_x86_64` or `cp35-macosx_10_6_intel` - you can list specific ones to build and `cibuildwheel` will only build those, and/or list ones to skip and `cibuildwheel` won't try to build them. When both options are specified, both conditions are applied and only builds with a tag that matches `CIBW_BUILD` and does not match `CIBW_SKIP` will be built. -The format is `python_tag-platform_tag`. The tags are as defined in [PEP 0425](https://www.python.org/dev/peps/pep-0425/#details). +The format is `python_tag-platform_tag`. The tags are similar but not identical to the ones defined in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details). -Python tags look like `cp27` `cp34` `cp35` `cp36` `cp37` +Python tags look like `cp27` `cp35` `cp36` `cp37` `cp38` -Platform tags look like `macosx_10_6_intel` `manylinux1_x86_64` `manylinux1_i686` `win32` `win_amd64` +Platform tags look like `macosx_10_6_intel` `macosx_10_9_x86_64` `manylinux_x86_64` `manylinux_i686` `win32` `win_amd64` -You can also use shell-style globbing syntax (as per `fnmatch`) +You can also use shell-style globbing syntax (as per `fnmatch`). + +The list of supported and currently selected build identifiers can be retrieved by passing the `--print-build-identifiers` flag to `cibuildwheel`. Examples: - Only build on Python 3.6: `CIBW_BUILD`:`cp36-*` - Skip building on Python 2.7 on the Mac: `CIBW_SKIP`:`cp27-macosx_10_6_intel` +- Skip building on Python 3.8 on the Mac: `CIBW_SKIP`:`cp38-macosx_10_9_x86_64` - Skip building on Python 2.7 on all platforms: `CIBW_SKIP`:`cp27-*` - Skip Python 2.7 on Windows: `CIBW_SKIP`:`cp27-win*` - Skip Python 2.7 on 32-bit Windows: `CIBW_SKIP`:`cp27-win32` -- Skip Python 3.4 and Python 3.5: `CIBW_SKIP`:`cp34-* cp35-*` +- Skip Python 2.7 and Python 3.5: `CIBW_SKIP`:`cp27-* cp35-*` - Skip Python 3.6 on Linux: `CIBW_SKIP`:`cp36-manylinux*` -- Only build on Python 3 and skip 32-bit builds: `CIBW_BUILD`:`cp3?-*` and `CIBW_SKIP`:`*-win32 *-manylinux1_i686` +- Only build on Python 3 and skip 32-bit builds: `CIBW_BUILD`:`cp3?-*` and `CIBW_SKIP`:`*-win32 *-manylinux_i686` *** @@ -338,10 +347,10 @@ 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. -Example: `CFLAGS="-g -Wall" CXXFLAGS="-Wall"` -Example: `PATH=$PATH:/usr/local/bin` -Example: `BUILD_TIME="$(date)"` -Example: `PIP_EXTRA_INDEX_URL="https://pypi.myorg.com/simple"` +Example: `CFLAGS="-g -Wall" CXXFLAGS="-Wall"`\ +Example: `PATH=$PATH:/usr/local/bin`\ +Example: `BUILD_TIME="$(date)"`\ +Example: `PIP_EXTRA_INDEX_URL="https://pypi.myorg.com/simple"`\ Platform-specific variants also available: `CIBW_ENVIRONMENT_MACOS` | `CIBW_ENVIRONMENT_WINDOWS` | `CIBW_ENVIRONMENT_LINUX` @@ -361,25 +370,30 @@ If dependencies are required to build your wheel (for example if you include a h 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. -Example: `pip install .` -Example: `pip install pybind11` +Example: `pip install .`\ +Example: `pip install pybind11`\ Example: `yum install -y libffi-dev && pip install .` -Platform-specific variants also available: +Platform-specific variants also available:\ `CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX` *** -| Environment variables: `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` +| Environment variables: `CIBW_MANYLINUX_X86_64_IMAGE` and `CIBW_MANYLINUX_I686_IMAGE` | --- Optional. -An alternative docker image to be used for building [`manylinux1`](https://github.com/pypa/manylinux) wheels. `cibuildwheel` will then pull these instead of the official images, [`quay.io/pypa/manylinux1_x86_64`](https://quay.io/pypa/manylinux1_i686) and [`quay.io/pypa/manylinux1_i686`](https://quay.io/pypa/manylinux1_i686). +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). -Beware to specify a valid docker image that can be used the same 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-compatible in order to produce valid `manylinux1` wheels (see https://github.com/pypa/manylinux and [PEP 513](https://www.python.org/dev/peps/pep-0513/) for more details). +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. -Example: `dockcross/manylinux-x64` +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). + +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)"`). + +Example: `manylinux1`\ +Example: `dockcross/manylinux-x64`\ Example: `dockcross/manylinux-x86` *** @@ -391,7 +405,7 @@ Optional. 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 Mac, the command runs in a shell, so you can write things like `cmd1 && cmd2`. Example: `nosetests {project}/tests` @@ -407,7 +421,7 @@ Optional. Space-separated list of dependencies required for running the tests. -Example: `pytest` +Example: `pytest`\ Example: `nose==1.3.7 moto==0.4.31` Platform-specific variants also available: @@ -458,13 +472,13 @@ After you've built your wheels, you'll probably want to deliver them to PyPI. On your development machine, do the following... ```bash -# Clear out your 'dist' folder. +# Clear out your 'dist' folder. rm -rf dist # Make a source distribution python setup.py sdist # 🏃🏻 -# Go and download your wheel files from wherever you put them. Put +# Go and download your wheel files from wherever you put them. Put # them all into the 'dist' folder. # Upload using 'twine' (you may need to 'pip install twine') @@ -496,7 +510,7 @@ If your wheel didn't compile, check the list below for some debugging tips. Working examples ---------------- -Here are some repos that use cibuildwheel. +Here are some repos that use cibuildwheel. - [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext) - [websockets](https://github.com/aaugustin/websockets) @@ -514,7 +528,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` runs the wheel through 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. @@ -546,7 +560,7 @@ _26 May 2019_ - ✨ Add support for building on Azure pipelines! This lets you build all Linux, Mac and Windows wheels on one service, so it promises to be the - easiest to set up! Check out the quickstart in the docs, or + easiest to set up! Check out the quickstart in the docs, or [cibuildwheel-azure-example](https://github.com/joerick/cibuildwheel-azure-example) for an example project. (#126, #132) - 🛠 Internal change - the end-to-end test projects format was updated, so we @@ -686,7 +700,7 @@ _11 June 2017_ _13 April 2017_ -- ✨ Added `CIBW_SKIP` option, letting users explicitly skip a build +- ✨ Added `CIBW_SKIP` option, letting users explicitly skip a build - ✨ Added `CIBW_BEFORE_BUILD` option, letting users run a shell command before the build starts ### 0.1.3 @@ -728,7 +742,7 @@ Maintainers Credits ------- -`cibuildwheel` stands on the shoulders of giants. +`cibuildwheel` stands on the shoulders of giants. - ⭐️ @matthew-brett for [matthew-brett/multibuild](http://github.com/matthew-brett/multibuild) and [matthew-brett/delocate](http://github.com/matthew-brett/delocate) - @PyPA for the manylinux Docker images [pypa/manylinux](https://github.com/pypa/manylinux) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5a9e501c..6d67dfbb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ jobs: - job: linux - pool: {vmImage: 'Ubuntu-16.04'} - steps: + pool: {vmImage: 'Ubuntu-18.04'} + steps: - task: UsePythonVersion@0 - bash: | python -m pip install -r requirements-dev.txt @@ -9,7 +9,7 @@ jobs: - job: macos pool: {vmImage: 'macOS-10.13'} - steps: + steps: - task: UsePythonVersion@0 - bash: | python -m pip install -r requirements-dev.txt @@ -17,15 +17,8 @@ jobs: - job: windows pool: {vmImage: 'vs2017-win2016'} - steps: - - {task: UsePythonVersion@0, inputs: {versionSpec: '2.7', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '2.7', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.5', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.5', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.6', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.6', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.7', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.7', architecture: x64}} + steps: + - task: UsePythonVersion@0 - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 516f0d69..67d90827 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -54,6 +54,8 @@ def main(): args = parser.parse_args() + detect_obsolete_options() + if args.platform != 'auto': platform = args.platform else: @@ -63,6 +65,8 @@ def main(): 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: @@ -141,11 +145,17 @@ def main(): ) if platform == 'linux': - manylinux1_x86_64_image = os.environ.get('CIBW_MANYLINUX1_X86_64_IMAGE', None) - manylinux1_i686_image = os.environ.get('CIBW_MANYLINUX1_I686_IMAGE', None) + manylinux_x86_64_image = os.environ.get('CIBW_MANYLINUX_X86_64_IMAGE', 'manylinux2010') + 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'} + default_manylinux_images_i686 = {'manylinux1': 'quay.io/pypa/manylinux1_i686', + 'manylinux2010': 'quay.io/pypa/manylinux2010_i686'} build_options.update( - manylinux1_images={'x86_64': manylinux1_x86_64_image, 'i686': manylinux1_i686_image}, + manylinux_images={'x86_64': default_manylinux_images_x86_64.get(manylinux_x86_64_image) or manylinux_x86_64_image, + 'i686': default_manylinux_images_i686.get(manylinux_i686_image) or manylinux_i686_image}, ) elif platform == 'macos': pass @@ -170,6 +180,26 @@ def main(): raise Exception('Unsupported platform') +def detect_obsolete_options(): + # Check the old 'MANYLINUX1_*_IMAGE' options + for (deprecated, alternative) in [('CIBW_MANYLINUX1_X86_64_IMAGE', 'CIBW_MANYLINUX_X86_64_IMAGE'), + ('CIBW_MANYLINUX1_I686_IMAGE', 'CIBW_MANYLINUX_I686_IMAGE')]: + if deprecated in os.environ: + print("'{}' has been deprecated, and will be removed in a future release. Use the option '{}' instead.".format(deprecated, alternative)) + if alternative not in os.environ: + print("Using value of option '{}' as replacement for '{}'".format(deprecated, alternative)) + os.environ[alternative] = os.environ[deprecated] + else: + print("Option '{}' is not empty. Please unset '{}'".format(alternative, deprecated)) + exit(2) + + # Check for 'manylinux1' in the 'CIBW_BUILD' and 'CIBW_SKIP' options + for deprecated in ['CIBW_BUILD', 'CIBW_SKIP']: + if deprecated in os.environ and 'manylinux1' in os.environ[deprecated]: + print("Build identifiers with 'manylinux1' been deprecated. Replacing all occurences of 'manylinux1' by 'manylinux' in the option '{}'".format(deprecated)) + os.environ[deprecated] = os.environ[deprecated].replace('manylinux1', 'manylinux') + + def print_preamble(platform, build_options): print(textwrap.dedent(''' _ _ _ _ _ _ _ diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 2ca2b8df..1ac2e67e 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -12,25 +12,25 @@ except ImportError: def get_python_configurations(build_selector): PythonConfiguration = namedtuple('PythonConfiguration', ['identifier', 'path']) python_configurations = [ - PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27m'), - PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27mu'), - PythonConfiguration(identifier='cp34-manylinux1_x86_64', path='/opt/python/cp34-cp34m'), - PythonConfiguration(identifier='cp35-manylinux1_x86_64', path='/opt/python/cp35-cp35m'), - PythonConfiguration(identifier='cp36-manylinux1_x86_64', path='/opt/python/cp36-cp36m'), - PythonConfiguration(identifier='cp37-manylinux1_x86_64', path='/opt/python/cp37-cp37m'), - PythonConfiguration(identifier='cp27-manylinux1_i686', path='/opt/python/cp27-cp27m'), - PythonConfiguration(identifier='cp27-manylinux1_i686', path='/opt/python/cp27-cp27mu'), - PythonConfiguration(identifier='cp34-manylinux1_i686', path='/opt/python/cp34-cp34m'), - PythonConfiguration(identifier='cp35-manylinux1_i686', path='/opt/python/cp35-cp35m'), - PythonConfiguration(identifier='cp36-manylinux1_i686', path='/opt/python/cp36-cp36m'), - PythonConfiguration(identifier='cp37-manylinux1_i686', path='/opt/python/cp37-cp37m'), + PythonConfiguration(identifier='cp27-manylinux_x86_64', path='/opt/python/cp27-cp27m'), + PythonConfiguration(identifier='cp27-manylinux_x86_64', path='/opt/python/cp27-cp27mu'), + PythonConfiguration(identifier='cp35-manylinux_x86_64', path='/opt/python/cp35-cp35m'), + PythonConfiguration(identifier='cp36-manylinux_x86_64', path='/opt/python/cp36-cp36m'), + PythonConfiguration(identifier='cp37-manylinux_x86_64', path='/opt/python/cp37-cp37m'), + PythonConfiguration(identifier='cp38-manylinux_x86_64', path='/opt/python/cp38-cp38'), + PythonConfiguration(identifier='cp27-manylinux_i686', path='/opt/python/cp27-cp27m'), + PythonConfiguration(identifier='cp27-manylinux_i686', path='/opt/python/cp27-cp27mu'), + PythonConfiguration(identifier='cp35-manylinux_i686', path='/opt/python/cp35-cp35m'), + PythonConfiguration(identifier='cp36-manylinux_i686', path='/opt/python/cp36-cp36m'), + PythonConfiguration(identifier='cp37-manylinux_i686', path='/opt/python/cp37-cp37m'), + PythonConfiguration(identifier='cp38-manylinux_i686', path='/opt/python/cp38-cp38'), ] # skip builds as required 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, manylinux1_images): +def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment, manylinux_images): try: subprocess.check_call(['docker', '--version']) except: @@ -42,8 +42,8 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef python_configurations = get_python_configurations(build_selector) platforms = [ - ('manylinux1_x86_64', manylinux1_images.get('x86_64') or 'quay.io/pypa/manylinux1_x86_64'), - ('manylinux1_i686', manylinux1_images.get('i686') or 'quay.io/pypa/manylinux1_i686'), + ('manylinux_x86_64', manylinux_images['x86_64']), + ('manylinux_i686', manylinux_images['i686']), ] for platform_tag, docker_image in platforms: @@ -62,9 +62,9 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef for PYBIN in {pybin_paths}; do # Setup rm -rf /tmp/built_wheel - rm -rf /tmp/delocated_wheel + rm -rf /tmp/delocated_wheels mkdir /tmp/built_wheel - mkdir /tmp/delocated_wheel + mkdir /tmp/delocated_wheels if [ ! -z {before_build} ]; then PATH="$PYBIN:$PATH" sh -c {before_build} @@ -79,11 +79,11 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef # the first element if [[ "$built_wheel" == *none-any.whl ]]; then # pure python wheel - just copy - mv "$built_wheel" /tmp/delocated_wheel + mv "$built_wheel" /tmp/delocated_wheels else - auditwheel repair "$built_wheel" -w /tmp/delocated_wheel + auditwheel repair "$built_wheel" -w /tmp/delocated_wheels fi - delocated_wheel=(/tmp/delocated_wheel/*.whl) + delocated_wheels=(/tmp/delocated_wheels/*.whl) if [ ! -z {test_command} ]; then # Set up a virtual environment to install and test from, to make sure @@ -100,7 +100,12 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef echo "Running tests using `which python`" # Install the wheel we just built - pip install "$delocated_wheel"{test_extras} + # Note: If auditwheel produced two wheels, it's because the earlier produced wheel + # conforms to multiple manylinux standards. These multiple versions of the wheel are + # 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} # Install any requirements to run the tests if [ ! -z "{test_requires}" ]; then @@ -122,8 +127,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_wheel" /output - chown {uid}:{gid} "/output/$(basename "$delocated_wheel")" + mv "${{delocated_wheels[@]}}" /output + for delocated_wheel in "${{delocated_wheels[@]}}"; do chown {uid}:{gid} "/output/$(basename "$delocated_wheel")"; done done '''.format( pybin_paths=' '.join(c.path+'/bin' for c in platform_configs), diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 2709cc1a..25bf78a7 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -14,11 +14,11 @@ from .util import prepare_command, get_build_verbosity_extra_flags def get_python_configurations(build_selector): PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url']) python_configurations = [ - PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.16/python-2.7.16-macosx10.6.pkg'), - PythonConfiguration(version='3.4', identifier='cp34-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.4.4/python-3.4.4-macosx10.6.pkg'), + PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.17/python-2.7.17-macosx10.6.pkg'), PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'), PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.6.pkg'), - PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.7.4/python-3.7.4-macosx10.6.pkg'), + PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.7.5/python-3.7.5-macosx10.6.pkg'), + PythonConfiguration(version='3.8', identifier='cp38-macosx_10_9_x86_64', url='https://www.python.org/ftp/python/3.8.0/python-3.8.0-macosx10.9.pkg'), ] # skip builds as required @@ -58,7 +58,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef # install call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/']) # patch open ssl - if config.version in ('3.4', '3.5'): + if config.version == '3.5': call(['curl', '-fsSLo', '/tmp/python-patch.tar.gz', 'https://github.com/mayeut/patch-macos-python-openssl/releases/download/v1.0.2t/patch-macos-python-%s-openssl-v1.0.2t.tar.gz' % config.version]) call(['sudo', 'tar', '-C', '/Library/Frameworks/Python.framework/Versions/%s/' % config.version, '-xmf', '/tmp/python-patch.tar.gz']) @@ -152,7 +152,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef # and not the repo code) test_command_prepared = prepare_command(test_command, project=abs_project_dir) call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True) - + # clean up shutil.rmtree(venv_dir) diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index a25dab69..d37d7509 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -1,67 +1,78 @@ from __future__ import print_function -import os, tempfile, subprocess, shutil +import os, tempfile, subprocess, shutil, sys from collections import namedtuple from glob import glob +try: + from shlex import quote as shlex_quote +except ImportError: + from pipes import quote as shlex_quote + +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + from .util import prepare_command, get_build_verbosity_extra_flags IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache') +IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows' + def get_python_path(config): - if IS_RUNNING_ON_AZURE: - # We can't hard-code the paths because on Azure, we don't know which - # bugfix release of Python we are getting so we need to check which - # ones exist. We just use the first one that is found since there should - # only be one. - path_pattern = 'C:\\hostedtoolcache\\windows\\Python\\{version}\\{arch}'.format( - version=config.version.replace('x', '*'), - arch='x86' if config.arch == '32' else 'x64' - ) - try: - return glob(path_pattern)[0] - except IndexError: - raise Exception('Could not find a Python install at ' + path_pattern) - else: - # Assume we're running on AppVeyor - major, minor = config.version.split('.')[:2] - return 'C:\\Python{major}{minor}{arch}'.format( - major=major, - minor=minor, - arch = '-x64' if config.arch == '64' else '' - ) + nuget_args = get_nuget_args(config) + return os.path.join(nuget_args[-1], nuget_args[0] + "." + config.version, "tools") +def get_nuget_args(configuration): + python_name = "python" if configuration.version[0] == '3' else "python2" + if configuration.arch == "32": + python_name = python_name + "x86" + return [python_name, "-Version", configuration.version, "-OutputDirectory", "C:/python"] + def get_python_configurations(build_selector): - PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier', 'path']) + PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier']) python_configurations = [ - PythonConfiguration(version='2.7.x', arch="32", identifier='cp27-win32', path='C:\Python27'), - PythonConfiguration(version='2.7.x', arch="64", identifier='cp27-win_amd64', path='C:\Python27-x64'), - PythonConfiguration(version='3.4.x', arch="32", identifier='cp34-win32', path='C:\Python34'), - PythonConfiguration(version='3.4.x', arch="64", identifier='cp34-win_amd64', path='C:\Python34-x64'), - PythonConfiguration(version='3.5.x', arch="32", identifier='cp35-win32', path='C:\Python35'), - PythonConfiguration(version='3.5.x', arch="64", identifier='cp35-win_amd64', path='C:\Python35-x64'), - PythonConfiguration(version='3.6.x', arch="32", identifier='cp36-win32', path='C:\Python36'), - PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\Python36-x64'), - PythonConfiguration(version='3.7.x', arch="32", identifier='cp37-win32', path='C:\Python37'), - PythonConfiguration(version='3.7.x', arch="64", identifier='cp37-win_amd64', path='C:\Python37-x64'), + PythonConfiguration(version='2.7.17', arch="32", identifier='cp27-win32'), + PythonConfiguration(version='2.7.17', arch="64", identifier='cp27-win_amd64'), + PythonConfiguration(version='3.5.4', arch="32", identifier='cp35-win32'), + PythonConfiguration(version='3.5.4', arch="64", identifier='cp35-win_amd64'), + PythonConfiguration(version='3.6.8', arch="32", identifier='cp36-win32'), + PythonConfiguration(version='3.6.8', arch="64", identifier='cp36-win_amd64'), + PythonConfiguration(version='3.7.5', arch="32", identifier='cp37-win32'), + PythonConfiguration(version='3.7.5', arch="64", identifier='cp37-win_amd64'), + PythonConfiguration(version='3.8.0', arch="32", identifier='cp38-win32'), + PythonConfiguration(version='3.8.0', arch="64", identifier='cp38-win_amd64'), ] - if IS_RUNNING_ON_AZURE: - # Python 3.4 isn't supported on Azure. - # See https://github.com/Microsoft/azure-pipelines-tasks/issues/9674 - python_configurations = [c for c in python_configurations if c.version != '3.4.x'] + if IS_RUNNING_ON_TRAVIS: + # cannot install VCForPython27.msi which is needed for compiling C software + # try with (and similar): msiexec /i VCForPython27.msi ALLUSERS=1 ACCEPT=YES /passive + python_configurations = [c for c in python_configurations if not c.version.startswith('2.7.')] + + # skip builds as required + python_configurations = [c for c in python_configurations if build_selector(c.identifier)] + + return python_configurations - # skip builds as required - 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): - if IS_RUNNING_ON_AZURE: - def shell(args, env=None, cwd=None): - print('+ ' + ' '.join(args)) - args = ['cmd', '/E:ON', '/V:ON', '/C'] + args - return subprocess.check_call(' '.join(args), env=env, cwd=cwd) + def simple_shell(args, env=None, cwd=None): + print('+ ' + ' '.join(args)) + args = ['cmd', '/E:ON', '/V:ON', '/C'] + args + return subprocess.check_call(' '.join(args), env=env, cwd=cwd) + def download(url, dest): + print('+ Download ' + url + ' to ' + dest) + response = urlopen(url) + try: + with open(dest, 'wb') as file: + file.write(response.read()) + finally: + response.close() + if IS_RUNNING_ON_AZURE or IS_RUNNING_ON_TRAVIS: + shell = simple_shell else: run_with_env = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources', 'appveyor_run_with_env.cmd')) @@ -77,10 +88,19 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef temp_dir = tempfile.mkdtemp(prefix='cibuildwheel') built_wheel_dir = os.path.join(temp_dir, 'built_wheel') - python_configurations = get_python_configurations(build_selector) + # install nuget as best way to provide python + nuget = 'C:\\nuget.exe' + download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget) + # get pip fo this installation which not have. + get_pip_script = 'C:\\get-pip.py' + download('https://bootstrap.pypa.io/get-pip.py', get_pip_script) + python_configurations = get_python_configurations(build_selector) for config in python_configurations: 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')) @@ -107,8 +127,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env) # prepare the Python environment - shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], - env=env) + shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], env=env) shell(['pip', 'install', '--upgrade', 'setuptools'], env=env) shell(['pip', 'install', 'wheel'], env=env) diff --git a/test/01_basic/cibuildwheel_test.py b/test/01_basic/cibuildwheel_test.py index 93c67829..998b55de 100644 --- a/test/01_basic/cibuildwheel_test.py +++ b/test/01_basic/cibuildwheel_test.py @@ -17,6 +17,10 @@ def test(): def test_build_identifiers(): # check that the number of expected wheels matches the number of build # identifiers - expected_wheels = utils.expected_wheels('spam', '0.1.0') + # after adding CIBW_MANYLINUX_IMAGE to support manylinux2010, there + # can be multiple wheels for each wheel, though, so we need to limit + # the expected wheels + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if not '-manylinux' in w or '-manylinux1' in w] build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir) assert len(expected_wheels) == len(build_identifiers) diff --git a/test/02_test/cibuildwheel_test.py b/test/02_test/cibuildwheel_test.py index 54973573..99324e87 100644 --- a/test/02_test/cibuildwheel_test.py +++ b/test/02_test/cibuildwheel_test.py @@ -1,4 +1,5 @@ -import os +import os, subprocess +import pytest import utils def test(): @@ -35,3 +36,16 @@ def test_extras_require(): 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(): + '''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={ + 'CIBW_TEST_COMMAND': 'false', + }) + + assert len(os.listdir('wheelhouse')) + diff --git a/test/04_build_skip/cibuildwheel_test.py b/test/04_build_skip/cibuildwheel_test.py index 98333fd2..764874a2 100644 --- a/test/04_build_skip/cibuildwheel_test.py +++ b/test/04_build_skip/cibuildwheel_test.py @@ -7,11 +7,11 @@ def test(): # build the wheels utils.cibuildwheel_run(project_dir, add_env={ 'CIBW_BUILD': 'cp3?-*', - 'CIBW_SKIP': 'cp34-*', + 'CIBW_SKIP': 'cp37-*', }) - # check that we got the right wheels. There should be no 2.7 or 3.4. + # 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 ('-cp34' not in w)] + if ('-cp3' in w) and ('-cp37' not in w)] actual_wheels = os.listdir('wheelhouse') assert set(actual_wheels) == set(expected_wheels) diff --git a/test/06_docker_images/cibuildwheel_test.py b/test/06_docker_images/cibuildwheel_test.py index a5448485..9067bc0f 100644 --- a/test/06_docker_images/cibuildwheel_test.py +++ b/test/06_docker_images/cibuildwheel_test.py @@ -5,14 +5,17 @@ def test(): project_dir = os.path.dirname(__file__) if utils.platform != 'linux': - pytest.skip('the docker test is only relevant to the linux build') + pytest.skip('the test is only relevant to the linux build') utils.cibuildwheel_run(project_dir, add_env={ - 'CIBW_MANYLINUX1_X86_64_IMAGE': 'dockcross/manylinux-x64', - 'CIBW_MANYLINUX1_I686_IMAGE': 'dockcross/manylinux-x86', + '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 + 'CIBW_ENVIRONMENT': 'AUDITWHEEL_PLAT=`if [ $(uname -i) == "x86_64" ]; then echo "manylinux2010_x86_64"; else echo "manylinux1_i686"; fi`', }) # also check that we got the right wheels built - expected_wheels = utils.expected_wheels('spam', '0.1.0') + 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) diff --git a/test/08_manylinux2010_only/cibuildwheel_test.py b/test/08_manylinux2010_only/cibuildwheel_test.py new file mode 100644 index 00000000..dab763e7 --- /dev/null +++ b/test/08_manylinux2010_only/cibuildwheel_test.py @@ -0,0 +1,21 @@ +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) diff --git a/test/08_manylinux2010_only/setup.py b/test/08_manylinux2010_only/setup.py new file mode 100644 index 00000000..866fa22c --- /dev/null +++ b/test/08_manylinux2010_only/setup.py @@ -0,0 +1,7 @@ +from setuptools import setup, Extension + +setup( + name="spam", + ext_modules=[Extension('spam', sources=['spam.c'])], + version="0.1.0", +) diff --git a/test/08_manylinux2010_only/spam.c b/test/08_manylinux2010_only/spam.c new file mode 100644 index 00000000..0e50eba9 --- /dev/null +++ b/test/08_manylinux2010_only/spam.c @@ -0,0 +1,57 @@ +#include +#if defined(__linux__) +#include +#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(__linux__) + 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) +} diff --git a/test/shared/utils.py b/test/shared/utils.py index 0284dd4a..d4e9c9c6 100644 --- a/test/shared/utils.py +++ b/test/shared/utils.py @@ -6,7 +6,8 @@ This file is added to the PYTHONPATH in the test runner at bin/run_test.py. import subprocess, sys, os -IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache') +IS_WINDOWS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache') +IS_WINDOWS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows' def cibuildwheel_get_build_identifiers(project_path, env=None): @@ -25,14 +26,14 @@ def cibuildwheel_get_build_identifiers(project_path, env=None): def cibuildwheel_run(project_path, env=None, add_env=None): ''' - Runs cibuildwheel as a subprocess, building the project at project_path. - + Runs cibuildwheel as a subprocess, building the project at project_path. + Uses the current Python interpreter. Configure settings using env. ''' if env is None: env = os.environ.copy() - + if add_env is not None: env.update(add_env) @@ -50,45 +51,57 @@ def expected_wheels(package_name, package_version): 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}-cp34-cp34m-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}-cp34-cp34m-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', ] elif platform == 'windows': templates = [ '{package_name}-{package_version}-cp27-cp27m-win32.whl', - '{package_name}-{package_version}-cp34-cp34m-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}-cp34-cp34m-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', ] elif platform == 'macos': templates = [ '{package_name}-{package_version}-cp27-cp27m-macosx_10_6_intel.whl', - '{package_name}-{package_version}-cp34-cp34m-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', ] else: raise Exception('unsupported platform') - - if IS_RUNNING_ON_AZURE: - # Python 3.4 isn't supported on Azure. - templates = [t for t in templates if '-cp34-' not in t] - + + 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]