Skip to content

Commit 080c30a

Browse files
committed
queue: tflite-runtime 2.14.0 - green on PR #2154; skills: gotchas 494-497
Both riscv64 legs built and tested on the first CI cycle, and the publish job dry-ran clean. The four gotchas are the reusable half of that port: a hermetic Python that predates riscv64 supplies both the Python and the numpy headers, so two repositories have to be stood in (494); a Bazel port's loading phase, including those overrides, rehearses on x86_64 in minutes even behind blocked egress (495); gotcha 420's XNNPACK fp16 define does not apply to a 2023 pin whose riscv64 production microkernels are scalar-only (496); and an upstream build script's own env hooks take the whole riscv64 delta, with the later flag cancelling one the script hardcodes (497).
1 parent dab0e9b commit 080c30a

5 files changed

Lines changed: 121 additions & 2 deletions

File tree

‎.queue.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3797,7 +3797,7 @@ packages:
37973797
repo: https://github.com/tensorflow/tensorflow
37983798
status: in-review
37993799
pr: https://github.com/riseproject-dev/python-wheels/pull/2154
3800-
notes: 'PR #2154 open as a draft, first CI run started. 12 Linux wheels upstream (abi: cp310,cp311,cp38,cp39); no riscv64 on PyPI or pypi.riseproject.dev. Feasible and much smaller than tensorflow itself (gotcha 426): 2.14.0 is the last tflite-runtime release and predates the LiteRT split, so upstream is tensorflow/tensorflow at tag v2.14.0 (verified: PyPI lists only www.tensorflow.org/lite, and tensorflow/tools/pip_package/setup.py at that tag reads _VERSION = 2.14.0 while tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh builds the tflite_runtime distribution). The recipe builds ONE bazel target, //tensorflow/lite/python/interpreter_wrapper:_pywrap_tensorflow_interpreter_wrapper, with -c opt --config=monolithic --config=noaws --config=nogcp --config=nohdfs --config=nonccl, then copies it next to interpreter.py/metrics_portable.py and runs setup_with_binary.py - no TF core, no MLIR, and flex is behind a define we do not set, so this is comparable in scope to ai-edge-litert (PR #2135) rather than to a full TF build. FOUR riscv64 questions checked statically before the first cycle: (1) bazel: .bazelversion says 6.1.0 and no riscv64 binary exists for any bazel release, so 7.5.0 is bootstrapped as elsewhere in this repo - TF 2.14 has no MODULE.bazel, its only version gate is workspace2.bzl versions.check("1.0.0"), and every flag its .bazelrc sets (--experimental_cc_shared_library, --experimental_link_static_libraries_once, --incompatible_enforce_config_setting_visibility, --experimental_repo_remote_exec, configs monolithic/noaws/nogcp/nohdfs/nonccl) was verified to parse under a real bazel 7.5.0 locally; build:linux is auto-applied via --enable_platform_specific_config and already carries --cxxopt=-std=c++17. (2) XNNPACK at this TF commit is b9d4073a, where riscv64 PRODUCTION microkernels are scalar only (scalar-riscv amalgam / PROD_SCALAR_RISCV_MICROKERNEL_SRCS); ALL_RVV_MICROKERNEL_SRCS and the XNN_ENABLE_RISCV_VECTOR define appear only in bench_microkernels/test_microkernels, and the tree has no rvvfp16arith at all - so neither gotcha 420 (zvfh vs binutils 2.41) nor an RVV-intrinsics-vs-GCC-14 problem can arise, and no xnn_enable_* define is needed. cpuinfo 87d82345 has a linux_riscv64 srcs branch. (3) hermetic python IS the one real gap: TF 2.14 pins rules_python 0.23.1, whose PLATFORMS/TOOL_VERSIONS have no riscv64 CPython, and BOTH //third_party/python_runtime:headers (via @local_config_python -> @python//:python_headers) and //third_party/py/numpy:headers (@pypi_numpy//:numpy_headers) come from it; WORKSPACE also load()s @python//:defs.bzl, so the toolchain_aliases repo is fetched eagerly and get_host_platform() fails on riscv64. Solved with no patch by --override_repository=python=... and --override_repository=pypi_numpy=..., two repos written at run time from the container CPython include dir and numpy.get_include(); VALIDATED off-target: a real bazel 7.5.0 on x86_64 evaluated the whole WORKSPACE python/pip_parse block with those overrides and got as far as workspace3.bzl fetching tf_runtime, i.e. past every hermetic-python line, and pip_parse never ran pip. (4) numpy: nothing needs patching either - the interpreter_wrapper C++ uses only APIs numpy 2 still exports (PyArray_SimpleNewFromData/EMPTY/FromAny/Return/SetBaseObject/ENABLEFLAGS/GETITEM/Iter*, NPY_ARRAY_*, no descr->elsize), so it builds against the registry numpy (2.2.2 cp310 / 2.4.3 cp311) and that keeps the wheel loadable under numpy 1.x and 2.x alike. Matrix is cp310+cp311 by upstream constraint, not by choice: upstream ships cp38-cp311 only, pybind11 is pinned at 2.10.4 which predates CPython 3.12, TF_PYTHON_VERSION accepts 3.9-3.11, and the manylinux riscv64 image has no interpreter below 3.10; registry numpy covers both. Local validation could not go further than WORKSPACE evaluation: this sandbox egress blocks codeload.github.com, so every tf_http_archive 403s.'
3800+
notes: 'PR #2154 open as a draft and FULLY GREEN on the first CI cycle - both legs built and tested, publish dry run clean (cp310 53m, cp311 52m; bazel build 991 actions / 2739s, wheels 1.8MB, tflite_runtime/_pywrap_tensorflow_interpreter_wrapper.so 3.9MB with ELF e_machine 0xF3, tag cp3XX-cp3XX-manylinux_2_39_riscv64 after auditwheel retagged linux_riscv64, test installs numpy 2.4.3 from the registry and runs testdata/add.bin to 3x its input). 12 Linux wheels upstream (abi: cp310,cp311,cp38,cp39); no riscv64 on PyPI or pypi.riseproject.dev. Feasible and much smaller than tensorflow itself (gotcha 426): 2.14.0 is the last tflite-runtime release and predates the LiteRT split, so upstream is tensorflow/tensorflow at tag v2.14.0 (verified: PyPI lists only www.tensorflow.org/lite, and tensorflow/tools/pip_package/setup.py at that tag reads _VERSION = 2.14.0 while tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh builds the tflite_runtime distribution). The recipe builds ONE bazel target, //tensorflow/lite/python/interpreter_wrapper:_pywrap_tensorflow_interpreter_wrapper, with -c opt --config=monolithic --config=noaws --config=nogcp --config=nohdfs --config=nonccl, then copies it next to interpreter.py/metrics_portable.py and runs setup_with_binary.py - no TF core, no MLIR, and flex is behind a define we do not set, so this is comparable in scope to ai-edge-litert (PR #2135) rather than to a full TF build. FOUR riscv64 questions checked statically before the first cycle: (1) bazel: .bazelversion says 6.1.0 and no riscv64 binary exists for any bazel release, so 7.5.0 is bootstrapped as elsewhere in this repo - TF 2.14 has no MODULE.bazel, its only version gate is workspace2.bzl versions.check("1.0.0"), and every flag its .bazelrc sets (--experimental_cc_shared_library, --experimental_link_static_libraries_once, --incompatible_enforce_config_setting_visibility, --experimental_repo_remote_exec, configs monolithic/noaws/nogcp/nohdfs/nonccl) was verified to parse under a real bazel 7.5.0 locally; build:linux is auto-applied via --enable_platform_specific_config and already carries --cxxopt=-std=c++17. (2) XNNPACK at this TF commit is b9d4073a, where riscv64 PRODUCTION microkernels are scalar only (scalar-riscv amalgam / PROD_SCALAR_RISCV_MICROKERNEL_SRCS); ALL_RVV_MICROKERNEL_SRCS and the XNN_ENABLE_RISCV_VECTOR define appear only in bench_microkernels/test_microkernels, and the tree has no rvvfp16arith at all - so neither gotcha 420 (zvfh vs binutils 2.41) nor an RVV-intrinsics-vs-GCC-14 problem can arise, and no xnn_enable_* define is needed. cpuinfo 87d82345 has a linux_riscv64 srcs branch. (3) hermetic python IS the one real gap: TF 2.14 pins rules_python 0.23.1, whose PLATFORMS/TOOL_VERSIONS have no riscv64 CPython, and BOTH //third_party/python_runtime:headers (via @local_config_python -> @python//:python_headers) and //third_party/py/numpy:headers (@pypi_numpy//:numpy_headers) come from it; WORKSPACE also load()s @python//:defs.bzl, so the toolchain_aliases repo is fetched eagerly and get_host_platform() fails on riscv64. Solved with no patch by --override_repository=python=... and --override_repository=pypi_numpy=..., two repos written at run time from the container CPython include dir and numpy.get_include(); VALIDATED off-target: a real bazel 7.5.0 on x86_64 evaluated the whole WORKSPACE python/pip_parse block with those overrides and got as far as workspace3.bzl fetching tf_runtime, i.e. past every hermetic-python line, and pip_parse never ran pip. (4) numpy: nothing needs patching either - the interpreter_wrapper C++ uses only APIs numpy 2 still exports (PyArray_SimpleNewFromData/EMPTY/FromAny/Return/SetBaseObject/ENABLEFLAGS/GETITEM/Iter*, NPY_ARRAY_*, no descr->elsize), so it builds against the registry numpy (2.2.2 cp310 / 2.4.3 cp311) and that keeps the wheel loadable under numpy 1.x and 2.x alike. Matrix is cp310+cp311 by upstream constraint, not by choice: upstream ships cp38-cp311 only, pybind11 is pinned at 2.10.4 which predates CPython 3.12, TF_PYTHON_VERSION accepts 3.9-3.11, and the manylinux riscv64 image has no interpreter below 3.10; registry numpy covers both. Local validation could not go further than WORKSPACE evaluation: this sandbox egress blocks codeload.github.com, so every tf_http_archive 403s.'
38013801
- pkg: cmeel-zlib
38023802
version: 1.3.2
38033803
home: https://github.com/cmake-wheel/cmeel-zlib

‎skills/python-project-porting/references/gotchas-index.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Gotchas index — router for the themed gotcha files
22

3-
The porting gotchas (479 of them) live in [`references/gotchas/`](gotchas/), split by theme so only the relevant slice loads. Every gotcha keeps a **permanent number** cited elsewhere as "gotcha N" (and in workflow comments as "CLAUDE.md gotcha N"). Numbers are stable IDs — **not sequential**, and four are **reused** with different content (two each of 33, 55, 56, 57), disambiguated by theme below.
3+
The porting gotchas (483 of them) live in [`references/gotchas/`](gotchas/), split by theme so only the relevant slice loads. Every gotcha keeps a **permanent number** cited elsewhere as "gotcha N" (and in workflow comments as "CLAUDE.md gotcha N"). Numbers are stable IDs — **not sequential**, and four are **reused** with different content (two each of 33, 55, 56, 57), disambiguated by theme below.
44

55
## How to find the gotcha you need
66

@@ -558,6 +558,12 @@ The porting gotchas (479 of them) live in [`references/gotchas/`](gotchas/), spl
558558
child, so a cmeel distribution that delegates its whole build to one ships into
559559
`cmeel.prefix/lib64/` rather than `lib/`; read the released wheel's namelist, not the sibling
560560
workflow (the cmeel-zlib case, and the mechanism behind gotcha 492).
561+
- **494** — A hermetic Python predating riscv64 is a *two*-repository problem — Python headers
562+
and numpy headers both come from it — and in a WORKSPACE tree `--override_repository` over two
563+
run-time-written repos settles it with no patch (the tflite-runtime/TensorFlow 2.14 case).
564+
- **497** — Drive an upstream build script through the env hooks it already exposes
565+
(`CUSTOM_BAZEL_FLAGS`, `BAZEL_STARTUP_OPTIONS`), and use the fact that the later flag wins to
566+
cancel one it hardcodes, such as `-s`.
561567

562568
### The manylinux image & toolchain — [`gotchas/manylinux-image-and-toolchain.md`](gotchas/manylinux-image-and-toolchain.md)
563569

@@ -658,6 +664,9 @@ The porting gotchas (479 of them) live in [`references/gotchas/`](gotchas/), spl
658664
- **485** — CMake's `find_package(Python3 COMPONENTS Development)` cannot configure in the
659665
manylinux image because PEP 513 forbids shipping `libpython`; the fix is a zero-byte file at
660666
the path FindPython validates, and upstream probably already carries it (the usd-core case).
667+
- **496** — Gotcha 420's XNNPACK fp16 define does not belong in an older tree: at a 2023 pin the
668+
riscv64 *production* microkernels are scalar-only and every RVV gate sits in a bench/test
669+
target, so attribute each `riscv` line to its target before adding a define.
661670

662671
### Native dependencies & linking — [`gotchas/native-deps-and-linking.md`](gotchas/native-deps-and-linking.md)
663672

@@ -967,6 +976,9 @@ The porting gotchas (479 of them) live in [`references/gotchas/`](gotchas/), spl
967976
wheel hands you a byte-comparable feature oracle: configure once under QEMU and diff it
968977
against the released wheel's before compiling anything; also where an ECMWF binary-wrapper
969978
distribution's real build recipe lives when its wheel job is private (the eckitlib case).
979+
- **495** — A Bazel port's loading phase rehearses on x86_64 in minutes: check the project's
980+
`.bazelrc` flags against the bazel you bootstrap in an empty workspace, then evaluate the real
981+
WORKSPACE with the real overrides — blocked egress only stops it at the first archive fetch.
970982

971983
### PR, CI, triggers, publishing & maintainer signals — [`gotchas/pr-ci-and-maintainer.md`](gotchas/pr-ci-and-maintainer.md)
972984

‎skills/python-project-porting/references/gotchas/local-validation-and-rehearsal.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/local-validation-and-r
3636
- **444** — Verify a hand-edited `.patch` with `git apply --check`, never with `patch`:
3737
a wrong `@@` line count makes GNU `patch` silently swallow the *next* hunk and exit 0.
3838
- **490** — An ecbuild/CMake project that installs its generated config header into the
39+
- **495** — A Bazel port's loading phase rehearses on x86_64 in minutes, even in a sandbox
40+
that cannot fetch the dependencies.
3941
wheel hands you a byte-comparable feature oracle
4042

4143
---
@@ -545,3 +547,26 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/local-validation-and-r
545547
be dropped (keeping it also means cython in the container). The per-interpreter wheel
546548
list is a mirage for the same reason — cp310..cp314 differ only in tag, nothing links the
547549
Python C API — so build one `py3-none` wheel, as `build-eccodeslib.yml` already does.
550+
551+
495. **A Bazel port's loading phase rehearses on x86_64 in minutes, even in a sandbox that
552+
cannot fetch the dependencies.** Two checks, both arch-independent, both cheaper than the
553+
hours-long riscv64 cycle they replace:
554+
- **The project's `.bazelrc` against the bazel version you actually bootstrap.** Copy it
555+
into an empty workspace (`touch WORKSPACE`) and run `bazel build --nobuild` with the
556+
same `--config`s the upstream script passes. An old tree pinned to bazel 6 may name
557+
flags a newer bazel deleted, and an unknown one is a startup failure, not a warning —
558+
`--experimental_cc_shared_library`, `--experimental_link_static_libraries_once` and
559+
`--incompatible_enforce_config_setting_visibility` all still parse in 7.5.0, which is
560+
one reason these trees want 7.x and not 8 (which also dropped WORKSPACE `bind()`).
561+
With no targets bazel exits 0 on "requested an empty set of targets", so the run is
562+
purely a flag check.
563+
- **WORKSPACE evaluation on the real checkout, with the real repository overrides.**
564+
Everything up to the first `http_archive` fetch is host-independent: it proves the
565+
overrides resolve, every `load()` finds its symbols, and no repository rule shells out
566+
to an interpreter that isn't there (gotcha 494's failure mode lands here). Where egress
567+
blocks `codeload.github.com` the run dies on the first archive with a 403 — *after* that
568+
whole block, which is the part worth testing; read the traceback's `WORKSPACE:<line>` to
569+
confirm how far it got.
570+
- Point `--output_user_root` at `.git/pw-scratch/<pkg>/` and delete it afterwards: a
571+
bazel install base plus a shallow clone of a monorepo is ~700MB on a disk other agents
572+
share.

‎skills/python-project-porting/references/gotchas/manylinux-image-and-toolchain.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/manylinux-image-and-to
9191
nothing else in the tree declares: translate its `-dev` packages to Rocky names before the
9292
first run, or the image's missing header stops the compile (the vllm `numa.h` case).
9393
- **485** — CMake's `find_package(Python3 COMPONENTS Development)` fails inside the manylinux
94+
- **496** — Before copying gotcha 420's XNNPACK fp16 define into an older tree, check which
95+
target the gate sits in — an old pin may compile no vector kernels at all.
9496
image because PEP 513 forbids shipping `libpython`, and the fix is a zero-byte file, not a
9597
build-flag change (the usd-core/OpenUSD case).
9698
---
@@ -1522,3 +1524,23 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/manylinux-image-and-to
15221524
linux/riscv64 $MANYLINUX_RISCV64_IMAGE` and print `os.path.exists(LIBDIR/LDLIBRARY)` for
15231525
each interpreter you plan to build. `False` everywhere means this gotcha applies to any
15241526
`Development`-requiring configure in that image.
1527+
1528+
496. **Before copying gotcha 420's `--define=xnn_enable_riscv_fp16_vector=false` into an
1529+
older tree, check which XNNPACK *target* the gate sits in — an old pin may compile no
1530+
vector kernels at all.** At the commit TensorFlow 2.14 pins (`b9d4073a`, mid-2023) the
1531+
riscv64 production library is scalar-only: `riscv_srcs` is
1532+
`src/amalgam/gen/scalar-riscv.c` / `PROD_SCALAR_RISCV_MICROKERNEL_SRCS`, while
1533+
`ALL_RVV_MICROKERNEL_SRCS`, the `-march=rv64gcv` copts and the `XNN_ENABLE_RISCV_VECTOR`
1534+
define appear only in `bench_microkernels` and `test_microkernels`, and `rvvfp16arith`
1535+
is not in the tree at all. Neither the `zvfh`-vs-binutils-2.41 trap (420) nor the
1536+
pre-0.12 RVV intrinsic spellings GCC 14 no longer accepts can fire, so the define would
1537+
be a deviation with nothing behind it — the build was green without it.
1538+
- **Attribute each `riscv` hit to its target before concluding anything**:
1539+
`grep -n riscv BUILD.bazel` then, per line, `awk 'NR<=<line> && / name = /'
1540+
BUILD.bazel | tail -1`. A gate inside a benchmark or test library never reaches a
1541+
wheel.
1542+
- **Read `:riscv_vector_enabled` twice**: its `explicit_false` branch resolves to the
1543+
*explicit_true* config_setting, which looks like a bug and is not — with
1544+
`--define xnn_enable_riscv_vector=false` that setting no longer matches, so the select
1545+
falls through to its default and RVV is off. The off-switch works; the indirection
1546+
just does not read like one.

0 commit comments

Comments
 (0)