Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
054c273997 | ||
|
|
87a9d170b0 | ||
|
|
1d3c59d804 | ||
|
|
0b791dbea5 | ||
|
|
44256e4aa5 | ||
|
|
b579cd5f2a | ||
|
|
8523b25a18 | ||
|
|
637a251b79 | ||
|
|
a6ff864010 | ||
|
|
79f044314b | ||
|
|
0c0e21aa83 | ||
|
|
f1bba58f86 | ||
|
|
56218d896c | ||
|
|
d79ca07bbb | ||
|
|
c6f4f01732 | ||
|
|
586b3c7197 | ||
|
|
0b4475ed07 | ||
|
|
38b3b0a3da | ||
|
|
5adfce9838 | ||
|
|
bc83839387 | ||
|
|
481b1cb060 | ||
|
|
ccfc3c3aa1 | ||
|
|
3d23cbf2a6 | ||
|
|
b9a296324d | ||
|
|
c4822ebdd6 | ||
|
|
2ca6500bba | ||
|
|
8dd71189b2 | ||
|
|
a448c02d7f | ||
|
|
696866bfe1 | ||
|
|
1faa2fe5df | ||
|
|
602acebcc8 | ||
|
|
c43f1b6e3d | ||
|
|
0d3e67b1f9 | ||
|
|
e3b565320c | ||
|
|
56973d34df | ||
|
|
66e9a1cc19 | ||
|
|
2a91396064 | ||
|
|
1c98a9ed22 | ||
|
|
dbcf5ef64b | ||
|
|
cc030312a3 | ||
|
|
31c162fa59 | ||
|
|
d80636aa22 | ||
|
|
22a6f0c7a9 | ||
|
|
7362075b61 | ||
|
|
c108807e16 | ||
|
|
05a054245a | ||
|
|
a5f89fa7aa | ||
|
|
cf73851c61 | ||
|
|
9372e37b18 | ||
|
|
fbb447c3aa | ||
|
|
1e978d1b35 | ||
|
|
1dbda7af7e | ||
|
|
b64770a560 | ||
|
|
4cc09a35b4 | ||
|
|
d4885fe44a | ||
|
|
fcf1e9cd84 | ||
|
|
f417a91a57 | ||
|
|
1b9c74aabc | ||
|
|
35832c4309 | ||
|
|
c9fffab6ea | ||
|
|
9f7fdbf456 | ||
|
|
7c6b331e15 | ||
|
|
22f69e4ced | ||
|
|
4083a7600a | ||
|
|
20624e44a3 | ||
|
|
332b8ec6ac | ||
|
|
eaf59e385c | ||
|
|
57454e75b0 | ||
|
|
391c95d355 | ||
|
|
8124b14491 | ||
|
|
b3b15f8404 | ||
|
|
9a96910919 | ||
|
|
fce00dd77e | ||
|
|
6da52a544b | ||
|
|
c8037fb237 | ||
|
|
95a81f2216 | ||
|
|
56c9c9864d | ||
|
|
0789842ef0 | ||
|
|
5c47700d31 | ||
|
|
5ef7eeba4d | ||
|
|
bb554acb28 | ||
|
|
ea3c52631f | ||
|
|
b18281867b | ||
|
|
4a0d05df49 | ||
|
|
c1cd99ee4c | ||
|
|
e68400b403 | ||
|
|
2f1f34f693 | ||
|
|
3ef401b19e | ||
|
|
8800ea514b | ||
|
|
f62b9755e1 | ||
|
|
033ba29ec6 | ||
|
|
0627b38402 | ||
|
|
189dc13714 | ||
|
|
793026f3ed | ||
|
|
08b4895b9c | ||
|
|
7c635b4550 | ||
|
|
33433f0b21 | ||
|
|
e3981db2a6 | ||
|
|
1ec652dff8 | ||
|
|
d2394e9a57 | ||
|
|
0b21df216e | ||
|
|
e5b9d1f586 | ||
|
|
9b31b5e6c9 | ||
|
|
1a910257bb | ||
|
|
4f542ca3d4 | ||
|
|
57a2259a00 | ||
|
|
d186b0bbb7 | ||
|
|
57cdb8711c | ||
|
|
7448ca3cf1 | ||
|
|
d93547d8be | ||
|
|
a863e21b14 | ||
|
|
b4c0150d43 | ||
|
|
c8019dac1d | ||
|
|
e6fa70a910 | ||
|
|
b19e8b76f3 | ||
|
|
23ab1f780e | ||
|
|
eedcd62753 | ||
|
|
3a4d611da1 | ||
|
|
8877990ec6 | ||
|
|
0cc41fabba | ||
|
|
0156a9a870 | ||
|
|
460a4d9656 | ||
|
|
8d9d970874 | ||
|
|
c563bca054 | ||
|
|
b47a5c018f | ||
|
|
94e33cd7e3 | ||
|
|
c9c54602ed | ||
|
|
b74333a940 | ||
|
|
4655311a7a | ||
|
|
71503b7143 | ||
|
|
5099d60584 | ||
|
|
2ebde4c078 | ||
|
|
e33b6bed77 | ||
|
|
4d61b08fa3 | ||
|
|
5e009e53c9 | ||
|
|
783a4deec6 | ||
|
|
529e22bfe0 | ||
|
|
418cb9c39d | ||
|
|
99469087ed | ||
|
|
3b847ab0aa | ||
|
|
7f51b1d8e7 | ||
|
|
7f77aa86b1 | ||
|
|
47873a9175 | ||
|
|
c38a33381d | ||
|
|
121f7cc678 | ||
|
|
d6361c0e31 | ||
|
|
ffb48a61cb | ||
|
|
d16c63ad95 | ||
|
|
d16d81e207 | ||
|
|
e5c7bb416d | ||
|
|
a85b535d83 | ||
|
|
9013a7783f | ||
|
|
08194a1db9 | ||
|
|
a9e05a596a | ||
|
|
e40f9b2345 | ||
|
|
65dccc46b2 | ||
|
|
d247743713 | ||
|
|
4e0b3c0f31 | ||
|
|
6bbef964c9 | ||
|
|
ede818944e | ||
|
|
9c73dd2ac7 | ||
|
|
5f7c019392 | ||
|
|
cd9eeb72e5 | ||
|
|
d075c731b6 | ||
|
|
8fa41df67d | ||
|
|
0e849c2bcf | ||
|
|
212fa34d9d | ||
|
|
cb73b18bce | ||
|
|
1730d6fd0b | ||
|
|
1e9067272d | ||
|
|
b0afaf33c2 | ||
|
|
d0e5a4bb3c | ||
|
|
4dc8bf447f | ||
|
|
9a6a7d3375 | ||
|
|
719ad30d05 | ||
|
|
666c10465a |
@@ -0,0 +1,81 @@
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
osx-python2:
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
environment:
|
||||
PYTHON: python2
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Prepare the environment.
|
||||
command: |
|
||||
bash .circleci/prepare.sh
|
||||
- run:
|
||||
name: Test.
|
||||
command: |
|
||||
venv/bin/python ./bin/run_tests.py
|
||||
|
||||
osx-python3:
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
environment:
|
||||
PYTHON: python3
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Prepare the environment.
|
||||
command: |
|
||||
bash .circleci/prepare.sh
|
||||
- run:
|
||||
name: Test.
|
||||
command: |
|
||||
venv/bin/python ./bin/run_tests.py
|
||||
|
||||
linux-python2:
|
||||
docker:
|
||||
- image: circleci/python:2.7
|
||||
environment:
|
||||
PYTHON: python2
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
|
||||
- run:
|
||||
name: Prepare the environment.
|
||||
command: |
|
||||
bash .circleci/prepare.sh
|
||||
- run:
|
||||
name: Test.
|
||||
command: |
|
||||
venv/bin/python ./bin/run_tests.py
|
||||
|
||||
linux-python3:
|
||||
docker:
|
||||
- image: circleci/python:3.6
|
||||
environment:
|
||||
PYTHON: python3
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
|
||||
- run:
|
||||
name: Prepare the environment.
|
||||
command: |
|
||||
bash .circleci/prepare.sh
|
||||
- run:
|
||||
name: Test.
|
||||
command: |
|
||||
venv/bin/python ./bin/run_tests.py
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
all-tests:
|
||||
jobs:
|
||||
- osx-python2
|
||||
- osx-python3
|
||||
- linux-python2
|
||||
- linux-python3
|
||||
@@ -0,0 +1,7 @@
|
||||
$PYTHON --version
|
||||
$PYTHON -m pip --version
|
||||
$PYTHON -m pip install -q --user --ignore-installed --upgrade virtualenv
|
||||
$PYTHON -m virtualenv -p $PYTHON venv
|
||||
venv/bin/python -m pip install -r requirements-dev.txt
|
||||
venv/bin/python -m pip freeze
|
||||
venv/bin/python --version
|
||||
+12
-26
@@ -5,42 +5,28 @@ matrix:
|
||||
# Linux Python 2
|
||||
- sudo: required
|
||||
language: python
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- "PYTHON=python2"
|
||||
python: 2.7
|
||||
services: docker
|
||||
env: PYTHON=python
|
||||
|
||||
# Linux Python 3
|
||||
- sudo: required
|
||||
language: python
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- "PYTHON=python3"
|
||||
before_install:
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get install -y python3-pip
|
||||
python: 3.4
|
||||
services: docker
|
||||
env: PYTHON=python
|
||||
|
||||
# macOS Python 2
|
||||
- os: osx
|
||||
env:
|
||||
- "PYTHON=python2"
|
||||
env: PYTHON=python2
|
||||
|
||||
# macOS Python 3
|
||||
- os: osx
|
||||
env:
|
||||
- "PYTHON=python3"
|
||||
env: PYTHON=python3
|
||||
before_install:
|
||||
- brew update
|
||||
- brew install python3
|
||||
- brew outdated python || brew upgrade python
|
||||
|
||||
script:
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
$PYTHON -m pip install -r requirements-dev.txt
|
||||
$PYTHON ./bin/run_tests.py
|
||||
else
|
||||
# linux test requires root to clean up the wheelhouse (docker runs as root)
|
||||
sudo $PYTHON -m pip install -r requirements-dev.txt
|
||||
sudo $PYTHON ./bin/run_tests.py
|
||||
fi
|
||||
install: $PYTHON -m pip install -r requirements-dev.txt
|
||||
|
||||
script: $PYTHON ./bin/run_tests.py
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
cibuildwheel
|
||||
============
|
||||
|
||||
[](https://pypi.python.org/pypi/cibuildwheel) [](https://travis-ci.org/joerick/cibuildwheel) [](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/master)
|
||||
[](https://pypi.python.org/pypi/cibuildwheel) [](https://travis-ci.org/joerick/cibuildwheel) [](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/master) [](https://circleci.com/gh/joerick/cibuildwheel)
|
||||
|
||||
Python wheels are great. Building them across **Mac, Linux, Windows**, on **multiple versions of Python**, is not.
|
||||
|
||||
`cibuildwheel` is here to help. `cibuildwheel` runs on your CI server - currently it supports Travis CI and Appveyor - and it builds and tests your wheels across all of your platforms.
|
||||
`cibuildwheel` is here to help. `cibuildwheel` runs on your CI server - currently it supports Travis CI, Appveyor, and CircleCI - and it builds and tests your wheels across all of your platforms.
|
||||
|
||||
**`cibuildwheel` is in beta**. It's brand new - I'd love for you to try it and help make it better!
|
||||
|
||||
@@ -15,46 +15,98 @@ What does it do?
|
||||
| | macOS 10.6+ | manylinux i686 | manylinux x86_64 | Windows 32bit | Windows 64bit |
|
||||
|---|---|---|---|---|---|
|
||||
| Python 2.7 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.3 | | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.4 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
- Builds manylinux, macOS and Windows (32 and 64bit) wheels using Travis CI and Appveyor
|
||||
- Builds manylinux, macOS and Windows (32 and 64bit) wheels using 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)
|
||||
- Runs the library test suite against the wheel-installed version of your library
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
`cibuildwheel` currently works on **Travis CI** to build Linux and Mac wheels, and **Appveyor** to build Windows wheels.
|
||||
`cibuildwheel` currently works on **Travis CI** and **CircleCI** to build Linux and Mac wheels, and **Appveyor** to build Windows wheels.
|
||||
|
||||
`cibuildwheel` is not intended to run on your development machine. It will try to install packages globally; this is no good. Travis CI and Appveyor run their builds in isolated environments, so are ideal for this kind of script.
|
||||
`cibuildwheel` is not intended to run on your development machine. It will try to install packages globally; this is no good. Travis CI, CircleCI, and Appveyor run their builds in isolated environments, so are ideal for this kind of script.
|
||||
|
||||
### Minimal setup
|
||||
|
||||
- Create a `.travis.yml` file in your repo.
|
||||
- To build Linux and Mac wheels on Travis CI, create a `.travis.yml` file in your repo.
|
||||
|
||||
```
|
||||
language: python
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- sudo: required
|
||||
services:
|
||||
- docker
|
||||
env: PIP=pip
|
||||
- os: osx
|
||||
language: generic
|
||||
env: PIP=pip2
|
||||
|
||||
script:
|
||||
- pip install cibuildwheel==0.5.1
|
||||
- $PIP install cibuildwheel==0.10.2
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
- Create an `appveyor.yml` file in your repo.
|
||||
- To build Linux and Mac wheels on CircleCI, create a `.circleci/config.yml` file in your repo,
|
||||
|
||||
```
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
linux-wheels:
|
||||
working_directory: ~/linux-wheels
|
||||
docker:
|
||||
- image: circleci/python:3.6
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
name: Build the Linux wheels.
|
||||
command: |
|
||||
pip install --user cibuildwheel
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
|
||||
osx-wheels:
|
||||
working_directory: ~/osx-wheels
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build the OS X wheels.
|
||||
command: |
|
||||
pip install --user cibuildwheel
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
all-tests:
|
||||
jobs:
|
||||
- linux-wheels
|
||||
- osx-wheels
|
||||
```
|
||||
|
||||
Note: CircleCI doesn't enable free macOS containers for open source by default, but you can ask for access. See [here](https://circleci.com/docs/2.0/oss/#overview) for more information.
|
||||
|
||||
CircleCI will store the built wheels for you - you can access them from the project console.
|
||||
|
||||
- To build Windows wheels on Appveyor, create an `appveyor.yml` file in your repo.
|
||||
|
||||
```
|
||||
build_script:
|
||||
- pip install cibuildwheel==0.5.1
|
||||
- pip install cibuildwheel==0.10.2
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
artifacts:
|
||||
- path: "wheelhouse\\*.whl"
|
||||
@@ -76,14 +128,25 @@ All being well, you should get wheels delivered to you in a few minutes.
|
||||
| | Option | |
|
||||
|---|---|---|
|
||||
| **Target wheels** | `CIBW_PLATFORM` | Override the auto-detected target platform |
|
||||
| | `CIBW_BUILD` | Build only certain Python versions |
|
||||
| | `CIBW_SKIP` | Skip certain Python versions |
|
||||
| **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 |
|
||||
| **Tests** | `CIBW_TEST_COMMAND` | Execute a shell command to test all built wheels |
|
||||
| | `CIBW_TEST_REQUIRES` | Install Python dependencies before running the tests |
|
||||
|
||||
A more detailed description of the options, the allowed values, and some examples can be found in the [Options](#options) section.
|
||||
|
||||
### 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:
|
||||
- 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.
|
||||
|
||||
|
||||
Options
|
||||
-------
|
||||
@@ -115,7 +178,9 @@ optional arguments:
|
||||
|
||||
```
|
||||
|
||||
Most of the config is via environment variables. These go into `.travis.yml` and `appveyor.yml` nicely.
|
||||
Most of the config is via environment variables. These go into `.travis.yml`, `appveyor.yml`, and `.circleci/config.yml` nicely.
|
||||
|
||||
***
|
||||
|
||||
| Environment variable: `CIBW_PLATFORM` | Command line argument: `--platform`
|
||||
| --- | ---
|
||||
@@ -124,28 +189,52 @@ Options: `auto` `linux` `macos` `windows`
|
||||
|
||||
Default: `auto`
|
||||
|
||||
`auto` will auto-detect platform using environment variables, such as `TRAVIS_OS_NAME`/`APPVEYOR`.
|
||||
`auto` will auto-detect platform using environment variables, such as `TRAVIS_OS_NAME`/`APPVEYOR`/`CIRCLECI`.
|
||||
|
||||
For `linux` you need Docker running, on Mac or Linux. For `macos`, you need a Mac machine, and note that this 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]`.
|
||||
|
||||
| Environment variable: `CIBW_SKIP`
|
||||
***
|
||||
|
||||
| Environment variables: `CIBW_BUILD` and `CIBW_SKIP`
|
||||
| ---
|
||||
|
||||
Optional.
|
||||
|
||||
Space-separated list of builds to skip. Each build has an identifier like `cp27-manylinux1_x86_64` or `cp34-macosx_10_6_intel` - you can list ones to skip here and `cibuildwheel` won't try to build them.
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
Python tags look like `cp27` `cp34` `cp35` `cp36`
|
||||
Python tags look like `cp27` `cp34` `cp35` `cp36` `cp37`
|
||||
|
||||
Platform tags look like `macosx_10_6_intel` `manylinux1_x86_64` `manylinux1_i386` `win32` `win_amd64`
|
||||
Platform tags look like `macosx_10_6_intel` `manylinux1_x86_64` `manylinux1_i686` `win32` `win_amd64`
|
||||
|
||||
You can also use shell-style globbing syntax (as per `fnmatch`)
|
||||
|
||||
Example: `cp27-macosx_10_6_intel` (don't build on Python 2 on Mac)
|
||||
Example: `cp27-win*` (don't build on Python 2.7 on Windows)
|
||||
Example: `cp34-* cp35-*` (don't build on Python 3.4 or Python 3.5)
|
||||
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 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 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`
|
||||
|
||||
**
|
||||
|
||||
| Environment variable: `CIBW_BUILD_VERBOSITY`
|
||||
| ---
|
||||
|
||||
Optional.
|
||||
|
||||
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:
|
||||
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX`
|
||||
|
||||
***
|
||||
|
||||
| Environment variable: `CIBW_ENVIRONMENT`
|
||||
| ---
|
||||
@@ -168,6 +257,8 @@ Platform-specific variants also available:
|
||||
|
||||
In addition to the above, `cibuildwheel` always defines the environment variable `CIBUILDWHEEL=1`. This can be useful for [building wheels with optional extensions](https://github.com/joerick/cibuildwheel/wiki/Building-packages-with-optional-C-extensions).
|
||||
|
||||
***
|
||||
|
||||
| Environment variable: `CIBW_BEFORE_BUILD`
|
||||
| ---
|
||||
|
||||
@@ -175,26 +266,49 @@ Optional.
|
||||
|
||||
A shell command to run before building the wheel. This option allows you to run a command in **each** Python environment before the `pip wheel` command. This is useful if you need to set up some dependency so it's available during the build.
|
||||
|
||||
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.
|
||||
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}`. These are useful when you need to write `python3` or `pip3` on a Python 3.x build.
|
||||
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: `yum install -y libffi-dev && {pip} install .`
|
||||
Example: `pip install .`
|
||||
Example: `pip install pybind11`
|
||||
Example: `yum install -y libffi-dev && pip install .`
|
||||
|
||||
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`
|
||||
| ---
|
||||
|
||||
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).
|
||||
|
||||
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).
|
||||
|
||||
Example: `dockcross/manylinux-x64`
|
||||
Example: `dockcross/manylinux-x86`
|
||||
|
||||
***
|
||||
|
||||
| Environment variable: `CIBW_TEST_COMMAND`
|
||||
| ---
|
||||
|
||||
Optional.
|
||||
|
||||
Shell command to run tests after the build. The wheel will be installed automatically and available for import from the tests. The project root should be included in the command as "{project}".
|
||||
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`.
|
||||
|
||||
Example: `nosetests {project}/tests`
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX`
|
||||
|
||||
***
|
||||
|
||||
| Environment variable: `CIBW_TEST_REQUIRES`
|
||||
| ---
|
||||
|
||||
@@ -205,9 +319,11 @@ Space-separated list of dependencies required for running the tests.
|
||||
Example: `pytest`
|
||||
Example: `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`
|
||||
|
||||
#### Example YML syntax
|
||||
|
||||
### Example YML syntax
|
||||
|
||||
<table>
|
||||
<tr><td><i>example .travis.yml environment variables</i><pre><code>env:
|
||||
@@ -263,7 +379,7 @@ It didn't work!
|
||||
If your wheel didn't compile, check the list below for some debugging tips.
|
||||
|
||||
- A mistake in your config. To quickly test your config without doing a git push and waiting for your code to build on CI, you can run the Linux build in a Docker container. On Mac or Linux, with Docker running, try `cibuildwheel --platform linux`. You'll have to bring your config into the current environment first.
|
||||
- Missing dependency. You might need to install something on the build machine. You can do this in `.travis.yml` or `appveyor.yml`, with apt-get, brew or whatever Windows uses :P . Given how the Linux build works, we'll probably have to build something into `cibuildwheel`. Let's chat about that over in the issues!
|
||||
- Missing dependency. You might need to install something on the build machine. You can do this in `.travis.yml`, `appveyor.yml`, or `.circleci/config.yml`, with apt-get, brew or whatever Windows uses :P . Given how the Linux build works, we'll probably have to build something into `cibuildwheel`. Let's chat about that over in the issues!
|
||||
- Windows: missing C feature. The Windows C compiler doesn't support C language features invented after 1990, so you'll have to backport your C code to C90. For me, this mostly involved putting my variable declarations at the top of the function like an animal.
|
||||
|
||||
Working examples
|
||||
@@ -273,54 +389,161 @@ Here are some repos that use cibuildwheel.
|
||||
|
||||
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext)
|
||||
- [websockets](https://github.com/aaugustin/websockets)
|
||||
- [Parselmouth](https://github.com/YannickJadoul/Parselmouth)
|
||||
- [python-admesh](https://github.com/admesh/python-admesh)
|
||||
- [pybase64](https://github.com/mayeut/pybase64)
|
||||
- [KDEpy](https://github.com/tommyod/KDEpy)
|
||||
- [AutoPy](https://github.com/autopilot-rs/autopy)
|
||||
- [apriltags2-ethz](https://github.com/safijari/apriltags2_ethz)
|
||||
|
||||
> Add repo here! Send a PR.
|
||||
|
||||
Legal note
|
||||
----------
|
||||
|
||||
Since `cibuildwheel` runs the wheel through delocate or auditwheel, it will automatically bundle library dependencies. This is similar to static linking, so it might have some licence implications. Check the license for any code you're pulling in to make sure that's allowed.
|
||||
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.
|
||||
|
||||
This is similar to static linking, so it might have some licence implications. Check the license for any code you're pulling in to make sure that's allowed.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
### 0.10.1
|
||||
|
||||
_3 February 2019_
|
||||
|
||||
- 🐛 Fix build stalling on macOS (that was introduced in pip 19) (#122)
|
||||
- 🐛 Fix "AttributeError: 'Popen' object has no attribute 'args'" on Python 2.7 for Linux builds (#108)
|
||||
- 🛠 Update Python from 3.6.7, 3.7.1 to 3.6.8, 3.7.2 on macOS
|
||||
- 🛠 Update openssl patch from 1.0.2p to 1.0.2q on macOS
|
||||
- 🛠 Sorting build options dict items when printing preamble (#114)
|
||||
|
||||
### 0.10.0
|
||||
|
||||
_23 September 2018_
|
||||
|
||||
- ✨ Add `CIBW_BUILD` option, for specifying which specific builds to perform (#101)
|
||||
- ✨ Add support for building Mac and Linux on CircleCI (#91, #97)
|
||||
- 🛠 Improved support for building universal wheels (#95)
|
||||
- 🛠 Ensure log output is unbuffered and therefore in the correct order (#92)
|
||||
- 🛠 Improved error reporting for errors that occur inside a package's setup.py (#88)
|
||||
- ⚠️ Removed support for Python 3.3 on Windows.
|
||||
|
||||
### 0.9.4
|
||||
|
||||
_29 July 2018_
|
||||
|
||||
- 🛠 CIBW_TEST_COMMAND now runs in a shell on Mac (as well as Linux) (#81)
|
||||
|
||||
### 0.9.3
|
||||
|
||||
_10 July 2018_
|
||||
|
||||
- 🛠 Update to Python 3.6.6 on macOS (#82)
|
||||
- ✨ Add support for building Python 3.7 wheels on Windows (#76)
|
||||
- ⚠️ Deprecated support for Python 3.3 on Windows.
|
||||
|
||||
### 0.9.2
|
||||
|
||||
_1 July 2018_
|
||||
|
||||
- 🛠 Update Python 3.7.0rc1 to 3.7.0 on macOS (#79)
|
||||
|
||||
### 0.9.1
|
||||
|
||||
_18 June 2018_
|
||||
|
||||
- 🛠 Removed the need to use `{python}` and `{pip}` in `CIBW_BEFORE_BUILD` statements, by ensuring the correct version is always on the path at `python` and `pip` instead. (#60)
|
||||
- 🛠 We now patch the _ssl module on Python 3.4 and 3.5 so these versions can still make SSL web requests using TLS 1.2 while building. (#71)
|
||||
|
||||
### 0.9.0
|
||||
|
||||
_18 June 2018_
|
||||
|
||||
- ✨ Add support for Python 3.7 (#73)
|
||||
|
||||
### 0.8.0
|
||||
|
||||
_4 May 2018_
|
||||
|
||||
- ⚠️ Drop support for Python 3.3 on Linux (#67)
|
||||
- 🐛 Fix TLS by updating setuptools (#69)
|
||||
|
||||
### 0.7.1
|
||||
|
||||
_2 April 2017_
|
||||
|
||||
- 🐛 macOS: Fix Pip bugs resulting from PyPI TLS 1.2 enforcement
|
||||
- 🐛 macOS: Fix brew Python3 version problems in the CI
|
||||
|
||||
### 0.7.0
|
||||
|
||||
_7 January 2018_
|
||||
|
||||
- ✨ You can now specify a custom docker image using the `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` options. (#46)
|
||||
- 🐛 Fixed a bug where cibuildwheel would download and build a package from PyPI(!) instead of building the package on the local machine. (#51)
|
||||
|
||||
### 0.6.0
|
||||
|
||||
_9 October 2017_
|
||||
|
||||
- ✨ On the Linux build, the host filesystem is now accessible via `/host` (#36)
|
||||
- 🐛 Fixed a bug where setup.py scripts would run the wrong version of Python when running subprocesses on Linux (#35)
|
||||
|
||||
### 0.5.1
|
||||
|
||||
_10 September 2017_
|
||||
|
||||
- 🐛 Fixed a couple of bugs on Python 3.
|
||||
- ✨ Added experimental support for Mac builds on [Bitrise.io](https://www.bitrise.io)
|
||||
|
||||
### 0.5.0
|
||||
|
||||
- `CIBW_ENVIRONMENT` added. You can now set environment variables for each build, even within the Docker container on Linux. This is a big one! (#21)
|
||||
- `CIBW_BEFORE_BUILD` now runs in a system shell on all platforms. You can now do things like `CIBW_BEFORE_BUILD="cmd1 && cmd2"`. (#32)
|
||||
_7 September 2017_
|
||||
|
||||
- ✨ `CIBW_ENVIRONMENT` added. You can now set environment variables for each build, even within the Docker container on Linux. This is a big one! (#21)
|
||||
- ✨ `CIBW_BEFORE_BUILD` now runs in a system shell on all platforms. You can now do things like `CIBW_BEFORE_BUILD="cmd1 && cmd2"`. (#32)
|
||||
|
||||
### 0.4.1
|
||||
|
||||
- Fixed a bug on Windows where subprocess' output was hidden (#23)
|
||||
- Fixed a bug on Appveyor where logs would appear in the wrong order due to output buffering (#24, thanks @YannickJadoul!)
|
||||
_14 August 2017_
|
||||
|
||||
- 🐛 Fixed a bug on Windows where subprocess' output was hidden (#23)
|
||||
- 🐛 Fixed a bug on Appveyor where logs would appear in the wrong order due to output buffering (#24, thanks @YannickJadoul!)
|
||||
|
||||
### 0.4.0
|
||||
|
||||
- Fixed a bug that was increasing the build time by building the wheel twice. This was a problem for large projects that have a long build time. If you're upgrading and you need the old behaviour, use `CIBW_BEFORE_BUILD={pip} install .`, or install exactly the dependencies you need in `CIBW_BEFORE_BUILD`. See #18.
|
||||
_23 July 2017_
|
||||
|
||||
- 🐛 Fixed a bug that was increasing the build time by building the wheel twice. This was a problem for large projects that have a long build time. If you're upgrading and you need the old behaviour, use `CIBW_BEFORE_BUILD={pip} install .`, or install exactly the dependencies you need in `CIBW_BEFORE_BUILD`. See #18.
|
||||
|
||||
### 0.3.0
|
||||
|
||||
- Removed Python 2.6 support on Linux (#12)
|
||||
_27 June 2017_
|
||||
|
||||
- ⚠️ Removed Python 2.6 support on Linux (#12)
|
||||
|
||||
### 0.2.1
|
||||
|
||||
11 June 2017
|
||||
_11 June 2017_
|
||||
|
||||
- Changed the build process to install the package before building the wheel - this allows direct dependencies to be installed first (#9, thanks @tgarc!)
|
||||
- Added Python 3 support for the main process, for systems where Python 3 is the default (#8, thanks @tgarc).
|
||||
- 🛠 Changed the build process to install the package before building the wheel - this allows direct dependencies to be installed first (#9, thanks @tgarc!)
|
||||
- ✨ Added Python 3 support for the main process, for systems where Python 3 is the default (#8, thanks @tgarc).
|
||||
|
||||
### 0.2.0
|
||||
|
||||
13 April 2017
|
||||
_13 April 2017_
|
||||
|
||||
- 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
|
||||
- ✨ 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
|
||||
|
||||
31 March 2017
|
||||
_31 March 2017_
|
||||
|
||||
- First public release!
|
||||
- 🌟 First public release!
|
||||
|
||||
Contributing
|
||||
============
|
||||
@@ -350,18 +573,26 @@ 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)
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
`cibuildwheel` stands on the shoulders of giants. Massive props to-
|
||||
`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)
|
||||
- @ogrisel for [wheelhouse-uploader](https://github.com/ogrisel/wheelhouse-uploader) and `run_with_env.cmd`
|
||||
|
||||
Massive props also to-
|
||||
|
||||
- @zfrenchee for [help debugging many issues](https://github.com/joerick/cibuildwheel/issues/2)
|
||||
- @lelit for some great bug reports and [contributions](https://github.com/joerick/cibuildwheel/pull/73)
|
||||
- @mayeut for a [phenomenal PR](https://github.com/joerick/cibuildwheel/pull/71) patching Python itself for better compatibility!
|
||||
|
||||
See also
|
||||
--------
|
||||
|
||||
If you'd like to keep wheel building separate from the package itself, check out [astrofrog/autowheel](https://github.com/astrofrog/autowheel). It builds packages using cibuildwheel from source distributions on PyPI.
|
||||
|
||||
If `cibuildwheel` is too limited for your needs, consider [matthew-brett/multibuild](http://github.com/matthew-brett/multibuild). `multibuild` is a toolbox for building a wheel on various platforms. It can do a lot more than this project - it's used to build SciPy!
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ def single_run(test_project):
|
||||
print('%s built successfully. %i wheels built.' % (test_project, len(wheels)))
|
||||
|
||||
# check some wheels were actually built
|
||||
assert len(wheels) >= 4
|
||||
assert len(wheels) >= 3
|
||||
|
||||
# clean up
|
||||
shutil.rmtree('wheelhouse')
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = '0.5.1'
|
||||
__version__ = '0.10.2'
|
||||
|
||||
+64
-31
@@ -4,9 +4,9 @@ import argparse, os, subprocess, sys, textwrap
|
||||
import cibuildwheel
|
||||
import cibuildwheel.linux, cibuildwheel.windows, cibuildwheel.macos
|
||||
from cibuildwheel.environment import parse_environment, EnvironmentParseError
|
||||
from cibuildwheel.util import BuildSkipper
|
||||
from cibuildwheel.util import BuildSelector, Unbuffered
|
||||
|
||||
def get_option_from_environment(option_name, platform=None):
|
||||
def get_option_from_environment(option_name, platform=None, default=None):
|
||||
'''
|
||||
Returns an option from the environment, optionally scoped by the platform.
|
||||
|
||||
@@ -21,7 +21,7 @@ def get_option_from_environment(option_name, platform=None):
|
||||
if option is not None:
|
||||
return option
|
||||
|
||||
return os.environ.get(option_name)
|
||||
return os.environ.get(option_name, default)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -53,6 +53,8 @@ def main():
|
||||
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':
|
||||
@@ -61,21 +63,33 @@ def main():
|
||||
platform = 'windows'
|
||||
elif 'BITRISE_BUILD_NUMBER' in os.environ:
|
||||
platform = 'macos'
|
||||
else:
|
||||
elif os.environ.get('CIRCLECI'):
|
||||
if sys.platform.startswith('linux'):
|
||||
platform = 'linux'
|
||||
elif sys.platform.startswith('darwin'):
|
||||
platform = 'macos'
|
||||
|
||||
if platform is None:
|
||||
print('cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server, '
|
||||
'Travis CI and Appveyor are supported. You can run on your development '
|
||||
'Travis CI, Appveyor, and CircleCI are supported. You can run on your development '
|
||||
'machine using the --platform argument. Check --help output for more '
|
||||
'information.',
|
||||
file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
output_dir = args.output_dir
|
||||
test_command = os.environ.get('CIBW_TEST_COMMAND', None)
|
||||
test_requires = os.environ.get('CIBW_TEST_REQUIRES', '').split()
|
||||
test_command = get_option_from_environment('CIBW_TEST_COMMAND', platform=platform)
|
||||
test_requires = get_option_from_environment('CIBW_TEST_REQUIRES', platform=platform, default='').split()
|
||||
project_dir = args.project_dir
|
||||
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
|
||||
skip_config = os.environ.get('CIBW_SKIP', '')
|
||||
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform) or ''
|
||||
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', '')
|
||||
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
|
||||
|
||||
try:
|
||||
build_verbosity = min(3, max(-3, int(build_verbosity)))
|
||||
except ValueError:
|
||||
build_verbosity = 0
|
||||
|
||||
try:
|
||||
environment = parse_environment(environment_config)
|
||||
@@ -85,43 +99,42 @@ def main():
|
||||
traceback.print_exc(None, sys.stderr)
|
||||
exit(2)
|
||||
|
||||
skip = BuildSkipper(skip_config)
|
||||
build_selector = BuildSelector(build_config, skip_config)
|
||||
|
||||
# Add CIBUILDWHEEL environment variable
|
||||
# This needs to be passed on to the docker container in linux.py
|
||||
os.environ['CIBUILDWHEEL'] = '1'
|
||||
|
||||
try:
|
||||
project_setup_py = os.path.join(project_dir, 'setup.py')
|
||||
name_output = subprocess.check_output([sys.executable, project_setup_py, '--name'],
|
||||
universal_newlines=True)
|
||||
# the last line of output is the name
|
||||
package_name = name_output.strip().splitlines()[-1]
|
||||
except subprocess.CalledProcessError as err:
|
||||
if not os.path.exists(project_setup_py):
|
||||
print('cibuildwheel: Could not find setup.py at root of project', file=sys.stderr)
|
||||
exit(2)
|
||||
else:
|
||||
print('cibuildwheel: Failed to get name of the package. Command was %s' % err.cmd,
|
||||
file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
if package_name == '' or package_name == 'UNKNOWN':
|
||||
print('cibuildwheel: Invalid package name "%s". Check your setup.py' % package_name,
|
||||
file=sys.stderr)
|
||||
if not os.path.exists(os.path.join(project_dir, 'setup.py')):
|
||||
print('cibuildwheel: Could not find setup.py at root of project', file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
build_options = dict(
|
||||
project_dir=project_dir,
|
||||
package_name=package_name,
|
||||
output_dir=output_dir,
|
||||
test_command=test_command,
|
||||
test_requires=test_requires,
|
||||
before_build=before_build,
|
||||
skip=skip,
|
||||
build_verbosity=build_verbosity,
|
||||
build_selector=build_selector,
|
||||
environment=environment,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
build_options.update(
|
||||
manylinux1_images={'x86_64': manylinux1_x86_64_image, 'i686': manylinux1_i686_image},
|
||||
)
|
||||
elif platform == 'macos':
|
||||
pass
|
||||
elif platform == 'windows':
|
||||
pass
|
||||
|
||||
# Python is buffering by default when running on the CI platforms, giving problems interleaving subprocess call output with unflushed calls to 'print'
|
||||
sys.stdout = Unbuffered(sys.stdout)
|
||||
|
||||
print_preamble(platform, build_options)
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
@@ -149,10 +162,30 @@ def print_preamble(platform, build_options):
|
||||
|
||||
print('Build options:')
|
||||
print(' platform: %r' % platform)
|
||||
for option, value in build_options.items():
|
||||
for option, value in sorted(build_options.items()):
|
||||
print(' %s: %r' % (option, value))
|
||||
|
||||
warnings = detect_warnings(platform, build_options)
|
||||
if warnings:
|
||||
print('\nWarnings:')
|
||||
for warning in warnings:
|
||||
print(' ' + warning)
|
||||
|
||||
print('\nHere we go!\n')
|
||||
|
||||
def detect_warnings(platform, build_options):
|
||||
warnings = []
|
||||
|
||||
# warn about deprecated {python} and {pip}
|
||||
for option_name in ['test_command', 'before_build']:
|
||||
option_value = build_options.get(option_name)
|
||||
|
||||
if option_value:
|
||||
if '{python}' in option_value or '{pip}' in option_value:
|
||||
warnings.append(option_name + ": '{python}' and '{pip}' are no longer needed, and will be removed in a future release. Simply use 'python' or 'pip' instead.")
|
||||
|
||||
return warnings
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
+48
-33
@@ -1,7 +1,7 @@
|
||||
from __future__ import print_function
|
||||
import os, subprocess, sys
|
||||
import os, subprocess, sys, uuid
|
||||
from collections import namedtuple
|
||||
from .util import prepare_command
|
||||
from .util import prepare_command, get_build_verbosity_extra_flags
|
||||
|
||||
try:
|
||||
from shlex import quote as shlex_quote
|
||||
@@ -9,12 +9,13 @@ except ImportError:
|
||||
from pipes import quote as shlex_quote
|
||||
|
||||
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, skip, environment):
|
||||
def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment, manylinux1_images):
|
||||
try:
|
||||
subprocess.check_call(['docker', '--version'])
|
||||
except:
|
||||
print('cibuildwheel: Docker not found. Docker is required to run Linux builds. '
|
||||
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.',
|
||||
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.'
|
||||
'If you\'re building on Circle CI in Linux, add a `setup_remote_docker` step to your .circleci/config.yml',
|
||||
file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
@@ -22,24 +23,24 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
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='cp33-manylinux1_x86_64', path='/opt/python/cp33-cp33m'),
|
||||
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='cp33-manylinux1_i686', path='/opt/python/cp33-cp33m'),
|
||||
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'),
|
||||
]
|
||||
|
||||
# skip builds as required
|
||||
python_configurations = [c for c in python_configurations if not skip(c.identifier)]
|
||||
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
||||
|
||||
platforms = [
|
||||
('manylinux1_x86_64', 'quay.io/pypa/manylinux1_x86_64'),
|
||||
('manylinux1_i686', 'quay.io/pypa/manylinux1_i686'),
|
||||
('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'),
|
||||
]
|
||||
|
||||
for platform_tag, docker_image in platforms:
|
||||
@@ -50,6 +51,7 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
bash_script = '''
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
mkdir /output
|
||||
cd /project
|
||||
|
||||
{environment_exports}
|
||||
@@ -62,11 +64,11 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
mkdir /tmp/delocated_wheel
|
||||
|
||||
if [ ! -z {before_build} ]; then
|
||||
PATH=$PYBIN:$PATH sh -c {before_build}
|
||||
PATH="$PYBIN:$PATH" sh -c {before_build}
|
||||
fi
|
||||
|
||||
# Build that wheel
|
||||
"$PYBIN/pip" wheel . -w /tmp/built_wheel --no-deps
|
||||
PATH="$PYBIN:$PATH" "$PYBIN/pip" wheel . -w /tmp/built_wheel --no-deps {build_verbosity_flag}
|
||||
built_wheel=(/tmp/built_wheel/*.whl)
|
||||
|
||||
# Delocate the wheel
|
||||
@@ -91,44 +93,57 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
# Run the tests from a different directory
|
||||
if [ ! -z {test_command} ]; then
|
||||
pushd $HOME
|
||||
PATH=$PYBIN:$PATH sh -c {test_command}
|
||||
PATH="$PYBIN:$PATH" sh -c {test_command}
|
||||
popd
|
||||
fi
|
||||
|
||||
# we're all done here; move it to output
|
||||
mv "$delocated_wheel" /output
|
||||
chown {uid}:{gid} "/output/$(basename "$delocated_wheel")"
|
||||
done
|
||||
'''.format(
|
||||
package_name=package_name,
|
||||
pybin_paths=' '.join(c.path+'/bin' for c in platform_configs),
|
||||
test_requires=' '.join(test_requires),
|
||||
test_command=shlex_quote(
|
||||
test_command.format(project='/project') if test_command else ''
|
||||
prepare_command(test_command, project='/project') if test_command else ''
|
||||
),
|
||||
before_build=shlex_quote(
|
||||
prepare_command(before_build, python='python', pip='pip') if before_build else ''
|
||||
prepare_command(before_build, project='/project') if before_build else ''
|
||||
),
|
||||
build_verbosity_flag=' '.join(get_build_verbosity_extra_flags(build_verbosity)),
|
||||
environment_exports='\n'.join(environment.as_shell_commands()),
|
||||
uid=os.getuid(),
|
||||
gid=os.getgid(),
|
||||
)
|
||||
|
||||
docker_process = subprocess.Popen([
|
||||
'docker',
|
||||
'run',
|
||||
'--env',
|
||||
'CIBUILDWHEEL',
|
||||
'--rm',
|
||||
'-i',
|
||||
'-v', '%s:/project' % os.path.abspath(project_dir),
|
||||
'-v', '%s:/output' % os.path.abspath(output_dir),
|
||||
docker_image,
|
||||
'/bin/bash'],
|
||||
stdin=subprocess.PIPE, universal_newlines=True)
|
||||
def run_docker(command, stdin_str=None):
|
||||
print('docker command: docker {}'.format(' '.join(map(shlex_quote, command))))
|
||||
if stdin_str is None:
|
||||
subprocess.check_call(['docker'] + command)
|
||||
else:
|
||||
args = ['docker'] + command
|
||||
process = subprocess.Popen(args, stdin=subprocess.PIPE, universal_newlines=True)
|
||||
try:
|
||||
process.communicate(stdin_str)
|
||||
except KeyboardInterrupt:
|
||||
process.kill()
|
||||
process.wait()
|
||||
if process.returncode != 0:
|
||||
raise subprocess.CalledProcessError(process.returncode, args)
|
||||
|
||||
container_name = 'cibuildwheel-{}'.format(uuid.uuid4())
|
||||
try:
|
||||
docker_process.communicate(bash_script)
|
||||
except KeyboardInterrupt:
|
||||
docker_process.kill()
|
||||
docker_process.wait()
|
||||
|
||||
if docker_process.returncode != 0:
|
||||
run_docker(['create',
|
||||
'--env', 'CIBUILDWHEEL',
|
||||
'--name', container_name,
|
||||
'-i',
|
||||
'-v', '/:/host', # ignored on Circle
|
||||
docker_image, '/bin/bash'])
|
||||
run_docker(['cp', os.path.abspath(project_dir) + '/.', container_name + ':/project'])
|
||||
run_docker(['start', '-i', '-a', container_name], stdin_str=bash_script)
|
||||
run_docker(['cp', container_name + ':/output/.', os.path.abspath(output_dir)])
|
||||
except subprocess.CalledProcessError:
|
||||
exit(1)
|
||||
finally:
|
||||
# Still gets executed, even when 'exit(1)' gets called
|
||||
run_docker(['rm', '--force', '-v', container_name])
|
||||
|
||||
+61
-29
@@ -7,17 +7,25 @@ try:
|
||||
except ImportError:
|
||||
from pipes import quote as shlex_quote
|
||||
|
||||
from .util import prepare_command
|
||||
from .util import prepare_command, get_build_verbosity_extra_flags
|
||||
|
||||
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, skip, environment):
|
||||
def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment):
|
||||
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.13/python-2.7.13-macosx10.6.pkg'),
|
||||
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='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.3/python-3.5.3-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.0/python-3.6.0-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.2/python-3.7.2-macosx10.6.pkg'),
|
||||
]
|
||||
get_pip_url = 'https://bootstrap.pypa.io/get-pip.py'
|
||||
get_pip_script = '/tmp/get-pip.py'
|
||||
|
||||
pkgs_output = subprocess.check_output(['pkgutil', '--pkgs'])
|
||||
if sys.version_info[0] >= 3:
|
||||
pkgs_output = pkgs_output.decode('utf8')
|
||||
installed_system_packages = pkgs_output.splitlines()
|
||||
|
||||
def call(args, env=None, cwd=None, shell=False):
|
||||
# print the command executing for the logs
|
||||
@@ -28,35 +36,59 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
|
||||
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])
|
||||
|
||||
for config in python_configurations:
|
||||
if skip(config.identifier):
|
||||
if not build_selector(config.identifier):
|
||||
print('cibuildwheel: Skipping build %s' % config.identifier, file=sys.stderr)
|
||||
continue
|
||||
|
||||
# download the pkg
|
||||
call(['curl', '-L', '-o', '/tmp/Python.pkg', config.url])
|
||||
# install
|
||||
call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/'])
|
||||
# if this version of python isn't installed, get it from python.org and install
|
||||
python_package_identifier = 'org.python.Python.PythonFramework-%s' % config.version
|
||||
if python_package_identifier not in installed_system_packages:
|
||||
# download the pkg
|
||||
call(['curl', '-L', '-o', '/tmp/Python.pkg', config.url])
|
||||
# install
|
||||
call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/'])
|
||||
# patch open ssl
|
||||
if config.version in ('3.4', '3.5'):
|
||||
call(['curl', '-fsSLo', '/tmp/python-patch.tar.gz', 'https://github.com/mayeut/patch-macos-python-openssl/releases/download/v1.0.2r/patch-macos-python-%s-openssl-v1.0.2r.tar.gz' % config.version])
|
||||
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)
|
||||
|
||||
# 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.
|
||||
if os.path.exists('/tmp/cibw_bin'):
|
||||
shutil.rmtree('/tmp/cibw_bin')
|
||||
os.makedirs('/tmp/cibw_bin')
|
||||
|
||||
if config.version[0] == '3':
|
||||
os.symlink(os.path.join(installation_bin_path, 'python3'), '/tmp/cibw_bin/python')
|
||||
os.symlink(os.path.join(installation_bin_path, 'python3-config'), '/tmp/cibw_bin/python-config')
|
||||
os.symlink(os.path.join(installation_bin_path, 'pip3'), '/tmp/cibw_bin/pip')
|
||||
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = os.pathsep.join([
|
||||
'/Library/Frameworks/Python.framework/Versions/%s/bin' % config.version,
|
||||
'/tmp/cibw_bin',
|
||||
installation_bin_path,
|
||||
env['PATH'],
|
||||
])
|
||||
env = environment.as_dictionary(prev_environment=env)
|
||||
|
||||
python = 'python3' if config.version[0] == '3' else 'python2'
|
||||
pip = 'pip3' if config.version[0] == '3' else 'pip2'
|
||||
|
||||
# check what version we're on
|
||||
call(['which', python], env=env)
|
||||
call([python, '--version'], env=env)
|
||||
call(['which', 'python'], env=env)
|
||||
call(['python', '--version'], env=env)
|
||||
|
||||
# install pip & wheel
|
||||
call([python, '-m', 'ensurepip', '--upgrade'], env=env)
|
||||
call([pip, '--version'], env=env)
|
||||
call([pip, 'install', 'wheel'], env=env)
|
||||
call([pip, 'install', 'delocate'], env=env)
|
||||
call(['python', get_pip_script, '--no-setuptools', '--no-wheel'], env=env)
|
||||
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'):
|
||||
@@ -68,11 +100,11 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
|
||||
# run the before_build command
|
||||
if before_build:
|
||||
before_build_prepared = prepare_command(before_build, python=python, pip=pip)
|
||||
before_build_prepared = prepare_command(before_build, project=abs_project_dir)
|
||||
call(before_build_prepared, env=env, shell=True)
|
||||
|
||||
# build the wheel
|
||||
call([pip, 'wheel', project_dir, '-w', '/tmp/built_wheel', '--no-deps'], env=env)
|
||||
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 built_wheel.endswith('none-any.whl'):
|
||||
@@ -86,18 +118,18 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
delocated_wheel = glob('/tmp/delocated_wheel/*.whl')[0]
|
||||
|
||||
# install the wheel
|
||||
call([pip, 'install', delocated_wheel], env=env)
|
||||
call(['pip', 'install', delocated_wheel], env=env)
|
||||
|
||||
# test the wheel
|
||||
if test_requires:
|
||||
call([pip, 'install'] + test_requires, env=env)
|
||||
call(['pip', 'install'] + test_requires, env=env)
|
||||
if test_command:
|
||||
# run the tests from $HOME, with an absolute path in the command
|
||||
# (this ensures that Python runs the tests against the installed wheel
|
||||
# and not the repo code)
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
test_command_absolute = test_command.format(project=abs_project_dir)
|
||||
call(shlex.split(test_command_absolute), cwd=os.environ['HOME'], env=env)
|
||||
test_command_prepared = prepare_command(test_command, project=abs_project_dir)
|
||||
call(test_command_prepared, cwd=os.environ['HOME'], env=env, shell=True)
|
||||
|
||||
# we're all done here; move it to output
|
||||
shutil.move(delocated_wheel, output_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)
|
||||
|
||||
+23
-12
@@ -1,27 +1,38 @@
|
||||
from fnmatch import fnmatch
|
||||
import warnings
|
||||
|
||||
|
||||
def prepare_command(command, python, pip):
|
||||
def prepare_command(command, project):
|
||||
'''
|
||||
Preprocesses a command by expanding variables like {python} or {pip}.
|
||||
Preprocesses a command by expanding variables like {project}.
|
||||
|
||||
For example, used for the before_build option, where the user would
|
||||
like to run a command like `python setup.py test`. If the command should run on
|
||||
Python 3, the user could write `{python} setup.py test`. This command would expand
|
||||
it out to python2 or python3 as appropriate.
|
||||
For example, used in the test_command option, to specify the path to the
|
||||
tests directory.
|
||||
'''
|
||||
return command.format(python=python, pip=pip)
|
||||
return command.format(python='python', pip='pip', project=project)
|
||||
|
||||
|
||||
class BuildSkipper(object):
|
||||
def __init__(self, skip_config):
|
||||
self.patterns = skip_config.split()
|
||||
def get_build_verbosity_extra_flags(level):
|
||||
if level > 0:
|
||||
return ['-' + level * 'v']
|
||||
elif level < 0:
|
||||
return ['-' + -level * 'q']
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
class BuildSelector(object):
|
||||
def __init__(self, build_config, skip_config):
|
||||
self.build_patterns = build_config.split()
|
||||
self.skip_patterns = skip_config.split()
|
||||
|
||||
def __call__(self, build_id):
|
||||
return any(fnmatch(build_id, pattern) for pattern in self.patterns)
|
||||
def match_any(patterns):
|
||||
return any(fnmatch(build_id, pattern) for pattern in patterns)
|
||||
return match_any(self.build_patterns) and not match_any(self.skip_patterns)
|
||||
|
||||
def __repr__(self):
|
||||
return 'BuildSkipper(%r)' % ' '.join(self.patterns)
|
||||
return 'BuildSelector({!r} - {!r})'.format(' '.join(self.build_patterns), ' '.join(self.skip_patterns))
|
||||
|
||||
|
||||
# Taken from https://stackoverflow.com/a/107717
|
||||
|
||||
+21
-17
@@ -7,14 +7,10 @@ except ImportError:
|
||||
from collections import namedtuple
|
||||
from glob import glob
|
||||
|
||||
from .util import prepare_command, Unbuffered
|
||||
from .util import prepare_command, get_build_verbosity_extra_flags
|
||||
|
||||
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, skip, environment):
|
||||
# Python under AppVeyor/Windows seems to be buffering by default, giving problems interleaving subprocess call output with unflushed calls to 'print'
|
||||
sys.stdout.flush()
|
||||
sys.stdout = Unbuffered(sys.stdout)
|
||||
|
||||
def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment):
|
||||
# run_with_env is a cmd file that sets the right environment variables to
|
||||
run_with_env = os.path.join(tempfile.gettempdir(), 'appveyor_run_with_env.cmd')
|
||||
if not os.path.exists(run_with_env):
|
||||
@@ -32,23 +28,28 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
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.3.x', arch="32", identifier='cp33-win32', path='C:\Python33'),
|
||||
PythonConfiguration(version='3.3.x', arch="64", identifier='cp33-win_amd64', path='C:\Python33-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'),
|
||||
]
|
||||
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
|
||||
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
|
||||
|
||||
for config in python_configurations:
|
||||
if skip(config.identifier):
|
||||
if not build_selector(config.identifier):
|
||||
print('cibuildwheel: Skipping build %s' % config.identifier, file=sys.stderr)
|
||||
continue
|
||||
|
||||
# check python & pip exist for this configuration
|
||||
assert os.path.exists(os.path.join(config.path, 'python.exe'))
|
||||
assert os.path.exists(os.path.join(config.path, 'Scripts', 'pip.exe'))
|
||||
|
||||
# setup dirs
|
||||
if os.path.exists(built_wheel_dir):
|
||||
@@ -71,17 +72,18 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env)
|
||||
|
||||
# prepare the Python environment
|
||||
shell(['pip', 'install', '--disable-pip-version-check', '--user', '--upgrade', 'pip'],
|
||||
shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'],
|
||||
env=env)
|
||||
shell(['pip', 'install', '--upgrade', 'setuptools'], env=env)
|
||||
shell(['pip', 'install', 'wheel'], env=env)
|
||||
|
||||
# run the before_build command
|
||||
if before_build:
|
||||
before_build_prepared = prepare_command(before_build, python='python', pip='pip')
|
||||
before_build_prepared = prepare_command(before_build, project=abs_project_dir)
|
||||
shell([before_build_prepared], env=env)
|
||||
|
||||
# build the wheel
|
||||
shell(['pip', 'wheel', project_dir, '-w', built_wheel_dir, '--no-deps'], env=env)
|
||||
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]
|
||||
|
||||
# install the wheel
|
||||
@@ -94,9 +96,11 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
# run the tests from c:\, with an absolute path in the command
|
||||
# (this ensures that Python runs the tests against the installed wheel
|
||||
# and not the repo code)
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
test_command_absolute = test_command.format(project=abs_project_dir)
|
||||
shell([test_command_absolute], cwd='c:\\', env=env)
|
||||
test_command_prepared = prepare_command(test_command, project=abs_project_dir)
|
||||
shell([test_command_prepared], cwd='c:\\', env=env)
|
||||
|
||||
# we're all done here; move it to output
|
||||
shutil.move(built_wheel, output_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))
|
||||
if os.path.isfile(dst):
|
||||
os.remove(dst)
|
||||
shutil.move(built_wheel, dst)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 0.5.1
|
||||
current_version = 0.10.2
|
||||
commit = True
|
||||
tag = True
|
||||
message = Bump version
|
||||
|
||||
@@ -8,8 +8,8 @@ except ImportError:
|
||||
|
||||
setup(
|
||||
name='cibuildwheel',
|
||||
version='0.5.1',
|
||||
install_requires=['bashlex'],
|
||||
version='0.10.2',
|
||||
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',
|
||||
author="Joe Rickerby",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"CIBW_TEST_REQUIRES": "nose",
|
||||
"CIBW_TEST_COMMAND": "nosetests {project}/test"
|
||||
"CIBW_TEST_COMMAND": "false || nosetests {project}/test",
|
||||
"comment": "The 'false ||' bit is to ensure this command runs in a shell on Mac and Linux",
|
||||
"CIBW_TEST_COMMAND_WINDOWS": "nosetests {project}/test"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"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)\""
|
||||
"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)\""
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
from setuptools import setup, Extension
|
||||
import sys, os
|
||||
|
||||
if sys.argv[-1] != '--name':
|
||||
# assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_BUILD step
|
||||
# is the same one as is currently running.
|
||||
version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt'
|
||||
with open(version_file) as f:
|
||||
stored_version = f.read()
|
||||
print('stored_version', stored_version)
|
||||
print('sys.version', sys.version)
|
||||
assert stored_version == sys.version
|
||||
# assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_BUILD step
|
||||
# is the same one as is currently running.
|
||||
version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt'
|
||||
with open(version_file) as f:
|
||||
stored_version = f.read()
|
||||
print('stored_version', stored_version)
|
||||
print('sys.version', sys.version)
|
||||
assert stored_version == sys.version
|
||||
|
||||
# check that the executable also was written
|
||||
executable_file = 'c:\\pythonexecutable.txt' if sys.platform == 'win32' else '/tmp/pythonexecutable.txt'
|
||||
with open(executable_file) as f:
|
||||
stored_executable = f.read()
|
||||
print('stored_executable', stored_executable)
|
||||
print('sys.executable', sys.executable)
|
||||
# windows/mac are case insensitive
|
||||
assert os.path.realpath(stored_executable).lower() == os.path.realpath(sys.executable).lower()
|
||||
# check that the executable also was written
|
||||
executable_file = 'c:\\pythonexecutable.txt' if sys.platform == 'win32' else '/tmp/pythonexecutable.txt'
|
||||
with open(executable_file) as f:
|
||||
stored_executable = f.read()
|
||||
print('stored_executable', stored_executable)
|
||||
print('sys.executable', sys.executable)
|
||||
# windows/mac are case insensitive
|
||||
assert os.path.realpath(stored_executable).lower() == os.path.realpath(sys.executable).lower()
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"CIBW_BUILD": "cp3?-*",
|
||||
"CIBW_SKIP": "cp34-*"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
from setuptools import setup, Extension
|
||||
import sys
|
||||
|
||||
# explode if run on Python 2.7 or Python 3.4 (these should be skipped)
|
||||
if sys.version_info[0:2] == (2, 7):
|
||||
raise Exception('Python 2.7 should not be built')
|
||||
if sys.version_info[0:2] == (3, 4):
|
||||
raise Exception('Python 3.4 should be skipped')
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
ext_modules=[Extension('spam', sources=['spam.c'])],
|
||||
version="0.1.0",
|
||||
)
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"CIBW_SKIP": "cp26-* cp33-*"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
from setuptools import setup, Extension
|
||||
import sys
|
||||
|
||||
if sys.argv[-1] != '--name':
|
||||
# explode if run on Python 2.6 or Python 3.3 (these should be skipped)
|
||||
if sys.version_info[0:2] == (2, 6):
|
||||
raise Exception('Python 2.6 should be skipped')
|
||||
if sys.version_info[0:2] == (3, 3):
|
||||
raise Exception('Python 3.3 should be skipped')
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
ext_modules=[Extension('spam', sources=['spam.c'])],
|
||||
version="0.1.0",
|
||||
)
|
||||
@@ -1,20 +1,19 @@
|
||||
from setuptools import setup, Extension
|
||||
import sys, os
|
||||
|
||||
if sys.argv[-1] != '--name':
|
||||
# explode if environment isn't correct, as set in CIBW_ENVIRONMENT
|
||||
CIBW_TEST_VAR = os.environ.get('CIBW_TEST_VAR')
|
||||
CIBW_TEST_VAR_2 = os.environ.get('CIBW_TEST_VAR_2')
|
||||
PATH = os.environ.get('PATH')
|
||||
# explode if environment isn't correct, as set in CIBW_ENVIRONMENT
|
||||
CIBW_TEST_VAR = os.environ.get('CIBW_TEST_VAR')
|
||||
CIBW_TEST_VAR_2 = os.environ.get('CIBW_TEST_VAR_2')
|
||||
PATH = os.environ.get('PATH')
|
||||
|
||||
if CIBW_TEST_VAR != 'a b c':
|
||||
raise Exception('CIBW_TEST_VAR should equal "a b c". It was "%s"' % CIBW_TEST_VAR)
|
||||
if CIBW_TEST_VAR_2 != '1':
|
||||
raise Exception('CIBW_TEST_VAR_2 should equal "1". It was "%s"' % CIBW_TEST_VAR_2)
|
||||
if '/opt/cibw_test_path' not in PATH:
|
||||
raise Exception('PATH should contain "/opt/cibw_test_path". It was "%s"' % PATH)
|
||||
if '$PATH' in PATH:
|
||||
raise Exception('$PATH should be expanded in PATH. It was "%s"' % PATH)
|
||||
if CIBW_TEST_VAR != 'a b c':
|
||||
raise Exception('CIBW_TEST_VAR should equal "a b c". It was "%s"' % CIBW_TEST_VAR)
|
||||
if CIBW_TEST_VAR_2 != '1':
|
||||
raise Exception('CIBW_TEST_VAR_2 should equal "1". It was "%s"' % CIBW_TEST_VAR_2)
|
||||
if '/opt/cibw_test_path' not in PATH:
|
||||
raise Exception('PATH should contain "/opt/cibw_test_path". It was "%s"' % PATH)
|
||||
if '$PATH' in PATH:
|
||||
raise Exception('$PATH should be expanded in PATH. It was "%s"' % PATH)
|
||||
|
||||
|
||||
setup(
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"CIBW_MANYLINUX1_X86_64_IMAGE": "dockcross/manylinux-x64",
|
||||
"CIBW_MANYLINUX1_I686_IMAGE": "dockcross/manylinux-x86",
|
||||
"CIBW_SKIP": "cp37-manylinux*"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import os, sys
|
||||
|
||||
from setuptools import setup, Extension
|
||||
|
||||
# check that we're running in the correct docker image as specified in the
|
||||
# environment options CIBW_MANYLINUX1_*_IMAGE
|
||||
if 'linux' in sys.platform and not os.path.exists('/dockcross'):
|
||||
raise Exception('/dockcross directory not found. Is this test running in the correct docker image?')
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
ext_modules=[Extension('spam', sources=['spam.c'])],
|
||||
version="0.1.0",
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <Python.h>
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *command;
|
||||
int sts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
sts = system(command);
|
||||
return PyLong_FromLong(sts);
|
||||
}
|
||||
|
||||
/* Module initialization */
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
static struct PyModuleDef moduledef = { \
|
||||
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
|
||||
m = PyModule_Create(&moduledef);
|
||||
#define MOD_RETURN(m) return m;
|
||||
#else
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
m = Py_InitModule3(name, methods, doc);
|
||||
#define MOD_RETURN(m) return;
|
||||
#endif
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"system", (PyCFunction)spam_system, METH_VARARGS,
|
||||
"Execute a shell command."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
MOD_INIT(spam)
|
||||
{
|
||||
PyObject* m;
|
||||
|
||||
MOD_DEF(m,
|
||||
"spam",
|
||||
"Example module",
|
||||
module_methods,
|
||||
-1)
|
||||
|
||||
MOD_RETURN(m)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import ssl
|
||||
import sys
|
||||
from setuptools import setup, Extension
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
from urllib2 import urlopen
|
||||
else:
|
||||
from urllib.request import urlopen
|
||||
|
||||
if sys.version_info[0:2] == (3, 3):
|
||||
data = urlopen('https://www.nist.gov')
|
||||
else:
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
data = urlopen('https://www.nist.gov', context=context)
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
ext_modules=[Extension('spam', sources=['spam.c'])],
|
||||
version="0.1.0",
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <Python.h>
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *command;
|
||||
int sts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
sts = system(command);
|
||||
return PyLong_FromLong(sts);
|
||||
}
|
||||
|
||||
/* Module initialization */
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
static struct PyModuleDef moduledef = { \
|
||||
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
|
||||
m = PyModule_Create(&moduledef);
|
||||
#define MOD_RETURN(m) return m;
|
||||
#else
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
m = Py_InitModule3(name, methods, doc);
|
||||
#define MOD_RETURN(m) return;
|
||||
#endif
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"system", (PyCFunction)spam_system, METH_VARARGS,
|
||||
"Execute a shell command."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
MOD_INIT(spam)
|
||||
{
|
||||
PyObject* m;
|
||||
|
||||
MOD_DEF(m,
|
||||
"spam",
|
||||
"Example module",
|
||||
module_methods,
|
||||
-1)
|
||||
|
||||
MOD_RETURN(m)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
from cibuildwheel.util import BuildSelector
|
||||
|
||||
|
||||
def test_build():
|
||||
build_selector = BuildSelector(build_config="cp3?-* *-manylinux1*", skip_config="")
|
||||
|
||||
assert build_selector('cp27-manylinux1_x86_64')
|
||||
assert build_selector('cp36-manylinux1_x86_64')
|
||||
assert build_selector('cp37-manylinux1_x86_64')
|
||||
assert build_selector('cp27-manylinux1_i686')
|
||||
assert build_selector('cp36-manylinux1_i686')
|
||||
assert build_selector('cp37-manylinux1_i686')
|
||||
assert not build_selector('cp27-macosx_10_6_intel')
|
||||
assert build_selector('cp36-macosx_10_6_intel')
|
||||
assert build_selector('cp37-macosx_10_6_intel')
|
||||
assert not build_selector('cp27-win32')
|
||||
assert build_selector('cp36-win32')
|
||||
assert build_selector('cp37-win32')
|
||||
assert not build_selector('cp27-win_amd64')
|
||||
assert build_selector('cp36-win_amd64')
|
||||
assert build_selector('cp37-win_amd64')
|
||||
|
||||
|
||||
def test_skip():
|
||||
build_selector = BuildSelector(build_config="*", skip_config="cp27-* cp3?-manylinux1_i686 cp36-win* *-win32")
|
||||
|
||||
assert not build_selector('cp27-manylinux1_x86_64')
|
||||
assert build_selector('cp36-manylinux1_x86_64')
|
||||
assert build_selector('cp37-manylinux1_x86_64')
|
||||
assert not build_selector('cp27-manylinux1_i686')
|
||||
assert not build_selector('cp36-manylinux1_i686')
|
||||
assert not build_selector('cp37-manylinux1_i686')
|
||||
assert not build_selector('cp27-macosx_10_6_intel')
|
||||
assert build_selector('cp36-macosx_10_6_intel')
|
||||
assert build_selector('cp37-macosx_10_6_intel')
|
||||
assert not build_selector('cp27-win32')
|
||||
assert not build_selector('cp36-win32')
|
||||
assert not build_selector('cp37-win32')
|
||||
assert not build_selector('cp27-win_amd64')
|
||||
assert not build_selector('cp36-win_amd64')
|
||||
assert build_selector('cp37-win_amd64')
|
||||
|
||||
|
||||
def test_build_and_skip():
|
||||
build_selector = BuildSelector(build_config="cp36-* cp37-macosx* *-manylinux1*", skip_config="cp27-* cp37-manylinux1_i686")
|
||||
|
||||
assert not build_selector('cp27-manylinux1_x86_64')
|
||||
assert build_selector('cp36-manylinux1_x86_64')
|
||||
assert build_selector('cp37-manylinux1_x86_64')
|
||||
assert not build_selector('cp27-manylinux1_i686')
|
||||
assert build_selector('cp36-manylinux1_i686')
|
||||
assert not build_selector('cp37-manylinux1_i686')
|
||||
assert not build_selector('cp27-macosx_10_6_intel')
|
||||
assert build_selector('cp36-macosx_10_6_intel')
|
||||
assert build_selector('cp37-macosx_10_6_intel')
|
||||
assert not build_selector('cp27-win32')
|
||||
assert build_selector('cp36-win32')
|
||||
assert not build_selector('cp37-win32')
|
||||
assert not build_selector('cp27-win_amd64')
|
||||
assert build_selector('cp36-win_amd64')
|
||||
assert not build_selector('cp37-win_amd64')
|
||||
Reference in New Issue
Block a user