[CI] Build Python wheels for MacOS (x86_64 and arm64) (#7621)
* Build Python wheels for OSX (x86_64 and arm64) * Use Conda's libomp when running Python tests * fix * Add comment to explain CIBW_TARGET_OSX_ARM64 * Update release script * Add comments in build_python_wheels.sh * Document wheel pipeline
This commit is contained in:
parent
271a7c5d43
commit
f6e6d0b2c0
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
@ -21,10 +21,7 @@ jobs:
|
|||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
- name: Install system packages
|
- name: Install system packages
|
||||||
run: |
|
run: |
|
||||||
# Use libomp 11.1.0: https://github.com/dmlc/xgboost/issues/7039
|
|
||||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -O $(find $(brew --repository) -name libomp.rb)
|
|
||||||
brew install ninja libomp
|
brew install ninja libomp
|
||||||
brew pin libomp
|
|
||||||
- name: Build gtest binary
|
- name: Build gtest binary
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|||||||
34
.github/workflows/python_tests.yml
vendored
34
.github/workflows/python_tests.yml
vendored
@ -17,10 +17,7 @@ jobs:
|
|||||||
- name: Install osx system dependencies
|
- name: Install osx system dependencies
|
||||||
if: matrix.os == 'macos-10.15'
|
if: matrix.os == 'macos-10.15'
|
||||||
run: |
|
run: |
|
||||||
# Use libomp 11.1.0: https://github.com/dmlc/xgboost/issues/7039
|
|
||||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -O $(find $(brew --repository) -name libomp.rb)
|
|
||||||
brew install ninja libomp
|
brew install ninja libomp
|
||||||
brew pin libomp
|
|
||||||
- name: Install Ubuntu system dependencies
|
- name: Install Ubuntu system dependencies
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
run: |
|
run: |
|
||||||
@ -119,14 +116,16 @@ jobs:
|
|||||||
conda list
|
conda list
|
||||||
|
|
||||||
- name: Build XGBoost on macos
|
- name: Build XGBoost on macos
|
||||||
|
shell: bash -l {0}
|
||||||
run: |
|
run: |
|
||||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -O $(find $(brew --repository) -name libomp.rb)
|
brew install ninja
|
||||||
brew install ninja libomp
|
|
||||||
brew pin libomp
|
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -GNinja -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON
|
# Set prefix, to use OpenMP library from Conda env
|
||||||
|
# See https://github.com/dmlc/xgboost/issues/7039#issuecomment-1025038228
|
||||||
|
# to learn why we don't use libomp from Homebrew.
|
||||||
|
cmake .. -GNinja -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON -DCMAKE_PREFIX_PATH=$CONDA_PREFIX
|
||||||
ninja
|
ninja
|
||||||
|
|
||||||
- name: Install Python package
|
- name: Install Python package
|
||||||
@ -141,24 +140,3 @@ jobs:
|
|||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
run: |
|
run: |
|
||||||
pytest -s -v ./tests/python
|
pytest -s -v ./tests/python
|
||||||
|
|
||||||
- name: Rename Python wheel
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
TAG=macosx_10_15_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64
|
|
||||||
python tests/ci_build/rename_whl.py python-package/dist/*.whl ${{ github.sha }} ${TAG}
|
|
||||||
|
|
||||||
- name: Extract branch name
|
|
||||||
shell: bash
|
|
||||||
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
|
|
||||||
id: extract_branch
|
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
|
||||||
|
|
||||||
- name: Upload Python wheel
|
|
||||||
shell: bash -l {0}
|
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
|
||||||
run: |
|
|
||||||
python -m awscli s3 cp python-package/dist/*.whl s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/ --acl public-read
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_IAM_S3_UPLOADER }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_IAM_S3_UPLOADER }}
|
|
||||||
|
|||||||
57
.github/workflows/python_wheels.yml
vendored
Normal file
57
.github/workflows/python_wheels.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
name: XGBoost-Python-Wheels
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
python-wheels:
|
||||||
|
name: Build wheel for ${{ matrix.platform_id }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: macos-latest
|
||||||
|
python: 37
|
||||||
|
platform_id: macosx_x86_64
|
||||||
|
wheel_tag: macosx_10_15_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64
|
||||||
|
- os: macos-latest
|
||||||
|
python: 38
|
||||||
|
platform_id: macosx_arm64
|
||||||
|
wheel_tag: macosx_12_0_arm64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
- name: Set env var for ARM64
|
||||||
|
shell: bash
|
||||||
|
run: echo "::set-output name=value::CIBW_TARGET_OSX_ARM64=1"
|
||||||
|
id: arm64_flag
|
||||||
|
if: matrix.platform_id == 'macosx_arm64'
|
||||||
|
- name: Build wheels
|
||||||
|
env:
|
||||||
|
CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform_id }}
|
||||||
|
CIBW_ARCHS: all
|
||||||
|
CIBW_ENVIRONMENT: ${{ steps.arm64_flag.outputs.value }}
|
||||||
|
CIBW_TEST_SKIP: "*-macosx_arm64"
|
||||||
|
CIBW_BUILD_VERBOSITY: 3
|
||||||
|
run: bash tests/ci_build/build_python_wheels.sh
|
||||||
|
|
||||||
|
- name: Rename Python wheel
|
||||||
|
run: |
|
||||||
|
python tests/ci_build/rename_whl.py wheelhouse/*.whl ${{ github.sha }} ${{ matrix.wheel_tag }}
|
||||||
|
- name: Extract branch name
|
||||||
|
shell: bash
|
||||||
|
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
|
||||||
|
id: extract_branch
|
||||||
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
||||||
|
- name: Upload Python wheel
|
||||||
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
||||||
|
run: |
|
||||||
|
python -m pip install awscli
|
||||||
|
python -m awscli s3 cp wheelhouse/*.whl s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/ --acl public-read
|
||||||
|
env:
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_IAM_S3_UPLOADER }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_IAM_S3_UPLOADER }}
|
||||||
@ -80,7 +80,8 @@ def download_py_packages(major: int, minor: int, commit_hash: str):
|
|||||||
"win_amd64",
|
"win_amd64",
|
||||||
"manylinux2014_x86_64",
|
"manylinux2014_x86_64",
|
||||||
"manylinux2014_aarch64",
|
"manylinux2014_aarch64",
|
||||||
"macosx_10_14_x86_64.macosx_10_15_x86_64.macosx_11_0_x86_64",
|
"macosx_10_15_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64",
|
||||||
|
"macosx_12_0_arm64"
|
||||||
]
|
]
|
||||||
|
|
||||||
dir_URL = PREFIX + str(major) + "." + str(minor) + ".0" + "/"
|
dir_URL = PREFIX + str(major) + "." + str(minor) + ".0" + "/"
|
||||||
|
|||||||
@ -25,3 +25,15 @@ requests and every update to branches. A few tests however require manual activa
|
|||||||
details about noLD. This is a requirement for keeping XGBoost on CRAN (the R package index).
|
details about noLD. This is a requirement for keeping XGBoost on CRAN (the R package index).
|
||||||
To invoke this test suite for a particular pull request, simply add a review comment
|
To invoke this test suite for a particular pull request, simply add a review comment
|
||||||
``/gha run r-nold-test``. (Ordinary comment won't work. It needs to be a review comment.)
|
``/gha run r-nold-test``. (Ordinary comment won't work. It needs to be a review comment.)
|
||||||
|
|
||||||
|
GitHub Actions is also used to build Python wheels targeting MacOS Intel and Apple Silicon. See
|
||||||
|
`.github/workflows/python_wheels.yml
|
||||||
|
<https://github.com/dmlc/xgboost/tree/master/.github/workflows/python_wheels.yml>`_. The
|
||||||
|
``python_wheels`` pipeline sets up environment variables prefixed ``CIBW_*`` to indicate the target
|
||||||
|
OS and processor. The pipeline then invokes the script ``build_python_wheels.sh``, which in turns
|
||||||
|
calls ``cibuildwheel`` to build the wheel. The ``cibuildwheel`` is a library that sets up a
|
||||||
|
suitable Python environment for each OS and processor target. Since we don't have Apple Silion
|
||||||
|
machine in GitHub Actions, cross-compilation is needed; ``cibuildwheel`` takes care of the complex
|
||||||
|
task of cross-compiling a Python wheel. (Note that ``cibuildwheel`` will call
|
||||||
|
``setup.py bdist_wheel``. Since XGBoost has a native library component, ``setup.py`` contains
|
||||||
|
a glue code to call CMake and a C++ compiler to build the native library on the fly.)
|
||||||
|
|||||||
@ -119,6 +119,13 @@ class BuildExt(build_ext.build_ext): # pylint: disable=too-many-ancestors
|
|||||||
continue
|
continue
|
||||||
cmake_cmd.append('-D' + arg + '=' + value)
|
cmake_cmd.append('-D' + arg + '=' + value)
|
||||||
|
|
||||||
|
# Flag for cross-compiling for Apple Silicon
|
||||||
|
# We use environment variable because it's the only way to pass down custom flags
|
||||||
|
# through the cibuildwheel package, which otherwise calls `python setup.py bdist_wheel`
|
||||||
|
# command.
|
||||||
|
if 'CIBW_TARGET_OSX_ARM64' in os.environ:
|
||||||
|
cmake_cmd.append("-DCMAKE_OSX_ARCHITECTURES=arm64")
|
||||||
|
|
||||||
self.logger.info('Run CMake command: %s', str(cmake_cmd))
|
self.logger.info('Run CMake command: %s', str(cmake_cmd))
|
||||||
subprocess.check_call(cmake_cmd, cwd=build_dir)
|
subprocess.check_call(cmake_cmd, cwd=build_dir)
|
||||||
|
|
||||||
|
|||||||
38
tests/ci_build/build_python_wheels.sh
Normal file
38
tests/ci_build/build_python_wheels.sh
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# Bundle libomp 11.1.0 when targeting MacOS.
|
||||||
|
# This is a workaround in order to prevent segfaults when running inside a Conda environment.
|
||||||
|
# See https://github.com/dmlc/xgboost/issues/7039#issuecomment-1025125003 for more context.
|
||||||
|
# The workaround is also used by the scikit-learn project.
|
||||||
|
if [[ "$RUNNER_OS" == "macOS" ]]; then
|
||||||
|
# Make sure to use a libomp version binary compatible with the oldest
|
||||||
|
# supported version of the macos SDK as libomp will be vendored into the
|
||||||
|
# XGBoost wheels for MacOS.
|
||||||
|
|
||||||
|
if [[ "$CIBW_BUILD" == *-macosx_arm64 ]]; then
|
||||||
|
# arm64 builds must cross compile because CI is on x64
|
||||||
|
# cibuildwheel will take care of cross-compilation.
|
||||||
|
export PYTHON_CROSSENV=1
|
||||||
|
export MACOSX_DEPLOYMENT_TARGET=12.0
|
||||||
|
OPENMP_URL="https://anaconda.org/conda-forge/llvm-openmp/11.1.0/download/osx-arm64/llvm-openmp-11.1.0-hf3c4609_1.tar.bz2"
|
||||||
|
else
|
||||||
|
export MACOSX_DEPLOYMENT_TARGET=10.13
|
||||||
|
OPENMP_URL="https://anaconda.org/conda-forge/llvm-openmp/11.1.0/download/osx-64/llvm-openmp-11.1.0-hda6cdc1_1.tar.bz2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo conda create -n build $OPENMP_URL
|
||||||
|
PREFIX="/usr/local/miniconda/envs/build"
|
||||||
|
|
||||||
|
export CC=/usr/bin/clang
|
||||||
|
export CXX=/usr/bin/clang++
|
||||||
|
export CPPFLAGS="$CPPFLAGS -Xpreprocessor -fopenmp"
|
||||||
|
export CFLAGS="$CFLAGS -I$PREFIX/include"
|
||||||
|
export CXXFLAGS="$CXXFLAGS -I$PREFIX/include"
|
||||||
|
export LDFLAGS="$LDFLAGS -Wl,-rpath,$PREFIX/lib -L$PREFIX/lib -lomp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
python -m pip install cibuildwheel
|
||||||
|
python -m cibuildwheel python-package --output-dir wheelhouse
|
||||||
@ -10,6 +10,7 @@ dependencies:
|
|||||||
- pylint
|
- pylint
|
||||||
- numpy
|
- numpy
|
||||||
- scipy
|
- scipy
|
||||||
|
- llvm-openmp
|
||||||
- scikit-learn
|
- scikit-learn
|
||||||
- pandas
|
- pandas
|
||||||
- matplotlib
|
- matplotlib
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user