Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
29465ef
e2e for cross sdist build
xangcastle Jul 23, 2026
bd4944f
enable cross compile mode
xangcastle Jul 23, 2026
b911ca4
check so arch in e2e
xangcastle Jul 23, 2026
2e1e751
extract the compiler flags
xangcastle Jul 23, 2026
34a9642
check EXT_SUFFIX and SOABI
xangcastle Jul 23, 2026
0f6d1fc
modify EXT_SUFFIX and SOABI
xangcastle Jul 23, 2026
a776291
adding cffi as default build dependency to break the build, since thi…
xangcastle Jul 23, 2026
8fe1b2a
improve selection wheel with exec_transition
xangcastle Jul 23, 2026
d41150e
validate wheel platform
xangcastle Jul 23, 2026
73cf6a3
linter errors
xangcastle Jul 23, 2026
17d7552
revert exec transition
xangcastle Jul 23, 2026
88e0826
exec transition
xangcastle Jul 23, 2026
1571655
documenting
xangcastle Jul 23, 2026
0b06775
deriving from the exec/target interpreter platform identities
xangcastle Jul 23, 2026
bf1385f
add pycross tests
jbedard Jul 26, 2026
a8ca499
crossbuild test cases
xangcastle Aug 6, 2026
62b3a96
crossbuild helper
xangcastle Aug 7, 2026
4965c22
typing e2e
xangcastle Aug 7, 2026
884fc56
typing e2e
xangcastle Aug 7, 2026
751c00b
sdists darwin→linux
xangcastle Aug 10, 2026
18b57f0
e2e for cross sdist build
xangcastle Jul 23, 2026
90272dc
check so arch in e2e
xangcastle Jul 23, 2026
d98b720
check EXT_SUFFIX and SOABI
xangcastle Jul 23, 2026
6d521f8
crossbuild test cases
xangcastle Aug 6, 2026
60a5c5e
typing e2e
xangcastle Aug 7, 2026
6ea0cb4
fixing ci
xangcastle Aug 10, 2026
9de528f
enable macos
xangcastle Aug 11, 2026
d96690a
test(e2e): defer the e2e/cases cross matrix to a follow-up
xangcastle Aug 11, 2026
a4741c8
refactor(e2e): normalize geohash onto the per-case hub layout
xangcastle Aug 11, 2026
7bb1c03
test(e2e): add pycross tests under e2e/crossbuild
jbedard Jul 26, 2026
20f1125
test(e2e): consolidate the pycross suites in e2e/crossbuild
xangcastle Aug 11, 2026
8d67ac2
test(e2e): restore the cross-arch pyc precompilation regression guard
xangcastle Aug 12, 2026
c6fc189
fix(e2e): regenerate the crossbuild lockfile with the pinned bazel 8.6.0
xangcastle Aug 13, 2026
1e4e576
refactor(uv): deduplicate and tighten build_helper.py
xangcastle Aug 14, 2026
fdbd3f7
refactor(uv): reorganize the pep517_whl package by concern
xangcastle Aug 14, 2026
d17979d
Merge remote-tracking branch 'origin' into xangcastle/cross-sdist
xangcastle Aug 14, 2026
4e91cf7
ci(e2e): execute crossbuild images on native runners via artifacts
xangcastle Aug 14, 2026
631c52c
ci(e2e): register QEMU binfmt on the crossbuild image builder
xangcastle Aug 14, 2026
cb218ef
fix(e2e): define the ci config in e2e/crossbuild's bazelrc
xangcastle Aug 14, 2026
ef0b521
fix(uv): link the -nostdlib++ toolchain's static runtime archives exp…
xangcastle Aug 14, 2026
1c684e5
ci(e2e): surface meson tracebacks in the darwin image builder
xangcastle Aug 14, 2026
7bb1992
fix(uv): stop treating compiler-introspection probes as link invocations
xangcastle Aug 14, 2026
37825dd
ci(e2e): close the linux-to-linux cycle with an arm64 image builder
xangcastle Aug 14, 2026
32d5679
fix(uv): only offer meson an exe_wrapper when qemu can load the binary
xangcastle Aug 14, 2026
5eabe8e
ci(e2e): materialize tarballs on the arm64 builder despite minimal do…
xangcastle Aug 14, 2026
544aa92
ci(e2e): rename crossbuild-images to crossbuild-images-amd64
xangcastle Aug 14, 2026
36ff7c7
refining github workflow
xangcastle Aug 14, 2026
98f8bff
ci(e2e): fold the crossbuild pipelines into one reusable workflow
xangcastle Aug 14, 2026
22da005
ci: gate test-all on the crossbuild pipelines, tolerating the darwin …
xangcastle Aug 14, 2026
929e38d
refactor(e2e): move crossbuild execution off-host — native runners only
xangcastle Aug 14, 2026
d25f1da
refining github workflow
xangcastle Aug 14, 2026
dc6e2ba
ci: repair test-all gating and restore native amd64 execution coverage
xangcastle Aug 14, 2026
fd8f3ef
refining github workflow
xangcastle Aug 14, 2026
add2163
ci: make the amd64 pipeline fully native — one builder, one runner
xangcastle Aug 14, 2026
c22820d
ci: the amd64 pipeline cross-builds for arm64 and runs on native arm64
xangcastle Aug 14, 2026
617dc74
ci: materialize tarballs on the darwin builder too
xangcastle Aug 14, 2026
80e5709
refining github workflow
xangcastle Aug 14, 2026
debfb9d
Merge remote-tracking branch 'origin' into xangcastle/cross-sdist-macos
xangcastle Aug 14, 2026
2840a2a
spliting test cases MODULE.bazel
xangcastle Aug 14, 2026
b8e9753
refine workflow
xangcastle Aug 14, 2026
11c9aa3
fix smoke test
xangcastle Aug 14, 2026
8e243f5
fix smoke test
xangcastle Aug 14, 2026
8eccac4
Merge remote-tracking branch 'origin' into xangcastle/cross-sdist-macos
xangcastle Aug 14, 2026
50bbc92
remove smoke tests
xangcastle Aug 14, 2026
818880c
Merge remote-tracking branch 'origin' into xangcastle/cross-sdist-macos
xangcastle Aug 14, 2026
c593d95
Merge branch 'main' into xangcastle/cross-sdist-macos
xangcastle Aug 15, 2026
52c8eef
fix: darwin exec-host cross builds — exec-resolved JDK, ar→libtool fa…
xangcastle Aug 17, 2026
e1a3875
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 17, 2026
7821454
Merge branch 'main' into xangcastle/cross-sdist-macos
xangcastle Aug 17, 2026
3f05868
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 17, 2026
f12166b
chore: drop accidental typing reverts against main
xangcastle Aug 17, 2026
a179d18
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 18, 2026
a5cfe1d
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 19, 2026
317e9ba
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 19, 2026
6a0ea24
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 20, 2026
eea6a9d
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 25, 2026
00e86f3
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 25, 2026
a6ce693
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 26, 2026
3e16914
fix(e2e): unred spike CI — drop swept-in strays, bump setproctitle fo…
xangcastle Aug 27, 2026
5e31898
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 27, 2026
3a11800
fix(uv): drop shadowed duplicate _generate_meson_cross_file after mai…
xangcastle Aug 27, 2026
1b40dd2
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 28, 2026
3c35cea
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 28, 2026
85de6a7
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 28, 2026
f74e781
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 28, 2026
2f22556
fix(e2e): drop the spike's jpype1 case, superseded by main's pycross-jdk
xangcastle Aug 28, 2026
50104d5
ci(spike): remove all QEMU emulation
xangcastle Aug 28, 2026
647f92f
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Aug 28, 2026
5ba3f3e
feat(uv): port remaining crossbuild e2e cases with wheel-only cross v…
xangcastle Aug 28, 2026
7fa9823
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Sep 3, 2026
99c73eb
feat(uv): derive Rust and JDK build env from toolchains
xangcastle Sep 3, 2026
d35c7d5
chore(e2e): restore build_graph snapshot file modes
xangcastle Sep 3, 2026
87e8b4d
chore(uv): let gazelle own rust_layer bzl_library visibility
xangcastle Sep 3, 2026
909daa6
Merge branch 'xangcastle/crossbuild-exec-verify-macos' into xangcastl…
xangcastle Sep 3, 2026
590b916
refactor: rebase spike internals onto main's pep517 mechanisms
xangcastle Sep 3, 2026
dbc670e
chore(e2e): realign crossbuild .bazelrc with main (path mapping on)
xangcastle Sep 3, 2026
9b8f102
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Sep 8, 2026
fe97e09
fix(uv): link libstdc++ statically for GNU C++ builds, dump meson-log…
xangcastle Sep 8, 2026
8b6b72c
fix(uv): keep meson-python's build dir so meson-log.txt survives a fa…
xangcastle Sep 8, 2026
6230725
fix(uv): point pkg-config's python3 at the interpreter the wheel is b…
xangcastle Sep 8, 2026
b3e290b
chore: sync the spike with the rust_toolchain PR
xangcastle Sep 9, 2026
7536a41
feat(uv): vendor the crates a Rust sdist's Cargo.lock pins, build off…
xangcastle Sep 9, 2026
0cd5cc7
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Sep 9, 2026
1258def
feat(uv): ship rules_py's own Rust toolchain for pep517 sdists
xangcastle Sep 9, 2026
18c9af0
ci: drop the macOS smoke job
xangcastle Sep 9, 2026
243c04e
Merge remote-tracking branch 'origin/main' into xangcastle/cross-sdis…
xangcastle Sep 9, 2026
8b416c1
chore(e2e): point the shared setproctitle label at the 1.3.7 the spik…
xangcastle Sep 9, 2026
eb55b70
Revert "feat(uv): ship rules_py's own Rust toolchain for pep517 sdists"
xangcastle Sep 10, 2026
5bbfd62
fix(uv): only infer setuptools-rust under a setuptools backend
xangcastle Sep 10, 2026
75c4723
feat(uv): fail early when a Rust sdist has no rust_toolchain to build…
xangcastle Sep 9, 2026
7f94586
fix(uv): demand a Rust toolchain only for declared Rust builds
xangcastle Sep 10, 2026
163c39b
docs(uv): Rust sdists build with the project's rules_rust or rules_rs…
xangcastle Sep 10, 2026
203e000
test(e2e): export the Rust cases' wheels for the native-arch runs
xangcastle Sep 10, 2026
d4d5f12
feat(uv): rust_toolchain on uv.project wires Rust sdist builds automa…
xangcastle Sep 3, 2026
f27eb24
feat(uv): prove rust_toolchain against rules_rs; pass rustc its sysro…
xangcastle Sep 8, 2026
694c8fc
feat(uv): vendor the crates a Rust sdist's Cargo.lock pins, build off…
xangcastle Sep 9, 2026
1825f70
feat(uv): fail early when a declared Rust sdist has no rust_toolchain
xangcastle Sep 9, 2026
af368fc
test(e2e): export the Rust cases' wheels for the native-arch runs
xangcastle Sep 10, 2026
1f4c6cd
docs(uv): Rust sdists build with the project's rules_rust or rules_rs…
xangcastle Sep 10, 2026
3bf25a1
feat(uv): declare Rust toolchains with uv.package_toolchains(), not o…
xangcastle Sep 10, 2026
a15fe91
fix(uv): forbid maturin from downloading a Rust toolchain of its own
xangcastle Sep 10, 2026
0c8eae1
feat(uv): reproducible rustc wrapper and cc-rs environment for Rust s…
xangcastle Sep 10, 2026
5e93608
fix(uv): turn off maturin's SBOM so Rust wheels are reproducible
xangcastle Sep 10, 2026
bc44642
feat(uv): package_toolchains scopes to a package and carries generic …
xangcastle Sep 11, 2026
efa605a
feat(uv): host-independent symbol hashes for Rust wheels
xangcastle Sep 15, 2026
bd3666e
test(e2e): per-case test.sh scripts in crossbuild
xangcastle Sep 15, 2026
fc74512
feat(uv): `:cargo_lock` target generates a Rust sdist's Cargo.lock
xangcastle Sep 15, 2026
2957fe9
feat(uv)!: uv.rust_toolchain() replaces uv.package_toolchains()
xangcastle Sep 15, 2026
5793d65
chore(gazelle): order the pep517_whl bzl_library targets
xangcastle Sep 15, 2026
da00753
Merge branch 'xangcastle/pep517-rust-toolchain' into xangcastle/cross…
xangcastle Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 193 additions & 9 deletions docs/uv.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,86 @@ platform_transition_filegroup(
)
```

## Example: Cross-compiling sdists

Wheels are selected for the target platform, but when a package only ships a
source distribution — or no published wheel matches the target — uv builds the
sdist as part of the build. Two modes exist:

- **Pure-Python sdists** produce a `-none-any` wheel and build identically in
any configuration, cross or not.
- **Native sdists** (C/C++ extensions) build in *native mode* when the exec and
target platforms coincide. When they differ, the build enters *cross mode*.

Cross mode requires a **cross-capable C++ toolchain** registered with
`register_toolchains` — one whose compiler can target the destination platform
from the exec platform (for example `toolchains_llvm`, whose clang is
multi-target). If none resolves, analysis fails with an explicit error naming
the missing toolchain type rather than an obscure toolchain-resolution
failure. No per-package opt-in is needed: cross mode activates automatically
from the platform configuration.

Under cross mode the build action:

1. Extracts the C++ toolchain selected for the target platform (compiler,
compile/link flags, sysroot) and re-materializes it as compiler wrapper
scripts, so flags such as `-target` / `--sysroot` survive the PEP 517
backend's own command construction. Per backend it also generates the
cross artifact the backend requires: a meson cross file plus exe_wrapper
(meson-python only auto-synthesizes cross files on macOS), a CMake
toolchain file (scikit-build-core's cross detection likewise only covers
macOS), and a `rustc --sysroot` wrapper plus sandboxed `CARGO_HOME` for
cargo-based backends (maturin, setuptools-rust).
2. Overrides the target interpreter's sysconfig for the build
(`_PYTHON_SYSCONFIGDATA_NAME` pointing at the target runtime's
`_sysconfigdata_*.py`, `_PYTHON_HOST_PLATFORM`, and the target's
`EXT_SUFFIX`/`SOABI`), so the produced `.so` and wheel are tagged for the
destination platform.
3. Resolves the sdist's *build* dependencies (`uv.project`'s
`default_build_dependencies`, e.g. `build`, `setuptools`, `cffi`) for the
**exec platform** but the **target Python version** — the interpreter that
runs the build is the host one; the wheels it imports match the host.
4. Validates the produced wheel's platform tag against the target OS/CPU and
fails the action if the backend leaked the exec platform into the tag.

Cargo-based backends need a Rust toolchain that runs on the exec platform.
Declare it once per module (or per project with `lock`) with
`uv.rust_toolchain(toolchain = "@rules_rust//rust/toolchain:current_rust_toolchain")`;
sdist repos whose build backend is maturin, or whose build requirements
include setuptools-rust, then receive `CARGO`, `RUSTC` and the exec-platform
sysroot automatically, and cargo builds offline against the crates vendored
from the sdist's `Cargo.lock`. No per-package `uv.override_package` `env` or
`toolchains` entries are needed for Rust; see "Build-time toolchains" below.

Other build-time toolchains are still layered per package through
`uv.override_package(toolchains = [...])`. Toolchains exporting the JDK
(`$(JAVA)`, `$(JAVABASE)`) or Ant (`$(ANT_HOME)`) make variables are mapped
into the build environment automatically; any other make variable still needs
an explicit `env` entry.

A working end-to-end suite lives in `e2e/crossbuild/`: real packages forced
to build from sdist (`[tool.uv] no-binary-package`) and cross-compiled for
linux/amd64 and linux/arm64, covering setuptools (`pycross-geohash`,
`pycross-msgpack`, `pycross-psutil`, `pycross-setuptools`), setuptools-rust
(`pycross-tiktoken`, `pycross-bcrypt`), maturin/PyO3 (`pycross-rust`,
`pycross-rpds_py`), meson-python (`pycross-meson`, `pycross-numpy`), and
scikit-build-core/CMake (`pycross-cmake`, `pycross-jdk`). Each case asserts
the produced wheels' `Tag:` metadata and the ELF architecture of every bundled
`.so`, and exports a wheel bundle that CI installs and runs on a native runner
of the target architecture. `pycross-geohash` additionally covers a macOS
arm64 → macOS amd64 cross target when run from a macOS host (see
`e2e/crossbuild/test.sh`).

Current limitations:

- CPU-feature detection that runs compiled binaries cannot work in cross
mode and needs per-package baselines.
- No shared-library "repair" (auditwheel/delocate style bundling) is performed
yet; wheels linking against Bazel-provided native libraries need care.
- Windows targets and MSVC are not supported.
- Remote execution with an exec platform different from the host is untested;
the build-dependency resolution assumes exec == host.

## Example: Constraining library compatibility

By default uv hubs let you write `py_library` and other targets which are
Expand Down Expand Up @@ -382,23 +462,127 @@ useful when a pre-build patch removes stale entry-point metadata.
### Build-time toolchains

A native sdist build may need tools beyond the C++ toolchain: a JDK for JNI
extensions, cargo and rustc for Rust extensions, Ant. List them on the
package's override and their well-known make-variables reach the build
environment on their own:
extensions, Ant, cargo and rustc for Rust extensions. Tools one package needs
go on that package's override and their well-known make-variables reach the
build environment on their own:

```starlark
uv.override_package(
lock = "//:uv.lock",
name = "jpype1",
lock = "//:uv.lock",
toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"],
)
```

`$(JAVA)` and `$(JAVABASE)` arrive as `JAVA` and `JAVA_HOME`; `$(CARGO)`,
`$(RUSTC)` and `$(RUST_HOST_SYSROOT)` as the variables the Rust build path
reads; `$(ANT_HOME)` and `$(ANT_BIN_DIR)` likewise. Any other make-variable a
toolchain exports still needs an explicit `env` entry (`"FOO": "$(FOO)"`),
and an explicit entry always wins over the derived value.
Toolchain files become inputs of that package's build action and of no
other, which is what keeps a JDK out of every unrelated sdist build. Rust is
the exception with its own declaration below: rules_py detects which sdists
build Rust, so one module-wide declaration is precise.

`$(JAVA)` and `$(JAVABASE)` arrive as `JAVA` and `JAVA_HOME`; `$(ANT_HOME)` and
`$(ANT_BIN_DIR)` likewise; `$(CARGO)`, `$(RUSTC)`, `$(RUST_SYSROOT)` and
`$(RUST_HOST_SYSROOT)` as the variables the Rust build path reads, for
toolchains wired by hand. Any other make-variable a toolchain exports still
needs an explicit `env` entry (`"FOO": "$(FOO)"`), and an explicit entry always
wins over the derived value.

Rust sdists (maturin, setuptools-rust) build with the Rust toolchain your
module registers. Fetching rustc and cargo is the Rust rulesets' job, and
rules_py depends on neither of them, so point `uv.rust_toolchain()` at the
toolchain once and every Rust sdist of every `uv.project()` in the module is
wired to it. Either ruleset works:

- [rules_rust](https://github.com/bazelbuild/rules_rust):
`toolchain = "@rules_rust//rust/toolchain:current_rust_toolchain"`
- [rules_rs](https://github.com/hermeticbuild/rules_rs): its toolchains are
rules_rust `rust_toolchain` instances declared in the patched `rules_rust`
repository it fetches, so expose that repository and point at its
`current_rust_toolchain`:

```starlark
rules_rust_rs = use_extension("@rules_rs//rs:rules_rust.bzl", "rules_rust")
use_repo(rules_rust_rs, rules_rust_rs = "rules_rust")
```

then `toolchain = "@rules_rust_rs//rust/toolchain:current_rust_toolchain"`.

```starlark
uv.rust_toolchain(
toolchain = "@rules_rust//rust/toolchain:current_rust_toolchain",
)
```

Scope a declaration with `lock` to apply it to one project only; it wins over
the module-wide one for that project. That is how a workspace builds one
project on rules_rust and another on rules_rs:

```starlark
uv.rust_toolchain(
lock = "//other:uv.lock",
toolchain = "@rules_rust_rs//rust/toolchain:current_rust_toolchain",
)
```

Every sdist whose build backend is maturin, or whose build requirements
include setuptools-rust, then gets the toolchain and an
exec-configured `rust_host_sysroot` layer wired into its build. In a cross
build cargo also *compiles* code for the exec platform and runs it there
(`build.rs` scripts, proc-macro crates); that layer supplies the exec
platform's standard library next to the target's, the way rustup keeps
several targets in one install. No `uv.override_package` entry is needed for
Rust packages, and a Rust sdist in a module with no `uv.rust_toolchain()`
covering its project fails while the repository is generated, naming the
declaration to add; only declared Rust builds are demanding, an sdist that
merely ships `.rs` files (zstandard's optional extension) builds as before. The crates the
sdist's `Cargo.lock` pins on crates.io are fetched with their checksums while
the repository is generated and vendored into it; cargo then builds offline,
so the build needs no network and works under remote execution. A lock that
pins crates outside crates.io (git or path sources) is rejected. An sdist
without a `Cargo.lock` builds with network access and a warning naming the
`:cargo_lock` target of its generated repository. `bazel run` that target
and it resolves the crates with the project's own Rust toolchain and writes
the lock into the workspace:

```
bazel run @sdist_build__my_project__tiktoken__0_13_0//:cargo_lock -- third_party/tiktoken.Cargo.lock
```

The repository is `sdist_build__<project>__<package>__<version>`, with the
project's `pyproject.toml` name; the warning prints it in canonical form,
so either add it to `use_repo` or spell it with `@@` as printed. The argument
is the workspace-relative output, `<name>-<version>.Cargo.lock` at the root
when omitted. Declare the file with
`uv.override_package(cargo_lock = "//third_party:tiktoken.Cargo.lock")` and
it is vendored and placed next to the sdist's `Cargo.toml` before the build;
once declared, the target regenerates that file in place. maturin is told
not to download a Rust toolchain of its own (`MATURIN_NO_INSTALL_RUST=1`): a
Rust sdist with no toolchain wired fails instead of fetching rustc inside the
build.

The rustc cargo runs is a wrapper that also makes the extension independent
of where the action ran: sandbox and execroot paths are remapped out of the
binaries (`--remap-path-prefix`), target crates compile as one codegen unit,
and the `-C metadata=` hash cargo mangles into every symbol, which mixes in
the host's `rustc -vV` output and the paths of host-compiled build scripts,
is replaced for target crates by one derived from the toolchain's release
string and the crate's own identity (package name and version, crate name,
types, cfgs, target and the codegen options its profile sets). maturin's
SBOM, which records sandbox paths, is turned
off unless the sdist configures it. The wheel's bytes then match across hosts
and downstream actions hit the cache. Crates that compile C or C++ through
cc-rs (`ring`, `zstd-sys`) find the wired C toolchain under `CC_<triple>`,
`CXX_<triple>`, `AR_<triple>` and `RANLIB_<triple>` instead of whatever is on
the PATH.

PyO3 needs no configuration file from rules_py: in a cross build maturin
writes its own `PYO3_CONFIG_FILE` from the `--interpreter` it is handed, and
setuptools-rust builds derive pointer width and ABI from
`PYO3_CROSS_PYTHON_VERSION` and the target triple, which the helper sets. A
PyO3 release older than the Python it is built for refuses to compile and
names `PYO3_USE_STABLE_ABI_FORWARD_COMPATIBILITY=1` as the way to build
against the stable ABI anyway; pass it through
`uv.override_package(env = {...})` for that package rather than globally,
since it changes the wheel's ABI tag.

### Backend config settings

Expand Down
23 changes: 14 additions & 9 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,22 @@ support rests on a single case: setuptools/distutils C extensions
(`pycross-geohash`, `pycross-psutil`, `pycross-msgpack`, `pycross-setuptools`),
meson-python (`pycross-meson`, `pycross-numpy`), scikit-build-core/CMake
(`pycross-cmake`, `pycross-jdk` — the latter also needing a JDK and a
hermetically vendored Apache Ant) and maturin/PyO3 (`pycross-rust`).
Every case builds for linux/amd64 and linux/arm64; in-suite verification is
structural (`Tag:` metadata, ELF arch of every bundled `.so`), and the
non-Rust cases export a wheel bundle that CI installs and runs on NATIVE
amd64 and arm64 runners — no emulation in the verdict. The suites are isolated from
hermetically vendored Apache Ant), maturin/PyO3 (`pycross-rust` on a
rules_rust toolchain, `pycross-rust-rs` on a rules_rs one, `pycross-rpds_py`)
and setuptools-rust (`pycross-bcrypt`, `pycross-tiktoken`). Every case builds
for linux/amd64 and linux/arm64;
in-suite verification is structural (`Tag:` metadata, ELF arch of every
bundled `.so`), and each case exports a wheel bundle that CI installs and runs
on NATIVE amd64 and arm64 runners — no emulation in the verdict. The suites are isolated from
`e2e/cases` because their hubs need package-specific configuration
(`default_build_dependencies`, pre-build patches, a larger `resource_set`)
that would otherwise leak onto unrelated packages sharing the hub. On a macOS
host, `test.sh` additionally cross-builds `pycross-geohash` for macOS amd64
(a manual target: the platform transition always resolves to os:macos, so
`target_compatible_with` cannot tell hosts apart).
that would otherwise leak onto unrelated packages sharing the hub. Like
`cases`, its `test.sh` aggregates the per-case `<case>/test.sh` scripts that
cannot be an `sh_test`: `pycross-geohash` cross-builds for macOS amd64 on a
macOS host only (a manual target: the platform transition always resolves to
os:macos, so `target_compatible_with` cannot tell hosts apart), and
`pycross-tiktoken` runs the `:cargo_lock` generator of its sdist repository,
which needs `bazel run` and the crates.io index the action sandbox denies.

Each isolated workspace points back at repo-root rules_py with
`local_path_override(path = "../..")`.
Expand Down
1 change: 0 additions & 1 deletion e2e/cases/snapshots/uv_gazelle_778.gazelle_python.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading