Skip to content

Commit bc946b9

Browse files
authored
Modernize wheel building job config (google#1783)
It is now possible to build Mac wheels on native machines in Github Actions, so ARM64 Mac wheels are now built and tested on M1 machines. Also, the artifact up-/download was migrated to v4, which made it necessary to upload wheels to unique artifact names, and then later stitch them together again in a subsequent job. The cross-platform Mac build injection in setup.py was removed, since it is no longer necessary. I relanded a monkey-patching of Bazel build files, this time for MODULE.bazel. This is because `rules_python` does not allow running as the root user, which is the case in cibuildwheel+Linux (happens in a Docker container). Since I did not see a quick way of switching to rootless containers, and did not want to hardcode the config change (it can apparently cause cache misses and build failures), I inject the "ignore_root_user_error" flag into the MODULE.bazel file when running in cibuildwheel on Linux.
1 parent 185c55d commit bc946b9

File tree

4 files changed

+83
-43
lines changed

4 files changed

+83
-43
lines changed

.github/install_bazel.sh

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ if ! bazel version; then
33
if [ "$arch" == "aarch64" ]; then
44
arch="arm64"
55
fi
6-
echo "Installing wget and downloading $arch Bazel binary from GitHub releases."
7-
yum install -y wget
8-
wget "https://github.com/bazelbuild/bazel/releases/download/6.4.0/bazel-6.4.0-linux-$arch" -O /usr/local/bin/bazel
9-
chmod +x /usr/local/bin/bazel
6+
echo "Downloading $arch Bazel binary from GitHub releases."
7+
curl -L -o $HOME/bin/bazel --create-dirs "https://github.com/bazelbuild/bazel/releases/download/7.1.1/bazel-7.1.1-linux-$arch"
8+
chmod +x $HOME/bin/bazel
109
else
11-
# bazel is installed for the correct architecture
10+
# Bazel is installed for the correct architecture
1211
exit 0
1312
fi

.github/workflows/wheels.yml

+31-19
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,24 @@ jobs:
1515
uses: actions/checkout@v4
1616
with:
1717
fetch-depth: 0
18-
- name: Install Python 3.11
18+
- name: Install Python 3.12
1919
uses: actions/setup-python@v5
2020
with:
21-
python-version: 3.11
21+
python-version: 3.12
2222
- run: python -m pip install build
2323
- name: Build sdist
2424
run: python -m build --sdist
25-
- uses: actions/upload-artifact@v3
25+
- uses: actions/upload-artifact@v4
2626
with:
27-
name: dist
27+
name: dist-sdist
2828
path: dist/*.tar.gz
2929

3030
build_wheels:
3131
name: Build Google Benchmark wheels on ${{ matrix.os }}
3232
runs-on: ${{ matrix.os }}
3333
strategy:
3434
matrix:
35-
os: [ubuntu-latest, macos-latest, windows-latest]
35+
os: [ubuntu-latest, macos-13, macos-14, windows-latest]
3636

3737
steps:
3838
- name: Check out Google Benchmark
@@ -47,32 +47,44 @@ jobs:
4747
platforms: all
4848

4949
- name: Build wheels on ${{ matrix.os }} using cibuildwheel
50-
uses: pypa/cibuildwheel@v2.16.2
50+
uses: pypa/cibuildwheel@v2.17
5151
env:
52-
CIBW_BUILD: 'cp38-* cp39-* cp310-* cp311-* cp312-*'
52+
CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-*"
5353
CIBW_SKIP: "*-musllinux_*"
54-
CIBW_TEST_SKIP: "*-macosx_arm64"
55-
CIBW_ARCHS_LINUX: x86_64 aarch64
56-
CIBW_ARCHS_MACOS: x86_64 arm64
57-
CIBW_ARCHS_WINDOWS: AMD64
54+
CIBW_TEST_SKIP: "cp38-macosx_*:arm64"
55+
CIBW_ARCHS_LINUX: auto64 aarch64
56+
CIBW_ARCHS_WINDOWS: auto64
5857
CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh
58+
# Grab the rootless Bazel installation inside the container.
59+
CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin
5960
CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py
6061

6162
- name: Upload Google Benchmark ${{ matrix.os }} wheels
62-
uses: actions/upload-artifact@v3
63+
uses: actions/upload-artifact@v4
6364
with:
64-
name: dist
65+
name: dist-${{ matrix.os }}
6566
path: wheelhouse/*.whl
6667

68+
merge_wheels:
69+
name: Merge all built wheels into one artifact
70+
runs-on: ubuntu-latest
71+
needs: build_wheels
72+
steps:
73+
- name: Merge wheels
74+
uses: actions/upload-artifact/merge@v4
75+
with:
76+
name: dist
77+
pattern: dist-*
78+
delete-merged: true
79+
6780
pypi_upload:
6881
name: Publish google-benchmark wheels to PyPI
69-
needs: [build_sdist, build_wheels]
82+
needs: [merge_wheels]
7083
runs-on: ubuntu-latest
7184
permissions:
7285
id-token: write
7386
steps:
74-
- uses: actions/download-artifact@v3
75-
with:
76-
name: dist
77-
path: dist
78-
- uses: pypa/[email protected]
87+
- uses: actions/download-artifact@v4
88+
with:
89+
path: dist
90+
- uses: pypa/gh-action-pypi-publish@v1

MODULE.bazel

-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ python.toolchain(
2727
is_default = True,
2828
python_version = "3.12",
2929
)
30-
use_repo(
31-
python,
32-
python = "python_versions",
33-
)
3430

3531
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True)
3632
pip.parse(

setup.py

+48-15
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
import contextlib
12
import os
23
import platform
4+
import re
35
import shutil
46
from pathlib import Path
5-
from typing import Any
7+
from typing import Any, Generator
68

79
import setuptools
810
from setuptools.command import build_ext
911

1012
IS_WINDOWS = platform.system() == "Windows"
1113
IS_MAC = platform.system() == "Darwin"
14+
IS_LINUX = platform.system() == "Linux"
1215

1316
# hardcoded SABI-related options. Requires that each Python interpreter
1417
# (hermetic or not) participating is of the same major-minor version.
@@ -17,6 +20,46 @@
1720
options = {"bdist_wheel": {"py_limited_api": "cp312"}} if py_limited_api else {}
1821

1922

23+
def is_cibuildwheel() -> bool:
24+
return os.getenv("CIBUILDWHEEL") is not None
25+
26+
27+
@contextlib.contextmanager
28+
def _maybe_patch_toolchains() -> Generator[None, None, None]:
29+
"""
30+
Patch rules_python toolchains to ignore root user error
31+
when run in a Docker container on Linux in cibuildwheel.
32+
"""
33+
34+
def fmt_toolchain_args(matchobj):
35+
suffix = "ignore_root_user_error = True"
36+
callargs = matchobj.group(1)
37+
# toolchain def is broken over multiple lines
38+
if callargs.endswith("\n"):
39+
callargs = callargs + " " + suffix + ",\n"
40+
# toolchain def is on one line.
41+
else:
42+
callargs = callargs + ", " + suffix
43+
return "python.toolchain(" + callargs + ")"
44+
45+
CIBW_LINUX = is_cibuildwheel() and IS_LINUX
46+
try:
47+
if CIBW_LINUX:
48+
module_bazel = Path("MODULE.bazel")
49+
content: str = module_bazel.read_text()
50+
module_bazel.write_text(
51+
re.sub(
52+
r"python.toolchain\(([\w\"\s,.=]*)\)",
53+
fmt_toolchain_args,
54+
content,
55+
)
56+
)
57+
yield
58+
finally:
59+
if CIBW_LINUX:
60+
module_bazel.write_text(content)
61+
62+
2063
class BazelExtension(setuptools.Extension):
2164
"""A C/C++ extension that is defined as a Bazel BUILD target."""
2265

@@ -73,21 +116,11 @@ def bazel_build(self, ext: BazelExtension) -> None:
73116
for library_dir in self.library_dirs:
74117
bazel_argv.append("--linkopt=/LIBPATH:" + library_dir)
75118
elif IS_MAC:
76-
if platform.machine() == "x86_64":
77-
# C++17 needs macOS 10.14 at minimum
78-
bazel_argv.append("--macos_minimum_os=10.14")
79-
80-
# cross-compilation for Mac ARM64 on GitHub Mac x86 runners.
81-
# ARCHFLAGS is set by cibuildwheel before macOS wheel builds.
82-
archflags = os.getenv("ARCHFLAGS", "")
83-
if "arm64" in archflags:
84-
bazel_argv.append("--cpu=darwin_arm64")
85-
bazel_argv.append("--macos_cpus=arm64")
86-
87-
elif platform.machine() == "arm64":
88-
bazel_argv.append("--macos_minimum_os=11.0")
119+
# C++17 needs macOS 10.14 at minimum
120+
bazel_argv.append("--macos_minimum_os=10.14")
89121

90-
self.spawn(bazel_argv)
122+
with _maybe_patch_toolchains():
123+
self.spawn(bazel_argv)
91124

92125
if IS_WINDOWS:
93126
suffix = ".pyd"

0 commit comments

Comments
 (0)