Skip to content

Commit 13805ff

Browse files
authored
ARROW-56 Improve Wheel Support (#67)
1 parent ddc172f commit 13805ff

File tree

6 files changed

+142
-77
lines changed

6 files changed

+142
-77
lines changed

.github/workflows/release-python.yml

Lines changed: 75 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -9,101 +9,103 @@ concurrency:
99
cancel-in-progress: true
1010

1111
jobs:
12-
build-non-linux-wheels:
13-
runs-on: ${{ matrix.os }}
12+
build_wheels:
13+
name: Build wheel for ${{ matrix.python }}-${{ matrix.buildplat[1] }}
14+
runs-on: ${{ matrix.buildplat[0] }}
1415
strategy:
16+
# Ensure that a wheel builder finishes even if another fails
17+
fail-fast: false
1518
matrix:
16-
os: [macos-10.15, windows-latest]
17-
python-version: [3.7, 3.8, 3.9, "3.10"]
18-
name: Build CPython ${{ matrix.python-version }}-${{ matrix.os }}
19+
# Github Actions doesn't support pairing matrix values together, let's improvise
20+
# https://github.com/github/feedback/discussions/7835#discussioncomment-1769026
21+
buildplat:
22+
- [ubuntu-20.04, manylinux_x86_64]
23+
- [macos-10.15, macosx_*]
24+
- [windows-2019, win_amd64]
25+
python: ["cp37", "cp38", "cp39", "cp310"]
26+
1927
steps:
20-
- uses: actions/checkout@v2
21-
- name: Setup Python
22-
uses: actions/setup-python@v2
28+
- name: Checkout pymongoarrow
29+
uses: actions/checkout@v2
2330
with:
24-
python-version: ${{ matrix.python-version }}
25-
cache: 'pip'
26-
cache-dependency-path: '**/setup.cfg'
31+
fetch-depth: 0
32+
33+
- uses: actions/setup-python@v2
34+
35+
- name: Install cibuildwheel
36+
run: python -m pip install "cibuildwheel>=2.4,<3"
37+
38+
- name: Build MacOS Py38 Wheel
39+
if: ${{ matrix.python == 'cp38' && matrix.buildplat[0] == 'macos-10.15' }}
40+
working-directory: ./bindings/python
41+
shell: bash
42+
env:
43+
CIBW_BUILD: cp38-macosx_x86_64
44+
MACOSX_DEPLOYMENT_TARGET: "10.13"
45+
run: python -m cibuildwheel --output-dir wheelhouse
46+
2747
- name: Build wheels
48+
if: ${{ matrix.python != 'cp38' || matrix.buildplat[0] != 'macos-10.15' }}
2849
working-directory: ./bindings/python
2950
shell: bash
30-
run: |
31-
./release.sh
51+
env:
52+
CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }}
53+
MACOSX_DEPLOYMENT_TARGET: "10.13"
54+
run: python -m cibuildwheel --output-dir wheelhouse
55+
3256
- uses: actions/upload-artifact@v2
3357
with:
34-
name: pymongoarrow-${{ matrix.python-version }}-${{ matrix.os }}-wheel
35-
path: ./bindings/python/dist/*.whl
58+
name: ${{ matrix.python }}-${{ startsWith(matrix.buildplat[1], 'macosx') && 'macosx' || matrix.buildplat[1] }}
59+
path: ./bindings/python/wheelhouse/*.whl
3660
if-no-files-found: error
37-
test-non-linux-wheels:
38-
needs: build-non-linux-wheels
39-
runs-on: ${{ matrix.os }}
40-
strategy:
41-
matrix:
42-
os: [macos-10.15, windows-latest]
43-
python-version: [3.7, 3.8, 3.9, "3.10"]
44-
name: Test CPython ${{ matrix.python-version }}-${{ matrix.os }}
61+
62+
make_sdist:
63+
name: Make SDist
64+
runs-on: ubuntu-latest
4565
steps:
46-
- name: Setup Python
47-
uses: actions/setup-python@v2
66+
- uses: actions/checkout@v2
4867
with:
49-
python-version: ${{ matrix.python-version }}
50-
- name: Download a previously created wheel
51-
uses: actions/download-artifact@v2
68+
fetch-depth: 0
69+
70+
- uses: actions/setup-python@v2
5271
with:
53-
name: pymongoarrow-${{ matrix.python-version }}-${{ matrix.os }}-wheel
54-
- name: Test wheel
55-
shell: bash
72+
# Build sdist on lowest supported Python
73+
python-version: '3.7'
74+
75+
- name: Build SDist
76+
working-directory: ./bindings/python
5677
run: |
57-
python -m pip install -U pip
58-
python -m pip install *.whl
59-
python -c "from pymongoarrow.lib import process_bson_stream"
60-
# Linux
61-
build-manylinux-wheels:
62-
runs-on: ubuntu-latest
63-
strategy:
64-
matrix:
65-
# Cannot have '/' in artifact names, so hardcode 'quay.io/pypa/'
66-
container: ['manylinux2010_x86_64', 'manylinux2014_x86_64']
67-
python-version: ['cp37-cp37m', 'cp38-cp38',
68-
'cp39-cp39', 'cp310-cp310']
69-
name: Build CPython ${{ matrix.python-version }}-${{ matrix.container }}
70-
steps:
71-
- uses: actions/checkout@v2
72-
- name: Build wheels
78+
set -ex
79+
python -m pip install -U pip build
80+
export LIBBSON_INSTALL_DIR="$(pwd)/libbson"
81+
./build-libbson.sh
82+
python -m build --sdist .
83+
84+
- name: Test Sdist
7385
working-directory: ./bindings/python
7486
run: |
75-
docker run --rm --volume `pwd`:/python --workdir /python --env PLAT=${{ matrix.container }} --env PYTHON_BINARY=/opt/python/${{ matrix.python-version }}/bin/python quay.io/pypa/${{ matrix.container }} ./release.sh
87+
export LIBBSON_INSTALL_DIR="$(pwd)/libbson"
88+
python -m pip install dist/*.gz
89+
cd ..
90+
python -c "from pymongoarrow.lib import process_bson_stream"
91+
7692
- uses: actions/upload-artifact@v2
7793
with:
78-
name: pymongoarrow-${{ matrix.python-version }}-${{ matrix.container }}-wheel
79-
path: ./bindings/python/wheelhouse/*.whl
80-
if-no-files-found: error
81-
test-manylinux-wheels:
82-
runs-on: ubuntu-latest
83-
needs: build-manylinux-wheels
84-
strategy:
85-
matrix:
86-
container: ['manylinux2010_x86_64', 'manylinux2014_x86_64']
87-
python-version: ['cp37-cp37m', 'cp38-cp38',
88-
'cp39-cp39', 'cp310-cp310']
89-
name: Test CPython ${{ matrix.python-version }}-${{ matrix.container }}
90-
steps:
91-
- name: Download a previously created wheel
92-
uses: actions/download-artifact@v2
93-
with:
94-
name: pymongoarrow-${{ matrix.python-version }}-${{ matrix.container }}-wheel
95-
- name: Test wheel
96-
run: |
97-
docker run --rm --volume `pwd`:/python quay.io/pypa/${{ matrix.container }} /bin/bash -c "/opt/python/${{ matrix.python-version }}/bin/python -m pip install -U pip && /opt/python/${{ matrix.python-version }}/bin/python -m pip install /python/*.whl && /opt/python/${{ matrix.python-version }}/bin/python -c 'from pymongoarrow.lib import process_bson_stream'"
98-
# Collect all built wheels
99-
collect-wheels:
94+
name: "sdist"
95+
path: ./bindings/python/dist/*.tar.gz
96+
97+
collect-dist:
10098
runs-on: ubuntu-latest
101-
needs: [build-non-linux-wheels, build-manylinux-wheels]
99+
needs: [build_wheels, make_sdist]
102100
name: Download Wheels
103101
steps:
104102
- name: Download all workflow run artifacts
105103
uses: actions/download-artifact@v2
104+
- name: Flatten directory
105+
run: |
106+
find . -mindepth 2 -type f -exec mv {} . \;
107+
find . -type d -empty -delete
106108
- uses: actions/upload-artifact@v2
107109
with:
108-
name: nix-wheels
109-
path: "*-wheel"
110+
name: all-dist
111+
path: "./*"

bindings/python/MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
include README.rst
22
include LICENSE
3-
include build-libbson.sh
3+
include *.sh
44
include pyproject.toml
55

66
exclude THIRD-PARTY-NOTICES

bindings/python/build-libbson.sh

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,39 @@ then
1919
git clone --depth 1 -b "$LIBBSON_VERSION" https://github.com/mongodb/mongo-c-driver.git "$WORKDIR"
2020
fi
2121

22+
echo "Installing libbson..."
23+
24+
MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-"10.15"}
25+
CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES:-"x86_64"}
26+
2227
# Directory where build artifacts will be placed
2328
LIBBSON_INSTALL_DIR=${LIBBSON_INSTALL_DIR:-""}
2429

30+
# Replace a relative path with an absolute one for cmake
31+
LIBBSON_INSTALL_DIR="$(cd "$(dirname "$LIBBSON_INSTALL_DIR")"; pwd)/$(basename "$LIBBSON_INSTALL_DIR")"
32+
33+
echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}"
34+
echo "CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}"
35+
echo "LIBBSON_INSTALL_DIR=${LIBBSON_INSTALL_DIR}"
36+
2537
# Build libbson
2638
pushd "$WORKDIR"
2739
git checkout "$LIBBSON_VERSION"
2840
mkdir -p cmake-build
2941
pushd cmake-build
3042
if [ -n "$LIBBSON_INSTALL_DIR" ]
3143
then
32-
echo "Installing libbson in $LIBBSON_INSTALL_DIR"
3344
cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF \
3445
-DENABLE_MONGOC=OFF \
35-
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9" \
46+
-DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} \
47+
-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} \
3648
-DCMAKE_INSTALL_PREFIX:PATH="$LIBBSON_INSTALL_DIR" \
3749
..
3850
else
3951
cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF \
52+
-DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} \
53+
-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} \
4054
-DENABLE_MONGOC=OFF \
41-
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9" \
4255
..
4356
fi
4457
cmake --build . --target clean

bindings/python/cibw_before_build.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash -ex
2+
3+
set -o xtrace
4+
set -o errexit
5+
6+
# Handle architectures from cibuildwheel.
7+
# Set CMAKE_OSX_ARCHITECTURES for libbson.
8+
# Get the appropriate version of pyarrow for macos.
9+
10+
if [[ "$CIBW_BUILD" == *"macosx_"* ]]
11+
then
12+
mac_version="${MACOSX_DEPLOYMENT_TARGET/\./_}"
13+
if [[ "$ARCHFLAGS" == *"arm64"* ]]
14+
then
15+
platform="macosx_${mac_version}_universal2"
16+
export CMAKE_OSX_ARCHITECTURES="arm64;x86_64"
17+
else
18+
platform="macosx_${mac_version}_x86_64"
19+
fi
20+
21+
# Install pyarrow with the appropriate platform.
22+
pip install --platform $platform --target $HOME/wheels --no-deps --only-binary=:all: pyarrow
23+
fi
24+
25+
26+
# Build libbson with the appropriate arch.
27+
./build-libbson.sh

bindings/python/pyproject.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,19 @@ requires = [
66
# Must be kept in sync with the `install_requires` in `setup.cfg`
77
"pyarrow>=7.0.0,<7.1.0",
88
]
9+
10+
[tool.cibuildwheel]
11+
skip = "pp* *-manylinux_i686 *_ppc64le *_s390x *-musllinux*"
12+
before-build = "bash ./cibw_before_build.sh"
13+
build-frontend = "build"
14+
test-command = "python -c \"from pymongoarrow.lib import process_bson_stream\""
15+
16+
[tool.cibuildwheel.environment]
17+
LIBBSON_INSTALL_DIR = "./libbson"
18+
19+
[tool.cibuildwheel.linux]
20+
manylinux-x86_64-image = "manylinux2014"
21+
22+
[tool.cibuildwheel.macos]
23+
archs = "x86_64 universal2"
24+
test-skip = "*universal2:arm64"

bindings/python/setup.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def append_libbson_flags(module):
3737
pc_path = "libbson-1.0"
3838
install_dir = os.environ.get("LIBBSON_INSTALL_DIR")
3939
if install_dir:
40+
install_dir = os.path.abspath(install_dir)
4041
# Handle the copy-able library file if applicable.
4142
if COPY_LIBBSON:
4243
if platform == "darwin":
@@ -56,6 +57,10 @@ def append_libbson_flags(module):
5657
lib_dirs = glob.glob(os.path.join(install_dir, "lib*"))
5758
if len(lib_dirs) != 1:
5859
warnings.warn(f"Unable to locate libbson in {install_dir}")
60+
if IS_WIN:
61+
raise ValueError(
62+
"We require a LIBBSON_INSTALL_DIR with a compiled library on Windows"
63+
)
5964
else:
6065
lib_dir = lib_dirs[0]
6166
if IS_WIN:
@@ -84,6 +89,7 @@ def append_libbson_flags(module):
8489
raise ValueError(f'Could not find "{pc_path}" library')
8590

8691
cflags = query_pkgconfig("pkg-config --cflags {}".format(pc_path))
92+
8793
if cflags:
8894
orig_cflags = os.environ.get("CFLAGS", "")
8995
os.environ["CFLAGS"] = cflags + " " + orig_cflags
@@ -174,6 +180,7 @@ def get_extension_modules():
174180
module.extra_link_args += ["-rpath", "@loader_path"]
175181
elif platform == "linux":
176182
module.extra_link_args += ["-Wl,-rpath,$ORIGIN"]
183+
177184
return modules
178185

179186

0 commit comments

Comments
 (0)